xref: /linux/drivers/net/ethernet/intel/idpf/idpf_idc.c (revision 66182ca873a4e87b3496eca79d57f86b76d7f52d)
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