diff options
author | jhb <jhb@FreeBSD.org> | 2008-08-05 18:24:41 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-08-05 18:24:41 +0000 |
commit | be95b0fe3c10d07ed8c0887e7695a358ee6a2e17 (patch) | |
tree | 6d68c34e6d2fbb3de1767c52467f1763571c8617 /sys/dev/pci | |
parent | b808cfb9c8b3a6f217bd7cc7f193fcc20a48a854 (diff) | |
download | FreeBSD-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.c | 46 |
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, ®, 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) |