Author: marius
Date: Sat Sep 12 22:49:32 2015
New Revision: 287726
URL: https://svnweb.freebsd.org/changeset/base/287726

Log:
  - Factor out the common and generic parts of the sparc64 host-PCI-bridge
    drivers into the revived sys/sparc64/pci/ofw_pci.c, previously already
    serving a similar purpose. This has been done with sun4v in mind, which
    explains a) the otherwise not that obvious scheme employed and b) why
    reusing sys/powerpc/ofw/ofw_pci.c was even lesser an option.
  - Add a workaround for QEMU once again not emulating real machines, in
    this case by not providing the OFW_PCI_CS_MEM64 range. [1]
  
  Submitted by: jhb [1]
  MFC after:    1 week

Added:
  head/sys/sparc64/pci/ofw_pci.c
     - copied, changed from r170929, head/sys/sparc64/pci/ofw_pci.c
Modified:
  head/sys/conf/files.sparc64
  head/sys/sparc64/pci/fire.c
  head/sys/sparc64/pci/firereg.h
  head/sys/sparc64/pci/firevar.h
  head/sys/sparc64/pci/ofw_pci.h
  head/sys/sparc64/pci/psycho.c
  head/sys/sparc64/pci/psychoreg.h
  head/sys/sparc64/pci/psychovar.h
  head/sys/sparc64/pci/schizo.c
  head/sys/sparc64/pci/schizoreg.h
  head/sys/sparc64/pci/schizovar.h

Modified: head/sys/conf/files.sparc64
==============================================================================
--- head/sys/conf/files.sparc64 Sat Sep 12 21:23:24 2015        (r287725)
+++ head/sys/conf/files.sparc64 Sat Sep 12 22:49:32 2015        (r287726)
@@ -82,6 +82,7 @@ sparc64/isa/isa_dma.c         optional        isa
 sparc64/isa/ofw_isa.c          optional        ebus | isa
 sparc64/pci/apb.c              optional        pci
 sparc64/pci/fire.c             optional        pci
+sparc64/pci/ofw_pci.c          optional        pci
 sparc64/pci/ofw_pcib.c         optional        pci
 sparc64/pci/ofw_pcib_subr.c    optional        pci
 sparc64/pci/ofw_pcibus.c       optional        pci

Modified: head/sys/sparc64/pci/fire.c
==============================================================================
--- head/sys/sparc64/pci/fire.c Sat Sep 12 21:23:24 2015        (r287725)
+++ head/sys/sparc64/pci/fire.c Sat Sep 12 22:49:32 2015        (r287726)
@@ -59,7 +59,6 @@ __FBSDID("$FreeBSD$");
 #include <sys/timetc.h>
 
 #include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_pci.h>
 #include <dev/ofw/openfirm.h>
 
 #include <vm/vm.h>
@@ -68,7 +67,6 @@ __FBSDID("$FreeBSD$");
 #include <machine/bus.h>
 #include <machine/bus_common.h>
 #include <machine/bus_private.h>
-#include <machine/fsr.h>
 #include <machine/iommureg.h>
 #include <machine/iommuvar.h>
 #include <machine/pmap.h>
@@ -111,19 +109,14 @@ static driver_filter_t fire_xcb;
 /*
  * Methods
  */
-static bus_activate_resource_t fire_activate_resource;
-static bus_adjust_resource_t fire_adjust_resource;
 static pcib_alloc_msi_t fire_alloc_msi;
 static pcib_alloc_msix_t fire_alloc_msix;
 static bus_alloc_resource_t fire_alloc_resource;
 static device_attach_t fire_attach;
-static bus_get_dma_tag_t fire_get_dma_tag;
-static ofw_bus_get_node_t fire_get_node;
 static pcib_map_msi_t fire_map_msi;
 static pcib_maxslots_t fire_maxslots;
 static device_probe_t fire_probe;
 static pcib_read_config_t fire_read_config;
-static bus_read_ivar_t fire_read_ivar;
 static pcib_release_msi_t fire_release_msi;
 static pcib_release_msix_t fire_release_msix;
 static pcib_route_interrupt_t fire_route_interrupt;
@@ -140,15 +133,15 @@ static device_method_t fire_methods[] = 
        DEVMETHOD(device_resume,        bus_generic_resume),
 
        /* Bus interface */
-       DEVMETHOD(bus_read_ivar,        fire_read_ivar),
+       DEVMETHOD(bus_read_ivar,        ofw_pci_read_ivar),
        DEVMETHOD(bus_setup_intr,       fire_setup_intr),
        DEVMETHOD(bus_teardown_intr,    fire_teardown_intr),
        DEVMETHOD(bus_alloc_resource,   fire_alloc_resource),
-       DEVMETHOD(bus_activate_resource, fire_activate_resource),
+       DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource),
        DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
