[PATCH net-next 1/8] tg3: Workaround tagged status update bug
From: Matt Carlson <hidden>
Date: 2011-06-13 23:38:19
Subsystem:
networking drivers, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
On rare occasions, writing the tag to the interrupt mailbox does not reenable interrupts. This patch fixes the problem by reissuing the mailbox update. Signed-off-by: Matt Carlson <redacted> Signed-off-by: Michael Chan <mchan@broadcom.com> Reviewed-by: Benjamin Li <redacted> --- drivers/net/tg3.c | 38 +++++++++++++++++++++++++++++++++++++- drivers/net/tg3.h | 3 +++ 2 files changed, 40 insertions(+), 1 deletions(-)
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index c8a145d..e8f16c5 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c@@ -7752,6 +7752,9 @@ static void tg3_rings_reset(struct tg3 *tp) /* Disable interrupts */ tw32_mailbox_f(tp->napi[0].int_mbox, 1); + tp->napi[0].chk_msi_cnt = 0; + tp->napi[0].last_rx_cons = 0; + tp->napi[0].last_tx_cons = 0; /* Zero mailbox registers. */ if (tg3_flag(tp, SUPPORT_MSIX)) {
@@ -7762,6 +7765,9 @@ static void tg3_rings_reset(struct tg3 *tp) tw32_mailbox(tp->napi[i].prodmbox, 0); tw32_rx_mbox(tp->napi[i].consmbox, 0); tw32_mailbox_f(tp->napi[i].int_mbox, 1); + tp->napi[0].chk_msi_cnt = 0; + tp->napi[i].last_rx_cons = 0; + tp->napi[i].last_tx_cons = 0; } if (!tg3_flag(tp, ENABLE_TSS)) tw32_mailbox(tp->napi[0].prodmbox, 0);
@@ -8817,6 +8823,30 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp) TG3_STAT_ADD32(&sp->rx_errors, RCVLPC_IN_ERRORS_CNT); } +static void tg3_chk_missed_msi(struct tg3 *tp) +{ + u32 i; + + for (i = 0; i < tp->irq_cnt; i++) { + struct tg3_napi *tnapi = &tp->napi[i]; + + if (tg3_has_work(tnapi)) { + if (tnapi->last_rx_cons == tnapi->rx_rcb_ptr && + tnapi->last_tx_cons == tnapi->tx_cons) { + if (tnapi->chk_msi_cnt < 1) { + tnapi->chk_msi_cnt++; + return; + } + tw32_mailbox(tnapi->int_mbox, + tnapi->last_tag << 24); + } + } + tnapi->chk_msi_cnt = 0; + tnapi->last_rx_cons = tnapi->rx_rcb_ptr; + tnapi->last_tx_cons = tnapi->tx_cons; + } +} + static void tg3_timer(unsigned long __opaque) { struct tg3 *tp = (struct tg3 *) __opaque;
@@ -8826,6 +8856,10 @@ static void tg3_timer(unsigned long __opaque) spin_lock(&tp->lock); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) + tg3_chk_missed_msi(tp); + if (!tg3_flag(tp, TAGGED_STATUS)) { /* All of this garbage is because when using non-tagged * IRQ status the mailbox/status_block protocol the chip
@@ -9301,7 +9335,9 @@ static int tg3_open(struct net_device *dev) tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); } else { - if (tg3_flag(tp, TAGGED_STATUS)) + if (tg3_flag(tp, TAGGED_STATUS) && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) tp->timer_offset = HZ; else tp->timer_offset = HZ / 10;
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 5b3d2f3..3c113c1 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h@@ -2800,6 +2800,7 @@ struct tg3_napi { struct tg3 *tp; struct tg3_hw_status *hw_status; + u32 chk_msi_cnt; u32 last_tag; u32 last_irq_tag; u32 int_mbox;
@@ -2807,6 +2808,7 @@ struct tg3_napi { u32 consmbox ____cacheline_aligned; u32 rx_rcb_ptr; + u32 last_rx_cons; u16 *rx_rcb_prod_idx; struct tg3_rx_prodring_set prodring; struct tg3_rx_buffer_desc *rx_rcb;
@@ -2814,6 +2816,7 @@ struct tg3_napi { u32 tx_prod ____cacheline_aligned; u32 tx_cons; u32 tx_pending; + u32 last_tx_cons; u32 prodmbox; struct tg3_tx_buffer_desc *tx_ring; struct ring_info *tx_buffers;
--
1.7.3.4