summaryrefslogtreecommitdiffstats
path: root/sys/amd64/pci/pci_cfgreg.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-09-10 18:06:08 +0000
committerjhb <jhb@FreeBSD.org>2008-09-10 18:06:08 +0000
commitddef31011106cf0f134191491d7068326eb3a518 (patch)
tree7a5201c3b1fba518c0c396d23ddbc83848c8f777 /sys/amd64/pci/pci_cfgreg.c
parentfd768740df307f22a28b0251f47a3e972ae091cb (diff)
downloadFreeBSD-src-ddef31011106cf0f134191491d7068326eb3a518.zip
FreeBSD-src-ddef31011106cf0f134191491d7068326eb3a518.tar.gz
Some K8 chipsets don't expose all of the PCI devices on bus 0 via PCIe
memory-mapped config access. Add a workaround for these systems by checking the first function of each slot on bus 0 using both the memory-mapped config access and the older type 1 I/O port config access. If we find a slot that is only visible via the type 1 I/O port config access, we flag that slot. Future PCI config transactions to flagged slots on bus 0 use type 1 I/O port config access rather than memory mapped config access.
Diffstat (limited to 'sys/amd64/pci/pci_cfgreg.c')
-rw-r--r--sys/amd64/pci/pci_cfgreg.c62
1 files changed, 48 insertions, 14 deletions
diff --git a/sys/amd64/pci/pci_cfgreg.c b/sys/amd64/pci/pci_cfgreg.c
index 8d5dde0..13d27a1 100644
--- a/sys/amd64/pci/pci_cfgreg.c
+++ b/sys/amd64/pci/pci_cfgreg.c
@@ -46,6 +46,8 @@ enum {
CFGMECH_PCIE,
};
+static uint32_t pci_docfgregread(int bus, int slot, int func, int reg,
+ int bytes);
static int pciereg_cfgread(int bus, unsigned slot, unsigned func,
unsigned reg, unsigned bytes);
static void pciereg_cfgwrite(int bus, unsigned slot, unsigned func,
@@ -56,6 +58,7 @@ static void pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int
static int cfgmech;
static vm_offset_t pcie_base;
static int pcie_minbus, pcie_maxbus;
+static uint32_t pcie_badslots;
static struct mtx pcicfg_mtx;
/*
@@ -64,12 +67,17 @@ static struct mtx pcicfg_mtx;
int
pci_cfgregopen(void)
{
+ static int once = 0;
uint64_t pciebar;
uint16_t did, vid;
+ if (!once) {
+ mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
+ once = 1;
+ }
+
if (cfgmech != CFGMECH_NONE)
return (1);
- mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
cfgmech = CFGMECH_1;
/*
@@ -103,6 +111,17 @@ pci_cfgregopen(void)
return (1);
}
+static uint32_t
+pci_docfgregread(int bus, int slot, int func, int reg, int bytes)
+{
+
+ if (cfgmech == CFGMECH_PCIE &&
+ (bus != 0 || !(1 << slot & pcie_badslots)))
+ return (pciereg_cfgread(bus, slot, func, reg, bytes));
+ else
+ return (pcireg_cfgread(bus, slot, func, reg, bytes));
+}
+
/*
* Read configuration space register
*/
@@ -120,12 +139,12 @@ pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
* as an invalid IRQ.
*/
if (reg == PCIR_INTLINE && bytes == 1) {
- line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
+ line = pci_docfgregread(bus, slot, func, PCIR_INTLINE, 1);
if (line == 0 || line >= 128)
line = PCI_INVALID_IRQ;
return (line);
}
- return (pcireg_cfgread(bus, slot, func, reg, bytes));
+ return (pci_docfgregread(bus, slot, func, reg, bytes));
}
/*
@@ -135,7 +154,11 @@ void
pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
{
- pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
+ if (cfgmech == CFGMECH_PCIE &&
+ (bus != 0 || !(1 << slot & pcie_badslots)))
+ pciereg_cfgwrite(bus, slot, func, reg, data, bytes);
+ else
+ pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
}
/*
@@ -175,11 +198,6 @@ pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
int data = -1;
int port;
- if (cfgmech == CFGMECH_PCIE) {
- data = pciereg_cfgread(bus, slot, func, reg, bytes);
- return (data);
- }
-
mtx_lock_spin(&pcicfg_mtx);
port = pci_cfgenable(bus, slot, func, reg, bytes);
if (port != 0) {
@@ -205,11 +223,6 @@ pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
{
int port;
- if (cfgmech == CFGMECH_PCIE) {
- pciereg_cfgwrite(bus, slot, func, reg, data, bytes);
- return;
- }
-
mtx_lock_spin(&pcicfg_mtx);
port = pci_cfgenable(bus, slot, func, reg, bytes);
if (port != 0) {
@@ -232,6 +245,8 @@ pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
int
pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus)
{
+ uint32_t val1, val2;
+ int slot;
if (minbus != 0)
return (0);
@@ -245,6 +260,25 @@ pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus)
pcie_minbus = minbus;
pcie_maxbus = maxbus;
cfgmech = CFGMECH_PCIE;
+
+ /*
+ * On some AMD systems, some of the devices on bus 0 are
+ * inaccessible using memory-mapped PCI config access. Walk
+ * bus 0 looking for such devices. For these devices, we will
+ * fall back to using type 1 config access instead.
+ */
+ if (pci_cfgregopen() != 0) {
+ for (slot = 0; slot < 32; slot++) {
+ val1 = pcireg_cfgread(0, slot, 0, 0, 4);
+ if (val1 == 0xffffffff)
+ continue;
+
+ val2 = pciereg_cfgread(0, slot, 0, 0, 4);
+ if (val2 != val1)
+ pcie_badslots |= (1 << slot);
+ }
+ }
+
return (1);
}
OpenPOWER on IntegriCloud