diff options
author | luoqi <luoqi@FreeBSD.org> | 2008-07-23 09:44:36 +0000 |
---|---|---|
committer | luoqi <luoqi@FreeBSD.org> | 2008-07-23 09:44:36 +0000 |
commit | 2620286140b697937520b92f540813fd844d2222 (patch) | |
tree | 4e066aa66c4ced0839aa104cb426a675b9f0e5b8 /sys/dev/pci/pci.c | |
parent | d27f65928a6e40f7d6391c4441edc752c1702212 (diff) | |
download | FreeBSD-src-2620286140b697937520b92f540813fd844d2222.zip FreeBSD-src-2620286140b697937520b92f540813fd844d2222.tar.gz |
SATA device on some nForce based boards could get confused if MSI is not
used but MSI to HyperTransport IRQ mapping is enabled, and would act as
if MSI is turned on, resulting in interrupt loss.
This commit will,
1. enable MSI mapping on a device only when MSI is enabled for that
device and the MSI address matches the HT mapping window.
2. enable MSI mapping on a bridge only when a downstream device is
allocated an MSI address in the mapping window
PR: kern/118842
Reviewed by: jhb
MFC after: 1 week
Diffstat (limited to 'sys/dev/pci/pci.c')
-rw-r--r-- | sys/dev/pci/pci.c | 46 |
1 files changed, 42 insertions, 4 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, |