diff options
author | rnoland <rnoland@FreeBSD.org> | 2009-03-04 18:23:48 +0000 |
---|---|---|
committer | rnoland <rnoland@FreeBSD.org> | 2009-03-04 18:23:48 +0000 |
commit | 5e2ed35d2497301a2298e37ba8b1f3a1c46763bf (patch) | |
tree | a8a5c7b08ed31670f37119db1da7c0890ed42313 | |
parent | 2ea73058a405a12b39bf427a7cfadb905270d7e2 (diff) | |
download | FreeBSD-src-5e2ed35d2497301a2298e37ba8b1f3a1c46763bf.zip FreeBSD-src-5e2ed35d2497301a2298e37ba8b1f3a1c46763bf.tar.gz |
Extend the management of PCIM_CMD_INTxDIS.
We now explicitly enable INTx during bus_setup_intr() if it is needed.
Several of the ata drivers were managing this bit internally. This is
better handled in pci and it should work for all drivers now.
We also mask INTx during bus_teardown_intr() by setting this bit.
Reviewed by: jhb
MFC after: 3 days
-rw-r--r-- | sys/dev/pci/pci.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index d73c34c..df732ef 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -2825,14 +2825,24 @@ pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, if (error) return (error); - /* - * If this is a direct child, check to see if the interrupt is - * MSI or MSI-X. If so, ask our parent to map the MSI and give - * us the address and data register values. If we fail for some - * reason, teardown the interrupt handler. - */ + /* If this is not a direct child, just bail out. */ + if (device_get_parent(child) != dev) { + *cookiep = cookie; + return(0); + } + rid = rman_get_rid(irq); - if (device_get_parent(child) == dev && rid > 0) { + if (rid == 0) { + /* Make sure that INTx is enabled */ + pci_clear_command_bit(dev, child, PCIM_CMD_INTxDIS); + } else { + /* + * Check to see if the interrupt is MSI or MSI-X. + * Ask our parent to map the MSI and give + * us the address and data register values. + * If we fail for some reason, teardown the + * interrupt handler. + */ dinfo = device_get_ivars(child); if (dinfo->cfg.msi.msi_alloc > 0) { if (dinfo->cfg.msi.msi_addr == 0) { @@ -2874,7 +2884,8 @@ pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, } mte->mte_handlers++; } - /* Disable INTx if we are using MSI/MSIX */ + + /* Make sure that INTx is disabled if we are using MSI/MSIX */ pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS); bad: if (error) { @@ -2896,16 +2907,24 @@ pci_teardown_intr(device_t dev, device_t child, struct resource *irq, struct pci_devinfo *dinfo; int error, rid; - /* - * If this is a direct child, check to see if the interrupt is - * MSI or MSI-X. If so, decrement the appropriate handlers - * count and mask the MSI-X message, or disable MSI messages - * if the count drops to 0. - */ if (irq == NULL || !(rman_get_flags(irq) & RF_ACTIVE)) return (EINVAL); + + /* If this isn't a direct child, just bail out */ + if (device_get_parent(child) != dev) + return(bus_generic_teardown_intr(dev, child, irq, cookie)); + rid = rman_get_rid(irq); - if (device_get_parent(child) == dev && rid > 0) { + if (rid > 0) { + /* Mask INTx */ + pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS); + } else { + /* + * Check to see if the interrupt is MSI or MSI-X. If so, + * decrement the appropriate handlers count and mask the + * MSI-X message, or disable MSI messages if the count + * drops to 0. + */ dinfo = device_get_ivars(child); rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid); if (rle->res != irq) @@ -2930,11 +2949,9 @@ pci_teardown_intr(device_t dev, device_t child, struct resource *irq, if (mte->mte_handlers == 0) pci_mask_msix(child, rid - 1); } - /* Restore INTx capability for MSI/MSIX */ - pci_clear_command_bit(dev, child, PCIM_CMD_INTxDIS); } error = bus_generic_teardown_intr(dev, child, irq, cookie); - if (device_get_parent(child) == dev && rid > 0) + if (rid > 0) KASSERT(error == 0, ("%s: generic teardown failed for MSI/MSI-X", __func__)); return (error); |