From: Shunfeng Yang yangshunfeng2@huawei.com
mainline inclusion from mainline-v5.3 commit 97545b10221 category: bugfix bugzilla: NA CVE: NA
When the user submits more than 32 work request to a srq queue at a time, it needs to find the corresponding number of entries in the bitmap in the idx queue. However, the original lookup function named ffs only processes 32 bits of the array element, When the number of srq wqe issued exceeds 32, the ffs will only process the lower 32 bits of the elements, it will not be able to get the correct wqe index for srq wqe.
Signed-off-by: Shunfeng Yang yangshunfeng2@huawei.com Signed-off-by: Yangyang Li liyangyang20@huawei.com Reviewed-by: chunzhi hu huchunzhi@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 34 ++++++++++++---------- drivers/infiniband/hw/hns/hns_roce_srq.c | 13 ++------- 2 files changed, 21 insertions(+), 26 deletions(-)
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 5f70692688f6a..f712a0b1b5f85 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -3039,15 +3039,10 @@ static void *get_srq_wqe(struct hns_roce_srq *srq, int n)
static void hns_roce_free_srq_wqe(struct hns_roce_srq *srq, int wqe_index) { - u32 bitmap_num; - int bit_num; - /* always called with interrupts disabled. */ spin_lock(&srq->lock);
- bitmap_num = wqe_index / BITS_PER_LONG_LONG; - bit_num = wqe_index % BITS_PER_LONG_LONG; - srq->idx_que.bitmap[bitmap_num] |= (1ULL << bit_num); + bitmap_clear(srq->idx_que.bitmap, wqe_index, 1); srq->idx_que.tail++;
spin_unlock(&srq->lock); @@ -7044,18 +7039,19 @@ int hns_roce_srqwq_overflow(struct hns_roce_srq *srq, int nreq) return cur + nreq >= srq->max - 1; }
-static int find_empty_entry(struct hns_roce_idx_que *idx_que) +static int find_empty_entry(struct hns_roce_idx_que *idx_que, + unsigned long size) { - int bit_num; - int i; + int wqe_idx;
- /* bitmap[i] is set zero if all bits are allocated */ - for (i = 0; idx_que->bitmap[i] == 0; ++i) - ; - bit_num = __ffs64(idx_que->bitmap[i]) + 1; - idx_que->bitmap[i] &= ~(1ULL << (bit_num - 1)); + if (unlikely(bitmap_full(idx_que->bitmap, size))) + return -ENOSPC; + + wqe_idx = find_first_zero_bit(idx_que->bitmap, size); + + bitmap_set(idx_que->bitmap, wqe_idx, 1);
- return i * BITS_PER_LONG_LONG + (bit_num - 1); + return wqe_idx; }
static void fill_idx_queue(struct hns_roce_idx_que *idx_que, @@ -7113,7 +7109,13 @@ static int hns_roce_v2_post_srq_recv(struct ib_srq *ibsrq, break; }
- wqe_idx = find_empty_entry(&srq->idx_que); + wqe_idx = find_empty_entry(&srq->idx_que, srq->max); + if (wqe_idx < 0) { + ret = -ENOMEM; + *bad_wr = wr; + break; + } + fill_idx_queue(&srq->idx_que, ind, wqe_idx); wqe = get_srq_wqe(srq, wqe_idx); dseg = (struct hns_roce_v2_wqe_data_seg *)wqe; diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c index 40ce6abdcd374..52a9b23c13e0b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_srq.c +++ b/drivers/infiniband/hw/hns/hns_roce_srq.c @@ -312,29 +312,22 @@ static int hns_roce_create_idx_que(struct ib_pd *pd, struct hns_roce_srq *srq, struct hns_roce_dev *hr_dev = to_hr_dev(pd->device); struct hns_roce_idx_que *idx_que = &srq->idx_que; struct hns_roce_buf *kbuf; - u32 bitmap_num; - int i;
idx_que->entry_sz = HNS_ROCE_IDX_QUE_ENTRY_SZ; - bitmap_num = HNS_ROCE_ALIGN_UP(srq->max, BITS_PER_LONG_LONG);
- idx_que->bitmap = kcalloc(1, bitmap_num / BITS_PER_BYTE, GFP_KERNEL); + idx_que->bitmap = bitmap_zalloc(srq->max, GFP_KERNEL); if (!idx_que->bitmap) return -ENOMEM;
- bitmap_num = bitmap_num / BITS_PER_LONG_LONG; - idx_que->buf_size = srq->max * idx_que->entry_sz;
kbuf = hns_roce_buf_alloc(hr_dev, idx_que->buf_size, page_shift, 0); if (IS_ERR(kbuf)) { - kfree(idx_que->bitmap); + bitmap_free(idx_que->bitmap); return -ENOMEM; }
idx_que->idx_buf = kbuf; - for (i = 0; i < bitmap_num; i++) - idx_que->bitmap[i] = ~(0UL);
idx_que->head = 0; idx_que->tail = 0; @@ -405,7 +398,7 @@ static int create_kernel_srq(struct ib_pd *pd, struct hns_roce_srq *srq,
err_kernel_create_idx: hns_roce_buf_free(hr_dev, srq->idx_que.idx_buf); - kfree(srq->idx_que.bitmap); + bitmap_free(srq->idx_que.bitmap);
err_kernel_srq_mtt: hns_roce_mtt_cleanup(hr_dev, &srq->mtt);