summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-01-16 22:22:30 +0000
committerjhb <jhb@FreeBSD.org>2009-01-16 22:22:30 +0000
commit9d7c60d6cda5df8a13fd42687731147716cfbac9 (patch)
tree98d45ce7811f957770bb56a6fca0f36b1c9ce56d /sys/dev/pci
parentc8283e83beb733f870ebeed9647b5de69bf22b5d (diff)
downloadFreeBSD-src-9d7c60d6cda5df8a13fd42687731147716cfbac9.zip
FreeBSD-src-9d7c60d6cda5df8a13fd42687731147716cfbac9.tar.gz
Disable decoding of BARs by devices before we trash the value in the BAR
by writing all 1's to it to determine its length. This fixes issues with MCFG on at least some machines where a trashed BAR claimed subsequent attempts at PCI config transactions because the addresses in the MCFG window fell in the decoding range of the BAR. In general it is a bad idea to leave the BARs enabled while we are frobbing with them in this manner. Sleuthing by: tegge MFC after: 1 week
Diffstat (limited to 'sys/dev/pci')
-rw-r--r--sys/dev/pci/pci.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 295e68d..a027e99 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -2291,9 +2291,27 @@ pci_add_map(device_t pcib, device_t bus, device_t dev,
struct resource *res;
map = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4);
+
+ /*
+ * Disable decoding via the command register before
+ * determining the BARs length since we will be placing them
+ * in a weird state.
+ */
+ cmd = PCIB_READ_CONFIG(pcib, b, s, f, PCIR_COMMAND, 2);
+ PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND,
+ cmd & ~(PCI_BAR_MEM(map) ? PCIM_CMD_MEMEN : PCIM_CMD_PORTEN), 2);
+
+ /*
+ * Determine the BAR's length by writing all 1's. The bottom
+ * log_2(size) bits of the BAR will stick as 0 when we read
+ * the value back.
+ */
PCIB_WRITE_CONFIG(pcib, b, s, f, reg, 0xffffffff, 4);
testval = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4);
+
+ /* Restore the BAR and command register. */
PCIB_WRITE_CONFIG(pcib, b, s, f, reg, map, 4);
+ PCIB_WRITE_CONFIG(pcib, b, s, f, PCIR_COMMAND, cmd, 2);
if (PCI_BAR_MEM(map))
type = SYS_RES_MEMORY;
OpenPOWER on IntegriCloud