From 0e6cf6a9e3cf911577b1dde0dc724f634e4ca119 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 13 Jun 2011 13:38:55 +0000 Subject: [PATCH] tg3: Workaround tagged status update bug 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 Signed-off-by: Michael Chan Reviewed-by: Benjamin Li Signed-off-by: David S. Miller --- drivers/net/tg3.c | 38 +++++++++++++++++++++++++++++++++++++- drivers/net/tg3.h | 3 +++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index aa1d1defc820..46352da36a81 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7754,6 +7754,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)) { @@ -7764,6 +7767,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); @@ -8819,6 +8825,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; @@ -8828,6 +8858,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 @@ -9303,7 +9337,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 5b3d2f34da7a..3c113c1e9d35 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; -- 2.11.0