Skip to content

Commit

Permalink
[TG3]: Add msi test
Browse files Browse the repository at this point in the history
Add MSI test for chips that support MSI. If MSI test fails, it will
switch back to INTx mode and will print a message asking the user to
report the failure.

Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Michael Chan authored and David S. Miller committed Apr 22, 2005
1 parent 88b06bc commit 7938109
Showing 1 changed file with 151 additions and 3 deletions.
154 changes: 151 additions & 3 deletions drivers/net/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -2996,6 +2996,22 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_RETVAL(handled);
}

/* ISR for interrupt test */
static irqreturn_t tg3_test_isr(int irq, void *dev_id,
struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct tg3 *tp = netdev_priv(dev);
struct tg3_hw_status *sblk = tp->hw_status;

if (sblk->status & SD_STATUS_UPDATED) {
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000001);
return IRQ_RETVAL(1);
}
return IRQ_RETVAL(0);
}

static int tg3_init_hw(struct tg3 *);
static int tg3_halt(struct tg3 *);

Expand Down Expand Up @@ -5796,6 +5812,118 @@ static void tg3_timer(unsigned long __opaque)
add_timer(&tp->timer);
}

static int tg3_test_interrupt(struct tg3 *tp)
{
struct net_device *dev = tp->dev;
int err, i;
u32 int_mbox = 0;

tg3_disable_ints(tp);

free_irq(tp->pdev->irq, dev);

err = request_irq(tp->pdev->irq, tg3_test_isr,
SA_SHIRQ, dev->name, dev);
if (err)
return err;

tg3_enable_ints(tp);

tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
HOSTCC_MODE_NOW);

for (i = 0; i < 5; i++) {
int_mbox = tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
if (int_mbox != 0)
break;
msleep(10);
}

tg3_disable_ints(tp);

free_irq(tp->pdev->irq, dev);

if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
err = request_irq(tp->pdev->irq, tg3_msi,
0, dev->name, dev);
else
err = request_irq(tp->pdev->irq, tg3_interrupt,
SA_SHIRQ, dev->name, dev);

if (err)
return err;

if (int_mbox != 0)
return 0;

return -EIO;
}

/* Returns 0 if MSI test succeeds or MSI test fails and INTx mode is
* successfully restored
*/
static int tg3_test_msi(struct tg3 *tp)
{
struct net_device *dev = tp->dev;
int err;
u16 pci_cmd;

if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSI))
return 0;

/* Turn off SERR reporting in case MSI terminates with Master
* Abort.
*/
pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
pci_write_config_word(tp->pdev, PCI_COMMAND,
pci_cmd & ~PCI_COMMAND_SERR);

err = tg3_test_interrupt(tp);

pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);

if (!err)
return 0;

/* other failures */
if (err != -EIO)
return err;

/* MSI test failed, go back to INTx mode */
printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, "
"switching to INTx mode. Please report this failure to "
"the PCI maintainer and include system chipset information.\n",
tp->dev->name);

free_irq(tp->pdev->irq, dev);
pci_disable_msi(tp->pdev);

tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;

err = request_irq(tp->pdev->irq, tg3_interrupt,
SA_SHIRQ, dev->name, dev);

if (err)
return err;

/* Need to reset the chip because the MSI cycle may have terminated
* with Master Abort.
*/
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);

tg3_halt(tp);
err = tg3_init_hw(tp);

spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);

if (err)
free_irq(tp->pdev->irq, dev);

return err;
}

static int tg3_open(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
Expand Down Expand Up @@ -5860,9 +5988,6 @@ static int tg3_open(struct net_device *dev)
tp->timer.expires = jiffies + tp->timer_offset;
tp->timer.data = (unsigned long) tp;
tp->timer.function = tg3_timer;
add_timer(&tp->timer);

tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
}

spin_unlock(&tp->tx_lock);
Expand All @@ -5878,9 +6003,32 @@ static int tg3_open(struct net_device *dev)
return err;
}

if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
err = tg3_test_msi(tp);
if (err) {
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);

if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
pci_disable_msi(tp->pdev);
tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
}
tg3_halt(tp);
tg3_free_rings(tp);
tg3_free_consistent(tp);

spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);

return err;
}
}

spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);

add_timer(&tp->timer);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
tg3_enable_ints(tp);

spin_unlock(&tp->tx_lock);
Expand Down

0 comments on commit 7938109

Please sign in to comment.