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 */
idpf_idc_init(struct idpf_adapter * adapter)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 */
idpf_vport_adev_release(struct device * dev)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 */
idpf_plug_vport_aux_dev(struct iidc_rdma_core_dev_info * cdev_info,struct iidc_rdma_vport_dev_info * vdev_info)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 */
idpf_idc_init_aux_vport_dev(struct idpf_vport * vport)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 */
idpf_idc_vdev_mtu_event(struct iidc_rdma_vport_dev_info * vdev_info,enum iidc_rdma_event_type event_type)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 */
idpf_core_adev_release(struct device * dev)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 */
idpf_plug_core_aux_dev(struct iidc_rdma_core_dev_info * cdev_info)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 */
idpf_unplug_aux_dev(struct auxiliary_device * adev)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 */
idpf_idc_issue_reset_event(struct iidc_rdma_core_dev_info * cdev_info)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 */
idpf_idc_vport_dev_up(struct idpf_adapter * adapter)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 */
idpf_idc_vport_dev_down(struct idpf_adapter * adapter)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 */
idpf_idc_vport_dev_ctrl(struct iidc_rdma_core_dev_info * cdev_info,bool up)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 */
idpf_idc_request_reset(struct iidc_rdma_core_dev_info * cdev_info,enum iidc_rdma_reset_type __always_unused reset_type)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
idpf_idc_init_msix_data(struct idpf_adapter * adapter)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 */
idpf_idc_init_aux_core_dev(struct idpf_adapter * adapter,enum iidc_function_type ftype)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 */
idpf_idc_deinit_core_aux_device(struct idpf_adapter * adapter)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 */
idpf_idc_deinit_vport_aux_device(struct iidc_rdma_vport_dev_info * vdev_info)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