hns_roce_srq.c 12.0 KB
Newer Older
L
Lijun Ou 已提交
1 2 3 4 5 6 7 8 9 10 11
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
 * Copyright (c) 2018 Hisilicon Limited.
 */

#include <rdma/ib_umem.h>
#include <rdma/hns-abi.h>
#include "hns_roce_device.h"
#include "hns_roce_cmd.h"
#include "hns_roce_hem.h"

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type)
{
	struct hns_roce_srq_table *srq_table = &hr_dev->srq_table;
	struct hns_roce_srq *srq;

	xa_lock(&srq_table->xa);
	srq = xa_load(&srq_table->xa, srqn & (hr_dev->caps.num_srqs - 1));
	if (srq)
		atomic_inc(&srq->refcount);
	xa_unlock(&srq_table->xa);

	if (!srq) {
		dev_warn(hr_dev->dev, "Async event for bogus SRQ %08x\n", srqn);
		return;
	}

	srq->event(srq, event_type);

	if (atomic_dec_and_test(&srq->refcount))
		complete(&srq->free);
}

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
static void hns_roce_ib_srq_event(struct hns_roce_srq *srq,
				  enum hns_roce_event event_type)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(srq->ibsrq.device);
	struct ib_srq *ibsrq = &srq->ibsrq;
	struct ib_event event;

	if (ibsrq->event_handler) {
		event.device      = ibsrq->device;
		event.element.srq = ibsrq;
		switch (event_type) {
		case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH:
			event.event = IB_EVENT_SRQ_LIMIT_REACHED;
			break;
		case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR:
			event.event = IB_EVENT_SRQ_ERR;
			break;
		default:
			dev_err(hr_dev->dev,
			   "hns_roce:Unexpected event type 0x%x on SRQ %06lx\n",
			   event_type, srq->srqn);
			return;
		}

		ibsrq->event_handler(&event, ibsrq->srq_context);
	}
}

62 63 64
static int hns_roce_hw_create_srq(struct hns_roce_dev *dev,
				  struct hns_roce_cmd_mailbox *mailbox,
				  unsigned long srq_num)
65 66
{
	return hns_roce_cmd_mbox(dev, mailbox->dma, 0, srq_num, 0,
67
				 HNS_ROCE_CMD_CREATE_SRQ,
68 69 70
				 HNS_ROCE_CMD_TIMEOUT_MSECS);
}

71 72 73
static int hns_roce_hw_destroy_srq(struct hns_roce_dev *dev,
				   struct hns_roce_cmd_mailbox *mailbox,
				   unsigned long srq_num)
74 75
{
	return hns_roce_cmd_mbox(dev, 0, mailbox ? mailbox->dma : 0, srq_num,
76
				 mailbox ? 0 : 1, HNS_ROCE_CMD_DESTROY_SRQ,
77 78 79
				 HNS_ROCE_CMD_TIMEOUT_MSECS);
}

