162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright(c) 2016 - 2018 Intel Corporation.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/dma-mapping.h>
962306a36Sopenharmony_ci#include "vt.h"
1062306a36Sopenharmony_ci#include "cq.h"
1162306a36Sopenharmony_ci#include "trace.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define RVT_UVERBS_ABI_VERSION 2
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
1662306a36Sopenharmony_ciMODULE_DESCRIPTION("RDMA Verbs Transport Library");
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic int __init rvt_init(void)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	int ret = rvt_driver_cq_init();
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	if (ret)
2362306a36Sopenharmony_ci		pr_err("Error in driver CQ init.\n");
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	return ret;
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_cimodule_init(rvt_init);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic void __exit rvt_cleanup(void)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	rvt_cq_exit();
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_cimodule_exit(rvt_cleanup);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/**
3662306a36Sopenharmony_ci * rvt_alloc_device - allocate rdi
3762306a36Sopenharmony_ci * @size: how big of a structure to allocate
3862306a36Sopenharmony_ci * @nports: number of ports to allocate array slots for
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * Use IB core device alloc to allocate space for the rdi which is assumed to be
4162306a36Sopenharmony_ci * inside of the ib_device. Any extra space that drivers require should be
4262306a36Sopenharmony_ci * included in size.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * We also allocate a port array based on the number of ports.
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * Return: pointer to allocated rdi
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_cistruct rvt_dev_info *rvt_alloc_device(size_t size, int nports)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct rvt_dev_info *rdi;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	rdi = container_of(_ib_alloc_device(size), struct rvt_dev_info, ibdev);
5362306a36Sopenharmony_ci	if (!rdi)
5462306a36Sopenharmony_ci		return rdi;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	rdi->ports = kcalloc(nports, sizeof(*rdi->ports), GFP_KERNEL);
5762306a36Sopenharmony_ci	if (!rdi->ports)
5862306a36Sopenharmony_ci		ib_dealloc_device(&rdi->ibdev);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return rdi;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_alloc_device);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/**
6562306a36Sopenharmony_ci * rvt_dealloc_device - deallocate rdi
6662306a36Sopenharmony_ci * @rdi: structure to free
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * Free a structure allocated with rvt_alloc_device()
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_civoid rvt_dealloc_device(struct rvt_dev_info *rdi)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	kfree(rdi->ports);
7362306a36Sopenharmony_ci	ib_dealloc_device(&rdi->ibdev);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_dealloc_device);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic int rvt_query_device(struct ib_device *ibdev,
7862306a36Sopenharmony_ci			    struct ib_device_attr *props,
7962306a36Sopenharmony_ci			    struct ib_udata *uhw)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (uhw->inlen || uhw->outlen)
8462306a36Sopenharmony_ci		return -EINVAL;
8562306a36Sopenharmony_ci	/*
8662306a36Sopenharmony_ci	 * Return rvt_dev_info.dparms.props contents
8762306a36Sopenharmony_ci	 */
8862306a36Sopenharmony_ci	*props = rdi->dparms.props;
8962306a36Sopenharmony_ci	return 0;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic int rvt_get_numa_node(struct ib_device *ibdev)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return rdi->dparms.node;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int rvt_modify_device(struct ib_device *device,
10062306a36Sopenharmony_ci			     int device_modify_mask,
10162306a36Sopenharmony_ci			     struct ib_device_modify *device_modify)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	/*
10462306a36Sopenharmony_ci	 * There is currently no need to supply this based on qib and hfi1.
10562306a36Sopenharmony_ci	 * Future drivers may need to implement this though.
10662306a36Sopenharmony_ci	 */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	return -EOPNOTSUPP;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/**
11262306a36Sopenharmony_ci * rvt_query_port - Passes the query port call to the driver
11362306a36Sopenharmony_ci * @ibdev: Verbs IB dev
11462306a36Sopenharmony_ci * @port_num: port number, 1 based from ib core
11562306a36Sopenharmony_ci * @props: structure to hold returned properties
11662306a36Sopenharmony_ci *
11762306a36Sopenharmony_ci * Return: 0 on success
11862306a36Sopenharmony_ci */
11962306a36Sopenharmony_cistatic int rvt_query_port(struct ib_device *ibdev, u32 port_num,
12062306a36Sopenharmony_ci			  struct ib_port_attr *props)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
12362306a36Sopenharmony_ci	struct rvt_ibport *rvp;
12462306a36Sopenharmony_ci	u32 port_index = ibport_num_to_idx(ibdev, port_num);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	rvp = rdi->ports[port_index];
12762306a36Sopenharmony_ci	/* props being zeroed by the caller, avoid zeroing it here */
12862306a36Sopenharmony_ci	props->sm_lid = rvp->sm_lid;
12962306a36Sopenharmony_ci	props->sm_sl = rvp->sm_sl;
13062306a36Sopenharmony_ci	props->port_cap_flags = rvp->port_cap_flags;
13162306a36Sopenharmony_ci	props->max_msg_sz = 0x80000000;
13262306a36Sopenharmony_ci	props->pkey_tbl_len = rvt_get_npkeys(rdi);
13362306a36Sopenharmony_ci	props->bad_pkey_cntr = rvp->pkey_violations;
13462306a36Sopenharmony_ci	props->qkey_viol_cntr = rvp->qkey_violations;
13562306a36Sopenharmony_ci	props->subnet_timeout = rvp->subnet_timeout;
13662306a36Sopenharmony_ci	props->init_type_reply = 0;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* Populate the remaining ib_port_attr elements */
13962306a36Sopenharmony_ci	return rdi->driver_f.query_port_state(rdi, port_num, props);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/**
14362306a36Sopenharmony_ci * rvt_modify_port - modify port
14462306a36Sopenharmony_ci * @ibdev: Verbs IB dev
14562306a36Sopenharmony_ci * @port_num: Port number, 1 based from ib core
14662306a36Sopenharmony_ci * @port_modify_mask: How to change the port
14762306a36Sopenharmony_ci * @props: Structure to fill in
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * Return: 0 on success
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_cistatic int rvt_modify_port(struct ib_device *ibdev, u32 port_num,
15262306a36Sopenharmony_ci			   int port_modify_mask, struct ib_port_modify *props)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
15562306a36Sopenharmony_ci	struct rvt_ibport *rvp;
15662306a36Sopenharmony_ci	int ret = 0;
15762306a36Sopenharmony_ci	u32 port_index = ibport_num_to_idx(ibdev, port_num);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	rvp = rdi->ports[port_index];
16062306a36Sopenharmony_ci	if (port_modify_mask & IB_PORT_OPA_MASK_CHG) {
16162306a36Sopenharmony_ci		rvp->port_cap3_flags |= props->set_port_cap_mask;
16262306a36Sopenharmony_ci		rvp->port_cap3_flags &= ~props->clr_port_cap_mask;
16362306a36Sopenharmony_ci	} else {
16462306a36Sopenharmony_ci		rvp->port_cap_flags |= props->set_port_cap_mask;
16562306a36Sopenharmony_ci		rvp->port_cap_flags &= ~props->clr_port_cap_mask;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (props->set_port_cap_mask || props->clr_port_cap_mask)
16962306a36Sopenharmony_ci		rdi->driver_f.cap_mask_chg(rdi, port_num);
17062306a36Sopenharmony_ci	if (port_modify_mask & IB_PORT_SHUTDOWN)
17162306a36Sopenharmony_ci		ret = rdi->driver_f.shut_down_port(rdi, port_num);
17262306a36Sopenharmony_ci	if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR)
17362306a36Sopenharmony_ci		rvp->qkey_violations = 0;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return ret;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/**
17962306a36Sopenharmony_ci * rvt_query_pkey - Return a pkey from the table at a given index
18062306a36Sopenharmony_ci * @ibdev: Verbs IB dev
18162306a36Sopenharmony_ci * @port_num: Port number, 1 based from ib core
18262306a36Sopenharmony_ci * @index: Index into pkey table
18362306a36Sopenharmony_ci * @pkey: returned pkey from the port pkey table
18462306a36Sopenharmony_ci *
18562306a36Sopenharmony_ci * Return: 0 on failure pkey otherwise
18662306a36Sopenharmony_ci */
18762306a36Sopenharmony_cistatic int rvt_query_pkey(struct ib_device *ibdev, u32 port_num, u16 index,
18862306a36Sopenharmony_ci			  u16 *pkey)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	/*
19162306a36Sopenharmony_ci	 * Driver will be responsible for keeping rvt_dev_info.pkey_table up to
19262306a36Sopenharmony_ci	 * date. This function will just return that value. There is no need to
19362306a36Sopenharmony_ci	 * lock, if a stale value is read and sent to the user so be it there is
19462306a36Sopenharmony_ci	 * no way to protect against that anyway.
19562306a36Sopenharmony_ci	 */
19662306a36Sopenharmony_ci	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
19762306a36Sopenharmony_ci	u32 port_index;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	port_index = ibport_num_to_idx(ibdev, port_num);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (index >= rvt_get_npkeys(rdi))
20262306a36Sopenharmony_ci		return -EINVAL;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	*pkey = rvt_get_pkey(rdi, port_index, index);
20562306a36Sopenharmony_ci	return 0;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci/**
20962306a36Sopenharmony_ci * rvt_query_gid - Return a gid from the table
21062306a36Sopenharmony_ci * @ibdev: Verbs IB dev
21162306a36Sopenharmony_ci * @port_num: Port number, 1 based from ib core
21262306a36Sopenharmony_ci * @guid_index: Index in table
21362306a36Sopenharmony_ci * @gid: Gid to return
21462306a36Sopenharmony_ci *
21562306a36Sopenharmony_ci * Return: 0 on success
21662306a36Sopenharmony_ci */
21762306a36Sopenharmony_cistatic int rvt_query_gid(struct ib_device *ibdev, u32 port_num,
21862306a36Sopenharmony_ci			 int guid_index, union ib_gid *gid)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct rvt_dev_info *rdi;
22162306a36Sopenharmony_ci	struct rvt_ibport *rvp;
22262306a36Sopenharmony_ci	u32 port_index;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/*
22562306a36Sopenharmony_ci	 * Driver is responsible for updating the guid table. Which will be used
22662306a36Sopenharmony_ci	 * to craft the return value. This will work similar to how query_pkey()
22762306a36Sopenharmony_ci	 * is being done.
22862306a36Sopenharmony_ci	 */
22962306a36Sopenharmony_ci	port_index = ibport_num_to_idx(ibdev, port_num);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	rdi = ib_to_rvt(ibdev);
23262306a36Sopenharmony_ci	rvp = rdi->ports[port_index];
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	gid->global.subnet_prefix = rvp->gid_prefix;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return rdi->driver_f.get_guid_be(rdi, rvp, guid_index,
23762306a36Sopenharmony_ci					 &gid->global.interface_id);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/**
24162306a36Sopenharmony_ci * rvt_alloc_ucontext - Allocate a user context
24262306a36Sopenharmony_ci * @uctx: Verbs context
24362306a36Sopenharmony_ci * @udata: User data allocated
24462306a36Sopenharmony_ci */
24562306a36Sopenharmony_cistatic int rvt_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	return 0;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/**
25162306a36Sopenharmony_ci * rvt_dealloc_ucontext - Free a user context
25262306a36Sopenharmony_ci * @context: Unused
25362306a36Sopenharmony_ci */
25462306a36Sopenharmony_cistatic void rvt_dealloc_ucontext(struct ib_ucontext *context)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	return;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic int rvt_get_port_immutable(struct ib_device *ibdev, u32 port_num,
26062306a36Sopenharmony_ci				  struct ib_port_immutable *immutable)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
26362306a36Sopenharmony_ci	struct ib_port_attr attr;
26462306a36Sopenharmony_ci	int err;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	immutable->core_cap_flags = rdi->dparms.core_cap_flags;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	err = ib_query_port(ibdev, port_num, &attr);
26962306a36Sopenharmony_ci	if (err)
27062306a36Sopenharmony_ci		return err;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	immutable->pkey_tbl_len = attr.pkey_tbl_len;
27362306a36Sopenharmony_ci	immutable->gid_tbl_len = attr.gid_tbl_len;
27462306a36Sopenharmony_ci	immutable->max_mad_size = rdi->dparms.max_mad_size;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	return 0;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cienum {
28062306a36Sopenharmony_ci	MISC,
28162306a36Sopenharmony_ci	QUERY_DEVICE,
28262306a36Sopenharmony_ci	MODIFY_DEVICE,
28362306a36Sopenharmony_ci	QUERY_PORT,
28462306a36Sopenharmony_ci	MODIFY_PORT,
28562306a36Sopenharmony_ci	QUERY_PKEY,
28662306a36Sopenharmony_ci	QUERY_GID,
28762306a36Sopenharmony_ci	ALLOC_UCONTEXT,
28862306a36Sopenharmony_ci	DEALLOC_UCONTEXT,
28962306a36Sopenharmony_ci	GET_PORT_IMMUTABLE,
29062306a36Sopenharmony_ci	CREATE_QP,
29162306a36Sopenharmony_ci	MODIFY_QP,
29262306a36Sopenharmony_ci	DESTROY_QP,
29362306a36Sopenharmony_ci	QUERY_QP,
29462306a36Sopenharmony_ci	POST_SEND,
29562306a36Sopenharmony_ci	POST_RECV,
29662306a36Sopenharmony_ci	POST_SRQ_RECV,
29762306a36Sopenharmony_ci	CREATE_AH,
29862306a36Sopenharmony_ci	DESTROY_AH,
29962306a36Sopenharmony_ci	MODIFY_AH,
30062306a36Sopenharmony_ci	QUERY_AH,
30162306a36Sopenharmony_ci	CREATE_SRQ,
30262306a36Sopenharmony_ci	MODIFY_SRQ,
30362306a36Sopenharmony_ci	DESTROY_SRQ,
30462306a36Sopenharmony_ci	QUERY_SRQ,
30562306a36Sopenharmony_ci	ATTACH_MCAST,
30662306a36Sopenharmony_ci	DETACH_MCAST,
30762306a36Sopenharmony_ci	GET_DMA_MR,
30862306a36Sopenharmony_ci	REG_USER_MR,
30962306a36Sopenharmony_ci	DEREG_MR,
31062306a36Sopenharmony_ci	ALLOC_MR,
31162306a36Sopenharmony_ci	MAP_MR_SG,
31262306a36Sopenharmony_ci	ALLOC_FMR,
31362306a36Sopenharmony_ci	MAP_PHYS_FMR,
31462306a36Sopenharmony_ci	UNMAP_FMR,
31562306a36Sopenharmony_ci	DEALLOC_FMR,
31662306a36Sopenharmony_ci	MMAP,
31762306a36Sopenharmony_ci	CREATE_CQ,
31862306a36Sopenharmony_ci	DESTROY_CQ,
31962306a36Sopenharmony_ci	POLL_CQ,
32062306a36Sopenharmony_ci	REQ_NOTFIY_CQ,
32162306a36Sopenharmony_ci	RESIZE_CQ,
32262306a36Sopenharmony_ci	ALLOC_PD,
32362306a36Sopenharmony_ci	DEALLOC_PD,
32462306a36Sopenharmony_ci	_VERB_IDX_MAX /* Must always be last! */
32562306a36Sopenharmony_ci};
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic const struct ib_device_ops rvt_dev_ops = {
32862306a36Sopenharmony_ci	.uverbs_abi_ver = RVT_UVERBS_ABI_VERSION,
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	.alloc_mr = rvt_alloc_mr,
33162306a36Sopenharmony_ci	.alloc_pd = rvt_alloc_pd,
33262306a36Sopenharmony_ci	.alloc_ucontext = rvt_alloc_ucontext,
33362306a36Sopenharmony_ci	.attach_mcast = rvt_attach_mcast,
33462306a36Sopenharmony_ci	.create_ah = rvt_create_ah,
33562306a36Sopenharmony_ci	.create_cq = rvt_create_cq,
33662306a36Sopenharmony_ci	.create_qp = rvt_create_qp,
33762306a36Sopenharmony_ci	.create_srq = rvt_create_srq,
33862306a36Sopenharmony_ci	.create_user_ah = rvt_create_ah,
33962306a36Sopenharmony_ci	.dealloc_pd = rvt_dealloc_pd,
34062306a36Sopenharmony_ci	.dealloc_ucontext = rvt_dealloc_ucontext,
34162306a36Sopenharmony_ci	.dereg_mr = rvt_dereg_mr,
34262306a36Sopenharmony_ci	.destroy_ah = rvt_destroy_ah,
34362306a36Sopenharmony_ci	.destroy_cq = rvt_destroy_cq,
34462306a36Sopenharmony_ci	.destroy_qp = rvt_destroy_qp,
34562306a36Sopenharmony_ci	.destroy_srq = rvt_destroy_srq,
34662306a36Sopenharmony_ci	.detach_mcast = rvt_detach_mcast,
34762306a36Sopenharmony_ci	.get_dma_mr = rvt_get_dma_mr,
34862306a36Sopenharmony_ci	.get_numa_node = rvt_get_numa_node,
34962306a36Sopenharmony_ci	.get_port_immutable = rvt_get_port_immutable,
35062306a36Sopenharmony_ci	.map_mr_sg = rvt_map_mr_sg,
35162306a36Sopenharmony_ci	.mmap = rvt_mmap,
35262306a36Sopenharmony_ci	.modify_ah = rvt_modify_ah,
35362306a36Sopenharmony_ci	.modify_device = rvt_modify_device,
35462306a36Sopenharmony_ci	.modify_port = rvt_modify_port,
35562306a36Sopenharmony_ci	.modify_qp = rvt_modify_qp,
35662306a36Sopenharmony_ci	.modify_srq = rvt_modify_srq,
35762306a36Sopenharmony_ci	.poll_cq = rvt_poll_cq,
35862306a36Sopenharmony_ci	.post_recv = rvt_post_recv,
35962306a36Sopenharmony_ci	.post_send = rvt_post_send,
36062306a36Sopenharmony_ci	.post_srq_recv = rvt_post_srq_recv,
36162306a36Sopenharmony_ci	.query_ah = rvt_query_ah,
36262306a36Sopenharmony_ci	.query_device = rvt_query_device,
36362306a36Sopenharmony_ci	.query_gid = rvt_query_gid,
36462306a36Sopenharmony_ci	.query_pkey = rvt_query_pkey,
36562306a36Sopenharmony_ci	.query_port = rvt_query_port,
36662306a36Sopenharmony_ci	.query_qp = rvt_query_qp,
36762306a36Sopenharmony_ci	.query_srq = rvt_query_srq,
36862306a36Sopenharmony_ci	.reg_user_mr = rvt_reg_user_mr,
36962306a36Sopenharmony_ci	.req_notify_cq = rvt_req_notify_cq,
37062306a36Sopenharmony_ci	.resize_cq = rvt_resize_cq,
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_ah, rvt_ah, ibah),
37362306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_cq, rvt_cq, ibcq),
37462306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_pd, rvt_pd, ibpd),
37562306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_qp, rvt_qp, ibqp),
37662306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_srq, rvt_srq, ibsrq),
37762306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_ucontext, rvt_ucontext, ibucontext),
37862306a36Sopenharmony_ci};
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic noinline int check_support(struct rvt_dev_info *rdi, int verb)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	switch (verb) {
38362306a36Sopenharmony_ci	case MISC:
38462306a36Sopenharmony_ci		/*
38562306a36Sopenharmony_ci		 * These functions are not part of verbs specifically but are
38662306a36Sopenharmony_ci		 * required for rdmavt to function.
38762306a36Sopenharmony_ci		 */
38862306a36Sopenharmony_ci		if ((!rdi->ibdev.ops.port_groups) ||
38962306a36Sopenharmony_ci		    (!rdi->driver_f.get_pci_dev))
39062306a36Sopenharmony_ci			return -EINVAL;
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	case MODIFY_DEVICE:
39462306a36Sopenharmony_ci		/*
39562306a36Sopenharmony_ci		 * rdmavt does not support modify device currently drivers must
39662306a36Sopenharmony_ci		 * provide.
39762306a36Sopenharmony_ci		 */
39862306a36Sopenharmony_ci		if (!rdi->ibdev.ops.modify_device)
39962306a36Sopenharmony_ci			return -EOPNOTSUPP;
40062306a36Sopenharmony_ci		break;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	case QUERY_PORT:
40362306a36Sopenharmony_ci		if (!rdi->ibdev.ops.query_port)
40462306a36Sopenharmony_ci			if (!rdi->driver_f.query_port_state)
40562306a36Sopenharmony_ci				return -EINVAL;
40662306a36Sopenharmony_ci		break;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	case MODIFY_PORT:
40962306a36Sopenharmony_ci		if (!rdi->ibdev.ops.modify_port)
41062306a36Sopenharmony_ci			if (!rdi->driver_f.cap_mask_chg ||
41162306a36Sopenharmony_ci			    !rdi->driver_f.shut_down_port)
41262306a36Sopenharmony_ci				return -EINVAL;
41362306a36Sopenharmony_ci		break;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	case QUERY_GID:
41662306a36Sopenharmony_ci		if (!rdi->ibdev.ops.query_gid)
41762306a36Sopenharmony_ci			if (!rdi->driver_f.get_guid_be)
41862306a36Sopenharmony_ci				return -EINVAL;
41962306a36Sopenharmony_ci		break;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	case CREATE_QP:
42262306a36Sopenharmony_ci		if (!rdi->ibdev.ops.create_qp)
42362306a36Sopenharmony_ci			if (!rdi->driver_f.qp_priv_alloc ||
42462306a36Sopenharmony_ci			    !rdi->driver_f.qp_priv_free ||
42562306a36Sopenharmony_ci			    !rdi->driver_f.notify_qp_reset ||
42662306a36Sopenharmony_ci			    !rdi->driver_f.flush_qp_waiters ||
42762306a36Sopenharmony_ci			    !rdi->driver_f.stop_send_queue ||
42862306a36Sopenharmony_ci			    !rdi->driver_f.quiesce_qp)
42962306a36Sopenharmony_ci				return -EINVAL;
43062306a36Sopenharmony_ci		break;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	case MODIFY_QP:
43362306a36Sopenharmony_ci		if (!rdi->ibdev.ops.modify_qp)
43462306a36Sopenharmony_ci			if (!rdi->driver_f.notify_qp_reset ||
43562306a36Sopenharmony_ci			    !rdi->driver_f.schedule_send ||
43662306a36Sopenharmony_ci			    !rdi->driver_f.get_pmtu_from_attr ||
43762306a36Sopenharmony_ci			    !rdi->driver_f.flush_qp_waiters ||
43862306a36Sopenharmony_ci			    !rdi->driver_f.stop_send_queue ||
43962306a36Sopenharmony_ci			    !rdi->driver_f.quiesce_qp ||
44062306a36Sopenharmony_ci			    !rdi->driver_f.notify_error_qp ||
44162306a36Sopenharmony_ci			    !rdi->driver_f.mtu_from_qp ||
44262306a36Sopenharmony_ci			    !rdi->driver_f.mtu_to_path_mtu)
44362306a36Sopenharmony_ci				return -EINVAL;
44462306a36Sopenharmony_ci		break;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	case DESTROY_QP:
44762306a36Sopenharmony_ci		if (!rdi->ibdev.ops.destroy_qp)
44862306a36Sopenharmony_ci			if (!rdi->driver_f.qp_priv_free ||
44962306a36Sopenharmony_ci			    !rdi->driver_f.notify_qp_reset ||
45062306a36Sopenharmony_ci			    !rdi->driver_f.flush_qp_waiters ||
45162306a36Sopenharmony_ci			    !rdi->driver_f.stop_send_queue ||
45262306a36Sopenharmony_ci			    !rdi->driver_f.quiesce_qp)
45362306a36Sopenharmony_ci				return -EINVAL;
45462306a36Sopenharmony_ci		break;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	case POST_SEND:
45762306a36Sopenharmony_ci		if (!rdi->ibdev.ops.post_send)
45862306a36Sopenharmony_ci			if (!rdi->driver_f.schedule_send ||
45962306a36Sopenharmony_ci			    !rdi->driver_f.do_send ||
46062306a36Sopenharmony_ci			    !rdi->post_parms)
46162306a36Sopenharmony_ci				return -EINVAL;
46262306a36Sopenharmony_ci		break;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	return 0;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci/**
47062306a36Sopenharmony_ci * rvt_register_device - register a driver
47162306a36Sopenharmony_ci * @rdi: main dev structure for all of rdmavt operations
47262306a36Sopenharmony_ci *
47362306a36Sopenharmony_ci * It is up to drivers to allocate the rdi and fill in the appropriate
47462306a36Sopenharmony_ci * information.
47562306a36Sopenharmony_ci *
47662306a36Sopenharmony_ci * Return: 0 on success otherwise an errno.
47762306a36Sopenharmony_ci */
47862306a36Sopenharmony_ciint rvt_register_device(struct rvt_dev_info *rdi)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	int ret = 0, i;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (!rdi)
48362306a36Sopenharmony_ci		return -EINVAL;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/*
48662306a36Sopenharmony_ci	 * Check to ensure drivers have setup the required helpers for the verbs
48762306a36Sopenharmony_ci	 * they want rdmavt to handle
48862306a36Sopenharmony_ci	 */
48962306a36Sopenharmony_ci	for (i = 0; i < _VERB_IDX_MAX; i++)
49062306a36Sopenharmony_ci		if (check_support(rdi, i)) {
49162306a36Sopenharmony_ci			pr_err("Driver support req not met at %d\n", i);
49262306a36Sopenharmony_ci			return -EINVAL;
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	ib_set_device_ops(&rdi->ibdev, &rvt_dev_ops);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/* Once we get past here we can use rvt_pr macros and tracepoints */
49862306a36Sopenharmony_ci	trace_rvt_dbg(rdi, "Driver attempting registration");
49962306a36Sopenharmony_ci	rvt_mmap_init(rdi);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/* Queue Pairs */
50262306a36Sopenharmony_ci	ret = rvt_driver_qp_init(rdi);
50362306a36Sopenharmony_ci	if (ret) {
50462306a36Sopenharmony_ci		pr_err("Error in driver QP init.\n");
50562306a36Sopenharmony_ci		return -EINVAL;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	/* Address Handle */
50962306a36Sopenharmony_ci	spin_lock_init(&rdi->n_ahs_lock);
51062306a36Sopenharmony_ci	rdi->n_ahs_allocated = 0;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* Shared Receive Queue */
51362306a36Sopenharmony_ci	rvt_driver_srq_init(rdi);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/* Multicast */
51662306a36Sopenharmony_ci	rvt_driver_mcast_init(rdi);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* Mem Region */
51962306a36Sopenharmony_ci	ret = rvt_driver_mr_init(rdi);
52062306a36Sopenharmony_ci	if (ret) {
52162306a36Sopenharmony_ci		pr_err("Error in driver MR init.\n");
52262306a36Sopenharmony_ci		goto bail_no_mr;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* Memory Working Set Size */
52662306a36Sopenharmony_ci	ret = rvt_wss_init(rdi);
52762306a36Sopenharmony_ci	if (ret) {
52862306a36Sopenharmony_ci		rvt_pr_err(rdi, "Error in WSS init.\n");
52962306a36Sopenharmony_ci		goto bail_mr;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/* Completion queues */
53362306a36Sopenharmony_ci	spin_lock_init(&rdi->n_cqs_lock);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	/* Protection Domain */
53662306a36Sopenharmony_ci	spin_lock_init(&rdi->n_pds_lock);
53762306a36Sopenharmony_ci	rdi->n_pds_allocated = 0;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/*
54062306a36Sopenharmony_ci	 * There are some things which could be set by underlying drivers but
54162306a36Sopenharmony_ci	 * really should be up to rdmavt to set. For instance drivers can't know
54262306a36Sopenharmony_ci	 * exactly which functions rdmavt supports, nor do they know the ABI
54362306a36Sopenharmony_ci	 * version, so we do all of this sort of stuff here.
54462306a36Sopenharmony_ci	 */
54562306a36Sopenharmony_ci	rdi->ibdev.uverbs_cmd_mask |=
54662306a36Sopenharmony_ci		(1ull << IB_USER_VERBS_CMD_POLL_CQ)             |
54762306a36Sopenharmony_ci		(1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ)       |
54862306a36Sopenharmony_ci		(1ull << IB_USER_VERBS_CMD_POST_SEND)           |
54962306a36Sopenharmony_ci		(1ull << IB_USER_VERBS_CMD_POST_RECV)           |
55062306a36Sopenharmony_ci		(1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
55162306a36Sopenharmony_ci	rdi->ibdev.node_type = RDMA_NODE_IB_CA;
55262306a36Sopenharmony_ci	if (!rdi->ibdev.num_comp_vectors)
55362306a36Sopenharmony_ci		rdi->ibdev.num_comp_vectors = 1;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/* We are now good to announce we exist */
55662306a36Sopenharmony_ci	ret = ib_register_device(&rdi->ibdev, dev_name(&rdi->ibdev.dev), NULL);
55762306a36Sopenharmony_ci	if (ret) {
55862306a36Sopenharmony_ci		rvt_pr_err(rdi, "Failed to register driver with ib core.\n");
55962306a36Sopenharmony_ci		goto bail_wss;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	rvt_create_mad_agents(rdi);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	rvt_pr_info(rdi, "Registration with rdmavt done.\n");
56562306a36Sopenharmony_ci	return ret;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cibail_wss:
56862306a36Sopenharmony_ci	rvt_wss_exit(rdi);
56962306a36Sopenharmony_cibail_mr:
57062306a36Sopenharmony_ci	rvt_mr_exit(rdi);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cibail_no_mr:
57362306a36Sopenharmony_ci	rvt_qp_exit(rdi);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return ret;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_register_device);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci/**
58062306a36Sopenharmony_ci * rvt_unregister_device - remove a driver
58162306a36Sopenharmony_ci * @rdi: rvt dev struct
58262306a36Sopenharmony_ci */
58362306a36Sopenharmony_civoid rvt_unregister_device(struct rvt_dev_info *rdi)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	trace_rvt_dbg(rdi, "Driver is unregistering.");
58662306a36Sopenharmony_ci	if (!rdi)
58762306a36Sopenharmony_ci		return;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	rvt_free_mad_agents(rdi);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	ib_unregister_device(&rdi->ibdev);
59262306a36Sopenharmony_ci	rvt_wss_exit(rdi);
59362306a36Sopenharmony_ci	rvt_mr_exit(rdi);
59462306a36Sopenharmony_ci	rvt_qp_exit(rdi);
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_unregister_device);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci/**
59962306a36Sopenharmony_ci * rvt_init_port - init internal data for driver port
60062306a36Sopenharmony_ci * @rdi: rvt_dev_info struct
60162306a36Sopenharmony_ci * @port: rvt port
60262306a36Sopenharmony_ci * @port_index: 0 based index of ports, different from IB core port num
60362306a36Sopenharmony_ci * @pkey_table: pkey_table for @port
60462306a36Sopenharmony_ci *
60562306a36Sopenharmony_ci * Keep track of a list of ports. No need to have a detach port.
60662306a36Sopenharmony_ci * They persist until the driver goes away.
60762306a36Sopenharmony_ci *
60862306a36Sopenharmony_ci * Return: always 0
60962306a36Sopenharmony_ci */
61062306a36Sopenharmony_ciint rvt_init_port(struct rvt_dev_info *rdi, struct rvt_ibport *port,
61162306a36Sopenharmony_ci		  int port_index, u16 *pkey_table)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	rdi->ports[port_index] = port;
61562306a36Sopenharmony_ci	rdi->ports[port_index]->pkey_table = pkey_table;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	return 0;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_init_port);
620