Re: [TG3 2/3]: Exit irq handler during chip reset.

2007-03-24 Thread David Miller
From: Michael Chan [EMAIL PROTECTED]
Date: Fri, 23 Mar 2007 16:13:07 -0800

 [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 [EMAIL PROTECTED] for reporting the problem.
 
 Signed-off-by: Michael Chan [EMAIL PROTECTED]

Applied, except I fixed up some weird tabbing on this line:

 @@ -3568,32 +3568,34 @@ static irqreturn_t tg3_interrupt(int irq, void 
 *dev_id)
 ...
 + } else {
 + /* No work, shared interrupt perhaps?  re-enable
 +  * interrupts, and flush that PCI write
 +  */
 + tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
 + 0x);


There are two tabs, some space characters, then a final tab,
and it doesn't even make the argument match up to the openning
parenthesis on the previous line :-)
-
To unsubscribe from this list: send the line unsubscribe netdev in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[TG3 2/3]: Exit irq handler during chip reset.

2007-03-23 Thread Michael Chan
[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 [EMAIL PROTECTED] for reporting the problem.

Signed-off-by: Michael Chan [EMAIL PROTECTED]

diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index ab87bb1..9aca100 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)
 * Reading the PCI State register will confirm whether the
 * interrupt is ours and will flush the status block.
 */
-   if ((sblk-status  SD_STATUS_UPDATED) ||
-   !(tr32(TG3PCI_PCISTATE)  PCISTATE_INT_NOT_ACTIVE)) {
-   /*
-* Writing any value to intr-mbox-0 clears PCI INTA# and
-* chip-internal interrupt pending events.
-* Writing non-zero to intr-mbox-0 additional tells the
-* NIC to stop sending us irqs, engaging in-intr-handler
-* event coalescing.
-*/
-   tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-0x0001);
-   if (tg3_irq_sync(tp))
+   if (unlikely(!(sblk-status  SD_STATUS_UPDATED))) {
+   if ((tp-tg3_flags  TG3_FLAG_CHIP_RESETTING) ||
+   (tr32(TG3PCI_PCISTATE)  PCISTATE_INT_NOT_ACTIVE)) {
+   handled = 0;
goto out;
-   sblk-status = ~SD_STATUS_UPDATED;
-   if (likely(tg3_has_work(tp))) {
-   prefetch(tp-rx_rcb[tp-rx_rcb_ptr]);
-   netif_rx_schedule(dev); /* schedule NAPI poll */
-   } else {
-   /* No work, shared interrupt perhaps?  re-enable
-* interrupts, and flush that PCI write
-*/
-   tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-   0x);
}
-   } else {/* shared interrupt */
-   handled = 0;
+   }
+
+   /*
+* Writing any value to intr-mbox-0 clears PCI INTA# and
+* chip-internal interrupt pending events.
+* Writing non-zero to intr-mbox-0 additional tells the
+* NIC to stop sending us irqs, engaging in-intr-handler
+* event coalescing.
+*/
+   tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x0001);
+   if (tg3_irq_sync(tp))
+   goto out;
+   sblk-status = ~SD_STATUS_UPDATED;
+   if (likely(tg3_has_work(tp))) {
+   prefetch(tp-rx_rcb[tp-rx_rcb_ptr]);
+   netif_rx_schedule(dev); /* schedule NAPI poll */
+   } else {
+   /* No work, shared interrupt perhaps?  re-enable
+* interrupts, and flush that PCI write
+*/
+   tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+   0x);
}
 out:
return IRQ_RETVAL(handled);
@@ -3611,31 +3613,33 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void 
*dev_id)
 * Reading the PCI State register will confirm whether the
 * interrupt is ours and will flush the status block.
 */
-   if ((sblk-status_tag != tp-last_tag) ||
-   !(tr32(TG3PCI_PCISTATE)  PCISTATE_INT_NOT_ACTIVE)) {
-   /*
-* writing any value to intr-mbox-0 clears PCI INTA# and
-* chip-internal interrupt pending events.
-* writing non-zero to intr-mbox-0 additional tells the
-* NIC to stop sending us irqs, engaging in-intr-handler
-* event coalescing.
-*/
-   tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-0x0001);
-   if (tg3_irq_sync(tp))
+   if (unlikely(sblk-status_tag == tp-last_tag)) {
+   if ((tp-tg3_flags  TG3_FLAG_CHIP_RESETTING) ||
+   (tr32(TG3PCI_PCISTATE)  PCISTATE_INT_NOT_ACTIVE)) {
+   handled = 0;
goto out;
-   if (netif_rx_schedule_prep(dev)) {
-   prefetch(tp-rx_rcb[tp-rx_rcb_ptr]);
-   /* Update last_tag to mark