[RFC PATCH v2 vfio 2/7] vfio/pds: Add support to register as PDS client

Brett Creeley
2022-12-14T23:24:14Z

The pds_core driver will create auxiliary devices for each PCI device
supported by pds_vfio. In order to communicate with the device, the
pds_vfio driver needs to register as an auxiliary driver for the
previously mentioned auxiliary device. Once the auxiliary device
is probed, the pds_vfio driver can send admin queue commands and
receive events from the device by way of pds_core.

Use the following commands to enable a VF and tell pds_core to
create its corresponding auxiliary device:

echo 1 > /sys/bus/pci/drivers/pds_core/$PF_BDF/sriov_numvfs
devlink dev param set pci/$PF_BDF name enable_migration value true cmode runtime

This functionality is needed to support live migration commands, which
are added later in the series.

Signed-off-by: Brett Creeley <brett.creeley@amd.com>
Signed-off-by: Shannon Nelson <shannon.nelson@amd.com>
---
drivers/vfio/pci/pds/Makefile | 2 +
drivers/vfio/pci/pds/aux_drv.c | 154 ++++++++++++++++++++++++++++++++
drivers/vfio/pci/pds/aux_drv.h | 29 ++++++
drivers/vfio/pci/pds/cmds.c | 30 +++++++
drivers/vfio/pci/pds/cmds.h | 14 +++
drivers/vfio/pci/pds/pci_drv.c | 18 +++-
drivers/vfio/pci/pds/pci_drv.h | 11 +++
drivers/vfio/pci/pds/vfio_dev.c | 8 ++
drivers/vfio/pci/pds/vfio_dev.h | 1 +
include/linux/pds/pds_lm.h | 12 +++
10 files changed, 278 insertions(+), 1 deletion(-)
create mode 100644 drivers/vfio/pci/pds/aux_drv.c
create mode 100644 drivers/vfio/pci/pds/aux_drv.h
create mode 100644 drivers/vfio/pci/pds/cmds.c
create mode 100644 drivers/vfio/pci/pds/cmds.h
create mode 100644 drivers/vfio/pci/pds/pci_drv.h
create mode 100644 include/linux/pds/pds_lm.h

diff --git a/drivers/vfio/pci/pds/Makefile b/drivers/vfio/pci/pds/Makefile
index dcc8f6beffe2..49bf8289739b 100644
--- a/drivers/vfio/pci/pds/Makefile
+++ b/drivers/vfio/pci/pds/Makefile
@@ -2,5 +2,7 @@
obj-$(CONFIG_PDS_VFIO_PCI) += pds_vfio.o

