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