Y
YueHaibing 已提交
80 81 82
static int hns_roce_srq_alloc(struct hns_roce_dev *hr_dev, u32 pdn, u32 cqn,
			      u16 xrcd, struct hns_roce_mtt *hr_mtt,
			      u64 db_rec_addr, struct hns_roce_srq *srq)
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
{
	struct hns_roce_srq_table *srq_table = &hr_dev->srq_table;
	struct hns_roce_cmd_mailbox *mailbox;
	dma_addr_t dma_handle_wqe;
	dma_addr_t dma_handle_idx;
	u64 *mtts_wqe;
	u64 *mtts_idx;
	int ret;

	/* Get the physical address of srq buf */
	mtts_wqe = hns_roce_table_find(hr_dev,
				       &hr_dev->mr_table.mtt_srqwqe_table,
				       srq->mtt.first_seg,
				       &dma_handle_wqe);
	if (!mtts_wqe) {
98
		dev_err(hr_dev->dev, "Failed to find mtt for srq buf.\n");
99 100 101 102 103 104 105 106 107
		return -EINVAL;
	}

	/* Get physical address of idx que buf */
	mtts_idx = hns_roce_table_find(hr_dev, &hr_dev->mr_table.mtt_idx_table,
				       srq->idx_que.mtt.first_seg,
				       &dma_handle_idx);
	if (!mtts_idx) {
		dev_err(hr_dev->dev,
108
			"Failed to find mtt for srq idx queue buf.\n");
109 110 111 112
		return -EINVAL;
	}

	ret = hns_roce_bitmap_alloc(&srq_table->bitmap, &srq->srqn);
113
	if (ret) {
114 115
		dev_err(hr_dev->dev,
			"Failed to alloc a bit from srq bitmap.\n");
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
		return -ENOMEM;
	}

	ret = hns_roce_table_get(hr_dev, &srq_table->table, srq->srqn);
	if (ret)
		goto err_out;

	ret = xa_err(xa_store(&srq_table->xa, srq->srqn, srq, GFP_KERNEL));
	if (ret)
		goto err_put;

	mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
	if (IS_ERR(mailbox)) {
		ret = PTR_ERR(mailbox);
		goto err_xa;
	}

	hr_dev->hw->write_srqc(hr_dev, srq, pdn, xrcd, cqn, mailbox->buf,
			       mtts_wqe, mtts_idx, dma_handle_wqe,
			       dma_handle_idx);

137
	ret = hns_roce_hw_create_srq(hr_dev, mailbox, srq->srqn);
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
	hns_roce_free_cmd_mailbox(hr_dev, mailbox);
	if (ret)
		goto err_xa;

	atomic_set(&srq->refcount, 1);
	init_completion(&srq->free);
	return ret;

err_xa:
	xa_erase(&srq_table->xa, srq->srqn);

err_put:
	hns_roce_table_put(hr_dev, &srq_table->table, srq->srqn);

err_out:
	hns_roce_bitmap_free(&srq_table->bitmap, srq->srqn, BITMAP_NO_RR);
	return ret;
}

Y
YueHaibing 已提交
157 158
static void hns_roce_srq_free(struct hns_roce_dev *hr_dev,
			      struct hns_roce_srq *srq)
159 160 161 162
{
	struct hns_roce_srq_table *srq_table = &hr_dev->srq_table;
	int ret;

163
	ret = hns_roce_hw_destroy_srq(hr_dev, NULL, srq->srqn);
164
	if (ret)
165
		dev_err(hr_dev->dev, "DESTROY_SRQ failed (%d) for SRQN %06lx\n",
166 167 168 169 170 171 172 173 174 175 176 177
			ret, srq->srqn);

	xa_erase(&srq_table->xa, srq->srqn);

	if (atomic_dec_and_test(&srq->refcount))
		complete(&srq->free);
	wait_for_completion(&srq->free);

	hns_roce_table_put(hr_dev, &srq_table->table, srq->srqn);
	hns_roce_bitmap_free(&srq_table->bitmap, srq->srqn, BITMAP_NO_RR);
}

178 179 180 181 182
static int create_user_srq(struct hns_roce_srq *srq, struct ib_udata *udata,
			   int srq_buf_size)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(srq->ibsrq.device);
	struct hns_roce_ib_create_srq  ucmd;
183 184
	int page_shift;
	int page_count;
185 186 187 188 189
	int ret;

	if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd)))
		return -EFAULT;

190 191
	srq->umem =
		ib_umem_get(srq->ibsrq.device, ucmd.buf_addr, srq_buf_size, 0);
192 193 194
	if (IS_ERR(srq->umem))
		return PTR_ERR(srq->umem);

195 196
	page_count = (ib_umem_page_count(srq->umem) +
		      (1 << hr_dev->caps.srqwqe_buf_pg_sz) - 1) /
197
		      (1 << hr_dev->caps.srqwqe_buf_pg_sz);