-       DEVMETHOD(bus_adjust_resource,  fire_adjust_resource),
+       DEVMETHOD(bus_adjust_resource,  ofw_pci_adjust_resource),
        DEVMETHOD(bus_release_resource, bus_generic_release_resource),
-       DEVMETHOD(bus_get_dma_tag,      fire_get_dma_tag),
+       DEVMETHOD(bus_get_dma_tag,      ofw_pci_get_dma_tag),
 
        /* pcib interface */
        DEVMETHOD(pcib_maxslots,        fire_maxslots),
@@ -162,7 +155,7 @@ static device_method_t fire_methods[] = 
        DEVMETHOD(pcib_map_msi,         fire_map_msi),
 
        /* ofw_bus interface */
-       DEVMETHOD(ofw_bus_get_node,     fire_get_node),
+       DEVMETHOD(ofw_bus_get_node,     ofw_pci_get_node),
 
        DEVMETHOD_END
 };
@@ -296,7 +289,7 @@ fire_attach(device_t dev)
        struct ofw_pci_msi_eq_to_devino msi_eq_to_devino;
        struct fire_msiqarg *fmqa;
        struct timecounter *tc;
-       struct ofw_pci_ranges *range;
+       bus_dma_tag_t dmat;
        uint64_t ino_bitmap, val;
        phandle_t node;
        uint32_t prop, prop_array[2];
@@ -310,7 +303,6 @@ fire_attach(device_t dev)
        mode = desc->fd_mode;
 
        sc->sc_dev = dev;
-       sc->sc_node = node;
        sc->sc_mode = mode;
        sc->sc_flags = 0;
 
@@ -715,79 +707,21 @@ fire_attach(device_t dev)
        sc->sc_is.is_bushandle = rman_get_bushandle(sc->sc_mem_res[FIRE_PCI]);
        sc->sc_is.is_iommu = FO_PCI_MMU;
        val = FIRE_PCI_READ_8(sc, FO_PCI_MMU + IMR_CTL);
-       iommu_init(device_get_nameunit(sc->sc_dev), &sc->sc_is, 7, -1, 0);
+       iommu_init(device_get_nameunit(dev), &sc->sc_is, 7, -1, 0);
 #ifdef FIRE_DEBUG
        device_printf(dev, "FO_PCI_MMU + IMR_CTL 0x%016llx -> 0x%016llx\n",
            (long long unsigned)val, (long long unsigned)sc->sc_is.is_cr);
 #endif
-
-       /* Initialize memory and I/O rmans. */
-       sc->sc_pci_io_rman.rm_type = RMAN_ARRAY;
-       sc->sc_pci_io_rman.rm_descr = "Fire PCI I/O Ports";
-       if (rman_init(&sc->sc_pci_io_rman) != 0 ||
-           rman_manage_region(&sc->sc_pci_io_rman, 0, FO_IO_SIZE) != 0)
-               panic("%s: failed to set up I/O rman", __func__);
-       sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY;
-       sc->sc_pci_mem_rman.rm_descr = "Fire PCI Memory";
-       if (rman_init(&sc->sc_pci_mem_rman) != 0 ||
-           rman_manage_region(&sc->sc_pci_mem_rman, 0, FO_MEM_SIZE) != 0)
-               panic("%s: failed to set up memory rman", __func__);
-
-       i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range);
-       /*
-        * Make sure that the expected ranges are present.  The
-        * OFW_PCI_CS_MEM64 one is not currently used though.
-        */
-       if (i != FIRE_NRANGE)
-               panic("%s: unsupported number of ranges", __func__);
-       /*
-        * Find the addresses of the various bus spaces.
-        * There should not be multiple ones of one kind.
-        * The physical start addresses of the ranges are the configuration,
-        * memory and I/O handles.
-        */
-       for (i = 0; i < FIRE_NRANGE; i++) {
-               j = OFW_PCI_RANGE_CS(&range[i]);
-               if (sc->sc_pci_bh[j] != 0)
-                       panic("%s: duplicate range for space %d",
-                           __func__, j);
-               sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]);
-       }
-       free(range, M_OFWPROP);
-
-       /* Allocate our tags. */
-       sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE);
-       if (sc->sc_pci_iot == NULL)
-               panic("%s: could not allocate PCI I/O tag", __func__);
-       sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE);
-       if (sc->sc_pci_cfgt == NULL)
-               panic("%s: could not allocate PCI configuration space tag",
-                   __func__);
+       /* Create our DMA tag. */
        if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0x100000000,
            sc->sc_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.is_pmaxaddr,
-           0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0)
+           0xff, 0xffffffff, 0, NULL, NULL, &dmat) != 0)
                panic("%s: could not create PCI DMA tag", __func__);
