aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2013-05-09 19:24:50 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2013-05-09 19:24:50 +0000
commit5569a8b8df00d55f3e834f0424d2fbd161d94596 (patch)
treec97d229122e0d9d60c1094407aa932df02d2ba65 /sys/dev/pci
parent241b67bb47591cedbe637fc0dae1b0ad4db32d3c (diff)
Notes
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/pci.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 79d5e570096b..2851ab76866a 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -280,6 +280,12 @@ SYSCTL_INT(_hw_pci, OID_AUTO, enable_io_modes, CTLFLAG_RW,
enable these bits correctly. We'd like to do this all the time, but there\n\
are some peripherals that this causes problems with.");
+static int pci_do_realloc_bars = 1;
+TUNABLE_INT("hw.pci.realloc_bars", &pci_do_realloc_bars);
+SYSCTL_INT(_hw_pci, OID_AUTO, realloc_bars, CTLFLAG_RW,
+ &pci_do_realloc_bars, 0,
+ "Attempt to allocate a new range for any BARs whose original firmware-assigned ranges fail to allocate during the initial device scan.");
+
static int pci_do_power_nodriver = 0;
TUNABLE_INT("hw.pci.do_power_nodriver", &pci_do_power_nodriver);
SYSCTL_INT(_hw_pci, OID_AUTO, do_power_nodriver, CTLFLAG_RW,
@@ -2816,13 +2822,34 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl,
*/
res = resource_list_reserve(rl, bus, dev, type, &reg, start, end, count,
prefetch ? RF_PREFETCHABLE : 0);
+ if (pci_do_realloc_bars && res == NULL && (start != 0 || end != ~0ul)) {
+ /*
+ * If the allocation fails, try to allocate a resource for
+ * this BAR using any available range. The firmware felt
+ * it was important enough to assign a resource, so don't
+ * disable decoding if we can help it.
+ */
+ resource_list_delete(rl, type, reg);
+ resource_list_add(rl, type, reg, 0, ~0ul, count);
+ res = resource_list_reserve(rl, bus, dev, type, &reg, 0, ~0ul,
+ count, prefetch ? RF_PREFETCHABLE : 0);
+ }
if (res == NULL) {
/*
* If the allocation fails, delete the resource list entry
- * to force pci_alloc_resource() to allocate resources
- * from the parent.
+ * and disable decoding for this device.
+ *
+ * If the driver requests this resource in the future,
+ * pci_reserve_map() will try to allocate a fresh
+ * resource range.
*/
resource_list_delete(rl, type, reg);
+ pci_disable_io(dev, type);
+ if (bootverbose)
+ device_printf(bus,
+ "pci%d:%d:%d:%d bar %#x failed to allocate\n",
+ pci_get_domain(dev), pci_get_bus(dev),
+ pci_get_slot(dev), pci_get_function(dev), reg);
} else {
start = rman_get_start(res);
pci_write_bar(dev, pm, start);