1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (C) 2025 Intel Corporation */ 3 4 #include <linux/export.h> 5 6 #include "idpf.h" 7 #include "idpf_virtchnl.h" 8 9 static DEFINE_IDA(idpf_idc_ida); 10 11 #define IDPF_IDC_MAX_ADEV_NAME_LEN 15 12 13 /** 14 * idpf_idc_init - Called to initialize IDC 15 * @adapter: driver private data structure 16 * 17 * Return: 0 on success or cap not enabled, error code on failure. 18 */ 19 int idpf_idc_init(struct idpf_adapter *adapter) 20 { 21 int err; 22 23 if (!idpf_is_rdma_cap_ena(adapter) || 24 !adapter->dev_ops.idc_init) 25 return 0; 26 27 err = adapter->dev_ops.idc_init(adapter); 28 if (err) 29 dev_err(&adapter->pdev->dev, "failed to initialize idc: %d\n", 30 err); 31 32 return err; 33 } 34 35 /** 36 * idpf_vport_adev_release - function to be mapped to aux dev's release op 37 * @dev: pointer to device to free 38 */ 39 static void idpf_vport_adev_release(struct device *dev) 40 { 41 struct iidc_rdma_vport_auxiliary_dev *iadev; 42 43 iadev = container_of(dev, struct iidc_rdma_vport_auxiliary_dev, adev.dev); 44 kfree(iadev); 45 iadev = NULL; 46 } 47 48 /** 49 * idpf_plug_vport_aux_dev - allocate and register a vport Auxiliary device 50 * @cdev_info: IDC core device info pointer 51 * @vdev_info: IDC vport device info pointer 52 * 53 * Return: 0 on success or error code on failure. 54 */ 55 static int idpf_plug_vport_aux_dev(struct iidc_rdma_core_dev_info *cdev_info, 56 struct iidc_rdma_vport_dev_info *vdev_info) 57 { 58 struct iidc_rdma_vport_auxiliary_dev *iadev; 59 char name[IDPF_IDC_MAX_ADEV_NAME_LEN]; 60 struct auxiliary_device *adev; 61 int ret; 62 63 iadev = kzalloc(sizeof(*iadev), GFP_KERNEL); 64 if (!iadev) 65 return -ENOMEM; 66 67 adev = &iadev->adev; 68 vdev_info->adev = &iadev->adev; 69 iadev->vdev_info = vdev_info; 70 71 ret = ida_alloc(&idpf_idc_ida, GFP_KERNEL); 72 if (ret < 0) { 73 pr_err("failed to allocate unique device ID for Auxiliary driver\n"); 74 goto err_ida_alloc; 75 } 76 adev->id = ret; 77 adev->dev.release = idpf_vport_adev_release; 78 adev->dev.parent = &cdev_info->pdev->dev; 79 sprintf(name, "%04x.rdma.vdev", cdev_info->pdev->vendor); 80 adev->name = name; 81 82 ret = auxiliary_device_init(adev); 83 if (ret) 84 goto err_aux_dev_init; 85 86 ret = auxiliary_device_add(adev); 87 if (ret) 88 goto err_aux_dev_add; 89 90 return 0; 91 92 err_aux_dev_add: 93 auxiliary_device_uninit(adev); 94 err_aux_dev_init: 95 ida_free(&idpf_idc_ida, adev->id); 96 err_ida_alloc: 97 vdev_info->adev = NULL; 98 kfree(iadev); 99 100 return ret; 101 } 102 103 /** 104 * idpf_idc_init_aux_vport_dev - initialize vport Auxiliary Device(s) 105 * @vport: virtual port data struct 106 * 107 * Return: 0 on success or error code on failure. 108 */ 109 static int idpf_idc_init_aux_vport_dev(struct idpf_vport *vport) 110 { 111 struct idpf_adapter *adapter = vport->adapter; 112 struct iidc_rdma_vport_dev_info *vdev_info; 113 struct iidc_rdma_core_dev_info *cdev_info; 114 struct virtchnl2_create_vport *vport_msg; 115 int err; 116 117 vport_msg = (struct virtchnl2_create_vport *) 118 adapter->vport_params_recvd[vport->idx]; 119 120 if (!(le16_to_cpu(vport_msg->vport_flags) & VIRTCHNL2_VPORT_ENABLE_RDMA)) 121 return 0; 122 123 vport->vdev_info = kzalloc(sizeof(*vdev_info), GFP_KERNEL); 124 if (!vport->vdev_info) 125 return -ENOMEM; 126 127 cdev_info = vport->adapter->cdev_info; 128 129 vdev_info = vport->vdev_info; 130 vdev_info->vport_id = vport->vport_id; 131 vdev_info->netdev = vport->netdev; 132 vdev_info->core_adev = cdev_info->adev; 133 134 err = idpf_plug_vport_aux_dev(cdev_info, vdev_info); 135 if (err) { 136 vport->vdev_info = NULL; 137 kfree(vdev_info); 138 return err; 139 } 140 141 return 0; 142 } 143 144 /** 145 * idpf_idc_vdev_mtu_event - Function to handle IDC vport mtu change events 146 * @vdev_info: IDC vport device info pointer 147 * @event_type: type of event to pass to handler 148 */ 149 void idpf_idc_vdev_mtu_event(struct iidc_rdma_vport_dev_info *vdev_info, 150 enum iidc_rdma_event_type event_type) 151 { 152 struct iidc_rdma_vport_auxiliary_drv *iadrv; 153 struct iidc_rdma_event event = { }; 154 struct auxiliary_device *adev; 155 156 if (!vdev_info) 157 /* RDMA is not enabled */ 158 return; 159 160 set_bit(event_type, event.type); 161 162 device_lock(&vdev_info->adev->dev); 163 adev = vdev_info->adev; 164 if (!adev || !adev->dev.driver) 165 goto unlock; 166 iadrv = container_of(adev->dev.driver, 167 struct iidc_rdma_vport_auxiliary_drv, 168 adrv.driver); 169 if (iadrv->event_handler) 170 iadrv->event_handler(vdev_info, &event); 171 unlock: 172 device_unlock(&vdev_info->adev->dev); 173 } 174 175 /** 176 * idpf_core_adev_release - function to be mapped to aux dev's release op 177 * @dev: pointer to device to free 178 */ 179 static void idpf_core_adev_release(struct device *dev) 180 { 181 struct iidc_rdma_core_auxiliary_dev *iadev; 182 183 iadev = container_of(dev, struct iidc_rdma_core_auxiliary_dev, adev.dev); 184 kfree(iadev); 185 iadev = NULL; 186 } 187 188 /** 189 * idpf_plug_core_aux_dev - allocate and register an Auxiliary device 190 * @cdev_info: IDC core device info pointer 191 * 192 * Return: 0 on success or error code on failure. 193 */ 194 static int idpf_plug_core_aux_dev(struct iidc_rdma_core_dev_info *cdev_info) 195 { 196 struct iidc_rdma_core_auxiliary_dev *iadev; 197 char name[IDPF_IDC_MAX_ADEV_NAME_LEN]; 198 struct auxiliary_device *adev; 199 int ret; 200 201 iadev = kzalloc(sizeof(*iadev), GFP_KERNEL); 202 if (!iadev) 203 return -ENOMEM; 204 205 adev = &iadev->adev; 206 cdev_info->adev = adev; 207 iadev->cdev_info = cdev_info; 208 209 ret = ida_alloc(&idpf_idc_ida, GFP_KERNEL); 210 if (ret < 0) { 211 pr_err("failed to allocate unique device ID for Auxiliary driver\n"); 212 goto err_ida_alloc; 213 } 214 adev->id = ret; 215 adev->dev.release = idpf_core_adev_release; 216 adev->dev.parent = &cdev_info->pdev->dev; 217 sprintf(name, "%04x.rdma.core", cdev_info->pdev->vendor); 218 adev->name = name; 219 220 ret = auxiliary_device_init(adev); 221 if (ret) 222 goto err_aux_dev_init; 223 224 ret = auxiliary_device_add(adev); 225 if (ret) 226 goto err_aux_dev_add; 227 228 return 0; 229 230 err_aux_dev_add: 231 auxiliary_device_uninit(adev); 232 err_aux_dev_init: 233 ida_free(&idpf_idc_ida, adev->id); 234 err_ida_alloc: 235 cdev_info->adev = NULL; 236 kfree(iadev); 237 238 return ret; 239 } 240 241 /** 242 * idpf_unplug_aux_dev - unregister and free an Auxiliary device 243 * @adev: auxiliary device struct 244 */ 245 static void idpf_unplug_aux_dev(struct auxiliary_device *adev) 246 { 247 if (!adev) 248 return; 249 250 auxiliary_device_delete(adev); 251 auxiliary_device_uninit(adev); 252 253 ida_free(&idpf_idc_ida, adev->id); 254 } 255 256 /** 257 * idpf_idc_issue_reset_event - Function to handle reset IDC event 258 * @cdev_info: IDC core device info pointer 259 */ 260 void idpf_idc_issue_reset_event(struct iidc_rdma_core_dev_info *cdev_info) 261 { 262 enum iidc_rdma_event_type event_type = IIDC_RDMA_EVENT_WARN_RESET; 263 struct iidc_rdma_core_auxiliary_drv *iadrv; 264 struct iidc_rdma_event event = { }; 265 struct auxiliary_device *adev; 266 267 if (!cdev_info) 268 /* RDMA is not enabled */ 269 return; 270 271 set_bit(event_type, event.type); 272 273 device_lock(&cdev_info->adev->dev); 274 275 adev = cdev_info->adev; 276 if (!adev || !adev->dev.driver) 277 goto unlock; 278 279 iadrv = container_of(adev->dev.driver, 280 struct iidc_rdma_core_auxiliary_drv, 281 adrv.driver); 282 if (iadrv->event_handler) 283 iadrv->event_handler(cdev_info, &event); 284 unlock: 285 device_unlock(&cdev_info->adev->dev); 286 } 287 288 /** 289 * idpf_idc_vport_dev_up - called when CORE is ready for vport aux devs 290 * @adapter: private data struct 291 * 292 * Return: 0 on success or error code on failure. 293 */ 294 static int idpf_idc_vport_dev_up(struct idpf_adapter *adapter) 295 { 296 int i, err = 0; 297 298 for (i = 0; i < adapter->num_alloc_vports; i++) { 299 struct idpf_vport *vport = adapter->vports[i]; 300 301 if (!vport) 302 continue; 303 304 if (!vport->vdev_info) 305 err = idpf_idc_init_aux_vport_dev(vport); 306 else 307 err = idpf_plug_vport_aux_dev(vport->adapter->cdev_info, 308 vport->vdev_info); 309 } 310 311 return err; 312 } 313 314 /** 315 * idpf_idc_vport_dev_down - called CORE is leaving vport aux dev support state 316 * @adapter: private data struct 317 */ 318 static void idpf_idc_vport_dev_down(struct idpf_adapter *adapter) 319 { 320 int i; 321 322 for (i = 0; i < adapter->num_alloc_vports; i++) { 323 struct idpf_vport *vport = adapter->vports[i]; 324 325 if (!vport) 326 continue; 327 328 idpf_unplug_aux_dev(vport->vdev_info->adev); 329 vport->vdev_info->adev = NULL; 330 } 331 } 332 333 /** 334 * idpf_idc_vport_dev_ctrl - Called by an Auxiliary Driver 335 * @cdev_info: IDC core device info pointer 336 * @up: RDMA core driver status 337 * 338 * This callback function is accessed by an Auxiliary Driver to indicate 339 * whether core driver is ready to support vport driver load or if vport 340 * drivers need to be taken down. 341 * 342 * Return: 0 on success or error code on failure. 343 */ 344 int idpf_idc_vport_dev_ctrl(struct iidc_rdma_core_dev_info *cdev_info, bool up) 345 { 346 struct idpf_adapter *adapter = pci_get_drvdata(cdev_info->pdev); 347 348 if (up) 349 return idpf_idc_vport_dev_up(adapter); 350 351 idpf_idc_vport_dev_down(adapter); 352 353 return 0; 354 } 355 EXPORT_SYMBOL_GPL(idpf_idc_vport_dev_ctrl); 356 357 /** 358 * idpf_idc_request_reset - Called by an Auxiliary Driver 359 * @cdev_info: IDC core device info pointer 360 * @reset_type: function, core or other 361 * 362 * This callback function is accessed by an Auxiliary Driver to request a reset 363 * on the Auxiliary Device. 364 * 365 * Return: 0 on success or error code on failure. 366 */ 367 int idpf_idc_request_reset(struct iidc_rdma_core_dev_info *cdev_info, 368 enum iidc_rdma_reset_type __always_unused reset_type) 369 { 370 struct idpf_adapter *adapter = pci_get_drvdata(cdev_info->pdev); 371 372 if (!idpf_is_reset_in_prog(adapter)) { 373 set_bit(IDPF_HR_FUNC_RESET, adapter->flags); 374 queue_delayed_work(adapter->vc_event_wq, 375 &adapter->vc_event_task, 376 msecs_to_jiffies(10)); 377 } 378 379 return 0; 380 } 381 EXPORT_SYMBOL_GPL(idpf_idc_request_reset); 382 383 /** 384 * idpf_idc_init_msix_data - initialize MSIX data for the cdev_info structure 385 * @adapter: driver private data structure 386 */ 387 static void 388 idpf_idc_init_msix_data(struct idpf_adapter *adapter) 389 { 390 struct iidc_rdma_core_dev_info *cdev_info; 391 struct iidc_rdma_priv_dev_info *privd; 392 393 if (!adapter->rdma_msix_entries) 394 return; 395 396 cdev_info = adapter->cdev_info; 397 privd = cdev_info->iidc_priv; 398 399 privd->msix_entries = adapter->rdma_msix_entries; 400 privd->msix_count = adapter->num_rdma_msix_entries; 401 } 402 403 /** 404 * idpf_idc_init_aux_core_dev - initialize Auxiliary Device(s) 405 * @adapter: driver private data structure 406 * @ftype: PF or VF 407 * 408 * Return: 0 on success or error code on failure. 409 */ 410 int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter, 411 enum iidc_function_type ftype) 412 { 413 struct iidc_rdma_core_dev_info *cdev_info; 414 struct iidc_rdma_priv_dev_info *privd; 415 int err, i; 416 417 adapter->cdev_info = kzalloc(sizeof(*cdev_info), GFP_KERNEL); 418 if (!adapter->cdev_info) 419 return -ENOMEM; 420 cdev_info = adapter->cdev_info; 421 422 privd = kzalloc(sizeof(*privd), GFP_KERNEL); 423 if (!privd) { 424 err = -ENOMEM; 425 goto err_privd_alloc; 426 } 427 428 cdev_info->iidc_priv = privd; 429 cdev_info->pdev = adapter->pdev; 430 cdev_info->rdma_protocol = IIDC_RDMA_PROTOCOL_ROCEV2; 431 privd->ftype = ftype; 432 433 privd->mapped_mem_regions = 434 kcalloc(adapter->hw.num_lan_regs, 435 sizeof(struct iidc_rdma_lan_mapped_mem_region), 436 GFP_KERNEL); 437 if (!privd->mapped_mem_regions) { 438 err = -ENOMEM; 439 goto err_plug_aux_dev; 440 } 441 442 privd->num_memory_regions = cpu_to_le16(adapter->hw.num_lan_regs); 443 for (i = 0; i < adapter->hw.num_lan_regs; i++) { 444 privd->mapped_mem_regions[i].region_addr = 445 adapter->hw.lan_regs[i].vaddr; 446 privd->mapped_mem_regions[i].size = 447 cpu_to_le64(adapter->hw.lan_regs[i].addr_len); 448 privd->mapped_mem_regions[i].start_offset = 449 cpu_to_le64(adapter->hw.lan_regs[i].addr_start); 450 } 451 452 idpf_idc_init_msix_data(adapter); 453 454 err = idpf_plug_core_aux_dev(cdev_info); 455 if (err) 456 goto err_free_mem_regions; 457 458 return 0; 459 460 err_free_mem_regions: 461 kfree(privd->mapped_mem_regions); 462 privd->mapped_mem_regions = NULL; 463 err_plug_aux_dev: 464 kfree(privd); 465 err_privd_alloc: 466 kfree(cdev_info); 467 adapter->cdev_info = NULL; 468 469 return err; 470 } 471 472 /** 473 * idpf_idc_deinit_core_aux_device - de-initialize Auxiliary Device(s) 474 * @cdev_info: IDC core device info pointer 475 */ 476 void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info) 477 { 478 struct iidc_rdma_priv_dev_info *privd; 479 480 if (!cdev_info) 481 return; 482 483 idpf_unplug_aux_dev(cdev_info->adev); 484 485 privd = cdev_info->iidc_priv; 486 kfree(privd->mapped_mem_regions); 487 kfree(privd); 488 kfree(cdev_info); 489 } 490 491 /** 492 * idpf_idc_deinit_vport_aux_device - de-initialize Auxiliary Device(s) 493 * @vdev_info: IDC vport device info pointer 494 */ 495 void idpf_idc_deinit_vport_aux_device(struct iidc_rdma_vport_dev_info *vdev_info) 496 { 497 if (!vdev_info) 498 return; 499 500 idpf_unplug_aux_dev(vdev_info->adev); 501 502 kfree(vdev_info); 503 } 504