qed: Fix qed_chain_set_prod() for PBL chains with non power of 2 page count

In PBL chains with non power of 2 page count, the producer is not at the
beginning of the chain when index is 0 after a wrap. Therefore, after the
producer index wrap around, page index should be calculated more carefully.

Signed-off-by: Denis Bolotin <dbolotin@marvell.com>
Signed-off-by: Ariel Elior <aelior@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Denis Bolotin 2019-01-03 12:02:39 +02:00 committed by David S. Miller
parent f8c468e853
commit 2d533a9287
1 changed files with 31 additions and 0 deletions

View File

@ -663,6 +663,37 @@ out:
static inline void qed_chain_set_prod(struct qed_chain *p_chain,
u32 prod_idx, void *p_prod_elem)
{
if (p_chain->mode == QED_CHAIN_MODE_PBL) {
u32 cur_prod, page_mask, page_cnt, page_diff;
cur_prod = is_chain_u16(p_chain) ? p_chain->u.chain16.prod_idx :
p_chain->u.chain32.prod_idx;
/* Assume that number of elements in a page is power of 2 */
page_mask = ~p_chain->elem_per_page_mask;
/* Use "cur_prod - 1" and "prod_idx - 1" since producer index
* reaches the first element of next page before the page index
* is incremented. See qed_chain_produce().
* Index wrap around is not a problem because the difference
* between current and given producer indices is always
* positive and lower than the chain's capacity.
*/
page_diff = (((cur_prod - 1) & page_mask) -
((prod_idx - 1) & page_mask)) /
p_chain->elem_per_page;
page_cnt = qed_chain_get_page_cnt(p_chain);
if (is_chain_u16(p_chain))
p_chain->pbl.c.u16.prod_page_idx =
(p_chain->pbl.c.u16.prod_page_idx -
page_diff + page_cnt) % page_cnt;
else
p_chain->pbl.c.u32.prod_page_idx =
(p_chain->pbl.c.u32.prod_page_idx -
page_diff + page_cnt) % page_cnt;
}
if (is_chain_u16(p_chain))
p_chain->u.chain16.prod_idx = (u16) prod_idx;
else