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

From: Brett Creeley <[email-masked]>
Date: Sun, 19 Feb 2023 00:39:03 -0800

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 <[email-masked]>
Signed-off-by: Shannon Nelson <[email-masked]>
---
 drivers/vfio/pci/pds/Makefile   |   2 +
 drivers/vfio/pci/pds/aux_drv.c  | 148 ++++++++++++++++++++++++++++++++
 drivers/vfio/pci/pds/aux_drv.h  |  27 ++++++
 drivers/vfio/pci/pds/cmds.c     |  30 +++++++
 drivers/vfio/pci/pds/cmds.h     |  14 +++
 drivers/vfio/pci/pds/pci_drv.c  |  17 ++++
 drivers/vfio/pci/pds/pci_drv.h  |  14 +++
 drivers/vfio/pci/pds/vfio_dev.c |   6 ++
 drivers/vfio/pci/pds/vfio_dev.h |   1 +
 include/linux/pds/pds_lm.h      |  12 +++
 10 files changed, 271 insertions(+)
 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 e1a55ae0f079..92cc392fd487 100644
--- a/drivers/vfio/pci/pds/Makefile
+++ b/drivers/vfio/pci/pds/Makefile
@@ -4,5 +4,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..eda262e7d895
--- /dev/null
+++ b/drivers/vfio/pci/pds/aux_drv.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2023 Advanced Micro Devices, 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);
+}
diff --git a/drivers/vfio/pci/pds/aux_drv.h b/drivers/vfio/pci/pds/aux_drv.h
new file mode 100644
index 000000000000..be5948575a0c
--- /dev/null
+++ b/drivers/vfio/pci/pds/aux_drv.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2023 Advanced Micro Devices, 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);
+
+#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..6ac39703cb54
--- /dev/null
+++ b/drivers/vfio/pci/pds/cmds.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2023 Advanced Micro Devices, 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..eb39a3ad5089
--- /dev/null
+++ b/drivers/vfio/pci/pds/cmds.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2023 Advanced Micro Devices, 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 96e155598a50..3861a80c4706 100644
--- a/drivers/vfio/pci/pds/pci_drv.c
+++ b/drivers/vfio/pci/pds/pci_drv.c
@@ -11,6 +11,8 @@
 #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	"AMD/Pensando VFIO Device Driver"
@@ -67,9 +69,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);
@@ -85,6 +95,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..3394715bfe7b
--- /dev/null
+++ b/drivers/vfio/pci/pds/pci_drv.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2023 Advanced Micro Devices, Inc. */
+
+#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 f1221f14e4f6..e882276f9788 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)
@@ -31,6 +32,11 @@ 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);
 
+	dev_dbg(&pdev->dev, "%s: PF %#04x VF %#04x (%d) vf_id %d domain %d pds_vfio %p\n",
+		__func__, pci_dev_id(pdev->physfn),
+		pds_vfio->pci_id, pds_vfio->pci_id, pds_vfio->vf_id,
+		pci_domain_nr(pdev->bus), pds_vfio);
+
 	return 0;
 }
 
diff --git a/drivers/vfio/pci/pds/vfio_dev.h b/drivers/vfio/pci/pds/vfio_dev.h
index 4d497695c4e9..48083002d1ad 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