summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2002-12-03 08:34:20 +0000
committerimp <imp@FreeBSD.org>2002-12-03 08:34:20 +0000
commita633045c6d06c932a4a94e221732a1c41ac9d8c2 (patch)
tree1dea01a64d68833a042698899963b3a80bc91cb8 /sys
parentfb2ab15ed1ce4f7d83c60c06e101b090808f35f7 (diff)
downloadFreeBSD-src-a633045c6d06c932a4a94e221732a1c41ac9d8c2.zip
FreeBSD-src-a633045c6d06c932a4a94e221732a1c41ac9d8c2.tar.gz
Properly account for prefetchable memory when a request is being made.
We allow the request to go through if it matches either a prefetchable or a non-prefetchable part of the bridge. We do not check to make sure it is the right kind of memory because most drivers to not yet properly set RF_PREFETCHABLE (only cardbus seems to do so, and I'm not entirely sure it does it right). RF_PREFETCHABLE was invented for cardbus, so hasn't been properly documented yet. This is still overridable by hw.pci.allow_unsupported_io_ranges, but the need for that is greatly reduced, especially for the nvida driver. Approved by: re Reviewed by: jhb and many testers Submitted by: Matt Emmerton (although this has been reworked somewhat)
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/pci_pci.c159
1 files changed, 112 insertions, 47 deletions
diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index a0e864a..40f8b8c 100644
--- a/sys/dev/pci/pci_pci.c
+++ b/sys/dev/pci/pci_pci.c
@@ -38,6 +38,8 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
#include <sys/sysctl.h>
#include <machine/resource.h>
@@ -252,7 +254,8 @@ 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.
+ * this is correct. Maybe the bridge needs to be subtractive decode for
+ * this to work?
*/
static int
pcib_is_isa_io(u_long start)
@@ -274,6 +277,33 @@ pcib_is_isa_mem(u_long start)
}
/*
+ * 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);
+}
+
+/*
+ * Is the nonprefetch window open (eg, can we allocate memory in it?)
+ */
+static int
+pcib_is_nonprefetch_open(struct pcib_softc *sc)
+{
+ return (sc->membase > 0 && sc->membase < sc->memlimit);
+}
+
+/*
+ * Is the io window open (eg, can we allocate ports in it?)
+ */
+static int
+pcib_is_io_open(struct pcib_softc *sc)
+{
+ return (sc->iobase > 0 && sc->iobase < sc->iolimit);
+}
+
+/*
* We have to trap resource allocation requests and ensure that the bridge
* is set up to, or capable of handling them.
*/
@@ -282,6 +312,7 @@ 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;
/*
* If this is a "default" allocation against this rid, we can't work
@@ -294,19 +325,21 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
} else {
/*
* Fail the allocation for this range if it's not supported.
- *
- * XXX we should probably just fix up the bridge decode and soldier on.
*/
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 (start < sc->iobase)
- start = sc->iobase;
- if (end > sc->iolimit)
- end = sc->iolimit;
- if (end < start)
- start = 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,
@@ -318,12 +351,16 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
printf("end (%lx) < start (%lx)\n", end, start);
}
}
- if (!pcib_is_isa_io(start) &&
- ((start < sc->iobase) || (end > sc->iolimit))) {
- 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);
+ 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)
@@ -331,48 +368,76 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
device_get_name(child), device_get_unit(child), start, end);
break;
- /*
- * XXX will have to decide whether the device making the request is asking
- * for prefetchable memory or not. If it's coming from another bridge
- * down the line, do we assume not, or ask the bridge to pass in another
- * flag as the request bubbles up?
- */
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);
+ if (pcib_is_prefetch_open(sc))
+ ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit);
if (!pci_allow_unsupported_io_range) {
- if (start < sc->membase && end >= sc->membase)
- start = sc->membase;
- if (end > sc->memlimit)
- end = sc->memlimit;
- if (end < start)
- start = 0;
- } else {
- if (start < sc->membase && end > 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 (!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);
}
}
- if (!pcib_is_isa_mem(start) &&
- (((start < sc->membase) || (end > sc->memlimit)) &&
- ((start < sc->pmembase) || (end > sc->pmemlimit)))) {
- if (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 (!pci_allow_unsupported_io_range)
- return (NULL);
+ 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);
+ device_get_name(child), device_get_unit(child), start, end);
break;
default:
OpenPOWER on IntegriCloud