hns_roce_qp.c 31.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/*
 * Copyright (c) 2016 Hisilicon Limited.
 * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
 *
 * This software is available to you under a choice of one of two
 * licenses.  You may choose to be licensed under the terms of the GNU
 * General Public License (GPL) Version 2, available from the file
 * COPYING in the main directory of this source tree, or the
 * OpenIB.org BSD license below:
 *
 *     Redistribution and use in source and binary forms, with or
 *     without modification, are permitted provided that the following
 *     conditions are met:
 *
 *      - Redistributions of source code must retain the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer.
 *
 *      - Redistributions in binary form must reproduce the above
 *        copyright notice, this list of conditions and the following
 *        disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

34
#include <linux/pci.h>
35
#include <linux/platform_device.h>
L
Lijun Ou 已提交
36
#include <rdma/ib_addr.h>
37
#include <rdma/ib_umem.h>
38
#include <rdma/uverbs_ioctl.h>
39 40 41
#include "hns_roce_common.h"
#include "hns_roce_device.h"
#include "hns_roce_hem.h"
42
#include <rdma/hns-abi.h>
43

44
#define SQP_NUM				(2 * HNS_ROCE_MAX_PORTS)
45 46 47 48

void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type)
{
	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
49
	struct device *dev = hr_dev->dev;
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
	struct hns_roce_qp *qp;

	spin_lock(&qp_table->lock);

	qp = __hns_roce_qp_lookup(hr_dev, qpn);
	if (qp)
		atomic_inc(&qp->refcount);

	spin_unlock(&qp_table->lock);

	if (!qp) {
		dev_warn(dev, "Async event for bogus QP %08x\n", qpn);
		return;
	}

	qp->event(qp, (enum hns_roce_event)event_type);

	if (atomic_dec_and_test(&qp->refcount))
		complete(&qp->free);
}
Y
Yixian Liu 已提交
70
EXPORT_SYMBOL_GPL(hns_roce_qp_event);
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

static void hns_roce_ib_qp_event(struct hns_roce_qp *hr_qp,
				 enum hns_roce_event type)
{
	struct ib_event event;
	struct ib_qp *ibqp = &hr_qp->ibqp;

	if (ibqp->event_handler) {
		event.device = ibqp->device;
		event.element.qp = ibqp;
		switch (type) {
		case HNS_ROCE_EVENT_TYPE_PATH_MIG:
			event.event = IB_EVENT_PATH_MIG;
			break;
		case HNS_ROCE_EVENT_TYPE_COMM_EST:
			event.event = IB_EVENT_COMM_EST;
			break;
		case HNS_ROCE_EVENT_TYPE_SQ_DRAINED:
			event.event = IB_EVENT_SQ_DRAINED;
			break;
		case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH:
			event.event = IB_EVENT_QP_LAST_WQE_REACHED;
			break;
		case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR:
			event.event = IB_EVENT_QP_FATAL;
			break;
		case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED:
			event.event = IB_EVENT_PATH_MIG_ERR;
			break;
		case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR:
			event.event = IB_EVENT_QP_REQ_ERR;
			break;
		case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR:
			event.event = IB_EVENT_QP_ACCESS_ERR;
			break;
		default:
107
			dev_dbg(ibqp->device->dev.parent, "roce_ib: Unexpected event type %d on QP %06lx\n",
108 109 110 111 112 113 114 115 116 117 118 119
				type, hr_qp->qpn);
			return;
		}
		ibqp->event_handler(&event, ibqp->qp_context);
	}
}

static int hns_roce_reserve_range_qp(struct hns_roce_dev *hr_dev, int cnt,
				     int align, unsigned long *base)
{
	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;

120 121 122 123
	return hns_roce_bitmap_alloc_range(&qp_table->bitmap, cnt, align,
					   base) ?
		       -ENOMEM :
		       0;
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
}

enum hns_roce_qp_state to_hns_roce_state(enum ib_qp_state state)
{
	switch (state) {
	case IB_QPS_RESET:
		return HNS_ROCE_QP_STATE_RST;
	case IB_QPS_INIT:
		return HNS_ROCE_QP_STATE_INIT;
	case IB_QPS_RTR:
		return HNS_ROCE_QP_STATE_RTR;
	case IB_QPS_RTS:
		return HNS_ROCE_QP_STATE_RTS;
	case IB_QPS_SQD:
		return HNS_ROCE_QP_STATE_SQD;
	case IB_QPS_ERR:
		return HNS_ROCE_QP_STATE_ERR;
	default:
		return HNS_ROCE_QP_NUM_STATE;
	}
}
145
EXPORT_SYMBOL_GPL(to_hns_roce_state);
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

static int hns_roce_gsi_qp_alloc(struct hns_roce_dev *hr_dev, unsigned long qpn,
				 struct hns_roce_qp *hr_qp)
{
	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
	int ret;

	if (!qpn)
		return -EINVAL;

	hr_qp->qpn = qpn;

	spin_lock_irq(&qp_table->lock);
	ret = radix_tree_insert(&hr_dev->qp_table_tree,
				hr_qp->qpn & (hr_dev->caps.num_qps - 1), hr_qp);
	spin_unlock_irq(&qp_table->lock);
	if (ret) {
163
		dev_err(hr_dev->dev, "QPC radix_tree_insert failed\n");
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
		goto err_put_irrl;
	}

	atomic_set(&hr_qp->refcount, 1);
	init_completion(&hr_qp->free);

	return 0;

err_put_irrl:

	return ret;
}

static int hns_roce_qp_alloc(struct hns_roce_dev *hr_dev, unsigned long qpn,
			     struct hns_roce_qp *hr_qp)
{
	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
181
	struct device *dev = hr_dev->dev;
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
	int ret;

	if (!qpn)
		return -EINVAL;

	hr_qp->qpn = qpn;

	/* Alloc memory for QPC */
	ret = hns_roce_table_get(hr_dev, &qp_table->qp_table, hr_qp->qpn);
	if (ret) {
		dev_err(dev, "QPC table get failed\n");
		goto err_out;
	}

	/* Alloc memory for IRRL */
	ret = hns_roce_table_get(hr_dev, &qp_table->irrl_table, hr_qp->qpn);
	if (ret) {
		dev_err(dev, "IRRL table get failed\n");
		goto err_put_qp;
	}

