Skip to content

Commit

Permalink
RDMA/hns: Optimize hns buffer allocation flow
Browse files Browse the repository at this point in the history
When the value of nbufs is 1, the buffer is in direct mode, which may cause
confusion. So optimizes current codes to make it easier to maintain and
understand.

Link: https://lore.kernel.org/r/1586779091-51410-3-git-send-email-liweihang@huawei.com
Signed-off-by: Xi Wang <wangxi11@huawei.com>
Signed-off-by: Lang Cheng <chenglang@huawei.com>
Signed-off-by: Weihang Li <liweihang@huawei.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
  • Loading branch information
Xi Wang authored and Jason Gunthorpe committed Apr 22, 2020
1 parent 3c87316 commit cc23267
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 128 deletions.
103 changes: 47 additions & 56 deletions drivers/infiniband/hw/hns/hns_roce_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,84 +157,78 @@ void hns_roce_bitmap_cleanup(struct hns_roce_bitmap *bitmap)
kfree(bitmap->table);
}

void hns_roce_buf_free(struct hns_roce_dev *hr_dev, u32 size,
struct hns_roce_buf *buf)
void hns_roce_buf_free(struct hns_roce_dev *hr_dev, struct hns_roce_buf *buf)
{
int i;
struct device *dev = hr_dev->dev;
u32 size = buf->size;
int i;

if (size == 0)
return;

buf->size = 0;

if (buf->nbufs == 1) {
if (hns_roce_buf_is_direct(buf)) {
dma_free_coherent(dev, size, buf->direct.buf, buf->direct.map);
} else {
for (i = 0; i < buf->nbufs; ++i)
for (i = 0; i < buf->npages; ++i)
if (buf->page_list[i].buf)
dma_free_coherent(dev, 1 << buf->page_shift,
buf->page_list[i].buf,
buf->page_list[i].map);
kfree(buf->page_list);
buf->page_list = NULL;
}
}

int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct,
struct hns_roce_buf *buf, u32 page_shift)
{
int i = 0;
dma_addr_t t;
struct hns_roce_buf_list *buf_list;
struct device *dev = hr_dev->dev;
u32 page_size = 1 << page_shift;
u32 order;
u32 page_size;
int i;

/* The minimum shift of the page accessed by hw is PAGE_ADDR_SHIFT */
buf->page_shift = max_t(int, PAGE_ADDR_SHIFT, page_shift);

/* SQ/RQ buf lease than one page, SQ + RQ = 8K */
page_size = 1 << buf->page_shift;
buf->npages = DIV_ROUND_UP(size, page_size);

/* required size is not bigger than one trunk size */
if (size <= max_direct) {
buf->nbufs = 1;
/* Npages calculated by page_size */
order = get_order(size);
if (order <= page_shift - PAGE_SHIFT)
order = 0;
else
order -= page_shift - PAGE_SHIFT;
buf->npages = 1 << order;
buf->page_shift = page_shift;
/* MTT PA must be recorded in 4k alignment, t is 4k aligned */
buf->direct.buf = dma_alloc_coherent(dev, size, &t,
buf->page_list = NULL;
buf->direct.buf = dma_alloc_coherent(dev, size,
&buf->direct.map,
GFP_KERNEL);
if (!buf->direct.buf)
return -ENOMEM;

buf->direct.map = t;

while (t & ((1 << buf->page_shift) - 1)) {
--buf->page_shift;
buf->npages *= 2;
}
} else {
buf->nbufs = (size + page_size - 1) / page_size;
buf->npages = buf->nbufs;
buf->page_shift = page_shift;
buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list),
GFP_KERNEL);

if (!buf->page_list)
buf_list = kcalloc(buf->npages, sizeof(*buf_list), GFP_KERNEL);
if (!buf_list)
return -ENOMEM;

for (i = 0; i < buf->nbufs; ++i) {
buf->page_list[i].buf = dma_alloc_coherent(dev,
page_size,
&t,
GFP_KERNEL);

if (!buf->page_list[i].buf)
goto err_free;
for (i = 0; i < buf->npages; i++) {
buf_list[i].buf = dma_alloc_coherent(dev, page_size,
&buf_list[i].map,
GFP_KERNEL);
if (!buf_list[i].buf)
break;
}

buf->page_list[i].map = t;
if (i != buf->npages && i > 0) {
while (i-- > 0)
dma_free_coherent(dev, page_size,
buf_list[i].buf,
buf_list[i].map);
kfree(buf_list);
return -ENOMEM;
}
buf->page_list = buf_list;
}
buf->size = size;

return 0;

err_free:
hns_roce_buf_free(hr_dev, size, buf);
return -ENOMEM;
}

