18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 48c2ecf20Sopenharmony_ci * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <rdma/rdma_netlink.h> 88c2ecf20Sopenharmony_ci#include <net/addrconf.h> 98c2ecf20Sopenharmony_ci#include "rxe.h" 108c2ecf20Sopenharmony_ci#include "rxe_loc.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ciMODULE_AUTHOR("Bob Pearson, Frank Zago, John Groves, Kamal Heib"); 138c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Soft RDMA transport"); 148c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cibool rxe_initialized; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* free resources for a rxe device all objects created for this device must 198c2ecf20Sopenharmony_ci * have been destroyed 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_civoid rxe_dealloc(struct ib_device *ib_dev) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct rxe_dev *rxe = container_of(ib_dev, struct rxe_dev, ib_dev); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->uc_pool); 268c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->pd_pool); 278c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->ah_pool); 288c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->srq_pool); 298c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->qp_pool); 308c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->cq_pool); 318c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->mr_pool); 328c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->mw_pool); 338c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->mc_grp_pool); 348c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->mc_elem_pool); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (rxe->tfm) 378c2ecf20Sopenharmony_ci crypto_free_shash(rxe->tfm); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* initialize rxe device parameters */ 418c2ecf20Sopenharmony_cistatic void rxe_init_device_param(struct rxe_dev *rxe) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci rxe->max_inline_data = RXE_MAX_INLINE_DATA; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci rxe->attr.vendor_id = RXE_VENDOR_ID; 468c2ecf20Sopenharmony_ci rxe->attr.max_mr_size = RXE_MAX_MR_SIZE; 478c2ecf20Sopenharmony_ci rxe->attr.page_size_cap = RXE_PAGE_SIZE_CAP; 488c2ecf20Sopenharmony_ci rxe->attr.max_qp = RXE_MAX_QP; 498c2ecf20Sopenharmony_ci rxe->attr.max_qp_wr = RXE_MAX_QP_WR; 508c2ecf20Sopenharmony_ci rxe->attr.device_cap_flags = RXE_DEVICE_CAP_FLAGS; 518c2ecf20Sopenharmony_ci rxe->attr.max_send_sge = RXE_MAX_SGE; 528c2ecf20Sopenharmony_ci rxe->attr.max_recv_sge = RXE_MAX_SGE; 538c2ecf20Sopenharmony_ci rxe->attr.max_sge_rd = RXE_MAX_SGE_RD; 548c2ecf20Sopenharmony_ci rxe->attr.max_cq = RXE_MAX_CQ; 558c2ecf20Sopenharmony_ci rxe->attr.max_cqe = (1 << RXE_MAX_LOG_CQE) - 1; 568c2ecf20Sopenharmony_ci rxe->attr.max_mr = RXE_MAX_MR; 578c2ecf20Sopenharmony_ci rxe->attr.max_pd = RXE_MAX_PD; 588c2ecf20Sopenharmony_ci rxe->attr.max_qp_rd_atom = RXE_MAX_QP_RD_ATOM; 598c2ecf20Sopenharmony_ci rxe->attr.max_res_rd_atom = RXE_MAX_RES_RD_ATOM; 608c2ecf20Sopenharmony_ci rxe->attr.max_qp_init_rd_atom = RXE_MAX_QP_INIT_RD_ATOM; 618c2ecf20Sopenharmony_ci rxe->attr.atomic_cap = IB_ATOMIC_HCA; 628c2ecf20Sopenharmony_ci rxe->attr.max_mcast_grp = RXE_MAX_MCAST_GRP; 638c2ecf20Sopenharmony_ci rxe->attr.max_mcast_qp_attach = RXE_MAX_MCAST_QP_ATTACH; 648c2ecf20Sopenharmony_ci rxe->attr.max_total_mcast_qp_attach = RXE_MAX_TOT_MCAST_QP_ATTACH; 658c2ecf20Sopenharmony_ci rxe->attr.max_ah = RXE_MAX_AH; 668c2ecf20Sopenharmony_ci rxe->attr.max_srq = RXE_MAX_SRQ; 678c2ecf20Sopenharmony_ci rxe->attr.max_srq_wr = RXE_MAX_SRQ_WR; 688c2ecf20Sopenharmony_ci rxe->attr.max_srq_sge = RXE_MAX_SRQ_SGE; 698c2ecf20Sopenharmony_ci rxe->attr.max_fast_reg_page_list_len = RXE_MAX_FMR_PAGE_LIST_LEN; 708c2ecf20Sopenharmony_ci rxe->attr.max_pkeys = RXE_MAX_PKEYS; 718c2ecf20Sopenharmony_ci rxe->attr.local_ca_ack_delay = RXE_LOCAL_CA_ACK_DELAY; 728c2ecf20Sopenharmony_ci addrconf_addr_eui48((unsigned char *)&rxe->attr.sys_image_guid, 738c2ecf20Sopenharmony_ci rxe->ndev->dev_addr); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci rxe->max_ucontext = RXE_MAX_UCONTEXT; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* initialize port attributes */ 798c2ecf20Sopenharmony_cistatic void rxe_init_port_param(struct rxe_port *port) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci port->attr.state = IB_PORT_DOWN; 828c2ecf20Sopenharmony_ci port->attr.max_mtu = IB_MTU_4096; 838c2ecf20Sopenharmony_ci port->attr.active_mtu = IB_MTU_256; 848c2ecf20Sopenharmony_ci port->attr.gid_tbl_len = RXE_PORT_GID_TBL_LEN; 858c2ecf20Sopenharmony_ci port->attr.port_cap_flags = RXE_PORT_PORT_CAP_FLAGS; 868c2ecf20Sopenharmony_ci port->attr.max_msg_sz = RXE_PORT_MAX_MSG_SZ; 878c2ecf20Sopenharmony_ci port->attr.bad_pkey_cntr = RXE_PORT_BAD_PKEY_CNTR; 888c2ecf20Sopenharmony_ci port->attr.qkey_viol_cntr = RXE_PORT_QKEY_VIOL_CNTR; 898c2ecf20Sopenharmony_ci port->attr.pkey_tbl_len = RXE_PORT_PKEY_TBL_LEN; 908c2ecf20Sopenharmony_ci port->attr.lid = RXE_PORT_LID; 918c2ecf20Sopenharmony_ci port->attr.sm_lid = RXE_PORT_SM_LID; 928c2ecf20Sopenharmony_ci port->attr.lmc = RXE_PORT_LMC; 938c2ecf20Sopenharmony_ci port->attr.max_vl_num = RXE_PORT_MAX_VL_NUM; 948c2ecf20Sopenharmony_ci port->attr.sm_sl = RXE_PORT_SM_SL; 958c2ecf20Sopenharmony_ci port->attr.subnet_timeout = RXE_PORT_SUBNET_TIMEOUT; 968c2ecf20Sopenharmony_ci port->attr.init_type_reply = RXE_PORT_INIT_TYPE_REPLY; 978c2ecf20Sopenharmony_ci port->attr.active_width = RXE_PORT_ACTIVE_WIDTH; 988c2ecf20Sopenharmony_ci port->attr.active_speed = RXE_PORT_ACTIVE_SPEED; 998c2ecf20Sopenharmony_ci port->attr.phys_state = RXE_PORT_PHYS_STATE; 1008c2ecf20Sopenharmony_ci port->mtu_cap = ib_mtu_enum_to_int(IB_MTU_256); 1018c2ecf20Sopenharmony_ci port->subnet_prefix = cpu_to_be64(RXE_PORT_SUBNET_PREFIX); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* initialize port state, note IB convention that HCA ports are always 1058c2ecf20Sopenharmony_ci * numbered from 1 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_cistatic void rxe_init_ports(struct rxe_dev *rxe) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct rxe_port *port = &rxe->port; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci rxe_init_port_param(port); 1128c2ecf20Sopenharmony_ci addrconf_addr_eui48((unsigned char *)&port->port_guid, 1138c2ecf20Sopenharmony_ci rxe->ndev->dev_addr); 1148c2ecf20Sopenharmony_ci spin_lock_init(&port->port_lock); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* init pools of managed objects */ 1188c2ecf20Sopenharmony_cistatic int rxe_init_pools(struct rxe_dev *rxe) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci int err; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci err = rxe_pool_init(rxe, &rxe->uc_pool, RXE_TYPE_UC, 1238c2ecf20Sopenharmony_ci rxe->max_ucontext); 1248c2ecf20Sopenharmony_ci if (err) 1258c2ecf20Sopenharmony_ci goto err1; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci err = rxe_pool_init(rxe, &rxe->pd_pool, RXE_TYPE_PD, 1288c2ecf20Sopenharmony_ci rxe->attr.max_pd); 1298c2ecf20Sopenharmony_ci if (err) 1308c2ecf20Sopenharmony_ci goto err2; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci err = rxe_pool_init(rxe, &rxe->ah_pool, RXE_TYPE_AH, 1338c2ecf20Sopenharmony_ci rxe->attr.max_ah); 1348c2ecf20Sopenharmony_ci if (err) 1358c2ecf20Sopenharmony_ci goto err3; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci err = rxe_pool_init(rxe, &rxe->srq_pool, RXE_TYPE_SRQ, 1388c2ecf20Sopenharmony_ci rxe->attr.max_srq); 1398c2ecf20Sopenharmony_ci if (err) 1408c2ecf20Sopenharmony_ci goto err4; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci err = rxe_pool_init(rxe, &rxe->qp_pool, RXE_TYPE_QP, 1438c2ecf20Sopenharmony_ci rxe->attr.max_qp); 1448c2ecf20Sopenharmony_ci if (err) 1458c2ecf20Sopenharmony_ci goto err5; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci err = rxe_pool_init(rxe, &rxe->cq_pool, RXE_TYPE_CQ, 1488c2ecf20Sopenharmony_ci rxe->attr.max_cq); 1498c2ecf20Sopenharmony_ci if (err) 1508c2ecf20Sopenharmony_ci goto err6; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci err = rxe_pool_init(rxe, &rxe->mr_pool, RXE_TYPE_MR, 1538c2ecf20Sopenharmony_ci rxe->attr.max_mr); 1548c2ecf20Sopenharmony_ci if (err) 1558c2ecf20Sopenharmony_ci goto err7; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci err = rxe_pool_init(rxe, &rxe->mw_pool, RXE_TYPE_MW, 1588c2ecf20Sopenharmony_ci rxe->attr.max_mw); 1598c2ecf20Sopenharmony_ci if (err) 1608c2ecf20Sopenharmony_ci goto err8; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci err = rxe_pool_init(rxe, &rxe->mc_grp_pool, RXE_TYPE_MC_GRP, 1638c2ecf20Sopenharmony_ci rxe->attr.max_mcast_grp); 1648c2ecf20Sopenharmony_ci if (err) 1658c2ecf20Sopenharmony_ci goto err9; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci err = rxe_pool_init(rxe, &rxe->mc_elem_pool, RXE_TYPE_MC_ELEM, 1688c2ecf20Sopenharmony_ci rxe->attr.max_total_mcast_qp_attach); 1698c2ecf20Sopenharmony_ci if (err) 1708c2ecf20Sopenharmony_ci goto err10; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cierr10: 1758c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->mc_grp_pool); 1768c2ecf20Sopenharmony_cierr9: 1778c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->mw_pool); 1788c2ecf20Sopenharmony_cierr8: 1798c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->mr_pool); 1808c2ecf20Sopenharmony_cierr7: 1818c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->cq_pool); 1828c2ecf20Sopenharmony_cierr6: 1838c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->qp_pool); 1848c2ecf20Sopenharmony_cierr5: 1858c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->srq_pool); 1868c2ecf20Sopenharmony_cierr4: 1878c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->ah_pool); 1888c2ecf20Sopenharmony_cierr3: 1898c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->pd_pool); 1908c2ecf20Sopenharmony_cierr2: 1918c2ecf20Sopenharmony_ci rxe_pool_cleanup(&rxe->uc_pool); 1928c2ecf20Sopenharmony_cierr1: 1938c2ecf20Sopenharmony_ci return err; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* initialize rxe device state */ 1978c2ecf20Sopenharmony_cistatic int rxe_init(struct rxe_dev *rxe) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci int err; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* init default device parameters */ 2028c2ecf20Sopenharmony_ci rxe_init_device_param(rxe); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci rxe_init_ports(rxe); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci err = rxe_init_pools(rxe); 2078c2ecf20Sopenharmony_ci if (err) 2088c2ecf20Sopenharmony_ci return err; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* init pending mmap list */ 2118c2ecf20Sopenharmony_ci spin_lock_init(&rxe->mmap_offset_lock); 2128c2ecf20Sopenharmony_ci spin_lock_init(&rxe->pending_lock); 2138c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rxe->pending_mmaps); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci mutex_init(&rxe->usdev_lock); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_civoid rxe_set_mtu(struct rxe_dev *rxe, unsigned int ndev_mtu) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct rxe_port *port = &rxe->port; 2238c2ecf20Sopenharmony_ci enum ib_mtu mtu; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci mtu = eth_mtu_int_to_enum(ndev_mtu); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* Make sure that new MTU in range */ 2288c2ecf20Sopenharmony_ci mtu = mtu ? min_t(enum ib_mtu, mtu, IB_MTU_4096) : IB_MTU_256; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci port->attr.active_mtu = mtu; 2318c2ecf20Sopenharmony_ci port->mtu_cap = ib_mtu_enum_to_int(mtu); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* called by ifc layer to create new rxe device. 2358c2ecf20Sopenharmony_ci * The caller should allocate memory for rxe by calling ib_alloc_device. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ciint rxe_add(struct rxe_dev *rxe, unsigned int mtu, const char *ibdev_name) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci int err; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci err = rxe_init(rxe); 2428c2ecf20Sopenharmony_ci if (err) 2438c2ecf20Sopenharmony_ci return err; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci rxe_set_mtu(rxe, mtu); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return rxe_register_device(rxe, ibdev_name); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int rxe_newlink(const char *ibdev_name, struct net_device *ndev) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct rxe_dev *exists; 2538c2ecf20Sopenharmony_ci int err = 0; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (is_vlan_dev(ndev)) { 2568c2ecf20Sopenharmony_ci pr_err("rxe creation allowed on top of a real device only\n"); 2578c2ecf20Sopenharmony_ci err = -EPERM; 2588c2ecf20Sopenharmony_ci goto err; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci exists = rxe_get_dev_from_net(ndev); 2628c2ecf20Sopenharmony_ci if (exists) { 2638c2ecf20Sopenharmony_ci ib_device_put(&exists->ib_dev); 2648c2ecf20Sopenharmony_ci pr_err("already configured on %s\n", ndev->name); 2658c2ecf20Sopenharmony_ci err = -EEXIST; 2668c2ecf20Sopenharmony_ci goto err; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci err = rxe_net_add(ibdev_name, ndev); 2708c2ecf20Sopenharmony_ci if (err) { 2718c2ecf20Sopenharmony_ci pr_err("failed to add %s\n", ndev->name); 2728c2ecf20Sopenharmony_ci goto err; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_cierr: 2758c2ecf20Sopenharmony_ci return err; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic struct rdma_link_ops rxe_link_ops = { 2798c2ecf20Sopenharmony_ci .type = "rxe", 2808c2ecf20Sopenharmony_ci .newlink = rxe_newlink, 2818c2ecf20Sopenharmony_ci}; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int __init rxe_module_init(void) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci int err; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci err = rxe_net_init(); 2888c2ecf20Sopenharmony_ci if (err) 2898c2ecf20Sopenharmony_ci return err; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci rdma_link_register(&rxe_link_ops); 2928c2ecf20Sopenharmony_ci rxe_initialized = true; 2938c2ecf20Sopenharmony_ci pr_info("loaded\n"); 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic void __exit rxe_module_exit(void) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci rdma_link_unregister(&rxe_link_ops); 3008c2ecf20Sopenharmony_ci ib_unregister_driver(RDMA_DRIVER_RXE); 3018c2ecf20Sopenharmony_ci rxe_net_exit(); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci rxe_initialized = false; 3048c2ecf20Sopenharmony_ci pr_info("unloaded\n"); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cilate_initcall(rxe_module_init); 3088c2ecf20Sopenharmony_cimodule_exit(rxe_module_exit); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciMODULE_ALIAS_RDMA_LINK("rxe"); 311