public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 0/4] debugfs to hisilicon migration driver
@ 2024-08-06 12:29 Longfang Liu
  2024-08-06 12:29 ` [PATCH v8 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Longfang Liu @ 2024-08-06 12:29 UTC (permalink / raw)
  To: alex.williamson, jgg, shameerali.kolothum.thodi, jonathan.cameron
  Cc: kvm, linux-kernel, linuxarm, liulongfang

Add a debugfs function to the hisilicon migration driver in VFIO to
provide intermediate state values and data during device migration.

When the execution of live migration fails, the user can view the
status and data during the migration process separately from the
source and the destination, which is convenient for users to analyze
and locate problems.

Changes v7 -> v8
	Delete unnecessary information

Changes v6 -> v7
	Remove redundant kernel error log printing and
	remove unrelated bugfix code

Changes v5 -> v6
	Modify log output calling error

Changes v4 -> v5
	Adjust the descriptioniptionbugfs file directory

Changes v3 -> v4
	Rebased on kernel6.9

Changes 2 -> v3
	Solve debugfs serialization problem.

Changes v1 -> v2
	Solve the racy problem of io_base.

Longfang Liu (4):
  hisi_acc_vfio_pci: extract public functions for container_of
  hisi_acc_vfio_pci: create subfunction for data reading
  hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  Documentation: add debugfs description for hisi migration

 .../ABI/testing/debugfs-hisi-migration        |  25 ++
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 284 ++++++++++++++++--
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |   6 +
 3 files changed, 284 insertions(+), 31 deletions(-)
 create mode 100644 Documentation/ABI/testing/debugfs-hisi-migration

-- 
2.24.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v8 1/4] hisi_acc_vfio_pci: extract public functions for container_of
  2024-08-06 12:29 [PATCH v8 0/4] debugfs to hisilicon migration driver Longfang Liu
@ 2024-08-06 12:29 ` Longfang Liu
  2024-08-06 12:29 ` [PATCH v8 2/4] hisi_acc_vfio_pci: create subfunction for data reading Longfang Liu
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 12+ messages in thread
From: Longfang Liu @ 2024-08-06 12:29 UTC (permalink / raw)
  To: alex.williamson, jgg, shameerali.kolothum.thodi, jonathan.cameron
  Cc: kvm, linux-kernel, linuxarm, liulongfang

In the current driver, vdev is obtained from struct
hisi_acc_vf_core_device through the container_of function.
This method is used in many places in the driver. In order to
reduce this repetitive operation, It was extracted into
a public function.

Signed-off-by: Longfang Liu <liulongfang@huawei.com>
Reviewed-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
---
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 21 ++++++++++---------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
index 9a3e97108ace..45351be8e270 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
@@ -630,6 +630,12 @@ static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vde
 	}
 }
 
+static struct hisi_acc_vf_core_device *hisi_acc_get_vf_dev(struct vfio_device *vdev)
+{
+	return container_of(vdev, struct hisi_acc_vf_core_device,
+			    core_device.vdev);
+}
+
 static void hisi_acc_vf_reset(struct hisi_acc_vf_core_device *hisi_acc_vdev)
 {
 	hisi_acc_vdev->vf_qm_state = QM_NOT_READY;
@@ -1033,8 +1039,7 @@ static struct file *
 hisi_acc_vfio_pci_set_device_state(struct vfio_device *vdev,
 				   enum vfio_device_mig_state new_state)
 {
-	struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(vdev,
-			struct hisi_acc_vf_core_device, core_device.vdev);
+	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
 	enum vfio_device_mig_state next_state;
 	struct file *res = NULL;
 	int ret;
@@ -1075,8 +1080,7 @@ static int
 hisi_acc_vfio_pci_get_device_state(struct vfio_device *vdev,
 				   enum vfio_device_mig_state *curr_state)
 {
-	struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(vdev,
-			struct hisi_acc_vf_core_device, core_device.vdev);
+	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
 
 	mutex_lock(&hisi_acc_vdev->state_mutex);
 	*curr_state = hisi_acc_vdev->mig_state;
@@ -1280,8 +1284,7 @@ static long hisi_acc_vfio_pci_ioctl(struct vfio_device *core_vdev, unsigned int
 
 static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
 {
-	struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(core_vdev,
-			struct hisi_acc_vf_core_device, core_device.vdev);
+	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
 	struct vfio_pci_core_device *vdev = &hisi_acc_vdev->core_device;
 	int ret;
 
@@ -1304,8 +1307,7 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
 
 static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev)
 {
-	struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(core_vdev,
-			struct hisi_acc_vf_core_device, core_device.vdev);
+	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
 	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
 
 	iounmap(vf_qm->io_base);
@@ -1320,8 +1322,7 @@ static const struct vfio_migration_ops hisi_acc_vfio_pci_migrn_state_ops = {
 
 static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev)
 {
-	struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(core_vdev,
-			struct hisi_acc_vf_core_device, core_device.vdev);
+	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
 	struct pci_dev *pdev = to_pci_dev(core_vdev->dev);
 	struct hisi_qm *pf_qm = hisi_acc_get_pf_qm(pdev);
 
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v8 2/4] hisi_acc_vfio_pci: create subfunction for data reading
  2024-08-06 12:29 [PATCH v8 0/4] debugfs to hisilicon migration driver Longfang Liu
  2024-08-06 12:29 ` [PATCH v8 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
@ 2024-08-06 12:29 ` Longfang Liu
  2024-08-06 12:29 ` [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
  2024-08-06 12:29 ` [PATCH v8 4/4] Documentation: add debugfs description for hisi migration Longfang Liu
  3 siblings, 0 replies; 12+ messages in thread
From: Longfang Liu @ 2024-08-06 12:29 UTC (permalink / raw)
  To: alex.williamson, jgg, shameerali.kolothum.thodi, jonathan.cameron
  Cc: kvm, linux-kernel, linuxarm, liulongfang

This patch generates the code for the operation of reading data from
the device into a sub-function.
Then, it can be called during the device status data saving phase of
the live migration process and the device status data reading function
in debugfs.
Thereby reducing the redundant code of the driver.

Signed-off-by: Longfang Liu <liulongfang@huawei.com>
Reviewed-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
---
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 54 +++++++++++--------
 1 file changed, 33 insertions(+), 21 deletions(-)

diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
index 45351be8e270..a8c53952d82e 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
@@ -486,31 +486,11 @@ static int vf_qm_load_data(struct hisi_acc_vf_core_device *hisi_acc_vdev,
 	return 0;
 }
 
-static int vf_qm_state_save(struct hisi_acc_vf_core_device *hisi_acc_vdev,
-			    struct hisi_acc_vf_migration_file *migf)
+static int vf_qm_read_data(struct hisi_qm *vf_qm, struct acc_vf_data *vf_data)
 {
-	struct acc_vf_data *vf_data = &migf->vf_data;
-	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
 	struct device *dev = &vf_qm->pdev->dev;
 	int ret;
 
-	if (unlikely(qm_wait_dev_not_ready(vf_qm))) {
-		/* Update state and return with match data */
-		vf_data->vf_qm_state = QM_NOT_READY;
-		hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state;
-		migf->total_length = QM_MATCH_SIZE;
-		return 0;
-	}
-
-	vf_data->vf_qm_state = QM_READY;
-	hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state;
-
-	ret = vf_qm_cache_wb(vf_qm);
-	if (ret) {
-		dev_err(dev, "failed to writeback QM Cache!\n");
-		return ret;
-	}
-
 	ret = qm_get_regs(vf_qm, vf_data);
 	if (ret)
 		return -EINVAL;
@@ -536,6 +516,38 @@ static int vf_qm_state_save(struct hisi_acc_vf_core_device *hisi_acc_vdev,
 		return -EINVAL;
 	}
 
+	return 0;
+}
+
+static int vf_qm_state_save(struct hisi_acc_vf_core_device *hisi_acc_vdev,
+			    struct hisi_acc_vf_migration_file *migf)
+{
+	struct acc_vf_data *vf_data = &migf->vf_data;
+	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
+	struct device *dev = &vf_qm->pdev->dev;
+	int ret;
+
+	if (unlikely(qm_wait_dev_not_ready(vf_qm))) {
+		/* Update state and return with match data */
+		vf_data->vf_qm_state = QM_NOT_READY;
+		hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state;
+		migf->total_length = QM_MATCH_SIZE;
+		return 0;
+	}
+
+	vf_data->vf_qm_state = QM_READY;
+	hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state;
+
+	ret = vf_qm_cache_wb(vf_qm);
+	if (ret) {
+		dev_err(dev, "failed to writeback QM Cache!\n");
+		return ret;
+	}
+
+	ret = vf_qm_read_data(vf_qm, vf_data);
+	if (ret)
+		return -EINVAL;
+
 	migf->total_length = sizeof(struct acc_vf_data);
 	return 0;
 }
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-08-06 12:29 [PATCH v8 0/4] debugfs to hisilicon migration driver Longfang Liu
  2024-08-06 12:29 ` [PATCH v8 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
  2024-08-06 12:29 ` [PATCH v8 2/4] hisi_acc_vfio_pci: create subfunction for data reading Longfang Liu
@ 2024-08-06 12:29 ` Longfang Liu
  2024-08-14  9:39   ` Shameerali Kolothum Thodi
  2024-08-26 21:06   ` Alex Williamson
  2024-08-06 12:29 ` [PATCH v8 4/4] Documentation: add debugfs description for hisi migration Longfang Liu
  3 siblings, 2 replies; 12+ messages in thread
From: Longfang Liu @ 2024-08-06 12:29 UTC (permalink / raw)
  To: alex.williamson, jgg, shameerali.kolothum.thodi, jonathan.cameron
  Cc: kvm, linux-kernel, linuxarm, liulongfang

On the debugfs framework of VFIO, if the CONFIG_VFIO_DEBUGFS macro is
enabled, the debug function is registered for the live migration driver
of the HiSilicon accelerator device.

After registering the HiSilicon accelerator device on the debugfs
framework of live migration of vfio, a directory file "hisi_acc"
of debugfs is created, and then three debug function files are
created in this directory:

   vfio
    |
    +---<dev_name1>
    |    +---migration
    |        +--state
    |        +--hisi_acc
    |            +--dev_data
    |            +--migf_data
    |            +--cmd_state
    |
    +---<dev_name2>
         +---migration
             +--state
             +--hisi_acc
                 +--dev_data
                 +--migf_data
                 +--cmd_state

dev_data file: read device data that needs to be migrated from the
current device in real time
migf_data file: read the migration data of the last live migration
from the current driver.
cmd_state: used to get the cmd channel state for the device.

+----------------+        +--------------+       +---------------+
| migration dev  |        |   src  dev   |       |   dst  dev    |
+-------+--------+        +------+-------+       +-------+-------+
        |                        |                       |
        |                 +------v-------+       +-------v-------+
        |                 |  saving_migf |       | resuming_migf |
  read  |                 |     file     |       |     file      |
        |                 +------+-------+       +-------+-------+
        |                        |          copy         |
        |                        +------------+----------+
        |                                     |
+-------v--------+                    +-------v--------+
|   data buffer  |                    |   debug_migf   |
+-------+--------+                    +-------+--------+
        |                                     |
   cat  |                                 cat |
+-------v--------+                    +-------v--------+
|   dev_data     |                    |   migf_data    |
+----------------+                    +----------------+

When accessing debugfs, user can obtain the most recent status data
of the device through the "dev_data" file. It can read recent
complete status data of the device. If the current device is being
migrated, it will wait for it to complete.
The data for the last completed migration function will be stored
in debug_migf. Users can read it via "migf_data".

Signed-off-by: Longfang Liu <liulongfang@huawei.com>
---
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 209 ++++++++++++++++++
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |   6 +
 2 files changed, 215 insertions(+)

diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
index a8c53952d82e..379657904f86 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
@@ -627,15 +627,30 @@ static void hisi_acc_vf_disable_fd(struct hisi_acc_vf_migration_file *migf)
 	mutex_unlock(&migf->lock);
 }
 
+static void hisi_acc_debug_migf_copy(struct hisi_acc_vf_core_device *hisi_acc_vdev,
+	struct hisi_acc_vf_migration_file *src_migf)
+{
+	struct hisi_acc_vf_migration_file *dst_migf = hisi_acc_vdev->debug_migf;
+
+	if (!dst_migf)
+		return;
+
+	dst_migf->total_length = src_migf->total_length;
+	memcpy(&dst_migf->vf_data, &src_migf->vf_data,
+		sizeof(struct acc_vf_data));
+}
+
 static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vdev)
 {
 	if (hisi_acc_vdev->resuming_migf) {
+		hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->resuming_migf);
 		hisi_acc_vf_disable_fd(hisi_acc_vdev->resuming_migf);
 		fput(hisi_acc_vdev->resuming_migf->filp);
 		hisi_acc_vdev->resuming_migf = NULL;
 	}
 
 	if (hisi_acc_vdev->saving_migf) {
+		hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->saving_migf);
 		hisi_acc_vf_disable_fd(hisi_acc_vdev->saving_migf);
 		fput(hisi_acc_vdev->saving_migf->filp);
 		hisi_acc_vdev->saving_migf = NULL;
@@ -1294,6 +1309,191 @@ static long hisi_acc_vfio_pci_ioctl(struct vfio_device *core_vdev, unsigned int
 	return vfio_pci_core_ioctl(core_vdev, cmd, arg);
 }
 
+static int hisi_acc_vf_debug_check(struct seq_file *seq, struct vfio_device *vdev)
+{
+	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
+	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
+	int ret;
+
+	lockdep_assert_held(&hisi_acc_vdev->state_mutex);
+	if (!vdev->mig_ops) {
+		seq_printf(seq, "%s\n", "device does not support live migration!\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * When the device is not opened, the io_base is not mapped.
+	 * The driver cannot perform device read and write operations.
+	 */
+	if (!hisi_acc_vdev->dev_opened) {
+		seq_printf(seq, "%s\n", "device not opened!\n");
+		return -EINVAL;
+	}
+
+	ret = qm_wait_dev_not_ready(vf_qm);
+	if (ret) {
+		seq_printf(seq, "%s\n", "VF device not ready!\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int hisi_acc_vf_debug_cmd(struct seq_file *seq, void *data)
+{
+	struct device *vf_dev = seq->private;
+	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
+	struct vfio_device *vdev = &core_device->vdev;
+	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
+	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
+	u64 value;
+	int ret;
+
+	mutex_lock(&hisi_acc_vdev->state_mutex);
+	ret = hisi_acc_vf_debug_check(seq, vdev);
+	if (ret) {
+		mutex_unlock(&hisi_acc_vdev->state_mutex);
+		return ret;
+	}
+
+	value = readl(vf_qm->io_base + QM_MB_CMD_SEND_BASE);
+	if (value == QM_MB_CMD_NOT_READY) {
+		mutex_unlock(&hisi_acc_vdev->state_mutex);
+		seq_printf(seq, "mailbox cmd channel not ready!\n");
+		return -EINVAL;
+	}
+	mutex_unlock(&hisi_acc_vdev->state_mutex);
+	seq_printf(seq, "mailbox cmd channel ready!\n");
+
+	return 0;
+}
+
+static int hisi_acc_vf_dev_read(struct seq_file *seq, void *data)
+{
+	struct device *vf_dev = seq->private;
+	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
+	struct vfio_device *vdev = &core_device->vdev;
+	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
+	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
+	struct acc_vf_data *vf_data = NULL;
+	int ret;
+
+	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
+	if (!vf_data)
+		return -ENOMEM;
+
+	mutex_lock(&hisi_acc_vdev->state_mutex);
+	ret = hisi_acc_vf_debug_check(seq, vdev);
+	if (ret) {
+		mutex_unlock(&hisi_acc_vdev->state_mutex);
+		goto migf_err;
+	}
+
+	vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state;
+	ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data);
+	if (ret) {
+		mutex_unlock(&hisi_acc_vdev->state_mutex);
+		goto migf_err;
+	}
+
+	mutex_unlock(&hisi_acc_vdev->state_mutex);
+
+	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
+			(unsigned char *)vf_data,
+			vf_data_sz, false);
+
+	seq_printf(seq,
+		 "acc device:\n"
+		 "device  ready: %u\n"
+		 "device  opened: %d\n"
+		 "data     size: %lu\n",
+		 hisi_acc_vdev->vf_qm_state,
+		 hisi_acc_vdev->dev_opened,
+		 sizeof(struct acc_vf_data));
+
+migf_err:
+	kfree(vf_data);
+
+	return ret;
+}
+
+static int hisi_acc_vf_migf_read(struct seq_file *seq, void *data)
+{
+	struct device *vf_dev = seq->private;
+	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
+	struct vfio_device *vdev = &core_device->vdev;
+	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
+	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
+	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
+
+	/* Check whether the live migration operation has been performed */
+	if (debug_migf->total_length < QM_MATCH_SIZE) {
+		seq_printf(seq, "%s\n", "device not migrated!\n");
+		return -EAGAIN;
+	}
+
+	seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
+			(unsigned char *)&debug_migf->vf_data,
+			vf_data_sz, false);
+
+	seq_printf(seq,
+		 "acc device:\n"
+		 "device  ready: %u\n"
+		 "device  opened: %d\n"
+		 "data     size: %lu\n",
+		 hisi_acc_vdev->vf_qm_state,
+		 hisi_acc_vdev->dev_opened,
+		 debug_migf->total_length);
+
+	return 0;
+}
+
+static int hisi_acc_vfio_debug_init(struct hisi_acc_vf_core_device *hisi_acc_vdev)
+{
+	struct vfio_device *vdev = &hisi_acc_vdev->core_device.vdev;
+	struct dentry *vfio_dev_migration = NULL;
+	struct dentry *vfio_hisi_acc = NULL;
+	struct device *dev = vdev->dev;
+	void *migf = NULL;
+
+	if (!debugfs_initialized() ||
+	    !IS_ENABLED(CONFIG_VFIO_DEBUGFS))
+		return 0;
+
+	migf = kzalloc(sizeof(struct hisi_acc_vf_migration_file), GFP_KERNEL);
+	if (!migf)
+		return -ENOMEM;
+	hisi_acc_vdev->debug_migf = migf;
+
+	vfio_dev_migration = debugfs_lookup("migration", vdev->debug_root);
+	if (!vfio_dev_migration) {
+		kfree(migf);
+		hisi_acc_vdev->debug_migf = NULL;
+		dev_err(dev, "failed to lookup migration debugfs file!\n");
+		return -ENODEV;
+	}
+
+	vfio_hisi_acc = debugfs_create_dir("hisi_acc", vfio_dev_migration);
+	debugfs_create_devm_seqfile(dev, "dev_data", vfio_hisi_acc,
+				  hisi_acc_vf_dev_read);
+	debugfs_create_devm_seqfile(dev, "migf_data", vfio_hisi_acc,
+				  hisi_acc_vf_migf_read);
+	debugfs_create_devm_seqfile(dev, "cmd_state", vfio_hisi_acc,
+				  hisi_acc_vf_debug_cmd);
+
+	return 0;
+}
+
+static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev)
+{
+	if (!debugfs_initialized() ||
+	    !IS_ENABLED(CONFIG_VFIO_DEBUGFS))
+		return;
+
+	if (hisi_acc_vdev->debug_migf)
+		kfree(hisi_acc_vdev->debug_migf);
+}
+
 static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
 {
 	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
@@ -1311,9 +1511,11 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
 			return ret;
 		}
 		hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING;
+		hisi_acc_vdev->dev_opened = true;
 	}
 
 	vfio_pci_core_finish_enable(vdev);
+
 	return 0;
 }
 
@@ -1322,7 +1524,10 @@ static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev)
 	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
 	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
 
+	mutex_lock(&hisi_acc_vdev->state_mutex);
+	hisi_acc_vdev->dev_opened = false;
 	iounmap(vf_qm->io_base);
+	mutex_unlock(&hisi_acc_vdev->state_mutex);
 	vfio_pci_core_close_device(core_vdev);
 }
 
@@ -1413,6 +1618,9 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device
 	ret = vfio_pci_core_register_device(&hisi_acc_vdev->core_device);
 	if (ret)
 		goto out_put_vdev;
+
+	if (ops == &hisi_acc_vfio_pci_migrn_ops)
+		hisi_acc_vfio_debug_init(hisi_acc_vdev);
 	return 0;
 
 out_put_vdev:
@@ -1425,6 +1633,7 @@ static void hisi_acc_vfio_pci_remove(struct pci_dev *pdev)
 	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev);
 
 	vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);
+	hisi_acc_vf_debugfs_exit(hisi_acc_vdev);
 	vfio_put_device(&hisi_acc_vdev->core_device.vdev);
 }
 
diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
index 5bab46602fad..f86f3b88b09e 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
@@ -32,6 +32,7 @@
 #define QM_SQC_VFT_BASE_MASK_V2		GENMASK(15, 0)
 #define QM_SQC_VFT_NUM_SHIFT_V2		45
 #define QM_SQC_VFT_NUM_MASK_V2		GENMASK(9, 0)
+#define QM_MB_CMD_NOT_READY	0xffffffff
 
 /* RW regs */
 #define QM_REGS_MAX_LEN		7
@@ -111,5 +112,10 @@ struct hisi_acc_vf_core_device {
 	int vf_id;
 	struct hisi_acc_vf_migration_file *resuming_migf;
 	struct hisi_acc_vf_migration_file *saving_migf;
+
+	/* To make sure the device is opened */
+	bool dev_opened;
+	/* To save migration data */
+	struct hisi_acc_vf_migration_file *debug_migf;
 };
 #endif /* HISI_ACC_VFIO_PCI_H */
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v8 4/4] Documentation: add debugfs description for hisi migration
  2024-08-06 12:29 [PATCH v8 0/4] debugfs to hisilicon migration driver Longfang Liu
                   ` (2 preceding siblings ...)
  2024-08-06 12:29 ` [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
@ 2024-08-06 12:29 ` Longfang Liu
  2024-08-14  9:35   ` Shameerali Kolothum Thodi
  3 siblings, 1 reply; 12+ messages in thread
From: Longfang Liu @ 2024-08-06 12:29 UTC (permalink / raw)
  To: alex.williamson, jgg, shameerali.kolothum.thodi, jonathan.cameron
  Cc: kvm, linux-kernel, linuxarm, liulongfang

Add a debugfs document description file to help users understand
how to use the hisilicon accelerator live migration driver's
debugfs.

Update the file paths that need to be maintained in MAINTAINERS

Signed-off-by: Longfang Liu <liulongfang@huawei.com>
---
 .../ABI/testing/debugfs-hisi-migration        | 25 +++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 Documentation/ABI/testing/debugfs-hisi-migration

diff --git a/Documentation/ABI/testing/debugfs-hisi-migration b/Documentation/ABI/testing/debugfs-hisi-migration
new file mode 100644
index 000000000000..ad6eb437cdcd
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-hisi-migration
@@ -0,0 +1,25 @@
+What:		/sys/kernel/debug/vfio/<device>/migration/hisi_acc/dev_data
+Date:		Aug 2024
+KernelVersion:  6.11
+Contact:	Longfang Liu <liulongfang@huawei.com>
+Description:	Read the configuration data and some status data
+		required for device live migration. These data include device
+		status data, queue configuration data, some task configuration
+		data and device attribute data. The output format of the data
+		is defined by the live migration driver.
+
+What:		/sys/kernel/debug/vfio/<device>/migration/hisi_acc/migf_data
+Date:		Aug 2024
+KernelVersion:  6.11
+Contact:	Longfang Liu <liulongfang@huawei.com>
+Description:	Read the data from the last completed live migration.
+		This data includes the same device status data as in "dev_data".
+		The migf_data is the dev_data that is migrated.
+
+What:		/sys/kernel/debug/vfio/<device>/migration/hisi_acc/cmd_state
+Date:		Aug 2024
+KernelVersion:  6.11
+Contact:	Longfang Liu <liulongfang@huawei.com>
+Description:	Used to obtain the device command sending and receiving
+		channel status. Returns failure or success logs based on the
+		results.
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* RE: [PATCH v8 4/4] Documentation: add debugfs description for hisi migration
  2024-08-06 12:29 ` [PATCH v8 4/4] Documentation: add debugfs description for hisi migration Longfang Liu
@ 2024-08-14  9:35   ` Shameerali Kolothum Thodi
  0 siblings, 0 replies; 12+ messages in thread
From: Shameerali Kolothum Thodi @ 2024-08-14  9:35 UTC (permalink / raw)
  To: liulongfang, alex.williamson@redhat.com, jgg@nvidia.com,
	Jonathan Cameron
  Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	linuxarm@openeuler.org



> -----Original Message-----
> From: liulongfang <liulongfang@huawei.com>
> Sent: Tuesday, August 6, 2024 1:29 PM
> To: alex.williamson@redhat.com; jgg@nvidia.com; Shameerali Kolothum Thodi
> <shameerali.kolothum.thodi@huawei.com>; Jonathan Cameron
> <jonathan.cameron@huawei.com>
> Cc: kvm@vger.kernel.org; linux-kernel@vger.kernel.org;
> linuxarm@openeuler.org; liulongfang <liulongfang@huawei.com>
> Subject: [PATCH v8 4/4] Documentation: add debugfs description for hisi
> migration
> 
> Add a debugfs document description file to help users understand
> how to use the hisilicon accelerator live migration driver's
> debugfs.
> 
> Update the file paths that need to be maintained in MAINTAINERS
> 
> Signed-off-by: Longfang Liu <liulongfang@huawei.com>

LGTM,

Reviewed-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>

Thanks,
Shameer

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-08-06 12:29 ` [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
@ 2024-08-14  9:39   ` Shameerali Kolothum Thodi
  2024-08-22  8:29     ` liulongfang
  2024-08-26 21:06   ` Alex Williamson
  1 sibling, 1 reply; 12+ messages in thread
From: Shameerali Kolothum Thodi @ 2024-08-14  9:39 UTC (permalink / raw)
  To: liulongfang, alex.williamson@redhat.com, jgg@nvidia.com,
	Jonathan Cameron
  Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	linuxarm@openeuler.org



> -----Original Message-----
> From: liulongfang <liulongfang@huawei.com>
> Sent: Tuesday, August 6, 2024 1:29 PM
> To: alex.williamson@redhat.com; jgg@nvidia.com; Shameerali Kolothum Thodi
> <shameerali.kolothum.thodi@huawei.com>; Jonathan Cameron
> <jonathan.cameron@huawei.com>
> Cc: kvm@vger.kernel.org; linux-kernel@vger.kernel.org;
> linuxarm@openeuler.org; liulongfang <liulongfang@huawei.com>
> Subject: [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon
> migration driver
... 
> +static int hisi_acc_vf_dev_read(struct seq_file *seq, void *data)
> +{
> +	struct device *vf_dev = seq->private;
> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
> +	struct vfio_device *vdev = &core_device->vdev;
> +	struct hisi_acc_vf_core_device *hisi_acc_vdev =
> hisi_acc_get_vf_dev(vdev);
> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
> +	struct acc_vf_data *vf_data = NULL;
> +	int ret;
> +
> +	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
> +	if (!vf_data)
> +		return -ENOMEM;
> +
> +	mutex_lock(&hisi_acc_vdev->state_mutex);
> +	ret = hisi_acc_vf_debug_check(seq, vdev);
> +	if (ret) {
> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
> +		goto migf_err;
> +	}
> +
> +	vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state;
> +	ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data);
> +	if (ret) {
> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
> +		goto migf_err;
> +	}
> +
> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
> +
> +	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
> +			(unsigned char *)vf_data,
> +			vf_data_sz, false);
> +
> +	seq_printf(seq,
> +		 "acc device:\n"
> +		 "device  ready: %u\n"
> +		 "device  opened: %d\n"
> +		 "data     size: %lu\n",
> +		 hisi_acc_vdev->vf_qm_state,
> +		 hisi_acc_vdev->dev_opened,

I think the dev_opened will be always true if it reaches here and can be
removed from here and from hisi_acc_vf_migf_read() as well.

Please don't respin just for this. Let us wait for others to review this.

Thanks,
Shameer

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-08-14  9:39   ` Shameerali Kolothum Thodi
@ 2024-08-22  8:29     ` liulongfang
  0 siblings, 0 replies; 12+ messages in thread
From: liulongfang @ 2024-08-22  8:29 UTC (permalink / raw)
  To: Shameerali Kolothum Thodi, alex.williamson@redhat.com,
	jgg@nvidia.com, Jonathan Cameron
  Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	linuxarm@openeuler.org

On 2024/8/14 17:39, Shameerali Kolothum Thodi wrote:
> 
> 
>> -----Original Message-----
>> From: liulongfang <liulongfang@huawei.com>
>> Sent: Tuesday, August 6, 2024 1:29 PM
>> To: alex.williamson@redhat.com; jgg@nvidia.com; Shameerali Kolothum Thodi
>> <shameerali.kolothum.thodi@huawei.com>; Jonathan Cameron
>> <jonathan.cameron@huawei.com>
>> Cc: kvm@vger.kernel.org; linux-kernel@vger.kernel.org;
>> linuxarm@openeuler.org; liulongfang <liulongfang@huawei.com>
>> Subject: [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon
>> migration driver
> ... 
>> +static int hisi_acc_vf_dev_read(struct seq_file *seq, void *data)
>> +{
>> +	struct device *vf_dev = seq->private;
>> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
>> +	struct vfio_device *vdev = &core_device->vdev;
>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev =
>> hisi_acc_get_vf_dev(vdev);
>> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
>> +	struct acc_vf_data *vf_data = NULL;
>> +	int ret;
>> +
>> +	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
>> +	if (!vf_data)
>> +		return -ENOMEM;
>> +
>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>> +	if (ret) {
>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +		goto migf_err;
>> +	}
>> +
>> +	vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state;
>> +	ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data);
>> +	if (ret) {
>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +		goto migf_err;
>> +	}
>> +
>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +
>> +	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
>> +			(unsigned char *)vf_data,
>> +			vf_data_sz, false);
>> +
>> +	seq_printf(seq,
>> +		 "acc device:\n"
>> +		 "device  ready: %u\n"
>> +		 "device  opened: %d\n"
>> +		 "data     size: %lu\n",
>> +		 hisi_acc_vdev->vf_qm_state,
>> +		 hisi_acc_vdev->dev_opened,
> 
> I think the dev_opened will be always true if it reaches here and can be
> removed from here and from hisi_acc_vf_migf_read() as well.
> 
> Please don't respin just for this. Let us wait for others to review this.
>
Hello,Alex Williamson and Jason Gunthorpe:

Could you take a moment to review this patch?

Thanks,
Longfang.

> Thanks,
> Shameer
> .
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-08-06 12:29 ` [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
  2024-08-14  9:39   ` Shameerali Kolothum Thodi
@ 2024-08-26 21:06   ` Alex Williamson
  2024-08-27  9:35     ` liulongfang
  2024-08-27 12:41     ` liulongfang
  1 sibling, 2 replies; 12+ messages in thread
From: Alex Williamson @ 2024-08-26 21:06 UTC (permalink / raw)
  To: Longfang Liu
  Cc: jgg, shameerali.kolothum.thodi, jonathan.cameron, kvm,
	linux-kernel, linuxarm

On Tue, 6 Aug 2024 20:29:27 +0800
Longfang Liu <liulongfang@huawei.com> wrote:

> On the debugfs framework of VFIO, if the CONFIG_VFIO_DEBUGFS macro is
> enabled, the debug function is registered for the live migration driver
> of the HiSilicon accelerator device.
> 
> After registering the HiSilicon accelerator device on the debugfs
> framework of live migration of vfio, a directory file "hisi_acc"
> of debugfs is created, and then three debug function files are
> created in this directory:
> 
>    vfio
>     |
>     +---<dev_name1>
>     |    +---migration
>     |        +--state
>     |        +--hisi_acc
>     |            +--dev_data
>     |            +--migf_data
>     |            +--cmd_state
>     |
>     +---<dev_name2>
>          +---migration
>              +--state
>              +--hisi_acc
>                  +--dev_data
>                  +--migf_data
>                  +--cmd_state
> 
> dev_data file: read device data that needs to be migrated from the
> current device in real time
> migf_data file: read the migration data of the last live migration
> from the current driver.
> cmd_state: used to get the cmd channel state for the device.
> 
> +----------------+        +--------------+       +---------------+
> | migration dev  |        |   src  dev   |       |   dst  dev    |
> +-------+--------+        +------+-------+       +-------+-------+
>         |                        |                       |
>         |                 +------v-------+       +-------v-------+
>         |                 |  saving_migf |       | resuming_migf |
>   read  |                 |     file     |       |     file      |
>         |                 +------+-------+       +-------+-------+
>         |                        |          copy         |
>         |                        +------------+----------+
>         |                                     |
> +-------v--------+                    +-------v--------+
> |   data buffer  |                    |   debug_migf   |
> +-------+--------+                    +-------+--------+
>         |                                     |
>    cat  |                                 cat |
> +-------v--------+                    +-------v--------+
> |   dev_data     |                    |   migf_data    |
> +----------------+                    +----------------+
> 
> When accessing debugfs, user can obtain the most recent status data
> of the device through the "dev_data" file. It can read recent
> complete status data of the device. If the current device is being
> migrated, it will wait for it to complete.
> The data for the last completed migration function will be stored
> in debug_migf. Users can read it via "migf_data".
> 
> Signed-off-by: Longfang Liu <liulongfang@huawei.com>
> ---
>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 209 ++++++++++++++++++
>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |   6 +
>  2 files changed, 215 insertions(+)
> 
> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> index a8c53952d82e..379657904f86 100644
> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> @@ -627,15 +627,30 @@ static void hisi_acc_vf_disable_fd(struct hisi_acc_vf_migration_file *migf)
>  	mutex_unlock(&migf->lock);
>  }
>  
> +static void hisi_acc_debug_migf_copy(struct hisi_acc_vf_core_device *hisi_acc_vdev,
> +	struct hisi_acc_vf_migration_file *src_migf)
> +{
> +	struct hisi_acc_vf_migration_file *dst_migf = hisi_acc_vdev->debug_migf;
> +
> +	if (!dst_migf)
> +		return;
> +
> +	dst_migf->total_length = src_migf->total_length;
> +	memcpy(&dst_migf->vf_data, &src_migf->vf_data,
> +		sizeof(struct acc_vf_data));
> +}
> +
>  static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>  {
>  	if (hisi_acc_vdev->resuming_migf) {
> +		hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->resuming_migf);
>  		hisi_acc_vf_disable_fd(hisi_acc_vdev->resuming_migf);
>  		fput(hisi_acc_vdev->resuming_migf->filp);
>  		hisi_acc_vdev->resuming_migf = NULL;
>  	}
>  
>  	if (hisi_acc_vdev->saving_migf) {
> +		hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->saving_migf);
>  		hisi_acc_vf_disable_fd(hisi_acc_vdev->saving_migf);
>  		fput(hisi_acc_vdev->saving_migf->filp);
>  		hisi_acc_vdev->saving_migf = NULL;
> @@ -1294,6 +1309,191 @@ static long hisi_acc_vfio_pci_ioctl(struct vfio_device *core_vdev, unsigned int
>  	return vfio_pci_core_ioctl(core_vdev, cmd, arg);
>  }
>  
> +static int hisi_acc_vf_debug_check(struct seq_file *seq, struct vfio_device *vdev)
> +{
> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
> +	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
> +	int ret;
> +
> +	lockdep_assert_held(&hisi_acc_vdev->state_mutex);
> +	if (!vdev->mig_ops) {
> +		seq_printf(seq, "%s\n", "device does not support live migration!\n");
> +		return -EINVAL;
> +	}

I don't think it's possible for this to be called with this condition,
the debugfs files are only registered when this exists.

Also, we don't need %s for a fixed string, nor do we need multiple new
lines.  Please fix throughout.

> +
> +	/*
> +	 * When the device is not opened, the io_base is not mapped.
> +	 * The driver cannot perform device read and write operations.
> +	 */
> +	if (!hisi_acc_vdev->dev_opened) {
> +		seq_printf(seq, "%s\n", "device not opened!\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = qm_wait_dev_not_ready(vf_qm);
> +	if (ret) {
> +		seq_printf(seq, "%s\n", "VF device not ready!\n");
> +		return -EBUSY;
> +	}
> +
> +	return 0;
> +}
> +
> +static int hisi_acc_vf_debug_cmd(struct seq_file *seq, void *data)
> +{
> +	struct device *vf_dev = seq->private;
> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
> +	struct vfio_device *vdev = &core_device->vdev;
> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
> +	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
> +	u64 value;
> +	int ret;
> +
> +	mutex_lock(&hisi_acc_vdev->state_mutex);
> +	ret = hisi_acc_vf_debug_check(seq, vdev);
> +	if (ret) {
> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
> +		return ret;
> +	}
> +
> +	value = readl(vf_qm->io_base + QM_MB_CMD_SEND_BASE);
> +	if (value == QM_MB_CMD_NOT_READY) {
> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
> +		seq_printf(seq, "mailbox cmd channel not ready!\n");
> +		return -EINVAL;
> +	}
> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
> +	seq_printf(seq, "mailbox cmd channel ready!\n");

This debugfs entry seems pretty pointless to me.  Also we polled for
the device to be ready in debug_check, so if the channel is not ready
aren't we more likely to see any error (without a seq_printf) in the
first error branch?

> +
> +	return 0;
> +}
> +
> +static int hisi_acc_vf_dev_read(struct seq_file *seq, void *data)
> +{
> +	struct device *vf_dev = seq->private;
> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
> +	struct vfio_device *vdev = &core_device->vdev;
> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
> +	struct acc_vf_data *vf_data = NULL;
> +	int ret;
> +
> +	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
> +	if (!vf_data)
> +		return -ENOMEM;
> +
> +	mutex_lock(&hisi_acc_vdev->state_mutex);
> +	ret = hisi_acc_vf_debug_check(seq, vdev);
> +	if (ret) {
> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
> +		goto migf_err;
> +	}
> +
> +	vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state;
> +	ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data);
> +	if (ret) {
> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
> +		goto migf_err;
> +	}
> +
> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
> +
> +	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
> +			(unsigned char *)vf_data,
> +			vf_data_sz, false);
> +
> +	seq_printf(seq,
> +		 "acc device:\n"
> +		 "device  ready: %u\n"
> +		 "device  opened: %d\n"
> +		 "data     size: %lu\n",
> +		 hisi_acc_vdev->vf_qm_state,
> +		 hisi_acc_vdev->dev_opened,
> +		 sizeof(struct acc_vf_data));

This function called hisi_acc_vf_debug_check() which requires the
device to be opened, therefore except for the race where the unlock
allowed the device to close, what is the purpose of printing the opened
state here?  We can also tell from the hex dump the size of the data,
so why is that value printed here?  vf_qm_state appears to be a state
value rather than a bool, so labeling it as "ready" doesn't make much
sense.  The arbitrary white space also doesn't make much sense.

> +
> +migf_err:
> +	kfree(vf_data);
> +
> +	return ret;
> +}
> +
> +static int hisi_acc_vf_migf_read(struct seq_file *seq, void *data)
> +{
> +	struct device *vf_dev = seq->private;
> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
> +	struct vfio_device *vdev = &core_device->vdev;
> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
> +	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
> +
> +	/* Check whether the live migration operation has been performed */
> +	if (debug_migf->total_length < QM_MATCH_SIZE) {
> +		seq_printf(seq, "%s\n", "device not migrated!\n");
> +		return -EAGAIN;
> +	}
> +
> +	seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
> +			(unsigned char *)&debug_migf->vf_data,
> +			vf_data_sz, false);

Why doesn't this stop at total_length?

> +
> +	seq_printf(seq,
> +		 "acc device:\n"
> +		 "device  ready: %u\n"
> +		 "device  opened: %d\n"
> +		 "data     size: %lu\n",
> +		 hisi_acc_vdev->vf_qm_state,
> +		 hisi_acc_vdev->dev_opened,
> +		 debug_migf->total_length);

Again, "ready" seems more like a "state" value, here opened could be
false, but why do we care(?), size could be inferred from the hex dump,
and white spaces are arbitrary.

> +
> +	return 0;
> +}
> +
> +static int hisi_acc_vfio_debug_init(struct hisi_acc_vf_core_device *hisi_acc_vdev)
> +{
> +	struct vfio_device *vdev = &hisi_acc_vdev->core_device.vdev;
> +	struct dentry *vfio_dev_migration = NULL;
> +	struct dentry *vfio_hisi_acc = NULL;
> +	struct device *dev = vdev->dev;
> +	void *migf = NULL;
> +
> +	if (!debugfs_initialized() ||
> +	    !IS_ENABLED(CONFIG_VFIO_DEBUGFS))
> +		return 0;
> +
> +	migf = kzalloc(sizeof(struct hisi_acc_vf_migration_file), GFP_KERNEL);
> +	if (!migf)
> +		return -ENOMEM;
> +	hisi_acc_vdev->debug_migf = migf;
> +
> +	vfio_dev_migration = debugfs_lookup("migration", vdev->debug_root);

Test this before anything is allocated or assigned.

> +	if (!vfio_dev_migration) {
> +		kfree(migf);
> +		hisi_acc_vdev->debug_migf = NULL;
> +		dev_err(dev, "failed to lookup migration debugfs file!\n");
> +		return -ENODEV;
> +	}
> +
> +	vfio_hisi_acc = debugfs_create_dir("hisi_acc", vfio_dev_migration);
> +	debugfs_create_devm_seqfile(dev, "dev_data", vfio_hisi_acc,
> +				  hisi_acc_vf_dev_read);
> +	debugfs_create_devm_seqfile(dev, "migf_data", vfio_hisi_acc,
> +				  hisi_acc_vf_migf_read);
> +	debugfs_create_devm_seqfile(dev, "cmd_state", vfio_hisi_acc,
> +				  hisi_acc_vf_debug_cmd);
> +
> +	return 0;
> +}

Why does this function return an int when the only caller ignores the
return value?

> +
> +static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev)
> +{
> +	if (!debugfs_initialized() ||
> +	    !IS_ENABLED(CONFIG_VFIO_DEBUGFS))
> +		return;

Do we really need to test these on the exit path?  debug_migf would not
be allocated.

> +
> +	if (hisi_acc_vdev->debug_migf)
> +		kfree(hisi_acc_vdev->debug_migf);

I suppose this is not set NULL because this is only called in the
device remove path.

> +}
> +
>  static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>  {
>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
> @@ -1311,9 +1511,11 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>  			return ret;
>  		}
>  		hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING;
> +		hisi_acc_vdev->dev_opened = true;
>  	}
>  
>  	vfio_pci_core_finish_enable(vdev);
> +
>  	return 0;
>  }
>  
> @@ -1322,7 +1524,10 @@ static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev)
>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
>  	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
>  
> +	mutex_lock(&hisi_acc_vdev->state_mutex);
> +	hisi_acc_vdev->dev_opened = false;
>  	iounmap(vf_qm->io_base);
> +	mutex_unlock(&hisi_acc_vdev->state_mutex);

