162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
462306a36Sopenharmony_ci * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
862306a36Sopenharmony_ci#include <net/addrconf.h>
962306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "rxe.h"
1262306a36Sopenharmony_ci#include "rxe_queue.h"
1362306a36Sopenharmony_ci#include "rxe_hw_counters.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr);
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* dev */
1862306a36Sopenharmony_cistatic int rxe_query_device(struct ib_device *ibdev,
1962306a36Sopenharmony_ci			    struct ib_device_attr *attr,
2062306a36Sopenharmony_ci			    struct ib_udata *udata)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibdev);
2362306a36Sopenharmony_ci	int err;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	if (udata->inlen || udata->outlen) {
2662306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "malformed udata");
2762306a36Sopenharmony_ci		err = -EINVAL;
2862306a36Sopenharmony_ci		goto err_out;
2962306a36Sopenharmony_ci	}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	memcpy(attr, &rxe->attr, sizeof(*attr));
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	return 0;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cierr_out:
3662306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
3762306a36Sopenharmony_ci	return err;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic int rxe_query_port(struct ib_device *ibdev,
4162306a36Sopenharmony_ci			  u32 port_num, struct ib_port_attr *attr)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibdev);
4462306a36Sopenharmony_ci	int err, ret;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (port_num != 1) {
4762306a36Sopenharmony_ci		err = -EINVAL;
4862306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "bad port_num = %d", port_num);
4962306a36Sopenharmony_ci		goto err_out;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	memcpy(attr, &rxe->port.attr, sizeof(*attr));
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	mutex_lock(&rxe->usdev_lock);
5562306a36Sopenharmony_ci	ret = ib_get_eth_speed(ibdev, port_num, &attr->active_speed,
5662306a36Sopenharmony_ci			       &attr->active_width);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (attr->state == IB_PORT_ACTIVE)
5962306a36Sopenharmony_ci		attr->phys_state = IB_PORT_PHYS_STATE_LINK_UP;
6062306a36Sopenharmony_ci	else if (dev_get_flags(rxe->ndev) & IFF_UP)
6162306a36Sopenharmony_ci		attr->phys_state = IB_PORT_PHYS_STATE_POLLING;
6262306a36Sopenharmony_ci	else
6362306a36Sopenharmony_ci		attr->phys_state = IB_PORT_PHYS_STATE_DISABLED;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	mutex_unlock(&rxe->usdev_lock);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	return ret;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cierr_out:
7062306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
7162306a36Sopenharmony_ci	return err;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int rxe_query_pkey(struct ib_device *ibdev,
7562306a36Sopenharmony_ci			  u32 port_num, u16 index, u16 *pkey)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibdev);
7862306a36Sopenharmony_ci	int err;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	if (index != 0) {
8162306a36Sopenharmony_ci		err = -EINVAL;
8262306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "bad pkey index = %d", index);
8362306a36Sopenharmony_ci		goto err_out;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	*pkey = IB_DEFAULT_PKEY_FULL;
8762306a36Sopenharmony_ci	return 0;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cierr_out:
9062306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
9162306a36Sopenharmony_ci	return err;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int rxe_modify_device(struct ib_device *ibdev,
9562306a36Sopenharmony_ci			     int mask, struct ib_device_modify *attr)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibdev);
9862306a36Sopenharmony_ci	int err;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID |
10162306a36Sopenharmony_ci		     IB_DEVICE_MODIFY_NODE_DESC)) {
10262306a36Sopenharmony_ci		err = -EOPNOTSUPP;
10362306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "unsupported mask = 0x%x", mask);
10462306a36Sopenharmony_ci		goto err_out;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID)
10862306a36Sopenharmony_ci		rxe->attr.sys_image_guid = cpu_to_be64(attr->sys_image_guid);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
11162306a36Sopenharmony_ci		memcpy(rxe->ib_dev.node_desc,
11262306a36Sopenharmony_ci		       attr->node_desc, sizeof(rxe->ib_dev.node_desc));
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	return 0;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cierr_out:
11862306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
11962306a36Sopenharmony_ci	return err;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int rxe_modify_port(struct ib_device *ibdev, u32 port_num,
12362306a36Sopenharmony_ci			   int mask, struct ib_port_modify *attr)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibdev);
12662306a36Sopenharmony_ci	struct rxe_port *port;
12762306a36Sopenharmony_ci	int err;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (port_num != 1) {
13062306a36Sopenharmony_ci		err = -EINVAL;
13162306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "bad port_num = %d", port_num);
13262306a36Sopenharmony_ci		goto err_out;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	//TODO is shutdown useful
13662306a36Sopenharmony_ci	if (mask & ~(IB_PORT_RESET_QKEY_CNTR)) {
13762306a36Sopenharmony_ci		err = -EOPNOTSUPP;
13862306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "unsupported mask = 0x%x", mask);
13962306a36Sopenharmony_ci		goto err_out;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	port = &rxe->port;
14362306a36Sopenharmony_ci	port->attr.port_cap_flags |= attr->set_port_cap_mask;
14462306a36Sopenharmony_ci	port->attr.port_cap_flags &= ~attr->clr_port_cap_mask;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (mask & IB_PORT_RESET_QKEY_CNTR)
14762306a36Sopenharmony_ci		port->attr.qkey_viol_cntr = 0;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return 0;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cierr_out:
15262306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
15362306a36Sopenharmony_ci	return err;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic enum rdma_link_layer rxe_get_link_layer(struct ib_device *ibdev,
15762306a36Sopenharmony_ci					       u32 port_num)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibdev);
16062306a36Sopenharmony_ci	int err;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (port_num != 1) {
16362306a36Sopenharmony_ci		err = -EINVAL;
16462306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "bad port_num = %d", port_num);
16562306a36Sopenharmony_ci		goto err_out;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	return IB_LINK_LAYER_ETHERNET;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cierr_out:
17162306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
17262306a36Sopenharmony_ci	return err;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic int rxe_port_immutable(struct ib_device *ibdev, u32 port_num,
17662306a36Sopenharmony_ci			      struct ib_port_immutable *immutable)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibdev);
17962306a36Sopenharmony_ci	struct ib_port_attr attr = {};
18062306a36Sopenharmony_ci	int err;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (port_num != 1) {
18362306a36Sopenharmony_ci		err = -EINVAL;
18462306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "bad port_num = %d", port_num);
18562306a36Sopenharmony_ci		goto err_out;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	err = ib_query_port(ibdev, port_num, &attr);
18962306a36Sopenharmony_ci	if (err)
19062306a36Sopenharmony_ci		goto err_out;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP;
19362306a36Sopenharmony_ci	immutable->pkey_tbl_len = attr.pkey_tbl_len;
19462306a36Sopenharmony_ci	immutable->gid_tbl_len = attr.gid_tbl_len;
19562306a36Sopenharmony_ci	immutable->max_mad_size = IB_MGMT_MAD_SIZE;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return 0;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cierr_out:
20062306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
20162306a36Sopenharmony_ci	return err;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/* uc */
20562306a36Sopenharmony_cistatic int rxe_alloc_ucontext(struct ib_ucontext *ibuc, struct ib_udata *udata)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibuc->device);
20862306a36Sopenharmony_ci	struct rxe_ucontext *uc = to_ruc(ibuc);
20962306a36Sopenharmony_ci	int err;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	err = rxe_add_to_pool(&rxe->uc_pool, uc);
21262306a36Sopenharmony_ci	if (err)
21362306a36Sopenharmony_ci		rxe_err_dev(rxe, "unable to create uc");
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return err;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic void rxe_dealloc_ucontext(struct ib_ucontext *ibuc)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct rxe_ucontext *uc = to_ruc(ibuc);
22162306a36Sopenharmony_ci	int err;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	err = rxe_cleanup(uc);
22462306a36Sopenharmony_ci	if (err)
22562306a36Sopenharmony_ci		rxe_err_uc(uc, "cleanup failed, err = %d", err);
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/* pd */
22962306a36Sopenharmony_cistatic int rxe_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibpd->device);
23262306a36Sopenharmony_ci	struct rxe_pd *pd = to_rpd(ibpd);
23362306a36Sopenharmony_ci	int err;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	err = rxe_add_to_pool(&rxe->pd_pool, pd);
23662306a36Sopenharmony_ci	if (err) {
23762306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "unable to alloc pd");
23862306a36Sopenharmony_ci		goto err_out;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return 0;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cierr_out:
24462306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
24562306a36Sopenharmony_ci	return err;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int rxe_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct rxe_pd *pd = to_rpd(ibpd);
25162306a36Sopenharmony_ci	int err;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	err = rxe_cleanup(pd);
25462306a36Sopenharmony_ci	if (err)
25562306a36Sopenharmony_ci		rxe_err_pd(pd, "cleanup failed, err = %d", err);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return 0;
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci/* ah */
26162306a36Sopenharmony_cistatic int rxe_create_ah(struct ib_ah *ibah,
26262306a36Sopenharmony_ci			 struct rdma_ah_init_attr *init_attr,
26362306a36Sopenharmony_ci			 struct ib_udata *udata)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibah->device);
26662306a36Sopenharmony_ci	struct rxe_ah *ah = to_rah(ibah);
26762306a36Sopenharmony_ci	struct rxe_create_ah_resp __user *uresp = NULL;
26862306a36Sopenharmony_ci	int err, cleanup_err;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (udata) {
27162306a36Sopenharmony_ci		/* test if new user provider */
27262306a36Sopenharmony_ci		if (udata->outlen >= sizeof(*uresp))
27362306a36Sopenharmony_ci			uresp = udata->outbuf;
27462306a36Sopenharmony_ci		ah->is_user = true;
27562306a36Sopenharmony_ci	} else {
27662306a36Sopenharmony_ci		ah->is_user = false;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	err = rxe_add_to_pool_ah(&rxe->ah_pool, ah,
28062306a36Sopenharmony_ci			init_attr->flags & RDMA_CREATE_AH_SLEEPABLE);
28162306a36Sopenharmony_ci	if (err) {
28262306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "unable to create ah");
28362306a36Sopenharmony_ci		goto err_out;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* create index > 0 */
28762306a36Sopenharmony_ci	ah->ah_num = ah->elem.index;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	err = rxe_ah_chk_attr(ah, init_attr->ah_attr);
29062306a36Sopenharmony_ci	if (err) {
29162306a36Sopenharmony_ci		rxe_dbg_ah(ah, "bad attr");
29262306a36Sopenharmony_ci		goto err_cleanup;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (uresp) {
29662306a36Sopenharmony_ci		/* only if new user provider */
29762306a36Sopenharmony_ci		err = copy_to_user(&uresp->ah_num, &ah->ah_num,
29862306a36Sopenharmony_ci					 sizeof(uresp->ah_num));
29962306a36Sopenharmony_ci		if (err) {
30062306a36Sopenharmony_ci			err = -EFAULT;
30162306a36Sopenharmony_ci			rxe_dbg_ah(ah, "unable to copy to user");
30262306a36Sopenharmony_ci			goto err_cleanup;
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci	} else if (ah->is_user) {
30562306a36Sopenharmony_ci		/* only if old user provider */
30662306a36Sopenharmony_ci		ah->ah_num = 0;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	rxe_init_av(init_attr->ah_attr, &ah->av);
31062306a36Sopenharmony_ci	rxe_finalize(ah);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	return 0;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cierr_cleanup:
31562306a36Sopenharmony_ci	cleanup_err = rxe_cleanup(ah);
31662306a36Sopenharmony_ci	if (cleanup_err)
31762306a36Sopenharmony_ci		rxe_err_ah(ah, "cleanup failed, err = %d", cleanup_err);
31862306a36Sopenharmony_cierr_out:
31962306a36Sopenharmony_ci	rxe_err_ah(ah, "returned err = %d", err);
32062306a36Sopenharmony_ci	return err;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int rxe_modify_ah(struct ib_ah *ibah, struct rdma_ah_attr *attr)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct rxe_ah *ah = to_rah(ibah);
32662306a36Sopenharmony_ci	int err;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	err = rxe_ah_chk_attr(ah, attr);
32962306a36Sopenharmony_ci	if (err) {
33062306a36Sopenharmony_ci		rxe_dbg_ah(ah, "bad attr");
33162306a36Sopenharmony_ci		goto err_out;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	rxe_init_av(attr, &ah->av);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	return 0;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cierr_out:
33962306a36Sopenharmony_ci	rxe_err_ah(ah, "returned err = %d", err);
34062306a36Sopenharmony_ci	return err;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic int rxe_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *attr)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	struct rxe_ah *ah = to_rah(ibah);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	memset(attr, 0, sizeof(*attr));
34862306a36Sopenharmony_ci	attr->type = ibah->type;
34962306a36Sopenharmony_ci	rxe_av_to_attr(&ah->av, attr);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return 0;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic int rxe_destroy_ah(struct ib_ah *ibah, u32 flags)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	struct rxe_ah *ah = to_rah(ibah);
35762306a36Sopenharmony_ci	int err;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	err = rxe_cleanup_ah(ah, flags & RDMA_DESTROY_AH_SLEEPABLE);
36062306a36Sopenharmony_ci	if (err)
36162306a36Sopenharmony_ci		rxe_err_ah(ah, "cleanup failed, err = %d", err);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return 0;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci/* srq */
36762306a36Sopenharmony_cistatic int rxe_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *init,
36862306a36Sopenharmony_ci			  struct ib_udata *udata)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibsrq->device);
37162306a36Sopenharmony_ci	struct rxe_pd *pd = to_rpd(ibsrq->pd);
37262306a36Sopenharmony_ci	struct rxe_srq *srq = to_rsrq(ibsrq);
37362306a36Sopenharmony_ci	struct rxe_create_srq_resp __user *uresp = NULL;
37462306a36Sopenharmony_ci	int err, cleanup_err;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (udata) {
37762306a36Sopenharmony_ci		if (udata->outlen < sizeof(*uresp)) {
37862306a36Sopenharmony_ci			err = -EINVAL;
37962306a36Sopenharmony_ci			rxe_err_dev(rxe, "malformed udata");
38062306a36Sopenharmony_ci			goto err_out;
38162306a36Sopenharmony_ci		}
38262306a36Sopenharmony_ci		uresp = udata->outbuf;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (init->srq_type != IB_SRQT_BASIC) {
38662306a36Sopenharmony_ci		err = -EOPNOTSUPP;
38762306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "srq type = %d, not supported",
38862306a36Sopenharmony_ci				init->srq_type);
38962306a36Sopenharmony_ci		goto err_out;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	err = rxe_srq_chk_init(rxe, init);
39362306a36Sopenharmony_ci	if (err) {
39462306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "invalid init attributes");
39562306a36Sopenharmony_ci		goto err_out;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	err = rxe_add_to_pool(&rxe->srq_pool, srq);
39962306a36Sopenharmony_ci	if (err) {
40062306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "unable to create srq, err = %d", err);
40162306a36Sopenharmony_ci		goto err_out;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	rxe_get(pd);
40562306a36Sopenharmony_ci	srq->pd = pd;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	err = rxe_srq_from_init(rxe, srq, init, udata, uresp);
40862306a36Sopenharmony_ci	if (err) {
40962306a36Sopenharmony_ci		rxe_dbg_srq(srq, "create srq failed, err = %d", err);
41062306a36Sopenharmony_ci		goto err_cleanup;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return 0;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cierr_cleanup:
41662306a36Sopenharmony_ci	cleanup_err = rxe_cleanup(srq);
41762306a36Sopenharmony_ci	if (cleanup_err)
41862306a36Sopenharmony_ci		rxe_err_srq(srq, "cleanup failed, err = %d", cleanup_err);
41962306a36Sopenharmony_cierr_out:
42062306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
42162306a36Sopenharmony_ci	return err;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic int rxe_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
42562306a36Sopenharmony_ci			  enum ib_srq_attr_mask mask,
42662306a36Sopenharmony_ci			  struct ib_udata *udata)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	struct rxe_srq *srq = to_rsrq(ibsrq);
42962306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibsrq->device);
43062306a36Sopenharmony_ci	struct rxe_modify_srq_cmd cmd = {};
43162306a36Sopenharmony_ci	int err;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	if (udata) {
43462306a36Sopenharmony_ci		if (udata->inlen < sizeof(cmd)) {
43562306a36Sopenharmony_ci			err = -EINVAL;
43662306a36Sopenharmony_ci			rxe_dbg_srq(srq, "malformed udata");
43762306a36Sopenharmony_ci			goto err_out;
43862306a36Sopenharmony_ci		}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci		err = ib_copy_from_udata(&cmd, udata, sizeof(cmd));
44162306a36Sopenharmony_ci		if (err) {
44262306a36Sopenharmony_ci			err = -EFAULT;
44362306a36Sopenharmony_ci			rxe_dbg_srq(srq, "unable to read udata");
44462306a36Sopenharmony_ci			goto err_out;
44562306a36Sopenharmony_ci		}
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	err = rxe_srq_chk_attr(rxe, srq, attr, mask);
44962306a36Sopenharmony_ci	if (err) {
45062306a36Sopenharmony_ci		rxe_dbg_srq(srq, "bad init attributes");
45162306a36Sopenharmony_ci		goto err_out;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	err = rxe_srq_from_attr(rxe, srq, attr, mask, &cmd, udata);
45562306a36Sopenharmony_ci	if (err) {
45662306a36Sopenharmony_ci		rxe_dbg_srq(srq, "bad attr");
45762306a36Sopenharmony_ci		goto err_out;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	return 0;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cierr_out:
46362306a36Sopenharmony_ci	rxe_err_srq(srq, "returned err = %d", err);
46462306a36Sopenharmony_ci	return err;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic int rxe_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct rxe_srq *srq = to_rsrq(ibsrq);
47062306a36Sopenharmony_ci	int err;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (srq->error) {
47362306a36Sopenharmony_ci		err = -EINVAL;
47462306a36Sopenharmony_ci		rxe_dbg_srq(srq, "srq in error state");
47562306a36Sopenharmony_ci		goto err_out;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	attr->max_wr = srq->rq.queue->buf->index_mask;
47962306a36Sopenharmony_ci	attr->max_sge = srq->rq.max_sge;
48062306a36Sopenharmony_ci	attr->srq_limit = srq->limit;
48162306a36Sopenharmony_ci	return 0;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cierr_out:
48462306a36Sopenharmony_ci	rxe_err_srq(srq, "returned err = %d", err);
48562306a36Sopenharmony_ci	return err;
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic int rxe_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
48962306a36Sopenharmony_ci			     const struct ib_recv_wr **bad_wr)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	int err = 0;
49262306a36Sopenharmony_ci	struct rxe_srq *srq = to_rsrq(ibsrq);
49362306a36Sopenharmony_ci	unsigned long flags;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	spin_lock_irqsave(&srq->rq.producer_lock, flags);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	while (wr) {
49862306a36Sopenharmony_ci		err = post_one_recv(&srq->rq, wr);
49962306a36Sopenharmony_ci		if (unlikely(err))
50062306a36Sopenharmony_ci			break;
50162306a36Sopenharmony_ci		wr = wr->next;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	spin_unlock_irqrestore(&srq->rq.producer_lock, flags);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	if (err) {
50762306a36Sopenharmony_ci		*bad_wr = wr;
50862306a36Sopenharmony_ci		rxe_err_srq(srq, "returned err = %d", err);
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	return err;
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic int rxe_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct rxe_srq *srq = to_rsrq(ibsrq);
51762306a36Sopenharmony_ci	int err;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	err = rxe_cleanup(srq);
52062306a36Sopenharmony_ci	if (err)
52162306a36Sopenharmony_ci		rxe_err_srq(srq, "cleanup failed, err = %d", err);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	return 0;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci/* qp */
52762306a36Sopenharmony_cistatic int rxe_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init,
52862306a36Sopenharmony_ci			 struct ib_udata *udata)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibqp->device);
53162306a36Sopenharmony_ci	struct rxe_pd *pd = to_rpd(ibqp->pd);
53262306a36Sopenharmony_ci	struct rxe_qp *qp = to_rqp(ibqp);
53362306a36Sopenharmony_ci	struct rxe_create_qp_resp __user *uresp = NULL;
53462306a36Sopenharmony_ci	int err, cleanup_err;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (udata) {
53762306a36Sopenharmony_ci		if (udata->inlen) {
53862306a36Sopenharmony_ci			err = -EINVAL;
53962306a36Sopenharmony_ci			rxe_dbg_dev(rxe, "malformed udata, err = %d", err);
54062306a36Sopenharmony_ci			goto err_out;
54162306a36Sopenharmony_ci		}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		if (udata->outlen < sizeof(*uresp)) {
54462306a36Sopenharmony_ci			err = -EINVAL;
54562306a36Sopenharmony_ci			rxe_dbg_dev(rxe, "malformed udata, err = %d", err);
54662306a36Sopenharmony_ci			goto err_out;
54762306a36Sopenharmony_ci		}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		qp->is_user = true;
55062306a36Sopenharmony_ci		uresp = udata->outbuf;
55162306a36Sopenharmony_ci	} else {
55262306a36Sopenharmony_ci		qp->is_user = false;
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (init->create_flags) {
55662306a36Sopenharmony_ci		err = -EOPNOTSUPP;
55762306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "unsupported create_flags, err = %d", err);
55862306a36Sopenharmony_ci		goto err_out;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	err = rxe_qp_chk_init(rxe, init);
56262306a36Sopenharmony_ci	if (err) {
56362306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "bad init attr, err = %d", err);
56462306a36Sopenharmony_ci		goto err_out;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	err = rxe_add_to_pool(&rxe->qp_pool, qp);
56862306a36Sopenharmony_ci	if (err) {
56962306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "unable to create qp, err = %d", err);
57062306a36Sopenharmony_ci		goto err_out;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	err = rxe_qp_from_init(rxe, qp, pd, init, uresp, ibqp->pd, udata);
57462306a36Sopenharmony_ci	if (err) {
57562306a36Sopenharmony_ci		rxe_dbg_qp(qp, "create qp failed, err = %d", err);
57662306a36Sopenharmony_ci		goto err_cleanup;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	rxe_finalize(qp);
58062306a36Sopenharmony_ci	return 0;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cierr_cleanup:
58362306a36Sopenharmony_ci	cleanup_err = rxe_cleanup(qp);
58462306a36Sopenharmony_ci	if (cleanup_err)
58562306a36Sopenharmony_ci		rxe_err_qp(qp, "cleanup failed, err = %d", cleanup_err);
58662306a36Sopenharmony_cierr_out:
58762306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
58862306a36Sopenharmony_ci	return err;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic int rxe_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
59262306a36Sopenharmony_ci			 int mask, struct ib_udata *udata)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibqp->device);
59562306a36Sopenharmony_ci	struct rxe_qp *qp = to_rqp(ibqp);
59662306a36Sopenharmony_ci	int err;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (mask & ~IB_QP_ATTR_STANDARD_BITS) {
59962306a36Sopenharmony_ci		err = -EOPNOTSUPP;
60062306a36Sopenharmony_ci		rxe_dbg_qp(qp, "unsupported mask = 0x%x, err = %d",
60162306a36Sopenharmony_ci			   mask, err);
60262306a36Sopenharmony_ci		goto err_out;
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	err = rxe_qp_chk_attr(rxe, qp, attr, mask);
60662306a36Sopenharmony_ci	if (err) {
60762306a36Sopenharmony_ci		rxe_dbg_qp(qp, "bad mask/attr, err = %d", err);
60862306a36Sopenharmony_ci		goto err_out;
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	err = rxe_qp_from_attr(qp, attr, mask, udata);
61262306a36Sopenharmony_ci	if (err) {
61362306a36Sopenharmony_ci		rxe_dbg_qp(qp, "modify qp failed, err = %d", err);
61462306a36Sopenharmony_ci		goto err_out;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if ((mask & IB_QP_AV) && (attr->ah_attr.ah_flags & IB_AH_GRH))
61862306a36Sopenharmony_ci		qp->src_port = rdma_get_udp_sport(attr->ah_attr.grh.flow_label,
61962306a36Sopenharmony_ci						  qp->ibqp.qp_num,
62062306a36Sopenharmony_ci						  qp->attr.dest_qp_num);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	return 0;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cierr_out:
62562306a36Sopenharmony_ci	rxe_err_qp(qp, "returned err = %d", err);
62662306a36Sopenharmony_ci	return err;
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cistatic int rxe_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
63062306a36Sopenharmony_ci			int mask, struct ib_qp_init_attr *init)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	struct rxe_qp *qp = to_rqp(ibqp);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	rxe_qp_to_init(qp, init);
63562306a36Sopenharmony_ci	rxe_qp_to_attr(qp, attr, mask);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	return 0;
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic int rxe_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	struct rxe_qp *qp = to_rqp(ibqp);
64362306a36Sopenharmony_ci	int err;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	err = rxe_qp_chk_destroy(qp);
64662306a36Sopenharmony_ci	if (err) {
64762306a36Sopenharmony_ci		rxe_dbg_qp(qp, "unable to destroy qp, err = %d", err);
64862306a36Sopenharmony_ci		goto err_out;
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	err = rxe_cleanup(qp);
65262306a36Sopenharmony_ci	if (err)
65362306a36Sopenharmony_ci		rxe_err_qp(qp, "cleanup failed, err = %d", err);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	return 0;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cierr_out:
65862306a36Sopenharmony_ci	rxe_err_qp(qp, "returned err = %d", err);
65962306a36Sopenharmony_ci	return err;
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci/* send wr */
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/* sanity check incoming send work request */
66562306a36Sopenharmony_cistatic int validate_send_wr(struct rxe_qp *qp, const struct ib_send_wr *ibwr,
66662306a36Sopenharmony_ci			    unsigned int *maskp, unsigned int *lengthp)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	int num_sge = ibwr->num_sge;
66962306a36Sopenharmony_ci	struct rxe_sq *sq = &qp->sq;
67062306a36Sopenharmony_ci	unsigned int mask = 0;
67162306a36Sopenharmony_ci	unsigned long length = 0;
67262306a36Sopenharmony_ci	int err = -EINVAL;
67362306a36Sopenharmony_ci	int i;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	do {
67662306a36Sopenharmony_ci		mask = wr_opcode_mask(ibwr->opcode, qp);
67762306a36Sopenharmony_ci		if (!mask) {
67862306a36Sopenharmony_ci			rxe_err_qp(qp, "bad wr opcode for qp type");
67962306a36Sopenharmony_ci			break;
68062306a36Sopenharmony_ci		}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		if (num_sge > sq->max_sge) {
68362306a36Sopenharmony_ci			rxe_err_qp(qp, "num_sge > max_sge");
68462306a36Sopenharmony_ci			break;
68562306a36Sopenharmony_ci		}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci		length = 0;
68862306a36Sopenharmony_ci		for (i = 0; i < ibwr->num_sge; i++)
68962306a36Sopenharmony_ci			length += ibwr->sg_list[i].length;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci		if (length > (1UL << 31)) {
69262306a36Sopenharmony_ci			rxe_err_qp(qp, "message length too long");
69362306a36Sopenharmony_ci			break;
69462306a36Sopenharmony_ci		}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		if (mask & WR_ATOMIC_MASK) {
69762306a36Sopenharmony_ci			if (length != 8) {
69862306a36Sopenharmony_ci				rxe_err_qp(qp, "atomic length != 8");
69962306a36Sopenharmony_ci				break;
70062306a36Sopenharmony_ci			}
70162306a36Sopenharmony_ci			if (atomic_wr(ibwr)->remote_addr & 0x7) {
70262306a36Sopenharmony_ci				rxe_err_qp(qp, "misaligned atomic address");
70362306a36Sopenharmony_ci				break;
70462306a36Sopenharmony_ci			}
70562306a36Sopenharmony_ci		}
70662306a36Sopenharmony_ci		if (ibwr->send_flags & IB_SEND_INLINE) {
70762306a36Sopenharmony_ci			if (!(mask & WR_INLINE_MASK)) {
70862306a36Sopenharmony_ci				rxe_err_qp(qp, "opcode doesn't support inline data");
70962306a36Sopenharmony_ci				break;
71062306a36Sopenharmony_ci			}
71162306a36Sopenharmony_ci			if (length > sq->max_inline) {
71262306a36Sopenharmony_ci				rxe_err_qp(qp, "inline length too big");
71362306a36Sopenharmony_ci				break;
71462306a36Sopenharmony_ci			}
71562306a36Sopenharmony_ci		}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		err = 0;
71862306a36Sopenharmony_ci	} while (0);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	*maskp = mask;
72162306a36Sopenharmony_ci	*lengthp = (int)length;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	return err;
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cistatic int init_send_wr(struct rxe_qp *qp, struct rxe_send_wr *wr,
72762306a36Sopenharmony_ci			 const struct ib_send_wr *ibwr)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	wr->wr_id = ibwr->wr_id;
73062306a36Sopenharmony_ci	wr->opcode = ibwr->opcode;
73162306a36Sopenharmony_ci	wr->send_flags = ibwr->send_flags;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	if (qp_type(qp) == IB_QPT_UD ||
73462306a36Sopenharmony_ci	    qp_type(qp) == IB_QPT_GSI) {
73562306a36Sopenharmony_ci		struct ib_ah *ibah = ud_wr(ibwr)->ah;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci		wr->wr.ud.remote_qpn = ud_wr(ibwr)->remote_qpn;
73862306a36Sopenharmony_ci		wr->wr.ud.remote_qkey = ud_wr(ibwr)->remote_qkey;
73962306a36Sopenharmony_ci		wr->wr.ud.ah_num = to_rah(ibah)->ah_num;
74062306a36Sopenharmony_ci		if (qp_type(qp) == IB_QPT_GSI)
74162306a36Sopenharmony_ci			wr->wr.ud.pkey_index = ud_wr(ibwr)->pkey_index;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci		switch (wr->opcode) {
74462306a36Sopenharmony_ci		case IB_WR_SEND_WITH_IMM:
74562306a36Sopenharmony_ci			wr->ex.imm_data = ibwr->ex.imm_data;
74662306a36Sopenharmony_ci			break;
74762306a36Sopenharmony_ci		case IB_WR_SEND:
74862306a36Sopenharmony_ci			break;
74962306a36Sopenharmony_ci		default:
75062306a36Sopenharmony_ci			rxe_err_qp(qp, "bad wr opcode %d for UD/GSI QP",
75162306a36Sopenharmony_ci					wr->opcode);
75262306a36Sopenharmony_ci			return -EINVAL;
75362306a36Sopenharmony_ci		}
75462306a36Sopenharmony_ci	} else {
75562306a36Sopenharmony_ci		switch (wr->opcode) {
75662306a36Sopenharmony_ci		case IB_WR_RDMA_WRITE_WITH_IMM:
75762306a36Sopenharmony_ci			wr->ex.imm_data = ibwr->ex.imm_data;
75862306a36Sopenharmony_ci			fallthrough;
75962306a36Sopenharmony_ci		case IB_WR_RDMA_READ:
76062306a36Sopenharmony_ci		case IB_WR_RDMA_WRITE:
76162306a36Sopenharmony_ci			wr->wr.rdma.remote_addr = rdma_wr(ibwr)->remote_addr;
76262306a36Sopenharmony_ci			wr->wr.rdma.rkey	= rdma_wr(ibwr)->rkey;
76362306a36Sopenharmony_ci			break;
76462306a36Sopenharmony_ci		case IB_WR_SEND_WITH_IMM:
76562306a36Sopenharmony_ci			wr->ex.imm_data = ibwr->ex.imm_data;
76662306a36Sopenharmony_ci			break;
76762306a36Sopenharmony_ci		case IB_WR_SEND_WITH_INV:
76862306a36Sopenharmony_ci			wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey;
76962306a36Sopenharmony_ci			break;
77062306a36Sopenharmony_ci		case IB_WR_RDMA_READ_WITH_INV:
77162306a36Sopenharmony_ci			wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey;
77262306a36Sopenharmony_ci			wr->wr.rdma.remote_addr = rdma_wr(ibwr)->remote_addr;
77362306a36Sopenharmony_ci			wr->wr.rdma.rkey	= rdma_wr(ibwr)->rkey;
77462306a36Sopenharmony_ci			break;
77562306a36Sopenharmony_ci		case IB_WR_ATOMIC_CMP_AND_SWP:
77662306a36Sopenharmony_ci		case IB_WR_ATOMIC_FETCH_AND_ADD:
77762306a36Sopenharmony_ci			wr->wr.atomic.remote_addr =
77862306a36Sopenharmony_ci				atomic_wr(ibwr)->remote_addr;
77962306a36Sopenharmony_ci			wr->wr.atomic.compare_add =
78062306a36Sopenharmony_ci				atomic_wr(ibwr)->compare_add;
78162306a36Sopenharmony_ci			wr->wr.atomic.swap = atomic_wr(ibwr)->swap;
78262306a36Sopenharmony_ci			wr->wr.atomic.rkey = atomic_wr(ibwr)->rkey;
78362306a36Sopenharmony_ci			break;
78462306a36Sopenharmony_ci		case IB_WR_LOCAL_INV:
78562306a36Sopenharmony_ci			wr->ex.invalidate_rkey = ibwr->ex.invalidate_rkey;
78662306a36Sopenharmony_ci			break;
78762306a36Sopenharmony_ci		case IB_WR_REG_MR:
78862306a36Sopenharmony_ci			wr->wr.reg.mr = reg_wr(ibwr)->mr;
78962306a36Sopenharmony_ci			wr->wr.reg.key = reg_wr(ibwr)->key;
79062306a36Sopenharmony_ci			wr->wr.reg.access = reg_wr(ibwr)->access;
79162306a36Sopenharmony_ci			break;
79262306a36Sopenharmony_ci		case IB_WR_SEND:
79362306a36Sopenharmony_ci		case IB_WR_BIND_MW:
79462306a36Sopenharmony_ci		case IB_WR_FLUSH:
79562306a36Sopenharmony_ci		case IB_WR_ATOMIC_WRITE:
79662306a36Sopenharmony_ci			break;
79762306a36Sopenharmony_ci		default:
79862306a36Sopenharmony_ci			rxe_err_qp(qp, "unsupported wr opcode %d",
79962306a36Sopenharmony_ci					wr->opcode);
80062306a36Sopenharmony_ci			return -EINVAL;
80162306a36Sopenharmony_ci		}
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	return 0;
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic void copy_inline_data_to_wqe(struct rxe_send_wqe *wqe,
80862306a36Sopenharmony_ci				    const struct ib_send_wr *ibwr)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	struct ib_sge *sge = ibwr->sg_list;
81162306a36Sopenharmony_ci	u8 *p = wqe->dma.inline_data;
81262306a36Sopenharmony_ci	int i;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	for (i = 0; i < ibwr->num_sge; i++, sge++) {
81562306a36Sopenharmony_ci		memcpy(p, ib_virt_dma_to_page(sge->addr), sge->length);
81662306a36Sopenharmony_ci		p += sge->length;
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_cistatic int init_send_wqe(struct rxe_qp *qp, const struct ib_send_wr *ibwr,
82162306a36Sopenharmony_ci			 unsigned int mask, unsigned int length,
82262306a36Sopenharmony_ci			 struct rxe_send_wqe *wqe)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	int num_sge = ibwr->num_sge;
82562306a36Sopenharmony_ci	int err;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	err = init_send_wr(qp, &wqe->wr, ibwr);
82862306a36Sopenharmony_ci	if (err)
82962306a36Sopenharmony_ci		return err;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* local operation */
83262306a36Sopenharmony_ci	if (unlikely(mask & WR_LOCAL_OP_MASK)) {
83362306a36Sopenharmony_ci		wqe->mask = mask;
83462306a36Sopenharmony_ci		wqe->state = wqe_state_posted;
83562306a36Sopenharmony_ci		return 0;
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (unlikely(ibwr->send_flags & IB_SEND_INLINE))
83962306a36Sopenharmony_ci		copy_inline_data_to_wqe(wqe, ibwr);
84062306a36Sopenharmony_ci	else
84162306a36Sopenharmony_ci		memcpy(wqe->dma.sge, ibwr->sg_list,
84262306a36Sopenharmony_ci		       num_sge * sizeof(struct ib_sge));
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	wqe->iova = mask & WR_ATOMIC_MASK ? atomic_wr(ibwr)->remote_addr :
84562306a36Sopenharmony_ci		mask & WR_READ_OR_WRITE_MASK ? rdma_wr(ibwr)->remote_addr : 0;
84662306a36Sopenharmony_ci	wqe->mask		= mask;
84762306a36Sopenharmony_ci	wqe->dma.length		= length;
84862306a36Sopenharmony_ci	wqe->dma.resid		= length;
84962306a36Sopenharmony_ci	wqe->dma.num_sge	= num_sge;
85062306a36Sopenharmony_ci	wqe->dma.cur_sge	= 0;
85162306a36Sopenharmony_ci	wqe->dma.sge_offset	= 0;
85262306a36Sopenharmony_ci	wqe->state		= wqe_state_posted;
85362306a36Sopenharmony_ci	wqe->ssn		= atomic_add_return(1, &qp->ssn);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	return 0;
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic int post_one_send(struct rxe_qp *qp, const struct ib_send_wr *ibwr)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	int err;
86162306a36Sopenharmony_ci	struct rxe_sq *sq = &qp->sq;
86262306a36Sopenharmony_ci	struct rxe_send_wqe *send_wqe;
86362306a36Sopenharmony_ci	unsigned int mask;
86462306a36Sopenharmony_ci	unsigned int length;
86562306a36Sopenharmony_ci	int full;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	err = validate_send_wr(qp, ibwr, &mask, &length);
86862306a36Sopenharmony_ci	if (err)
86962306a36Sopenharmony_ci		return err;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	full = queue_full(sq->queue, QUEUE_TYPE_FROM_ULP);
87262306a36Sopenharmony_ci	if (unlikely(full)) {
87362306a36Sopenharmony_ci		rxe_err_qp(qp, "send queue full");
87462306a36Sopenharmony_ci		return -ENOMEM;
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	send_wqe = queue_producer_addr(sq->queue, QUEUE_TYPE_FROM_ULP);
87862306a36Sopenharmony_ci	err = init_send_wqe(qp, ibwr, mask, length, send_wqe);
87962306a36Sopenharmony_ci	if (!err)
88062306a36Sopenharmony_ci		queue_advance_producer(sq->queue, QUEUE_TYPE_FROM_ULP);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	return err;
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cistatic int rxe_post_send_kernel(struct rxe_qp *qp,
88662306a36Sopenharmony_ci				const struct ib_send_wr *ibwr,
88762306a36Sopenharmony_ci				const struct ib_send_wr **bad_wr)
88862306a36Sopenharmony_ci{
88962306a36Sopenharmony_ci	int err = 0;
89062306a36Sopenharmony_ci	unsigned long flags;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	spin_lock_irqsave(&qp->sq.sq_lock, flags);
89362306a36Sopenharmony_ci	while (ibwr) {
89462306a36Sopenharmony_ci		err = post_one_send(qp, ibwr);
89562306a36Sopenharmony_ci		if (err) {
89662306a36Sopenharmony_ci			*bad_wr = ibwr;
89762306a36Sopenharmony_ci			break;
89862306a36Sopenharmony_ci		}
89962306a36Sopenharmony_ci		ibwr = ibwr->next;
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->sq.sq_lock, flags);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	if (!err)
90462306a36Sopenharmony_ci		rxe_sched_task(&qp->req.task);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	spin_lock_irqsave(&qp->state_lock, flags);
90762306a36Sopenharmony_ci	if (qp_state(qp) == IB_QPS_ERR)
90862306a36Sopenharmony_ci		rxe_sched_task(&qp->comp.task);
90962306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->state_lock, flags);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	return err;
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic int rxe_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
91562306a36Sopenharmony_ci			 const struct ib_send_wr **bad_wr)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	struct rxe_qp *qp = to_rqp(ibqp);
91862306a36Sopenharmony_ci	int err;
91962306a36Sopenharmony_ci	unsigned long flags;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	spin_lock_irqsave(&qp->state_lock, flags);
92262306a36Sopenharmony_ci	/* caller has already called destroy_qp */
92362306a36Sopenharmony_ci	if (WARN_ON_ONCE(!qp->valid)) {
92462306a36Sopenharmony_ci		spin_unlock_irqrestore(&qp->state_lock, flags);
92562306a36Sopenharmony_ci		rxe_err_qp(qp, "qp has been destroyed");
92662306a36Sopenharmony_ci		return -EINVAL;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	if (unlikely(qp_state(qp) < IB_QPS_RTS)) {
93062306a36Sopenharmony_ci		spin_unlock_irqrestore(&qp->state_lock, flags);
93162306a36Sopenharmony_ci		*bad_wr = wr;
93262306a36Sopenharmony_ci		rxe_err_qp(qp, "qp not ready to send");
93362306a36Sopenharmony_ci		return -EINVAL;
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->state_lock, flags);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	if (qp->is_user) {
93862306a36Sopenharmony_ci		/* Utilize process context to do protocol processing */
93962306a36Sopenharmony_ci		rxe_run_task(&qp->req.task);
94062306a36Sopenharmony_ci	} else {
94162306a36Sopenharmony_ci		err = rxe_post_send_kernel(qp, wr, bad_wr);
94262306a36Sopenharmony_ci		if (err)
94362306a36Sopenharmony_ci			return err;
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	return 0;
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci/* recv wr */
95062306a36Sopenharmony_cistatic int post_one_recv(struct rxe_rq *rq, const struct ib_recv_wr *ibwr)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	int i;
95362306a36Sopenharmony_ci	unsigned long length;
95462306a36Sopenharmony_ci	struct rxe_recv_wqe *recv_wqe;
95562306a36Sopenharmony_ci	int num_sge = ibwr->num_sge;
95662306a36Sopenharmony_ci	int full;
95762306a36Sopenharmony_ci	int err;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	full = queue_full(rq->queue, QUEUE_TYPE_FROM_ULP);
96062306a36Sopenharmony_ci	if (unlikely(full)) {
96162306a36Sopenharmony_ci		err = -ENOMEM;
96262306a36Sopenharmony_ci		rxe_dbg("queue full");
96362306a36Sopenharmony_ci		goto err_out;
96462306a36Sopenharmony_ci	}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	if (unlikely(num_sge > rq->max_sge)) {
96762306a36Sopenharmony_ci		err = -EINVAL;
96862306a36Sopenharmony_ci		rxe_dbg("bad num_sge > max_sge");
96962306a36Sopenharmony_ci		goto err_out;
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	length = 0;
97362306a36Sopenharmony_ci	for (i = 0; i < num_sge; i++)
97462306a36Sopenharmony_ci		length += ibwr->sg_list[i].length;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	/* IBA max message size is 2^31 */
97762306a36Sopenharmony_ci	if (length >= (1UL<<31)) {
97862306a36Sopenharmony_ci		err = -EINVAL;
97962306a36Sopenharmony_ci		rxe_dbg("message length too long");
98062306a36Sopenharmony_ci		goto err_out;
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	recv_wqe = queue_producer_addr(rq->queue, QUEUE_TYPE_FROM_ULP);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	recv_wqe->wr_id = ibwr->wr_id;
98662306a36Sopenharmony_ci	recv_wqe->dma.length = length;
98762306a36Sopenharmony_ci	recv_wqe->dma.resid = length;
98862306a36Sopenharmony_ci	recv_wqe->dma.num_sge = num_sge;
98962306a36Sopenharmony_ci	recv_wqe->dma.cur_sge = 0;
99062306a36Sopenharmony_ci	recv_wqe->dma.sge_offset = 0;
99162306a36Sopenharmony_ci	memcpy(recv_wqe->dma.sge, ibwr->sg_list,
99262306a36Sopenharmony_ci	       num_sge * sizeof(struct ib_sge));
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	queue_advance_producer(rq->queue, QUEUE_TYPE_FROM_ULP);
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	return 0;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cierr_out:
99962306a36Sopenharmony_ci	rxe_dbg("returned err = %d", err);
100062306a36Sopenharmony_ci	return err;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic int rxe_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
100462306a36Sopenharmony_ci			 const struct ib_recv_wr **bad_wr)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	int err = 0;
100762306a36Sopenharmony_ci	struct rxe_qp *qp = to_rqp(ibqp);
100862306a36Sopenharmony_ci	struct rxe_rq *rq = &qp->rq;
100962306a36Sopenharmony_ci	unsigned long flags;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	spin_lock_irqsave(&qp->state_lock, flags);
101262306a36Sopenharmony_ci	/* caller has already called destroy_qp */
101362306a36Sopenharmony_ci	if (WARN_ON_ONCE(!qp->valid)) {
101462306a36Sopenharmony_ci		spin_unlock_irqrestore(&qp->state_lock, flags);
101562306a36Sopenharmony_ci		rxe_err_qp(qp, "qp has been destroyed");
101662306a36Sopenharmony_ci		return -EINVAL;
101762306a36Sopenharmony_ci	}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	/* see C10-97.2.1 */
102062306a36Sopenharmony_ci	if (unlikely((qp_state(qp) < IB_QPS_INIT))) {
102162306a36Sopenharmony_ci		spin_unlock_irqrestore(&qp->state_lock, flags);
102262306a36Sopenharmony_ci		*bad_wr = wr;
102362306a36Sopenharmony_ci		rxe_dbg_qp(qp, "qp not ready to post recv");
102462306a36Sopenharmony_ci		return -EINVAL;
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->state_lock, flags);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	if (unlikely(qp->srq)) {
102962306a36Sopenharmony_ci		*bad_wr = wr;
103062306a36Sopenharmony_ci		rxe_dbg_qp(qp, "qp has srq, use post_srq_recv instead");
103162306a36Sopenharmony_ci		return -EINVAL;
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	spin_lock_irqsave(&rq->producer_lock, flags);
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	while (wr) {
103762306a36Sopenharmony_ci		err = post_one_recv(rq, wr);
103862306a36Sopenharmony_ci		if (unlikely(err)) {
103962306a36Sopenharmony_ci			*bad_wr = wr;
104062306a36Sopenharmony_ci			break;
104162306a36Sopenharmony_ci		}
104262306a36Sopenharmony_ci		wr = wr->next;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	spin_unlock_irqrestore(&rq->producer_lock, flags);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	spin_lock_irqsave(&qp->state_lock, flags);
104862306a36Sopenharmony_ci	if (qp_state(qp) == IB_QPS_ERR)
104962306a36Sopenharmony_ci		rxe_sched_task(&qp->resp.task);
105062306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->state_lock, flags);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	return err;
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci/* cq */
105662306a36Sopenharmony_cistatic int rxe_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
105762306a36Sopenharmony_ci			 struct ib_udata *udata)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	struct ib_device *dev = ibcq->device;
106062306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(dev);
106162306a36Sopenharmony_ci	struct rxe_cq *cq = to_rcq(ibcq);
106262306a36Sopenharmony_ci	struct rxe_create_cq_resp __user *uresp = NULL;
106362306a36Sopenharmony_ci	int err, cleanup_err;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	if (udata) {
106662306a36Sopenharmony_ci		if (udata->outlen < sizeof(*uresp)) {
106762306a36Sopenharmony_ci			err = -EINVAL;
106862306a36Sopenharmony_ci			rxe_dbg_dev(rxe, "malformed udata, err = %d", err);
106962306a36Sopenharmony_ci			goto err_out;
107062306a36Sopenharmony_ci		}
107162306a36Sopenharmony_ci		uresp = udata->outbuf;
107262306a36Sopenharmony_ci	}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (attr->flags) {
107562306a36Sopenharmony_ci		err = -EOPNOTSUPP;
107662306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "bad attr->flags, err = %d", err);
107762306a36Sopenharmony_ci		goto err_out;
107862306a36Sopenharmony_ci	}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	err = rxe_cq_chk_attr(rxe, NULL, attr->cqe, attr->comp_vector);
108162306a36Sopenharmony_ci	if (err) {
108262306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "bad init attributes, err = %d", err);
108362306a36Sopenharmony_ci		goto err_out;
108462306a36Sopenharmony_ci	}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	err = rxe_add_to_pool(&rxe->cq_pool, cq);
108762306a36Sopenharmony_ci	if (err) {
108862306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "unable to create cq, err = %d", err);
108962306a36Sopenharmony_ci		goto err_out;
109062306a36Sopenharmony_ci	}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	err = rxe_cq_from_init(rxe, cq, attr->cqe, attr->comp_vector, udata,
109362306a36Sopenharmony_ci			       uresp);
109462306a36Sopenharmony_ci	if (err) {
109562306a36Sopenharmony_ci		rxe_dbg_cq(cq, "create cq failed, err = %d", err);
109662306a36Sopenharmony_ci		goto err_cleanup;
109762306a36Sopenharmony_ci	}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	return 0;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_cierr_cleanup:
110262306a36Sopenharmony_ci	cleanup_err = rxe_cleanup(cq);
110362306a36Sopenharmony_ci	if (cleanup_err)
110462306a36Sopenharmony_ci		rxe_err_cq(cq, "cleanup failed, err = %d", cleanup_err);
110562306a36Sopenharmony_cierr_out:
110662306a36Sopenharmony_ci	rxe_err_dev(rxe, "returned err = %d", err);
110762306a36Sopenharmony_ci	return err;
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cistatic int rxe_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	struct rxe_cq *cq = to_rcq(ibcq);
111362306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibcq->device);
111462306a36Sopenharmony_ci	struct rxe_resize_cq_resp __user *uresp = NULL;
111562306a36Sopenharmony_ci	int err;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (udata) {
111862306a36Sopenharmony_ci		if (udata->outlen < sizeof(*uresp)) {
111962306a36Sopenharmony_ci			err = -EINVAL;
112062306a36Sopenharmony_ci			rxe_dbg_cq(cq, "malformed udata");
112162306a36Sopenharmony_ci			goto err_out;
112262306a36Sopenharmony_ci		}
112362306a36Sopenharmony_ci		uresp = udata->outbuf;
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	err = rxe_cq_chk_attr(rxe, cq, cqe, 0);
112762306a36Sopenharmony_ci	if (err) {
112862306a36Sopenharmony_ci		rxe_dbg_cq(cq, "bad attr, err = %d", err);
112962306a36Sopenharmony_ci		goto err_out;
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	err = rxe_cq_resize_queue(cq, cqe, uresp, udata);
113362306a36Sopenharmony_ci	if (err) {
113462306a36Sopenharmony_ci		rxe_dbg_cq(cq, "resize cq failed, err = %d", err);
113562306a36Sopenharmony_ci		goto err_out;
113662306a36Sopenharmony_ci	}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return 0;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cierr_out:
114162306a36Sopenharmony_ci	rxe_err_cq(cq, "returned err = %d", err);
114262306a36Sopenharmony_ci	return err;
114362306a36Sopenharmony_ci}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_cistatic int rxe_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	int i;
114862306a36Sopenharmony_ci	struct rxe_cq *cq = to_rcq(ibcq);
114962306a36Sopenharmony_ci	struct rxe_cqe *cqe;
115062306a36Sopenharmony_ci	unsigned long flags;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	spin_lock_irqsave(&cq->cq_lock, flags);
115362306a36Sopenharmony_ci	for (i = 0; i < num_entries; i++) {
115462306a36Sopenharmony_ci		cqe = queue_head(cq->queue, QUEUE_TYPE_TO_ULP);
115562306a36Sopenharmony_ci		if (!cqe)
115662306a36Sopenharmony_ci			break;	/* queue empty */
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci		memcpy(wc++, &cqe->ibwc, sizeof(*wc));
115962306a36Sopenharmony_ci		queue_advance_consumer(cq->queue, QUEUE_TYPE_TO_ULP);
116062306a36Sopenharmony_ci	}
116162306a36Sopenharmony_ci	spin_unlock_irqrestore(&cq->cq_lock, flags);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	return i;
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic int rxe_peek_cq(struct ib_cq *ibcq, int wc_cnt)
116762306a36Sopenharmony_ci{
116862306a36Sopenharmony_ci	struct rxe_cq *cq = to_rcq(ibcq);
116962306a36Sopenharmony_ci	int count;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	count = queue_count(cq->queue, QUEUE_TYPE_TO_ULP);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	return (count > wc_cnt) ? wc_cnt : count;
117462306a36Sopenharmony_ci}
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_cistatic int rxe_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
117762306a36Sopenharmony_ci{
117862306a36Sopenharmony_ci	struct rxe_cq *cq = to_rcq(ibcq);
117962306a36Sopenharmony_ci	int ret = 0;
118062306a36Sopenharmony_ci	int empty;
118162306a36Sopenharmony_ci	unsigned long irq_flags;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	spin_lock_irqsave(&cq->cq_lock, irq_flags);
118462306a36Sopenharmony_ci	cq->notify |= flags & IB_CQ_SOLICITED_MASK;
118562306a36Sopenharmony_ci	empty = queue_empty(cq->queue, QUEUE_TYPE_TO_ULP);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && !empty)
118862306a36Sopenharmony_ci		ret = 1;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	spin_unlock_irqrestore(&cq->cq_lock, irq_flags);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	return ret;
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_cistatic int rxe_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	struct rxe_cq *cq = to_rcq(ibcq);
119862306a36Sopenharmony_ci	int err;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	/* See IBA C11-17: The CI shall return an error if this Verb is
120162306a36Sopenharmony_ci	 * invoked while a Work Queue is still associated with the CQ.
120262306a36Sopenharmony_ci	 */
120362306a36Sopenharmony_ci	if (atomic_read(&cq->num_wq)) {
120462306a36Sopenharmony_ci		err = -EINVAL;
120562306a36Sopenharmony_ci		rxe_dbg_cq(cq, "still in use");
120662306a36Sopenharmony_ci		goto err_out;
120762306a36Sopenharmony_ci	}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	err = rxe_cleanup(cq);
121062306a36Sopenharmony_ci	if (err)
121162306a36Sopenharmony_ci		rxe_err_cq(cq, "cleanup failed, err = %d", err);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	return 0;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cierr_out:
121662306a36Sopenharmony_ci	rxe_err_cq(cq, "returned err = %d", err);
121762306a36Sopenharmony_ci	return err;
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci/* mr */
122162306a36Sopenharmony_cistatic struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access)
122262306a36Sopenharmony_ci{
122362306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibpd->device);
122462306a36Sopenharmony_ci	struct rxe_pd *pd = to_rpd(ibpd);
122562306a36Sopenharmony_ci	struct rxe_mr *mr;
122662306a36Sopenharmony_ci	int err;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
122962306a36Sopenharmony_ci	if (!mr)
123062306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	err = rxe_add_to_pool(&rxe->mr_pool, mr);
123362306a36Sopenharmony_ci	if (err) {
123462306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "unable to create mr");
123562306a36Sopenharmony_ci		goto err_free;
123662306a36Sopenharmony_ci	}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	rxe_get(pd);
123962306a36Sopenharmony_ci	mr->ibmr.pd = ibpd;
124062306a36Sopenharmony_ci	mr->ibmr.device = ibpd->device;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	rxe_mr_init_dma(access, mr);
124362306a36Sopenharmony_ci	rxe_finalize(mr);
124462306a36Sopenharmony_ci	return &mr->ibmr;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_cierr_free:
124762306a36Sopenharmony_ci	kfree(mr);
124862306a36Sopenharmony_ci	rxe_err_pd(pd, "returned err = %d", err);
124962306a36Sopenharmony_ci	return ERR_PTR(err);
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_cistatic struct ib_mr *rxe_reg_user_mr(struct ib_pd *ibpd, u64 start,
125362306a36Sopenharmony_ci				     u64 length, u64 iova, int access,
125462306a36Sopenharmony_ci				     struct ib_udata *udata)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibpd->device);
125762306a36Sopenharmony_ci	struct rxe_pd *pd = to_rpd(ibpd);
125862306a36Sopenharmony_ci	struct rxe_mr *mr;
125962306a36Sopenharmony_ci	int err, cleanup_err;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	if (access & ~RXE_ACCESS_SUPPORTED_MR) {
126262306a36Sopenharmony_ci		rxe_err_pd(pd, "access = %#x not supported (%#x)", access,
126362306a36Sopenharmony_ci				RXE_ACCESS_SUPPORTED_MR);
126462306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
126562306a36Sopenharmony_ci	}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
126862306a36Sopenharmony_ci	if (!mr)
126962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	err = rxe_add_to_pool(&rxe->mr_pool, mr);
127262306a36Sopenharmony_ci	if (err) {
127362306a36Sopenharmony_ci		rxe_dbg_pd(pd, "unable to create mr");
127462306a36Sopenharmony_ci		goto err_free;
127562306a36Sopenharmony_ci	}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	rxe_get(pd);
127862306a36Sopenharmony_ci	mr->ibmr.pd = ibpd;
127962306a36Sopenharmony_ci	mr->ibmr.device = ibpd->device;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	err = rxe_mr_init_user(rxe, start, length, iova, access, mr);
128262306a36Sopenharmony_ci	if (err) {
128362306a36Sopenharmony_ci		rxe_dbg_mr(mr, "reg_user_mr failed, err = %d", err);
128462306a36Sopenharmony_ci		goto err_cleanup;
128562306a36Sopenharmony_ci	}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	rxe_finalize(mr);
128862306a36Sopenharmony_ci	return &mr->ibmr;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_cierr_cleanup:
129162306a36Sopenharmony_ci	cleanup_err = rxe_cleanup(mr);
129262306a36Sopenharmony_ci	if (cleanup_err)
129362306a36Sopenharmony_ci		rxe_err_mr(mr, "cleanup failed, err = %d", cleanup_err);
129462306a36Sopenharmony_cierr_free:
129562306a36Sopenharmony_ci	kfree(mr);
129662306a36Sopenharmony_ci	rxe_err_pd(pd, "returned err = %d", err);
129762306a36Sopenharmony_ci	return ERR_PTR(err);
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_cistatic struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags,
130162306a36Sopenharmony_ci				       u64 start, u64 length, u64 iova,
130262306a36Sopenharmony_ci				       int access, struct ib_pd *ibpd,
130362306a36Sopenharmony_ci				       struct ib_udata *udata)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	struct rxe_mr *mr = to_rmr(ibmr);
130662306a36Sopenharmony_ci	struct rxe_pd *old_pd = to_rpd(ibmr->pd);
130762306a36Sopenharmony_ci	struct rxe_pd *pd = to_rpd(ibpd);
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	/* for now only support the two easy cases:
131062306a36Sopenharmony_ci	 * rereg_pd and rereg_access
131162306a36Sopenharmony_ci	 */
131262306a36Sopenharmony_ci	if (flags & ~RXE_MR_REREG_SUPPORTED) {
131362306a36Sopenharmony_ci		rxe_err_mr(mr, "flags = %#x not supported", flags);
131462306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
131562306a36Sopenharmony_ci	}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	if (flags & IB_MR_REREG_PD) {
131862306a36Sopenharmony_ci		rxe_put(old_pd);
131962306a36Sopenharmony_ci		rxe_get(pd);
132062306a36Sopenharmony_ci		mr->ibmr.pd = ibpd;
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	if (flags & IB_MR_REREG_ACCESS) {
132462306a36Sopenharmony_ci		if (access & ~RXE_ACCESS_SUPPORTED_MR) {
132562306a36Sopenharmony_ci			rxe_err_mr(mr, "access = %#x not supported", access);
132662306a36Sopenharmony_ci			return ERR_PTR(-EOPNOTSUPP);
132762306a36Sopenharmony_ci		}
132862306a36Sopenharmony_ci		mr->access = access;
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	return NULL;
133262306a36Sopenharmony_ci}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_cistatic struct ib_mr *rxe_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type mr_type,
133562306a36Sopenharmony_ci				  u32 max_num_sg)
133662306a36Sopenharmony_ci{
133762306a36Sopenharmony_ci	struct rxe_dev *rxe = to_rdev(ibpd->device);
133862306a36Sopenharmony_ci	struct rxe_pd *pd = to_rpd(ibpd);
133962306a36Sopenharmony_ci	struct rxe_mr *mr;
134062306a36Sopenharmony_ci	int err, cleanup_err;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	if (mr_type != IB_MR_TYPE_MEM_REG) {
134362306a36Sopenharmony_ci		err = -EINVAL;
134462306a36Sopenharmony_ci		rxe_dbg_pd(pd, "mr type %d not supported, err = %d",
134562306a36Sopenharmony_ci			   mr_type, err);
134662306a36Sopenharmony_ci		goto err_out;
134762306a36Sopenharmony_ci	}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
135062306a36Sopenharmony_ci	if (!mr)
135162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	err = rxe_add_to_pool(&rxe->mr_pool, mr);
135462306a36Sopenharmony_ci	if (err)
135562306a36Sopenharmony_ci		goto err_free;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	rxe_get(pd);
135862306a36Sopenharmony_ci	mr->ibmr.pd = ibpd;
135962306a36Sopenharmony_ci	mr->ibmr.device = ibpd->device;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	err = rxe_mr_init_fast(max_num_sg, mr);
136262306a36Sopenharmony_ci	if (err) {
136362306a36Sopenharmony_ci		rxe_dbg_mr(mr, "alloc_mr failed, err = %d", err);
136462306a36Sopenharmony_ci		goto err_cleanup;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	rxe_finalize(mr);
136862306a36Sopenharmony_ci	return &mr->ibmr;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_cierr_cleanup:
137162306a36Sopenharmony_ci	cleanup_err = rxe_cleanup(mr);
137262306a36Sopenharmony_ci	if (cleanup_err)
137362306a36Sopenharmony_ci		rxe_err_mr(mr, "cleanup failed, err = %d", err);
137462306a36Sopenharmony_cierr_free:
137562306a36Sopenharmony_ci	kfree(mr);
137662306a36Sopenharmony_cierr_out:
137762306a36Sopenharmony_ci	rxe_err_pd(pd, "returned err = %d", err);
137862306a36Sopenharmony_ci	return ERR_PTR(err);
137962306a36Sopenharmony_ci}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_cistatic int rxe_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
138262306a36Sopenharmony_ci{
138362306a36Sopenharmony_ci	struct rxe_mr *mr = to_rmr(ibmr);
138462306a36Sopenharmony_ci	int err, cleanup_err;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	/* See IBA 10.6.7.2.6 */
138762306a36Sopenharmony_ci	if (atomic_read(&mr->num_mw) > 0) {
138862306a36Sopenharmony_ci		err = -EINVAL;
138962306a36Sopenharmony_ci		rxe_dbg_mr(mr, "mr has mw's bound");
139062306a36Sopenharmony_ci		goto err_out;
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	cleanup_err = rxe_cleanup(mr);
139462306a36Sopenharmony_ci	if (cleanup_err)
139562306a36Sopenharmony_ci		rxe_err_mr(mr, "cleanup failed, err = %d", cleanup_err);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	kfree_rcu_mightsleep(mr);
139862306a36Sopenharmony_ci	return 0;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cierr_out:
140162306a36Sopenharmony_ci	rxe_err_mr(mr, "returned err = %d", err);
140262306a36Sopenharmony_ci	return err;
140362306a36Sopenharmony_ci}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_cistatic ssize_t parent_show(struct device *device,
140662306a36Sopenharmony_ci			   struct device_attribute *attr, char *buf)
140762306a36Sopenharmony_ci{
140862306a36Sopenharmony_ci	struct rxe_dev *rxe =
140962306a36Sopenharmony_ci		rdma_device_to_drv_device(device, struct rxe_dev, ib_dev);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", rxe_parent_name(rxe, 1));
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(parent);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cistatic struct attribute *rxe_dev_attributes[] = {
141762306a36Sopenharmony_ci	&dev_attr_parent.attr,
141862306a36Sopenharmony_ci	NULL
141962306a36Sopenharmony_ci};
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_cistatic const struct attribute_group rxe_attr_group = {
142262306a36Sopenharmony_ci	.attrs = rxe_dev_attributes,
142362306a36Sopenharmony_ci};
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_cistatic int rxe_enable_driver(struct ib_device *ib_dev)
142662306a36Sopenharmony_ci{
142762306a36Sopenharmony_ci	struct rxe_dev *rxe = container_of(ib_dev, struct rxe_dev, ib_dev);
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	rxe_set_port_state(rxe);
143062306a36Sopenharmony_ci	dev_info(&rxe->ib_dev.dev, "added %s\n", netdev_name(rxe->ndev));
143162306a36Sopenharmony_ci	return 0;
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_cistatic const struct ib_device_ops rxe_dev_ops = {
143562306a36Sopenharmony_ci	.owner = THIS_MODULE,
143662306a36Sopenharmony_ci	.driver_id = RDMA_DRIVER_RXE,
143762306a36Sopenharmony_ci	.uverbs_abi_ver = RXE_UVERBS_ABI_VERSION,
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	.alloc_hw_port_stats = rxe_ib_alloc_hw_port_stats,
144062306a36Sopenharmony_ci	.alloc_mr = rxe_alloc_mr,
144162306a36Sopenharmony_ci	.alloc_mw = rxe_alloc_mw,
144262306a36Sopenharmony_ci	.alloc_pd = rxe_alloc_pd,
144362306a36Sopenharmony_ci	.alloc_ucontext = rxe_alloc_ucontext,
144462306a36Sopenharmony_ci	.attach_mcast = rxe_attach_mcast,
144562306a36Sopenharmony_ci	.create_ah = rxe_create_ah,
144662306a36Sopenharmony_ci	.create_cq = rxe_create_cq,
144762306a36Sopenharmony_ci	.create_qp = rxe_create_qp,
144862306a36Sopenharmony_ci	.create_srq = rxe_create_srq,
144962306a36Sopenharmony_ci	.create_user_ah = rxe_create_ah,
145062306a36Sopenharmony_ci	.dealloc_driver = rxe_dealloc,
145162306a36Sopenharmony_ci	.dealloc_mw = rxe_dealloc_mw,
145262306a36Sopenharmony_ci	.dealloc_pd = rxe_dealloc_pd,
145362306a36Sopenharmony_ci	.dealloc_ucontext = rxe_dealloc_ucontext,
145462306a36Sopenharmony_ci	.dereg_mr = rxe_dereg_mr,
145562306a36Sopenharmony_ci	.destroy_ah = rxe_destroy_ah,
145662306a36Sopenharmony_ci	.destroy_cq = rxe_destroy_cq,
145762306a36Sopenharmony_ci	.destroy_qp = rxe_destroy_qp,
145862306a36Sopenharmony_ci	.destroy_srq = rxe_destroy_srq,
145962306a36Sopenharmony_ci	.detach_mcast = rxe_detach_mcast,
146062306a36Sopenharmony_ci	.device_group = &rxe_attr_group,
146162306a36Sopenharmony_ci	.enable_driver = rxe_enable_driver,
146262306a36Sopenharmony_ci	.get_dma_mr = rxe_get_dma_mr,
146362306a36Sopenharmony_ci	.get_hw_stats = rxe_ib_get_hw_stats,
146462306a36Sopenharmony_ci	.get_link_layer = rxe_get_link_layer,
146562306a36Sopenharmony_ci	.get_port_immutable = rxe_port_immutable,
146662306a36Sopenharmony_ci	.map_mr_sg = rxe_map_mr_sg,
146762306a36Sopenharmony_ci	.mmap = rxe_mmap,
146862306a36Sopenharmony_ci	.modify_ah = rxe_modify_ah,
146962306a36Sopenharmony_ci	.modify_device = rxe_modify_device,
147062306a36Sopenharmony_ci	.modify_port = rxe_modify_port,
147162306a36Sopenharmony_ci	.modify_qp = rxe_modify_qp,
147262306a36Sopenharmony_ci	.modify_srq = rxe_modify_srq,
147362306a36Sopenharmony_ci	.peek_cq = rxe_peek_cq,
147462306a36Sopenharmony_ci	.poll_cq = rxe_poll_cq,
147562306a36Sopenharmony_ci	.post_recv = rxe_post_recv,
147662306a36Sopenharmony_ci	.post_send = rxe_post_send,
147762306a36Sopenharmony_ci	.post_srq_recv = rxe_post_srq_recv,
147862306a36Sopenharmony_ci	.query_ah = rxe_query_ah,
147962306a36Sopenharmony_ci	.query_device = rxe_query_device,
148062306a36Sopenharmony_ci	.query_pkey = rxe_query_pkey,
148162306a36Sopenharmony_ci	.query_port = rxe_query_port,
148262306a36Sopenharmony_ci	.query_qp = rxe_query_qp,
148362306a36Sopenharmony_ci	.query_srq = rxe_query_srq,
148462306a36Sopenharmony_ci	.reg_user_mr = rxe_reg_user_mr,
148562306a36Sopenharmony_ci	.req_notify_cq = rxe_req_notify_cq,
148662306a36Sopenharmony_ci	.rereg_user_mr = rxe_rereg_user_mr,
148762306a36Sopenharmony_ci	.resize_cq = rxe_resize_cq,
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_ah, rxe_ah, ibah),
149062306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_cq, rxe_cq, ibcq),
149162306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_pd, rxe_pd, ibpd),
149262306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_qp, rxe_qp, ibqp),
149362306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_srq, rxe_srq, ibsrq),
149462306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_ucontext, rxe_ucontext, ibuc),
149562306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_mw, rxe_mw, ibmw),
149662306a36Sopenharmony_ci};
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ciint rxe_register_device(struct rxe_dev *rxe, const char *ibdev_name)
149962306a36Sopenharmony_ci{
150062306a36Sopenharmony_ci	int err;
150162306a36Sopenharmony_ci	struct ib_device *dev = &rxe->ib_dev;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	strscpy(dev->node_desc, "rxe", sizeof(dev->node_desc));
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	dev->node_type = RDMA_NODE_IB_CA;
150662306a36Sopenharmony_ci	dev->phys_port_cnt = 1;
150762306a36Sopenharmony_ci	dev->num_comp_vectors = num_possible_cpus();
150862306a36Sopenharmony_ci	dev->local_dma_lkey = 0;
150962306a36Sopenharmony_ci	addrconf_addr_eui48((unsigned char *)&dev->node_guid,
151062306a36Sopenharmony_ci			    rxe->ndev->dev_addr);
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	dev->uverbs_cmd_mask |= BIT_ULL(IB_USER_VERBS_CMD_POST_SEND) |
151362306a36Sopenharmony_ci				BIT_ULL(IB_USER_VERBS_CMD_REQ_NOTIFY_CQ);
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	ib_set_device_ops(dev, &rxe_dev_ops);
151662306a36Sopenharmony_ci	err = ib_device_set_netdev(&rxe->ib_dev, rxe->ndev, 1);
151762306a36Sopenharmony_ci	if (err)
151862306a36Sopenharmony_ci		return err;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	err = rxe_icrc_init(rxe);
152162306a36Sopenharmony_ci	if (err)
152262306a36Sopenharmony_ci		return err;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	err = ib_register_device(dev, ibdev_name, NULL);
152562306a36Sopenharmony_ci	if (err)
152662306a36Sopenharmony_ci		rxe_dbg_dev(rxe, "failed with error %d\n", err);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	/*
152962306a36Sopenharmony_ci	 * Note that rxe may be invalid at this point if another thread
153062306a36Sopenharmony_ci	 * unregistered it.
153162306a36Sopenharmony_ci	 */
153262306a36Sopenharmony_ci	return err;
153362306a36Sopenharmony_ci}
1534