-       /* Customize the tag. */
-       sc->sc_pci_dmat->dt_cookie = &sc->sc_is;
-       sc->sc_pci_dmat->dt_mt = &sc->sc_dma_methods;
+       dmat->dt_cookie = &sc->sc_is;
+       dmat->dt_mt = &sc->sc_dma_methods;
 
-       /*
-        * Get the bus range from the firmware.
-        * NB: Neither Fire nor Oberon support PCI bus reenumeration.
-        */
-       i = OF_getprop(node, "bus-range", (void *)prop_array,
-           sizeof(prop_array));
-       if (i == -1)
-               panic("%s: could not get bus-range", __func__);
-       if (i != sizeof(prop_array))
-               panic("%s: broken bus-range (%d)", __func__, i);
-       sc->sc_pci_secbus = prop_array[0];
-       sc->sc_pci_subbus = prop_array[1];
-       if (bootverbose != 0)
-               device_printf(dev, "bus range %u to %u; PCI bus %d\n",
-                   sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus);
-
-       ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t));
+       if (ofw_pci_attach_common(dev, dmat, FO_IO_SIZE, FO_MEM_SIZE) != 0)
+               panic("%s: ofw_pci_attach_common() failed", __func__);
 
 #define        FIRE_SYSCTL_ADD_UINT(name, arg, desc)                           
\
        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),                     \
@@ -1390,136 +1324,44 @@ static uint32_t
 fire_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
     int width)
 {
-       struct fire_softc *sc;
-       bus_space_handle_t bh;
-       u_long offset = 0;
-       uint32_t r, wrd;
-       int i;
-       uint16_t shrt;
-       uint8_t byte;
-
-       sc = device_get_softc(dev);
-       if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
-           slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
-               return (-1);
-
-       offset = FO_CONF_OFF(bus, slot, func, reg);
-       bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
-       switch (width) {
-       case 1:
-               i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte);
-               r = byte;
-               break;
-       case 2:
-               i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt);
-               r = shrt;
-               break;
-       case 4:
-               i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd);
-               r = wrd;
-               break;
-       default:
-               panic("%s: bad width", __func__);
-               /* NOTREACHED */
-       }
 
-       if (i) {
-#ifdef FIRE_DEBUG
-               printf("%s: read data error reading: %d.%d.%d: 0x%x\n",
-                   __func__, bus, slot, func, reg);
-#endif
-               r = -1;
-       }
-       return (r);
+       return (ofw_pci_read_config_common(dev, PCIE_REGMAX, FO_CONF_OFF(bus,
+           slot, func, reg), bus, slot, func, reg, width));
 }
 
 static void
 fire_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
     uint32_t val, int width)
 {
-       struct fire_softc *sc;
-       bus_space_handle_t bh;
-       u_long offset = 0;
-
-       sc = device_get_softc(dev);
-       if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
-           slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX)
-               return;
 
-       offset = FO_CONF_OFF(bus, slot, func, reg);
-       bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
-       switch (width) {
-       case 1:
-               bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val);
-               break;
-       case 2:
-               bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val);
-               break;
-       case 4:
-               bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val);
-               break;
-       default:
-               panic("%s: bad width", __func__);
-               /* NOTREACHED */
-       }
+       ofw_pci_write_config_common(dev, PCIE_REGMAX, FO_CONF_OFF(bus, slot,
+           func, reg), bus, slot, func, reg, val, width);
 }
 
 static int
 fire_route_interrupt(device_t bridge, device_t dev, int pin)
 {
-       struct fire_softc *sc;
-       struct ofw_pci_register reg;
-       ofw_pci_intr_t pintr, mintr;
-
-       sc = device_get_softc(bridge);
-       pintr = pin;
-       if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo,
-           &reg, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
-           NULL) != 0)
-               return (mintr);
-
-       device_printf(bridge, "could not route pin %d for device %d.%d\n",
-           pin, pci_get_slot(dev), pci_get_function(dev));
-       return (PCI_INVALID_IRQ);
-}
-
-static int
-fire_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
-{
-       struct fire_softc *sc;
+       ofw_pci_intr_t mintr;
 
-       sc = device_get_softc(dev);
-       switch (which) {
-       case PCIB_IVAR_DOMAIN:
-               *result = device_get_unit(dev);
-               return (0);
-       case PCIB_IVAR_BUS:
-               *result = sc->sc_pci_secbus;
-               return (0);
-       }
-       return (ENOENT);
+       mintr = ofw_pci_route_interrupt_common(bridge, dev, pin);
+       if (!PCI_INTERRUPT_VALID(mintr))
+               device_printf(bridge,
+                   "could not route pin %d for device %d.%d\n",
+                   pin, pci_get_slot(dev), pci_get_function(dev));
+       return (mintr);
 }
 
 static void
 fire_dmamap_sync(bus_dma_tag_t dt __unused, bus_dmamap_t map,
     bus_dmasync_op_t op)
 {
-       static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE);
-       register_t reg, s;
 
        if ((map->dm_flags & DMF_LOADED) == 0)
                return;
 