pds_vfio-y := \
+ aux_drv.o \
+ cmds.o \
pci_drv.o \
vfio_dev.o
diff --git a/drivers/vfio/pci/pds/aux_drv.c b/drivers/vfio/pci/pds/aux_drv.c
new file mode 100644
index 000000000000..494551894926
--- /dev/null
+++ b/drivers/vfio/pci/pds/aux_drv.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2022 Pensando Systems, Inc */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/pds/pds_core_if.h>
+#include <linux/pds/pds_adminq.h>
+#include <linux/pds/pds_auxbus.h>
+#include <linux/pds/pds_lm.h>
+
+#include "aux_drv.h"
+#include "vfio_dev.h"
+#include "pci_drv.h"
+#include "cmds.h"
+
+static const
+struct auxiliary_device_id pds_vfio_aux_id_table[] = {
+ { .name = PDS_LM_DEV_NAME, },
+ {},
+};
+
+static void
+pds_vfio_aux_notify_handler(struct pds_auxiliary_dev *padev,
+ union pds_core_notifyq_comp *event)
+{
+ struct device *dev = &padev->aux_dev.dev;
+ u16 ecode = le16_to_cpu(event->ecode);
+
+ dev_dbg(dev, "%s: event code %d\n", __func__, ecode);
+}
+
+static int
+pds_vfio_aux_probe(struct auxiliary_device *aux_dev,
+ const struct auxiliary_device_id *id)
+
+{
+ struct pds_auxiliary_dev *padev =
+ container_of(aux_dev, struct pds_auxiliary_dev, aux_dev);
+ struct pds_vfio_pci_device *pds_vfio;
+ struct device *dev = &aux_dev->dev;
+ struct pds_vfio_aux *vfio_aux;
+ struct pci_dev *pdev;
+ struct pci_bus *bus;
+ int busnr;
+ u16 devfn;
+ int err;
+
+ /* Find our VF PCI device */
+ busnr = PCI_BUS_NUM(padev->id);
+ devfn = padev->id & 0xff;
+ bus = pci_find_bus(0, busnr);
+ pdev = pci_get_slot(bus, devfn);
+
+ if (!pds_vfio_is_vfio_pci_driver(pdev)) {
+ dev_dbg(&aux_dev->dev, "unbind %s from %s driver and bind to %s driver for live migration support\n",
+ pci_name(pdev), dev_driver_string(&pdev->dev), PDS_VFIO_DRV_NAME);
+ return -EPROBE_DEFER;
+ }
+
+ pds_vfio = pci_get_drvdata(pdev);
+ if (!pds_vfio) {
+ dev_dbg(&pdev->dev, "PCI device not probed yet, defer until PCI device is probed by %s driver\n",
+ PDS_VFIO_DRV_NAME);
+ return -EPROBE_DEFER;
+ }
+
+ vfio_aux = kzalloc(sizeof(*vfio_aux), GFP_KERNEL);
+ if (!vfio_aux)
+ return -ENOMEM;
+
+ vfio_aux->padev = padev;
+ vfio_aux->pds_vfio = pds_vfio;
+ auxiliary_set_drvdata(aux_dev, vfio_aux);
+
+ dev_dbg(dev, "%s: id %#04x busnr %#x devfn %#x bus %p pds_vfio %p\n",
+ __func__, padev->id, busnr, devfn, bus, vfio_aux->pds_vfio);
+
+ vfio_aux->pds_vfio->vfio_aux = vfio_aux;
+
+ vfio_aux->padrv.event_handler = pds_vfio_aux_notify_handler;
+ err = pds_vfio_register_client_cmd(vfio_aux->pds_vfio);
+ if (err) {
+ dev_err(dev, "failed to register as client: %pe\n",
+ ERR_PTR(err));
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ auxiliary_set_drvdata(aux_dev, NULL);
+ kfree(vfio_aux);
+
+ return err;
+}
+
+static void
+pds_vfio_aux_remove(struct auxiliary_device *aux_dev)
+{
+ struct pds_vfio_aux *vfio_aux = auxiliary_get_drvdata(aux_dev);
+ struct pds_vfio_pci_device *pds_vfio = vfio_aux->pds_vfio;
+
+ if (pds_vfio) {
+ pds_vfio_unregister_client_cmd(pds_vfio);
+ vfio_aux->pds_vfio->vfio_aux = NULL;
+ pci_dev_put(pds_vfio->pdev);
+ }
+
+ kfree(vfio_aux);
+ auxiliary_set_drvdata(aux_dev, NULL);
+}
+
+static struct auxiliary_driver
+pds_vfio_aux_driver = {
+ .name = PDS_DEV_TYPE_LM_STR,
+ .probe = pds_vfio_aux_probe,
+ .remove = pds_vfio_aux_remove,
+ .id_table = pds_vfio_aux_id_table,
+};
+
+struct auxiliary_driver *
+pds_vfio_aux_driver_info(void)
+{
+ return &pds_vfio_aux_driver;
+}
+
+static int
+pds_vfio_aux_match_id(struct device *dev, const void *data)
+{
+ dev_dbg(dev, "%s: %s\n", __func__, (char *)data);
+ return !strcmp(dev_name(dev), data);
+}
+
+struct pds_vfio_aux *
+pds_vfio_aux_get_drvdata(int vf_pci_id)
+{
+ struct auxiliary_device *aux_dev;
+ char name[32];
+
+ snprintf(name, sizeof(name), "%s.%d", PDS_LM_DEV_NAME, vf_pci_id);
+ aux_dev = auxiliary_find_device(NULL, name, pds_vfio_aux_match_id);
+ if (!aux_dev)
+ return NULL;
+
+ return auxiliary_get_drvdata(aux_dev);
+}
+
+void
+pds_vfio_put_aux_dev(struct pds_vfio_aux *vfio_aux)
+{
+ put_device(&vfio_aux->padev->aux_dev.dev);
+}
diff --git a/drivers/vfio/pci/pds/aux_drv.h b/drivers/vfio/pci/pds/aux_drv.h
new file mode 100644
index 000000000000..0f05a968bb00
--- /dev/null
+++ b/drivers/vfio/pci/pds/aux_drv.h
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2022 Pensando Systems, Inc */
+
+#ifndef _AUX_DRV_H_
+#define _AUX_DRV_H_
+
+#include <linux/auxiliary_bus.h>
+
+#include <linux/pds/pds_intr.h>
+#include <linux/pds/pds_common.h>
+#include <linux/pds/pds_adminq.h>
+#include <linux/pds/pds_auxbus.h>
+
+struct pds_vfio_pci_device;
+
+struct pds_vfio_aux {
+ struct pds_auxiliary_dev *padev;
+ struct pds_auxiliary_drv padrv;
+ struct pds_vfio_pci_device *pds_vfio;
+};
+
+struct auxiliary_driver *
+pds_vfio_aux_driver_info(void);
+struct pds_vfio_aux *
+pds_vfio_aux_get_drvdata(int vf_pci_id);
+void
+pds_vfio_put_aux_dev(struct pds_vfio_aux *vfio_aux);
+
+#endif /* _AUX_DRV_H_ */
diff --git a/drivers/vfio/pci/pds/cmds.c b/drivers/vfio/pci/pds/cmds.c
new file mode 100644
index 000000000000..5a3fadcd38d8
--- /dev/null
+++ b/drivers/vfio/pci/pds/cmds.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2022 Pensando Systems, Inc */
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+#include <linux/pds/pds_core_if.h>
+#include <linux/pds/pds_adminq.h>
+#include <linux/pds/pds_auxbus.h>
+
+#include "vfio_dev.h"
+#include "aux_drv.h"
+#include "cmds.h"
+
+int
+pds_vfio_register_client_cmd(struct pds_vfio_pci_device *pds_vfio)
+{
+ struct pds_vfio_aux *vfio_aux = pds_vfio->vfio_aux;
+ struct pds_auxiliary_dev *padev = vfio_aux->padev;
+
+ return padev->ops->register_client(padev, &vfio_aux->padrv);
+}
+
+void
+pds_vfio_unregister_client_cmd(struct pds_vfio_pci_device *pds_vfio)
+{
+ struct pds_auxiliary_dev *padev = pds_vfio->vfio_aux->padev;
+
+ padev->ops->unregister_client(padev);
+}
diff --git a/drivers/vfio/pci/pds/cmds.h b/drivers/vfio/pci/pds/cmds.h
new file mode 100644
index 000000000000..7fe2d1efd894
--- /dev/null
+++ b/drivers/vfio/pci/pds/cmds.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2022 Pensando Systems, Inc */
+
+#ifndef _CMDS_H_
+#define _CMDS_H_
+
+struct pds_vfio_pci_device;
+
+int
+pds_vfio_register_client_cmd(struct pds_vfio_pci_device *pds_vfio);
+void
+pds_vfio_unregister_client_cmd(struct pds_vfio_pci_device *pds_vfio);
+
+#endif /* _CMDS_H_ */
diff --git a/drivers/vfio/pci/pds/pci_drv.c b/drivers/vfio/pci/pds/pci_drv.c
index 09cab0dbb0e9..d6ad15719ec4 100644
--- a/drivers/vfio/pci/pds/pci_drv.c
+++ b/drivers/vfio/pci/pds/pci_drv.c
@@ -11,8 +11,9 @@
#include <linux/pds/pds_core_if.h>

#include "vfio_dev.h"
+#include "aux_drv.h"
+#include "pci_drv.h"

-#define PDS_VFIO_DRV_NAME "pds_vfio"
#define PDS_VFIO_DRV_DESCRIPTION "Pensando VFIO Device Driver"
#define PCI_VENDOR_ID_PENSANDO 0x1dd8

@@ -75,9 +76,17 @@ pds_vfio_pci_driver = {
.driver_managed_dma = true,
};

+bool
+pds_vfio_is_vfio_pci_driver(struct pci_dev *pdev)
+{
+ return (to_pci_driver(pdev->dev.driver) == &pds_vfio_pci_driver);
+}
+
static void __exit
pds_vfio_pci_cleanup(void)
{
+ auxiliary_driver_unregister(pds_vfio_aux_driver_info());
+
pci_unregister_driver(&pds_vfio_pci_driver);
}
module_exit(pds_vfio_pci_cleanup);
@@ -93,6 +102,13 @@ pds_vfio_pci_init(void)
return err;
}

