diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 09440d783e65542912bac932fa727a288df1891c..cad519910767474e649356ab1e34c9d2dfb1334f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7365,10 +7365,6 @@ static int tg3_open(struct net_device *dev) } else if (pci_enable_msi(tp->pdev) == 0) { u32 msi_mode; - /* Hardware bug - MSI won't work if INTX disabled. */ - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) - pci_intx(tp->pdev, 1); - msi_mode = tr32(MSGINT_MODE); tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); tp->tg3_flags2 |= TG3_FLG2_USING_MSI; @@ -12681,11 +12677,6 @@ static int tg3_resume(struct pci_dev *pdev) if (err) return err; - /* Hardware bug - MSI won't work if INTX disabled. */ - if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) && - (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) - pci_intx(tp->pdev, 1); - netif_device_attach(dev); tg3_full_lock(tp, 0); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 87e01615053dc1fb228b05473e1bdac2d32b8e6c..07c9f09c856dba943a15f7e794ba8e1eaef78387 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -224,6 +224,12 @@ static struct msi_desc* alloc_msi_entry(void) return entry; } +static void pci_intx_for_msi(struct pci_dev *dev, int enable) +{ + if (!(dev->dev_flags & PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG)) + pci_intx(dev, enable); +} + #ifdef CONFIG_PM static void __pci_restore_msi_state(struct pci_dev *dev) { @@ -237,7 +243,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) entry = get_irq_msi(dev->irq); pos = entry->msi_attrib.pos; - pci_intx(dev, 0); /* disable intx */ + pci_intx_for_msi(dev, 0); msi_set_enable(dev, 0); write_msi_msg(dev->irq, &entry->msg); if (entry->msi_attrib.maskbit) @@ -260,7 +266,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) return; /* route the table */ - pci_intx(dev, 0); /* disable intx */ + pci_intx_for_msi(dev, 0); msix_set_enable(dev, 0); list_for_each_entry(entry, &dev->msi_list, list) { @@ -343,7 +349,7 @@ static int msi_capability_init(struct pci_dev *dev) } /* Set MSI enabled bits */ - pci_intx(dev, 0); /* disable intx */ + pci_intx_for_msi(dev, 0); msi_set_enable(dev, 1); dev->msi_enabled = 1; @@ -433,7 +439,7 @@ static int msix_capability_init(struct pci_dev *dev, i++; } /* Set MSI-X enabled bits */ - pci_intx(dev, 0); /* disable intx */ + pci_intx_for_msi(dev, 0); msix_set_enable(dev, 1); dev->msix_enabled = 1; @@ -528,7 +534,7 @@ void pci_disable_msi(struct pci_dev* dev) return; msi_set_enable(dev, 0); - pci_intx(dev, 1); /* enable intx */ + pci_intx_for_msi(dev, 1); dev->msi_enabled = 0; BUG_ON(list_empty(&dev->msi_list)); @@ -640,7 +646,7 @@ void pci_disable_msix(struct pci_dev* dev) return; msix_set_enable(dev, 0); - pci_intx(dev, 1); /* enable intx */ + pci_intx_for_msi(dev, 1); dev->msix_enabled = 0; msix_free_all_irqs(dev); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f975f7fccb1dfe241537ebe58a471572d0116a29..9e8c7af0cc164cebe4eaedeb239a7a773a01e9b5 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1707,4 +1707,28 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_msi_ht_cap); + +static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) +{ + dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, + PCI_DEVICE_ID_TIGON3_5780, + quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, + PCI_DEVICE_ID_TIGON3_5780S, + quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, + PCI_DEVICE_ID_TIGON3_5714, + quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, + PCI_DEVICE_ID_TIGON3_5714S, + quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, + PCI_DEVICE_ID_TIGON3_5715, + quirk_msi_intx_disable_bug); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, + PCI_DEVICE_ID_TIGON3_5715S, + quirk_msi_intx_disable_bug); + #endif /* CONFIG_PCI_MSI */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 5d2281f661f77e70a13090d7508f8adcdbba9584..7c04f38e6ac353fe2d49a8bda4b4b8b05c191e8a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -109,6 +109,14 @@ enum pcie_reset_state { pcie_hot_reset = (__force pcie_reset_state_t) 3 }; +typedef unsigned short __bitwise pci_dev_flags_t; +enum pci_dev_flags { + /* INTX_DISABLE in PCI_COMMAND register disables MSI + * generation too. + */ + PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = (__force pci_dev_flags_t) 1, +}; + typedef unsigned short __bitwise pci_bus_flags_t; enum pci_bus_flags { PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, @@ -185,6 +193,7 @@ struct pci_dev { unsigned int msix_enabled:1; unsigned int is_managed:1; unsigned int is_pcie:1; + pci_dev_flags_t dev_flags; atomic_t enable_cnt; /* pci_enable_device has been called */ u32 saved_config_space[16]; /* config space saved at suspend time */