203 204 205 206 207 208 209 210 211 212
	if (hr_dev->caps.trrl_entry_sz) {
		/* Alloc memory for TRRL */
		ret = hns_roce_table_get(hr_dev, &qp_table->trrl_table,
					 hr_qp->qpn);
		if (ret) {
			dev_err(dev, "TRRL table get failed\n");
			goto err_put_irrl;
		}
	}

213 214 215 216 217 218 219 220 221 222
	if (hr_dev->caps.sccc_entry_sz) {
		/* Alloc memory for SCC CTX */
		ret = hns_roce_table_get(hr_dev, &qp_table->sccc_table,
					 hr_qp->qpn);
		if (ret) {
			dev_err(dev, "SCC CTX table get failed\n");
			goto err_put_trrl;
		}
	}

223 224 225 226 227 228
	spin_lock_irq(&qp_table->lock);
	ret = radix_tree_insert(&hr_dev->qp_table_tree,
				hr_qp->qpn & (hr_dev->caps.num_qps - 1), hr_qp);
	spin_unlock_irq(&qp_table->lock);
	if (ret) {
		dev_err(dev, "QPC radix_tree_insert failed\n");
229
		goto err_put_sccc;
230 231 232 233 234 235 236
	}

	atomic_set(&hr_qp->refcount, 1);
	init_completion(&hr_qp->free);

	return 0;

237 238 239 240 241
err_put_sccc:
	if (hr_dev->caps.sccc_entry_sz)
		hns_roce_table_put(hr_dev, &qp_table->sccc_table,
				   hr_qp->qpn);

242 243 244 245
err_put_trrl:
	if (hr_dev->caps.trrl_entry_sz)
		hns_roce_table_put(hr_dev, &qp_table->trrl_table, hr_qp->qpn);

246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
err_put_irrl:
	hns_roce_table_put(hr_dev, &qp_table->irrl_table, hr_qp->qpn);

err_put_qp:
	hns_roce_table_put(hr_dev, &qp_table->qp_table, hr_qp->qpn);

err_out:
	return ret;
}

void hns_roce_qp_remove(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
{
	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
	unsigned long flags;

	spin_lock_irqsave(&qp_table->lock, flags);
	radix_tree_delete(&hr_dev->qp_table_tree,
			  hr_qp->qpn & (hr_dev->caps.num_qps - 1));
	spin_unlock_irqrestore(&qp_table->lock, flags);
}
266
EXPORT_SYMBOL_GPL(hns_roce_qp_remove);
267 268 269 270 271 272 273 274 275 276

void hns_roce_qp_free(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp)
{
	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;

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

	if ((hr_qp->ibqp.qp_type) != IB_QPT_GSI) {
277 278 279
		if (hr_dev->caps.trrl_entry_sz)
			hns_roce_table_put(hr_dev, &qp_table->trrl_table,
					   hr_qp->qpn);
280 281 282 283
		hns_roce_table_put(hr_dev, &qp_table->irrl_table, hr_qp->qpn);
		hns_roce_table_put(hr_dev, &qp_table->qp_table, hr_qp->qpn);
	}
}
284
EXPORT_SYMBOL_GPL(hns_roce_qp_free);
285 286 287 288 289 290

void hns_roce_release_range_qp(struct hns_roce_dev *hr_dev, int base_qpn,
			       int cnt)
{
	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;

291
	if (base_qpn < SQP_NUM)
292 293
		return;

294
	hns_roce_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt, BITMAP_RR);
295
}
296
EXPORT_SYMBOL_GPL(hns_roce_release_range_qp);
297 298

static int hns_roce_set_rq_size(struct hns_roce_dev *hr_dev,
299
				struct ib_qp_cap *cap, bool is_user, int has_rq,
300 301
				struct hns_roce_qp *hr_qp)
{
302
	struct device *dev = hr_dev->dev;
303 304 305 306 307 308 309 310 311 312
	u32 max_cnt;

	/* Check the validity of QP support capacity */
	if (cap->max_recv_wr > hr_dev->caps.max_wqes ||
	    cap->max_recv_sge > hr_dev->caps.max_rq_sg) {
		dev_err(dev, "RQ WR or sge error!max_recv_wr=%d max_recv_sge=%d\n",
			cap->max_recv_wr, cap->max_recv_sge);
		return -EINVAL;
	}

313 314 315 316 317 318
	/* If srq exist, set zero for relative number of rq */
	if (!has_rq) {
		hr_qp->rq.wqe_cnt = 0;
		hr_qp->rq.max_gs = 0;
		cap->max_recv_wr = 0;
		cap->max_recv_sge = 0;
319 320 321 322 323 324
	} else {
		if (is_user && (!cap->max_recv_wr || !cap->max_recv_sge)) {
			dev_err(dev, "user space no need config max_recv_wr max_recv_sge\n");
			return -EINVAL;
		}

325 326 327 328 329
		if (hr_dev->caps.min_wqes)
			max_cnt = max(cap->max_recv_wr, hr_dev->caps.min_wqes);
		else
			max_cnt = cap->max_recv_wr;

330 331 332
		hr_qp->rq.wqe_cnt = roundup_pow_of_two(max_cnt);

		if ((u32)hr_qp->rq.wqe_cnt > hr_dev->caps.max_wqes) {
333
			dev_err(dev, "while setting rq size, rq.wqe_cnt too large\n");
334 335 336 337 338
			return -EINVAL;
		}

		max_cnt = max(1U, cap->max_recv_sge);
		hr_qp->rq.max_gs = roundup_pow_of_two(max_cnt);
339 340 341 342 343 344 345
		if (hr_dev->caps.max_rq_sg <= 2)
			hr_qp->rq.wqe_shift =
					ilog2(hr_dev->caps.max_rq_desc_sz);
		else
			hr_qp->rq.wqe_shift =
					ilog2(hr_dev->caps.max_rq_desc_sz
					      * hr_qp->rq.max_gs);
346 347 348 349 350 351 352 353 354
	}