Co-opting the state_mutex to protect dev_opened is rather sketchy.

>  	vfio_pci_core_close_device(core_vdev);
>  }
>  
> @@ -1413,6 +1618,9 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device
>  	ret = vfio_pci_core_register_device(&hisi_acc_vdev->core_device);
>  	if (ret)
>  		goto out_put_vdev;
> +
> +	if (ops == &hisi_acc_vfio_pci_migrn_ops)
> +		hisi_acc_vfio_debug_init(hisi_acc_vdev);

Call this unconditionally and test hisi_acc_vdev->mig_ops in the
debug_init function.  That way init and exit are symmetric.

>  	return 0;
>  
>  out_put_vdev:
> @@ -1425,6 +1633,7 @@ static void hisi_acc_vfio_pci_remove(struct pci_dev *pdev)
>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev);
>  
>  	vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);
> +	hisi_acc_vf_debugfs_exit(hisi_acc_vdev);
>  	vfio_put_device(&hisi_acc_vdev->core_device.vdev);
>  }
>  
> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
> index 5bab46602fad..f86f3b88b09e 100644
> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
> @@ -32,6 +32,7 @@
>  #define QM_SQC_VFT_BASE_MASK_V2		GENMASK(15, 0)
>  #define QM_SQC_VFT_NUM_SHIFT_V2		45
>  #define QM_SQC_VFT_NUM_MASK_V2		GENMASK(9, 0)
> +#define QM_MB_CMD_NOT_READY	0xffffffff
>  
>  /* RW regs */
>  #define QM_REGS_MAX_LEN		7
> @@ -111,5 +112,10 @@ struct hisi_acc_vf_core_device {
>  	int vf_id;
>  	struct hisi_acc_vf_migration_file *resuming_migf;
>  	struct hisi_acc_vf_migration_file *saving_migf;
> +
> +	/* To make sure the device is opened */
> +	bool dev_opened;
> +	/* To save migration data */
> +	struct hisi_acc_vf_migration_file *debug_migf;

Poor structure packing.

>  };
>  #endif /* HISI_ACC_VFIO_PCI_H */


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-08-26 21:06   ` Alex Williamson
@ 2024-08-27  9:35     ` liulongfang
  2024-08-27 11:26       ` liulongfang
  2024-08-27 12:41     ` liulongfang
  1 sibling, 1 reply; 12+ messages in thread