+ err = auxiliary_driver_register(pds_vfio_aux_driver_info());
+ if (err) {
+ pr_err("aux driver register failed: %pe\n", ERR_PTR(err));
+ pci_unregister_driver(&pds_vfio_pci_driver);
+ return err;
+ }
+
return 0;
}
module_init(pds_vfio_pci_init);
diff --git a/drivers/vfio/pci/pds/pci_drv.h b/drivers/vfio/pci/pds/pci_drv.h
new file mode 100644
index 000000000000..549092f40f5a
--- /dev/null
+++ b/drivers/vfio/pci/pds/pci_drv.h
@@ -0,0 +1,11 @@
+#ifndef _PCI_DRV_H
+#define _PCI_DRV_H
+
+#include <linux/pci.h>
+
+#define PDS_VFIO_DRV_NAME "pds_vfio"
+
+bool
+pds_vfio_is_vfio_pci_driver(struct pci_dev *pdev);
+
+#endif /* _PCI_DRV_H */
diff --git a/drivers/vfio/pci/pds/vfio_dev.c b/drivers/vfio/pci/pds/vfio_dev.c
index f8f4006c0915..30c3bb47a2be 100644
--- a/drivers/vfio/pci/pds/vfio_dev.c
+++ b/drivers/vfio/pci/pds/vfio_dev.c
@@ -5,6 +5,7 @@
#include <linux/vfio_pci_core.h>