	cap->max_recv_wr = hr_qp->rq.max_post = hr_qp->rq.wqe_cnt;
	cap->max_recv_sge = hr_qp->rq.max_gs;

	return 0;
}

static int hns_roce_set_user_sq_size(struct hns_roce_dev *hr_dev,
355
				     struct ib_qp_cap *cap,
356 357 358 359 360
				     struct hns_roce_qp *hr_qp,
				     struct hns_roce_ib_create_qp *ucmd)
{
	u32 roundup_sq_stride = roundup_pow_of_two(hr_dev->caps.max_sq_desc_sz);
	u8 max_sq_stride = ilog2(roundup_sq_stride);
L
Lijun Ou 已提交
361
	u32 ex_sge_num;
362
	u32 page_size;
363
	u32 max_cnt;
364 365 366 367 368

	/* Sanity check SQ size before proceeding */
	if ((u32)(1 << ucmd->log_sq_bb_count) > hr_dev->caps.max_wqes ||
	     ucmd->log_sq_stride > max_sq_stride ||
	     ucmd->log_sq_stride < HNS_ROCE_IB_MIN_SQ_STRIDE) {
369
		dev_err(hr_dev->dev, "check SQ size error!\n");
370 371 372
		return -EINVAL;
	}

373 374 375 376 377 378
	if (cap->max_send_sge > hr_dev->caps.max_sq_sg) {
		dev_err(hr_dev->dev, "SQ sge error! max_send_sge=%d\n",
			cap->max_send_sge);
		return -EINVAL;
	}

379 380 381
	hr_qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count;
	hr_qp->sq.wqe_shift = ucmd->log_sq_stride;

382 383 384 385 386 387 388 389 390
	max_cnt = max(1U, cap->max_send_sge);
	if (hr_dev->caps.max_sq_sg <= 2)
		hr_qp->sq.max_gs = roundup_pow_of_two(max_cnt);
	else
		hr_qp->sq.max_gs = max_cnt;

	if (hr_qp->sq.max_gs > 2)
		hr_qp->sge.sge_cnt = roundup_pow_of_two(hr_qp->sq.wqe_cnt *
							(hr_qp->sq.max_gs - 2));
391 392 393 394 395 396 397 398 399 400

	if ((hr_qp->sq.max_gs > 2) && (hr_dev->pci_dev->revision == 0x20)) {
		if (hr_qp->sge.sge_cnt > hr_dev->caps.max_extend_sg) {
			dev_err(hr_dev->dev,
				"The extended sge cnt error! sge_cnt=%d\n",
				hr_qp->sge.sge_cnt);
			return -EINVAL;
		}
	}

401
	hr_qp->sge.sge_shift = 4;
L
Lijun Ou 已提交
402
	ex_sge_num = hr_qp->sge.sge_cnt;
403

404
	/* Get buf size, SQ and RQ  are aligned to page_szie */
405 406
	if (hr_dev->caps.max_sq_sg <= 2) {
		hr_qp->buff_size = HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt <<
407
					     hr_qp->rq.wqe_shift), PAGE_SIZE) +
408
				   HNS_ROCE_ALOGN_UP((hr_qp->sq.wqe_cnt <<
409 410
					     hr_qp->sq.wqe_shift), PAGE_SIZE);

411 412
		hr_qp->sq.offset = 0;
		hr_qp->rq.offset = HNS_ROCE_ALOGN_UP((hr_qp->sq.wqe_cnt <<
413
					     hr_qp->sq.wqe_shift), PAGE_SIZE);
414
	} else {
415
		page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
L
Lijun Ou 已提交
416 417
		hr_qp->sge.sge_cnt =
		       max(page_size / (1 << hr_qp->sge.sge_shift), ex_sge_num);
418
		hr_qp->buff_size = HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt <<
419
					     hr_qp->rq.wqe_shift), page_size) +
420
				   HNS_ROCE_ALOGN_UP((hr_qp->sge.sge_cnt <<
421
					     hr_qp->sge.sge_shift), page_size) +
422
				   HNS_ROCE_ALOGN_UP((hr_qp->sq.wqe_cnt <<
423
					     hr_qp->sq.wqe_shift), page_size);
424 425

		hr_qp->sq.offset = 0;
L
Lijun Ou 已提交
426
		if (ex_sge_num) {
427 428 429
			hr_qp->sge.offset = HNS_ROCE_ALOGN_UP(
							(hr_qp->sq.wqe_cnt <<
							hr_qp->sq.wqe_shift),
430
							page_size);
431 432 433
			hr_qp->rq.offset = hr_qp->sge.offset +
					HNS_ROCE_ALOGN_UP((hr_qp->sge.sge_cnt <<
						hr_qp->sge.sge_shift),
434
						page_size);
435 436 437 438
		} else {
			hr_qp->rq.offset = HNS_ROCE_ALOGN_UP(
							(hr_qp->sq.wqe_cnt <<
							hr_qp->sq.wqe_shift),
439
							page_size);
440 441
		}
	}
442 443 444 445 446 447 448 449

	return 0;
}

static int hns_roce_set_kernel_sq_size(struct hns_roce_dev *hr_dev,
				       struct ib_qp_cap *cap,
				       struct hns_roce_qp *hr_qp)
{
450
	struct device *dev = hr_dev->dev;
451
	u32 page_size;
452
	u32 max_cnt;
453
	int size;
454 455 456 457

	if (cap->max_send_wr  > hr_dev->caps.max_wqes  ||
	    cap->max_send_sge > hr_dev->caps.max_sq_sg ||
	    cap->max_inline_data > hr_dev->caps.max_sq_inline) {
458
		dev_err(dev, "SQ WR or sge or inline data error!\n");
459 460 461 462 463 464 465
		return -EINVAL;
	}

