diff options
author | David S. Miller <davem@davemloft.net> | 2016-05-11 23:46:09 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-05-11 23:46:09 -0400 |
commit | 1b7cc307a88377b0c948f9cbc36d026b272fe6e3 (patch) | |
tree | 10bed408042dacc3bc4a73f84126477c67f55138 | |
parent | 5f46feab87bb105d6a217d966b327fdc56696802 (diff) | |
parent | fa7e28127a5ad9fd55ac9c7707d8c8b835113a7c (diff) |
Merge branch 'bnxt_en-fixes'
Michael Chan says:
====================
bnxt_en: Add workaround to detect bad opaque in rx completion.
2-part workaround for this hardware bug.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt.c | 63 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 |
2 files changed, 65 insertions, 0 deletions
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 9d4e8e113fe1..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 | ||
816 | static 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 | |||
846 | static 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 | |||
816 | static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, | 856 | static 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; |
@@ -867,6 +912,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, | |||
867 | 912 | ||
868 | rxr->rx_prod = NEXT_RX(prod); | 913 | rxr->rx_prod = NEXT_RX(prod); |
869 | cons = NEXT_RX(cons); | 914 | cons = NEXT_RX(cons); |
915 | rxr->rx_next_cons = NEXT_RX(cons); | ||
870 | cons_rx_buf = &rxr->rx_buf_ring[cons]; | 916 | cons_rx_buf = &rxr->rx_buf_ring[cons]; |
871 | 917 | ||
872 | bnxt_reuse_rx_data(rxr, cons, cons_rx_buf->data); | 918 | bnxt_reuse_rx_data(rxr, cons, cons_rx_buf->data); |
@@ -980,6 +1026,14 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, | |||
980 | dma_addr_t mapping; | 1026 | dma_addr_t mapping; |
981 | struct sk_buff *skb; | 1027 | struct sk_buff *skb; |
982 | 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 | |||
983 | tpa_info = &rxr->rx_tpa[agg_id]; | 1037 | tpa_info = &rxr->rx_tpa[agg_id]; |
984 | data = tpa_info->data; | 1038 | data = tpa_info->data; |
985 | prefetch(data); | 1039 | prefetch(data); |
@@ -1146,6 +1200,12 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, | |||
1146 | cons = rxcmp->rx_cmp_opaque; | 1200 | cons = rxcmp->rx_cmp_opaque; |
1147 | rx_buf = &rxr->rx_buf_ring[cons]; | 1201 | rx_buf = &rxr->rx_buf_ring[cons]; |
1148 | 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 | } | ||
1149 | prefetch(data); | 1209 | prefetch(data); |
1150 | 1210 | ||
1151 | 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) >> |
@@ -1245,6 +1305,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, | |||
1245 | 1305 | ||
1246 | next_rx: | 1306 | next_rx: |
1247 | rxr->rx_prod = NEXT_RX(prod); | 1307 | rxr->rx_prod = NEXT_RX(prod); |
1308 | rxr->rx_next_cons = NEXT_RX(cons); | ||
1248 | 1309 | ||
1249 | next_rx_no_prod: | 1310 | next_rx_no_prod: |
1250 | *raw_cons = tmp_raw_cons; | 1311 | *raw_cons = tmp_raw_cons; |
@@ -2486,6 +2547,7 @@ static void bnxt_clear_ring_indices(struct bnxt *bp) | |||
2486 | rxr->rx_prod = 0; | 2547 | rxr->rx_prod = 0; |
2487 | rxr->rx_agg_prod = 0; | 2548 | rxr->rx_agg_prod = 0; |
2488 | rxr->rx_sw_agg_prod = 0; | 2549 | rxr->rx_sw_agg_prod = 0; |
2550 | rxr->rx_next_cons = 0; | ||
2489 | } | 2551 | } |
2490 | } | 2552 | } |
2491 | } | 2553 | } |
@@ -4462,6 +4524,7 @@ static void bnxt_enable_napi(struct bnxt *bp) | |||
4462 | int i; | 4524 | int i; |
4463 | 4525 | ||
4464 | 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; | ||
4465 | bnxt_enable_poll(bp->bnapi[i]); | 4528 | bnxt_enable_poll(bp->bnapi[i]); |
4466 | napi_enable(&bp->bnapi[i]->napi); | 4529 | napi_enable(&bp->bnapi[i]->napi); |
4467 | } | 4530 | } |
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 8b823ff558ff..de9d53eee3dd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h | |||
@@ -584,6 +584,7 @@ struct bnxt_rx_ring_info { | |||
584 | u16 rx_prod; | 584 | u16 rx_prod; |
585 | u16 rx_agg_prod; | 585 | u16 rx_agg_prod; |
586 | u16 rx_sw_agg_prod; | 586 | u16 rx_sw_agg_prod; |
587 | u16 rx_next_cons; | ||
587 | void __iomem *rx_doorbell; | 588 | void __iomem *rx_doorbell; |
588 | void __iomem *rx_agg_doorbell; | 589 | void __iomem *rx_agg_doorbell; |
589 | 590 | ||
@@ -636,6 +637,7 @@ struct bnxt_napi { | |||
636 | #ifdef CONFIG_NET_RX_BUSY_POLL | 637 | #ifdef CONFIG_NET_RX_BUSY_POLL |
637 | atomic_t poll_state; | 638 | atomic_t poll_state; |
638 | #endif | 639 | #endif |
640 | bool in_reset; | ||
639 | }; | 641 | }; |
640 | 642 | ||
641 | #ifdef CONFIG_NET_RX_BUSY_POLL | 643 | #ifdef CONFIG_NET_RX_BUSY_POLL |