#include "vfio_dev.h"
+#include "aux_drv.h"

struct pds_vfio_pci_device *
pds_vfio_pci_drvdata(struct pci_dev *pdev)
@@ -22,6 +23,7 @@ pds_vfio_init_device(struct vfio_device *vdev)
container_of(vdev, struct pds_vfio_pci_device,
vfio_coredev.vdev);
struct pci_dev *pdev = to_pci_dev(vdev->dev);
+ struct pds_vfio_aux *vfio_aux;
int err;

err = vfio_pci_core_init_dev(vdev);
@@ -30,6 +32,12 @@ pds_vfio_init_device(struct vfio_device *vdev)

pds_vfio->vf_id = pci_iov_vf_id(pdev);
pds_vfio->pci_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
+ vfio_aux = pds_vfio_aux_get_drvdata(pds_vfio->pci_id);
+ if (vfio_aux) {
+ vfio_aux->pds_vfio = pds_vfio;
+ pds_vfio->vfio_aux = vfio_aux;
+ pds_vfio_put_aux_dev(vfio_aux);
+ }

return 0;
}
diff --git a/drivers/vfio/pci/pds/vfio_dev.h b/drivers/vfio/pci/pds/vfio_dev.h
index 289479a08dce..b16668693e1f 100644
--- a/drivers/vfio/pci/pds/vfio_dev.h
+++ b/drivers/vfio/pci/pds/vfio_dev.h
@@ -10,6 +10,7 @@
struct pds_vfio_pci_device {
struct vfio_pci_core_device vfio_coredev;
struct pci_dev *pdev;
+ struct pds_vfio_aux *vfio_aux;

int vf_id;
int pci_id;
diff --git a/include/linux/pds/pds_lm.h b/include/linux/pds/pds_lm.h
new file mode 100644
index 000000000000..fdaf2bf71d35
--- /dev/null
+++ b/include/linux/pds/pds_lm.h
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2022 Pensando Systems, Inc */
+
+#ifndef _PDS_LM_H_
+#define _PDS_LM_H_
+
+#include "pds_common.h"
+
+#define PDS_DEV_TYPE_LM_STR "LM"
+#define PDS_LM_DEV_NAME PDS_CORE_DRV_NAME "." PDS_DEV_TYPE_LM_STR
+
+#endif /* _PDS_LM_H_ */
--
2.17.1