	hr_qp->sq.wqe_shift = ilog2(hr_dev->caps.max_sq_desc_sz);
	hr_qp->sq_max_wqes_per_wr = 1;
	hr_qp->sq_spare_wqes = 0;

466 467 468 469 470
	if (hr_dev->caps.min_wqes)
		max_cnt = max(cap->max_send_wr, hr_dev->caps.min_wqes);
	else
		max_cnt = cap->max_send_wr;

471 472
	hr_qp->sq.wqe_cnt = roundup_pow_of_two(max_cnt);
	if ((u32)hr_qp->sq.wqe_cnt > hr_dev->caps.max_wqes) {
473
		dev_err(dev, "while setting kernel sq size, sq.wqe_cnt too large\n");
474 475 476 477 478
		return -EINVAL;
	}

	/* Get data_seg numbers */
	max_cnt = max(1U, cap->max_send_sge);
479 480 481 482
	if (hr_dev->caps.max_sq_sg <= 2)
		hr_qp->sq.max_gs = roundup_pow_of_two(max_cnt);
	else
		hr_qp->sq.max_gs = max_cnt;
483

484 485 486 487 488 489
	if (hr_qp->sq.max_gs > 2) {
		hr_qp->sge.sge_cnt = roundup_pow_of_two(hr_qp->sq.wqe_cnt *
				     (hr_qp->sq.max_gs - 2));
		hr_qp->sge.sge_shift = 4;
	}

O
oulijun 已提交
490 491 492 493 494 495 496
	/* ud sqwqe's sge use extend sge */
	if (hr_dev->caps.max_sq_sg > 2 && hr_qp->ibqp.qp_type == IB_QPT_GSI) {
		hr_qp->sge.sge_cnt = roundup_pow_of_two(hr_qp->sq.wqe_cnt *
				     hr_qp->sq.max_gs);
		hr_qp->sge.sge_shift = 4;
	}

497 498 499 500 501 502 503 504
	if ((hr_qp->sq.max_gs > 2) && hr_dev->pci_dev->revision == 0x20) {
		if (hr_qp->sge.sge_cnt > hr_dev->caps.max_extend_sg) {
			dev_err(dev, "The extended sge cnt error! sge_cnt=%d\n",
				hr_qp->sge.sge_cnt);
			return -EINVAL;
		}
	}

505
	/* Get buf size, SQ and RQ are aligned to PAGE_SIZE */
506
	page_size = 1 << (hr_dev->caps.mtt_buf_pg_sz + PAGE_SHIFT);
507
	hr_qp->sq.offset = 0;
508
	size = HNS_ROCE_ALOGN_UP(hr_qp->sq.wqe_cnt << hr_qp->sq.wqe_shift,
509
				 page_size);
510 511

	if (hr_dev->caps.max_sq_sg > 2 && hr_qp->sge.sge_cnt) {
L
Lijun Ou 已提交
512 513
		hr_qp->sge.sge_cnt = max(page_size/(1 << hr_qp->sge.sge_shift),
					(u32)hr_qp->sge.sge_cnt);
514 515
		hr_qp->sge.offset = size;
		size += HNS_ROCE_ALOGN_UP(hr_qp->sge.sge_cnt <<
516
					  hr_qp->sge.sge_shift, page_size);
517 518 519 520
	}

	hr_qp->rq.offset = size;
	size += HNS_ROCE_ALOGN_UP((hr_qp->rq.wqe_cnt << hr_qp->rq.wqe_shift),
521
				  page_size);
522
	hr_qp->buff_size = size;
523 524 525 526 527 528 529 530 531 532 533

	/* Get wr and sge number which send */
	cap->max_send_wr = hr_qp->sq.max_post = hr_qp->sq.wqe_cnt;
	cap->max_send_sge = hr_qp->sq.max_gs;

	/* We don't support inline sends for kernel QPs (yet) */
	cap->max_inline_data = 0;

	return 0;
}

534 535 536 537 538 539 540 541
static int hns_roce_qp_has_sq(struct ib_qp_init_attr *attr)
{
	if (attr->qp_type == IB_QPT_XRC_TGT)
		return 0;

	return 1;
}

542 543 544
static int hns_roce_qp_has_rq(struct ib_qp_init_attr *attr)
{
	if (attr->qp_type == IB_QPT_XRC_INI ||
545 546
	    attr->qp_type == IB_QPT_XRC_TGT || attr->srq ||
	    !attr->cap.max_recv_wr)
547 548 549 550 551
		return 0;

	return 1;
}

552 553 554 555 556 557
static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev,
				     struct ib_pd *ib_pd,
				     struct ib_qp_init_attr *init_attr,
				     struct ib_udata *udata, unsigned long sqpn,
				     struct hns_roce_qp *hr_qp)
{
558
	struct device *dev = hr_dev->dev;
559
	struct hns_roce_ib_create_qp ucmd;
560
	struct hns_roce_ib_create_qp_resp resp = {};
561 562
	struct hns_roce_ucontext *uctx = rdma_udata_to_drv_context(
		udata, struct hns_roce_ucontext, ibucontext);
563 564
	unsigned long qpn = 0;
	int ret = 0;
565 566
	u32 page_shift;
	u32 npages;
567
	int i;
568 569 570 571 572 573 574

	mutex_init(&hr_qp->mutex);
	spin_lock_init(&hr_qp->sq.lock);
	spin_lock_init(&hr_qp->rq.lock);