int hns_roce_get_kmem_bufs(struct hns_roce_dev *hr_dev, dma_addr_t *bufs,
Expand All @@ -246,18 +240,14 @@ int hns_roce_get_kmem_bufs(struct hns_roce_dev *hr_dev, dma_addr_t *bufs,
end = start + buf_cnt;
if (end > buf->npages) {
dev_err(hr_dev->dev,
"invalid kmem region,offset %d,buf_cnt %d,total %d!\n",
"Failed to check kmem bufs, end %d + %d total %d!\n",
start, buf_cnt, buf->npages);
return -EINVAL;
}

total = 0;
for (i = start; i < end; i++)
if (buf->nbufs == 1)
bufs[total++] = buf->direct.map +
((dma_addr_t)i << buf->page_shift);
else
bufs[total++] = buf->page_list[i].map;
bufs[total++] = hns_roce_buf_page(buf, i);

return total;
}
Expand All @@ -271,8 +261,9 @@ int hns_roce_get_umem_bufs(struct hns_roce_dev *hr_dev, dma_addr_t *bufs,
int idx = 0;
u64 addr;

if (page_shift < PAGE_SHIFT) {
dev_err(hr_dev->dev, "invalid page shift %d!\n", page_shift);
if (page_shift < PAGE_ADDR_SHIFT) {
dev_err(hr_dev->dev, "Failed to check umem page shift %d!\n",
page_shift);
return -EINVAL;
}

Expand Down
18 changes: 9 additions & 9 deletions drivers/infiniband/hw/hns/hns_roce_cq.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,12 @@ static int get_cq_umem(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq,
struct hns_roce_ib_create_cq ucmd,
struct ib_udata *udata)
{
struct hns_roce_buf *buf = &hr_cq->buf;
struct hns_roce_mtt *mtt = &hr_cq->mtt;
struct ib_umem **umem = &hr_cq->umem;
u32 npages;
int ret;

*umem = ib_umem_get(&hr_dev->ib_dev, ucmd.buf_addr, buf->size,
*umem = ib_umem_get(&hr_dev->ib_dev, ucmd.buf_addr, hr_cq->buf_size,
IB_ACCESS_LOCAL_WRITE);
if (IS_ERR(*umem))
return PTR_ERR(*umem);
Expand All @@ -175,7 +174,7 @@ static int get_cq_umem(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq,

npages = DIV_ROUND_UP(ib_umem_page_count(*umem),
1 << hr_dev->caps.cqe_buf_pg_sz);
ret = hns_roce_mtt_init(hr_dev, npages, buf->page_shift, mtt);
ret = hns_roce_mtt_init(hr_dev, npages, hr_cq->page_shift, mtt);
if (ret)
goto err_buf;

Expand All @@ -199,8 +198,9 @@ static int alloc_cq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
struct hns_roce_mtt *mtt = &hr_cq->mtt;
int ret;

ret = hns_roce_buf_alloc(hr_dev, buf->size, (1 << buf->page_shift) * 2,
buf, buf->page_shift);
ret = hns_roce_buf_alloc(hr_dev, hr_cq->buf_size,
(1 << hr_cq->page_shift) * 2,
buf, hr_cq->page_shift);
if (ret)
goto out;

Expand All @@ -223,15 +223,15 @@ static int alloc_cq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
hns_roce_mtt_cleanup(hr_dev, mtt);

err_buf:
hns_roce_buf_free(hr_dev, buf->size, buf);
hns_roce_buf_free(hr_dev, buf);

out:
return ret;
}

static void free_cq_buf(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq)
{
hns_roce_buf_free(hr_dev, hr_cq->buf.size, &hr_cq->buf);
hns_roce_buf_free(hr_dev, &hr_cq->buf);
}

static int create_user_cq(struct hns_roce_dev *hr_dev,
Expand Down Expand Up @@ -367,8 +367,8 @@ int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,
hr_cq->ib_cq.cqe = cq_entries - 1; /* used as cqe index */
hr_cq->cq_depth = cq_entries;
hr_cq->vector = vector;
hr_cq->buf.size = hr_cq->cq_depth * hr_dev->caps.cq_entry_sz;
hr_cq->buf.page_shift = PAGE_SHIFT + hr_dev->caps.cqe_buf_pg_sz;
hr_cq->buf_size = hr_cq->cq_depth * hr_dev->caps.cq_entry_sz;
hr_cq->page_shift = PAGE_SHIFT + hr_dev->caps.cqe_buf_pg_sz;
spin_lock_init(&hr_cq->lock);
INIT_LIST_HEAD(&hr_cq->sq_list);
INIT_LIST_HEAD(&hr_cq->rq_list);
Expand Down
32 changes: 24 additions & 8 deletions drivers/infiniband/hw/hns/hns_roce_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,6 @@ struct hns_roce_buf_list {
struct hns_roce_buf {
struct hns_roce_buf_list direct;
struct hns_roce_buf_list *page_list;
int nbufs;
u32 npages;
u32 size;
int page_shift;
Expand Down Expand Up @@ -510,6 +509,8 @@ struct hns_roce_cq {
u8 db_en;
spinlock_t lock;
struct ib_umem *umem;
u32 buf_size;
int page_shift;
u32 cq_depth;
u32 cons_index;
u32 *set_ci_db;
Expand Down Expand Up @@ -549,6 +550,8 @@ struct hns_roce_srq {
struct hns_roce_buf buf;
u64 *wrid;
struct ib_umem *umem;
u32 buf_size;
int page_shift;
struct hns_roce_mtt mtt;
struct hns_roce_idx_que idx_que;
spinlock_t lock;
Expand Down Expand Up @@ -1124,15 +1127,29 @@ static inline struct hns_roce_qp
return xa_load(&hr_dev->qp_table_xa, qpn & (hr_dev->caps.num_qps - 1));
}

static inline bool hns_roce_buf_is_direct(struct hns_roce_buf *buf)
{
if (buf->page_list)
return false;

return true;
}

static inline void *hns_roce_buf_offset(struct hns_roce_buf *buf, int offset)
{
u32 page_size = 1 << buf->page_shift;
if (hns_roce_buf_is_direct(buf))
return (char *)(buf->direct.buf) + (offset & (buf->size - 1));

if (buf->nbufs == 1)
return (char *)(buf->direct.buf) + offset;
return (char *)(buf->page_list[offset >> buf->page_shift].buf) +
(offset & ((1 << buf->page_shift) - 1));
}

static inline dma_addr_t hns_roce_buf_page(struct hns_roce_buf *buf, int idx)
{
if (hns_roce_buf_is_direct(buf))
return buf->direct.map + ((dma_addr_t)idx << buf->page_shift);
else
return (char *)(buf->page_list[offset >> buf->page_shift].buf) +
(offset & (page_size - 1));
return buf->page_list[idx].map;
}

static inline u64 to_hr_hw_page_addr(u64 addr)
Expand Down Expand Up @@ -1240,8 +1257,7 @@ struct ib_mw *hns_roce_alloc_mw(struct ib_pd *pd, enum ib_mw_type,
struct ib_udata *udata);
int hns_roce_dealloc_mw(struct ib_mw *ibmw);

void hns_roce_buf_free(struct hns_roce_dev *hr_dev, u32 size,
struct hns_roce_buf *buf);
void hns_roce_buf_free(struct hns_roce_dev *hr_dev, struct hns_roce_buf *buf);
int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct,
struct hns_roce_buf *buf, u32 page_shift);

Expand Down
2 changes: 1 addition & 1 deletion drivers/infiniband/hw/hns/hns_roce_hw_v1.c
Original file line number Diff line number Diff line change
Expand Up @@ -3666,7 +3666,7 @@ static void hns_roce_v1_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
ib_umem_release(hr_cq->umem);
if (!udata) {
/* Free the buff of stored cq */
hns_roce_buf_free(hr_dev, hr_cq->buf.size, &hr_cq->buf);
hns_roce_buf_free(hr_dev, &hr_cq->buf);
}
}

Expand Down
Loading

0 comments on commit cc23267

Please sign in to comment.