-       if ((op & BUS_DMASYNC_POSTREAD) != 0) {
-               s = intr_disable();
-               reg = rd(fprs);
-               wr(fprs, reg | FPRS_FEF, 0);
-               __asm __volatile("stda %%f0, [%0] %1"
-                   : : "r" (buf), "n" (ASI_BLK_COMMIT_S));
-               membar(Sync);
-               wr(fprs, reg, 0);
-               intr_restore(s);
-       } else if ((op & BUS_DMASYNC_PREWRITE) != 0)
+       if ((op & BUS_DMASYNC_POSTREAD) != 0)
+               ofw_pci_dmamap_sync_stst_order_common();
+       else if ((op & BUS_DMASYNC_PREWRITE) != 0)
                membar(Sync);
 }
 
@@ -2013,121 +1855,13 @@ fire_alloc_resource(device_t bus, device
     u_long start, u_long end, u_long count, u_int flags)
 {
        struct fire_softc *sc;
-       struct resource *rv;
-       struct rman *rm;
 
-       sc = device_get_softc(bus);
-       switch (type) {
-       case SYS_RES_IRQ:
-               /*
-                * XXX: Don't accept blank ranges for now, only single
-                * interrupts.  The other case should not happen with
-                * the MI PCI code...
-                * XXX: This may return a resource that is out of the
-                * range that was specified.  Is this correct...?
-                */
-               if (start != end)
-                       panic("%s: XXX: interrupt range", __func__);
-               if (*rid == 0)
-                       start = end = INTMAP_VEC(sc->sc_ign, end);
-               return (bus_generic_alloc_resource(bus, child, type, rid,
-                   start, end, count, flags));
-       case SYS_RES_MEMORY:
-               rm = &sc->sc_pci_mem_rman;
-               break;
-       case SYS_RES_IOPORT:
-               rm = &sc->sc_pci_io_rman;
-               break;
-       default:
-               return (NULL);
-       }
-
-       rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
-           child);
-       if (rv == NULL)
-               return (NULL);
-       rman_set_rid(rv, *rid);
-
-       if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type,
-           *rid, rv) != 0) {
-               rman_release_resource(rv);
-               return (NULL);
+       if (type == SYS_RES_IRQ && *rid == 0) {
+               sc = device_get_softc(bus);
+               start = end = INTMAP_VEC(sc->sc_ign, end);
        }
-       return (rv);
-}
-
-static int
-fire_activate_resource(device_t bus, device_t child, int type, int rid,
-    struct resource *r)
-{
-       struct fire_softc *sc;
-       struct bus_space_tag *tag;
-
-       sc = device_get_softc(bus);
-       switch (type) {
-       case SYS_RES_IRQ:
-               return (bus_generic_activate_resource(bus, child, type, rid,
-                   r));
-       case SYS_RES_MEMORY:
-               tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE);
-               if (tag == NULL)
-                       return (ENOMEM);
-               rman_set_bustag(r, tag);
-               rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] +
-                   rman_get_start(r));
-               break;
-       case SYS_RES_IOPORT:
-               rman_set_bustag(r, sc->sc_pci_iot);
-               rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] +
-                   rman_get_start(r));
-               break;
-       }
-       return (rman_activate_resource(r));
-}
-
-static int
-fire_adjust_resource(device_t bus, device_t child, int type,
-    struct resource *r, u_long start, u_long end)
-{
-       struct fire_softc *sc;
-       struct rman *rm;
-
-       sc = device_get_softc(bus);
-       switch (type) {
-       case SYS_RES_IRQ:
-               return (bus_generic_adjust_resource(bus, child, type, r,
-                   start, end));
-       case SYS_RES_MEMORY:
-               rm = &sc->sc_pci_mem_rman;
-               break;
-       case SYS_RES_IOPORT:
-               rm = &sc->sc_pci_io_rman;
-               break;
-       default:
-               return (EINVAL);
-       }
-       if (rman_is_region_manager(r, rm) == 0)
-               return (EINVAL);
-       return (rman_adjust_resource(r, start, end));
-}
-
-static bus_dma_tag_t
-fire_get_dma_tag(device_t bus, device_t child __unused)
-{
-       struct fire_softc *sc;
-
-       sc = device_get_softc(bus);
-       return (sc->sc_pci_dmat);
-}
-
-static phandle_t
-fire_get_node(device_t bus, device_t child __unused)
-{
-       struct fire_softc *sc;
-
-       sc = device_get_softc(bus);
-       /* We only have one child, the PCI bus, which needs our own node. */
-       return (sc->sc_node);
+       return (ofw_pci_alloc_resource(bus, child, type, rid, start, end,
+           count, flags));
 }
 
 static u_int