198 199
	page_shift = PAGE_SHIFT + hr_dev->caps.srqwqe_buf_pg_sz;
	ret = hns_roce_mtt_init(hr_dev, page_count, page_shift,
200
				&srq->mtt);
201 202 203 204 205 206 207 208
	if (ret)
		goto err_user_buf;

	ret = hns_roce_ib_umem_write_mtt(hr_dev, &srq->mtt, srq->umem);
	if (ret)
		goto err_user_srq_mtt;

	/* config index queue BA */
209
	srq->idx_que.umem = ib_umem_get(srq->ibsrq.device, ucmd.que_addr,
210
					srq->idx_que.buf_size, 0);
211 212 213 214 215 216
	if (IS_ERR(srq->idx_que.umem)) {
		dev_err(hr_dev->dev, "ib_umem_get error for index queue\n");
		ret = PTR_ERR(srq->idx_que.umem);
		goto err_user_srq_mtt;
	}

217 218 219 220
	page_count = DIV_ROUND_UP(ib_umem_page_count(srq->idx_que.umem),
				  1 << hr_dev->caps.idx_buf_pg_sz);
	page_shift = PAGE_SHIFT + hr_dev->caps.idx_buf_pg_sz;
	ret = hns_roce_mtt_init(hr_dev, page_count, page_shift,
221
				&srq->idx_que.mtt);
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
	if (ret) {
		dev_err(hr_dev->dev, "hns_roce_mtt_init error for idx que\n");
		goto err_user_idx_mtt;
	}

	ret = hns_roce_ib_umem_write_mtt(hr_dev, &srq->idx_que.mtt,
					 srq->idx_que.umem);
	if (ret) {
		dev_err(hr_dev->dev,
			"hns_roce_ib_umem_write_mtt error for idx que\n");
		goto err_user_idx_buf;
	}

	return 0;

err_user_idx_buf:
	hns_roce_mtt_cleanup(hr_dev, &srq->idx_que.mtt);

err_user_idx_mtt:
	ib_umem_release(srq->idx_que.umem);

err_user_srq_mtt:
	hns_roce_mtt_cleanup(hr_dev, &srq->mtt);

err_user_buf:
	ib_umem_release(srq->umem);

	return ret;
}

252 253 254 255 256 257
static int hns_roce_create_idx_que(struct ib_pd *pd, struct hns_roce_srq *srq,
				   u32 page_shift)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
	struct hns_roce_idx_que *idx_que = &srq->idx_que;

258
	idx_que->bitmap = bitmap_zalloc(srq->wqe_cnt, GFP_KERNEL);
259 260 261 262 263 264 265
	if (!idx_que->bitmap)
		return -ENOMEM;

	idx_que->buf_size = srq->idx_que.buf_size;

	if (hns_roce_buf_alloc(hr_dev, idx_que->buf_size, (1 << page_shift) * 2,
			       &idx_que->idx_buf, page_shift)) {
266
		bitmap_free(idx_que->bitmap);
267 268 269 270 271 272
		return -ENOMEM;
	}

	return 0;
}

273 274 275 276 277 278 279 280 281 282 283
static int create_kernel_srq(struct hns_roce_srq *srq, int srq_buf_size)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(srq->ibsrq.device);
	u32 page_shift = PAGE_SHIFT + hr_dev->caps.srqwqe_buf_pg_sz;
	int ret;

	if (hns_roce_buf_alloc(hr_dev, srq_buf_size, (1 << page_shift) * 2,
			       &srq->buf, page_shift))
		return -ENOMEM;

	srq->head = 0;
