summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-08-05 18:24:41 +0000
committerjhb <jhb@FreeBSD.org>2008-08-05 18:24:41 +0000
commitbe95b0fe3c10d07ed8c0887e7695a358ee6a2e17 (patch)
tree6d68c34e6d2fbb3de1767c52467f1763571c8617 /sys/dev/pci
parentb808cfb9c8b3a6f217bd7cc7f193fcc20a48a854 (diff)
downloadFreeBSD-src-be95b0fe3c10d07ed8c0887e7695a358ee6a2e17.zip
FreeBSD-src-be95b0fe3c10d07ed8c0887e7695a358ee6a2e17.tar.gz
If the kernel fails to allocate resources for the initial value of a BAR
for a PCI device during the boot-time probe of the parent PCI bus, then zero the BAR and clear the resource list entry for that BAR. This forces the PCI bus driver to request a valid resource range from the parent bridge driver when the device driver tries to allocate the BAR. Similarly, if the initial value of a BAR is a valid range but it is > 4GB and the current OS only has 32-bit longs, then do a full teardown of the initial value of the BAR to force a reallocation. Reviewed by: imp MFC after: 1 week
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/pci.c46
1 files changed, 33 insertions, 13 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index ee27e9a..f912586 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -2379,7 +2379,7 @@ pci_add_map(device_t pcib, device_t bus, device_t dev,
count = 1 << ln2size;
if (base == 0 || base == pci_mapbase(testval)) {
- start = 0; /* Let the parent deside */
+ start = 0; /* Let the parent decide. */
end = ~0ULL;
} else {
start = base;
@@ -2388,21 +2388,41 @@ pci_add_map(device_t pcib, device_t bus, device_t dev,
resource_list_add(rl, type, reg, start, end, count);
/*
- * Not quite sure what to do on failure of allocating the resource
- * since I can postulate several right answers.
+ * Try to allocate the resource for this BAR from our parent
+ * so that this resource range is already reserved. The
+ * driver for this device will later inherit this resource in
+ * pci_alloc_resource().
*/
res = resource_list_alloc(rl, bus, dev, type, &reg, start, end, count,
prefetch ? RF_PREFETCHABLE : 0);
- if (res == NULL)
- return (barlen);
- start = rman_get_start(res);
- if ((u_long)start != start) {
- /* Wait a minute! this platform can't do this address. */
- device_printf(bus,
- "pci%d:%d.%d.%x bar %#x start %#jx, too many bits.",
- pci_get_domain(dev), b, s, f, reg, (uintmax_t)start);
- resource_list_release(rl, bus, dev, type, reg, res);
- return (barlen);
+ if (res == NULL) {
+ /*
+ * If the allocation fails, clear the BAR and delete
+ * the resource list entry to force
+ * pci_alloc_resource() to allocate resources from the
+ * parent.
+ */
+ resource_list_delete(rl, type, reg);
+ start = 0;
+ } else {
+ start = rman_get_start(res);
+ if ((u_long)start != start) {
+ /*
+ * Wait a minute! This platform can't do this
+ * address.
+ */
+ device_printf(bus,
+ "pci%d:%d.%d.%x bar %#x start %#jx, too many bits.",
+ pci_get_domain(dev), b, s, f, reg,
+ (uintmax_t)start);
+
+ /*
+ * Delete this resource and zero the BAR.
+ */
+ resource_list_release(rl, bus, dev, type, reg, res);
+ resource_list_delete(rl, type, reg);
+ start = 0;
+ }
}
pci_write_config(dev, reg, start, 4);
if (ln2range == 64)
OpenPOWER on IntegriCloud