summaryrefslogtreecommitdiffstats
path: root/sys/sparc64/pci/apb.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/apb.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/apb.c')
-rw-r--r--sys/sparc64/pci/apb.c62
1 files changed, 57 insertions, 5 deletions
diff --git a/sys/sparc64/pci/apb.c b/sys/sparc64/pci/apb.c
index 87f1821..7d42b7b 100644
--- a/sys/sparc64/pci/apb.c
+++ b/sys/sparc64/pci/apb.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/rman.h>
+#include <sys/sysctl.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/openfirm.h>
@@ -77,6 +78,7 @@ struct apb_softc {
static device_probe_t apb_probe;
static device_attach_t apb_attach;
static bus_alloc_resource_t apb_alloc_resource;
+static bus_adjust_resource_t apb_adjust_resource;
static device_method_t apb_methods[] = {
/* Device interface */
@@ -85,6 +87,8 @@ static device_method_t apb_methods[] = {
/* Bus interface */
DEVMETHOD(bus_alloc_resource, apb_alloc_resource),
+ DEVMETHOD(bus_adjust_resource, apb_adjust_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
/* pcib interface */
DEVMETHOD(pcib_route_interrupt, ofw_pcib_gen_route_interrupt),
@@ -158,6 +162,8 @@ static int
apb_attach(device_t dev)
{
struct apb_softc *sc;
+ struct sysctl_ctx_list *sctx;
+ struct sysctl_oid *soid;
sc = device_get_softc(dev);
@@ -165,12 +171,41 @@ apb_attach(device_t dev)
* Get current bridge configuration.
*/
sc->sc_bsc.ops_pcib_sc.domain = pci_get_domain(dev);
+ sc->sc_bsc.ops_pcib_sc.secstat =
+ pci_read_config(dev, PCIR_SECSTAT_1, 2);
+ sc->sc_bsc.ops_pcib_sc.command =
+ pci_read_config(dev, PCIR_COMMAND, 2);
+ sc->sc_bsc.ops_pcib_sc.pribus =
+ pci_read_config(dev, PCIR_PRIBUS_1, 1);
sc->sc_bsc.ops_pcib_sc.secbus =
pci_read_config(dev, PCIR_SECBUS_1, 1);
sc->sc_bsc.ops_pcib_sc.subbus =
pci_read_config(dev, PCIR_SUBBUS_1, 1);
+ sc->sc_bsc.ops_pcib_sc.bridgectl =
+ pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
+ sc->sc_bsc.ops_pcib_sc.seclat =
+ pci_read_config(dev, PCIR_SECLAT_1, 1);
sc->sc_iomap = pci_read_config(dev, APBR_IOMAP, 1);
sc->sc_memmap = pci_read_config(dev, APBR_MEMMAP, 1);
+
+ /*
+ * Setup SYSCTL reporting nodes.
+ */
+ sctx = device_get_sysctl_ctx(dev);
+ soid = device_get_sysctl_tree(dev);
+ SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain",
+ CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.domain, 0,
+ "Domain number");
+ SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
+ CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.pribus, 0,
+ "Primary bus number");
+ SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
+ CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.secbus, 0,
+ "Secondary bus number");
+ SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
+ CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.subbus, 0,
+ "Subordinate bus number");
+
ofw_pcib_gen_setup(dev);
if (bootverbose) {
@@ -233,9 +268,9 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid,
"%s requested decoded I/O range 0x%lx-0x%lx\n",
device_get_nameunit(child), start, end);
break;
-
case SYS_RES_MEMORY:
- if (!apb_checkrange(sc->sc_memmap, APB_MEM_SCALE, start, end)) {
+ if (!apb_checkrange(sc->sc_memmap, APB_MEM_SCALE, start,
+ end)) {
device_printf(dev, "device %s requested unsupported "
"memory range 0x%lx-0x%lx\n",
device_get_nameunit(child), start, end);
@@ -246,9 +281,6 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid,
"%s requested decoded memory range 0x%lx-0x%lx\n",
device_get_nameunit(child), start, end);
break;
-
- default:
- break;
}
passup:
@@ -258,3 +290,23 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid,
return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
count, flags));
}
+
+static int
+apb_adjust_resource(device_t dev, device_t child, int type,
+ struct resource *r, u_long start, u_long end)
+{
+ struct apb_softc *sc;
+
+ sc = device_get_softc(dev);
+ switch (type) {
+ case SYS_RES_IOPORT:
+ if (!apb_checkrange(sc->sc_iomap, APB_IO_SCALE, start, end))
+ return (ENXIO);
+ break;
+ case SYS_RES_MEMORY:
+ if (!apb_checkrange(sc->sc_memmap, APB_MEM_SCALE, start, end))
+ return (ENXIO);
+ break;
+ }
+ return (bus_generic_adjust_resource(dev, child, type, r, start, end));
+}
OpenPOWER on IntegriCloud