Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pds_core: add auxiliary_bus devices

An auxiliary_bus device is created for each vDPA type VF at VF
probe and destroyed at VF remove. The aux device name comes
from the driver name + VIF type + the unique id assigned at PCI
probe. The VFs are always removed on PF remove, so there should
be no issues with VFs trying to access missing PF structures.

The auxiliary_device names will look like "pds_core.vDPA.nn"
where 'nn' is the VF's uid.

Signed-off-by: Shannon Nelson <shannon.nelson@amd.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Shannon Nelson and committed by
David S. Miller
4569cce4 f53d9311

+171 -2
+1
drivers/net/ethernet/amd/pds_core/Makefile
··· 5 5 6 6 pds_core-y := main.o \ 7 7 devlink.o \ 8 + auxbus.o \ 8 9 dev.o \ 9 10 adminq.o \ 10 11 core.o \
+115
drivers/net/ethernet/amd/pds_core/auxbus.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #include <linux/pci.h> 5 + 6 + #include "core.h" 7 + #include <linux/pds/pds_auxbus.h> 8 + 9 + static void pdsc_auxbus_dev_release(struct device *dev) 10 + { 11 + struct pds_auxiliary_dev *padev = 12 + container_of(dev, struct pds_auxiliary_dev, aux_dev.dev); 13 + 14 + kfree(padev); 15 + } 16 + 17 + static struct pds_auxiliary_dev *pdsc_auxbus_dev_register(struct pdsc *cf, 18 + struct pdsc *pf, 19 + char *name) 20 + { 21 + struct auxiliary_device *aux_dev; 22 + struct pds_auxiliary_dev *padev; 23 + int err; 24 + 25 + padev = kzalloc(sizeof(*padev), GFP_KERNEL); 26 + if (!padev) 27 + return ERR_PTR(-ENOMEM); 28 + 29 + padev->vf_pdev = cf->pdev; 30 + 31 + aux_dev = &padev->aux_dev; 32 + aux_dev->name = name; 33 + aux_dev->id = cf->uid; 34 + aux_dev->dev.parent = cf->dev; 35 + aux_dev->dev.release = pdsc_auxbus_dev_release; 36 + 37 + err = auxiliary_device_init(aux_dev); 38 + if (err < 0) { 39 + dev_warn(cf->dev, "auxiliary_device_init of %s failed: %pe\n", 40 + name, ERR_PTR(err)); 41 + goto err_out; 42 + } 43 + 44 + err = auxiliary_device_add(aux_dev); 45 + if (err) { 46 + dev_warn(cf->dev, "auxiliary_device_add of %s failed: %pe\n", 47 + name, ERR_PTR(err)); 48 + goto err_out_uninit; 49 + } 50 + 51 + return padev; 52 + 53 + err_out_uninit: 54 + auxiliary_device_uninit(aux_dev); 55 + err_out: 56 + kfree(padev); 57 + return ERR_PTR(err); 58 + } 59 + 60 + int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf) 61 + { 62 + struct pds_auxiliary_dev *padev; 63 + int err = 0; 64 + 65 + mutex_lock(&pf->config_lock); 66 + 67 + padev = pf->vfs[cf->vf_id].padev; 68 + if (padev) { 69 + auxiliary_device_delete(&padev->aux_dev); 70 + auxiliary_device_uninit(&padev->aux_dev); 71 + } 72 + pf->vfs[cf->vf_id].padev = NULL; 73 + 74 + mutex_unlock(&pf->config_lock); 75 + return err; 76 + } 77 + 78 + int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf) 79 + { 80 + struct pds_auxiliary_dev *padev; 81 + enum pds_core_vif_types vt; 82 + u16 vt_support; 83 + int err = 0; 84 + 85 + mutex_lock(&pf->config_lock); 86 + 87 + /* We only support vDPA so far, so it is the only one to 88 + * be verified that it is available in the Core device and 89 + * enabled in the devlink param. In the future this might 90 + * become a loop for several VIF types. 91 + */ 92 + 93 + /* Verify that the type is supported and enabled. It is not 94 + * an error if there is no auxbus device support for this 95 + * VF, it just means something else needs to happen with it. 96 + */ 97 + vt = PDS_DEV_TYPE_VDPA; 98 + vt_support = !!le16_to_cpu(pf->dev_ident.vif_types[vt]); 99 + if (!(vt_support && 100 + pf->viftype_status[vt].supported && 101 + pf->viftype_status[vt].enabled)) 102 + goto out_unlock; 103 + 104 + padev = pdsc_auxbus_dev_register(cf, pf, 105 + pf->viftype_status[vt].name); 106 + if (IS_ERR(padev)) { 107 + err = PTR_ERR(padev); 108 + goto out_unlock; 109 + } 110 + pf->vfs[cf->vf_id].padev = padev; 111 + 112 + out_unlock: 113 + mutex_unlock(&pf->config_lock); 114 + return err; 115 + }
+6
drivers/net/ethernet/amd/pds_core/core.h
··· 30 30 int res_index; 31 31 }; 32 32 33 + struct pdsc; 34 + 33 35 struct pdsc_vf { 34 36 struct pds_auxiliary_dev *padev; 37 + struct pdsc *vf; 35 38 u16 index; 36 39 __le16 vif_types[PDS_DEV_TYPE_MAX]; 37 40 }; ··· 289 286 int pdsc_start(struct pdsc *pdsc); 290 287 void pdsc_stop(struct pdsc *pdsc); 291 288 void pdsc_health_thread(struct work_struct *work); 289 + 290 + int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf); 291 + int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf); 292 292 293 293 void pdsc_process_adminq(struct pdsc_qcq *qcq); 294 294 void pdsc_work_thread(struct work_struct *work);
+34 -2
drivers/net/ethernet/amd/pds_core/main.c
··· 169 169 static int pdsc_init_vf(struct pdsc *vf) 170 170 { 171 171 struct devlink *dl; 172 + struct pdsc *pf; 173 + int err; 174 + 175 + pf = pdsc_get_pf_struct(vf->pdev); 176 + if (IS_ERR_OR_NULL(pf)) 177 + return PTR_ERR(pf) ?: -1; 172 178 173 179 vf->vf_id = pci_iov_vf_id(vf->pdev); 174 180 ··· 183 177 devl_register(dl); 184 178 devl_unlock(dl); 185 179 186 - return 0; 180 + pf->vfs[vf->vf_id].vf = vf; 181 + err = pdsc_auxbus_dev_add(vf, pf); 182 + if (err) { 183 + devl_lock(dl); 184 + devl_unregister(dl); 185 + devl_unlock(dl); 186 + } 187 + 188 + return err; 187 189 } 188 190 189 191 static const struct devlink_health_reporter_ops pdsc_fw_reporter_ops = { ··· 379 365 } 380 366 devl_unlock(dl); 381 367 382 - if (!pdev->is_virtfn) { 368 + if (pdev->is_virtfn) { 369 + struct pdsc *pf; 370 + 371 + pf = pdsc_get_pf_struct(pdsc->pdev); 372 + if (!IS_ERR(pf)) { 373 + pdsc_auxbus_dev_del(pdsc, pf); 374 + pf->vfs[pdsc->vf_id].vf = NULL; 375 + } 376 + } else { 377 + /* Remove the VFs and their aux_bus connections before other 378 + * cleanup so that the clients can use the AdminQ to cleanly 379 + * shut themselves down. 380 + */ 383 381 pdsc_sriov_configure(pdev, 0); 384 382 385 383 del_timer_sync(&pdsc->wdtimer); ··· 427 401 .remove = pdsc_remove, 428 402 .sriov_configure = pdsc_sriov_configure, 429 403 }; 404 + 405 + void *pdsc_get_pf_struct(struct pci_dev *vf_pdev) 406 + { 407 + return pci_iov_get_pf_drvdata(vf_pdev, &pdsc_driver); 408 + } 409 + EXPORT_SYMBOL_GPL(pdsc_get_pf_struct); 430 410 431 411 static int __init pdsc_init_module(void) 432 412 {
+14
include/linux/pds/pds_auxbus.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #ifndef _PDSC_AUXBUS_H_ 5 + #define _PDSC_AUXBUS_H_ 6 + 7 + #include <linux/auxiliary_bus.h> 8 + 9 + struct pds_auxiliary_dev { 10 + struct auxiliary_device aux_dev; 11 + struct pci_dev *vf_pdev; 12 + u16 client_id; 13 + }; 14 + #endif /* _PDSC_AUXBUS_H_ */
+1
include/linux/pds/pds_common.h
··· 60 60 PDS_CORE_QTYPE_MAX = 16 /* don't change - used in struct size */ 61 61 }; 62 62 63 + void *pdsc_get_pf_struct(struct pci_dev *vf_pdev); 63 64 #endif /* _PDS_COMMON_H_ */