diff mbox

[net-next,1/8] tg3: Workaround tagged status update bug

Message ID 1308008342-21030-2-git-send-email-mcarlson@broadcom.com
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Matt Carlson June 13, 2011, 11:38 p.m. UTC
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>
---
 drivers/net/tg3.c |   38 +++++++++++++++++++++++++++++++++++++-
 drivers/net/tg3.h |    3 +++
 2 files changed, 40 insertions(+), 1 deletions(-)
diff mbox

Patch

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;