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