aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2007-03-24 23:57:11 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-03-25 21:48:08 -0400
commitd18edcb212d7dc864a59e6aa9b6b9826299e0210 (patch)
tree341955faabd7db53af392f4bdbd856dcbe6f8d11
parent1c46ae05d96f77f349ae60c799acb6ac6ddf07a8 (diff)
[TG3]: Exit irq handler during chip reset.
On most tg3 chips, the memory enable bit in the PCI command register gets cleared during chip reset and must be restored before accessing PCI registers using memory cycles. The chip does not generate interrupt during chip reset, but the irq handler can still be called because of irq sharing or irqpoll. Reading a register in the irq handler can cause a master abort in this scenario and may result in a crash on some architectures. Use the TG3_FLAG_CHIP_RESETTING flag to tell the irq handler to exit without touching any registers. The checking of the flag is in the "slow" path of the irq handler and will not affect normal performance. The msi handler is not shared and therefore does not require checking the flag. Thanks to Bernhard Walle <bwalle@suse.de> for reporting the problem. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/tg3.c113
-rw-r--r--drivers/net/tg3.h1
2 files changed, 67 insertions, 47 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index ab87bb1893a5..26dcd1c36b30 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3568,32 +3568,34 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id)
3568 * Reading the PCI State register will confirm whether the 3568 * Reading the PCI State register will confirm whether the
3569 * interrupt is ours and will flush the status block. 3569 * interrupt is ours and will flush the status block.
3570 */ 3570 */
3571 if ((sblk->status & SD_STATUS_UPDATED) || 3571 if (unlikely(!(sblk->status & SD_STATUS_UPDATED))) {
3572 !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { 3572 if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) ||
3573 /* 3573 (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
3574 * Writing any value to intr-mbox-0 clears PCI INTA# and 3574 handled = 0;
3575 * chip-internal interrupt pending events.
3576 * Writing non-zero to intr-mbox-0 additional tells the
3577 * NIC to stop sending us irqs, engaging "in-intr-handler"
3578 * event coalescing.
3579 */
3580 tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
3581 0x00000001);
3582 if (tg3_irq_sync(tp))
3583 goto out; 3575 goto out;
3584 sblk->status &= ~SD_STATUS_UPDATED;
3585 if (likely(tg3_has_work(tp))) {
3586 prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
3587 netif_rx_schedule(dev); /* schedule NAPI poll */
3588 } else {
3589 /* No work, shared interrupt perhaps? re-enable
3590 * interrupts, and flush that PCI write
3591 */
3592 tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
3593 0x00000000);
3594 } 3576 }
3595 } else { /* shared interrupt */ 3577 }
3596 handled = 0; 3578
3579 /*
3580 * Writing any value to intr-mbox-0 clears PCI INTA# and
3581 * chip-internal interrupt pending events.
3582 * Writing non-zero to intr-mbox-0 additional tells the
3583 * NIC to stop sending us irqs, engaging "in-intr-handler"
3584 * event coalescing.
3585 */
3586 tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
3587 if (tg3_irq_sync(tp))
3588 goto out;
3589 sblk->status &= ~SD_STATUS_UPDATED;
3590 if (likely(tg3_has_work(tp))) {
3591 prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
3592 netif_rx_schedule(dev); /* schedule NAPI poll */
3593 } else {
3594 /* No work, shared interrupt perhaps? re-enable
3595 * interrupts, and flush that PCI write
3596 */
3597 tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
3598 0x00000000);
3597 } 3599 }
3598out: 3600out:
3599 return IRQ_RETVAL(handled); 3601 return IRQ_RETVAL(handled);
@@ -3611,31 +3613,33 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
3611 * Reading the PCI State register will confirm whether the 3613 * Reading the PCI State register will confirm whether the
3612 * interrupt is ours and will flush the status block. 3614 * interrupt is ours and will flush the status block.
3613 */ 3615 */
3614 if ((sblk->status_tag != tp->last_tag) || 3616 if (unlikely(sblk->status_tag == tp->last_tag)) {
3615 !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { 3617 if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) ||
3616 /* 3618 (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
3617 * writing any value to intr-mbox-0 clears PCI INTA# and 3619 handled = 0;
3618 * chip-internal interrupt pending events.
3619 * writing non-zero to intr-mbox-0 additional tells the
3620 * NIC to stop sending us irqs, engaging "in-intr-handler"
3621 * event coalescing.
3622 */
3623 tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
3624 0x00000001);
3625 if (tg3_irq_sync(tp))
3626 goto out; 3620 goto out;
3627 if (netif_rx_schedule_prep(dev)) {
3628 prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
3629 /* Update last_tag to mark that this status has been
3630 * seen. Because interrupt may be shared, we may be
3631 * racing with tg3_poll(), so only update last_tag
3632 * if tg3_poll() is not scheduled.
3633 */
3634 tp->last_tag = sblk->status_tag;
3635 __netif_rx_schedule(dev);
3636 } 3621 }
3637 } else { /* shared interrupt */ 3622 }
3638 handled = 0; 3623
3624 /*
3625 * writing any value to intr-mbox-0 clears PCI INTA# and
3626 * chip-internal interrupt pending events.
3627 * writing non-zero to intr-mbox-0 additional tells the
3628 * NIC to stop sending us irqs, engaging "in-intr-handler"
3629 * event coalescing.
3630 */
3631 tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
3632 if (tg3_irq_sync(tp))
3633 goto out;
3634 if (netif_rx_schedule_prep(dev)) {
3635 prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
3636 /* Update last_tag to mark that this status has been
3637 * seen. Because interrupt may be shared, we may be
3638 * racing with tg3_poll(), so only update last_tag
3639 * if tg3_poll() is not scheduled.
3640 */
3641 tp->last_tag = sblk->status_tag;
3642 __netif_rx_schedule(dev);
3639 } 3643 }
3640out: 3644out:
3641 return IRQ_RETVAL(handled); 3645 return IRQ_RETVAL(handled);
@@ -4823,6 +4827,19 @@ static int tg3_chip_reset(struct tg3 *tp)
4823 if (write_op == tg3_write_flush_reg32) 4827 if (write_op == tg3_write_flush_reg32)
4824 tp->write32 = tg3_write32; 4828 tp->write32 = tg3_write32;
4825 4829
4830 /* Prevent the irq handler from reading or writing PCI registers
4831 * during chip reset when the memory enable bit in the PCI command
4832 * register may be cleared. The chip does not generate interrupt
4833 * at this time, but the irq handler may still be called due to irq
4834 * sharing or irqpoll.
4835 */
4836 tp->tg3_flags |= TG3_FLAG_CHIP_RESETTING;
4837 tp->hw_status->status = 0;
4838 tp->hw_status->status_tag = 0;
4839 tp->last_tag = 0;
4840 smp_mb();
4841 synchronize_irq(tp->pdev->irq);
4842
4826 /* do the reset */ 4843 /* do the reset */
4827 val = GRC_MISC_CFG_CORECLK_RESET; 4844 val = GRC_MISC_CFG_CORECLK_RESET;
4828 4845
@@ -4904,6 +4921,8 @@ static int tg3_chip_reset(struct tg3 *tp)
4904 4921
4905 pci_restore_state(tp->pdev); 4922 pci_restore_state(tp->pdev);
4906 4923
4924 tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING;
4925
4907 /* Make sure PCI-X relaxed ordering bit is clear. */ 4926 /* Make sure PCI-X relaxed ordering bit is clear. */
4908 pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val); 4927 pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
4909 val &= ~PCIX_CAPS_RELAXED_ORDERING; 4928 val &= ~PCIX_CAPS_RELAXED_ORDERING;
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 5df8f76cdfe7..d515ed23841b 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2223,6 +2223,7 @@ struct tg3 {
2223#define TG3_FLAG_40BIT_DMA_BUG 0x08000000 2223#define TG3_FLAG_40BIT_DMA_BUG 0x08000000
2224#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 2224#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
2225#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 2225#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000
2226#define TG3_FLAG_CHIP_RESETTING 0x40000000
2226#define TG3_FLAG_INIT_COMPLETE 0x80000000 2227#define TG3_FLAG_INIT_COMPLETE 0x80000000
2227 u32 tg3_flags2; 2228 u32 tg3_flags2;
2228#define TG3_FLG2_RESTART_TIMER 0x00000001 2229#define TG3_FLG2_RESTART_TIMER 0x00000001