From: liulongfang @ 2024-08-27  9:35 UTC (permalink / raw)
  To: Alex Williamson
  Cc: jgg, shameerali.kolothum.thodi, jonathan.cameron, kvm,
	linux-kernel, linuxarm

On 2024/8/27 5:06, Alex Williamson wrote:
> On Tue, 6 Aug 2024 20:29:27 +0800
> Longfang Liu <liulongfang@huawei.com> wrote:
> 
>> On the debugfs framework of VFIO, if the CONFIG_VFIO_DEBUGFS macro is
>> enabled, the debug function is registered for the live migration driver
>> of the HiSilicon accelerator device.
>>
>> After registering the HiSilicon accelerator device on the debugfs
>> framework of live migration of vfio, a directory file "hisi_acc"
>> of debugfs is created, and then three debug function files are
>> created in this directory:
>>
>>    vfio
>>     |
>>     +---<dev_name1>
>>     |    +---migration
>>     |        +--state
>>     |        +--hisi_acc
>>     |            +--dev_data
>>     |            +--migf_data
>>     |            +--cmd_state
>>     |
>>     +---<dev_name2>
>>          +---migration
>>              +--state
>>              +--hisi_acc
>>                  +--dev_data
>>                  +--migf_data
>>                  +--cmd_state
>>
>> dev_data file: read device data that needs to be migrated from the
>> current device in real time
>> migf_data file: read the migration data of the last live migration
>> from the current driver.
>> cmd_state: used to get the cmd channel state for the device.
>>
>> +----------------+        +--------------+       +---------------+
>> | migration dev  |        |   src  dev   |       |   dst  dev    |
>> +-------+--------+        +------+-------+       +-------+-------+
>>         |                        |                       |
>>         |                 +------v-------+       +-------v-------+
>>         |                 |  saving_migf |       | resuming_migf |
>>   read  |                 |     file     |       |     file      |
>>         |                 +------+-------+       +-------+-------+
>>         |                        |          copy         |
>>         |                        +------------+----------+
>>         |                                     |
>> +-------v--------+                    +-------v--------+
>> |   data buffer  |                    |   debug_migf   |
>> +-------+--------+                    +-------+--------+
>>         |                                     |
>>    cat  |                                 cat |
>> +-------v--------+                    +-------v--------+
>> |   dev_data     |                    |   migf_data    |
>> +----------------+                    +----------------+
>>
>> When accessing debugfs, user can obtain the most recent status data
>> of the device through the "dev_data" file. It can read recent
>> complete status data of the device. If the current device is being
>> migrated, it will wait for it to complete.
>> The data for the last completed migration function will be stored
>> in debug_migf. Users can read it via "migf_data".
>>
>> Signed-off-by: Longfang Liu <liulongfang@huawei.com>
>> ---
>>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 209 ++++++++++++++++++
>>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |   6 +
>>  2 files changed, 215 insertions(+)
>>
>> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>> index a8c53952d82e..379657904f86 100644
>> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>> @@ -627,15 +627,30 @@ static void hisi_acc_vf_disable_fd(struct hisi_acc_vf_migration_file *migf)
>>  	mutex_unlock(&migf->lock);
>>  }
>>  
>> +static void hisi_acc_debug_migf_copy(struct hisi_acc_vf_core_device *hisi_acc_vdev,
>> +	struct hisi_acc_vf_migration_file *src_migf)
>> +{
>> +	struct hisi_acc_vf_migration_file *dst_migf = hisi_acc_vdev->debug_migf;
>> +
>> +	if (!dst_migf)
>> +		return;
>> +
>> +	dst_migf->total_length = src_migf->total_length;
>> +	memcpy(&dst_migf->vf_data, &src_migf->vf_data,
>> +		sizeof(struct acc_vf_data));
>> +}
>> +
>>  static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>>  {
>>  	if (hisi_acc_vdev->resuming_migf) {
>> +		hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->resuming_migf);
>>  		hisi_acc_vf_disable_fd(hisi_acc_vdev->resuming_migf);
>>  		fput(hisi_acc_vdev->resuming_migf->filp);
>>  		hisi_acc_vdev->resuming_migf = NULL;
>>  	}
>>  
>>  	if (hisi_acc_vdev->saving_migf) {
>> +		hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->saving_migf);
>>  		hisi_acc_vf_disable_fd(hisi_acc_vdev->saving_migf);
>>  		fput(hisi_acc_vdev->saving_migf->filp);
>>  		hisi_acc_vdev->saving_migf = NULL;
>> @@ -1294,6 +1309,191 @@ static long hisi_acc_vfio_pci_ioctl(struct vfio_device *core_vdev, unsigned int
>>  	return vfio_pci_core_ioctl(core_vdev, cmd, arg);
>>  }
>>  
>> +static int hisi_acc_vf_debug_check(struct seq_file *seq, struct vfio_device *vdev)
>> +{
>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>> +	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
>> +	int ret;
>> +
>> +	lockdep_assert_held(&hisi_acc_vdev->state_mutex);
>> +	if (!vdev->mig_ops) {
>> +		seq_printf(seq, "%s\n", "device does not support live migration!\n");
>> +		return -EINVAL;
>> +	}
> 
> I don't think it's possible for this to be called with this condition,
> the debugfs files are only registered when this exists.
> 
> Also, we don't need %s for a fixed string, nor do we need multiple new
> lines.  Please fix throughout.
>

Yes, I looked at the creation process. The debugfs directory only exists
when mig_ops is enabled.
The judgment here is not required.

>> +
>> +	/*
>> +	 * When the device is not opened, the io_base is not mapped.
>> +	 * The driver cannot perform device read and write operations.
>> +	 */
>> +	if (!hisi_acc_vdev->dev_opened) {
>> +		seq_printf(seq, "%s\n", "device not opened!\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = qm_wait_dev_not_ready(vf_qm);
>> +	if (ret) {
>> +		seq_printf(seq, "%s\n", "VF device not ready!\n");
>> +		return -EBUSY;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int hisi_acc_vf_debug_cmd(struct seq_file *seq, void *data)
>> +{
>> +	struct device *vf_dev = seq->private;
>> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
>> +	struct vfio_device *vdev = &core_device->vdev;
>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>> +	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
>> +	u64 value;
>> +	int ret;
>> +
>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>> +	if (ret) {
>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +		return ret;
>> +	}
>> +
>> +	value = readl(vf_qm->io_base + QM_MB_CMD_SEND_BASE);
>> +	if (value == QM_MB_CMD_NOT_READY) {
>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +		seq_printf(seq, "mailbox cmd channel not ready!\n");
>> +		return -EINVAL;
>> +	}
>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +	seq_printf(seq, "mailbox cmd channel ready!\n");
> 
> This debugfs entry seems pretty pointless to me.  Also we polled for
> the device to be ready in debug_check, so if the channel is not ready
> aren't we more likely to see any error (without a seq_printf) in the
> first error branch?
>

This cmd channel check is a means to assist problem location.
The accelerator IO device has some special exception errors,
which will cause the bus to become unresponsive and cause a long
period of silence.
In another scenario, after the live migration command is started,
dirty pages may be generated very quickly, causing the migration
to be silent for a long time.
The cmd channel check here is to deal with this type of problem and
is used to determine whether the bus is abnormal or dirty pages
are being migrated.

>> +
>> +	return 0;
>> +}
>> +
>> +static int hisi_acc_vf_dev_read(struct seq_file *seq, void *data)
>> +{
>> +	struct device *vf_dev = seq->private;
>> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
>> +	struct vfio_device *vdev = &core_device->vdev;
>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
>> +	struct acc_vf_data *vf_data = NULL;
>> +	int ret;
>> +
>> +	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
>> +	if (!vf_data)
>> +		return -ENOMEM;
>> +
>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>> +	if (ret) {
>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +		goto migf_err;
>> +	}
>> +
>> +	vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state;
>> +	ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data);
>> +	if (ret) {
>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +		goto migf_err;
>> +	}
>> +
>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +
>> +	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
>> +			(unsigned char *)vf_data,
>> +			vf_data_sz, false);
>> +
>> +	seq_printf(seq,
>> +		 "acc device:\n"
>> +		 "device  ready: %u\n"
>> +		 "device  opened: %d\n"
>> +		 "data     size: %lu\n",
>> +		 hisi_acc_vdev->vf_qm_state,
>> +		 hisi_acc_vdev->dev_opened,
>> +		 sizeof(struct acc_vf_data));
> 
> This function called hisi_acc_vf_debug_check() which requires the
> device to be opened, therefore except for the race where the unlock
> allowed the device to close, what is the purpose of printing the opened
> state here?  We can also tell from the hex dump the size of the data,
> so why is that value printed here?  vf_qm_state appears to be a state
> value rather than a bool, so labeling it as "ready" doesn't make much
> sense.  The arbitrary white space also doesn't make much sense.
>

The purpose of vf_qm_state is not to indicate whether the current device
is open. It refers to whether the VF device in the VM has a
device driver loaded.

The operation process of live migration is different when the driver
is loaded and when the driver is not loaded.
If the driver is not loaded, then the current IO device must not be
running tasks, so the data migration of the IO device can be directly
skipped during live migration.
Therefore, this status is very useful.

>> +
>> +migf_err:
>> +	kfree(vf_data);
>> +
>> +	return ret;
>> +}
>> +
>> +static int hisi_acc_vf_migf_read(struct seq_file *seq, void *data)
>> +{
>> +	struct device *vf_dev = seq->private;
>> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
>> +	struct vfio_device *vdev = &core_device->vdev;
>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
>> +	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
>> +
>> +	/* Check whether the live migration operation has been performed */
>> +	if (debug_migf->total_length < QM_MATCH_SIZE) {
>> +		seq_printf(seq, "%s\n", "device not migrated!\n");
>> +		return -EAGAIN;
>> +	}
>> +
>> +	seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
>> +			(unsigned char *)&debug_migf->vf_data,
>> +			vf_data_sz, false);
> 
> Why doesn't this stop at total_length?
>

Next is the address data of the device.
The address data cannot be directly output to the log.

>> +
>> +	seq_printf(seq,
>> +		 "acc device:\n"
>> +		 "device  ready: %u\n"
>> +		 "device  opened: %d\n"
>> +		 "data     size: %lu\n",
>> +		 hisi_acc_vdev->vf_qm_state,
>> +		 hisi_acc_vdev->dev_opened,
>> +		 debug_migf->total_length);
> 
> Again, "ready" seems more like a "state" value, here opened could be
> false, but why do we care(?), size could be inferred from the hex dump,
> and white spaces are arbitrary.
>

The spaces can be modified to keep the output results aligned.

When dev_opened here only has log, you can know whether the dump
operation was read before or after qemu was closed.

This detailed information is still necessary when only logs are used
for problem analysis.

>> +
>> +	return 0;
>> +}
>> +
>> +static int hisi_acc_vfio_debug_init(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>> +{
>> +	struct vfio_device *vdev = &hisi_acc_vdev->core_device.vdev;
>> +	struct dentry *vfio_dev_migration = NULL;
>> +	struct dentry *vfio_hisi_acc = NULL;
>> +	struct device *dev = vdev->dev;
>> +	void *migf = NULL;
>> +
>> +	if (!debugfs_initialized() ||
>> +	    !IS_ENABLED(CONFIG_VFIO_DEBUGFS))
>> +		return 0;
>> +
>> +	migf = kzalloc(sizeof(struct hisi_acc_vf_migration_file), GFP_KERNEL);
>> +	if (!migf)
>> +		return -ENOMEM;
>> +	hisi_acc_vdev->debug_migf = migf;
>> +
>> +	vfio_dev_migration = debugfs_lookup("migration", vdev->debug_root);
> 
> Test this before anything is allocated or assigned.
>

OK.

Thanks.
Longfang.

>> +	if (!vfio_dev_migration) {
>> +		kfree(migf);
>> +		hisi_acc_vdev->debug_migf = NULL;
>> +		dev_err(dev, "failed to lookup migration debugfs file!\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	vfio_hisi_acc = debugfs_create_dir("hisi_acc", vfio_dev_migration);
>> +	debugfs_create_devm_seqfile(dev, "dev_data", vfio_hisi_acc,
>> +				  hisi_acc_vf_dev_read);
>> +	debugfs_create_devm_seqfile(dev, "migf_data", vfio_hisi_acc,
>> +				  hisi_acc_vf_migf_read);
>> +	debugfs_create_devm_seqfile(dev, "cmd_state", vfio_hisi_acc,
>> +				  hisi_acc_vf_debug_cmd);
>> +
>> +	return 0;
>> +}
> 
> Why does this function return an int when the only caller ignores the
> return value?
> 
>> +
>> +static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>> +{
>> +	if (!debugfs_initialized() ||
>> +	    !IS_ENABLED(CONFIG_VFIO_DEBUGFS))
>> +		return;
> 
> Do we really need to test these on the exit path?  debug_migf would not
> be allocated.
> 
>> +
>> +	if (hisi_acc_vdev->debug_migf)
>> +		kfree(hisi_acc_vdev->debug_migf);
> 
> I suppose this is not set NULL because this is only called in the
> device remove path.
> 
>> +}
>> +
>>  static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>>  {
>>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
>> @@ -1311,9 +1511,11 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>>  			return ret;
>>  		}
>>  		hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING;
>> +		hisi_acc_vdev->dev_opened = true;
>>  	}
>>  
>>  	vfio_pci_core_finish_enable(vdev);
>> +
>>  	return 0;
>>  }
>>  
>> @@ -1322,7 +1524,10 @@ static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev)
>>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
>>  	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
>>  
>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>> +	hisi_acc_vdev->dev_opened = false;
>>  	iounmap(vf_qm->io_base);
>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
> 
> Co-opting the state_mutex to protect dev_opened is rather sketchy.
> 
>>  	vfio_pci_core_close_device(core_vdev);
>>  }
>>  
>> @@ -1413,6 +1618,9 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device
>>  	ret = vfio_pci_core_register_device(&hisi_acc_vdev->core_device);
>>  	if (ret)
>>  		goto out_put_vdev;
>> +
>> +	if (ops == &hisi_acc_vfio_pci_migrn_ops)
>> +		hisi_acc_vfio_debug_init(hisi_acc_vdev);
> 
> Call this unconditionally and test hisi_acc_vdev->mig_ops in the
> debug_init function.  That way init and exit are symmetric.
> 
>>  	return 0;
>>  
>>  out_put_vdev:
>> @@ -1425,6 +1633,7 @@ static void hisi_acc_vfio_pci_remove(struct pci_dev *pdev)
>>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev);
>>  
>>  	vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);
>> +	hisi_acc_vf_debugfs_exit(hisi_acc_vdev);
>>  	vfio_put_device(&hisi_acc_vdev->core_device.vdev);
>>  }
>>  
>> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>> index 5bab46602fad..f86f3b88b09e 100644
>> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>> @@ -32,6 +32,7 @@
>>  #define QM_SQC_VFT_BASE_MASK_V2		GENMASK(15, 0)
>>  #define QM_SQC_VFT_NUM_SHIFT_V2		45
>>  #define QM_SQC_VFT_NUM_MASK_V2		GENMASK(9, 0)
>> +#define QM_MB_CMD_NOT_READY	0xffffffff
>>  
>>  /* RW regs */
>>  #define QM_REGS_MAX_LEN		7
>> @@ -111,5 +112,10 @@ struct hisi_acc_vf_core_device {
>>  	int vf_id;
>>  	struct hisi_acc_vf_migration_file *resuming_migf;
>>  	struct hisi_acc_vf_migration_file *saving_migf;
>> +
>> +	/* To make sure the device is opened */
>> +	bool dev_opened;
>> +	/* To save migration data */
>> +	struct hisi_acc_vf_migration_file *debug_migf;
> 
> Poor structure packing.
> 
>>  };
>>  #endif /* HISI_ACC_VFIO_PCI_H */
> 
> 
> .
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-08-27  9:35     ` liulongfang
@ 2024-08-27 11:26       ` liulongfang
  0 siblings, 0 replies; 12+ messages in thread
