summaryrefslogtreecommitdiffstats
path: root/sys/sparc64/pci/fire.c
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2011-10-02 23:22:38 +0000
committermarius <marius@FreeBSD.org>2011-10-02 23:22:38 +0000
commitb730263346b617e3949a799cd7cbbaec0a0faaba (patch)
tree8a3ccb0c4cbe92ab406722848f03d20132c1e280 /sys/sparc64/pci/fire.c
parent2dc050638298978fc3e396cc2d0206c599dc8c46 (diff)
downloadFreeBSD-src-b730263346b617e3949a799cd7cbbaec0a0faaba.zip
FreeBSD-src-b730263346b617e3949a799cd7cbbaec0a0faaba.tar.gz
Make sparc64 compatible with NEW_PCIB and enable it:
- Implement bus_adjust_resource() methods as far as necessary and in non-PCI bridge drivers as far as feasible without rototilling them. - As NEW_PCIB does a layering violation by activating resources at layers above pci(4) without previously bubbling up their allocation there, move the assignment of bus tags and handles from the bus_alloc_resource() to the bus_activate_resource() methods like at least the other NEW_PCIB enabled architectures do. This is somewhat unfortunate as previously sparc64 (ab)used resource activation to indicate whether SYS_RES_MEMORY resources should be mapped into KVA, which is only necessary if their going to be accessed via the pointer returned from rman_get_virtual() but not for bus_space(9) as the later always uses physical access on sparc64. Besides wasting KVA if we always map in SYS_RES_MEMORY resources, a driver also may deliberately not map them in if the firmware already has done so, possibly in a special way. So in order to still allow a driver to decide whether a SYS_RES_MEMORY resource should be mapped into KVA we let it indicate that by calling bus_space_map(9) with BUS_SPACE_MAP_LINEAR as actually documented in the bus_space(9) page. This is implemented by allocating a separate bus tag per SYS_RES_MEMORY resource and passing the resource via the previously unused bus tag cookie so we later on can call rman_set_virtual() in sparc64_bus_mem_map(). As a side effect this now also allows to actually indicate that a SYS_RES_MEMORY resource should be mapped in as cacheable and/or read-only via BUS_SPACE_MAP_CACHEABLE and BUS_SPACE_MAP_READONLY respectively. - Do some minor cleanup like taking advantage of rman_init_from_resource(), factor out the common part of bus tag allocation into a newly added sparc64_alloc_bus_tag(), hook up some missing newbus methods and replace some homegrown versions with the generic counterparts etc. - While at it, let apb_attach() (which can't use the generic NEW_PCIB code as APB bridges just don't have the base and limit registers implemented) regarding the config space registers cached in pcib_softc and the SYSCTL reporting nodes set up.
Diffstat (limited to 'sys/sparc64/pci/fire.c')
-rw-r--r--sys/sparc64/pci/fire.c159
1 files changed, 67 insertions, 92 deletions
diff --git a/sys/sparc64/pci/fire.c b/sys/sparc64/pci/fire.c
index 0402896..5a1e08a 100644
--- a/sys/sparc64/pci/fire.c
+++ b/sys/sparc64/pci/fire.c
@@ -85,7 +85,6 @@ __FBSDID("$FreeBSD$");
struct fire_msiqarg;
-static bus_space_tag_t fire_alloc_bus_tag(struct fire_softc *sc, int type);
static const struct fire_desc *fire_get_desc(device_t dev);
static void fire_dmamap_sync(bus_dma_tag_t dt __unused, bus_dmamap_t map,
bus_dmasync_op_t op);
@@ -113,11 +112,11 @@ 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_deactivate_resource_t fire_deactivate_resource;
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;
@@ -127,7 +126,6 @@ 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 bus_release_resource_t fire_release_resource;
static pcib_route_interrupt_t fire_route_interrupt;
static bus_setup_intr_t fire_setup_intr;
static bus_teardown_intr_t fire_teardown_intr;
@@ -147,9 +145,10 @@ static device_method_t fire_methods[] = {
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_deactivate_resource, fire_deactivate_resource),
- DEVMETHOD(bus_release_resource, fire_release_resource),
+ DEVMETHOD(bus_activate_resource, fire_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_adjust_resource, fire_adjust_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
DEVMETHOD(bus_get_dma_tag, fire_get_dma_tag),
/* pcib interface */
@@ -757,13 +756,19 @@ fire_attach(device_t dev)
free(range, M_OFWPROP);
/* Allocate our tags. */
- sc->sc_pci_memt = fire_alloc_bus_tag(sc, PCI_MEMORY_BUS_SPACE);
- sc->sc_pci_iot = fire_alloc_bus_tag(sc, PCI_IO_BUS_SPACE);
- sc->sc_pci_cfgt = fire_alloc_bus_tag(sc, PCI_CONFIG_BUS_SPACE);
+ sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, rman_get_bustag(
+ sc->sc_mem_res[FIRE_PCI]), PCI_IO_BUS_SPACE, NULL);
+ 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, rman_get_bustag(
+ sc->sc_mem_res[FIRE_PCI]), PCI_CONFIG_BUS_SPACE, NULL);
+ if (sc->sc_pci_cfgt == NULL)
+ panic("%s: could not allocate PCI configuration space tag",
+ __func__);
if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0,
sc->sc_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.is_pmaxaddr,
0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0)
- panic("%s: bus_dma_tag_create failed", __func__);
+ 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;
@@ -2015,14 +2020,10 @@ fire_alloc_resource(device_t bus, device_t child, int type, int *rid,
struct fire_softc *sc;
struct resource *rv;
struct rman *rm;
- bus_space_tag_t bt;
- bus_space_handle_t bh;
- int needactivate = flags & RF_ACTIVE;
-
- flags &= ~RF_ACTIVE;
sc = device_get_softc(bus);
- if (type == SYS_RES_IRQ) {
+ switch (type) {
+ case SYS_RES_IRQ:
/*
* XXX: Don't accept blank ranges for now, only single
* interrupts. The other case should not happen with
@@ -2034,38 +2035,28 @@ fire_alloc_resource(device_t bus, device_t child, int type, int *rid,
panic("%s: XXX: interrupt range", __func__);
if (*rid == 0)
start = end = INTMAP_VEC(sc->sc_ign, end);
- return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
- type, rid, start, end, count, flags));
- }
- switch (type) {
+ return (bus_generic_alloc_resource(bus, child, type, rid,
+ start, end, count, flags));
case SYS_RES_MEMORY:
rm = &sc->sc_pci_mem_rman;
- bt = sc->sc_pci_memt;
- bh = sc->sc_pci_bh[OFW_PCI_CS_MEM32];
break;
case SYS_RES_IOPORT:
rm = &sc->sc_pci_io_rman;
- bt = sc->sc_pci_iot;
- bh = sc->sc_pci_bh[OFW_PCI_CS_IO];
break;
default:
return (NULL);
- /* NOTREACHED */
}
- rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
+ child);
if (rv == NULL)
return (NULL);
rman_set_rid(rv, *rid);
- bh += rman_get_start(rv);
- rman_set_bustag(rv, bt);
- rman_set_bushandle(rv, bh);
-
- if (needactivate) {
- if (bus_activate_resource(child, type, *rid, rv)) {
- rman_release_resource(rv);
- return (NULL);
- }
+
+ if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type,
+ *rid, rv) != 0) {
+ rman_release_resource(rv);
+ return (NULL);
}
return (rv);
}
@@ -2074,56 +2065,56 @@ static int
fire_activate_resource(device_t bus, device_t child, int type, int rid,
struct resource *r)
{
- void *p;
- int error;
+ struct fire_softc *sc;
+ struct bus_space_tag *tag;
- if (type == SYS_RES_IRQ)
- return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child,
- type, rid, r));
- if (type == SYS_RES_MEMORY) {
- /*
- * Need to memory-map the device space, as some drivers
- * depend on the virtual address being set and usable.
- */
- error = sparc64_bus_mem_map(rman_get_bustag(r),
- rman_get_bushandle(r), rman_get_size(r), 0, 0, &p);
- if (error != 0)
- return (error);
- rman_set_virtual(r, p);
+ 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, rman_get_bustag(
+ sc->sc_mem_res[FIRE_PCI]), PCI_MEMORY_BUS_SPACE, NULL);
+ 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_deactivate_resource(device_t bus, device_t child, int type, int rid,
- struct resource *r)
+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;
- if (type == SYS_RES_IRQ)
- return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus), child,
- type, rid, r));
- if (type == SYS_RES_MEMORY) {
- sparc64_bus_mem_unmap(rman_get_virtual(r), rman_get_size(r));
- rman_set_virtual(r, NULL);
- }
- return (rman_deactivate_resource(r));
-}
-
-static int
-fire_release_resource(device_t bus, device_t child, int type, int rid,
- struct resource *r)
-{
- int error;
-
- if (type == SYS_RES_IRQ)
- return (BUS_RELEASE_RESOURCE(device_get_parent(bus), child,
- type, rid, r));
- if (rman_get_flags(r) & RF_ACTIVE) {
- error = bus_deactivate_resource(child, type, rid, r);
- if (error)
- return (error);
+ 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);
}
- return (rman_release_resource(r));
+ if (rman_is_region_manager(r, rm) == 0)
+ return (EINVAL);
+ return (rman_adjust_resource(r, start, end));
}
static bus_dma_tag_t
@@ -2145,22 +2136,6 @@ fire_get_node(device_t bus, device_t child __unused)
return (sc->sc_node);
}
-static bus_space_tag_t
-fire_alloc_bus_tag(struct fire_softc *sc, int type)
-{
- bus_space_tag_t bt;
-
- bt = malloc(sizeof(struct bus_space_tag), M_DEVBUF,
- M_NOWAIT | M_ZERO);
- if (bt == NULL)
- panic("%s: out of memory", __func__);
-
- bt->bst_cookie = sc;
- bt->bst_parent = rman_get_bustag(sc->sc_mem_res[FIRE_PCI]);
- bt->bst_type = type;
- return (bt);
-}
-
static u_int
fire_get_timecount(struct timecounter *tc)
{
OpenPOWER on IntegriCloud