PCI: add infrastructure for devices with broken INTx masking
authorBjorn Helgaas <bhelgaas@google.com>
Sat, 16 Jun 2012 20:40:22 +0000 (14:40 -0600)
committerBjorn Helgaas <bhelgaas@google.com>
Sat, 16 Jun 2012 20:40:22 +0000 (14:40 -0600)
pci_intx_mask_supported() assumes INTx masking is supported if the
PCI_COMMAND_INTX_DISABLE bit is writable.  But when that bit is set,
some devices don't actually mask INTx or update PCI_STATUS_INTERRUPT
as we expect.

This patch adds a way for quirks to identify these broken devices.

[bhelgaas: split out from Chelsio quirk addition]
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/pci.c
drivers/pci/quirks.c
include/linux/pci.h

index 447e834..9ae517a 100644 (file)
@@ -2876,6 +2876,9 @@ bool pci_intx_mask_supported(struct pci_dev *dev)
        bool mask_supported = false;
        u16 orig, new;
 
+       if (dev->broken_intx_masking)
+               return false;
+
        pci_cfg_access_lock(dev);
 
        pci_read_config_word(dev, PCI_COMMAND, &orig);
index 2a75216..cc13415 100644 (file)
@@ -2929,6 +2929,16 @@ static void __devinit disable_igfx_irq(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
 
+/*
+ * Some devices may pass our check in pci_intx_mask_supported if
+ * PCI_COMMAND_INTX_DISABLE works though they actually do not properly
+ * support this feature.
+ */
+static void __devinit quirk_broken_intx_masking(struct pci_dev *dev)
+{
+       dev->broken_intx_masking = 1;
+}
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
                          struct pci_fixup *end)
 {
index d8c379d..40a039f 100644 (file)
@@ -324,6 +324,7 @@ struct pci_dev {
        unsigned int    is_hotplug_bridge:1;
        unsigned int    __aer_firmware_first_valid:1;
        unsigned int    __aer_firmware_first:1;
+       unsigned int    broken_intx_masking:1;
        pci_dev_flags_t dev_flags;
        atomic_t        enable_cnt;     /* pci_enable_device has been called */