diff options
-rw-r--r-- | sys/dev/pci/pci.c | 46 | ||||
-rw-r--r-- | sys/dev/pci/pci_pci.c | 8 | ||||
-rw-r--r-- | sys/dev/pci/pcivar.h | 10 |
3 files changed, 59 insertions, 5 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 0e8647f..ee27e9a 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -562,11 +562,12 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg) cfg->domain, cfg->bus, cfg->slot, cfg->func, (long long)addr); - } + } else + addr = MSI_INTEL_ADDR_BASE; - /* Enable MSI -> HT mapping. */ - val |= PCIM_HTCMD_MSI_ENABLE; - WREG(ptr + PCIR_HT_COMMAND, val, 2); + cfg->ht.ht_msimap = ptr; + cfg->ht.ht_msictrl = val; + cfg->ht.ht_msiaddr = addr; break; } break; @@ -1095,6 +1096,9 @@ pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data) bus_write_4(msix->msix_table_res, offset, address & 0xffffffff); bus_write_4(msix->msix_table_res, offset + 4, address >> 32); bus_write_4(msix->msix_table_res, offset + 8, data); + + /* Enable MSI -> HT mapping. */ + pci_ht_map_msi(dev, address); } void @@ -1534,6 +1538,34 @@ pci_msix_count_method(device_t dev, device_t child) } /* + * HyperTransport MSI mapping control + */ +void +pci_ht_map_msi(device_t dev, uint64_t addr) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + struct pcicfg_ht *ht = &dinfo->cfg.ht; + + if (!ht->ht_msimap) + return; + + if (addr && !(ht->ht_msictrl & PCIM_HTCMD_MSI_ENABLE) && + ht->ht_msiaddr >> 20 == addr >> 20) { + /* Enable MSI -> HT mapping. */ + ht->ht_msictrl |= PCIM_HTCMD_MSI_ENABLE; + pci_write_config(dev, ht->ht_msimap + PCIR_HT_COMMAND, + ht->ht_msictrl, 2); + } + + if (!addr && ht->ht_msictrl & PCIM_HTCMD_MSI_ENABLE) { + /* Disable MSI -> HT mapping. */ + ht->ht_msictrl &= ~PCIM_HTCMD_MSI_ENABLE; + pci_write_config(dev, ht->ht_msimap + PCIR_HT_COMMAND, + ht->ht_msictrl, 2); + } +} + +/* * Support for MSI message signalled interrupts. */ void @@ -1558,6 +1590,9 @@ pci_enable_msi(device_t dev, uint64_t address, uint16_t data) msi->msi_ctrl |= PCIM_MSICTRL_MSI_ENABLE; pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl, 2); + + /* Enable MSI -> HT mapping. */ + pci_ht_map_msi(dev, address); } void @@ -1566,6 +1601,9 @@ pci_disable_msi(device_t dev) struct pci_devinfo *dinfo = device_get_ivars(dev); struct pcicfg_msi *msi = &dinfo->cfg.msi; + /* Disable MSI -> HT mapping. */ + pci_ht_map_msi(dev, 0); + /* Disable MSI in the control register. */ msi->msi_ctrl &= ~PCIM_MSICTRL_MSI_ENABLE; pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl, diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c index 033ea74..13fa065 100644 --- a/sys/dev/pci/pci_pci.c +++ b/sys/dev/pci/pci_pci.c @@ -607,9 +607,15 @@ pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data) { device_t bus; + int error; bus = device_get_parent(pcib); - return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); + error = PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data); + if (error) + return (error); + + pci_ht_map_msi(pcib, *addr); + return (0); } /* diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index 7cb4c29..3c4c54d 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -115,6 +115,13 @@ struct pcicfg_msix { struct resource *msix_pba_res; /* Resource containing PBA. */ }; +/* Interesting values for HyperTransport */ +struct pcicfg_ht { + 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 */ +}; + /* config header information common to all header types */ typedef struct pcicfg { struct device *dev; /* device which owns this */ @@ -156,6 +163,7 @@ typedef struct pcicfg { struct pcicfg_vpd vpd; /* pci vital product data */ struct pcicfg_msi msi; /* pci msi */ struct pcicfg_msix msix; /* pci msi-x */ + struct pcicfg_ht ht; /* HyperTransport */ } pcicfgregs; /* additional type 1 device config header information (PCI to PCI bridge) */ @@ -455,6 +463,8 @@ int pci_pending_msix(device_t dev, u_int index); int pci_msi_device_blacklisted(device_t dev); +void pci_ht_map_msi(device_t dev, uint64_t addr); + #endif /* _SYS_BUS_H_ */ /* |