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
This commit is contained in:
parent
6dc0afa896
commit
4522ac77de
@ -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
|
||||
@ -1533,6 +1537,34 @@ pci_msix_count_method(device_t dev, device_t child)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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_ */
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user