pds_core: add auxiliary_bus devices
authorShannon Nelson <shannon.nelson@amd.com>
Wed, 19 Apr 2023 17:04:23 +0000 (10:04 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 21 Apr 2023 07:29:13 +0000 (08:29 +0100)
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>
drivers/net/ethernet/amd/pds_core/Makefile
drivers/net/ethernet/amd/pds_core/auxbus.c [new file with mode: 0644]
drivers/net/ethernet/amd/pds_core/core.h
drivers/net/ethernet/amd/pds_core/main.c
include/linux/pds/pds_auxbus.h [new file with mode: 0644]
include/linux/pds/pds_common.h

index 6d1d6c58a1fa436a14a3c2bc8ca4e08db92e99b2..0abc33ce826c311ba9a99a784695067751c103af 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_PDS_CORE) := pds_core.o
 
 pds_core-y := main.o \
              devlink.o \
+             auxbus.o \
              dev.o \
              adminq.o \
              core.o \
diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c
new file mode 100644 (file)
index 0000000..adee516
--- /dev/null
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2023 Advanced Micro Devices, Inc */
+
+#include <linux/pci.h>
+
+#include "core.h"
+#include <linux/pds/pds_auxbus.h>
+
+static void pdsc_auxbus_dev_release(struct device *dev)
+{
+       struct pds_auxiliary_dev *padev =
+               container_of(dev, struct pds_auxiliary_dev, aux_dev.dev);
+
+       kfree(padev);
+}
+
+static struct pds_auxiliary_dev *pdsc_auxbus_dev_register(struct pdsc *cf,
+                                                         struct pdsc *pf,
+                                                         char *name)
+{
+       struct auxiliary_device *aux_dev;
+       struct pds_auxiliary_dev *padev;
+       int err;
+
+       padev = kzalloc(sizeof(*padev), GFP_KERNEL);
+       if (!padev)
+               return ERR_PTR(-ENOMEM);
+
+       padev->vf_pdev = cf->pdev;
+
+       aux_dev = &padev->aux_dev;
+       aux_dev->name = name;
+       aux_dev->id = cf->uid;
+       aux_dev->dev.parent = cf->dev;
+       aux_dev->dev.release = pdsc_auxbus_dev_release;
+
+       err = auxiliary_device_init(aux_dev);
+       if (err < 0) {
+               dev_warn(cf->dev, "auxiliary_device_init of %s failed: %pe\n",
+                        name, ERR_PTR(err));
+               goto err_out;
+       }
+
+       err = auxiliary_device_add(aux_dev);
+       if (err) {
+               dev_warn(cf->dev, "auxiliary_device_add of %s failed: %pe\n",
+                        name, ERR_PTR(err));
+               goto err_out_uninit;
+       }
+
+       return padev;
+
+err_out_uninit:
+       auxiliary_device_uninit(aux_dev);
+err_out:
+       kfree(padev);
+       return ERR_PTR(err);
+}
+
+int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf)
+{
+       struct pds_auxiliary_dev *padev;
+       int err = 0;
+
+       mutex_lock(&pf->config_lock);
+
+       padev = pf->vfs[cf->vf_id].padev;
+       if (padev) {
+               auxiliary_device_delete(&padev->aux_dev);
+               auxiliary_device_uninit(&padev->aux_dev);
+       }
+       pf->vfs[cf->vf_id].padev = NULL;
+
+       mutex_unlock(&pf->config_lock);
+       return err;
+}
+
+int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf)
+{
+       struct pds_auxiliary_dev *padev;
+       enum pds_core_vif_types vt;
+       u16 vt_support;
+       int err = 0;
+
+       mutex_lock(&pf->config_lock);
+
+       /* We only support vDPA so far, so it is the only one to
+        * be verified that it is available in the Core device and
+        * enabled in the devlink param.  In the future this might
+        * become a loop for several VIF types.
+        */
+
+       /* Verify that the type is supported and enabled.  It is not
+        * an error if there is no auxbus device support for this
+        * VF, it just means something else needs to happen with it.
+        */
+       vt = PDS_DEV_TYPE_VDPA;
+       vt_support = !!le16_to_cpu(pf->dev_ident.vif_types[vt]);
+       if (!(vt_support &&
+             pf->viftype_status[vt].supported &&
+             pf->viftype_status[vt].enabled))
+               goto out_unlock;
+
+       padev = pdsc_auxbus_dev_register(cf, pf,
+                                        pf->viftype_status[vt].name);
+       if (IS_ERR(padev)) {
+               err = PTR_ERR(padev);
+               goto out_unlock;
+       }
+       pf->vfs[cf->vf_id].padev = padev;
+
+out_unlock:
+       mutex_unlock(&pf->config_lock);
+       return err;
+}
index 1ec8784773f190295a879cdfefe67accce6eff19..36099d3ac3dd856e0e60b21efb6ba3e8df259e49 100644 (file)
@@ -30,8 +30,11 @@ struct pdsc_dev_bar {
        int res_index;
 };
 
