1*1249c01aSStefan Metzmacher // SPDX-License-Identifier: GPL-2.0-or-later 2*1249c01aSStefan Metzmacher /* 3*1249c01aSStefan Metzmacher * Copyright (C) 2017, Microsoft Corporation. 4*1249c01aSStefan Metzmacher * Copyright (C) 2018, LG Electronics. 5*1249c01aSStefan Metzmacher * Copyright (c) 2025 Stefan Metzmacher 6*1249c01aSStefan Metzmacher */ 7*1249c01aSStefan Metzmacher 8*1249c01aSStefan Metzmacher #include "internal.h" 9*1249c01aSStefan Metzmacher 10*1249c01aSStefan Metzmacher static u8 smbdirect_ib_device_rdma_capable_node_type(struct ib_device *ib_dev) 11*1249c01aSStefan Metzmacher { 12*1249c01aSStefan Metzmacher if (!smbdirect_frwr_is_supported(&ib_dev->attrs)) 13*1249c01aSStefan Metzmacher return RDMA_NODE_UNSPECIFIED; 14*1249c01aSStefan Metzmacher 15*1249c01aSStefan Metzmacher switch (ib_dev->node_type) { 16*1249c01aSStefan Metzmacher case RDMA_NODE_IB_CA: /* Infiniband, RoCE v1 and v2 */ 17*1249c01aSStefan Metzmacher case RDMA_NODE_RNIC: /* iWarp */ 18*1249c01aSStefan Metzmacher return ib_dev->node_type; 19*1249c01aSStefan Metzmacher } 20*1249c01aSStefan Metzmacher 21*1249c01aSStefan Metzmacher return RDMA_NODE_UNSPECIFIED; 22*1249c01aSStefan Metzmacher } 23*1249c01aSStefan Metzmacher 24*1249c01aSStefan Metzmacher static int smbdirect_ib_client_add(struct ib_device *ib_dev) 25*1249c01aSStefan Metzmacher { 26*1249c01aSStefan Metzmacher u8 node_type = smbdirect_ib_device_rdma_capable_node_type(ib_dev); 27*1249c01aSStefan Metzmacher struct smbdirect_device *sdev; 28*1249c01aSStefan Metzmacher const char *node_str; 29*1249c01aSStefan Metzmacher const char *action; 30*1249c01aSStefan Metzmacher u32 pidx; 31*1249c01aSStefan Metzmacher 32*1249c01aSStefan Metzmacher switch (node_type) { 33*1249c01aSStefan Metzmacher case RDMA_NODE_IB_CA: 34*1249c01aSStefan Metzmacher node_str = "IB_CA"; 35*1249c01aSStefan Metzmacher action = "added"; 36*1249c01aSStefan Metzmacher break; 37*1249c01aSStefan Metzmacher case RDMA_NODE_RNIC: 38*1249c01aSStefan Metzmacher node_str = "RNIC"; 39*1249c01aSStefan Metzmacher action = "added"; 40*1249c01aSStefan Metzmacher break; 41*1249c01aSStefan Metzmacher case RDMA_NODE_UNSPECIFIED: 42*1249c01aSStefan Metzmacher node_str = "UNSPECIFIED"; 43*1249c01aSStefan Metzmacher action = "ignored"; 44*1249c01aSStefan Metzmacher break; 45*1249c01aSStefan Metzmacher default: 46*1249c01aSStefan Metzmacher node_str = "UNKNOWN"; 47*1249c01aSStefan Metzmacher action = "ignored"; 48*1249c01aSStefan Metzmacher node_type = RDMA_NODE_UNSPECIFIED; 49*1249c01aSStefan Metzmacher break; 50*1249c01aSStefan Metzmacher } 51*1249c01aSStefan Metzmacher 52*1249c01aSStefan Metzmacher pr_info("ib_dev[%.*s]: %s: %s %s=%u %s=0x%llx %s=0x%llx %s=0x%llx\n", 53*1249c01aSStefan Metzmacher IB_DEVICE_NAME_MAX, 54*1249c01aSStefan Metzmacher ib_dev->name, 55*1249c01aSStefan Metzmacher action, 56*1249c01aSStefan Metzmacher node_str, 57*1249c01aSStefan Metzmacher "max_fast_reg_page_list_len", 58*1249c01aSStefan Metzmacher ib_dev->attrs.max_fast_reg_page_list_len, 59*1249c01aSStefan Metzmacher "device_cap_flags", 60*1249c01aSStefan Metzmacher ib_dev->attrs.device_cap_flags, 61*1249c01aSStefan Metzmacher "kernel_cap_flags", 62*1249c01aSStefan Metzmacher ib_dev->attrs.kernel_cap_flags, 63*1249c01aSStefan Metzmacher "page_size_cap", 64*1249c01aSStefan Metzmacher ib_dev->attrs.page_size_cap); 65*1249c01aSStefan Metzmacher 66*1249c01aSStefan Metzmacher if (node_type == RDMA_NODE_UNSPECIFIED) 67*1249c01aSStefan Metzmacher return 0; 68*1249c01aSStefan Metzmacher 69*1249c01aSStefan Metzmacher pr_info("ib_dev[%.*s]: %s=%u %s=%u %s=%u %s=%u %s=%u %s=%u %s=%u %s=%u %s=%u\n", 70*1249c01aSStefan Metzmacher IB_DEVICE_NAME_MAX, 71*1249c01aSStefan Metzmacher ib_dev->name, 72*1249c01aSStefan Metzmacher "num_ports", 73*1249c01aSStefan Metzmacher rdma_end_port(ib_dev), 74*1249c01aSStefan Metzmacher "max_qp_rd_atom", 75*1249c01aSStefan Metzmacher ib_dev->attrs.max_qp_rd_atom, 76*1249c01aSStefan Metzmacher "max_qp_init_rd_atom", 77*1249c01aSStefan Metzmacher ib_dev->attrs.max_qp_init_rd_atom, 78*1249c01aSStefan Metzmacher "max_sgl_rd", 79*1249c01aSStefan Metzmacher ib_dev->attrs.max_sgl_rd, 80*1249c01aSStefan Metzmacher "max_sge_rd", 81*1249c01aSStefan Metzmacher ib_dev->attrs.max_sge_rd, 82*1249c01aSStefan Metzmacher "max_cqe", 83*1249c01aSStefan Metzmacher ib_dev->attrs.max_cqe, 84*1249c01aSStefan Metzmacher "max_qp_wr", 85*1249c01aSStefan Metzmacher ib_dev->attrs.max_qp_wr, 86*1249c01aSStefan Metzmacher "max_send_sge", 87*1249c01aSStefan Metzmacher ib_dev->attrs.max_send_sge, 88*1249c01aSStefan Metzmacher "max_recv_sge", 89*1249c01aSStefan Metzmacher ib_dev->attrs.max_recv_sge); 90*1249c01aSStefan Metzmacher 91*1249c01aSStefan Metzmacher rdma_for_each_port(ib_dev, pidx) { 92*1249c01aSStefan Metzmacher const struct ib_port_immutable *ib_pi = 93*1249c01aSStefan Metzmacher ib_port_immutable_read(ib_dev, pidx); 94*1249c01aSStefan Metzmacher u32 core_cap_flags = ib_pi ? ib_pi->core_cap_flags : 0; 95*1249c01aSStefan Metzmacher 96*1249c01aSStefan Metzmacher pr_info("ib_dev[%.*s]PORT[%u]: %s=%u %s=%u %s=%u %s=%u %s=%u %s=0x%x\n", 97*1249c01aSStefan Metzmacher IB_DEVICE_NAME_MAX, 98*1249c01aSStefan Metzmacher ib_dev->name, 99*1249c01aSStefan Metzmacher pidx, 100*1249c01aSStefan Metzmacher "iwarp", 101*1249c01aSStefan Metzmacher rdma_protocol_iwarp(ib_dev, pidx), 102*1249c01aSStefan Metzmacher "ib", 103*1249c01aSStefan Metzmacher rdma_protocol_ib(ib_dev, pidx), 104*1249c01aSStefan Metzmacher "roce", 105*1249c01aSStefan Metzmacher rdma_protocol_roce(ib_dev, pidx), 106*1249c01aSStefan Metzmacher "v1", 107*1249c01aSStefan Metzmacher rdma_protocol_roce_eth_encap(ib_dev, pidx), 108*1249c01aSStefan Metzmacher "v2", 109*1249c01aSStefan Metzmacher rdma_protocol_roce_udp_encap(ib_dev, pidx), 110*1249c01aSStefan Metzmacher "core_cap_flags", 111*1249c01aSStefan Metzmacher core_cap_flags); 112*1249c01aSStefan Metzmacher } 113*1249c01aSStefan Metzmacher 114*1249c01aSStefan Metzmacher sdev = kzalloc_obj(*sdev); 115*1249c01aSStefan Metzmacher if (!sdev) 116*1249c01aSStefan Metzmacher return -ENOMEM; 117*1249c01aSStefan Metzmacher sdev->ib_dev = ib_dev; 118*1249c01aSStefan Metzmacher snprintf(sdev->ib_name, ARRAY_SIZE(sdev->ib_name), "%.*s", 119*1249c01aSStefan Metzmacher IB_DEVICE_NAME_MAX, ib_dev->name); 120*1249c01aSStefan Metzmacher 121*1249c01aSStefan Metzmacher write_lock(&smbdirect_globals.devices.lock); 122*1249c01aSStefan Metzmacher list_add(&sdev->list, &smbdirect_globals.devices.list); 123*1249c01aSStefan Metzmacher write_unlock(&smbdirect_globals.devices.lock); 124*1249c01aSStefan Metzmacher 125*1249c01aSStefan Metzmacher return 0; 126*1249c01aSStefan Metzmacher } 127*1249c01aSStefan Metzmacher 128*1249c01aSStefan Metzmacher static void smbdirect_ib_client_remove(struct ib_device *ib_dev, void *client_data) 129*1249c01aSStefan Metzmacher { 130*1249c01aSStefan Metzmacher struct smbdirect_device *sdev, *tmp; 131*1249c01aSStefan Metzmacher 132*1249c01aSStefan Metzmacher write_lock(&smbdirect_globals.devices.lock); 133*1249c01aSStefan Metzmacher list_for_each_entry_safe(sdev, tmp, &smbdirect_globals.devices.list, list) { 134*1249c01aSStefan Metzmacher if (sdev->ib_dev == ib_dev) { 135*1249c01aSStefan Metzmacher list_del(&sdev->list); 136*1249c01aSStefan Metzmacher pr_info("ib_dev[%.*s] removed\n", 137*1249c01aSStefan Metzmacher IB_DEVICE_NAME_MAX, sdev->ib_name); 138*1249c01aSStefan Metzmacher kfree(sdev); 139*1249c01aSStefan Metzmacher break; 140*1249c01aSStefan Metzmacher } 141*1249c01aSStefan Metzmacher } 142*1249c01aSStefan Metzmacher write_unlock(&smbdirect_globals.devices.lock); 143*1249c01aSStefan Metzmacher } 144*1249c01aSStefan Metzmacher 145*1249c01aSStefan Metzmacher static void smbdirect_ib_client_rename(struct ib_device *ib_dev, void *client_data) 146*1249c01aSStefan Metzmacher { 147*1249c01aSStefan Metzmacher struct smbdirect_device *sdev; 148*1249c01aSStefan Metzmacher 149*1249c01aSStefan Metzmacher write_lock(&smbdirect_globals.devices.lock); 150*1249c01aSStefan Metzmacher list_for_each_entry(sdev, &smbdirect_globals.devices.list, list) { 151*1249c01aSStefan Metzmacher if (sdev->ib_dev == ib_dev) { 152*1249c01aSStefan Metzmacher pr_info("ib_dev[%.*s] renamed to [%.*s]\n", 153*1249c01aSStefan Metzmacher IB_DEVICE_NAME_MAX, sdev->ib_name, 154*1249c01aSStefan Metzmacher IB_DEVICE_NAME_MAX, ib_dev->name); 155*1249c01aSStefan Metzmacher snprintf(sdev->ib_name, ARRAY_SIZE(sdev->ib_name), "%.*s", 156*1249c01aSStefan Metzmacher IB_DEVICE_NAME_MAX, ib_dev->name); 157*1249c01aSStefan Metzmacher break; 158*1249c01aSStefan Metzmacher } 159*1249c01aSStefan Metzmacher } 160*1249c01aSStefan Metzmacher write_unlock(&smbdirect_globals.devices.lock); 161*1249c01aSStefan Metzmacher } 162*1249c01aSStefan Metzmacher 163*1249c01aSStefan Metzmacher static struct ib_client smbdirect_ib_client = { 164*1249c01aSStefan Metzmacher .name = "smbdirect_ib_client", 165*1249c01aSStefan Metzmacher .add = smbdirect_ib_client_add, 166*1249c01aSStefan Metzmacher .remove = smbdirect_ib_client_remove, 167*1249c01aSStefan Metzmacher .rename = smbdirect_ib_client_rename, 168*1249c01aSStefan Metzmacher }; 169*1249c01aSStefan Metzmacher 170*1249c01aSStefan Metzmacher static u8 smbdirect_netdev_find_rdma_capable_node_type(struct net_device *netdev) 171*1249c01aSStefan Metzmacher { 172*1249c01aSStefan Metzmacher struct smbdirect_device *sdev; 173*1249c01aSStefan Metzmacher u8 node_type = RDMA_NODE_UNSPECIFIED; 174*1249c01aSStefan Metzmacher 175*1249c01aSStefan Metzmacher read_lock(&smbdirect_globals.devices.lock); 176*1249c01aSStefan Metzmacher list_for_each_entry(sdev, &smbdirect_globals.devices.list, list) { 177*1249c01aSStefan Metzmacher u32 pi; 178*1249c01aSStefan Metzmacher 179*1249c01aSStefan Metzmacher rdma_for_each_port(sdev->ib_dev, pi) { 180*1249c01aSStefan Metzmacher struct net_device *ndev; 181*1249c01aSStefan Metzmacher 182*1249c01aSStefan Metzmacher ndev = ib_device_get_netdev(sdev->ib_dev, pi); 183*1249c01aSStefan Metzmacher if (!ndev) 184*1249c01aSStefan Metzmacher continue; 185*1249c01aSStefan Metzmacher 186*1249c01aSStefan Metzmacher if (ndev == netdev) { 187*1249c01aSStefan Metzmacher dev_put(ndev); 188*1249c01aSStefan Metzmacher node_type = sdev->ib_dev->node_type; 189*1249c01aSStefan Metzmacher goto out; 190*1249c01aSStefan Metzmacher } 191*1249c01aSStefan Metzmacher dev_put(ndev); 192*1249c01aSStefan Metzmacher } 193*1249c01aSStefan Metzmacher } 194*1249c01aSStefan Metzmacher out: 195*1249c01aSStefan Metzmacher read_unlock(&smbdirect_globals.devices.lock); 196*1249c01aSStefan Metzmacher 197*1249c01aSStefan Metzmacher if (node_type == RDMA_NODE_UNSPECIFIED) { 198*1249c01aSStefan Metzmacher struct ib_device *ibdev; 199*1249c01aSStefan Metzmacher 200*1249c01aSStefan Metzmacher ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_UNKNOWN); 201*1249c01aSStefan Metzmacher if (ibdev) { 202*1249c01aSStefan Metzmacher node_type = smbdirect_ib_device_rdma_capable_node_type(ibdev); 203*1249c01aSStefan Metzmacher ib_device_put(ibdev); 204*1249c01aSStefan Metzmacher } 205*1249c01aSStefan Metzmacher } 206*1249c01aSStefan Metzmacher 207*1249c01aSStefan Metzmacher return node_type; 208*1249c01aSStefan Metzmacher } 209*1249c01aSStefan Metzmacher 210*1249c01aSStefan Metzmacher /* 211*1249c01aSStefan Metzmacher * Returns RDMA_NODE_UNSPECIFIED when the netdev has 212*1249c01aSStefan Metzmacher * no support for smbdirect capable rdma. 213*1249c01aSStefan Metzmacher * 214*1249c01aSStefan Metzmacher * Otherwise RDMA_NODE_RNIC is returned for iwarp devices 215*1249c01aSStefan Metzmacher * and RDMA_NODE_IB_CA or Infiniband and RoCE (v1 and v2) 216*1249c01aSStefan Metzmacher */ 217*1249c01aSStefan Metzmacher u8 smbdirect_netdev_rdma_capable_node_type(struct net_device *netdev) 218*1249c01aSStefan Metzmacher { 219*1249c01aSStefan Metzmacher struct net_device *lower_dev; 220*1249c01aSStefan Metzmacher struct list_head *iter; 221*1249c01aSStefan Metzmacher u8 node_type = RDMA_NODE_UNSPECIFIED; 222*1249c01aSStefan Metzmacher 223*1249c01aSStefan Metzmacher node_type = smbdirect_netdev_find_rdma_capable_node_type(netdev); 224*1249c01aSStefan Metzmacher if (node_type != RDMA_NODE_UNSPECIFIED) 225*1249c01aSStefan Metzmacher return node_type; 226*1249c01aSStefan Metzmacher 227*1249c01aSStefan Metzmacher /* check if netdev is bridge or VLAN */ 228*1249c01aSStefan Metzmacher if (netif_is_bridge_master(netdev) || netdev->priv_flags & IFF_802_1Q_VLAN) 229*1249c01aSStefan Metzmacher netdev_for_each_lower_dev(netdev, lower_dev, iter) { 230*1249c01aSStefan Metzmacher node_type = smbdirect_netdev_find_rdma_capable_node_type(lower_dev); 231*1249c01aSStefan Metzmacher if (node_type != RDMA_NODE_UNSPECIFIED) 232*1249c01aSStefan Metzmacher return node_type; 233*1249c01aSStefan Metzmacher } 234*1249c01aSStefan Metzmacher 235*1249c01aSStefan Metzmacher /* check if netdev is IPoIB safely without layer violation */ 236*1249c01aSStefan Metzmacher if (netdev->type == ARPHRD_INFINIBAND) 237*1249c01aSStefan Metzmacher return RDMA_NODE_IB_CA; 238*1249c01aSStefan Metzmacher 239*1249c01aSStefan Metzmacher return RDMA_NODE_UNSPECIFIED; 240*1249c01aSStefan Metzmacher } 241*1249c01aSStefan Metzmacher __SMBDIRECT_EXPORT_SYMBOL__(smbdirect_netdev_rdma_capable_node_type); 242*1249c01aSStefan Metzmacher 243*1249c01aSStefan Metzmacher __init int smbdirect_devices_init(void) 244*1249c01aSStefan Metzmacher { 245*1249c01aSStefan Metzmacher int ret; 246*1249c01aSStefan Metzmacher 247*1249c01aSStefan Metzmacher rwlock_init(&smbdirect_globals.devices.lock); 248*1249c01aSStefan Metzmacher INIT_LIST_HEAD(&smbdirect_globals.devices.list); 249*1249c01aSStefan Metzmacher 250*1249c01aSStefan Metzmacher ret = ib_register_client(&smbdirect_ib_client); 251*1249c01aSStefan Metzmacher if (ret) { 252*1249c01aSStefan Metzmacher pr_crit("failed to ib_register_client: %d %1pe\n", 253*1249c01aSStefan Metzmacher ret, SMBDIRECT_DEBUG_ERR_PTR(ret)); 254*1249c01aSStefan Metzmacher return ret; 255*1249c01aSStefan Metzmacher } 256*1249c01aSStefan Metzmacher 257*1249c01aSStefan Metzmacher return 0; 258*1249c01aSStefan Metzmacher } 259*1249c01aSStefan Metzmacher 260*1249c01aSStefan Metzmacher __exit void smbdirect_devices_exit(void) 261*1249c01aSStefan Metzmacher { 262*1249c01aSStefan Metzmacher struct smbdirect_device *sdev, *tmp; 263*1249c01aSStefan Metzmacher 264*1249c01aSStefan Metzmacher /* 265*1249c01aSStefan Metzmacher * On exist we just cleanup so that 266*1249c01aSStefan Metzmacher * smbdirect_ib_client_remove() won't 267*1249c01aSStefan Metzmacher * print removals of devices. 268*1249c01aSStefan Metzmacher */ 269*1249c01aSStefan Metzmacher write_lock(&smbdirect_globals.devices.lock); 270*1249c01aSStefan Metzmacher list_for_each_entry_safe(sdev, tmp, &smbdirect_globals.devices.list, list) { 271*1249c01aSStefan Metzmacher list_del(&sdev->list); 272*1249c01aSStefan Metzmacher kfree(sdev); 273*1249c01aSStefan Metzmacher } 274*1249c01aSStefan Metzmacher write_unlock(&smbdirect_globals.devices.lock); 275*1249c01aSStefan Metzmacher 276*1249c01aSStefan Metzmacher ib_unregister_client(&smbdirect_ib_client); 277*1249c01aSStefan Metzmacher } 278