284
	srq->tail = srq->wqe_cnt - 1;
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314

	ret = hns_roce_mtt_init(hr_dev, srq->buf.npages, srq->buf.page_shift,
				&srq->mtt);
	if (ret)
		goto err_kernel_buf;

	ret = hns_roce_buf_write_mtt(hr_dev, &srq->mtt, &srq->buf);
	if (ret)
		goto err_kernel_srq_mtt;

	page_shift = PAGE_SHIFT + hr_dev->caps.idx_buf_pg_sz;
	ret = hns_roce_create_idx_que(srq->ibsrq.pd, srq, page_shift);
	if (ret) {
		dev_err(hr_dev->dev, "Create idx queue fail(%d)!\n", ret);
		goto err_kernel_srq_mtt;
	}

	/* Init mtt table for idx_que */
	ret = hns_roce_mtt_init(hr_dev, srq->idx_que.idx_buf.npages,
				srq->idx_que.idx_buf.page_shift,
				&srq->idx_que.mtt);
	if (ret)
		goto err_kernel_create_idx;

	/* Write buffer address into the mtt table */
	ret = hns_roce_buf_write_mtt(hr_dev, &srq->idx_que.mtt,
				     &srq->idx_que.idx_buf);
	if (ret)
		goto err_kernel_idx_buf;

315
	srq->wrid = kvmalloc_array(srq->wqe_cnt, sizeof(u64), GFP_KERNEL);
316 317 318 319 320 321 322 323 324 325 326
	if (!srq->wrid) {
		ret = -ENOMEM;
		goto err_kernel_idx_buf;
	}

	return 0;

err_kernel_idx_buf:
	hns_roce_mtt_cleanup(hr_dev, &srq->idx_que.mtt);

err_kernel_create_idx:
327
	hns_roce_buf_free(hr_dev, &srq->idx_que.idx_buf);
328 329 330 331 332 333
	kfree(srq->idx_que.bitmap);

err_kernel_srq_mtt:
	hns_roce_mtt_cleanup(hr_dev, &srq->mtt);

err_kernel_buf:
334
	hns_roce_buf_free(hr_dev, &srq->buf);
335 336 337 338 339 340 341 342 343 344 345 346 347 348

	return ret;
}

static void destroy_user_srq(struct hns_roce_dev *hr_dev,
			     struct hns_roce_srq *srq)
{
	hns_roce_mtt_cleanup(hr_dev, &srq->idx_que.mtt);
	ib_umem_release(srq->idx_que.umem);
	hns_roce_mtt_cleanup(hr_dev, &srq->mtt);
	ib_umem_release(srq->umem);
}

static void destroy_kernel_srq(struct hns_roce_dev *hr_dev,
349
			       struct hns_roce_srq *srq)
350 351 352
{
	kvfree(srq->wrid);
	hns_roce_mtt_cleanup(hr_dev, &srq->idx_que.mtt);
353
	hns_roce_buf_free(hr_dev, &srq->idx_que.idx_buf);
354 355
	kfree(srq->idx_que.bitmap);
	hns_roce_mtt_cleanup(hr_dev, &srq->mtt);
356
	hns_roce_buf_free(hr_dev, &srq->buf);
357 358
}

359
int hns_roce_create_srq(struct ib_srq *ib_srq,
360
			struct ib_srq_init_attr *init_attr,
361
			struct ib_udata *udata)
