The free queue metadata bitmap currently searches for a free slot from zero for every page allocation. Under sustained traffic this repeatedly scans occupied low-numbered slots. Remember the position after the most recently allocated slot and wrap the bitmap search at its end. This keeps allocation cost distributed across the metadata table. Fixes: 4d5ae32f5e1e ("net: ethernet: Add a driver for Gemini gigabit ethernet") Assisted-by: LLM Signed-off-by: Linus Walleij --- drivers/net/ethernet/cortina/gemini.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c index 2345d582cb59..87c537ae83e7 100644 --- a/drivers/net/ethernet/cortina/gemini.c +++ b/drivers/net/ethernet/cortina/gemini.c @@ -172,6 +172,7 @@ struct gemini_ethernet { struct xarray freeq_mappings; unsigned int num_freeq_pages; unsigned long *freeq_page_bitmap; + unsigned int freeq_page_cursor; spinlock_t freeq_lock; /* Locks queue from reentrance */ }; @@ -743,12 +744,20 @@ static int geth_freeq_alloc_slot(struct gemini_ethernet *geth) lockdep_assert_held(&geth->freeq_lock); - slot = find_first_zero_bit(geth->freeq_page_bitmap, - geth->num_freeq_pages); - if (slot == geth->num_freeq_pages) - return -ENOSPC; + slot = find_next_zero_bit(geth->freeq_page_bitmap, + geth->num_freeq_pages, + geth->freeq_page_cursor); + if (slot == geth->num_freeq_pages) { + slot = find_first_zero_bit(geth->freeq_page_bitmap, + geth->freeq_page_cursor); + if (slot == geth->freeq_page_cursor) + return -ENOSPC; + } __set_bit(slot, geth->freeq_page_bitmap); + geth->freeq_page_cursor = slot + 1; + if (geth->freeq_page_cursor == geth->num_freeq_pages) + geth->freeq_page_cursor = 0; return slot; } @@ -1110,6 +1119,7 @@ static int geth_setup_freeq(struct gemini_ethernet *geth) if (!geth->freeq_page_bitmap) goto err_freeq_pages; geth->num_freeq_pages = page_slots; + geth->freeq_page_cursor = 0; expected = len - (1 << fpp_order); filled = geth_fill_freeq(geth); -- 2.55.0