Skip to content

Commit

Permalink
PCI: Add quirk for devices which disable MSI when INTX_DISABLE is set.
Browse files Browse the repository at this point in the history
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: David S. Miller <davem@davemloft.net>
Acked-by: Michael Chan <mchan@broadcom.com>
Acked-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
David Miller authored and Greg Kroah-Hartman committed Nov 5, 2007
1 parent 1d84b54 commit ba698ad
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 15 deletions.
9 changes: 0 additions & 9 deletions drivers/net/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 12 additions & 6 deletions drivers/pci/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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)
Expand All @@ -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) {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions drivers/pci/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
9 changes: 9 additions & 0 deletions include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit ba698ad

Please sign in to comment.