1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2025 Broadcom. 3 4 #include <linux/module.h> 5 #include <linux/pci.h> 6 #include <linux/auxiliary_bus.h> 7 8 #include <rdma/ib_verbs.h> 9 10 #include "bng_res.h" 11 #include "bng_fw.h" 12 #include "bng_re.h" 13 #include "bnge.h" 14 #include "bnge_hwrm.h" 15 #include "bnge_auxr.h" 16 17 MODULE_AUTHOR("Siva Reddy Kallam <siva.kallam@broadcom.com>"); 18 MODULE_DESCRIPTION(BNG_RE_DESC); 19 MODULE_LICENSE("Dual BSD/GPL"); 20 21 static struct bng_re_dev *bng_re_dev_add(struct auxiliary_device *adev, 22 struct bnge_auxr_dev *aux_dev) 23 { 24 struct bng_re_dev *rdev; 25 26 /* Allocate bng_re_dev instance */ 27 rdev = ib_alloc_device(bng_re_dev, ibdev); 28 if (!rdev) { 29 pr_err("%s: bng_re_dev allocation failure!", KBUILD_MODNAME); 30 return NULL; 31 } 32 33 /* Assign auxiliary device specific data */ 34 rdev->netdev = aux_dev->net; 35 rdev->aux_dev = aux_dev; 36 rdev->adev = adev; 37 rdev->fn_id = rdev->aux_dev->pdev->devfn; 38 39 return rdev; 40 } 41 42 43 static int bng_re_register_netdev(struct bng_re_dev *rdev) 44 { 45 struct bnge_auxr_dev *aux_dev; 46 47 aux_dev = rdev->aux_dev; 48 return bnge_register_dev(aux_dev, rdev->adev); 49 } 50 51 static void bng_re_destroy_chip_ctx(struct bng_re_dev *rdev) 52 { 53 struct bng_re_chip_ctx *chip_ctx; 54 55 if (!rdev->chip_ctx) 56 return; 57 58 chip_ctx = rdev->chip_ctx; 59 rdev->chip_ctx = NULL; 60 rdev->rcfw.res = NULL; 61 rdev->bng_res.cctx = NULL; 62 rdev->bng_res.pdev = NULL; 63 kfree(chip_ctx); 64 } 65 66 static int bng_re_setup_chip_ctx(struct bng_re_dev *rdev) 67 { 68 struct bng_re_chip_ctx *chip_ctx; 69 struct bnge_auxr_dev *aux_dev; 70 71 aux_dev = rdev->aux_dev; 72 rdev->bng_res.pdev = aux_dev->pdev; 73 rdev->rcfw.res = &rdev->bng_res; 74 chip_ctx = kzalloc(sizeof(*chip_ctx), GFP_KERNEL); 75 if (!chip_ctx) 76 return -ENOMEM; 77 chip_ctx->chip_num = aux_dev->chip_num; 78 chip_ctx->hw_stats_size = aux_dev->hw_ring_stats_size; 79 80 rdev->chip_ctx = chip_ctx; 81 rdev->bng_res.cctx = rdev->chip_ctx; 82 83 return 0; 84 } 85 86 static void bng_re_init_hwrm_hdr(struct input *hdr, u16 opcd) 87 { 88 hdr->req_type = cpu_to_le16(opcd); 89 hdr->cmpl_ring = cpu_to_le16(-1); 90 hdr->target_id = cpu_to_le16(-1); 91 } 92 93 static void bng_re_fill_fw_msg(struct bnge_fw_msg *fw_msg, void *msg, 94 int msg_len, void *resp, int resp_max_len, 95 int timeout) 96 { 97 fw_msg->msg = msg; 98 fw_msg->msg_len = msg_len; 99 fw_msg->resp = resp; 100 fw_msg->resp_max_len = resp_max_len; 101 fw_msg->timeout = timeout; 102 } 103 104 static void bng_re_query_hwrm_version(struct bng_re_dev *rdev) 105 { 106 struct bnge_auxr_dev *aux_dev = rdev->aux_dev; 107 struct hwrm_ver_get_output ver_get_resp = {}; 108 struct hwrm_ver_get_input ver_get_req = {}; 109 struct bng_re_chip_ctx *cctx; 110 struct bnge_fw_msg fw_msg = {}; 111 int rc; 112 113 bng_re_init_hwrm_hdr((void *)&ver_get_req, HWRM_VER_GET); 114 ver_get_req.hwrm_intf_maj = HWRM_VERSION_MAJOR; 115 ver_get_req.hwrm_intf_min = HWRM_VERSION_MINOR; 116 ver_get_req.hwrm_intf_upd = HWRM_VERSION_UPDATE; 117 bng_re_fill_fw_msg(&fw_msg, (void *)&ver_get_req, sizeof(ver_get_req), 118 (void *)&ver_get_resp, sizeof(ver_get_resp), 119 BNGE_DFLT_HWRM_CMD_TIMEOUT); 120 rc = bnge_send_msg(aux_dev, &fw_msg); 121 if (rc) { 122 ibdev_err(&rdev->ibdev, "Failed to query HW version, rc = 0x%x", 123 rc); 124 return; 125 } 126 127 cctx = rdev->chip_ctx; 128 cctx->hwrm_intf_ver = 129 (u64)le16_to_cpu(ver_get_resp.hwrm_intf_major) << 48 | 130 (u64)le16_to_cpu(ver_get_resp.hwrm_intf_minor) << 32 | 131 (u64)le16_to_cpu(ver_get_resp.hwrm_intf_build) << 16 | 132 le16_to_cpu(ver_get_resp.hwrm_intf_patch); 133 134 cctx->hwrm_cmd_max_timeout = le16_to_cpu(ver_get_resp.max_req_timeout); 135 136 if (!cctx->hwrm_cmd_max_timeout) 137 cctx->hwrm_cmd_max_timeout = BNG_ROCE_FW_MAX_TIMEOUT; 138 } 139 140 static void bng_re_dev_uninit(struct bng_re_dev *rdev) 141 { 142 bng_re_free_rcfw_channel(&rdev->rcfw); 143 bng_re_destroy_chip_ctx(rdev); 144 if (test_and_clear_bit(BNG_RE_FLAG_NETDEV_REGISTERED, &rdev->flags)) 145 bnge_unregister_dev(rdev->aux_dev); 146 } 147 148 static int bng_re_dev_init(struct bng_re_dev *rdev) 149 { 150 int rc; 151 152 /* Registered a new RoCE device instance to netdev */ 153 rc = bng_re_register_netdev(rdev); 154 if (rc) { 155 ibdev_err(&rdev->ibdev, 156 "Failed to register with netedev: %#x\n", rc); 157 return -EINVAL; 158 } 159 160 set_bit(BNG_RE_FLAG_NETDEV_REGISTERED, &rdev->flags); 161 162 if (rdev->aux_dev->auxr_info->msix_requested < BNG_RE_MIN_MSIX) { 163 ibdev_err(&rdev->ibdev, 164 "RoCE requires minimum 2 MSI-X vectors, but only %d reserved\n", 165 rdev->aux_dev->auxr_info->msix_requested); 166 bnge_unregister_dev(rdev->aux_dev); 167 clear_bit(BNG_RE_FLAG_NETDEV_REGISTERED, &rdev->flags); 168 return -EINVAL; 169 } 170 ibdev_dbg(&rdev->ibdev, "Got %d MSI-X vectors\n", 171 rdev->aux_dev->auxr_info->msix_requested); 172 173 rc = bng_re_setup_chip_ctx(rdev); 174 if (rc) { 175 bnge_unregister_dev(rdev->aux_dev); 176 clear_bit(BNG_RE_FLAG_NETDEV_REGISTERED, &rdev->flags); 177 ibdev_err(&rdev->ibdev, "Failed to get chip context\n"); 178 return -EINVAL; 179 } 180 181 bng_re_query_hwrm_version(rdev); 182 183 rc = bng_re_alloc_fw_channel(&rdev->bng_res, &rdev->rcfw); 184 if (rc) { 185 ibdev_err(&rdev->ibdev, 186 "Failed to allocate RCFW Channel: %#x\n", rc); 187 goto fail; 188 } 189 190 return 0; 191 192 fail: 193 bng_re_dev_uninit(rdev); 194 return rc; 195 } 196 197 static int bng_re_add_device(struct auxiliary_device *adev) 198 { 199 struct bnge_auxr_priv *auxr_priv = 200 container_of(adev, struct bnge_auxr_priv, aux_dev); 201 struct bng_re_en_dev_info *dev_info; 202 struct bng_re_dev *rdev; 203 int rc; 204 205 dev_info = auxiliary_get_drvdata(adev); 206 207 rdev = bng_re_dev_add(adev, auxr_priv->auxr_dev); 208 if (!rdev) { 209 rc = -ENOMEM; 210 goto exit; 211 } 212 213 dev_info->rdev = rdev; 214 215 rc = bng_re_dev_init(rdev); 216 if (rc) 217 goto re_dev_dealloc; 218 219 return 0; 220 221 re_dev_dealloc: 222 ib_dealloc_device(&rdev->ibdev); 223 exit: 224 return rc; 225 } 226 227 228 static void bng_re_remove_device(struct bng_re_dev *rdev, 229 struct auxiliary_device *aux_dev) 230 { 231 bng_re_dev_uninit(rdev); 232 ib_dealloc_device(&rdev->ibdev); 233 } 234 235 236 static int bng_re_probe(struct auxiliary_device *adev, 237 const struct auxiliary_device_id *id) 238 { 239 struct bnge_auxr_priv *aux_priv = 240 container_of(adev, struct bnge_auxr_priv, aux_dev); 241 struct bng_re_en_dev_info *en_info; 242 int rc; 243 244 en_info = kzalloc(sizeof(*en_info), GFP_KERNEL); 245 if (!en_info) 246 return -ENOMEM; 247 248 en_info->auxr_dev = aux_priv->auxr_dev; 249 250 auxiliary_set_drvdata(adev, en_info); 251 252 rc = bng_re_add_device(adev); 253 if (rc) 254 kfree(en_info); 255 256 return rc; 257 } 258 259 static void bng_re_remove(struct auxiliary_device *adev) 260 { 261 struct bng_re_en_dev_info *dev_info = auxiliary_get_drvdata(adev); 262 struct bng_re_dev *rdev; 263 264 rdev = dev_info->rdev; 265 266 if (rdev) 267 bng_re_remove_device(rdev, adev); 268 kfree(dev_info); 269 } 270 271 static const struct auxiliary_device_id bng_re_id_table[] = { 272 { .name = BNG_RE_ADEV_NAME ".rdma", }, 273 {}, 274 }; 275 276 MODULE_DEVICE_TABLE(auxiliary, bng_re_id_table); 277 278 static struct auxiliary_driver bng_re_driver = { 279 .name = "rdma", 280 .probe = bng_re_probe, 281 .remove = bng_re_remove, 282 .id_table = bng_re_id_table, 283 }; 284 285 static int __init bng_re_mod_init(void) 286 { 287 int rc; 288 289 290 rc = auxiliary_driver_register(&bng_re_driver); 291 if (rc) { 292 pr_err("%s: Failed to register auxiliary driver\n", 293 KBUILD_MODNAME); 294 } 295 return rc; 296 } 297 298 static void __exit bng_re_mod_exit(void) 299 { 300 auxiliary_driver_unregister(&bng_re_driver); 301 } 302 303 module_init(bng_re_mod_init); 304 module_exit(bng_re_mod_exit); 305