	hr_qp->state = IB_QPS_RESET;

O
oulijun 已提交
575 576
	hr_qp->ibqp.qp_type = init_attr->qp_type;

577
	if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
578
		hr_qp->sq_signal_bits = cpu_to_le32(IB_SIGNAL_ALL_WR);
579
	else
580
		hr_qp->sq_signal_bits = cpu_to_le32(IB_SIGNAL_REQ_WR);
581

582
	ret = hns_roce_set_rq_size(hr_dev, &init_attr->cap, udata,
583
				   hns_roce_qp_has_rq(init_attr), hr_qp);
584 585 586 587 588
	if (ret) {
		dev_err(dev, "hns_roce_set_rq_size failed\n");
		goto err_out;
	}

589 590
	if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE) &&
	    hns_roce_qp_has_rq(init_attr)) {
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
		/* allocate recv inline buf */
		hr_qp->rq_inl_buf.wqe_list = kcalloc(hr_qp->rq.wqe_cnt,
					       sizeof(struct hns_roce_rinl_wqe),
					       GFP_KERNEL);
		if (!hr_qp->rq_inl_buf.wqe_list) {
			ret = -ENOMEM;
			goto err_out;
		}

		hr_qp->rq_inl_buf.wqe_cnt = hr_qp->rq.wqe_cnt;

		/* Firstly, allocate a list of sge space buffer */
		hr_qp->rq_inl_buf.wqe_list[0].sg_list =
					kcalloc(hr_qp->rq_inl_buf.wqe_cnt,
					       init_attr->cap.max_recv_sge *
					       sizeof(struct hns_roce_rinl_sge),
					       GFP_KERNEL);
		if (!hr_qp->rq_inl_buf.wqe_list[0].sg_list) {
			ret = -ENOMEM;
			goto err_wqe_list;
		}

		for (i = 1; i < hr_qp->rq_inl_buf.wqe_cnt; i++)
			/* Secondly, reallocate the buffer */
			hr_qp->rq_inl_buf.wqe_list[i].sg_list =
				&hr_qp->rq_inl_buf.wqe_list[0].sg_list[i *
				init_attr->cap.max_recv_sge];
	}

620
	if (udata) {
621 622 623
		if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) {
			dev_err(dev, "ib_copy_from_udata error for create qp\n");
			ret = -EFAULT;
624
			goto err_rq_sge_list;
625 626
		}

627 628
		ret = hns_roce_set_user_sq_size(hr_dev, &init_attr->cap, hr_qp,
						&ucmd);
629 630
		if (ret) {
			dev_err(dev, "hns_roce_set_user_sq_size error for create qp\n");
631
			goto err_rq_sge_list;
632 633
		}

634 635
		hr_qp->umem = ib_umem_get(udata, ucmd.buf_addr,
					  hr_qp->buff_size, 0, 0);
636 637 638
		if (IS_ERR(hr_qp->umem)) {
			dev_err(dev, "ib_umem_get error for create qp\n");
			ret = PTR_ERR(hr_qp->umem);
639
			goto err_rq_sge_list;
640 641
		}

642
		hr_qp->mtt.mtt_type = MTT_TYPE_WQE;
643
		page_shift = PAGE_SHIFT;
644 645 646
		if (hr_dev->caps.mtt_buf_pg_sz) {
			npages = (ib_umem_page_count(hr_qp->umem) +
				  (1 << hr_dev->caps.mtt_buf_pg_sz) - 1) /
647 648
				 (1 << hr_dev->caps.mtt_buf_pg_sz);
			page_shift += hr_dev->caps.mtt_buf_pg_sz;
649 650 651 652 653
			ret = hns_roce_mtt_init(hr_dev, npages,
				    page_shift,
				    &hr_qp->mtt);
		} else {
			ret = hns_roce_mtt_init(hr_dev,
654 655
						ib_umem_page_count(hr_qp->umem),
						page_shift, &hr_qp->mtt);
656
		}
657 658 659 660 661 662 663 664 665 666 667
		if (ret) {
			dev_err(dev, "hns_roce_mtt_init error for create qp\n");
			goto err_buf;
		}

		ret = hns_roce_ib_umem_write_mtt(hr_dev, &hr_qp->mtt,
						 hr_qp->umem);
		if (ret) {
			dev_err(dev, "hns_roce_ib_umem_write_mtt error for create qp\n");
			goto err_mtt;
		}
668

669 670 671 672
		if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SQ_RECORD_DB) &&
		    (udata->inlen >= sizeof(ucmd)) &&
		    (udata->outlen >= sizeof(resp)) &&
		    hns_roce_qp_has_sq(init_attr)) {
673 674
			ret = hns_roce_db_map_user(uctx, udata, ucmd.sdb_addr,
						   &hr_qp->sdb);
675 676 677 678 679 680 681 682 683 684
			if (ret) {
				dev_err(dev, "sq record doorbell map failed!\n");
				goto err_mtt;
			}

			/* indicate kernel supports sq record db */
			resp.cap_flags |= HNS_ROCE_SUPPORT_SQ_RECORD_DB;
			hr_qp->sdb_en = 1;
		}

685
		if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
686
		    (udata->outlen >= sizeof(resp)) &&
687
		    hns_roce_qp_has_rq(init_attr)) {
688 689
			ret = hns_roce_db_map_user(uctx, udata, ucmd.db_addr,
						   &hr_qp->rdb);
690
			if (ret) {
O
oulijun 已提交
691
				dev_err(dev, "rq record doorbell map failed!\n");
692
				goto err_sq_dbmap;
693
			}
694 695 696 697

			/* indicate kernel supports rq record db */
			resp.cap_flags |= HNS_ROCE_SUPPORT_RQ_RECORD_DB;
			hr_qp->rdb_en = 1;
698
		}
699 700 701 702 703
	} else {
		if (init_attr->create_flags &
		    IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) {
			dev_err(dev, "init_attr->create_flags error!\n");
			ret = -EINVAL;
704
			goto err_rq_sge_list;
705 706 707 708 709
		}

		if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO) {
			dev_err(dev, "init_attr->create_flags error!\n");
			ret = -EINVAL;
710
			goto err_rq_sge_list;
711 712 713 714
		}

		/* Set SQ size */
		ret = hns_roce_set_kernel_sq_size(hr_dev, &init_attr->cap,
715
						  hr_qp);
716 717
		if (ret) {
			dev_err(dev, "hns_roce_set_kernel_sq_size error!\n");
718
			goto err_rq_sge_list;
719 720 721
		}

		/* QP doorbell register address */
722
		hr_qp->sq.db_reg_l = hr_dev->reg_base + hr_dev->sdb_offset +
723
				     DB_REG_OFFSET * hr_dev->priv_uar.index;
724
		hr_qp->rq.db_reg_l = hr_dev->reg_base + hr_dev->odb_offset +
