summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci/pci.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2011-03-18 12:13:04 +0000
committerjhb <jhb@FreeBSD.org>2011-03-18 12:13:04 +0000
commit359e81dc4639eef5e3a0703c0128eb0a8c9f9f48 (patch)
tree0544948378de44682c7a66d8a5844aba327f32dc /sys/dev/pci/pci.c
parentc23159e1a271c4648f80d76340aab96cb4ca502b (diff)
downloadFreeBSD-src-359e81dc4639eef5e3a0703c0128eb0a8c9f9f48.zip
FreeBSD-src-359e81dc4639eef5e3a0703c0128eb0a8c9f9f48.tar.gz
Fix a few issues with HyperTransport devices and MSI interrupts:
- Always enable the HyperTransport MSI mapping window for HyperTransport to PCI bridges (these show up as HyperTransport slave devices). The mapping windows in PCI-PCI bridges are enabled by existing code in the PCI-PCI bridge driver as MSI requests propagate up the device tree, but Host-PCI bridges don't really show up in that tree. - If the PCI device at domain 0 bus 0 slot 0 function 0 is not a HyperTransport device, then blacklist MSI on any other HT devices in the system. Linux has a similar quirk. PR: kern/155442 Tested by: Zack Dannar zdannar of gmail MFC after: 1 week
Diffstat (limited to 'sys/dev/pci/pci.c')
-rw-r--r--sys/dev/pci/pci.c47
1 files changed, 43 insertions, 4 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 60cfc84..17e3a42 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -236,7 +236,7 @@ struct pci_quirk pci_quirks[] = {
struct devlist pci_devq;
uint32_t pci_generation;
uint32_t pci_numdevs = 0;
-static int pcie_chipset, pcix_chipset;
+static int ht_chipset, pcie_chipset, pcix_chipset;
/* sysctl vars */
SYSCTL_NODE(_hw, OID_AUTO, pci, CTLFLAG_RD, 0, "PCI bus tuning parameters");
@@ -612,10 +612,24 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg)
cfg->pp.pp_data = ptr + PCIR_POWER_DATA;
}
break;
-#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
case PCIY_HT: /* HyperTransport */
/* Determine HT-specific capability type. */
val = REG(ptr + PCIR_HT_COMMAND, 2);
+
+ if ((val & 0xe000) == PCIM_HTCAP_SLAVE) {
+ cfg->ht.ht_slave = ptr;
+
+ /*
+ * If device 0:0:0:0 is an HT slave,
+ * then this is an HT chipset and MSI
+ * should be enabled for HT devices.
+ */
+ if (cfg->domain == 0 && cfg->bus == 0 &&
+ cfg->slot == 0 && cfg->func == 0)
+ ht_chipset = 1;
+ }
+
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
switch (val & PCIM_HTCMD_CAP_MASK) {
case PCIM_HTCAP_MSI_MAPPING:
if (!(val & PCIM_HTCMD_MSI_FIXED)) {
@@ -627,7 +641,7 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg)
4);
if (addr != MSI_INTEL_ADDR_BASE)
device_printf(pcib,
- "HT Bridge at pci%d:%d:%d:%d has non-default MSI window 0x%llx\n",
+ "HT device at pci%d:%d:%d:%d has non-default MSI window 0x%llx\n",
cfg->domain, cfg->bus,
cfg->slot, cfg->func,
(long long)addr);
@@ -639,8 +653,8 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg)
cfg->ht.ht_msiaddr = addr;
break;
}
- break;
#endif
+ break;
case PCIY_MSI: /* PCI MSI */
cfg->msi.msi_location = ptr;
cfg->msi.msi_ctrl = REG(ptr + PCIR_MSI_CTRL, 2);
@@ -696,6 +710,24 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg)
break;
}
}
+
+
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
+ /*
+ * Enable the MSI mapping window for all HyperTransport
+ * slaves. PCI-PCI bridges have their windows enabled via
+ * PCIB_MAP_MSI().
+ */
+ if (cfg->ht.ht_slave != 0 && cfg->ht.ht_msimap != 0 &&
+ !(cfg->ht.ht_msictrl & PCIM_HTCMD_MSI_ENABLE)) {
+ device_printf(pcib,
+ "Enabling MSI window for HyperTransport slave at pci%d:%d:%d:%d\n",
+ cfg->domain, cfg->bus, cfg->slot, cfg->func);
+ cfg->ht.ht_msictrl |= PCIM_HTCMD_MSI_ENABLE;
+ WREG(cfg->ht.ht_msimap + PCIR_HT_COMMAND, cfg->ht.ht_msictrl,
+ 2);
+ }
+#endif
/* REG and WREG use carry through to next functions */
}
@@ -1837,6 +1869,13 @@ pci_msi_device_blacklisted(device_t dev)
q->type == PCI_QUIRK_DISABLE_MSI)
return (1);
}
+
+ /*
+ * Blacklist HyperTransport devices if the device at 0:0:0:0
+ * is not a HyperTransport slave.
+ */
+ if (!ht_chipset && pci_find_extcap(dev, PCIY_HT, NULL) == 0)
+ return (1);
return (0);
}
OpenPOWER on IntegriCloud