18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Shared Memory Communications over RDMA (SMC-R) and RoCE 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * IB infrastructure: 68c2ecf20Sopenharmony_ci * Establish SMC-R as an Infiniband Client to be notified about added and 78c2ecf20Sopenharmony_ci * removed IB devices of type RDMA. 88c2ecf20Sopenharmony_ci * Determine device and port characteristics for these IB devices. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2016 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Author(s): Ursula Braun <ubraun@linux.vnet.ibm.com> 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/random.h> 168c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 178c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 188c2ecf20Sopenharmony_ci#include <linux/wait.h> 198c2ecf20Sopenharmony_ci#include <linux/mutex.h> 208c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h> 218c2ecf20Sopenharmony_ci#include <rdma/ib_cache.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "smc_pnet.h" 248c2ecf20Sopenharmony_ci#include "smc_ib.h" 258c2ecf20Sopenharmony_ci#include "smc_core.h" 268c2ecf20Sopenharmony_ci#include "smc_wr.h" 278c2ecf20Sopenharmony_ci#include "smc.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define SMC_MAX_CQE 32766 /* max. # of completion queue elements */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define SMC_QP_MIN_RNR_TIMER 5 328c2ecf20Sopenharmony_ci#define SMC_QP_TIMEOUT 15 /* 4096 * 2 ** timeout usec */ 338c2ecf20Sopenharmony_ci#define SMC_QP_RETRY_CNT 7 /* 7: infinite */ 348c2ecf20Sopenharmony_ci#define SMC_QP_RNR_RETRY 7 /* 7: infinite */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct smc_ib_devices smc_ib_devices = { /* smc-registered ib devices */ 378c2ecf20Sopenharmony_ci .mutex = __MUTEX_INITIALIZER(smc_ib_devices.mutex), 388c2ecf20Sopenharmony_ci .list = LIST_HEAD_INIT(smc_ib_devices.list), 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciu8 local_systemid[SMC_SYSTEMID_LEN]; /* unique system identifier */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int smc_ib_modify_qp_init(struct smc_link *lnk) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct ib_qp_attr qp_attr; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci memset(&qp_attr, 0, sizeof(qp_attr)); 488c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_INIT; 498c2ecf20Sopenharmony_ci qp_attr.pkey_index = 0; 508c2ecf20Sopenharmony_ci qp_attr.port_num = lnk->ibport; 518c2ecf20Sopenharmony_ci qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE 528c2ecf20Sopenharmony_ci | IB_ACCESS_REMOTE_WRITE; 538c2ecf20Sopenharmony_ci return ib_modify_qp(lnk->roce_qp, &qp_attr, 548c2ecf20Sopenharmony_ci IB_QP_STATE | IB_QP_PKEY_INDEX | 558c2ecf20Sopenharmony_ci IB_QP_ACCESS_FLAGS | IB_QP_PORT); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int smc_ib_modify_qp_rtr(struct smc_link *lnk) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci enum ib_qp_attr_mask qp_attr_mask = 618c2ecf20Sopenharmony_ci IB_QP_STATE | IB_QP_AV | IB_QP_PATH_MTU | IB_QP_DEST_QPN | 628c2ecf20Sopenharmony_ci IB_QP_RQ_PSN | IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_MIN_RNR_TIMER; 638c2ecf20Sopenharmony_ci struct ib_qp_attr qp_attr; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci memset(&qp_attr, 0, sizeof(qp_attr)); 668c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_RTR; 678c2ecf20Sopenharmony_ci qp_attr.path_mtu = min(lnk->path_mtu, lnk->peer_mtu); 688c2ecf20Sopenharmony_ci qp_attr.ah_attr.type = RDMA_AH_ATTR_TYPE_ROCE; 698c2ecf20Sopenharmony_ci rdma_ah_set_port_num(&qp_attr.ah_attr, lnk->ibport); 708c2ecf20Sopenharmony_ci rdma_ah_set_grh(&qp_attr.ah_attr, NULL, 0, lnk->sgid_index, 1, 0); 718c2ecf20Sopenharmony_ci rdma_ah_set_dgid_raw(&qp_attr.ah_attr, lnk->peer_gid); 728c2ecf20Sopenharmony_ci memcpy(&qp_attr.ah_attr.roce.dmac, lnk->peer_mac, 738c2ecf20Sopenharmony_ci sizeof(lnk->peer_mac)); 748c2ecf20Sopenharmony_ci qp_attr.dest_qp_num = lnk->peer_qpn; 758c2ecf20Sopenharmony_ci qp_attr.rq_psn = lnk->peer_psn; /* starting receive packet seq # */ 768c2ecf20Sopenharmony_ci qp_attr.max_dest_rd_atomic = 1; /* max # of resources for incoming 778c2ecf20Sopenharmony_ci * requests 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ci qp_attr.min_rnr_timer = SMC_QP_MIN_RNR_TIMER; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return ib_modify_qp(lnk->roce_qp, &qp_attr, qp_attr_mask); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciint smc_ib_modify_qp_rts(struct smc_link *lnk) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct ib_qp_attr qp_attr; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci memset(&qp_attr, 0, sizeof(qp_attr)); 898c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_RTS; 908c2ecf20Sopenharmony_ci qp_attr.timeout = SMC_QP_TIMEOUT; /* local ack timeout */ 918c2ecf20Sopenharmony_ci qp_attr.retry_cnt = SMC_QP_RETRY_CNT; /* retry count */ 928c2ecf20Sopenharmony_ci qp_attr.rnr_retry = SMC_QP_RNR_RETRY; /* RNR retries, 7=infinite */ 938c2ecf20Sopenharmony_ci qp_attr.sq_psn = lnk->psn_initial; /* starting send packet seq # */ 948c2ecf20Sopenharmony_ci qp_attr.max_rd_atomic = 1; /* # of outstanding RDMA reads and 958c2ecf20Sopenharmony_ci * atomic ops allowed 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci return ib_modify_qp(lnk->roce_qp, &qp_attr, 988c2ecf20Sopenharmony_ci IB_QP_STATE | IB_QP_TIMEOUT | IB_QP_RETRY_CNT | 998c2ecf20Sopenharmony_ci IB_QP_SQ_PSN | IB_QP_RNR_RETRY | 1008c2ecf20Sopenharmony_ci IB_QP_MAX_QP_RD_ATOMIC); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciint smc_ib_modify_qp_error(struct smc_link *lnk) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct ib_qp_attr qp_attr; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci memset(&qp_attr, 0, sizeof(qp_attr)); 1088c2ecf20Sopenharmony_ci qp_attr.qp_state = IB_QPS_ERR; 1098c2ecf20Sopenharmony_ci return ib_modify_qp(lnk->roce_qp, &qp_attr, IB_QP_STATE); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciint smc_ib_ready_link(struct smc_link *lnk) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct smc_link_group *lgr = smc_get_lgr(lnk); 1158c2ecf20Sopenharmony_ci int rc = 0; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci rc = smc_ib_modify_qp_init(lnk); 1188c2ecf20Sopenharmony_ci if (rc) 1198c2ecf20Sopenharmony_ci goto out; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci rc = smc_ib_modify_qp_rtr(lnk); 1228c2ecf20Sopenharmony_ci if (rc) 1238c2ecf20Sopenharmony_ci goto out; 1248c2ecf20Sopenharmony_ci smc_wr_remember_qp_attr(lnk); 1258c2ecf20Sopenharmony_ci rc = ib_req_notify_cq(lnk->smcibdev->roce_cq_recv, 1268c2ecf20Sopenharmony_ci IB_CQ_SOLICITED_MASK); 1278c2ecf20Sopenharmony_ci if (rc) 1288c2ecf20Sopenharmony_ci goto out; 1298c2ecf20Sopenharmony_ci rc = smc_wr_rx_post_init(lnk); 1308c2ecf20Sopenharmony_ci if (rc) 1318c2ecf20Sopenharmony_ci goto out; 1328c2ecf20Sopenharmony_ci smc_wr_remember_qp_attr(lnk); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (lgr->role == SMC_SERV) { 1358c2ecf20Sopenharmony_ci rc = smc_ib_modify_qp_rts(lnk); 1368c2ecf20Sopenharmony_ci if (rc) 1378c2ecf20Sopenharmony_ci goto out; 1388c2ecf20Sopenharmony_ci smc_wr_remember_qp_attr(lnk); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ciout: 1418c2ecf20Sopenharmony_ci return rc; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int smc_ib_fill_mac(struct smc_ib_device *smcibdev, u8 ibport) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci const struct ib_gid_attr *attr; 1478c2ecf20Sopenharmony_ci int rc; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci attr = rdma_get_gid_attr(smcibdev->ibdev, ibport, 0); 1508c2ecf20Sopenharmony_ci if (IS_ERR(attr)) 1518c2ecf20Sopenharmony_ci return -ENODEV; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci rc = rdma_read_gid_l2_fields(attr, NULL, smcibdev->mac[ibport - 1]); 1548c2ecf20Sopenharmony_ci rdma_put_gid_attr(attr); 1558c2ecf20Sopenharmony_ci return rc; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* Create an identifier unique for this instance of SMC-R. 1598c2ecf20Sopenharmony_ci * The MAC-address of the first active registered IB device 1608c2ecf20Sopenharmony_ci * plus a random 2-byte number is used to create this identifier. 1618c2ecf20Sopenharmony_ci * This name is delivered to the peer during connection initialization. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_cistatic inline void smc_ib_define_local_systemid(struct smc_ib_device *smcibdev, 1648c2ecf20Sopenharmony_ci u8 ibport) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci memcpy(&local_systemid[2], &smcibdev->mac[ibport - 1], 1678c2ecf20Sopenharmony_ci sizeof(smcibdev->mac[ibport - 1])); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cibool smc_ib_is_valid_local_systemid(void) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci return !is_zero_ether_addr(&local_systemid[2]); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic void smc_ib_init_local_systemid(void) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci get_random_bytes(&local_systemid[0], 2); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cibool smc_ib_port_active(struct smc_ib_device *smcibdev, u8 ibport) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci return smcibdev->pattr[ibport - 1].state == IB_PORT_ACTIVE; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/* determine the gid for an ib-device port and vlan id */ 1868c2ecf20Sopenharmony_ciint smc_ib_determine_gid(struct smc_ib_device *smcibdev, u8 ibport, 1878c2ecf20Sopenharmony_ci unsigned short vlan_id, u8 gid[], u8 *sgid_index) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci const struct ib_gid_attr *attr; 1908c2ecf20Sopenharmony_ci const struct net_device *ndev; 1918c2ecf20Sopenharmony_ci int i; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci for (i = 0; i < smcibdev->pattr[ibport - 1].gid_tbl_len; i++) { 1948c2ecf20Sopenharmony_ci attr = rdma_get_gid_attr(smcibdev->ibdev, ibport, i); 1958c2ecf20Sopenharmony_ci if (IS_ERR(attr)) 1968c2ecf20Sopenharmony_ci continue; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci rcu_read_lock(); 1998c2ecf20Sopenharmony_ci ndev = rdma_read_gid_attr_ndev_rcu(attr); 2008c2ecf20Sopenharmony_ci if (!IS_ERR(ndev) && 2018c2ecf20Sopenharmony_ci ((!vlan_id && !is_vlan_dev(ndev)) || 2028c2ecf20Sopenharmony_ci (vlan_id && is_vlan_dev(ndev) && 2038c2ecf20Sopenharmony_ci vlan_dev_vlan_id(ndev) == vlan_id)) && 2048c2ecf20Sopenharmony_ci attr->gid_type == IB_GID_TYPE_ROCE) { 2058c2ecf20Sopenharmony_ci rcu_read_unlock(); 2068c2ecf20Sopenharmony_ci if (gid) 2078c2ecf20Sopenharmony_ci memcpy(gid, &attr->gid, SMC_GID_SIZE); 2088c2ecf20Sopenharmony_ci if (sgid_index) 2098c2ecf20Sopenharmony_ci *sgid_index = attr->index; 2108c2ecf20Sopenharmony_ci rdma_put_gid_attr(attr); 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci rcu_read_unlock(); 2148c2ecf20Sopenharmony_ci rdma_put_gid_attr(attr); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci return -ENODEV; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int smc_ib_remember_port_attr(struct smc_ib_device *smcibdev, u8 ibport) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci int rc; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci memset(&smcibdev->pattr[ibport - 1], 0, 2248c2ecf20Sopenharmony_ci sizeof(smcibdev->pattr[ibport - 1])); 2258c2ecf20Sopenharmony_ci rc = ib_query_port(smcibdev->ibdev, ibport, 2268c2ecf20Sopenharmony_ci &smcibdev->pattr[ibport - 1]); 2278c2ecf20Sopenharmony_ci if (rc) 2288c2ecf20Sopenharmony_ci goto out; 2298c2ecf20Sopenharmony_ci /* the SMC protocol requires specification of the RoCE MAC address */ 2308c2ecf20Sopenharmony_ci rc = smc_ib_fill_mac(smcibdev, ibport); 2318c2ecf20Sopenharmony_ci if (rc) 2328c2ecf20Sopenharmony_ci goto out; 2338c2ecf20Sopenharmony_ci if (!smc_ib_is_valid_local_systemid() && 2348c2ecf20Sopenharmony_ci smc_ib_port_active(smcibdev, ibport)) 2358c2ecf20Sopenharmony_ci /* create unique system identifier */ 2368c2ecf20Sopenharmony_ci smc_ib_define_local_systemid(smcibdev, ibport); 2378c2ecf20Sopenharmony_ciout: 2388c2ecf20Sopenharmony_ci return rc; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* process context wrapper for might_sleep smc_ib_remember_port_attr */ 2428c2ecf20Sopenharmony_cistatic void smc_ib_port_event_work(struct work_struct *work) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct smc_ib_device *smcibdev = container_of( 2458c2ecf20Sopenharmony_ci work, struct smc_ib_device, port_event_work); 2468c2ecf20Sopenharmony_ci u8 port_idx; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci for_each_set_bit(port_idx, &smcibdev->port_event_mask, SMC_MAX_PORTS) { 2498c2ecf20Sopenharmony_ci smc_ib_remember_port_attr(smcibdev, port_idx + 1); 2508c2ecf20Sopenharmony_ci clear_bit(port_idx, &smcibdev->port_event_mask); 2518c2ecf20Sopenharmony_ci if (!smc_ib_port_active(smcibdev, port_idx + 1)) { 2528c2ecf20Sopenharmony_ci set_bit(port_idx, smcibdev->ports_going_away); 2538c2ecf20Sopenharmony_ci smcr_port_err(smcibdev, port_idx + 1); 2548c2ecf20Sopenharmony_ci } else { 2558c2ecf20Sopenharmony_ci clear_bit(port_idx, smcibdev->ports_going_away); 2568c2ecf20Sopenharmony_ci smcr_port_add(smcibdev, port_idx + 1); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* can be called in IRQ context */ 2628c2ecf20Sopenharmony_cistatic void smc_ib_global_event_handler(struct ib_event_handler *handler, 2638c2ecf20Sopenharmony_ci struct ib_event *ibevent) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct smc_ib_device *smcibdev; 2668c2ecf20Sopenharmony_ci bool schedule = false; 2678c2ecf20Sopenharmony_ci u8 port_idx; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci smcibdev = container_of(handler, struct smc_ib_device, event_handler); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci switch (ibevent->event) { 2728c2ecf20Sopenharmony_ci case IB_EVENT_DEVICE_FATAL: 2738c2ecf20Sopenharmony_ci /* terminate all ports on device */ 2748c2ecf20Sopenharmony_ci for (port_idx = 0; port_idx < SMC_MAX_PORTS; port_idx++) { 2758c2ecf20Sopenharmony_ci set_bit(port_idx, &smcibdev->port_event_mask); 2768c2ecf20Sopenharmony_ci if (!test_and_set_bit(port_idx, 2778c2ecf20Sopenharmony_ci smcibdev->ports_going_away)) 2788c2ecf20Sopenharmony_ci schedule = true; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci if (schedule) 2818c2ecf20Sopenharmony_ci schedule_work(&smcibdev->port_event_work); 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci case IB_EVENT_PORT_ACTIVE: 2848c2ecf20Sopenharmony_ci port_idx = ibevent->element.port_num - 1; 2858c2ecf20Sopenharmony_ci if (port_idx >= SMC_MAX_PORTS) 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci set_bit(port_idx, &smcibdev->port_event_mask); 2888c2ecf20Sopenharmony_ci if (test_and_clear_bit(port_idx, smcibdev->ports_going_away)) 2898c2ecf20Sopenharmony_ci schedule_work(&smcibdev->port_event_work); 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci case IB_EVENT_PORT_ERR: 2928c2ecf20Sopenharmony_ci port_idx = ibevent->element.port_num - 1; 2938c2ecf20Sopenharmony_ci if (port_idx >= SMC_MAX_PORTS) 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci set_bit(port_idx, &smcibdev->port_event_mask); 2968c2ecf20Sopenharmony_ci if (!test_and_set_bit(port_idx, smcibdev->ports_going_away)) 2978c2ecf20Sopenharmony_ci schedule_work(&smcibdev->port_event_work); 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci case IB_EVENT_GID_CHANGE: 3008c2ecf20Sopenharmony_ci port_idx = ibevent->element.port_num - 1; 3018c2ecf20Sopenharmony_ci if (port_idx >= SMC_MAX_PORTS) 3028c2ecf20Sopenharmony_ci break; 3038c2ecf20Sopenharmony_ci set_bit(port_idx, &smcibdev->port_event_mask); 3048c2ecf20Sopenharmony_ci schedule_work(&smcibdev->port_event_work); 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci default: 3078c2ecf20Sopenharmony_ci break; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_civoid smc_ib_dealloc_protection_domain(struct smc_link *lnk) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci if (lnk->roce_pd) 3148c2ecf20Sopenharmony_ci ib_dealloc_pd(lnk->roce_pd); 3158c2ecf20Sopenharmony_ci lnk->roce_pd = NULL; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ciint smc_ib_create_protection_domain(struct smc_link *lnk) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci int rc; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci lnk->roce_pd = ib_alloc_pd(lnk->smcibdev->ibdev, 0); 3238c2ecf20Sopenharmony_ci rc = PTR_ERR_OR_ZERO(lnk->roce_pd); 3248c2ecf20Sopenharmony_ci if (IS_ERR(lnk->roce_pd)) 3258c2ecf20Sopenharmony_ci lnk->roce_pd = NULL; 3268c2ecf20Sopenharmony_ci return rc; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void smc_ib_qp_event_handler(struct ib_event *ibevent, void *priv) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct smc_link *lnk = (struct smc_link *)priv; 3328c2ecf20Sopenharmony_ci struct smc_ib_device *smcibdev = lnk->smcibdev; 3338c2ecf20Sopenharmony_ci u8 port_idx; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci switch (ibevent->event) { 3368c2ecf20Sopenharmony_ci case IB_EVENT_QP_FATAL: 3378c2ecf20Sopenharmony_ci case IB_EVENT_QP_ACCESS_ERR: 3388c2ecf20Sopenharmony_ci port_idx = ibevent->element.qp->port - 1; 3398c2ecf20Sopenharmony_ci if (port_idx >= SMC_MAX_PORTS) 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci set_bit(port_idx, &smcibdev->port_event_mask); 3428c2ecf20Sopenharmony_ci if (!test_and_set_bit(port_idx, smcibdev->ports_going_away)) 3438c2ecf20Sopenharmony_ci schedule_work(&smcibdev->port_event_work); 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci default: 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_civoid smc_ib_destroy_queue_pair(struct smc_link *lnk) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci if (lnk->roce_qp) 3538c2ecf20Sopenharmony_ci ib_destroy_qp(lnk->roce_qp); 3548c2ecf20Sopenharmony_ci lnk->roce_qp = NULL; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/* create a queue pair within the protection domain for a link */ 3588c2ecf20Sopenharmony_ciint smc_ib_create_queue_pair(struct smc_link *lnk) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct ib_qp_init_attr qp_attr = { 3618c2ecf20Sopenharmony_ci .event_handler = smc_ib_qp_event_handler, 3628c2ecf20Sopenharmony_ci .qp_context = lnk, 3638c2ecf20Sopenharmony_ci .send_cq = lnk->smcibdev->roce_cq_send, 3648c2ecf20Sopenharmony_ci .recv_cq = lnk->smcibdev->roce_cq_recv, 3658c2ecf20Sopenharmony_ci .srq = NULL, 3668c2ecf20Sopenharmony_ci .cap = { 3678c2ecf20Sopenharmony_ci /* include unsolicited rdma_writes as well, 3688c2ecf20Sopenharmony_ci * there are max. 2 RDMA_WRITE per 1 WR_SEND 3698c2ecf20Sopenharmony_ci */ 3708c2ecf20Sopenharmony_ci .max_send_wr = SMC_WR_BUF_CNT * 3, 3718c2ecf20Sopenharmony_ci .max_recv_wr = SMC_WR_BUF_CNT * 3, 3728c2ecf20Sopenharmony_ci .max_send_sge = SMC_IB_MAX_SEND_SGE, 3738c2ecf20Sopenharmony_ci .max_recv_sge = 1, 3748c2ecf20Sopenharmony_ci }, 3758c2ecf20Sopenharmony_ci .sq_sig_type = IB_SIGNAL_REQ_WR, 3768c2ecf20Sopenharmony_ci .qp_type = IB_QPT_RC, 3778c2ecf20Sopenharmony_ci }; 3788c2ecf20Sopenharmony_ci int rc; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci lnk->roce_qp = ib_create_qp(lnk->roce_pd, &qp_attr); 3818c2ecf20Sopenharmony_ci rc = PTR_ERR_OR_ZERO(lnk->roce_qp); 3828c2ecf20Sopenharmony_ci if (IS_ERR(lnk->roce_qp)) 3838c2ecf20Sopenharmony_ci lnk->roce_qp = NULL; 3848c2ecf20Sopenharmony_ci else 3858c2ecf20Sopenharmony_ci smc_wr_remember_qp_attr(lnk); 3868c2ecf20Sopenharmony_ci return rc; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_civoid smc_ib_put_memory_region(struct ib_mr *mr) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci ib_dereg_mr(mr); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic int smc_ib_map_mr_sg(struct smc_buf_desc *buf_slot, u8 link_idx) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci unsigned int offset = 0; 3978c2ecf20Sopenharmony_ci int sg_num; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* map the largest prefix of a dma mapped SG list */ 4008c2ecf20Sopenharmony_ci sg_num = ib_map_mr_sg(buf_slot->mr_rx[link_idx], 4018c2ecf20Sopenharmony_ci buf_slot->sgt[link_idx].sgl, 4028c2ecf20Sopenharmony_ci buf_slot->sgt[link_idx].orig_nents, 4038c2ecf20Sopenharmony_ci &offset, PAGE_SIZE); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return sg_num; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci/* Allocate a memory region and map the dma mapped SG list of buf_slot */ 4098c2ecf20Sopenharmony_ciint smc_ib_get_memory_region(struct ib_pd *pd, int access_flags, 4108c2ecf20Sopenharmony_ci struct smc_buf_desc *buf_slot, u8 link_idx) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci if (buf_slot->mr_rx[link_idx]) 4138c2ecf20Sopenharmony_ci return 0; /* already done */ 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci buf_slot->mr_rx[link_idx] = 4168c2ecf20Sopenharmony_ci ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, 1 << buf_slot->order); 4178c2ecf20Sopenharmony_ci if (IS_ERR(buf_slot->mr_rx[link_idx])) { 4188c2ecf20Sopenharmony_ci int rc; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci rc = PTR_ERR(buf_slot->mr_rx[link_idx]); 4218c2ecf20Sopenharmony_ci buf_slot->mr_rx[link_idx] = NULL; 4228c2ecf20Sopenharmony_ci return rc; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (smc_ib_map_mr_sg(buf_slot, link_idx) != 1) 4268c2ecf20Sopenharmony_ci return -EINVAL; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/* synchronize buffer usage for cpu access */ 4328c2ecf20Sopenharmony_civoid smc_ib_sync_sg_for_cpu(struct smc_link *lnk, 4338c2ecf20Sopenharmony_ci struct smc_buf_desc *buf_slot, 4348c2ecf20Sopenharmony_ci enum dma_data_direction data_direction) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct scatterlist *sg; 4378c2ecf20Sopenharmony_ci unsigned int i; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* for now there is just one DMA address */ 4408c2ecf20Sopenharmony_ci for_each_sg(buf_slot->sgt[lnk->link_idx].sgl, sg, 4418c2ecf20Sopenharmony_ci buf_slot->sgt[lnk->link_idx].nents, i) { 4428c2ecf20Sopenharmony_ci if (!sg_dma_len(sg)) 4438c2ecf20Sopenharmony_ci break; 4448c2ecf20Sopenharmony_ci ib_dma_sync_single_for_cpu(lnk->smcibdev->ibdev, 4458c2ecf20Sopenharmony_ci sg_dma_address(sg), 4468c2ecf20Sopenharmony_ci sg_dma_len(sg), 4478c2ecf20Sopenharmony_ci data_direction); 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci/* synchronize buffer usage for device access */ 4528c2ecf20Sopenharmony_civoid smc_ib_sync_sg_for_device(struct smc_link *lnk, 4538c2ecf20Sopenharmony_ci struct smc_buf_desc *buf_slot, 4548c2ecf20Sopenharmony_ci enum dma_data_direction data_direction) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct scatterlist *sg; 4578c2ecf20Sopenharmony_ci unsigned int i; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* for now there is just one DMA address */ 4608c2ecf20Sopenharmony_ci for_each_sg(buf_slot->sgt[lnk->link_idx].sgl, sg, 4618c2ecf20Sopenharmony_ci buf_slot->sgt[lnk->link_idx].nents, i) { 4628c2ecf20Sopenharmony_ci if (!sg_dma_len(sg)) 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci ib_dma_sync_single_for_device(lnk->smcibdev->ibdev, 4658c2ecf20Sopenharmony_ci sg_dma_address(sg), 4668c2ecf20Sopenharmony_ci sg_dma_len(sg), 4678c2ecf20Sopenharmony_ci data_direction); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/* Map a new TX or RX buffer SG-table to DMA */ 4728c2ecf20Sopenharmony_ciint smc_ib_buf_map_sg(struct smc_link *lnk, 4738c2ecf20Sopenharmony_ci struct smc_buf_desc *buf_slot, 4748c2ecf20Sopenharmony_ci enum dma_data_direction data_direction) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci int mapped_nents; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci mapped_nents = ib_dma_map_sg(lnk->smcibdev->ibdev, 4798c2ecf20Sopenharmony_ci buf_slot->sgt[lnk->link_idx].sgl, 4808c2ecf20Sopenharmony_ci buf_slot->sgt[lnk->link_idx].orig_nents, 4818c2ecf20Sopenharmony_ci data_direction); 4828c2ecf20Sopenharmony_ci if (!mapped_nents) 4838c2ecf20Sopenharmony_ci return -ENOMEM; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return mapped_nents; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_civoid smc_ib_buf_unmap_sg(struct smc_link *lnk, 4898c2ecf20Sopenharmony_ci struct smc_buf_desc *buf_slot, 4908c2ecf20Sopenharmony_ci enum dma_data_direction data_direction) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci if (!buf_slot->sgt[lnk->link_idx].sgl->dma_address) 4938c2ecf20Sopenharmony_ci return; /* already unmapped */ 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci ib_dma_unmap_sg(lnk->smcibdev->ibdev, 4968c2ecf20Sopenharmony_ci buf_slot->sgt[lnk->link_idx].sgl, 4978c2ecf20Sopenharmony_ci buf_slot->sgt[lnk->link_idx].orig_nents, 4988c2ecf20Sopenharmony_ci data_direction); 4998c2ecf20Sopenharmony_ci buf_slot->sgt[lnk->link_idx].sgl->dma_address = 0; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cilong smc_ib_setup_per_ibdev(struct smc_ib_device *smcibdev) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci struct ib_cq_init_attr cqattr = { 5058c2ecf20Sopenharmony_ci .cqe = SMC_MAX_CQE, .comp_vector = 0 }; 5068c2ecf20Sopenharmony_ci int cqe_size_order, smc_order; 5078c2ecf20Sopenharmony_ci long rc; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci mutex_lock(&smcibdev->mutex); 5108c2ecf20Sopenharmony_ci rc = 0; 5118c2ecf20Sopenharmony_ci if (smcibdev->initialized) 5128c2ecf20Sopenharmony_ci goto out; 5138c2ecf20Sopenharmony_ci /* the calculated number of cq entries fits to mlx5 cq allocation */ 5148c2ecf20Sopenharmony_ci cqe_size_order = cache_line_size() == 128 ? 7 : 6; 5158c2ecf20Sopenharmony_ci smc_order = MAX_ORDER - cqe_size_order - 1; 5168c2ecf20Sopenharmony_ci if (SMC_MAX_CQE + 2 > (0x00000001 << smc_order) * PAGE_SIZE) 5178c2ecf20Sopenharmony_ci cqattr.cqe = (0x00000001 << smc_order) * PAGE_SIZE - 2; 5188c2ecf20Sopenharmony_ci smcibdev->roce_cq_send = ib_create_cq(smcibdev->ibdev, 5198c2ecf20Sopenharmony_ci smc_wr_tx_cq_handler, NULL, 5208c2ecf20Sopenharmony_ci smcibdev, &cqattr); 5218c2ecf20Sopenharmony_ci rc = PTR_ERR_OR_ZERO(smcibdev->roce_cq_send); 5228c2ecf20Sopenharmony_ci if (IS_ERR(smcibdev->roce_cq_send)) { 5238c2ecf20Sopenharmony_ci smcibdev->roce_cq_send = NULL; 5248c2ecf20Sopenharmony_ci goto out; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci smcibdev->roce_cq_recv = ib_create_cq(smcibdev->ibdev, 5278c2ecf20Sopenharmony_ci smc_wr_rx_cq_handler, NULL, 5288c2ecf20Sopenharmony_ci smcibdev, &cqattr); 5298c2ecf20Sopenharmony_ci rc = PTR_ERR_OR_ZERO(smcibdev->roce_cq_recv); 5308c2ecf20Sopenharmony_ci if (IS_ERR(smcibdev->roce_cq_recv)) { 5318c2ecf20Sopenharmony_ci smcibdev->roce_cq_recv = NULL; 5328c2ecf20Sopenharmony_ci goto err; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci smc_wr_add_dev(smcibdev); 5358c2ecf20Sopenharmony_ci smcibdev->initialized = 1; 5368c2ecf20Sopenharmony_ci goto out; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cierr: 5398c2ecf20Sopenharmony_ci ib_destroy_cq(smcibdev->roce_cq_send); 5408c2ecf20Sopenharmony_ciout: 5418c2ecf20Sopenharmony_ci mutex_unlock(&smcibdev->mutex); 5428c2ecf20Sopenharmony_ci return rc; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic void smc_ib_cleanup_per_ibdev(struct smc_ib_device *smcibdev) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci mutex_lock(&smcibdev->mutex); 5488c2ecf20Sopenharmony_ci if (!smcibdev->initialized) 5498c2ecf20Sopenharmony_ci goto out; 5508c2ecf20Sopenharmony_ci smcibdev->initialized = 0; 5518c2ecf20Sopenharmony_ci ib_destroy_cq(smcibdev->roce_cq_recv); 5528c2ecf20Sopenharmony_ci ib_destroy_cq(smcibdev->roce_cq_send); 5538c2ecf20Sopenharmony_ci smc_wr_remove_dev(smcibdev); 5548c2ecf20Sopenharmony_ciout: 5558c2ecf20Sopenharmony_ci mutex_unlock(&smcibdev->mutex); 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic struct ib_client smc_ib_client; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci/* callback function for ib_register_client() */ 5618c2ecf20Sopenharmony_cistatic int smc_ib_add_dev(struct ib_device *ibdev) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct smc_ib_device *smcibdev; 5648c2ecf20Sopenharmony_ci u8 port_cnt; 5658c2ecf20Sopenharmony_ci int i; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (ibdev->node_type != RDMA_NODE_IB_CA) 5688c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci smcibdev = kzalloc(sizeof(*smcibdev), GFP_KERNEL); 5718c2ecf20Sopenharmony_ci if (!smcibdev) 5728c2ecf20Sopenharmony_ci return -ENOMEM; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci smcibdev->ibdev = ibdev; 5758c2ecf20Sopenharmony_ci INIT_WORK(&smcibdev->port_event_work, smc_ib_port_event_work); 5768c2ecf20Sopenharmony_ci atomic_set(&smcibdev->lnk_cnt, 0); 5778c2ecf20Sopenharmony_ci init_waitqueue_head(&smcibdev->lnks_deleted); 5788c2ecf20Sopenharmony_ci mutex_init(&smcibdev->mutex); 5798c2ecf20Sopenharmony_ci mutex_lock(&smc_ib_devices.mutex); 5808c2ecf20Sopenharmony_ci list_add_tail(&smcibdev->list, &smc_ib_devices.list); 5818c2ecf20Sopenharmony_ci mutex_unlock(&smc_ib_devices.mutex); 5828c2ecf20Sopenharmony_ci ib_set_client_data(ibdev, &smc_ib_client, smcibdev); 5838c2ecf20Sopenharmony_ci INIT_IB_EVENT_HANDLER(&smcibdev->event_handler, smcibdev->ibdev, 5848c2ecf20Sopenharmony_ci smc_ib_global_event_handler); 5858c2ecf20Sopenharmony_ci ib_register_event_handler(&smcibdev->event_handler); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* trigger reading of the port attributes */ 5888c2ecf20Sopenharmony_ci port_cnt = smcibdev->ibdev->phys_port_cnt; 5898c2ecf20Sopenharmony_ci pr_warn_ratelimited("smc: adding ib device %s with port count %d\n", 5908c2ecf20Sopenharmony_ci smcibdev->ibdev->name, port_cnt); 5918c2ecf20Sopenharmony_ci for (i = 0; 5928c2ecf20Sopenharmony_ci i < min_t(size_t, port_cnt, SMC_MAX_PORTS); 5938c2ecf20Sopenharmony_ci i++) { 5948c2ecf20Sopenharmony_ci set_bit(i, &smcibdev->port_event_mask); 5958c2ecf20Sopenharmony_ci /* determine pnetids of the port */ 5968c2ecf20Sopenharmony_ci if (smc_pnetid_by_dev_port(ibdev->dev.parent, i, 5978c2ecf20Sopenharmony_ci smcibdev->pnetid[i])) 5988c2ecf20Sopenharmony_ci smc_pnetid_by_table_ib(smcibdev, i + 1); 5998c2ecf20Sopenharmony_ci pr_warn_ratelimited("smc: ib device %s port %d has pnetid " 6008c2ecf20Sopenharmony_ci "%.16s%s\n", 6018c2ecf20Sopenharmony_ci smcibdev->ibdev->name, i + 1, 6028c2ecf20Sopenharmony_ci smcibdev->pnetid[i], 6038c2ecf20Sopenharmony_ci smcibdev->pnetid_by_user[i] ? 6048c2ecf20Sopenharmony_ci " (user defined)" : 6058c2ecf20Sopenharmony_ci ""); 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci schedule_work(&smcibdev->port_event_work); 6088c2ecf20Sopenharmony_ci return 0; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/* callback function for ib_unregister_client() */ 6128c2ecf20Sopenharmony_cistatic void smc_ib_remove_dev(struct ib_device *ibdev, void *client_data) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct smc_ib_device *smcibdev = client_data; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci mutex_lock(&smc_ib_devices.mutex); 6178c2ecf20Sopenharmony_ci list_del_init(&smcibdev->list); /* remove from smc_ib_devices */ 6188c2ecf20Sopenharmony_ci mutex_unlock(&smc_ib_devices.mutex); 6198c2ecf20Sopenharmony_ci pr_warn_ratelimited("smc: removing ib device %s\n", 6208c2ecf20Sopenharmony_ci smcibdev->ibdev->name); 6218c2ecf20Sopenharmony_ci smc_smcr_terminate_all(smcibdev); 6228c2ecf20Sopenharmony_ci smc_ib_cleanup_per_ibdev(smcibdev); 6238c2ecf20Sopenharmony_ci ib_unregister_event_handler(&smcibdev->event_handler); 6248c2ecf20Sopenharmony_ci cancel_work_sync(&smcibdev->port_event_work); 6258c2ecf20Sopenharmony_ci kfree(smcibdev); 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic struct ib_client smc_ib_client = { 6298c2ecf20Sopenharmony_ci .name = "smc_ib", 6308c2ecf20Sopenharmony_ci .add = smc_ib_add_dev, 6318c2ecf20Sopenharmony_ci .remove = smc_ib_remove_dev, 6328c2ecf20Sopenharmony_ci}; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ciint __init smc_ib_register_client(void) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci smc_ib_init_local_systemid(); 6378c2ecf20Sopenharmony_ci return ib_register_client(&smc_ib_client); 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_civoid smc_ib_unregister_client(void) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci ib_unregister_client(&smc_ib_client); 6438c2ecf20Sopenharmony_ci} 644