xref: /linux/drivers/net/ethernet/intel/idpf/idpf_idc.c (revision d69eb204c255c35abd9e8cb621484e8074c75eaa)
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(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  */
idpf_idc_init_aux_vport_dev(struct idpf_vport * vport)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  */
idpf_idc_vdev_mtu_event(struct iidc_rdma_vport_dev_info * vdev_info,enum iidc_rdma_event_type event_type)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  */
idpf_core_adev_release(struct device * dev)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  */
idpf_plug_core_aux_dev(struct iidc_rdma_core_dev_info * cdev_info)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  */
idpf_unplug_aux_dev(struct auxiliary_device * adev)245 static void idpf_unplug_aux_dev(struct auxiliary_device *adev)
246 {
247 	if (!adev)
248 		return;
249 
250 	ida_free(&idpf_idc_ida, adev->id);
251 
252 	auxiliary_device_delete(adev);
253 	auxiliary_device_uninit(adev);
254 }
255 
256 /**
257  * idpf_idc_issue_reset_event - Function to handle reset IDC event
258  * @cdev_info: IDC core device info pointer
259  */
idpf_idc_issue_reset_event(struct iidc_rdma_core_dev_info * cdev_info)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  */
idpf_idc_vport_dev_up(struct idpf_adapter * adapter)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  */
idpf_idc_vport_dev_down(struct idpf_adapter * adapter)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  */
idpf_idc_vport_dev_ctrl(struct iidc_rdma_core_dev_info * cdev_info,bool up)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  */
idpf_idc_request_reset(struct iidc_rdma_core_dev_info * cdev_info,enum iidc_rdma_reset_type __always_unused reset_type)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
idpf_idc_init_msix_data(struct idpf_adapter * adapter)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  */
idpf_idc_init_aux_core_dev(struct idpf_adapter * adapter,enum iidc_function_type ftype)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  */
idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info * cdev_info)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  */
idpf_idc_deinit_vport_aux_device(struct iidc_rdma_vport_dev_info * vdev_info)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