Modified: head/sys/sparc64/pci/firereg.h
==============================================================================
--- head/sys/sparc64/pci/firereg.h      Sat Sep 12 21:23:24 2015        
(r287725)
+++ head/sys/sparc64/pci/firereg.h      Sat Sep 12 22:49:32 2015        
(r287726)
@@ -30,7 +30,6 @@
 #define        _SPARC64_PCI_FIREREG_H_
 
 #define        FIRE_NINTR                              3       /* 2 OFW + 1 
MSIq */
-#define        FIRE_NRANGE                             4
 #define        FIRE_NREG                               2
 
 #define        FIRE_PCI                                0

Modified: head/sys/sparc64/pci/firevar.h
==============================================================================
--- head/sys/sparc64/pci/firevar.h      Sat Sep 12 21:23:24 2015        
(r287725)
+++ head/sys/sparc64/pci/firevar.h      Sat Sep 12 22:49:32 2015        
(r287726)
@@ -32,6 +32,12 @@
 #define        _SPARC64_PCI_FIREVAR_H_
 
 struct fire_softc {
+       /*
+        * This is here so that we can hook up the common bus interface
+        * methods in ofw_pci.c directly.
+        */
+       struct ofw_pci_softc            sc_ops;
+
        struct iommu_state              sc_is;
        struct bus_dma_methods          sc_dma_methods;
 
@@ -42,13 +48,6 @@ struct fire_softc {
        struct resource                 *sc_irq_res[FIRE_NINTR];
        void                            *sc_ihand[FIRE_NINTR];
 
-       struct rman                     sc_pci_mem_rman;
-       struct rman                     sc_pci_io_rman;
-       bus_space_handle_t              sc_pci_bh[FIRE_NRANGE];
-       bus_space_tag_t                 sc_pci_cfgt;
-       bus_space_tag_t                 sc_pci_iot;
-       bus_dma_tag_t                   sc_pci_dmat;
-
        device_t                        sc_dev;
 
        uint64_t                        *sc_msiq;
@@ -66,8 +65,6 @@ struct fire_softc {
        uint32_t                        sc_msiq_first;
        uint32_t                        sc_msiq_ino_first;
 
-       phandle_t                       sc_node;
-
        u_int                           sc_mode;
 #define        FIRE_MODE_FIRE                  0
 #define        FIRE_MODE_OBERON                1
@@ -87,11 +84,6 @@ struct fire_softc {
        uint32_t                        sc_stats_tlu_oe_rx_err;
        uint32_t                        sc_stats_tlu_oe_tx_err;
        uint32_t                        sc_stats_ubc_dmardue;
-
-       uint8_t                         sc_pci_secbus;
-       uint8_t                         sc_pci_subbus;
-
-       struct ofw_bus_iinfo            sc_pci_iinfo;
 };
 
 #endif /* !_SPARC64_PCI_FIREVAR_H_ */

Copied and modified: head/sys/sparc64/pci/ofw_pci.c (from r170929, 
head/sys/sparc64/pci/ofw_pci.c)
==============================================================================
--- head/sys/sparc64/pci/ofw_pci.c      Mon Jun 18 21:46:07 2007        
(r170929, copy source)
+++ head/sys/sparc64/pci/ofw_pci.c      Sat Sep 12 22:49:32 2015        
(r287726)
@@ -1,6 +1,7 @@
 /*-
  * Copyright (c) 1999, 2000 Matthew R. Green
  * Copyright (c) 2001 - 2003 by Thomas Moestl <[email protected]>
+ * Copyright (c) 2005 - 2015 by Marius Strobl <[email protected]>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,42 +36,371 @@ __FBSDID("$FreeBSD$");
 #include "opt_ofw_pci.h"
 
 #include <sys/param.h>
-#include <sys/kernel.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/rman.h>
 
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_pci.h>
 #include <dev/ofw/openfirm.h>
 
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <machine/asi.h>
 #include <machine/bus.h>
+#include <machine/bus_private.h>
+#include <machine/cpufunc.h>
+#include <machine/fsr.h>
+#include <machine/resource.h>
 
 #include <sparc64/pci/ofw_pci.h>
 
-static uint8_t pci_bus_cnt;
-static phandle_t *pci_bus_map;
-static int pci_bus_map_sz;
-
-#define        PCI_BUS_MAP_INC 10
-
-uint8_t
-ofw_pci_alloc_busno(phandle_t node)
-{
-       phandle_t *om;
-       int osz;
-       uint8_t n;
-
-       n = pci_bus_cnt++;
-       /* Establish a mapping between bus numbers and device nodes. */
-       if (n >= pci_bus_map_sz) {
-               osz = pci_bus_map_sz;
-               om = pci_bus_map;
-               pci_bus_map_sz = n + PCI_BUS_MAP_INC;
-               pci_bus_map = malloc(sizeof(*pci_bus_map) * pci_bus_map_sz,
-                   M_DEVBUF, M_WAITOK | M_ZERO);
-               if (om != NULL) {
-                       bcopy(om, pci_bus_map, sizeof(*om) * osz);
-                       free(om, M_DEVBUF);
+int
+ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize,
+    u_long memsize)
+{
+       struct ofw_pci_softc *sc;
+       struct ofw_pci_ranges *range;
+       phandle_t node;
+       uint32_t prop_array[2];
+       u_int i, j, nrange;
+
+       sc = device_get_softc(dev);
+       node = ofw_bus_get_node(dev);
+       sc->sc_node = node;
+       sc->sc_pci_dmat = dmat;
+
+       /* Initialize memory and I/O rmans. */
+       sc->sc_pci_io_rman.rm_type = RMAN_ARRAY;
+       sc->sc_pci_io_rman.rm_descr = "PCI I/O Ports";
+       if (rman_init(&sc->sc_pci_io_rman) != 0 ||
+           rman_manage_region(&sc->sc_pci_io_rman, 0, iosize) != 0) {
+               device_printf(dev, "failed to set up I/O rman\n");
+               return (ENXIO);
+       }
+       sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY;
+       sc->sc_pci_mem_rman.rm_descr = "PCI Memory";
+       if (rman_init(&sc->sc_pci_mem_rman) != 0 ||
+           rman_manage_region(&sc->sc_pci_mem_rman, 0, memsize) != 0) {
+               device_printf(dev, "failed to set up memory rman\n");
+               return (ENXIO);
+       }
+
+       /*
+        * Find the addresses of the various bus spaces.  The physical
+        * start addresses of the ranges are the configuration, I/O and
+        * memory handles.  There should not be multiple ones of one kind.
+        */
+       nrange = OF_getprop_alloc(node, "ranges", sizeof(*range),
+           (void **)&range);
+       for (i = 0; i < nrange; i++) {
+               j = OFW_PCI_RANGE_CS(&range[i]);
+               if (sc->sc_pci_bh[j] != 0) {
+                       device_printf(dev, "duplicate range for space %d\n",
+                           j);
+                       free(range, M_OFWPROP);
+                       return (EINVAL);
                }
+               sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]);
+       }
+       free(range, M_OFWPROP);
+
+       /*
+        * Make sure that the expected ranges are actually present.
+        * The OFW_PCI_CS_MEM64 one is not currently used.
+        */
+       if (sc->sc_pci_bh[OFW_PCI_CS_CONFIG] == 0) {
+               device_printf(dev, "missing CONFIG range\n");
+               return (ENXIO);
+       }
+       if (sc->sc_pci_bh[OFW_PCI_CS_IO] == 0) {
+               device_printf(dev, "missing IO range\n");
+               return (ENXIO);
+       }
+       if (sc->sc_pci_bh[OFW_PCI_CS_MEM32] == 0) {
+               device_printf(dev, "missing MEM32 range\n");
+               return (ENXIO);
+       }
+
+       /* Allocate our tags. */
+       sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE);
+       if (sc->sc_pci_iot == NULL) {
+               device_printf(dev, "could not allocate PCI I/O tag\n");
+               return (ENXIO);
+       }
+       sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE);
+       if (sc->sc_pci_cfgt == NULL) {
+               device_printf(dev,
+                   "could not allocate PCI configuration space tag\n");
+               return (ENXIO);
+       }
+
+       /*
+        * Get the bus range from the firmware.
+        */
+       i = OF_getprop(node, "bus-range", (void *)prop_array,
+           sizeof(prop_array));
+       if (i == -1) {
+               device_printf(dev, "could not get bus-range\n");
+               return (ENXIO);
+       }
+       if (i != sizeof(prop_array)) {
+               device_printf(dev, "broken bus-range (%d)", i);
+               return (EINVAL);
+       }
+       sc->sc_pci_secbus = prop_array[0];
+       sc->sc_pci_subbus = prop_array[1];
+       if (bootverbose != 0)
+               device_printf(dev, "bus range %u to %u; PCI bus %d\n",
+                   sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus);
+
+       ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t));
+
+       return (0);
+}
+
+uint32_t
+ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset,
+    u_int bus, u_int slot, u_int func, u_int reg, int width)
+{
+       struct ofw_pci_softc *sc;
+       bus_space_handle_t bh;
+       uint32_t r, wrd;
+       int i;
+       uint16_t shrt;
+       uint8_t byte;
+
+       sc = device_get_softc(dev);
+       if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
+           slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax)
+               return (-1);
+
+       bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
+       switch (width) {
+       case 1:
+               i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte);
+               r = byte;
+               break;
+       case 2:
+               i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt);
+               r = shrt;
+               break;
+       case 4:
+               i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd);
+               r = wrd;
+               break;
+       default:
+               panic("%s: bad width %d", __func__, width);
+               /* NOTREACHED */
+       }
+
+       if (i) {
+#ifdef OFW_PCI_DEBUG
+               printf("%s: read data error reading: %d.%d.%d: 0x%x\n",
+                   __func__, bus, slot, func, reg);
+#endif
+               r = -1;
+       }
+       return (r);
+}
+
+void
+ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset,
+    u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width)
+{
+       struct ofw_pci_softc *sc;
+       bus_space_handle_t bh;
+
+       sc = device_get_softc(dev);
+       if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
+           slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax)
+               return;
+
+       bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
+       switch (width) {
+       case 1:
+               bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val);
+               break;
+       case 2:
+               bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val);
+               break;
+       case 4:
+               bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val);
+               break;
+       default:
+               panic("%s: bad width %d", __func__, width);
+               /* NOTREACHED */
+       }
+}
+
+ofw_pci_intr_t
+ofw_pci_route_interrupt_common(device_t bridge, device_t dev, int pin)
+{
+       struct ofw_pci_softc *sc;
+       struct ofw_pci_register reg;
+       ofw_pci_intr_t pintr, mintr;
+
+       sc = device_get_softc(bridge);
+       pintr = pin;
+       if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo,
+           &reg, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
+           NULL) != 0)
+               return (mintr);
+       return (PCI_INVALID_IRQ);
+}
+
+void
+ofw_pci_dmamap_sync_stst_order_common(void)
+{
+       static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE);
+       register_t reg, s;
+
+       s = intr_disable();
+       reg = rd(fprs);
+       wr(fprs, reg | FPRS_FEF, 0);
+       __asm __volatile("stda %%f0, [%0] %1"
+           : : "r" (buf), "n" (ASI_BLK_COMMIT_S));
+       membar(Sync);
+       wr(fprs, reg, 0);
+       intr_restore(s);
+}
+
+int
+ofw_pci_read_ivar(device_t dev, device_t child __unused, int which,
+    uintptr_t *result)
+{
+       struct ofw_pci_softc *sc;
+
+       switch (which) {
+       case PCIB_IVAR_DOMAIN:
+               *result = device_get_unit(dev);
+               return (0);
+       case PCIB_IVAR_BUS:
+               sc = device_get_softc(dev);
+               *result = sc->sc_pci_secbus;
+               return (0);
+       }
+       return (ENOENT);
+}
+
+struct resource *
+ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+    u_long start, u_long end, u_long count, u_int flags)
+{
+       struct ofw_pci_softc *sc;
+       struct resource *rv;
+       struct rman *rm;
+
+       sc = device_get_softc(bus);
+       switch (type) {
+       case SYS_RES_IRQ:
+               /*
+                * XXX: Don't accept blank ranges for now, only single
+                * interrupts.  The other case should not happen with
+                * the MI PCI code ...
+                * XXX: This may return a resource that is out of the
+                * range that was specified.  Is this correct ...?
+                */
+               if (start != end)
+                       panic("%s: XXX: interrupt range", __func__);
+               return (bus_generic_alloc_resource(bus, child, type, rid,
+                   start, end, count, flags));
+       case SYS_RES_MEMORY:
+               rm = &sc->sc_pci_mem_rman;
+               break;
+       case SYS_RES_IOPORT:
+               rm = &sc->sc_pci_io_rman;
+               break;
+       default:
+               return (NULL);
+       }
+
+       rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
+           child);
+       if (rv == NULL)
+               return (NULL);
+       rman_set_rid(rv, *rid);
+
+       if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type,
+           *rid, rv) != 0) {
+               rman_release_resource(rv);
+               return (NULL);
        }
