aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Chan <michael.chan@broadcom.com>2016-05-10 19:18:00 -0400
committerDavid S. Miller <davem@davemloft.net>2016-05-11 23:46:09 -0400
commitfa7e28127a5ad9fd55ac9c7707d8c8b835113a7c (patch)
tree10bed408042dacc3bc4a73f84126477c67f55138
parent376a5b8647d6c56cb8f104d7ad0390b4f4057e70 (diff)
bnxt_en: Add workaround to detect bad opaque in rx completion (part 2)
Add detection and recovery code when the hardware returned opaque value does not match the expected consumer index. Once the issue is detected, we skip the processing of all RX and LRO/GRO packets. These completion entries are discarded without sending the SKB to the stack and without producing new buffers. The function will be reset from a workqueue. Signed-off-by: Michael Chan <michael.chan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c60
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h1
2 files changed, 61 insertions, 0 deletions
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 58999cdd3675..c39a7f5c6a01 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -813,6 +813,46 @@ static inline struct sk_buff *bnxt_copy_skb(struct bnxt_napi *bnapi, u8 *data,
813 return skb; 813 return skb;
814} 814}
815 815
816static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_napi *bnapi,
817 u32 *raw_cons, void *cmp)
818{
819 struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
820 struct rx_cmp *rxcmp = cmp;
821 u32 tmp_raw_cons = *raw_cons;
822 u8 cmp_type, agg_bufs = 0;
823
824 cmp_type = RX_CMP_TYPE(rxcmp);
825
826 if (cmp_type == CMP_TYPE_RX_L2_CMP) {
827 agg_bufs = (le32_to_cpu(rxcmp->rx_cmp_misc_v1) &
828 RX_CMP_AGG_BUFS) >>
829 RX_CMP_AGG_BUFS_SHIFT;
830 } else if (cmp_type == CMP_TYPE_RX_L2_TPA_END_CMP) {
831 struct rx_tpa_end_cmp *tpa_end = cmp;
832
833 agg_bufs = (le32_to_cpu(tpa_end->rx_tpa_end_cmp_misc_v1) &
834 RX_TPA_END_CMP_AGG_BUFS) >>
835 RX_TPA_END_CMP_AGG_BUFS_SHIFT;
836 }
837
838 if (agg_bufs) {
839 if (!bnxt_agg_bufs_valid(bp, cpr, agg_bufs, &tmp_raw_cons))
840 return -EBUSY;
841 }
842 *raw_cons = tmp_raw_cons;
843 return 0;
844}
845
846static void bnxt_sched_reset(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
847{
848 if (!rxr->bnapi->in_reset) {
849 rxr->bnapi->in_reset = true;
850 set_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event);
851 schedule_work(&bp->sp_task);
852 }
853 rxr->rx_next_cons = 0xffff;
854}
855
816static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, 856static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
817 struct rx_tpa_start_cmp *tpa_start, 857 struct rx_tpa_start_cmp *tpa_start,
818 struct rx_tpa_start_cmp_ext *tpa_start1) 858 struct rx_tpa_start_cmp_ext *tpa_start1)
@@ -830,6 +870,11 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
830 prod_rx_buf = &rxr->rx_buf_ring[prod]; 870 prod_rx_buf = &rxr->rx_buf_ring[prod];
831 tpa_info = &rxr->rx_tpa[agg_id]; 871 tpa_info = &rxr->rx_tpa[agg_id];
832 872
873 if (unlikely(cons != rxr->rx_next_cons)) {
874 bnxt_sched_reset(bp, rxr);
875 return;
876 }
877
833 prod_rx_buf->data = tpa_info->data; 878 prod_rx_buf->data = tpa_info->data;
834 879
835 mapping = tpa_info->mapping; 880 mapping = tpa_info->mapping;
@@ -981,6 +1026,14 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
981 dma_addr_t mapping; 1026 dma_addr_t mapping;
982 struct sk_buff *skb; 1027 struct sk_buff *skb;
983 1028
1029 if (unlikely(bnapi->in_reset)) {
1030 int rc = bnxt_discard_rx(bp, bnapi, raw_cons, tpa_end);
1031
1032 if (rc < 0)
1033 return ERR_PTR(-EBUSY);
1034 return NULL;
1035 }
1036
984 tpa_info = &rxr->rx_tpa[agg_id]; 1037 tpa_info = &rxr->rx_tpa[agg_id];
985 data = tpa_info->data; 1038 data = tpa_info->data;
986 prefetch(data); 1039 prefetch(data);
@@ -1147,6 +1200,12 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
1147 cons = rxcmp->rx_cmp_opaque; 1200 cons = rxcmp->rx_cmp_opaque;
1148 rx_buf = &rxr->rx_buf_ring[cons]; 1201 rx_buf = &rxr->rx_buf_ring[cons];
1149 data = rx_buf->data; 1202 data = rx_buf->data;
1203 if (unlikely(cons != rxr->rx_next_cons)) {
1204 int rc1 = bnxt_discard_rx(bp, bnapi, raw_cons, rxcmp);
1205
1206 bnxt_sched_reset(bp, rxr);
1207 return rc1;
1208 }
1150 prefetch(data); 1209 prefetch(data);
1151 1210
1152 agg_bufs = (le32_to_cpu(rxcmp->rx_cmp_misc_v1) & RX_CMP_AGG_BUFS) >> 1211 agg_bufs = (le32_to_cpu(rxcmp->rx_cmp_misc_v1) & RX_CMP_AGG_BUFS) >>
@@ -4465,6 +4524,7 @@ static void bnxt_enable_napi(struct bnxt *bp)
4465 int i; 4524 int i;
4466 4525
4467 for (i = 0; i < bp->cp_nr_rings; i++) { 4526 for (i = 0; i < bp->cp_nr_rings; i++) {
4527 bp->bnapi[i]->in_reset = false;
4468 bnxt_enable_poll(bp->bnapi[i]); 4528 bnxt_enable_poll(bp->bnapi[i]);
4469 napi_enable(&bp->bnapi[i]->napi); 4529 napi_enable(&bp->bnapi[i]->napi);
4470 } 4530 }
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 52f2d74a0d04..de9d53eee3dd 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -637,6 +637,7 @@ struct bnxt_napi {
637#ifdef CONFIG_NET_RX_BUSY_POLL 637#ifdef CONFIG_NET_RX_BUSY_POLL
638 atomic_t poll_state; 638 atomic_t poll_state;
639#endif 639#endif
640 bool in_reset;
640}; 641};
641 642
642#ifdef CONFIG_NET_RX_BUSY_POLL 643#ifdef CONFIG_NET_RX_BUSY_POLL