725 726
				     DB_REG_OFFSET * hr_dev->priv_uar.index;

727 728 729 730 731 732 733 734
		if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
		    hns_roce_qp_has_rq(init_attr)) {
			ret = hns_roce_alloc_db(hr_dev, &hr_qp->rdb, 0);
			if (ret) {
				dev_err(dev, "rq record doorbell alloc failed!\n");
				goto err_rq_sge_list;
			}
			*hr_qp->rdb.db_record = 0;
735
			hr_qp->rdb_en = 1;
736 737
		}

738
		/* Allocate QP buf */
739 740 741 742
		page_shift = PAGE_SHIFT + hr_dev->caps.mtt_buf_pg_sz;
		if (hns_roce_buf_alloc(hr_dev, hr_qp->buff_size,
				       (1 << page_shift) * 2,
				       &hr_qp->hr_buf, page_shift)) {
743 744
			dev_err(dev, "hns_roce_buf_alloc error!\n");
			ret = -ENOMEM;
745
			goto err_db;
746 747
		}

748
		hr_qp->mtt.mtt_type = MTT_TYPE_WQE;
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
		/* Write MTT */
		ret = hns_roce_mtt_init(hr_dev, hr_qp->hr_buf.npages,
					hr_qp->hr_buf.page_shift, &hr_qp->mtt);
		if (ret) {
			dev_err(dev, "hns_roce_mtt_init error for kernel create qp\n");
			goto err_buf;
		}

		ret = hns_roce_buf_write_mtt(hr_dev, &hr_qp->mtt,
					     &hr_qp->hr_buf);
		if (ret) {
			dev_err(dev, "hns_roce_buf_write_mtt error for kernel create qp\n");
			goto err_mtt;
		}

764 765 766 767
		hr_qp->sq.wrid = kcalloc(hr_qp->sq.wqe_cnt, sizeof(u64),
					 GFP_KERNEL);
		hr_qp->rq.wrid = kcalloc(hr_qp->rq.wqe_cnt, sizeof(u64),
					 GFP_KERNEL);
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
		if (!hr_qp->sq.wrid || !hr_qp->rq.wrid) {
			ret = -ENOMEM;
			goto err_wrid;
		}
	}

	if (sqpn) {
		qpn = sqpn;
	} else {
		/* Get QPN */
		ret = hns_roce_reserve_range_qp(hr_dev, 1, 1, &qpn);
		if (ret) {
			dev_err(dev, "hns_roce_reserve_range_qp alloc qpn error\n");
			goto err_wrid;
		}
	}

785 786 787
	if (init_attr->qp_type == IB_QPT_GSI &&
	    hr_dev->hw_rev == HNS_ROCE_HW_VER1) {
		/* In v1 engine, GSI QP context in RoCE engine's register */
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
		ret = hns_roce_gsi_qp_alloc(hr_dev, qpn, hr_qp);
		if (ret) {
			dev_err(dev, "hns_roce_qp_alloc failed!\n");
			goto err_qpn;
		}
	} else {
		ret = hns_roce_qp_alloc(hr_dev, qpn, hr_qp);
		if (ret) {
			dev_err(dev, "hns_roce_qp_alloc failed!\n");
			goto err_qpn;
		}
	}

	if (sqpn)
		hr_qp->doorbell_qpn = 1;
	else
		hr_qp->doorbell_qpn = cpu_to_le64(hr_qp->qpn);

806 807 808
	if (udata) {
		ret = ib_copy_to_udata(udata, &resp,
				       min(udata->outlen, sizeof(resp)));
809 810 811
		if (ret)
			goto err_qp;
	}
812 813 814 815 816 817 818

	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL) {
		ret = hr_dev->hw->qp_flow_control_init(hr_dev, hr_qp);
		if (ret)
			goto err_qp;
	}

819 820 821 822
	hr_qp->event = hns_roce_ib_qp_event;

	return 0;

823 824 825 826 827 828 829
err_qp:
	if (init_attr->qp_type == IB_QPT_GSI &&
		hr_dev->hw_rev == HNS_ROCE_HW_VER1)
		hns_roce_qp_remove(hr_dev, hr_qp);
	else
		hns_roce_qp_free(hr_dev, hr_qp);

830 831 832 833 834
err_qpn:
	if (!sqpn)
		hns_roce_release_range_qp(hr_dev, qpn, 1);

err_wrid:
835
	if (udata) {
836
		if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB) &&
837
		    (udata->outlen >= sizeof(resp)) &&
838
		    hns_roce_qp_has_rq(init_attr))
839
			hns_roce_db_unmap_user(uctx, &hr_qp->rdb);
840 841 842 843
	} else {
		kfree(hr_qp->sq.wrid);
		kfree(hr_qp->rq.wrid);
	}
844

845
err_sq_dbmap:
846
	if (udata)
847 848 849 850
		if ((hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SQ_RECORD_DB) &&
		    (udata->inlen >= sizeof(ucmd)) &&
		    (udata->outlen >= sizeof(resp)) &&
		    hns_roce_qp_has_sq(init_attr))
851
			hns_roce_db_unmap_user(uctx, &hr_qp->sdb);
852

853 854 855 856
err_mtt:
	hns_roce_mtt_cleanup(hr_dev, &hr_qp->mtt);

err_buf:
857
	if (hr_qp->umem)
858 859 860 861
		ib_umem_release(hr_qp->umem);
	else
		hns_roce_buf_free(hr_dev, hr_qp->buff_size, &hr_qp->hr_buf);

862
err_db:
863
	if (!udata && hns_roce_qp_has_rq(init_attr) &&
864 865 866
	    (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RECORD_DB))
		hns_roce_free_db(hr_dev, &hr_qp->rdb);

867 868 869 870 871 872 873 874
err_rq_sge_list:
	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE)
		kfree(hr_qp->rq_inl_buf.wqe_list[0].sg_list);

err_wqe_list:
	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_RQ_INLINE)
		kfree(hr_qp->rq_inl_buf.wqe_list);

875 876 877 878 879 880 881 882 883
err_out:
	return ret;
}