362
{
363
	struct hns_roce_dev *hr_dev = to_hr_dev(ib_srq->device);
364
	struct hns_roce_ib_create_srq_resp resp = {};
365
	struct hns_roce_srq *srq = to_hr_srq(ib_srq);
366 367 368 369 370 371
	int srq_desc_size;
	int srq_buf_size;
	int ret = 0;
	u32 cqn;

	/* Check the actual SRQ wqe and SRQ sge num */
372 373
	if (init_attr->attr.max_wr >= hr_dev->caps.max_srq_wrs ||
	    init_attr->attr.max_sge > hr_dev->caps.max_srq_sges)
374
		return -EINVAL;
375 376 377 378

	mutex_init(&srq->mutex);
	spin_lock_init(&srq->lock);

379 380
	srq->wqe_cnt = roundup_pow_of_two(init_attr->attr.max_wr + 1);
	srq->max_gs = init_attr->attr.max_sge;
381

L
Lang Cheng 已提交
382 383
	srq_desc_size = roundup_pow_of_two(max(HNS_ROCE_SGE_SIZE,
					HNS_ROCE_SGE_SIZE * srq->max_gs));
384 385 386

	srq->wqe_shift = ilog2(srq_desc_size);

387
	srq_buf_size = srq->wqe_cnt * srq_desc_size;
388 389

	srq->idx_que.entry_sz = HNS_ROCE_IDX_QUE_ENTRY_SZ;
390
	srq->idx_que.buf_size = srq->wqe_cnt * srq->idx_que.entry_sz;
391 392 393 394
	srq->mtt.mtt_type = MTT_TYPE_SRQWQE;
	srq->idx_que.mtt.mtt_type = MTT_TYPE_IDX;

	if (udata) {
395
		ret = create_user_srq(srq, udata, srq_buf_size);
396
		if (ret) {
397 398
			dev_err(hr_dev->dev, "Create user srq failed\n");
			goto err_srq;
399 400
		}
	} else {
401
		ret = create_kernel_srq(srq, srq_buf_size);
402
		if (ret) {
403 404
			dev_err(hr_dev->dev, "Create kernel srq failed\n");
			goto err_srq;
405 406 407
		}
	}

408 409
	cqn = ib_srq_has_cq(init_attr->srq_type) ?
	      to_hr_cq(init_attr->ext.cq)->cqn : 0;
410 411 412

	srq->db_reg_l = hr_dev->reg_base + SRQ_DB_REG;

413
	ret = hns_roce_srq_alloc(hr_dev, to_hr_pd(ib_srq->pd)->pdn, cqn, 0,
414 415 416 417 418
				 &srq->mtt, 0, srq);
	if (ret)
		goto err_wrid;

	srq->event = hns_roce_ib_srq_event;
419
	resp.srqn = srq->srqn;
420

421
	if (udata) {
422 423
		if (ib_copy_to_udata(udata, &resp,
				     min(udata->outlen, sizeof(resp)))) {
424
			ret = -EFAULT;
425
			goto err_srqc_alloc;
426 427 428
		}
	}

429
	return 0;
430

431 432 433
err_srqc_alloc:
	hns_roce_srq_free(hr_dev, srq);

434
err_wrid:
435 436 437
	if (udata)
		destroy_user_srq(hr_dev, srq);
	else
438
		destroy_kernel_srq(hr_dev, srq);
439

440
err_srq:
441
	return ret;
442 443
}

444
void hns_roce_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
445 446 447 448 449 450 451
{
	struct hns_roce_dev *hr_dev = to_hr_dev(ibsrq->device);
	struct hns_roce_srq *srq = to_hr_srq(ibsrq);

	hns_roce_srq_free(hr_dev, srq);
	hns_roce_mtt_cleanup(hr_dev, &srq->mtt);

452
	if (udata) {
453 454 455
		hns_roce_mtt_cleanup(hr_dev, &srq->idx_que.mtt);
	} else {
		kvfree(srq->wrid);
456
		hns_roce_buf_free(hr_dev, &srq->buf);
457
	}
458 459
	ib_umem_release(srq->idx_que.umem);
	ib_umem_release(srq->umem);
460 461
}

L
Lijun Ou 已提交
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
int hns_roce_init_srq_table(struct hns_roce_dev *hr_dev)
{
	struct hns_roce_srq_table *srq_table = &hr_dev->srq_table;

	xa_init(&srq_table->xa);

	return hns_roce_bitmap_init(&srq_table->bitmap, hr_dev->caps.num_srqs,
				    hr_dev->caps.num_srqs - 1,
				    hr_dev->caps.reserved_srqs, 0);
}

void hns_roce_cleanup_srq_table(struct hns_roce_dev *hr_dev)
{
	hns_roce_bitmap_cleanup(&hr_dev->srq_table.bitmap);
}