-       pci_bus_map[n] = node;
-       return (n);
+       return (rv);
+}
+
+int
+ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
+    struct resource *r)
+{
+       struct ofw_pci_softc *sc;
+       struct bus_space_tag *tag;
+
+       sc = device_get_softc(bus);
+       switch (type) {
+       case SYS_RES_IRQ:
+               return (bus_generic_activate_resource(bus, child, type, rid,
+                   r));
+       case SYS_RES_MEMORY:
+               tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE);
+               if (tag == NULL)
+                       return (ENOMEM);
+               rman_set_bustag(r, tag);
+               rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] +
+                   rman_get_start(r));
+               break;
+       case SYS_RES_IOPORT:
+               rman_set_bustag(r, sc->sc_pci_iot);
+               rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] +
+                   rman_get_start(r));
+               break;
+       }
+       return (rman_activate_resource(r));
+}
+
+int
+ofw_pci_adjust_resource(device_t bus, device_t child, int type,
+    struct resource *r, u_long start, u_long end)
+{
+       struct ofw_pci_softc *sc;
+       struct rman *rm;
+
+       sc = device_get_softc(bus);
+       switch (type) {
+       case SYS_RES_IRQ:
+               return (bus_generic_adjust_resource(bus, child, type, r,
+                   start, end));
+       case SYS_RES_MEMORY:
+               rm = &sc->sc_pci_mem_rman;
+               break;
+       case SYS_RES_IOPORT:
+               rm = &sc->sc_pci_io_rman;
+               break;
+       default:
+               return (EINVAL);
+       }
+       if (rman_is_region_manager(r, rm) == 0)
+               return (EINVAL);
+       return (rman_adjust_resource(r, start, end));
+}
+
+bus_dma_tag_t
+ofw_pci_get_dma_tag(device_t bus, device_t child __unused)
+{
+       struct ofw_pci_softc *sc;
+
+       sc = device_get_softc(bus);
+       return (sc->sc_pci_dmat);
+}
+
+phandle_t
+ofw_pci_get_node(device_t bus, device_t child __unused)
+{
+       struct ofw_pci_softc *sc;
+
+       sc = device_get_softc(bus);
+       /* We only have one child, the PCI bus, which needs our own node. */
+       return (sc->sc_node);
 }

