From 5e8784363bad1a38e88caab5eced9700f5d51672 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Thu, 3 Apr 2008 16:01:07 -0400 Subject: [PATCH] PCI: Add quirk for devices which disable MSI when INTX_DISABLE is set. Backport of upstream commit: commit ba698ad4b7e466cbb4a8bde6b9da8080ab06808d Author: David Miller Date: Thu Oct 25 01:16:30 2007 -0700 PCI: Add quirk for devices which disable MSI when INTX_DISABLE is set. A reasonably common problem with some devices is that they will disable MSI generation when the INTX_DISABLE bit is set in the PCI_COMMAND register. Quirk this explicitly, guarding the pci_intx() calls in msi.c with this quirk indication. The first entries for this quirk are for 5714 and 5780 Tigon3 chips, and thus we can remove the workaround code from the tg3.c driver. --- drivers/net/tg3.c | 9 --------- drivers/pci/msi.c | 11 +++++++++-- drivers/pci/quirks.c | 24 ++++++++++++++++++++++++ include/linux/pci.h | 9 +++++++++ 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 81f1575..6f16c90 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7422,10 +7422,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; @@ -12802,11 +12798,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 2a63a74..d18966d 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -433,6 +433,13 @@ static void irq_handler_init(int cap_id, int pos, int mask) spin_unlock_irqrestore(&irq_desc[pos].lock, flags); } + +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); +} + static void enable_msi_mode(struct pci_dev *dev, int pos, int type) { u16 control; @@ -450,7 +457,7 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type) } if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { /* PCI Express Endpoint device detected */ - pci_intx(dev, 0); /* disable intx */ + pci_intx_for_msi(dev, 0); /* disable intx */ } } @@ -471,7 +478,7 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) } if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { /* PCI Express Endpoint device detected */ - pci_intx(dev, 1); /* enable intx */ + pci_intx_for_msi(dev, 1); /* enable intx */ } } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ca70481..ad0dd11 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1866,4 +1866,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 3b2bcb1..2b6bf79 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -107,6 +107,14 @@ enum pcie_reset_state { pci_reset_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, @@ -182,6 +190,7 @@ struct pci_dev { unsigned int msix_enabled:1; #ifndef __GENKSYMS__ unsigned int is_managed:1; + pci_dev_flags_t dev_flags; #endif u32 saved_config_space[16]; /* config space saved at suspend time */ -- 1.5.2.1