summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2004-01-11 06:52:31 +0000
committerimp <imp@FreeBSD.org>2004-01-11 06:52:31 +0000
commitbf3ace5acaa8f607b40f3c34044ebb974a8de294 (patch)
treee3cb460b05334390a453e604741ee398c13fc4ae
parent6d7e46b26052df070fb25217d8bd904c80a0740a (diff)
downloadFreeBSD-src-bf3ace5acaa8f607b40f3c34044ebb974a8de294.zip
FreeBSD-src-bf3ace5acaa8f607b40f3c34044ebb974a8de294.tar.gz
Add support for subtractive decoding bridges. These bridges pass all
signals to addresses to the child busses. Typically, ProgIf of 1 means a subtractive bridge. However, Intel has a whole lot of ones with a ProgIf of 80 that are also subtractive. We cope with these bridges too. This eliminates hw.pci.allow_unsupported_io_range because that had almost the same effect as these patches (almost means 'buggy'). Remove the bogus checks for ISA bus locations: these cycles aren't special and are only passed by transparent bridges. We allow any range to succeed. If the range is a superset of the range that's decoded, trim the resource to that range. Otherwise, pass the range unchanged. This will change the location that PC Card and CardBus cards are attached. This might bogusly cause some overlapping allocation that wasn't present before, but the overlapping fixes need to be in the pci level. There's also a few formatting changes here.
-rw-r--r--sys/dev/pci/pci_pci.c285
-rw-r--r--sys/dev/pci/pcib_private.h2
2 files changed, 128 insertions, 159 deletions
diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index 3b8ec32..eeba000 100644
--- a/sys/dev/pci/pci_pci.c
+++ b/sys/dev/pci/pci_pci.c
@@ -92,18 +92,6 @@ devclass_t pcib_devclass;
DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0);
/*
- * sysctl and tunable vars
- */
-static int pci_allow_unsupported_io_range = 0;
-TUNABLE_INT("hw.pci.allow_unsupported_io_range",
- (int *)&pci_allow_unsupported_io_range);
-SYSCTL_DECL(_hw_pci);
-SYSCTL_INT(_hw_pci, OID_AUTO, allow_unsupported_io_range, CTLFLAG_RDTUN,
- &pci_allow_unsupported_io_range, 0,
- "Allows the PCI Bridge to pass through an unsupported memory range "
- "assigned by the BIOS.");
-
-/*
* Generic device interface
*/
static int
@@ -173,7 +161,7 @@ pcib_attach_common(device_t dev)
* Quirk handling.
*/
switch (pci_get_devid(dev)) {
- case 0x12258086: /* Intel 82454KX/GX (Orion) */
+ case 0x12258086: /* Intel 82454KX/GX (Orion) */
{
uint8_t supbus;
@@ -182,16 +170,42 @@ pcib_attach_common(device_t dev)
sc->secbus = supbus + 1;
sc->subbus = supbus + 1;
}
+ break;
}
+
+ /*
+ * The i82380FB mobile docking controller is a PCI-PCI bridge,
+ * and it is a subtractive bridge. However, the ProgIf is wrong
+ * so the normal setting of PCIB_SUBTRACTIVE bit doesn't
+ * happen. There's also a Toshiba bridge that behaves this
+ * way.
+ */
+ case 0x124b8086: /* Intel 82380FB Mobile */
+ case 0x060513d7: /* Toshiba ???? */
+ sc->flags |= PCIB_SUBTRACTIVE;
break;
}
+ /*
+ * Intel 815, 845 and other chipsets say they are PCI-PCI bridges,
+ * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM,
+ * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese.
+ * This means they act as if they were subtractively decoding
+ * bridges and pass all transactions. Mark them and real ProgIf 1
+ * parts as subtractive.
+ */
+ if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 ||
+ pci_read_config(dev, PCIR_PROGIF, 1) == 1)
+ sc->flags |= PCIB_SUBTRACTIVE;
+
if (bootverbose) {
device_printf(dev, " secondary bus %d\n", sc->secbus);
device_printf(dev, " subordinate bus %d\n", sc->subbus);
device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit);
device_printf(dev, " memory decode 0x%x-0x%x\n", sc->membase, sc->memlimit);
device_printf(dev, " prefetched decode 0x%x-0x%x\n", sc->pmembase, sc->pmemlimit);
+ if (sc->flags & PCIB_SUBTRACTIVE)
+ device_printf(dev, " Subtractively decoded bridge.\n");
}
/*
@@ -252,37 +266,12 @@ pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
}
/*
- * Is this a decoded ISA I/O port address? Note, we need to do the mask that
- * we do below because of the ISA alias addresses. I'm not 100% sure that
- * this is correct. Maybe the bridge needs to be subtractive decode for
- * this to work?
- */
-static int
-pcib_is_isa_io(u_long start)
-{
- if ((start & 0xfffUL) > 0x3ffUL || start == 0)
- return (0);
- return (1);
-}
-
-/*
- * Is this a decoded ISA memory address?
- */
-static int
-pcib_is_isa_mem(u_long start)
-{
- if (start > 0xfffffUL || start == 0)
- return (0);
- return (1);
-}
-
-/*
* Is the prefetch window open (eg, can we allocate memory in it?)
*/
static int
pcib_is_prefetch_open(struct pcib_softc *sc)
{
- return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit);
+ return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit);
}
/*
@@ -291,7 +280,7 @@ pcib_is_prefetch_open(struct pcib_softc *sc)
static int
pcib_is_nonprefetch_open(struct pcib_softc *sc)
{
- return (sc->membase > 0 && sc->membase < sc->memlimit);
+ return (sc->membase > 0 && sc->membase < sc->memlimit);
}
/*
@@ -300,7 +289,7 @@ pcib_is_nonprefetch_open(struct pcib_softc *sc)
static int
pcib_is_io_open(struct pcib_softc *sc)
{
- return (sc->iobase > 0 && sc->iobase < sc->iolimit);
+ return (sc->iobase > 0 && sc->iobase < sc->iolimit);
}
/*
@@ -311,144 +300,122 @@ struct resource *
pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
- struct pcib_softc *sc = device_get_softc(dev);
- int ok;
+ struct pcib_softc *sc = device_get_softc(dev);
+ int ok;
- /*
- * If this is a "default" allocation against this rid, we can't work
- * out where it's coming from (we should actually never see these) so we
- * just have to punt.
- */
- if ((start == 0) && (end == ~0)) {
- device_printf(dev, "can't decode default resource id %d for %s%d, bypassing\n",
- *rid, device_get_name(child), device_get_unit(child));
- } else {
/*
* Fail the allocation for this range if it's not supported.
*/
switch (type) {
case SYS_RES_IOPORT:
- ok = 1;
- if (!pcib_is_isa_io(start)) {
ok = 0;
- if (pcib_is_io_open(sc))
- ok = (start >= sc->iobase && end <= sc->iolimit);
- if (!pci_allow_unsupported_io_range) {
- if (!ok) {
- if (start < sc->iobase)
- start = sc->iobase;
- if (end > sc->iolimit)
- end = sc->iolimit;
- }
+ if (!pcib_is_io_open(sc))
+ break;
+ ok = (start >= sc->iobase && end <= sc->iolimit);
+ if ((sc->flags & PCIB_SUBTRACTIVE) == 0) {
+ if (!ok) {
+ if (start < sc->iobase)
+ start = sc->iobase;
+ if (end > sc->iolimit)
+ end = sc->iolimit;
+ }
} else {
- if (start < sc->iobase)
- printf("start (%lx) < sc->iobase (%x)\n", start,
- sc->iobase);
- if (end > sc->iolimit)
- printf("end (%lx) > sc->iolimit (%x)\n",
- end, sc->iolimit);
- if (end < start)
- printf("end (%lx) < start (%lx)\n", end, start);
+ ok = 1;
+ if (start < sc->iobase && end > sc->iolimit) {
+ start = sc->iobase;
+ end = sc->iolimit;
+ }
+
}
- }
- if (end < start) {
- start = 0;
- end = 0;
- ok = 0;
- }
- if (!ok) {
- device_printf(dev, "device %s%d requested unsupported I/O "
- "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n",
- device_get_name(child), device_get_unit(child), start, end,
- sc->iobase, sc->iolimit);
- return (NULL);
- }
- if (bootverbose)
- device_printf(sc->dev, "device %s%d requested decoded I/O range 0x%lx-0x%lx\n",
- device_get_name(child), device_get_unit(child), start, end);
- break;
+ if (end < start) {
+ device_printf(dev, "ioport: end (%lx) < start (%lx)\n", end, start);
+ start = 0;
+ end = 0;
+ ok = 0;
+ }
+ if (!ok) {
+ device_printf(dev, "device %s requested unsupported I/O "
+ "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n",
+ device_get_nameunit(child), start, end,
+ sc->iobase, sc->iolimit);
+ return (NULL);
+ }
+ if (bootverbose)
+ device_printf(dev, "device %s requested decoded I/O range 0x%lx-0x%lx\n",
+ device_get_nameunit(child), start, end);
+ break;
case SYS_RES_MEMORY:
- ok = 1;
- if (!pcib_is_isa_mem(start)) {
ok = 0;
if (pcib_is_nonprefetch_open(sc))
- ok = ok || (start >= sc->membase && end <= sc->memlimit);
+ ok = ok || (start >= sc->membase && end <= sc->memlimit);
if (pcib_is_prefetch_open(sc))
- ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit);
- if (!pci_allow_unsupported_io_range) {
- if (!ok) {
- ok = 1;
- if (flags & RF_PREFETCHABLE) {
- if (pcib_is_prefetch_open(sc)) {
- if (start < sc->pmembase)
- start = sc->pmembase;
- if (end > sc->pmemlimit)
- end = sc->pmemlimit;
- } else {
- ok = 0;
- }
- } else { /* non-prefetchable */
- if (pcib_is_nonprefetch_open(sc)) {
- if (start < sc->membase)
- start = sc->membase;
- if (end > sc->memlimit)
- end = sc->memlimit;
- } else {
- ok = 0;
- }
+ ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit);
+ if ((sc->flags & PCIB_SUBTRACTIVE) == 0) {
+ if (!ok) {
+ ok = 1;
+ if (flags & RF_PREFETCHABLE) {
+ if (pcib_is_prefetch_open(sc)) {
+ if (start < sc->pmembase)
+ start = sc->pmembase;
+ if (end > sc->pmemlimit)
+ end = sc->pmemlimit;
+ } else {
+ ok = 0;
+ }
+ } else { /* non-prefetchable */
+ if (pcib_is_nonprefetch_open(sc)) {
+ if (start < sc->membase)
+ start = sc->membase;
+ if (end > sc->memlimit)
+ end = sc->memlimit;
+ } else {
+ ok = 0;
+ }
+ }
}
- }
} else if (!ok) {
- ok = 1; /* pci_allow_unsupported_ranges -> always ok */
- if (pcib_is_nonprefetch_open(sc)) {
- if (start < sc->membase)
- printf("start (%lx) < sc->membase (%x)\n",
- start, sc->membase);
- if (end > sc->memlimit)
- printf("end (%lx) > sc->memlimit (%x)\n",
- end, sc->memlimit);
- }
- if (pcib_is_prefetch_open(sc)) {
- if (start < sc->pmembase)
- printf("start (%lx) < sc->pmembase (%x)\n",
- start, sc->pmembase);
- if (end > sc->pmemlimit)
- printf("end (%lx) > sc->pmemlimit (%x)\n",
- end, sc->memlimit);
- }
- if (end < start)
- printf("end (%lx) < start (%lx)\n", end, start);
+ ok = 1; /* subtractive bridge: always ok */
+ if (pcib_is_nonprefetch_open(sc)) {
+ if (start < sc->membase && end > sc->memlimit) {
+ start = sc->membase;
+ end = sc->memlimit;
+ }
+ }
+ if (pcib_is_prefetch_open(sc)) {
+ if (start < sc->pmembase && end > sc->pmemlimit) {
+ start = sc->pmembase;
+ end = sc->pmemlimit;
+ }
+ }
}
- }
- if (end < start) {
- start = 0;
- end = 0;
- ok = 0;
- }
- if (!ok && bootverbose)
- device_printf(dev,
- "device %s%d requested unsupported memory range "
- "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n",
- device_get_name(child), device_get_unit(child), start,
- end, sc->membase, sc->memlimit, sc->pmembase,
- sc->pmemlimit);
- if (!ok)
- return (NULL);
- if (bootverbose)
- device_printf(sc->dev, "device %s%d requested decoded memory range 0x%lx-0x%lx\n",
- device_get_name(child), device_get_unit(child), start, end);
- break;
+ if (end < start) {
+ device_printf(dev, "memory: end (%lx) < start (%lx)\n", end, start);
+ start = 0;
+ end = 0;
+ ok = 0;
+ }
+ if (!ok && bootverbose)
+ device_printf(dev,
+ "device %s requested unsupported memory range "
+ "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n",
+ device_get_nameunit(child), start, end,
+ sc->membase, sc->memlimit, sc->pmembase,
+ sc->pmemlimit);
+ if (!ok)
+ return (NULL);
+ if (bootverbose)
+ device_printf(dev,"device %s requested decoded memory range 0x%lx-0x%lx\n",
+ device_get_nameunit(child), start, end);
+ break;
default:
- break;
+ break;
}
- }
-
- /*
- * Bridge is OK decoding this resource, so pass it up.
- */
- return(bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags));
+ /*
+ * Bridge is OK decoding this resource, so pass it up.
+ */
+ return (bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags));
}
/*
diff --git a/sys/dev/pci/pcib_private.h b/sys/dev/pci/pcib_private.h
index 870b306..a4acaab 100644
--- a/sys/dev/pci/pcib_private.h
+++ b/sys/dev/pci/pcib_private.h
@@ -44,6 +44,8 @@
struct pcib_softc
{
device_t dev;
+ uint32_t flags; /* flags */
+#define PCIB_SUBTRACTIVE 0x1
uint16_t command; /* command register */
uint8_t secbus; /* secondary bus number */
uint8_t subbus; /* subordinate bus number */
OpenPOWER on IntegriCloud