struct ib_qp *hns_roce_create_qp(struct ib_pd *pd,
				 struct ib_qp_init_attr *init_attr,
				 struct ib_udata *udata)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(pd->device);
884
	struct device *dev = hr_dev->dev;
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
	struct hns_roce_sqp *hr_sqp;
	struct hns_roce_qp *hr_qp;
	int ret;

	switch (init_attr->qp_type) {
	case IB_QPT_RC: {
		hr_qp = kzalloc(sizeof(*hr_qp), GFP_KERNEL);
		if (!hr_qp)
			return ERR_PTR(-ENOMEM);

		ret = hns_roce_create_qp_common(hr_dev, pd, init_attr, udata, 0,
						hr_qp);
		if (ret) {
			dev_err(dev, "Create RC QP failed\n");
			kfree(hr_qp);
			return ERR_PTR(ret);
		}

		hr_qp->ibqp.qp_num = hr_qp->qpn;

		break;
	}
	case IB_QPT_GSI: {
		/* Userspace is not allowed to create special QPs: */
909
		if (udata) {
910 911 912 913 914 915 916 917 918
			dev_err(dev, "not support usr space GSI\n");
			return ERR_PTR(-EINVAL);
		}

		hr_sqp = kzalloc(sizeof(*hr_sqp), GFP_KERNEL);
		if (!hr_sqp)
			return ERR_PTR(-ENOMEM);

		hr_qp = &hr_sqp->hr_qp;
919 920
		hr_qp->port = init_attr->port_num - 1;
		hr_qp->phy_port = hr_dev->iboe.phy_port[hr_qp->port];
O
oulijun 已提交
921 922 923 924 925 926 927

		/* when hw version is v1, the sqpn is allocated */
		if (hr_dev->caps.max_sq_sg <= 2)
			hr_qp->ibqp.qp_num = HNS_ROCE_MAX_PORTS +
					     hr_dev->iboe.phy_port[hr_qp->port];
		else
			hr_qp->ibqp.qp_num = 1;
928 929

		ret = hns_roce_create_qp_common(hr_dev, pd, init_attr, udata,
930
						hr_qp->ibqp.qp_num, hr_qp);
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
		if (ret) {
			dev_err(dev, "Create GSI QP failed!\n");
			kfree(hr_sqp);
			return ERR_PTR(ret);
		}

		break;
	}
	default:{
		dev_err(dev, "not support QP type %d\n", init_attr->qp_type);
		return ERR_PTR(-EINVAL);
	}
	}

	return &hr_qp->ibqp;
}
947
EXPORT_SYMBOL_GPL(hns_roce_create_qp);
948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965

int to_hr_qp_type(int qp_type)
{
	int transport_type;

	if (qp_type == IB_QPT_RC)
		transport_type = SERV_TYPE_RC;
	else if (qp_type == IB_QPT_UC)
		transport_type = SERV_TYPE_UC;
	else if (qp_type == IB_QPT_UD)
		transport_type = SERV_TYPE_UD;
	else if (qp_type == IB_QPT_GSI)
		transport_type = SERV_TYPE_UD;
	else
		transport_type = -1;

	return transport_type;
}
966
EXPORT_SYMBOL_GPL(to_hr_qp_type);
967 968 969 970 971 972 973

int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
		       int attr_mask, struct ib_udata *udata)
{
	struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device);
	struct hns_roce_qp *hr_qp = to_hr_qp(ibqp);
	enum ib_qp_state cur_state, new_state;
974
	struct device *dev = hr_dev->dev;
975 976
	int ret = -EINVAL;
	int p;
L
Lijun Ou 已提交
977
	enum ib_mtu active_mtu;
978 979 980 981 982 983 984 985

	mutex_lock(&hr_qp->mutex);

	cur_state = attr_mask & IB_QP_CUR_STATE ?
		    attr->cur_qp_state : (enum ib_qp_state)hr_qp->state;
	new_state = attr_mask & IB_QP_STATE ?
		    attr->qp_state : cur_state;

986 987 988 989
	if (ibqp->uobject &&
	    (attr_mask & IB_QP_STATE) && new_state == IB_QPS_ERR) {
		if (hr_qp->sdb_en == 1) {
			hr_qp->sq.head = *(int *)(hr_qp->sdb.virt_addr);
990 991 992

			if (hr_qp->rdb_en == 1)
				hr_qp->rq.head = *(int *)(hr_qp->rdb.virt_addr);
993 994 995 996 997 998
		} else {
			dev_warn(dev, "flush cqe is not supported in userspace!\n");
			goto out;
		}
	}

999 1000
	if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type,
				attr_mask)) {
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
		dev_err(dev, "ib_modify_qp_is_ok failed\n");
		goto out;
	}

	if ((attr_mask & IB_QP_PORT) &&
	    (attr->port_num == 0 || attr->port_num > hr_dev->caps.num_ports)) {
		dev_err(dev, "attr port_num invalid.attr->port_num=%d\n",
			attr->port_num);
		goto out;
	}

	if (attr_mask & IB_QP_PKEY_INDEX) {
		p = attr_mask & IB_QP_PORT ? (attr->port_num - 1) : hr_qp->port;
		if (attr->pkey_index >= hr_dev->caps.pkey_table_len[p]) {
			dev_err(dev, "attr pkey_index invalid.attr->pkey_index=%d\n",
				attr->pkey_index);
			goto out;
		}
	}

L
Lijun Ou 已提交
1021 1022 1023 1024
	if (attr_mask & IB_QP_PATH_MTU) {
		p = attr_mask & IB_QP_PORT ? (attr->port_num - 1) : hr_qp->port;
		active_mtu = iboe_get_mtu(hr_dev->iboe.netdevs[p]->mtu);

1025 1026 1027 1028
		if ((hr_dev->caps.max_mtu == IB_MTU_4096 &&
		    attr->path_mtu > IB_MTU_4096) ||
		    (hr_dev->caps.max_mtu == IB_MTU_2048 &&
		    attr->path_mtu > IB_MTU_2048) ||
L
Lijun Ou 已提交
1029 1030 1031 1032 1033 1034 1035 1036
		    attr->path_mtu < IB_MTU_256 ||
		    attr->path_mtu > active_mtu) {
			dev_err(dev, "attr path_mtu(%d)invalid while modify qp",
				attr->path_mtu);
			goto out;
		}
	}

