aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2011-03-02 08:00:50 -0500
committerDavid S. Miller <davem@davemloft.net>2011-03-02 18:57:51 -0500
commit0197b087ed6384760656f1e4a620a3e92d8dc0b0 (patch)
tree352d590c2f23cc541c6b796da6ac0e690812186f /drivers/net
parent107c3f4d42adc9af393019b795dd2177fbe9e465 (diff)
cnic: Fix lost interrupt on bnx2x
We service 2 queues (kcq1 and kcq2) in cnic_service_bnx2x_bh(). If the status block index has changed when servicing the kcq2, we must go back and check kcq1. The latest status block index will be used to acknowledge the interrupt, and without looping back to check kcq1, we may miss events on kcq1. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/cnic.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index b0d9e4ab6467..302be4aa69d6 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -2914,26 +2914,35 @@ static void cnic_service_bnx2x_bh(unsigned long data)
2914{ 2914{
2915 struct cnic_dev *dev = (struct cnic_dev *) data; 2915 struct cnic_dev *dev = (struct cnic_dev *) data;
2916 struct cnic_local *cp = dev->cnic_priv; 2916 struct cnic_local *cp = dev->cnic_priv;
2917 u32 status_idx; 2917 u32 status_idx, new_status_idx;
2918 2918
2919 if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags))) 2919 if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
2920 return; 2920 return;
2921 2921
2922 status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1); 2922 while (1) {
2923 status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq1);
2923 2924
2924 CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx + MAX_KCQ_IDX); 2925 CNIC_WR16(dev, cp->kcq1.io_addr,
2926 cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
2925 2927
2926 if (BNX2X_CHIP_IS_E2(cp->chip_id)) { 2928 if (!BNX2X_CHIP_IS_E2(cp->chip_id)) {
2927 status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq2); 2929 cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
2930 status_idx, IGU_INT_ENABLE, 1);
2931 break;
2932 }
2933
2934 new_status_idx = cnic_service_bnx2x_kcq(dev, &cp->kcq2);
2935
2936 if (new_status_idx != status_idx)
2937 continue;
2928 2938
2929 CNIC_WR16(dev, cp->kcq2.io_addr, cp->kcq2.sw_prod_idx + 2939 CNIC_WR16(dev, cp->kcq2.io_addr, cp->kcq2.sw_prod_idx +
2930 MAX_KCQ_IDX); 2940 MAX_KCQ_IDX);
2931 2941
2932 cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF, 2942 cnic_ack_igu_sb(dev, cp->bnx2x_igu_sb_id, IGU_SEG_ACCESS_DEF,
2933 status_idx, IGU_INT_ENABLE, 1); 2943 status_idx, IGU_INT_ENABLE, 1);
2934 } else { 2944
2935 cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID, 2945 break;
2936 status_idx, IGU_INT_ENABLE, 1);
2937 } 2946 }
2938} 2947}
2939 2948