Commit ba698ad4 authored by David Miller's avatar David Miller Committed by Greg Kroah-Hartman

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.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Acked-by: default avatarMichael Chan <mchan@broadcom.com>
Acked-by: default avatarJeff Garzik <jgarzik@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 1d84b542
...@@ -7365,10 +7365,6 @@ static int tg3_open(struct net_device *dev) ...@@ -7365,10 +7365,6 @@ static int tg3_open(struct net_device *dev)
} else if (pci_enable_msi(tp->pdev) == 0) { } else if (pci_enable_msi(tp->pdev) == 0) {
u32 msi_mode; 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); msi_mode = tr32(MSGINT_MODE);
tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE); tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
tp->tg3_flags2 |= TG3_FLG2_USING_MSI; tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
...@@ -12681,11 +12677,6 @@ static int tg3_resume(struct pci_dev *pdev) ...@@ -12681,11 +12677,6 @@ static int tg3_resume(struct pci_dev *pdev)
if (err) if (err)
return 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); netif_device_attach(dev);
tg3_full_lock(tp, 0); tg3_full_lock(tp, 0);
......
...@@ -224,6 +224,12 @@ static struct msi_desc* alloc_msi_entry(void) ...@@ -224,6 +224,12 @@ static struct msi_desc* alloc_msi_entry(void)
return entry; 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 #ifdef CONFIG_PM
static void __pci_restore_msi_state(struct pci_dev *dev) static void __pci_restore_msi_state(struct pci_dev *dev)
{ {
...@@ -237,7 +243,7 @@ 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); entry = get_irq_msi(dev->irq);
pos = entry->msi_attrib.pos; pos = entry->msi_attrib.pos;
pci_intx(dev, 0); /* disable intx */ pci_intx_for_msi(dev, 0);
msi_set_enable(dev, 0); msi_set_enable(dev, 0);
write_msi_msg(dev->irq, &entry->msg); write_msi_msg(dev->irq, &entry->msg);
if (entry->msi_attrib.maskbit) if (entry->msi_attrib.maskbit)
...@@ -260,7 +266,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) ...@@ -260,7 +266,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
return; return;
/* route the table */ /* route the table */
pci_intx(dev, 0); /* disable intx */ pci_intx_for_msi(dev, 0);
msix_set_enable(dev, 0); msix_set_enable(dev, 0);
list_for_each_entry(entry, &dev->msi_list, list) { list_for_each_entry(entry, &dev->msi_list, list) {
...@@ -343,7 +349,7 @@ static int msi_capability_init(struct pci_dev *dev) ...@@ -343,7 +349,7 @@ static int msi_capability_init(struct pci_dev *dev)
} }
/* Set MSI enabled bits */ /* Set MSI enabled bits */
pci_intx(dev, 0); /* disable intx */ pci_intx_for_msi(dev, 0);
msi_set_enable(dev, 1); msi_set_enable(dev, 1);
dev->msi_enabled = 1; dev->msi_enabled = 1;
...@@ -433,7 +439,7 @@ static int msix_capability_init(struct pci_dev *dev, ...@@ -433,7 +439,7 @@ static int msix_capability_init(struct pci_dev *dev,
i++; i++;
} }
/* Set MSI-X enabled bits */ /* Set MSI-X enabled bits */
pci_intx(dev, 0); /* disable intx */ pci_intx_for_msi(dev, 0);
msix_set_enable(dev, 1); msix_set_enable(dev, 1);
dev->msix_enabled = 1; dev->msix_enabled = 1;
...@@ -528,7 +534,7 @@ void pci_disable_msi(struct pci_dev* dev) ...@@ -528,7 +534,7 @@ void pci_disable_msi(struct pci_dev* dev)
return; return;
msi_set_enable(dev, 0); msi_set_enable(dev, 0);
pci_intx(dev, 1); /* enable intx */ pci_intx_for_msi(dev, 1);
dev->msi_enabled = 0; dev->msi_enabled = 0;
BUG_ON(list_empty(&dev->msi_list)); BUG_ON(list_empty(&dev->msi_list));
...@@ -640,7 +646,7 @@ void pci_disable_msix(struct pci_dev* dev) ...@@ -640,7 +646,7 @@ void pci_disable_msix(struct pci_dev* dev)
return; return;
msix_set_enable(dev, 0); msix_set_enable(dev, 0);
pci_intx(dev, 1); /* enable intx */ pci_intx_for_msi(dev, 1);
dev->msix_enabled = 0; dev->msix_enabled = 0;
msix_free_all_irqs(dev); msix_free_all_irqs(dev);
......
...@@ -1707,4 +1707,28 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) ...@@ -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, DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_msi_ht_cap); 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 */ #endif /* CONFIG_PCI_MSI */
...@@ -109,6 +109,14 @@ enum pcie_reset_state { ...@@ -109,6 +109,14 @@ enum pcie_reset_state {
pcie_hot_reset = (__force pcie_reset_state_t) 3 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; typedef unsigned short __bitwise pci_bus_flags_t;
enum pci_bus_flags { enum pci_bus_flags {
PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
...@@ -185,6 +193,7 @@ struct pci_dev { ...@@ -185,6 +193,7 @@ struct pci_dev {
unsigned int msix_enabled:1; unsigned int msix_enabled:1;
unsigned int is_managed:1; unsigned int is_managed:1;
unsigned int is_pcie:1; unsigned int is_pcie:1;
pci_dev_flags_t dev_flags;
atomic_t enable_cnt; /* pci_enable_device has been called */ atomic_t enable_cnt; /* pci_enable_device has been called */
u32 saved_config_space[16]; /* config space saved at suspend time */ u32 saved_config_space[16]; /* config space saved at suspend time */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment