diff options
Diffstat (limited to 'freebsd/sys/dev/pci/pci.c')
-rw-r--r-- | freebsd/sys/dev/pci/pci.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/freebsd/sys/dev/pci/pci.c b/freebsd/sys/dev/pci/pci.c index 7dcaa0d5..426d06a2 100644 --- a/freebsd/sys/dev/pci/pci.c +++ b/freebsd/sys/dev/pci/pci.c @@ -211,6 +211,7 @@ struct pci_quirk { #define PCI_QUIRK_ENABLE_MSI_VM 3 /* Older chipset in VM where MSI works */ #define PCI_QUIRK_UNMAP_REG 4 /* Ignore PCI map register */ #define PCI_QUIRK_DISABLE_MSIX 5 /* MSI-X doesn't work */ +#define PCI_QUIRK_MSI_INTX_BUG 6 /* PCIM_CMD_INTxDIS disables MSI */ int arg1; int arg2; }; @@ -270,6 +271,26 @@ static const struct pci_quirk pci_quirks[] = { */ { 0x43851002, PCI_QUIRK_UNMAP_REG, 0x14, 0 }, + /* + * Atheros AR8161/AR8162/E2200 Ethernet controllers have a bug that + * MSI interrupt does not assert if PCIM_CMD_INTxDIS bit of the + * command register is set. + */ + { 0x10911969, PCI_QUIRK_MSI_INTX_BUG, 0, 0 }, + { 0xE0911969, PCI_QUIRK_MSI_INTX_BUG, 0, 0 }, + { 0x10901969, PCI_QUIRK_MSI_INTX_BUG, 0, 0 }, + + /* + * Broadcom BCM5714(S)/BCM5715(S)/BCM5780(S) Ethernet MACs don't + * issue MSI interrupts with PCIM_CMD_INTxDIS set either. + */ + { 0x166814e4, PCI_QUIRK_MSI_INTX_BUG, 0, 0 }, /* BCM5714 */ + { 0x166914e4, PCI_QUIRK_MSI_INTX_BUG, 0, 0 }, /* BCM5714S */ + { 0x166a14e4, PCI_QUIRK_MSI_INTX_BUG, 0, 0 }, /* BCM5780 */ + { 0x166b14e4, PCI_QUIRK_MSI_INTX_BUG, 0, 0 }, /* BCM5780S */ + { 0x167814e4, PCI_QUIRK_MSI_INTX_BUG, 0, 0 }, /* BCM5715 */ + { 0x167914e4, PCI_QUIRK_MSI_INTX_BUG, 0, 0 }, /* BCM5715S */ + { 0 } }; @@ -3567,8 +3588,16 @@ pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, mte->mte_handlers++; } - /* Make sure that INTx is disabled if we are using MSI/MSIX */ - pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS); + /* + * Make sure that INTx is disabled if we are using MSI/MSI-X, + * unless the device is affected by PCI_QUIRK_MSI_INTX_BUG, + * in which case we "enable" INTx so MSI/MSI-X actually works. + */ + if (!pci_has_quirk(pci_get_devid(child), + PCI_QUIRK_MSI_INTX_BUG)) + pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS); + else + pci_clear_command_bit(dev, child, PCIM_CMD_INTxDIS); bad: if (error) { (void)bus_generic_teardown_intr(dev, child, irq, |