diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2011-06-13 13:38:55 +0000 |
---|---|---|
committer | David S. Miller <davem@conan.davemloft.net> | 2011-06-15 11:11:55 -0400 |
commit | 0e6cf6a9e3cf911577b1dde0dc724f634e4ca119 (patch) | |
tree | 8a974393bd1fba47688223f771d3035657d306c4 | |
parent | b96368e9365a4db7429da87cfd25bb54b24954f8 (diff) |
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 <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Reviewed-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: David S. Miller <davem@conan.davemloft.net>
-rw-r--r-- | drivers/net/tg3.c | 38 | ||||
-rw-r--r-- | 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 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; |