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