aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2010-02-12 09:47:07 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-12 20:05:52 -0500
commitf89f38b8ec3171664314669a1396ab70b43e8961 (patch)
treed25cbb07060c2089482920f7178b13490103a5fb /drivers/net
parente92967bfb1f4fa7da7c425df9239c4bb615dec30 (diff)
tg3: Unwedge stuck MSI-X vectors
The previous patch changed the code so that new rx buffer submissions to the hardware stall if a new submission would overwrite data needed by an unserviced rx packet. On very busy 5717 and 57765 asic rev devices, there is a corner case where the hardware will fail to assert an MSI-X interrupt for rx traffic. If that vector's interrupt never has another reason to assert, any rx buffers held will never be serviced. If the buffers are never serviced and the hardware consumes all the available rx packets for other rx rings, deadlock will result. The most reliable and least intrusive way to work around the problem is to detect the case where new submissions would overwrite existing data and force all rx interrupt vectors to fire. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Reviewed-by: Michael Chan <mchan@broadcom.com> Reviewed-by: Benjamin Li <benli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/tg3.c29
-rw-r--r--drivers/net/tg3.h1
2 files changed, 20 insertions, 10 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index a46c26764ba7..c140e1bf6e02 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -642,7 +642,6 @@ static void tg3_disable_ints(struct tg3 *tp)
642static void tg3_enable_ints(struct tg3 *tp) 642static void tg3_enable_ints(struct tg3 *tp)
643{ 643{
644 int i; 644 int i;
645 u32 coal_now = 0;
646 645
647 tp->irq_sync = 0; 646 tp->irq_sync = 0;
648 wmb(); 647 wmb();
@@ -650,13 +649,14 @@ static void tg3_enable_ints(struct tg3 *tp)
650 tw32(TG3PCI_MISC_HOST_CTRL, 649 tw32(TG3PCI_MISC_HOST_CTRL,
651 (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); 650 (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
652 651
652 tp->coal_now = tp->coalesce_mode | HOSTCC_MODE_ENABLE;
653 for (i = 0; i < tp->irq_cnt; i++) { 653 for (i = 0; i < tp->irq_cnt; i++) {
654 struct tg3_napi *tnapi = &tp->napi[i]; 654 struct tg3_napi *tnapi = &tp->napi[i];
655 tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); 655 tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24);
656 if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) 656 if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
657 tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); 657 tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24);
658 658
659 coal_now |= tnapi->coal_now; 659 tp->coal_now |= tnapi->coal_now;
660 } 660 }
661 661
662 /* Force an initial interrupt */ 662 /* Force an initial interrupt */
@@ -664,8 +664,9 @@ static void tg3_enable_ints(struct tg3 *tp)
664 (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) 664 (tp->napi[0].hw_status->status & SD_STATUS_UPDATED))
665 tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); 665 tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
666 else 666 else
667 tw32(HOSTCC_MODE, tp->coalesce_mode | 667 tw32(HOSTCC_MODE, tp->coal_now);
668 HOSTCC_MODE_ENABLE | coal_now); 668
669 tp->coal_now &= ~(tp->napi[0].coal_now | tp->napi[1].coal_now);
669} 670}
670 671
671static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) 672static inline unsigned int tg3_has_work(struct tg3_napi *tnapi)
@@ -4794,12 +4795,12 @@ static void tg3_poll_link(struct tg3 *tp)
4794 } 4795 }
4795} 4796}
4796 4797
4797static void tg3_rx_prodring_xfer(struct tg3 *tp, 4798static int tg3_rx_prodring_xfer(struct tg3 *tp,
4798 struct tg3_rx_prodring_set *dpr, 4799 struct tg3_rx_prodring_set *dpr,
4799 struct tg3_rx_prodring_set *spr) 4800 struct tg3_rx_prodring_set *spr)
4800{ 4801{
4801 u32 si, di, cpycnt, src_prod_idx; 4802 u32 si, di, cpycnt, src_prod_idx;
4802 int i; 4803 int i, err = 0;
4803 4804
4804 while (1) { 4805 while (1) {
4805 src_prod_idx = spr->rx_std_prod_idx; 4806 src_prod_idx = spr->rx_std_prod_idx;
@@ -4825,6 +4826,7 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp,
4825 for (i = di; i < di + cpycnt; i++) { 4826 for (i = di; i < di + cpycnt; i++) {
4826 if (dpr->rx_std_buffers[i].skb) { 4827 if (dpr->rx_std_buffers[i].skb) {
4827 cpycnt = i - di; 4828 cpycnt = i - di;
4829 err = -ENOSPC;
4828 break; 4830 break;
4829 } 4831 }
4830 } 4832 }
@@ -4881,6 +4883,7 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp,
4881 for (i = di; i < di + cpycnt; i++) { 4883 for (i = di; i < di + cpycnt; i++) {
4882 if (dpr->rx_jmb_buffers[i].skb) { 4884 if (dpr->rx_jmb_buffers[i].skb) {
4883 cpycnt = i - di; 4885 cpycnt = i - di;
4886 err = -ENOSPC;
4884 break; 4887 break;
4885 } 4888 }
4886 } 4889 }
@@ -4911,6 +4914,8 @@ static void tg3_rx_prodring_xfer(struct tg3 *tp,
4911 dpr->rx_jmb_prod_idx = (dpr->rx_jmb_prod_idx + cpycnt) % 4914 dpr->rx_jmb_prod_idx = (dpr->rx_jmb_prod_idx + cpycnt) %
4912 TG3_RX_JUMBO_RING_SIZE; 4915 TG3_RX_JUMBO_RING_SIZE;
4913 } 4916 }
4917
4918 return err;
4914} 4919}
4915 4920
4916static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) 4921static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
@@ -4933,12 +4938,13 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
4933 4938
4934 if ((tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) && tnapi == &tp->napi[1]) { 4939 if ((tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) && tnapi == &tp->napi[1]) {
4935 struct tg3_rx_prodring_set *dpr = &tp->prodring[0]; 4940 struct tg3_rx_prodring_set *dpr = &tp->prodring[0];
4936 int i; 4941 int i, err = 0;
4937 u32 std_prod_idx = dpr->rx_std_prod_idx; 4942 u32 std_prod_idx = dpr->rx_std_prod_idx;
4938 u32 jmb_prod_idx = dpr->rx_jmb_prod_idx; 4943 u32 jmb_prod_idx = dpr->rx_jmb_prod_idx;
4939 4944
4940 for (i = 1; i < tp->irq_cnt; i++) 4945 for (i = 1; i < tp->irq_cnt; i++)
4941 tg3_rx_prodring_xfer(tp, dpr, tp->napi[i].prodring); 4946 err |= tg3_rx_prodring_xfer(tp, dpr,
4947 tp->napi[i].prodring);
4942 4948
4943 wmb(); 4949 wmb();
4944 4950
@@ -4951,6 +4957,9 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
4951 dpr->rx_jmb_prod_idx); 4957 dpr->rx_jmb_prod_idx);
4952 4958
4953 mmiowb(); 4959 mmiowb();
4960
4961 if (err)
4962 tw32_f(HOSTCC_MODE, tp->coal_now);
4954 } 4963 }
4955 4964
4956 return work_done; 4965 return work_done;
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 88a87bb618c0..cc8bf7d6823a 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2699,6 +2699,7 @@ struct tg3 {
2699 struct net_device *dev; 2699 struct net_device *dev;
2700 struct pci_dev *pdev; 2700 struct pci_dev *pdev;
2701 2701
2702 u32 coal_now;
2702 u32 msg_enable; 2703 u32 msg_enable;
2703 2704
2704 /* begin "tx thread" cacheline section */ 2705 /* begin "tx thread" cacheline section */