From: liulongfang @ 2024-08-27 11:26 UTC (permalink / raw)
  To: Alex Williamson
  Cc: jgg, shameerali.kolothum.thodi, jonathan.cameron, kvm,
	linux-kernel, linuxarm

On 2024/8/27 17:35, liulongfang write:
> On 2024/8/27 5:06, Alex Williamson wrote:
>> On Tue, 6 Aug 2024 20:29:27 +0800
>> Longfang Liu <liulongfang@huawei.com> wrote:
>>
>>> On the debugfs framework of VFIO, if the CONFIG_VFIO_DEBUGFS macro is
>>> enabled, the debug function is registered for the live migration driver
>>> of the HiSilicon accelerator device.
>>>
>>> After registering the HiSilicon accelerator device on the debugfs
>>> framework of live migration of vfio, a directory file "hisi_acc"
>>> of debugfs is created, and then three debug function files are
>>> created in this directory:
>>>
>>>    vfio
>>>     |
>>>     +---<dev_name1>
>>>     |    +---migration
>>>     |        +--state
>>>     |        +--hisi_acc
>>>     |            +--dev_data
>>>     |            +--migf_data
>>>     |            +--cmd_state
>>>     |
>>>     +---<dev_name2>
>>>          +---migration
>>>              +--state
>>>              +--hisi_acc
>>>                  +--dev_data
>>>                  +--migf_data
>>>                  +--cmd_state
>>>
>>> dev_data file: read device data that needs to be migrated from the
>>> current device in real time
>>> migf_data file: read the migration data of the last live migration
>>> from the current driver.
>>> cmd_state: used to get the cmd channel state for the device.
>>>
>>> +----------------+        +--------------+       +---------------+
>>> | migration dev  |        |   src  dev   |       |   dst  dev    |
>>> +-------+--------+        +------+-------+       +-------+-------+
>>>         |                        |                       |
>>>         |                 +------v-------+       +-------v-------+
>>>         |                 |  saving_migf |       | resuming_migf |
>>>   read  |                 |     file     |       |     file      |
>>>         |                 +------+-------+       +-------+-------+
>>>         |                        |          copy         |
>>>         |                        +------------+----------+
>>>         |                                     |
>>> +-------v--------+                    +-------v--------+
>>> |   data buffer  |                    |   debug_migf   |
>>> +-------+--------+                    +-------+--------+
>>>         |                                     |
>>>    cat  |                                 cat |
>>> +-------v--------+                    +-------v--------+
>>> |   dev_data     |                    |   migf_data    |
>>> +----------------+                    +----------------+
>>>
>>> When accessing debugfs, user can obtain the most recent status data
>>> of the device through the "dev_data" file. It can read recent
>>> complete status data of the device. If the current device is being
>>> migrated, it will wait for it to complete.
>>> The data for the last completed migration function will be stored
>>> in debug_migf. Users can read it via "migf_data".
>>>
>>> Signed-off-by: Longfang Liu <liulongfang@huawei.com>
>>> ---
>>>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 209 ++++++++++++++++++
>>>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |   6 +
>>>  2 files changed, 215 insertions(+)
>>>
>>> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>>> index a8c53952d82e..379657904f86 100644
>>> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>>> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>>> @@ -627,15 +627,30 @@ static void hisi_acc_vf_disable_fd(struct hisi_acc_vf_migration_file *migf)
>>>  	mutex_unlock(&migf->lock);
>>>  }
>>>  
>>> +static void hisi_acc_debug_migf_copy(struct hisi_acc_vf_core_device *hisi_acc_vdev,
>>> +	struct hisi_acc_vf_migration_file *src_migf)
>>> +{
>>> +	struct hisi_acc_vf_migration_file *dst_migf = hisi_acc_vdev->debug_migf;
>>> +
>>> +	if (!dst_migf)
>>> +		return;
>>> +
>>> +	dst_migf->total_length = src_migf->total_length;
>>> +	memcpy(&dst_migf->vf_data, &src_migf->vf_data,
>>> +		sizeof(struct acc_vf_data));
>>> +}
>>> +
>>>  static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>>>  {
>>>  	if (hisi_acc_vdev->resuming_migf) {
>>> +		hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->resuming_migf);
>>>  		hisi_acc_vf_disable_fd(hisi_acc_vdev->resuming_migf);
>>>  		fput(hisi_acc_vdev->resuming_migf->filp);
>>>  		hisi_acc_vdev->resuming_migf = NULL;
>>>  	}
>>>  
>>>  	if (hisi_acc_vdev->saving_migf) {
>>> +		hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->saving_migf);
>>>  		hisi_acc_vf_disable_fd(hisi_acc_vdev->saving_migf);
>>>  		fput(hisi_acc_vdev->saving_migf->filp);
>>>  		hisi_acc_vdev->saving_migf = NULL;
>>> @@ -1294,6 +1309,191 @@ static long hisi_acc_vfio_pci_ioctl(struct vfio_device *core_vdev, unsigned int
>>>  	return vfio_pci_core_ioctl(core_vdev, cmd, arg);
>>>  }
>>>  
>>> +static int hisi_acc_vf_debug_check(struct seq_file *seq, struct vfio_device *vdev)
>>> +{
>>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>>> +	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
>>> +	int ret;
>>> +
>>> +	lockdep_assert_held(&hisi_acc_vdev->state_mutex);
>>> +	if (!vdev->mig_ops) {
>>> +		seq_printf(seq, "%s\n", "device does not support live migration!\n");
>>> +		return -EINVAL;
>>> +	}
>>
>> I don't think it's possible for this to be called with this condition,
>> the debugfs files are only registered when this exists.
>>
>> Also, we don't need %s for a fixed string, nor do we need multiple new
>> lines.  Please fix throughout.
>>
> 
> Yes, I looked at the creation process. The debugfs directory only exists
> when mig_ops is enabled.
> The judgment here is not required.
> 
>>> +
>>> +	/*
>>> +	 * When the device is not opened, the io_base is not mapped.
>>> +	 * The driver cannot perform device read and write operations.
>>> +	 */
>>> +	if (!hisi_acc_vdev->dev_opened) {
>>> +		seq_printf(seq, "%s\n", "device not opened!\n");
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	ret = qm_wait_dev_not_ready(vf_qm);
>>> +	if (ret) {
>>> +		seq_printf(seq, "%s\n", "VF device not ready!\n");
>>> +		return -EBUSY;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int hisi_acc_vf_debug_cmd(struct seq_file *seq, void *data)
>>> +{
>>> +	struct device *vf_dev = seq->private;
>>> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
>>> +	struct vfio_device *vdev = &core_device->vdev;
>>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>>> +	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
>>> +	u64 value;
>>> +	int ret;
>>> +
>>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>>> +	if (ret) {
>>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>>> +		return ret;
>>> +	}
>>> +
>>> +	value = readl(vf_qm->io_base + QM_MB_CMD_SEND_BASE);
>>> +	if (value == QM_MB_CMD_NOT_READY) {
>>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>>> +		seq_printf(seq, "mailbox cmd channel not ready!\n");
>>> +		return -EINVAL;
>>> +	}
>>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
>>> +	seq_printf(seq, "mailbox cmd channel ready!\n");
>>
>> This debugfs entry seems pretty pointless to me.  Also we polled for
>> the device to be ready in debug_check, so if the channel is not ready
>> aren't we more likely to see any error (without a seq_printf) in the
>> first error branch?
>>
> 
> This cmd channel check is a means to assist problem location.
> The accelerator IO device has some special exception errors,
> which will cause the bus to become unresponsive and cause a long
> period of silence.
> In another scenario, after the live migration command is started,
> dirty pages may be generated very quickly, causing the migration
> to be silent for a long time.
> The cmd channel check here is to deal with this type of problem and
> is used to determine whether the bus is abnormal or dirty pages
> are being migrated.
> 
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int hisi_acc_vf_dev_read(struct seq_file *seq, void *data)
>>> +{
>>> +	struct device *vf_dev = seq->private;
>>> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
>>> +	struct vfio_device *vdev = &core_device->vdev;
>>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>>> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
>>> +	struct acc_vf_data *vf_data = NULL;
>>> +	int ret;
>>> +
>>> +	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
>>> +	if (!vf_data)
>>> +		return -ENOMEM;
>>> +
>>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>>> +	if (ret) {
>>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>>> +		goto migf_err;
>>> +	}
>>> +
>>> +	vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state;
>>> +	ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data);
>>> +	if (ret) {
>>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>>> +		goto migf_err;
>>> +	}
>>> +
>>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
>>> +
>>> +	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
>>> +			(unsigned char *)vf_data,
>>> +			vf_data_sz, false);
>>> +
>>> +	seq_printf(seq,
>>> +		 "acc device:\n"
>>> +		 "device  ready: %u\n"
>>> +		 "device  opened: %d\n"
>>> +		 "data     size: %lu\n",
>>> +		 hisi_acc_vdev->vf_qm_state,
>>> +		 hisi_acc_vdev->dev_opened,
>>> +		 sizeof(struct acc_vf_data));
>>
>> This function called hisi_acc_vf_debug_check() which requires the
>> device to be opened, therefore except for the race where the unlock
>> allowed the device to close, what is the purpose of printing the opened
>> state here?  We can also tell from the hex dump the size of the data,
>> so why is that value printed here?  vf_qm_state appears to be a state
>> value rather than a bool, so labeling it as "ready" doesn't make much
>> sense.  The arbitrary white space also doesn't make much sense.
>>
>
dev_opened does not need to be output, but data_size is still needed.
Querying data_size from hex_dump data requires matching against the code
to parse the information.

vf_qm_state is a very important piece of information. It is enabled in
the accelerator Host device driver. At the beginning, there is a Processing
state, indicating that it is loading or deleting.
So there is no problem using the enumeration's status value representation
here.

What you said is changed to bool type. If the driver on the host is modified,
it can be modified simultaneously here.

Thanks.
Longfang.

> The purpose of vf_qm_state is not to indicate whether the current device
> is open. It refers to whether the VF device in the VM has a
> device driver loaded.
> 
> The operation process of live migration is different when the driver
> is loaded and when the driver is not loaded.
> If the driver is not loaded, then the current IO device must not be
> running tasks, so the data migration of the IO device can be directly
> skipped during live migration.
> Therefore, this status is very useful.
> 
>>> +
>>> +migf_err:
>>> +	kfree(vf_data);
>>> +
>>> +	return ret;
>>> +}
>>> +
>>> +static int hisi_acc_vf_migf_read(struct seq_file *seq, void *data)
>>> +{
>>> +	struct device *vf_dev = seq->private;
>>> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
>>> +	struct vfio_device *vdev = &core_device->vdev;
>>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>>> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
>>> +	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
>>> +
>>> +	/* Check whether the live migration operation has been performed */
>>> +	if (debug_migf->total_length < QM_MATCH_SIZE) {
>>> +		seq_printf(seq, "%s\n", "device not migrated!\n");
>>> +		return -EAGAIN;
>>> +	}
>>> +
>>> +	seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
>>> +			(unsigned char *)&debug_migf->vf_data,
>>> +			vf_data_sz, false);
>>
>> Why doesn't this stop at total_length?
>>
> 
> Next is the address data of the device.
> The address data cannot be directly output to the log.
> 
>>> +
>>> +	seq_printf(seq,
>>> +		 "acc device:\n"
>>> +		 "device  ready: %u\n"
>>> +		 "device  opened: %d\n"
>>> +		 "data     size: %lu\n",
>>> +		 hisi_acc_vdev->vf_qm_state,
>>> +		 hisi_acc_vdev->dev_opened,
>>> +		 debug_migf->total_length);
>>
>> Again, "ready" seems more like a "state" value, here opened could be
>> false, but why do we care(?), size could be inferred from the hex dump,
>> and white spaces are arbitrary.
>>
> 
> The spaces can be modified to keep the output results aligned.
> 
> When dev_opened here only has log, you can know whether the dump
> operation was read before or after qemu was closed.
> 
> This detailed information is still necessary when only logs are used
> for problem analysis.
> 
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static int hisi_acc_vfio_debug_init(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>>> +{
>>> +	struct vfio_device *vdev = &hisi_acc_vdev->core_device.vdev;
>>> +	struct dentry *vfio_dev_migration = NULL;
>>> +	struct dentry *vfio_hisi_acc = NULL;
>>> +	struct device *dev = vdev->dev;
>>> +	void *migf = NULL;
>>> +
>>> +	if (!debugfs_initialized() ||
>>> +	    !IS_ENABLED(CONFIG_VFIO_DEBUGFS))
>>> +		return 0;
>>> +
>>> +	migf = kzalloc(sizeof(struct hisi_acc_vf_migration_file), GFP_KERNEL);
>>> +	if (!migf)
>>> +		return -ENOMEM;
>>> +	hisi_acc_vdev->debug_migf = migf;
>>> +
>>> +	vfio_dev_migration = debugfs_lookup("migration", vdev->debug_root);
>>
>> Test this before anything is allocated or assigned.
>>
> 
> OK.
> 
> Thanks.
> Longfang.
> 
>>> +	if (!vfio_dev_migration) {
>>> +		kfree(migf);
>>> +		hisi_acc_vdev->debug_migf = NULL;
>>> +		dev_err(dev, "failed to lookup migration debugfs file!\n");
>>> +		return -ENODEV;
>>> +	}
>>> +
>>> +	vfio_hisi_acc = debugfs_create_dir("hisi_acc", vfio_dev_migration);
>>> +	debugfs_create_devm_seqfile(dev, "dev_data", vfio_hisi_acc,
>>> +				  hisi_acc_vf_dev_read);
>>> +	debugfs_create_devm_seqfile(dev, "migf_data", vfio_hisi_acc,
>>> +				  hisi_acc_vf_migf_read);
>>> +	debugfs_create_devm_seqfile(dev, "cmd_state", vfio_hisi_acc,
>>> +				  hisi_acc_vf_debug_cmd);
>>> +
>>> +	return 0;
>>> +}
>>
>> Why does this function return an int when the only caller ignores the
>> return value?
>>
>>> +
>>> +static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>>> +{
>>> +	if (!debugfs_initialized() ||
>>> +	    !IS_ENABLED(CONFIG_VFIO_DEBUGFS))
>>> +		return;
>>
>> Do we really need to test these on the exit path?  debug_migf would not
>> be allocated.
>>
>>> +
>>> +	if (hisi_acc_vdev->debug_migf)
>>> +		kfree(hisi_acc_vdev->debug_migf);
>>
>> I suppose this is not set NULL because this is only called in the
>> device remove path.
>>
>>> +}
>>> +
>>>  static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>>>  {
>>>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
>>> @@ -1311,9 +1511,11 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>>>  			return ret;
>>>  		}
>>>  		hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING;
>>> +		hisi_acc_vdev->dev_opened = true;
>>>  	}
>>>  
>>>  	vfio_pci_core_finish_enable(vdev);
>>> +
>>>  	return 0;
>>>  }
>>>  
>>> @@ -1322,7 +1524,10 @@ static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev)
>>>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
>>>  	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
>>>  
>>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>>> +	hisi_acc_vdev->dev_opened = false;
>>>  	iounmap(vf_qm->io_base);
>>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
>>
>> Co-opting the state_mutex to protect dev_opened is rather sketchy.
>>
>>>  	vfio_pci_core_close_device(core_vdev);
>>>  }
>>>  
>>> @@ -1413,6 +1618,9 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device
>>>  	ret = vfio_pci_core_register_device(&hisi_acc_vdev->core_device);
>>>  	if (ret)
>>>  		goto out_put_vdev;
>>> +
>>> +	if (ops == &hisi_acc_vfio_pci_migrn_ops)
>>> +		hisi_acc_vfio_debug_init(hisi_acc_vdev);
>>
>> Call this unconditionally and test hisi_acc_vdev->mig_ops in the
>> debug_init function.  That way init and exit are symmetric.
>>
>>>  	return 0;
>>>  
>>>  out_put_vdev:
>>> @@ -1425,6 +1633,7 @@ static void hisi_acc_vfio_pci_remove(struct pci_dev *pdev)
>>>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev);
>>>  
>>>  	vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);
>>> +	hisi_acc_vf_debugfs_exit(hisi_acc_vdev);
>>>  	vfio_put_device(&hisi_acc_vdev->core_device.vdev);
>>>  }
>>>  
>>> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>>> index 5bab46602fad..f86f3b88b09e 100644
>>> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>>> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>>> @@ -32,6 +32,7 @@
>>>  #define QM_SQC_VFT_BASE_MASK_V2		GENMASK(15, 0)
>>>  #define QM_SQC_VFT_NUM_SHIFT_V2		45
>>>  #define QM_SQC_VFT_NUM_MASK_V2		GENMASK(9, 0)
>>> +#define QM_MB_CMD_NOT_READY	0xffffffff
>>>  
>>>  /* RW regs */
>>>  #define QM_REGS_MAX_LEN		7
>>> @@ -111,5 +112,10 @@ struct hisi_acc_vf_core_device {
>>>  	int vf_id;
>>>  	struct hisi_acc_vf_migration_file *resuming_migf;
>>>  	struct hisi_acc_vf_migration_file *saving_migf;
>>> +
>>> +	/* To make sure the device is opened */
>>> +	bool dev_opened;
>>> +	/* To save migration data */
>>> +	struct hisi_acc_vf_migration_file *debug_migf;
>>
>> Poor structure packing.
>>
>>>  };
>>>  #endif /* HISI_ACC_VFIO_PCI_H */
>>
>>
>> .
>>
> 
> .
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-08-26 21:06   ` Alex Williamson
  2024-08-27  9:35     ` liulongfang
