bnxt_en: Fix potential data corruption with HW GRO/LRO
Fix the max number of bits passed to find_first_zero_bit() in
bnxt_alloc_agg_idx(). We were incorrectly passing the number of
long words. find_first_zero_bit() may fail to find a zero bit and
cause a wrong ID to be used. If the wrong ID is already in use, this
can cause data corruption. Sometimes an error like this can also be
seen:
bnxt_en 0000:83:00.0 enp131s0np0: TPA end agg_buf 2 != expected agg_bufs 1
Fix it by passing the correct number of bits MAX_TPA_P5. Use
DECLARE_BITMAP() to more cleanly define the bitmap. Add a sanity
check to warn if a bit cannot be found and reset the ring [MChan].
Fixes: ec4d8e7cf0 ("bnxt_en: Add TPA ID mapping logic for 57500 chips.")
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Signed-off-by: Srijit Bose <srijit.bose@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Link: https://patch.msgid.link/20251231083625.3911652-1-michael.chan@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
92e6e0a87f
commit
ffeafa65b2
@@ -1482,9 +1482,11 @@ static u16 bnxt_alloc_agg_idx(struct bnxt_rx_ring_info *rxr, u16 agg_id)
|
||||
struct bnxt_tpa_idx_map *map = rxr->rx_tpa_idx_map;
|
||||
u16 idx = agg_id & MAX_TPA_P5_MASK;
|
||||
|
||||
if (test_bit(idx, map->agg_idx_bmap))
|
||||
idx = find_first_zero_bit(map->agg_idx_bmap,
|
||||
BNXT_AGG_IDX_BMAP_SIZE);
|
||||
if (test_bit(idx, map->agg_idx_bmap)) {
|
||||
idx = find_first_zero_bit(map->agg_idx_bmap, MAX_TPA_P5);
|
||||
if (idx >= MAX_TPA_P5)
|
||||
return INVALID_HW_RING_ID;
|
||||
}
|
||||
__set_bit(idx, map->agg_idx_bmap);
|
||||
map->agg_id_tbl[agg_id] = idx;
|
||||
return idx;
|
||||
@@ -1548,6 +1550,13 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
|
||||
if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
|
||||
agg_id = TPA_START_AGG_ID_P5(tpa_start);
|
||||
agg_id = bnxt_alloc_agg_idx(rxr, agg_id);
|
||||
if (unlikely(agg_id == INVALID_HW_RING_ID)) {
|
||||
netdev_warn(bp->dev, "Unable to allocate agg ID for ring %d, agg 0x%x\n",
|
||||
rxr->bnapi->index,
|
||||
TPA_START_AGG_ID_P5(tpa_start));
|
||||
bnxt_sched_reset_rxr(bp, rxr);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
agg_id = TPA_START_AGG_ID(tpa_start);
|
||||
}
|
||||
|
||||
@@ -1080,11 +1080,9 @@ struct bnxt_tpa_info {
|
||||
struct rx_agg_cmp *agg_arr;
|
||||
};
|
||||
|
||||
#define BNXT_AGG_IDX_BMAP_SIZE (MAX_TPA_P5 / BITS_PER_LONG)
|
||||
|
||||
struct bnxt_tpa_idx_map {
|
||||
u16 agg_id_tbl[1024];
|
||||
unsigned long agg_idx_bmap[BNXT_AGG_IDX_BMAP_SIZE];
|
||||
DECLARE_BITMAP(agg_idx_bmap, MAX_TPA_P5);
|
||||
};
|
||||
|
||||
struct bnxt_rx_ring_info {
|
||||
|
||||
Reference in New Issue
Block a user