+struct pdsc;
+
 struct pdsc_vf {
        struct pds_auxiliary_dev *padev;
+       struct pdsc *vf;
        u16     index;
        __le16  vif_types[PDS_DEV_TYPE_MAX];
 };
@@ -287,6 +290,9 @@ int pdsc_start(struct pdsc *pdsc);
 void pdsc_stop(struct pdsc *pdsc);
 void pdsc_health_thread(struct work_struct *work);
 
+int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf);
+int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf);
+
 void pdsc_process_adminq(struct pdsc_qcq *qcq);
 void pdsc_work_thread(struct work_struct *work);
 irqreturn_t pdsc_adminq_isr(int irq, void *data);
index 511cb91a295e4884c7231aabe838360f89989b5e..b848f3360fe25318b4fdbe6907eeaf922ff79985 100644 (file)
@@ -169,6 +169,12 @@ no_vfs:
 static int pdsc_init_vf(struct pdsc *vf)
 {
        struct devlink *dl;
+       struct pdsc *pf;
+       int err;
+
+       pf = pdsc_get_pf_struct(vf->pdev);
+       if (IS_ERR_OR_NULL(pf))
+               return PTR_ERR(pf) ?: -1;
 
        vf->vf_id = pci_iov_vf_id(vf->pdev);
 
@@ -177,7 +183,15 @@ static int pdsc_init_vf(struct pdsc *vf)
        devl_register(dl);
        devl_unlock(dl);
 
-       return 0;
+       pf->vfs[vf->vf_id].vf = vf;
+       err = pdsc_auxbus_dev_add(vf, pf);
+       if (err) {
+               devl_lock(dl);
+               devl_unregister(dl);
+               devl_unlock(dl);
+       }
+
+       return err;
 }
 
 static const struct devlink_health_reporter_ops pdsc_fw_reporter_ops = {
@@ -365,7 +379,19 @@ static void pdsc_remove(struct pci_dev *pdev)
        }
        devl_unlock(dl);
 
-       if (!pdev->is_virtfn) {
+       if (pdev->is_virtfn) {
+               struct pdsc *pf;
+
+               pf = pdsc_get_pf_struct(pdsc->pdev);
+               if (!IS_ERR(pf)) {
+                       pdsc_auxbus_dev_del(pdsc, pf);
+                       pf->vfs[pdsc->vf_id].vf = NULL;
+               }
+       } else {
+               /* Remove the VFs and their aux_bus connections before other
+                * cleanup so that the clients can use the AdminQ to cleanly
+                * shut themselves down.
+                */
                pdsc_sriov_configure(pdev, 0);
 
                del_timer_sync(&pdsc->wdtimer);
@@ -402,6 +428,12 @@ static struct pci_driver pdsc_driver = {
        .sriov_configure = pdsc_sriov_configure,
 };
 
+void *pdsc_get_pf_struct(struct pci_dev *vf_pdev)
+{
+       return pci_iov_get_pf_drvdata(vf_pdev, &pdsc_driver);
+}
+EXPORT_SYMBOL_GPL(pdsc_get_pf_struct);
+
 static int __init pdsc_init_module(void)
 {
        if (strcmp(KBUILD_MODNAME, PDS_CORE_DRV_NAME))
diff --git a/include/linux/pds/pds_auxbus.h b/include/linux/pds/pds_auxbus.h
new file mode 100644 (file)
index 0000000..493f75b
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2023 Advanced Micro Devices, Inc */
+
+#ifndef _PDSC_AUXBUS_H_
+#define _PDSC_AUXBUS_H_
+
+#include <linux/auxiliary_bus.h>
+
+struct pds_auxiliary_dev {
+       struct auxiliary_device aux_dev;
+       struct pci_dev *vf_pdev;
+       u16 client_id;
+};
+#endif /* _PDSC_AUXBUS_H_ */
index b2be14ebadb6d4979a35d6f51c51e1e4f1f25db2..961b3d02c69fc1d71c001ccf2977bba563590c1c 100644 (file)
@@ -60,4 +60,5 @@ enum pds_core_logical_qtype {
        PDS_CORE_QTYPE_MAX     = 16   /* don't change - used in struct size */
 };
 
+void *pdsc_get_pf_struct(struct pci_dev *vf_pdev);
 #endif /* _PDS_COMMON_H_ */