@ 2024-08-27 12:41     ` liulongfang
  1 sibling, 0 replies; 12+ messages in thread
From: liulongfang @ 2024-08-27 12:41 UTC (permalink / raw)
  To: Alex Williamson
  Cc: jgg, shameerali.kolothum.thodi, jonathan.cameron, kvm,
	linux-kernel, linuxarm

On 2024/8/27 5:06, Alex Williamson wrote:
> On Tue, 6 Aug 2024 20:29:27 +0800
> Longfang Liu <liulongfang@huawei.com> wrote:
> 
>> On the debugfs framework of VFIO, if the CONFIG_VFIO_DEBUGFS macro is
>> enabled, the debug function is registered for the live migration driver
>> of the HiSilicon accelerator device.
>>
>> After registering the HiSilicon accelerator device on the debugfs
>> framework of live migration of vfio, a directory file "hisi_acc"
>> of debugfs is created, and then three debug function files are
>> created in this directory:
>>
>>    vfio
>>     |
>>     +---<dev_name1>
>>     |    +---migration
>>     |        +--state
>>     |        +--hisi_acc
>>     |            +--dev_data
>>     |            +--migf_data
>>     |            +--cmd_state
>>     |
>>     +---<dev_name2>
>>          +---migration
>>              +--state
>>              +--hisi_acc
>>                  +--dev_data
>>                  +--migf_data
>>                  +--cmd_state
>>
>> dev_data file: read device data that needs to be migrated from the
>> current device in real time
>> migf_data file: read the migration data of the last live migration
>> from the current driver.
>> cmd_state: used to get the cmd channel state for the device.
>>
>> +----------------+        +--------------+       +---------------+
>> | migration dev  |        |   src  dev   |       |   dst  dev    |
>> +-------+--------+        +------+-------+       +-------+-------+
>>         |                        |                       |
>>         |                 +------v-------+       +-------v-------+
>>         |                 |  saving_migf |       | resuming_migf |
>>   read  |                 |     file     |       |     file      |
>>         |                 +------+-------+       +-------+-------+
>>         |                        |          copy         |
>>         |                        +------------+----------+
>>         |                                     |
>> +-------v--------+                    +-------v--------+
>> |   data buffer  |                    |   debug_migf   |
>> +-------+--------+                    +-------+--------+
>>         |                                     |
>>    cat  |                                 cat |
>> +-------v--------+                    +-------v--------+
>> |   dev_data     |                    |   migf_data    |
>> +----------------+                    +----------------+
>>
>> When accessing debugfs, user can obtain the most recent status data
>> of the device through the "dev_data" file. It can read recent
>> complete status data of the device. If the current device is being
>> migrated, it will wait for it to complete.
>> The data for the last completed migration function will be stored
>> in debug_migf. Users can read it via "migf_data".
>>
>> Signed-off-by: Longfang Liu <liulongfang@huawei.com>
>> ---
>>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 209 ++++++++++++++++++
>>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |   6 +
>>  2 files changed, 215 insertions(+)
>>
>> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>> index a8c53952d82e..379657904f86 100644
>> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>> @@ -627,15 +627,30 @@ static void hisi_acc_vf_disable_fd(struct hisi_acc_vf_migration_file *migf)
>>  	mutex_unlock(&migf->lock);
>>  }
>>  
>> +static void hisi_acc_debug_migf_copy(struct hisi_acc_vf_core_device *hisi_acc_vdev,
>> +	struct hisi_acc_vf_migration_file *src_migf)
>> +{
>> +	struct hisi_acc_vf_migration_file *dst_migf = hisi_acc_vdev->debug_migf;
>> +
>> +	if (!dst_migf)
>> +		return;
>> +
>> +	dst_migf->total_length = src_migf->total_length;
>> +	memcpy(&dst_migf->vf_data, &src_migf->vf_data,
>> +		sizeof(struct acc_vf_data));
>> +}
>> +
>>  static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>>  {
>>  	if (hisi_acc_vdev->resuming_migf) {
>> +		hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->resuming_migf);
>>  		hisi_acc_vf_disable_fd(hisi_acc_vdev->resuming_migf);
>>  		fput(hisi_acc_vdev->resuming_migf->filp);
>>  		hisi_acc_vdev->resuming_migf = NULL;
>>  	}
>>  
>>  	if (hisi_acc_vdev->saving_migf) {
>> +		hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->saving_migf);
>>  		hisi_acc_vf_disable_fd(hisi_acc_vdev->saving_migf);
>>  		fput(hisi_acc_vdev->saving_migf->filp);
>>  		hisi_acc_vdev->saving_migf = NULL;
>> @@ -1294,6 +1309,191 @@ static long hisi_acc_vfio_pci_ioctl(struct vfio_device *core_vdev, unsigned int
>>  	return vfio_pci_core_ioctl(core_vdev, cmd, arg);
>>  }
>>  
>> +static int hisi_acc_vf_debug_check(struct seq_file *seq, struct vfio_device *vdev)
>> +{
>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>> +	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
>> +	int ret;
>> +
>> +	lockdep_assert_held(&hisi_acc_vdev->state_mutex);
>> +	if (!vdev->mig_ops) {
>> +		seq_printf(seq, "%s\n", "device does not support live migration!\n");
>> +		return -EINVAL;
>> +	}
> 
> I don't think it's possible for this to be called with this condition,
> the debugfs files are only registered when this exists.
> 
> Also, we don't need %s for a fixed string, nor do we need multiple new
> lines.  Please fix throughout.
> 
>> +
>> +	/*
>> +	 * When the device is not opened, the io_base is not mapped.
>> +	 * The driver cannot perform device read and write operations.
>> +	 */
>> +	if (!hisi_acc_vdev->dev_opened) {
>> +		seq_printf(seq, "%s\n", "device not opened!\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = qm_wait_dev_not_ready(vf_qm);
>> +	if (ret) {
>> +		seq_printf(seq, "%s\n", "VF device not ready!\n");
>> +		return -EBUSY;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int hisi_acc_vf_debug_cmd(struct seq_file *seq, void *data)
>> +{
>> +	struct device *vf_dev = seq->private;
>> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
>> +	struct vfio_device *vdev = &core_device->vdev;
>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>> +	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
>> +	u64 value;
>> +	int ret;
>> +
>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>> +	if (ret) {
>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +		return ret;
>> +	}
>> +
>> +	value = readl(vf_qm->io_base + QM_MB_CMD_SEND_BASE);
>> +	if (value == QM_MB_CMD_NOT_READY) {
>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +		seq_printf(seq, "mailbox cmd channel not ready!\n");
>> +		return -EINVAL;
>> +	}
>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +	seq_printf(seq, "mailbox cmd channel ready!\n");
> 
> This debugfs entry seems pretty pointless to me.  Also we polled for
> the device to be ready in debug_check, so if the channel is not ready
> aren't we more likely to see any error (without a seq_printf) in the
> first error branch?
> 
>> +
>> +	return 0;
>> +}
>> +
>> +static int hisi_acc_vf_dev_read(struct seq_file *seq, void *data)
>> +{
>> +	struct device *vf_dev = seq->private;
>> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
>> +	struct vfio_device *vdev = &core_device->vdev;
>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
>> +	struct acc_vf_data *vf_data = NULL;
>> +	int ret;
>> +
>> +	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
>> +	if (!vf_data)
>> +		return -ENOMEM;
>> +
>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>> +	if (ret) {
>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +		goto migf_err;
>> +	}
>> +
>> +	vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state;
>> +	ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data);
>> +	if (ret) {
>> +		mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +		goto migf_err;
>> +	}
>> +
>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
>> +
>> +	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
>> +			(unsigned char *)vf_data,
>> +			vf_data_sz, false);
>> +
>> +	seq_printf(seq,
>> +		 "acc device:\n"
>> +		 "device  ready: %u\n"
>> +		 "device  opened: %d\n"
>> +		 "data     size: %lu\n",
>> +		 hisi_acc_vdev->vf_qm_state,
>> +		 hisi_acc_vdev->dev_opened,
>> +		 sizeof(struct acc_vf_data));
> 
> This function called hisi_acc_vf_debug_check() which requires the
> device to be opened, therefore except for the race where the unlock
> allowed the device to close, what is the purpose of printing the opened
> state here?  We can also tell from the hex dump the size of the data,
> so why is that value printed here?  vf_qm_state appears to be a state
> value rather than a bool, so labeling it as "ready" doesn't make much
> sense.  The arbitrary white space also doesn't make much sense.
> 
>> +
>> +migf_err:
>> +	kfree(vf_data);
>> +
>> +	return ret;
>> +}
>> +
>> +static int hisi_acc_vf_migf_read(struct seq_file *seq, void *data)
>> +{
>> +	struct device *vf_dev = seq->private;
>> +	struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev);
>> +	struct vfio_device *vdev = &core_device->vdev;
>> +	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
>> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
>> +	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
>> +
>> +	/* Check whether the live migration operation has been performed */
>> +	if (debug_migf->total_length < QM_MATCH_SIZE) {
>> +		seq_printf(seq, "%s\n", "device not migrated!\n");
>> +		return -EAGAIN;
>> +	}
>> +
>> +	seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
>> +			(unsigned char *)&debug_migf->vf_data,
>> +			vf_data_sz, false);
> 
> Why doesn't this stop at total_length?
> 
>> +
>> +	seq_printf(seq,
>> +		 "acc device:\n"
>> +		 "device  ready: %u\n"
>> +		 "device  opened: %d\n"
>> +		 "data     size: %lu\n",
>> +		 hisi_acc_vdev->vf_qm_state,
>> +		 hisi_acc_vdev->dev_opened,
>> +		 debug_migf->total_length);
> 
> Again, "ready" seems more like a "state" value, here opened could be
> false, but why do we care(?), size could be inferred from the hex dump,
> and white spaces are arbitrary.
> 
>> +
>> +	return 0;
>> +}
>> +
>> +static int hisi_acc_vfio_debug_init(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>> +{
>> +	struct vfio_device *vdev = &hisi_acc_vdev->core_device.vdev;
>> +	struct dentry *vfio_dev_migration = NULL;
>> +	struct dentry *vfio_hisi_acc = NULL;
>> +	struct device *dev = vdev->dev;
>> +	void *migf = NULL;
>> +
>> +	if (!debugfs_initialized() ||
>> +	    !IS_ENABLED(CONFIG_VFIO_DEBUGFS))
>> +		return 0;
>> +
>> +	migf = kzalloc(sizeof(struct hisi_acc_vf_migration_file), GFP_KERNEL);
>> +	if (!migf)
>> +		return -ENOMEM;
>> +	hisi_acc_vdev->debug_migf = migf;
>> +
>> +	vfio_dev_migration = debugfs_lookup("migration", vdev->debug_root);
> 
> Test this before anything is allocated or assigned.
> 
>> +	if (!vfio_dev_migration) {
>> +		kfree(migf);
>> +		hisi_acc_vdev->debug_migf = NULL;
>> +		dev_err(dev, "failed to lookup migration debugfs file!\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	vfio_hisi_acc = debugfs_create_dir("hisi_acc", vfio_dev_migration);
>> +	debugfs_create_devm_seqfile(dev, "dev_data", vfio_hisi_acc,
>> +				  hisi_acc_vf_dev_read);
>> +	debugfs_create_devm_seqfile(dev, "migf_data", vfio_hisi_acc,
>> +				  hisi_acc_vf_migf_read);
>> +	debugfs_create_devm_seqfile(dev, "cmd_state", vfio_hisi_acc,
>> +				  hisi_acc_vf_debug_cmd);
>> +
>> +	return 0;
>> +}
> 
> Why does this function return an int when the only caller ignores the
> return value?
>

Okay, I can change this function to void return type.

>> +
>> +static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>> +{
>> +	if (!debugfs_initialized() ||
>> +	    !IS_ENABLED(CONFIG_VFIO_DEBUGFS))
>> +		return;
> 
> Do we really need to test these on the exit path?  debug_migf would not
> be allocated.
>

Yes, redundant checks can be deleted here.

>> +
>> +	if (hisi_acc_vdev->debug_migf)
>> +		kfree(hisi_acc_vdev->debug_migf);
> 
> I suppose this is not set NULL because this is only called in the
> device remove path.


OK, I can add a line:
hisi_acc_vdev->debug_migf = NULL;

> 
>> +}
>> +
>>  static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>>  {
>>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
>> @@ -1311,9 +1511,11 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>>  			return ret;
>>  		}
>>  		hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING;
>> +		hisi_acc_vdev->dev_opened = true;
>>  	}
>>  
>>  	vfio_pci_core_finish_enable(vdev);
>> +
>>  	return 0;
>>  }
>>  
>> @@ -1322,7 +1524,10 @@ static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev)
>>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
>>  	struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
>>  
>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>> +	hisi_acc_vdev->dev_opened = false;
>>  	iounmap(vf_qm->io_base);
>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
> 
> Co-opting the state_mutex to protect dev_opened is rather sketchy.
>

So do we need to reconsider creating a new mmap_mutex here?

>>  	vfio_pci_core_close_device(core_vdev);
>>  }
>>  
>> @@ -1413,6 +1618,9 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device
>>  	ret = vfio_pci_core_register_device(&hisi_acc_vdev->core_device);
>>  	if (ret)
>>  		goto out_put_vdev;
>> +
>> +	if (ops == &hisi_acc_vfio_pci_migrn_ops)
>> +		hisi_acc_vfio_debug_init(hisi_acc_vdev);
> 
> Call this unconditionally and test hisi_acc_vdev->mig_ops in the
> debug_init function.  That way init and exit are symmetric.
>

OK, here is the processing code in exit, like this:

if (vdev->ops == &hisi_acc_vfio_pci_migrn_ops)
	hisi_acc_vf_debugfs_exit(hisi_acc_vdev);

>>  	return 0;
>>  
>>  out_put_vdev:
>> @@ -1425,6 +1633,7 @@ static void hisi_acc_vfio_pci_remove(struct pci_dev *pdev)
>>  	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev);
>>  
>>  	vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);
>> +	hisi_acc_vf_debugfs_exit(hisi_acc_vdev);
>>  	vfio_put_device(&hisi_acc_vdev->core_device.vdev);
>>  }
>>  
>> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>> index 5bab46602fad..f86f3b88b09e 100644
>> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>> @@ -32,6 +32,7 @@
>>  #define QM_SQC_VFT_BASE_MASK_V2		GENMASK(15, 0)
>>  #define QM_SQC_VFT_NUM_SHIFT_V2		45
>>  #define QM_SQC_VFT_NUM_MASK_V2		GENMASK(9, 0)
>> +#define QM_MB_CMD_NOT_READY	0xffffffff
>>  
>>  /* RW regs */
>>  #define QM_REGS_MAX_LEN		7
>> @@ -111,5 +112,10 @@ struct hisi_acc_vf_core_device {
>>  	int vf_id;
>>  	struct hisi_acc_vf_migration_file *resuming_migf;
>>  	struct hisi_acc_vf_migration_file *saving_migf;
>> +
>> +	/* To make sure the device is opened */
>> +	bool dev_opened;
>> +	/* To save migration data */
>> +	struct hisi_acc_vf_migration_file *debug_migf;
> 
> Poor structure packing.
>

OK, I will adjust the order in the next version.

Thanks.
Longfang.

>>  };
>>  #endif /* HISI_ACC_VFIO_PCI_H */
> 
> 
> .
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2024-08-27 12:41 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-06 12:29 [PATCH v8 0/4] debugfs to hisilicon migration driver Longfang Liu
2024-08-06 12:29 ` [PATCH v8 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
2024-08-06 12:29 ` [PATCH v8 2/4] hisi_acc_vfio_pci: create subfunction for data reading Longfang Liu
2024-08-06 12:29 ` [PATCH v8 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
2024-08-14  9:39   ` Shameerali Kolothum Thodi
2024-08-22  8:29     ` liulongfang
2024-08-26 21:06   ` Alex Williamson
2024-08-27  9:35     ` liulongfang
2024-08-27 11:26       ` liulongfang
2024-08-27 12:41     ` liulongfang
2024-08-06 12:29 ` [PATCH v8 4/4] Documentation: add debugfs description for hisi migration Longfang Liu
2024-08-14  9:35   ` Shameerali Kolothum Thodi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox