aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2009-04-20 02:55:01 -0400
committerDavid S. Miller <davem@davemloft.net>2009-04-21 04:41:00 -0400
commit624f8e5082efd0348ccf7e3d3f4bfc41efead26c (patch)
treebd6bfc88f62b49fc377101b4f268b0b00b101ea7 /drivers
parente5e9743bb7429f53c83ad69b432f7b661e74c3f0 (diff)
tg3: Allow screaming interrupt detection
The tg3 driver's ISR is coded to accept interrupts as its own if the status block tag does not equal the last tag the driver has seen. The last_tag field is updated from tg3_poll. In a screaming interrupt situation from another device sharing tg3's IRQ, tg3_poll does not get a chance to be called, so the last_tag will always be out of sync with the status block tag. Consequently, the driver will continually declare the screaming interrupts as its own, thus thwarting the screaming interrupt detection logic. This patch solves the problem by creating a new last_irq_tag member and recording the status block tag in the ISR. The ISR then checks the last_irq_tag for interrupt ownership. Many thanks to John Marvin for the detailed bug report and analysis and Michael Chan for the bugfix. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Signed-off-by: Michael Chan <mchan@broadcom.com> Tested-by: John Marvin <jsm@fc.hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/tg3.c29
-rw-r--r--drivers/net/tg3.h1
2 files changed, 18 insertions, 12 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 201be425643a..e4fa02c79278 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -4656,6 +4656,7 @@ static int tg3_poll(struct napi_struct *napi, int budget)
4656 * so we must read it before checking for more work. 4656 * so we must read it before checking for more work.
4657 */ 4657 */
4658 tp->last_tag = sblk->status_tag; 4658 tp->last_tag = sblk->status_tag;
4659 tp->last_irq_tag = tp->last_tag;
4659 rmb(); 4660 rmb();
4660 } else 4661 } else
4661 sblk->status &= ~SD_STATUS_UPDATED; 4662 sblk->status &= ~SD_STATUS_UPDATED;
@@ -4811,7 +4812,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
4811 * Reading the PCI State register will confirm whether the 4812 * Reading the PCI State register will confirm whether the
4812 * interrupt is ours and will flush the status block. 4813 * interrupt is ours and will flush the status block.
4813 */ 4814 */
4814 if (unlikely(sblk->status_tag == tp->last_tag)) { 4815 if (unlikely(sblk->status_tag == tp->last_irq_tag)) {
4815 if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) || 4816 if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) ||
4816 (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { 4817 (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
4817 handled = 0; 4818 handled = 0;
@@ -4831,18 +4832,22 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
4831 * excessive spurious interrupts can be worse in some cases. 4832 * excessive spurious interrupts can be worse in some cases.
4832 */ 4833 */
4833 tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); 4834 tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
4835
4836 /*
4837 * In a shared interrupt configuration, sometimes other devices'
4838 * interrupts will scream. We record the current status tag here
4839 * so that the above check can report that the screaming interrupts
4840 * are unhandled. Eventually they will be silenced.
4841 */
4842 tp->last_irq_tag = sblk->status_tag;
4843
4834 if (tg3_irq_sync(tp)) 4844 if (tg3_irq_sync(tp))
4835 goto out; 4845 goto out;
4836 if (napi_schedule_prep(&tp->napi)) { 4846
4837 prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); 4847 prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
4838 /* Update last_tag to mark that this status has been 4848
4839 * seen. Because interrupt may be shared, we may be 4849 napi_schedule(&tp->napi);
4840 * racing with tg3_poll(), so only update last_tag 4850
4841 * if tg3_poll() is not scheduled.
4842 */
4843 tp->last_tag = sblk->status_tag;
4844 __napi_schedule(&tp->napi);
4845 }
4846out: 4851out:
4847 return IRQ_RETVAL(handled); 4852 return IRQ_RETVAL(handled);
4848} 4853}
@@ -6156,6 +6161,7 @@ static int tg3_chip_reset(struct tg3 *tp)
6156 tp->hw_status->status_tag = 0; 6161 tp->hw_status->status_tag = 0;
6157 } 6162 }
6158 tp->last_tag = 0; 6163 tp->last_tag = 0;
6164 tp->last_irq_tag = 0;
6159 smp_mb(); 6165 smp_mb();
6160 synchronize_irq(tp->pdev->irq); 6166 synchronize_irq(tp->pdev->irq);
6161 6167
@@ -7138,7 +7144,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
7138 udelay(100); 7144 udelay(100);
7139 7145
7140 tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); 7146 tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
7141 tp->last_tag = 0;
7142 7147
7143 if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { 7148 if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
7144 tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); 7149 tw32_f(DMAC_MODE, DMAC_MODE_ENABLE);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index cb4c62abdd21..ca71a49a3fd5 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2501,6 +2501,7 @@ struct tg3 {
2501 struct tg3_hw_status *hw_status; 2501 struct tg3_hw_status *hw_status;
2502 dma_addr_t status_mapping; 2502 dma_addr_t status_mapping;
2503 u32 last_tag; 2503 u32 last_tag;
2504 u32 last_irq_tag;
2504 2505
2505 u32 msg_enable; 2506 u32 msg_enable;
2506 2507