1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
	    attr->max_rd_atomic > hr_dev->caps.max_qp_init_rdma) {
		dev_err(dev, "attr max_rd_atomic invalid.attr->max_rd_atomic=%d\n",
			attr->max_rd_atomic);
		goto out;
	}

	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
	    attr->max_dest_rd_atomic > hr_dev->caps.max_qp_dest_rdma) {
		dev_err(dev, "attr max_dest_rd_atomic invalid.attr->max_dest_rd_atomic=%d\n",
			attr->max_dest_rd_atomic);
		goto out;
	}

	if (cur_state == new_state && cur_state == IB_QPS_RESET) {
1052 1053 1054 1055 1056 1057 1058 1059
		if (hr_dev->caps.min_wqes) {
			ret = -EPERM;
			dev_err(dev, "cur_state=%d new_state=%d\n", cur_state,
				new_state);
		} else {
			ret = 0;
		}

1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
		goto out;
	}

	ret = hr_dev->hw->modify_qp(ibqp, attr, attr_mask, cur_state,
				    new_state);

out:
	mutex_unlock(&hr_qp->mutex);

	return ret;
}

void hns_roce_lock_cqs(struct hns_roce_cq *send_cq, struct hns_roce_cq *recv_cq)
		       __acquires(&send_cq->lock) __acquires(&recv_cq->lock)
{
	if (send_cq == recv_cq) {
		spin_lock_irq(&send_cq->lock);
		__acquire(&recv_cq->lock);
	} else if (send_cq->cqn < recv_cq->cqn) {
		spin_lock_irq(&send_cq->lock);
		spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);
	} else {
		spin_lock_irq(&recv_cq->lock);
		spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
	}
}
1086
EXPORT_SYMBOL_GPL(hns_roce_lock_cqs);
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102

void hns_roce_unlock_cqs(struct hns_roce_cq *send_cq,
			 struct hns_roce_cq *recv_cq) __releases(&send_cq->lock)
			 __releases(&recv_cq->lock)
{
	if (send_cq == recv_cq) {
		__release(&recv_cq->lock);
		spin_unlock_irq(&send_cq->lock);
	} else if (send_cq->cqn < recv_cq->cqn) {
		spin_unlock(&recv_cq->lock);
		spin_unlock_irq(&send_cq->lock);
	} else {
		spin_unlock(&send_cq->lock);
		spin_unlock_irq(&recv_cq->lock);
	}
}
1103
EXPORT_SYMBOL_GPL(hns_roce_unlock_cqs);
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114

static void *get_wqe(struct hns_roce_qp *hr_qp, int offset)
{

	return hns_roce_buf_offset(&hr_qp->hr_buf, offset);
}

void *get_recv_wqe(struct hns_roce_qp *hr_qp, int n)
{
	return get_wqe(hr_qp, hr_qp->rq.offset + (n << hr_qp->rq.wqe_shift));
}
1115
EXPORT_SYMBOL_GPL(get_recv_wqe);
1116 1117 1118 1119 1120

void *get_send_wqe(struct hns_roce_qp *hr_qp, int n)
{
	return get_wqe(hr_qp, hr_qp->sq.offset + (n << hr_qp->sq.wqe_shift));
}
1121
EXPORT_SYMBOL_GPL(get_send_wqe);
1122

1123 1124 1125 1126 1127 1128 1129
void *get_send_extend_sge(struct hns_roce_qp *hr_qp, int n)
{
	return hns_roce_buf_offset(&hr_qp->hr_buf, hr_qp->sge.offset +
					(n << hr_qp->sge.sge_shift));
}
EXPORT_SYMBOL_GPL(get_send_extend_sge);

1130 1131 1132 1133 1134 1135 1136 1137
bool hns_roce_wq_overflow(struct hns_roce_wq *hr_wq, int nreq,
			  struct ib_cq *ib_cq)
{
	struct hns_roce_cq *hr_cq;
	u32 cur;

	cur = hr_wq->head - hr_wq->tail;
	if (likely(cur + nreq < hr_wq->max_post))
1138
		return false;
1139 1140 1141 1142 1143 1144 1145 1146

	hr_cq = to_hr_cq(ib_cq);
	spin_lock(&hr_cq->lock);
	cur = hr_wq->head - hr_wq->tail;
	spin_unlock(&hr_cq->lock);

	return cur + nreq >= hr_wq->max_post;
}
1147
EXPORT_SYMBOL_GPL(hns_roce_wq_overflow);
1148 1149 1150 1151 1152

int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev)
{
	struct hns_roce_qp_table *qp_table = &hr_dev->qp_table;
	int reserved_from_top = 0;
L
Lijun Ou 已提交
1153
	int reserved_from_bot;
1154 1155
	int ret;

1156
	mutex_init(&qp_table->scc_mutex);
1157 1158 1159
	spin_lock_init(&qp_table->lock);
	INIT_RADIX_TREE(&hr_dev->qp_table_tree, GFP_ATOMIC);

L
Lijun Ou 已提交
1160 1161 1162 1163 1164 1165
	/* In hw v1, a port include two SQP, six ports total 12 */
	if (hr_dev->caps.max_sq_sg <= 2)
		reserved_from_bot = SQP_NUM;
	else
		reserved_from_bot = hr_dev->caps.reserved_qps;

1166
	ret = hns_roce_bitmap_init(&qp_table->bitmap, hr_dev->caps.num_qps,
L
Lijun Ou 已提交
1167
				   hr_dev->caps.num_qps - 1, reserved_from_bot,
1168 1169
				   reserved_from_top);
	if (ret) {
1170
		dev_err(hr_dev->dev, "qp bitmap init failed!error=%d\n",
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
			ret);
		return ret;
	}

	return 0;
}

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