Modified: head/sys/sparc64/pci/ofw_pci.h
==============================================================================
--- head/sys/sparc64/pci/ofw_pci.h      Sat Sep 12 21:23:24 2015        
(r287725)
+++ head/sys/sparc64/pci/ofw_pci.h      Sat Sep 12 22:49:32 2015        
(r287726)
@@ -62,6 +62,8 @@
 #ifndef _SPARC64_PCI_OFW_PCI_H_
 #define        _SPARC64_PCI_OFW_PCI_H_
 
+#include <sys/rman.h>
+
 #include <dev/ofw/ofw_bus_subr.h>
 
 #include "ofw_pci_if.h"
@@ -73,6 +75,7 @@ typedef uint32_t ofw_pci_intr_t;
 #define        OFW_PCI_CS_IO           0x01
 #define        OFW_PCI_CS_MEM32        0x02
 #define        OFW_PCI_CS_MEM64        0x03
+#define        OFW_PCI_NUM_CS          4
 
 /* OFW device types */
 #define        OFW_TYPE_PCI            "pci"
@@ -124,4 +127,44 @@ struct ofw_pci_ranges {
 /* default values */
 #define        OFW_PCI_LATENCY 64
 
+/*
+ * Common and generic parts of host-PCI-bridge support
+ */
+
+struct ofw_pci_softc {
+       struct rman             sc_pci_mem_rman;
+       struct rman             sc_pci_io_rman;
+
+       bus_space_handle_t      sc_pci_bh[OFW_PCI_NUM_CS];
+       bus_space_tag_t         sc_pci_cfgt;
+       bus_space_tag_t         sc_pci_iot;
+       bus_dma_tag_t           sc_pci_dmat;
+
+       struct ofw_bus_iinfo    sc_pci_iinfo;
+
+       phandle_t               sc_node;
+
+       uint8_t                 sc_pci_secbus;
+       uint8_t                 sc_pci_subbus;
+};
+
+int ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize,
+    u_long memsize);
+uint32_t ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset,
+    u_int bus, u_int slot, u_int func, u_int reg, int width);
+void ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset,
+    u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width);
+ofw_pci_intr_t ofw_pci_route_interrupt_common(device_t bridge, device_t dev,
+    int pin);
+
+void ofw_pci_dmamap_sync_stst_order_common(void);
+
+bus_activate_resource_t ofw_pci_activate_resource;
+bus_adjust_resource_t ofw_pci_adjust_resource;
+bus_alloc_resource_t ofw_pci_alloc_resource;
+bus_get_dma_tag_t ofw_pci_get_dma_tag;
+bus_read_ivar_t ofw_pci_read_ivar;
+
+ofw_bus_get_node_t ofw_pci_get_node;
+
 #endif /* ! _SPARC64_PCI_OFW_PCI_H_ */

Modified: head/sys/sparc64/pci/psycho.c
==============================================================================
--- head/sys/sparc64/pci/psycho.c       Sat Sep 12 21:23:24 2015        
(r287725)
+++ head/sys/sparc64/pci/psycho.c       Sat Sep 12 22:49:32 2015        
(r287726)
@@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysctl.h>
 
 #include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_pci.h>
 #include <dev/ofw/openfirm.h>

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to