File Index
Files and directories
Sign in
FILE

idpf_idc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/intel/idpf/idpf_idc.c C
  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
  9static 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 */
 19int 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 */
 39static 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 */
 55static 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
 92err_aux_dev_add:
 93	auxiliary_device_uninit(adev);
 94err_aux_dev_init:
 95	ida_free(&idpf_idc_ida, adev->id);
 96err_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 */
109static 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 */
149void 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);
171unlock:
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 */
179static 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 */
194static 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
230err_aux_dev_add:
231	auxiliary_device_uninit(adev);
232err_aux_dev_init:
233	ida_free(&idpf_idc_ida, adev->id);
234err_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 */
245static 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 */
260void 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);
284unlock:
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 */
294static 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 */
318static 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 || !vport->vdev_info)
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 */
344int 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}
355EXPORT_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 */
367int 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}
381EXPORT_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 */
387static void
388idpf_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 */
410int 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
460err_free_mem_regions:
461	kfree(privd->mapped_mem_regions);
462	privd->mapped_mem_regions = NULL;
463err_plug_aux_dev:
464	kfree(privd);
465err_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 */
476void 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 */
495void 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}
~/ Read-only file preview.