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
This commit is contained in:
John Baldwin 2011-03-18 12:13:04 +00:00
parent 587392a5a0
commit 8081bab70b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=219737
2 changed files with 44 additions and 4 deletions

View File

@ -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);
}

View File

@ -110,6 +110,7 @@ struct pcicfg_msix {
/* Interesting values for HyperTransport */
struct pcicfg_ht {
uint8_t ht_slave; /* Non-zero if device is an HT slave. */
uint8_t ht_msimap; /* Offset of MSI mapping cap registers. */
uint16_t ht_msictrl; /* MSI mapping control */
uint64_t ht_msiaddr; /* MSI mapping base address */