mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v12 0/4] debugfs to hisilicon migration driver
@ 2024-11-05  3:52 Longfang Liu
  2024-11-05  3:52 ` [PATCH v12 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Longfang Liu @ 2024-11-05  3:52 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 v11 -> v12
	Update comments and delete unnecessary logs

Changes v10 -> v11
	Update conditions for debugfs registration

Changes v9 -> v10
	Optimize symmetry processing of mutex

Changes v8 -> v9
	Added device enable mutex

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    | 266 ++++++++++++++++--
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |  15 +
 3 files changed, 275 insertions(+), 31 deletions(-)
 create mode 100644 Documentation/ABI/testing/debugfs-hisi-migration

-- 
2.24.0


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

* [PATCH v12 1/4] hisi_acc_vfio_pci: extract public functions for container_of
  2024-11-05  3:52 [PATCH v12 0/4] debugfs to hisilicon migration driver Longfang Liu
@ 2024-11-05  3:52 ` Longfang Liu
  2024-11-05  3:52 ` [PATCH v12 2/4] hisi_acc_vfio_pci: create subfunction for data reading Longfang Liu
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: Longfang Liu @ 2024-11-05  3:52 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	[flat|nested] 11+ messages in thread

* [PATCH v12 2/4] hisi_acc_vfio_pci: create subfunction for data reading
  2024-11-05  3:52 [PATCH v12 0/4] debugfs to hisilicon migration driver Longfang Liu
  2024-11-05  3:52 ` [PATCH v12 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
@ 2024-11-05  3:52 ` Longfang Liu
  2024-11-05  3:52 ` [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
  2024-11-05  3:52 ` [PATCH v12 4/4] Documentation: add debugfs description for hisi migration Longfang Liu
  3 siblings, 0 replies; 11+ messages in thread
From: Longfang Liu @ 2024-11-05  3:52 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	[flat|nested] 11+ messages in thread

* [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-11-05  3:52 [PATCH v12 0/4] debugfs to hisilicon migration driver Longfang Liu
  2024-11-05  3:52 ` [PATCH v12 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
  2024-11-05  3:52 ` [PATCH v12 2/4] hisi_acc_vfio_pci: create subfunction for data reading Longfang Liu
@ 2024-11-05  3:52 ` Longfang Liu
  2024-11-05  8:55   ` Shameerali Kolothum Thodi
  2024-11-05  3:52 ` [PATCH v12 4/4] Documentation: add debugfs description for hisi migration Longfang Liu
  3 siblings, 1 reply; 11+ messages in thread
From: Longfang Liu @ 2024-11-05  3:52 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>
Reviewed-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
---
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 191 ++++++++++++++++++
 .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |  15 ++
 2 files changed, 206 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..7728c9745b9d 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,129 @@ 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->open_mutex);
+	/*
+	 * 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, "device not opened!\n");
+		return -EINVAL;
+	}
+
+	ret = qm_wait_dev_not_ready(vf_qm);
+	if (ret) {
+		seq_printf(seq, "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->open_mutex);
+	ret = hisi_acc_vf_debug_check(seq, vdev);
+	if (ret) {
+		mutex_unlock(&hisi_acc_vdev->open_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->open_mutex);
+		seq_printf(seq, "mailbox cmd channel not ready!\n");
+		return -EINVAL;
+	}
+	mutex_unlock(&hisi_acc_vdev->open_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;
+	int ret;
+
+	mutex_lock(&hisi_acc_vdev->open_mutex);
+	ret = hisi_acc_vf_debug_check(seq, vdev);
+	if (ret) {
+		mutex_unlock(&hisi_acc_vdev->open_mutex);
+		return ret;
+	}
+
+	mutex_lock(&hisi_acc_vdev->state_mutex);
+	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
+	if (!vf_data) {
+		ret = -ENOMEM;
+		goto mutex_release;
+	}
+
+	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)
+		goto migf_err;
+
+	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
+		     (const void *)vf_data, vf_data_sz, false);
+
+	seq_printf(seq,
+		   "guest driver load: %u\n"
+		   "data size: %lu\n",
+		   hisi_acc_vdev->vf_qm_state,
+		   sizeof(struct acc_vf_data));
+
+migf_err:
+	kfree(vf_data);
+mutex_release:
+	mutex_unlock(&hisi_acc_vdev->state_mutex);
+	mutex_unlock(&hisi_acc_vdev->open_mutex);
+
+	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, "device not migrated!\n");
+		return -EAGAIN;
+	}
+
+	seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
+		     (const void *)&debug_migf->vf_data, vf_data_sz, false);
+	seq_printf(seq, "migrate data length: %lu\n", debug_migf->total_length);
+
+	return 0;
+}
+
 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);
@@ -1305,12 +1443,16 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
 		return ret;
 
 	if (core_vdev->mig_ops) {
+		mutex_lock(&hisi_acc_vdev->open_mutex);
 		ret = hisi_acc_vf_qm_init(hisi_acc_vdev);
 		if (ret) {
+			mutex_unlock(&hisi_acc_vdev->open_mutex);
 			vfio_pci_core_disable(vdev);
 			return ret;
 		}
 		hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING;
+		hisi_acc_vdev->dev_opened = true;
+		mutex_unlock(&hisi_acc_vdev->open_mutex);
 	}
 
 	vfio_pci_core_finish_enable(vdev);
@@ -1322,7 +1464,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->open_mutex);
+	hisi_acc_vdev->dev_opened = false;
 	iounmap(vf_qm->io_base);
+	mutex_unlock(&hisi_acc_vdev->open_mutex);
 	vfio_pci_core_close_device(core_vdev);
 }
 
@@ -1342,6 +1487,7 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev)
 	hisi_acc_vdev->pf_qm = pf_qm;
 	hisi_acc_vdev->vf_dev = pdev;
 	mutex_init(&hisi_acc_vdev->state_mutex);
+	mutex_init(&hisi_acc_vdev->open_mutex);
 
 	core_vdev->migration_flags = VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_PRE_COPY;
 	core_vdev->mig_ops = &hisi_acc_vfio_pci_migrn_state_ops;
@@ -1387,6 +1533,48 @@ static const struct vfio_device_ops hisi_acc_vfio_pci_ops = {
 	.detach_ioas = vfio_iommufd_physical_detach_ioas,
 };
 
+static void 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;
+
+	if (vdev->ops != &hisi_acc_vfio_pci_migrn_ops)
+		return;
+
+	vfio_dev_migration = debugfs_lookup("migration", vdev->debug_root);
+	if (!vfio_dev_migration) {
+		dev_err(dev, "failed to lookup migration debugfs file!\n");
+		return;
+	}
+
+	migf = kzalloc(sizeof(struct hisi_acc_vf_migration_file), GFP_KERNEL);
+	if (!migf)
+		return;
+	hisi_acc_vdev->debug_migf = migf;
+
+	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);
+}
+
+static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev)
+{
+	/* If migrn_ops is not used, kfree(NULL) is valid */
+	kfree(hisi_acc_vdev->debug_migf);
+	hisi_acc_vdev->debug_migf = NULL;
+}
+
 static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct hisi_acc_vf_core_device *hisi_acc_vdev;
@@ -1413,6 +1601,8 @@ 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;
+
+	hisi_acc_vfio_debug_init(hisi_acc_vdev);
 	return 0;
 
 out_put_vdev:
@@ -1425,6 +1615,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..47092cf4cf5c 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
@@ -99,6 +100,12 @@ struct hisi_acc_vf_migration_file {
 struct hisi_acc_vf_core_device {
 	struct vfio_pci_core_device core_device;
 	u8 match_done;
+	/*
+	 * io_base is only valid when dev_opened is true,
+	 * which is protected by open_mutex.
+	 */
+	bool dev_opened;
+	struct mutex open_mutex;
 
 	/* For migration state */
 	struct mutex state_mutex;
@@ -107,9 +114,17 @@ struct hisi_acc_vf_core_device {
 	struct pci_dev *vf_dev;
 	struct hisi_qm *pf_qm;
 	struct hisi_qm vf_qm;
+	/*
+	 * Record whether a driver is added to the acc device in Guest OS.
+	 * The value of QM_VF_STATE is set by the acc device driver.
+	 * The migration driver queries through the QM_VF_STATE register.
+	 */
 	u32 vf_qm_state;
 	int vf_id;
 	struct hisi_acc_vf_migration_file *resuming_migf;
 	struct hisi_acc_vf_migration_file *saving_migf;
+
+	/* An extra buffer for reporting migration data via debugfs */
+	struct hisi_acc_vf_migration_file *debug_migf;
 };
 #endif /* HISI_ACC_VFIO_PCI_H */
-- 
2.24.0


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

* [PATCH v12 4/4] Documentation: add debugfs description for hisi migration
  2024-11-05  3:52 [PATCH v12 0/4] debugfs to hisilicon migration driver Longfang Liu
                   ` (2 preceding siblings ...)
  2024-11-05  3:52 ` [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
@ 2024-11-05  3:52 ` Longfang Liu
  3 siblings, 0 replies; 11+ messages in thread
From: Longfang Liu @ 2024-11-05  3:52 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>
Reviewed-by: Shameer Kolothum <shameerali.kolothum.thodi@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..2c01b2d387dd
--- /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:		Jan 2025
+KernelVersion:  6.13
+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:		Jan 2025
+KernelVersion:  6.13
+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:		Jan 2025
+KernelVersion:  6.13
+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	[flat|nested] 11+ messages in thread

* RE: [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-11-05  3:52 ` [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
@ 2024-11-05  8:55   ` Shameerali Kolothum Thodi
  2024-11-05 18:21     ` Alex Williamson
  0 siblings, 1 reply; 11+ messages in thread
From: Shameerali Kolothum Thodi @ 2024-11-05  8:55 UTC (permalink / raw)
  To: liulongfang, alex.williamson, jgg, Jonathan Cameron
  Cc: kvm, linux-kernel, linuxarm



> -----Original Message-----
> From: liulongfang <liulongfang@huawei.com>
> Sent: Tuesday, November 5, 2024 3:53 AM
> 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 v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon
> migration driver

Hi,

Few minor comments below. Please don't re-spin just for these yet.
Please wait for others to review as well.

Thanks,
Shameer

> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> index a8c53952d82e..7728c9745b9d 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)

Alignment should match open parenthesis here.

> +{
> +	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));

Here too, alignment not correct. It is better to run,
./scripts/checkpatch --strict on these patches if you haven't done already.

> +}
> +
>  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,129 @@ 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->open_mutex);
> +	/*
> +	 * 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, "device not opened!\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = qm_wait_dev_not_ready(vf_qm);
> +	if (ret) {
> +		seq_printf(seq, "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->open_mutex);
> +	ret = hisi_acc_vf_debug_check(seq, vdev);
> +	if (ret) {
> +		mutex_unlock(&hisi_acc_vdev->open_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->open_mutex);
> +		seq_printf(seq, "mailbox cmd channel not ready!\n");
> +		return -EINVAL;
> +	}
> +	mutex_unlock(&hisi_acc_vdev->open_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;
> +	int ret;
> +
> +	mutex_lock(&hisi_acc_vdev->open_mutex);
> +	ret = hisi_acc_vf_debug_check(seq, vdev);
> +	if (ret) {
> +		mutex_unlock(&hisi_acc_vdev->open_mutex);
> +		return ret;
> +	}
> +
> +	mutex_lock(&hisi_acc_vdev->state_mutex);
> +	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
> +	if (!vf_data) {
> +		ret = -ENOMEM;
> +		goto mutex_release;
> +	}
> +
> +	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)
> +		goto migf_err;
> +
> +	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
> +		     (const void *)vf_data, vf_data_sz, false);
> +
> +	seq_printf(seq,
> +		   "guest driver load: %u\n"
> +		   "data size: %lu\n",
> +		   hisi_acc_vdev->vf_qm_state,
> +		   sizeof(struct acc_vf_data));

There was a suggestion to add a comment here to describe vf_qm_state better.
May be something like,

vf_qm_state here indicates whether the Guest has loaded the driver for the ACC VF
device or not.

> +
> +migf_err:
> +	kfree(vf_data);
> +mutex_release:
> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
> +	mutex_unlock(&hisi_acc_vdev->open_mutex);
> +
> +	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, "device not migrated!\n");
> +		return -EAGAIN;
> +	}
> +
> +	seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
> +		     (const void *)&debug_migf->vf_data, vf_data_sz, false);
> +	seq_printf(seq, "migrate data length: %lu\n", debug_migf-
> >total_length);
> +
> +	return 0;
> +}
> +
>  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);
> @@ -1305,12 +1443,16 @@ static int hisi_acc_vfio_pci_open_device(struct
> vfio_device *core_vdev)
>  		return ret;
> 
>  	if (core_vdev->mig_ops) {
> +		mutex_lock(&hisi_acc_vdev->open_mutex);
>  		ret = hisi_acc_vf_qm_init(hisi_acc_vdev);
>  		if (ret) {
> +			mutex_unlock(&hisi_acc_vdev->open_mutex);
>  			vfio_pci_core_disable(vdev);
>  			return ret;
>  		}
>  		hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING;
> +		hisi_acc_vdev->dev_opened = true;
> +		mutex_unlock(&hisi_acc_vdev->open_mutex);
>  	}
> 
>  	vfio_pci_core_finish_enable(vdev);
> @@ -1322,7 +1464,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->open_mutex);
> +	hisi_acc_vdev->dev_opened = false;
>  	iounmap(vf_qm->io_base);
> +	mutex_unlock(&hisi_acc_vdev->open_mutex);
>  	vfio_pci_core_close_device(core_vdev);
>  }
> 
> @@ -1342,6 +1487,7 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct
> vfio_device *core_vdev)
>  	hisi_acc_vdev->pf_qm = pf_qm;
>  	hisi_acc_vdev->vf_dev = pdev;
>  	mutex_init(&hisi_acc_vdev->state_mutex);
> +	mutex_init(&hisi_acc_vdev->open_mutex);
> 
>  	core_vdev->migration_flags = VFIO_MIGRATION_STOP_COPY |
> VFIO_MIGRATION_PRE_COPY;
>  	core_vdev->mig_ops = &hisi_acc_vfio_pci_migrn_state_ops;
> @@ -1387,6 +1533,48 @@ static const struct vfio_device_ops
> hisi_acc_vfio_pci_ops = {
>  	.detach_ioas = vfio_iommufd_physical_detach_ioas,
>  };
> 
> +static void 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;
> +
> +	if (vdev->ops != &hisi_acc_vfio_pci_migrn_ops)
> +		return;
> +
> +	vfio_dev_migration = debugfs_lookup("migration", vdev-
> >debug_root);
> +	if (!vfio_dev_migration) {
> +		dev_err(dev, "failed to lookup migration debugfs file!\n");
> +		return;
> +	}
> +
> +	migf = kzalloc(sizeof(struct hisi_acc_vf_migration_file),
> GFP_KERNEL);
> +	if (!migf)
> +		return;
> +	hisi_acc_vdev->debug_migf = migf;
> +
> +	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);
> +}
> +
> +static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device
> *hisi_acc_vdev)
> +{
> +	/* If migrn_ops is not used, kfree(NULL) is valid */

The above comment is not required. Please remove.

> +	kfree(hisi_acc_vdev->debug_migf);
> +	hisi_acc_vdev->debug_migf = NULL;
> +}
> +


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

* Re: [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-11-05  8:55   ` Shameerali Kolothum Thodi
@ 2024-11-05 18:21     ` Alex Williamson
  2024-11-06  9:19       ` liulongfang
  0 siblings, 1 reply; 11+ messages in thread
From: Alex Williamson @ 2024-11-05 18:21 UTC (permalink / raw)
  To: Shameerali Kolothum Thodi
  Cc: liulongfang, jgg, Jonathan Cameron, kvm, linux-kernel, linuxarm

On Tue, 5 Nov 2024 08:55:51 +0000
Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com> wrote:

> > -----Original Message-----
> > From: liulongfang <liulongfang@huawei.com>
> > Sent: Tuesday, November 5, 2024 3:53 AM
> > 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 v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon
> > migration driver  
> 
> Hi,
> 
> Few minor comments below. Please don't re-spin just for these yet.
> Please wait for others to review as well.
> 
> Thanks,
> Shameer
> 
> > diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> > b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> > index a8c53952d82e..7728c9745b9d 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)  
> 
> Alignment should match open parenthesis here.

I might also shorten the first line to 80 chars by putting "static" or
"static void" on a line by itself, but we're getting into personal
preference at that point and this driver already has lines exceeding 80
columns.

> > +{
> > +	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));  
> 
> Here too, alignment not correct. It is better to run,
> ./scripts/checkpatch --strict on these patches if you haven't done already.

Yup.  Only those two were missed as far as I see, but checkpatch does
warn several places where we should use seq_puts() rather than
seq_printf() for cases of printing a constant format without additional
arguments.  For example "device not opened!\n" is the first one below
but there are others.

> > +}
> > +
> >  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,129 @@ 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->open_mutex);
> > +	/*
> > +	 * 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, "device not opened!\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	ret = qm_wait_dev_not_ready(vf_qm);
> > +	if (ret) {
> > +		seq_printf(seq, "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->open_mutex);
> > +	ret = hisi_acc_vf_debug_check(seq, vdev);
> > +	if (ret) {
> > +		mutex_unlock(&hisi_acc_vdev->open_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->open_mutex);
> > +		seq_printf(seq, "mailbox cmd channel not ready!\n");
> > +		return -EINVAL;
> > +	}
> > +	mutex_unlock(&hisi_acc_vdev->open_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;
> > +	int ret;
> > +
> > +	mutex_lock(&hisi_acc_vdev->open_mutex);
> > +	ret = hisi_acc_vf_debug_check(seq, vdev);
> > +	if (ret) {
> > +		mutex_unlock(&hisi_acc_vdev->open_mutex);
> > +		return ret;
> > +	}
> > +
> > +	mutex_lock(&hisi_acc_vdev->state_mutex);
> > +	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
> > +	if (!vf_data) {
> > +		ret = -ENOMEM;
> > +		goto mutex_release;
> > +	}
> > +
> > +	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)
> > +		goto migf_err;
> > +
> > +	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
> > +		     (const void *)vf_data, vf_data_sz, false);
> > +
> > +	seq_printf(seq,
> > +		   "guest driver load: %u\n"
> > +		   "data size: %lu\n",
> > +		   hisi_acc_vdev->vf_qm_state,
> > +		   sizeof(struct acc_vf_data));  
> 
> There was a suggestion to add a comment here to describe vf_qm_state better.
> May be something like,
> 
> vf_qm_state here indicates whether the Guest has loaded the driver for the ACC VF
> device or not.

I think the comment ended up at the declaration of vf_qm_state in the
header file:

> @@ -107,9 +114,17 @@ struct hisi_acc_vf_core_device {
>  	struct pci_dev *vf_dev;
>  	struct hisi_qm *pf_qm;
>  	struct hisi_qm vf_qm;
> +	/*
> +	 * Record whether a driver is added to the acc device in Guest OS.
> +	 * The value of QM_VF_STATE is set by the acc device driver.
> +	 * The migration driver queries through the QM_VF_STATE register.
> +	 */
>  	u32 vf_qm_state;
>  	int vf_id;
>  	struct hisi_acc_vf_migration_file *resuming_migf;
>  	struct hisi_acc_vf_migration_file *saving_migf;
> +
> +	/* An extra buffer for reporting migration data via debugfs */
> +	struct hisi_acc_vf_migration_file *debug_migf;
>  };
>  #endif /* HISI_ACC_VFIO_PCI_H */

Is that satisfactory?

> > +
> > +migf_err:
> > +	kfree(vf_data);
> > +mutex_release:
> > +	mutex_unlock(&hisi_acc_vdev->state_mutex);
> > +	mutex_unlock(&hisi_acc_vdev->open_mutex);
> > +
> > +	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, "device not migrated!\n");
> > +		return -EAGAIN;
> > +	}
> > +
> > +	seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
> > +		     (const void *)&debug_migf->vf_data, vf_data_sz, false);
> > +	seq_printf(seq, "migrate data length: %lu\n", debug_migf-  
> > >total_length);  
> > +
> > +	return 0;
> > +}
> > +
> >  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);
> > @@ -1305,12 +1443,16 @@ static int hisi_acc_vfio_pci_open_device(struct
> > vfio_device *core_vdev)
> >  		return ret;
> > 
> >  	if (core_vdev->mig_ops) {
> > +		mutex_lock(&hisi_acc_vdev->open_mutex);
> >  		ret = hisi_acc_vf_qm_init(hisi_acc_vdev);
> >  		if (ret) {
> > +			mutex_unlock(&hisi_acc_vdev->open_mutex);
> >  			vfio_pci_core_disable(vdev);
> >  			return ret;
> >  		}
> >  		hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING;
> > +		hisi_acc_vdev->dev_opened = true;
> > +		mutex_unlock(&hisi_acc_vdev->open_mutex);
> >  	}
> > 
> >  	vfio_pci_core_finish_enable(vdev);
> > @@ -1322,7 +1464,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->open_mutex);
> > +	hisi_acc_vdev->dev_opened = false;
> >  	iounmap(vf_qm->io_base);
> > +	mutex_unlock(&hisi_acc_vdev->open_mutex);
> >  	vfio_pci_core_close_device(core_vdev);
> >  }
> > 
> > @@ -1342,6 +1487,7 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct
> > vfio_device *core_vdev)
> >  	hisi_acc_vdev->pf_qm = pf_qm;
> >  	hisi_acc_vdev->vf_dev = pdev;
> >  	mutex_init(&hisi_acc_vdev->state_mutex);
> > +	mutex_init(&hisi_acc_vdev->open_mutex);
> > 
> >  	core_vdev->migration_flags = VFIO_MIGRATION_STOP_COPY |
> > VFIO_MIGRATION_PRE_COPY;
> >  	core_vdev->mig_ops = &hisi_acc_vfio_pci_migrn_state_ops;
> > @@ -1387,6 +1533,48 @@ static const struct vfio_device_ops
> > hisi_acc_vfio_pci_ops = {
> >  	.detach_ioas = vfio_iommufd_physical_detach_ioas,
> >  };
> > 
> > +static void 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;
> > +
> > +	if (vdev->ops != &hisi_acc_vfio_pci_migrn_ops)
> > +		return;
> > +
> > +	vfio_dev_migration = debugfs_lookup("migration", vdev-  
> > >debug_root);  
> > +	if (!vfio_dev_migration) {
> > +		dev_err(dev, "failed to lookup migration debugfs file!\n");
> > +		return;
> > +	}
> > +
> > +	migf = kzalloc(sizeof(struct hisi_acc_vf_migration_file),
> > GFP_KERNEL);

checkpatch --strict also advises this could be written as:

	migf = kzalloc(sizeof(*migf), GFP_KERNEL);

There's another one above with acc_vf_data.  I'd consider these
optional, but I think it is good practice and is more consistent with
existing allocations in this file.

> > +	if (!migf)
> > +		return;
> > +	hisi_acc_vdev->debug_migf = migf;
> > +
> > +	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);
> > +}
> > +
> > +static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device
> > *hisi_acc_vdev)
> > +{
> > +	/* If migrn_ops is not used, kfree(NULL) is valid */  
> 
> The above comment is not required. Please remove.

I don't have a problem with it, but I'll let the two of you decide as
co-owners of the file.  Thanks,

Alex


> > +	kfree(hisi_acc_vdev->debug_migf);
> > +	hisi_acc_vdev->debug_migf = NULL;
> > +}
> > +  
> 


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

* Re: [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2024-11-05 18:21     ` Alex Williamson
@ 2024-11-06  9:19       ` liulongfang
  0 siblings, 0 replies; 11+ messages in thread
From: liulongfang @ 2024-11-06  9:19 UTC (permalink / raw)
  To: Alex Williamson, Shameerali Kolothum Thodi
  Cc: jgg, Jonathan Cameron, kvm, linux-kernel, linuxarm

On 2024/11/6 2:21, Alex Williamson wrote:
> On Tue, 5 Nov 2024 08:55:51 +0000
> Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com> wrote:
> 
>>> -----Original Message-----
>>> From: liulongfang <liulongfang@huawei.com>
>>> Sent: Tuesday, November 5, 2024 3:53 AM
>>> 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 v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon
>>> migration driver  
>>
>> Hi,
>>
>> Few minor comments below. Please don't re-spin just for these yet.
>> Please wait for others to review as well.
>>
>> Thanks,
>> Shameer
>>
>>> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>>> b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>>> index a8c53952d82e..7728c9745b9d 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)  
>>
>> Alignment should match open parenthesis here.
> 
> I might also shorten the first line to 80 chars by putting "static" or
> "static void" on a line by itself, but we're getting into personal
> preference at that point and this driver already has lines exceeding 80
> columns.
>

Okay, I put static void on a separate line,
and the following two are aligned.

>>> +{
>>> +	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));  
>>
>> Here too, alignment not correct. It is better to run,
>> ./scripts/checkpatch --strict on these patches if you haven't done already.
> 
> Yup.  Only those two were missed as far as I see, but checkpatch does
> warn several places where we should use seq_puts() rather than
> seq_printf() for cases of printing a constant format without additional
> arguments.  For example "device not opened!\n" is the first one below
> but there are others.
>

OK!
I will use "./scripts/checkpatch --strict" to handle it,
and replace seq_printf() with seq_puts()

>>> +}
>>> +
>>>  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,129 @@ 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->open_mutex);
>>> +	/*
>>> +	 * 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, "device not opened!\n");
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	ret = qm_wait_dev_not_ready(vf_qm);
>>> +	if (ret) {
>>> +		seq_printf(seq, "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->open_mutex);
>>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>>> +	if (ret) {
>>> +		mutex_unlock(&hisi_acc_vdev->open_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->open_mutex);
>>> +		seq_printf(seq, "mailbox cmd channel not ready!\n");
>>> +		return -EINVAL;
>>> +	}
>>> +	mutex_unlock(&hisi_acc_vdev->open_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;
>>> +	int ret;
>>> +
>>> +	mutex_lock(&hisi_acc_vdev->open_mutex);
>>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>>> +	if (ret) {
>>> +		mutex_unlock(&hisi_acc_vdev->open_mutex);
>>> +		return ret;
>>> +	}
>>> +
>>> +	mutex_lock(&hisi_acc_vdev->state_mutex);
>>> +	vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
>>> +	if (!vf_data) {
>>> +		ret = -ENOMEM;
>>> +		goto mutex_release;
>>> +	}
>>> +
>>> +	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)
>>> +		goto migf_err;
>>> +
>>> +	seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
>>> +		     (const void *)vf_data, vf_data_sz, false);
>>> +
>>> +	seq_printf(seq,
>>> +		   "guest driver load: %u\n"
>>> +		   "data size: %lu\n",
>>> +		   hisi_acc_vdev->vf_qm_state,
>>> +		   sizeof(struct acc_vf_data));  
>>
>> There was a suggestion to add a comment here to describe vf_qm_state better.
>> May be something like,
>>
>> vf_qm_state here indicates whether the Guest has loaded the driver for the ACC VF
>> device or not.
> 
> I think the comment ended up at the declaration of vf_qm_state in the
> header file:
>>> @@ -107,9 +114,17 @@ struct hisi_acc_vf_core_device {
>>  	struct pci_dev *vf_dev;
>>  	struct hisi_qm *pf_qm;
>>  	struct hisi_qm vf_qm;
>> +	/*
>> +	 * Record whether a driver is added to the acc device in Guest OS.
>> +	 * The value of QM_VF_STATE is set by the acc device driver.
>> +	 * The migration driver queries through the QM_VF_STATE register.
>> +	 */
>>  	u32 vf_qm_state;
>>  	int vf_id;
>>  	struct hisi_acc_vf_migration_file *resuming_migf;
>>  	struct hisi_acc_vf_migration_file *saving_migf;
>> +
>> +	/* An extra buffer for reporting migration data via debugfs */
>> +	struct hisi_acc_vf_migration_file *debug_migf;
>>  };
>>  #endif /* HISI_ACC_VFIO_PCI_H */
> 
> Is that satisfactory?
>
Okay, I'll update the comment.

>>> +
>>> +migf_err:
>>> +	kfree(vf_data);
>>> +mutex_release:
>>> +	mutex_unlock(&hisi_acc_vdev->state_mutex);
>>> +	mutex_unlock(&hisi_acc_vdev->open_mutex);
>>> +
>>> +	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, "device not migrated!\n");
>>> +		return -EAGAIN;
>>> +	}
>>> +
>>> +	seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
>>> +		     (const void *)&debug_migf->vf_data, vf_data_sz, false);
>>> +	seq_printf(seq, "migrate data length: %lu\n", debug_migf-  
>>>> total_length);  
>>> +
>>> +	return 0;
>>> +}
>>> +
>>>  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);
>>> @@ -1305,12 +1443,16 @@ static int hisi_acc_vfio_pci_open_device(struct
>>> vfio_device *core_vdev)
>>>  		return ret;
>>>
>>>  	if (core_vdev->mig_ops) {
>>> +		mutex_lock(&hisi_acc_vdev->open_mutex);
>>>  		ret = hisi_acc_vf_qm_init(hisi_acc_vdev);
>>>  		if (ret) {
>>> +			mutex_unlock(&hisi_acc_vdev->open_mutex);
>>>  			vfio_pci_core_disable(vdev);
>>>  			return ret;
>>>  		}
>>>  		hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING;
>>> +		hisi_acc_vdev->dev_opened = true;
>>> +		mutex_unlock(&hisi_acc_vdev->open_mutex);
>>>  	}
>>>
>>>  	vfio_pci_core_finish_enable(vdev);
>>> @@ -1322,7 +1464,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->open_mutex);
>>> +	hisi_acc_vdev->dev_opened = false;
>>>  	iounmap(vf_qm->io_base);
>>> +	mutex_unlock(&hisi_acc_vdev->open_mutex);
>>>  	vfio_pci_core_close_device(core_vdev);
>>>  }
>>>
>>> @@ -1342,6 +1487,7 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct
>>> vfio_device *core_vdev)
>>>  	hisi_acc_vdev->pf_qm = pf_qm;
>>>  	hisi_acc_vdev->vf_dev = pdev;
>>>  	mutex_init(&hisi_acc_vdev->state_mutex);
>>> +	mutex_init(&hisi_acc_vdev->open_mutex);
>>>
>>>  	core_vdev->migration_flags = VFIO_MIGRATION_STOP_COPY |
>>> VFIO_MIGRATION_PRE_COPY;
>>>  	core_vdev->mig_ops = &hisi_acc_vfio_pci_migrn_state_ops;
>>> @@ -1387,6 +1533,48 @@ static const struct vfio_device_ops
>>> hisi_acc_vfio_pci_ops = {
>>>  	.detach_ioas = vfio_iommufd_physical_detach_ioas,
>>>  };
>>>
>>> +static void 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;
>>> +
>>> +	if (vdev->ops != &hisi_acc_vfio_pci_migrn_ops)
>>> +		return;
>>> +
>>> +	vfio_dev_migration = debugfs_lookup("migration", vdev-  
>>>> debug_root);  
>>> +	if (!vfio_dev_migration) {
>>> +		dev_err(dev, "failed to lookup migration debugfs file!\n");
>>> +		return;
>>> +	}
>>> +
>>> +	migf = kzalloc(sizeof(struct hisi_acc_vf_migration_file),
>>> GFP_KERNEL);
> 
> checkpatch --strict also advises this could be written as:
> 
> 	migf = kzalloc(sizeof(*migf), GFP_KERNEL);
> 
> There's another one above with acc_vf_data.  I'd consider these
> optional, but I think it is good practice and is more consistent with
> existing allocations in this file.
>

OK, I will modify the two "kzalloc" together.

>>> +	if (!migf)
>>> +		return;
>>> +	hisi_acc_vdev->debug_migf = migf;
>>> +
>>> +	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);
>>> +}
>>> +
>>> +static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device
>>> *hisi_acc_vdev)
>>> +{
>>> +	/* If migrn_ops is not used, kfree(NULL) is valid */  
>>
>> The above comment is not required. Please remove.
> 
> I don't have a problem with it, but I'll let the two of you decide as
> co-owners of the file.  Thanks,
> 
> Alex
>

OK, I'll delete it.

Thanks.
Longfang.

> 
>>> +	kfree(hisi_acc_vdev->debug_migf);
>>> +	hisi_acc_vdev->debug_migf = NULL;
>>> +}
>>> +  
>>
> 
> 
> .
> 

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

* Re: [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2023-08-07 21:43   ` Alex Williamson
@ 2023-08-14  9:34     ` liulongfang
  0 siblings, 0 replies; 11+ messages in thread
From: liulongfang @ 2023-08-14  9:34 UTC (permalink / raw)
  To: Alex Williamson
  Cc: jgg, shameerali.kolothum.thodi, jonathan.cameron, cohuck,
	linux-kernel, linuxarm

On 2023/8/8 5:43, Alex Williamson wrote:
> On Fri, 28 Jul 2023 15:21:03 +0800
> liulongfang <liulongfang@huawei.com> wrote:
> 
>> From: Longfang Liu <liulongfang@huawei.com>
>>
>> On the debugfs framework of VFIO, if the CONFIG_DEBUG_FS 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:
>>
>> data file: used to get the migration data from the driver
>> attr file: used to get device attributes parameters from the driver
>> save file: used to read the data of the live migration device and save
>> it to the driver.
>> io_test: used to test IO read and write for the driver.
>>
>> Signed-off-by: Longfang Liu <liulongfang@huawei.com>
>> ---
>>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 178 ++++++++++++++++++
>>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |   3 +
>>  2 files changed, 181 insertions(+)
>>
>> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>> index 242ad319932a..a811dc237a29 100644
>> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
>> @@ -15,6 +15,7 @@
>>  #include <linux/anon_inodes.h>
>>  
>>  #include "hisi_acc_vfio_pci.h"
>> +#include "../../vfio.h"
>>  
>>  /* Return 0 on VM acc device ready, -ETIMEDOUT hardware timeout */
>>  static int qm_wait_dev_not_ready(struct hisi_qm *qm)
>> @@ -606,6 +607,18 @@ hisi_acc_check_int_state(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>>  	}
>>  }
>>  
>> +static void hisi_acc_vf_migf_save(struct hisi_acc_vf_migration_file *dst_migf,
>> +	struct hisi_acc_vf_migration_file *src_migf)
>> +{
>> +	if (!dst_migf)
>> +		return;
>> +
>> +	dst_migf->disabled = false;
>> +	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_fd(struct hisi_acc_vf_migration_file *migf)
>>  {
>>  	mutex_lock(&migf->lock);
>> @@ -618,12 +631,16 @@ static void hisi_acc_vf_disable_fd(struct hisi_acc_vf_migration_file *migf)
>>  static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>>  {
>>  	if (hisi_acc_vdev->resuming_migf) {
>> +		hisi_acc_vf_migf_save(hisi_acc_vdev->debug_migf,
>> +						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_vf_migf_save(hisi_acc_vdev->debug_migf,
>> +						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;
>> @@ -1303,6 +1320,162 @@ 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_acc_vf_migration_file *migf = hisi_acc_vdev->debug_migf;
>> +
>> +	if (!vdev->mig_ops || !migf) {
>> +		seq_printf(seq, "%s\n", "device does not support live migration!");
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* If device not opened, the debugfs operation will trigger calltrace */
>> +	if (!vdev->open_count) {
>> +		seq_printf(seq, "%s\n", "device not opened!");
>> +		return -EINVAL;
>> +	}
> 
> Following up on the previous reply:
> 
> https://lore.kernel.org/all/f01944a8-5668-8a3e-f384-fb9b0fc3b09f@huawei.com/
> 
>>> What prevents this from racing release of the device?
>>>
>> Now there are only read operations for debugfs. The open_count here only needs
>> to be used to prevent read operations when the device is not opened.
>> There is no need to deal with competition issues.
> 
> The explanation doesn't make sense to me, if we're not protecting that
> open_count remains elevated for the code path alluded to in the
> comment, then this test is useless.  If the calltrace can happen when
> the device is not open then it can happen when the device is closed
> immediately after this test is performed.
>

Yes, a solution is really needed here to ensure that the debugfs operation will
not be performed after device close.

The root cause of whether the device can be operated is whether the io_base of
the device has been mapped.
So, my solution is to use the mutex lock in vfio_device_set of vfio_device.
This mutex lock is used to ensure that this problem will not occur.

Thanks
Longfang.
>> +
>> +	return 0;
>> +}
>> +
>> +static int hisi_acc_vf_debug_io(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;
>> +
>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>> +	if (ret)
>> +		return 0;
>> +
> 
> For example, open_count can can be zero here regardless of the test in
> the previous function.
>
OK

>> +	ret = qm_wait_dev_not_ready(vf_qm);
>> +	if (ret) {
>> +		seq_printf(seq, "%s\n", "VF device not ready!");
>> +		return 0;
>> +	}
>> +
>> +	value = readl(vf_qm->io_base + QM_MB_CMD_SEND_BASE);
>> +	seq_printf(seq, "%s:0x%llx\n", "debug mailbox val", value);
>> +
>> +	return 0;
>> +}
> 
> I still don't understand why the debugfs file is called "io_test" for
> reading the mailbox.
>

Yes, it can be changed to io_state here.

>> +
>> +static int hisi_acc_vf_debug_save(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_acc_vf_migration_file *migf = hisi_acc_vdev->debug_migf;
>> +	int ret;
>> +
>> +	ret = hisi_acc_vf_debug_check(seq, vdev);
>> +	if (ret)
>> +		return 0;
> 
> Nothing requires that open_count is still elevated here.
>

OK

>> +
>> +	ret = vf_qm_state_save(hisi_acc_vdev, migf);
>> +	if (ret) {
>> +		seq_printf(seq, "%s\n", "failed to save device data!");
>> +		return 0;
>> +	}
>> +	seq_printf(seq, "%s\n", "successful to save device data!");
>> +
>> +	return 0;
>> +}
>> +
>> +static int hisi_acc_vf_data_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);
>> +	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
>> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
>> +
>> +	if (debug_migf && debug_migf->total_length)
>> +		seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
>> +				(unsigned char *)&debug_migf->vf_data,
>> +				vf_data_sz, false);
> 
> The previous save function attempts to make sure the device is open,
> but there's no attempt to drop the debug_migf data when the device is
> closed, so we can read the save data regardless of the device being
> opened or opened within the same instance where the data was saved.  Is
> this intentional?
>

I have understood what you said. The current save operation needs to have
a lock to ensure that the device is not closed when it reads.

>> +	else
>> +		seq_printf(seq, "%s\n", "device not migrated!");
>> +
>> +	return 0;
>> +}
>> +
>> +static int hisi_acc_vf_attr_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);
>> +	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
>> +
>> +	if (debug_migf && debug_migf->total_length) {
>> +		seq_printf(seq,
>> +			 "acc device:\n"
>> +			 "device  state: %d\n"
>> +			 "device  ready: %u\n"
>> +			 "data    valid: %d\n"
>> +			 "data     size: %lu\n",
>> +			 hisi_acc_vdev->mig_state,
>> +			 hisi_acc_vdev->vf_qm_state,
>> +			 debug_migf->disabled,
> 
> This is only ever false?
>
It should be false when there is no error.

>> +			 debug_migf->total_length);
>> +	} else {
>> +		seq_printf(seq, "%s\n", "device not migrated!");
>> +	}
>> +
>> +	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())
>> +		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) {
>> +		dev_err(dev, "failed to lookup migration debugfs file!\n");
>> +		return -ENODEV;
> 
> The allocation of debug_migf is rather wasted if we get here.
>

yes it should be free.


>> +	}
>> +
>> +	vfio_hisi_acc = debugfs_create_dir("hisi_acc", vfio_dev_migration);
>> +	debugfs_create_devm_seqfile(dev, "data", vfio_hisi_acc,
>> +				  hisi_acc_vf_data_read);
>> +	debugfs_create_devm_seqfile(dev, "attr", vfio_hisi_acc,
>> +				  hisi_acc_vf_attr_read);
> 
> Why do we want separate debugfs files for meta data vs data?  ie. why
> isn't the hex dump just another line of output along with the meta data?
>

The above data is the original data of the migration.
attr is the description attribute of migration data,
for example, total length, migration length.

>> +	debugfs_create_devm_seqfile(dev, "io_test", vfio_hisi_acc,
>> +				  hisi_acc_vf_debug_io);
>> +	debugfs_create_devm_seqfile(dev, "save", vfio_hisi_acc,
>> +				  hisi_acc_vf_debug_save);
>> +
>> +	return 0;
>> +}
>> +
>> +static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>> +{
>> +	if (!debugfs_initialized())
>> +		return;
>> +
>> +	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);
>> @@ -1323,6 +1496,7 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>>  	}
>>  
>>  	vfio_pci_core_finish_enable(vdev);
>> +
>>  	return 0;
>>  }
>>  
>> @@ -1422,6 +1596,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:
>> @@ -1433,6 +1610,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);
>>  
>> +	hisi_acc_vf_debugfs_exit(hisi_acc_vdev);
> 
> This frees debug_migf
> 
>>  	vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);
> 
> This triggers the recursive removal of the debugfs seqfiles.  There's a
> use-after-free race here where we can dump the contents of the freed
> buffer.  Thanks,
> 

Yes. This problem can be avoided if debugfs is deleted first,
and then the memory of debug_migf is released.

> Alex
>

Thanks.
Longfang.

>>  	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 dcabfeec6ca1..93f44bcf53ee 100644
>> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
>> @@ -113,5 +113,8 @@ struct hisi_acc_vf_core_device {
>>  	spinlock_t reset_lock;
>>  	struct hisi_acc_vf_migration_file *resuming_migf;
>>  	struct hisi_acc_vf_migration_file *saving_migf;
>> +
>> +	/* For debugfs */
>> +	struct hisi_acc_vf_migration_file *debug_migf;
>>  };
>>  #endif /* HISI_ACC_VFIO_PCI_H */
> 
> .
> 

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

* Re: [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2023-07-28  7:21 ` [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon " liulongfang
@ 2023-08-07 21:43   ` Alex Williamson
  2023-08-14  9:34     ` liulongfang
  0 siblings, 1 reply; 11+ messages in thread
From: Alex Williamson @ 2023-08-07 21:43 UTC (permalink / raw)
  To: liulongfang
  Cc: jgg, shameerali.kolothum.thodi, jonathan.cameron, cohuck,
	linux-kernel, linuxarm

On Fri, 28 Jul 2023 15:21:03 +0800
liulongfang <liulongfang@huawei.com> wrote:

> From: Longfang Liu <liulongfang@huawei.com>
> 
> On the debugfs framework of VFIO, if the CONFIG_DEBUG_FS 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:
> 
> data file: used to get the migration data from the driver
> attr file: used to get device attributes parameters from the driver
> save file: used to read the data of the live migration device and save
> it to the driver.
> io_test: used to test IO read and write for the driver.
> 
> Signed-off-by: Longfang Liu <liulongfang@huawei.com>
> ---
>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 178 ++++++++++++++++++
>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h    |   3 +
>  2 files changed, 181 insertions(+)
> 
> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> index 242ad319932a..a811dc237a29 100644
> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> @@ -15,6 +15,7 @@
>  #include <linux/anon_inodes.h>
>  
>  #include "hisi_acc_vfio_pci.h"
> +#include "../../vfio.h"
>  
>  /* Return 0 on VM acc device ready, -ETIMEDOUT hardware timeout */
>  static int qm_wait_dev_not_ready(struct hisi_qm *qm)
> @@ -606,6 +607,18 @@ hisi_acc_check_int_state(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>  	}
>  }
>  
> +static void hisi_acc_vf_migf_save(struct hisi_acc_vf_migration_file *dst_migf,
> +	struct hisi_acc_vf_migration_file *src_migf)
> +{
> +	if (!dst_migf)
> +		return;
> +
> +	dst_migf->disabled = false;
> +	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_fd(struct hisi_acc_vf_migration_file *migf)
>  {
>  	mutex_lock(&migf->lock);
> @@ -618,12 +631,16 @@ static void hisi_acc_vf_disable_fd(struct hisi_acc_vf_migration_file *migf)
>  static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vdev)
>  {
>  	if (hisi_acc_vdev->resuming_migf) {
> +		hisi_acc_vf_migf_save(hisi_acc_vdev->debug_migf,
> +						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_vf_migf_save(hisi_acc_vdev->debug_migf,
> +						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;
> @@ -1303,6 +1320,162 @@ 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_acc_vf_migration_file *migf = hisi_acc_vdev->debug_migf;
> +
> +	if (!vdev->mig_ops || !migf) {
> +		seq_printf(seq, "%s\n", "device does not support live migration!");
> +		return -EINVAL;
> +	}
> +
> +	/* If device not opened, the debugfs operation will trigger calltrace */
> +	if (!vdev->open_count) {
> +		seq_printf(seq, "%s\n", "device not opened!");
> +		return -EINVAL;
> +	}

Following up on the previous reply:

https://lore.kernel.org/all/f01944a8-5668-8a3e-f384-fb9b0fc3b09f@huawei.com/

>> What prevents this from racing release of the device?
>>
> Now there are only read operations for debugfs. The open_count here only needs
> to be used to prevent read operations when the device is not opened.
> There is no need to deal with competition issues.

The explanation doesn't make sense to me, if we're not protecting that
open_count remains elevated for the code path alluded to in the
comment, then this test is useless.  If the calltrace can happen when
the device is not open then it can happen when the device is closed
immediately after this test is performed.

> +
> +	return 0;
> +}
> +
> +static int hisi_acc_vf_debug_io(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;
> +
> +	ret = hisi_acc_vf_debug_check(seq, vdev);
> +	if (ret)
> +		return 0;
> +

For example, open_count can can be zero here regardless of the test in
the previous function.

> +	ret = qm_wait_dev_not_ready(vf_qm);
> +	if (ret) {
> +		seq_printf(seq, "%s\n", "VF device not ready!");
> +		return 0;
> +	}
> +
> +	value = readl(vf_qm->io_base + QM_MB_CMD_SEND_BASE);
> +	seq_printf(seq, "%s:0x%llx\n", "debug mailbox val", value);
> +
> +	return 0;
> +}

I still don't understand why the debugfs file is called "io_test" for
reading the mailbox.

> +
> +static int hisi_acc_vf_debug_save(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_acc_vf_migration_file *migf = hisi_acc_vdev->debug_migf;
> +	int ret;
> +
> +	ret = hisi_acc_vf_debug_check(seq, vdev);
> +	if (ret)
> +		return 0;

Nothing requires that open_count is still elevated here.

> +
> +	ret = vf_qm_state_save(hisi_acc_vdev, migf);
> +	if (ret) {
> +		seq_printf(seq, "%s\n", "failed to save device data!");
> +		return 0;
> +	}
> +	seq_printf(seq, "%s\n", "successful to save device data!");
> +
> +	return 0;
> +}
> +
> +static int hisi_acc_vf_data_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);
> +	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
> +	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
> +
> +	if (debug_migf && debug_migf->total_length)
> +		seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
> +				(unsigned char *)&debug_migf->vf_data,
> +				vf_data_sz, false);

The previous save function attempts to make sure the device is open,
but there's no attempt to drop the debug_migf data when the device is
closed, so we can read the save data regardless of the device being
opened or opened within the same instance where the data was saved.  Is
this intentional?

> +	else
> +		seq_printf(seq, "%s\n", "device not migrated!");
> +
> +	return 0;
> +}
> +
> +static int hisi_acc_vf_attr_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);
> +	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
> +
> +	if (debug_migf && debug_migf->total_length) {
> +		seq_printf(seq,
> +			 "acc device:\n"
> +			 "device  state: %d\n"
> +			 "device  ready: %u\n"
> +			 "data    valid: %d\n"
> +			 "data     size: %lu\n",
> +			 hisi_acc_vdev->mig_state,
> +			 hisi_acc_vdev->vf_qm_state,
> +			 debug_migf->disabled,

This is only ever false?

> +			 debug_migf->total_length);
> +	} else {
> +		seq_printf(seq, "%s\n", "device not migrated!");
> +	}
> +
> +	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())
> +		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) {
> +		dev_err(dev, "failed to lookup migration debugfs file!\n");
> +		return -ENODEV;

The allocation of debug_migf is rather wasted if we get here.

> +	}
> +
> +	vfio_hisi_acc = debugfs_create_dir("hisi_acc", vfio_dev_migration);
> +	debugfs_create_devm_seqfile(dev, "data", vfio_hisi_acc,
> +				  hisi_acc_vf_data_read);
> +	debugfs_create_devm_seqfile(dev, "attr", vfio_hisi_acc,
> +				  hisi_acc_vf_attr_read);

Why do we want separate debugfs files for meta data vs data?  ie. why
isn't the hex dump just another line of output along with the meta data?

> +	debugfs_create_devm_seqfile(dev, "io_test", vfio_hisi_acc,
> +				  hisi_acc_vf_debug_io);
> +	debugfs_create_devm_seqfile(dev, "save", vfio_hisi_acc,
> +				  hisi_acc_vf_debug_save);
> +
> +	return 0;
> +}
> +
> +static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev)
> +{
> +	if (!debugfs_initialized())
> +		return;
> +
> +	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);
> @@ -1323,6 +1496,7 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>  	}
>  
>  	vfio_pci_core_finish_enable(vdev);
> +
>  	return 0;
>  }
>  
> @@ -1422,6 +1596,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:
> @@ -1433,6 +1610,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);
>  
> +	hisi_acc_vf_debugfs_exit(hisi_acc_vdev);

This frees debug_migf

>  	vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);

This triggers the recursive removal of the debugfs seqfiles.  There's a
use-after-free race here where we can dump the contents of the freed
buffer.  Thanks,

Alex

>  	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 dcabfeec6ca1..93f44bcf53ee 100644
> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
> @@ -113,5 +113,8 @@ struct hisi_acc_vf_core_device {
>  	spinlock_t reset_lock;
>  	struct hisi_acc_vf_migration_file *resuming_migf;
>  	struct hisi_acc_vf_migration_file *saving_migf;
> +
> +	/* For debugfs */
> +	struct hisi_acc_vf_migration_file *debug_migf;
>  };
>  #endif /* HISI_ACC_VFIO_PCI_H */


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

* [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  2023-07-28  7:21 [PATCH v12 0/4] add debugfs to migration driver liulongfang
@ 2023-07-28  7:21 ` liulongfang
  2023-08-07 21:43   ` Alex Williamson
  0 siblings, 1 reply; 11+ messages in thread
From: liulongfang @ 2023-07-28  7:21 UTC (permalink / raw)
  To: alex.williamson, jgg, shameerali.kolothum.thodi, jonathan.cameron
  Cc: cohuck, linux-kernel, linuxarm, liulongfang

From: Longfang Liu <liulongfang@huawei.com>

On the debugfs framework of VFIO, if the CONFIG_DEBUG_FS 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:

data file: used to get the migration data from the driver
attr file: used to get device attributes parameters from the driver
save file: used to read the data of the live migration device and save
it to the driver.
io_test: used to test IO read and write for the driver.

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

diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
index 242ad319932a..a811dc237a29 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
@@ -15,6 +15,7 @@
 #include <linux/anon_inodes.h>
 
 #include "hisi_acc_vfio_pci.h"
+#include "../../vfio.h"
 
 /* Return 0 on VM acc device ready, -ETIMEDOUT hardware timeout */
 static int qm_wait_dev_not_ready(struct hisi_qm *qm)
@@ -606,6 +607,18 @@ hisi_acc_check_int_state(struct hisi_acc_vf_core_device *hisi_acc_vdev)
 	}
 }
 
+static void hisi_acc_vf_migf_save(struct hisi_acc_vf_migration_file *dst_migf,
+	struct hisi_acc_vf_migration_file *src_migf)
+{
+	if (!dst_migf)
+		return;
+
+	dst_migf->disabled = false;
+	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_fd(struct hisi_acc_vf_migration_file *migf)
 {
 	mutex_lock(&migf->lock);
@@ -618,12 +631,16 @@ static void hisi_acc_vf_disable_fd(struct hisi_acc_vf_migration_file *migf)
 static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vdev)
 {
 	if (hisi_acc_vdev->resuming_migf) {
+		hisi_acc_vf_migf_save(hisi_acc_vdev->debug_migf,
+						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_vf_migf_save(hisi_acc_vdev->debug_migf,
+						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;
@@ -1303,6 +1320,162 @@ 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_acc_vf_migration_file *migf = hisi_acc_vdev->debug_migf;
+
+	if (!vdev->mig_ops || !migf) {
+		seq_printf(seq, "%s\n", "device does not support live migration!");
+		return -EINVAL;
+	}
+
+	/* If device not opened, the debugfs operation will trigger calltrace */
+	if (!vdev->open_count) {
+		seq_printf(seq, "%s\n", "device not opened!");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int hisi_acc_vf_debug_io(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;
+
+	ret = hisi_acc_vf_debug_check(seq, vdev);
+	if (ret)
+		return 0;
+
+	ret = qm_wait_dev_not_ready(vf_qm);
+	if (ret) {
+		seq_printf(seq, "%s\n", "VF device not ready!");
+		return 0;
+	}
+
+	value = readl(vf_qm->io_base + QM_MB_CMD_SEND_BASE);
+	seq_printf(seq, "%s:0x%llx\n", "debug mailbox val", value);
+
+	return 0;
+}
+
+static int hisi_acc_vf_debug_save(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_acc_vf_migration_file *migf = hisi_acc_vdev->debug_migf;
+	int ret;
+
+	ret = hisi_acc_vf_debug_check(seq, vdev);
+	if (ret)
+		return 0;
+
+	ret = vf_qm_state_save(hisi_acc_vdev, migf);
+	if (ret) {
+		seq_printf(seq, "%s\n", "failed to save device data!");
+		return 0;
+	}
+	seq_printf(seq, "%s\n", "successful to save device data!");
+
+	return 0;
+}
+
+static int hisi_acc_vf_data_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);
+	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
+	size_t vf_data_sz = offsetofend(struct acc_vf_data, padding);
+
+	if (debug_migf && debug_migf->total_length)
+		seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1,
+				(unsigned char *)&debug_migf->vf_data,
+				vf_data_sz, false);
+	else
+		seq_printf(seq, "%s\n", "device not migrated!");
+
+	return 0;
+}
+
+static int hisi_acc_vf_attr_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);
+	struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf;
+
+	if (debug_migf && debug_migf->total_length) {
+		seq_printf(seq,
+			 "acc device:\n"
+			 "device  state: %d\n"
+			 "device  ready: %u\n"
+			 "data    valid: %d\n"
+			 "data     size: %lu\n",
+			 hisi_acc_vdev->mig_state,
+			 hisi_acc_vdev->vf_qm_state,
+			 debug_migf->disabled,
+			 debug_migf->total_length);
+	} else {
+		seq_printf(seq, "%s\n", "device not migrated!");
+	}
+
+	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())
+		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) {
+		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, "data", vfio_hisi_acc,
+				  hisi_acc_vf_data_read);
+	debugfs_create_devm_seqfile(dev, "attr", vfio_hisi_acc,
+				  hisi_acc_vf_attr_read);
+	debugfs_create_devm_seqfile(dev, "io_test", vfio_hisi_acc,
+				  hisi_acc_vf_debug_io);
+	debugfs_create_devm_seqfile(dev, "save", vfio_hisi_acc,
+				  hisi_acc_vf_debug_save);
+
+	return 0;
+}
+
+static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev)
+{
+	if (!debugfs_initialized())
+		return;
+
+	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);
@@ -1323,6 +1496,7 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
 	}
 
 	vfio_pci_core_finish_enable(vdev);
+
 	return 0;
 }
 
@@ -1422,6 +1596,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:
@@ -1433,6 +1610,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);
 
+	hisi_acc_vf_debugfs_exit(hisi_acc_vdev);
 	vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);
 	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 dcabfeec6ca1..93f44bcf53ee 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h
@@ -113,5 +113,8 @@ struct hisi_acc_vf_core_device {
 	spinlock_t reset_lock;
 	struct hisi_acc_vf_migration_file *resuming_migf;
 	struct hisi_acc_vf_migration_file *saving_migf;
+
+	/* For debugfs */
+	struct hisi_acc_vf_migration_file *debug_migf;
 };
 #endif /* HISI_ACC_VFIO_PCI_H */
-- 
2.24.0


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

end of thread, other threads:[~2024-11-06  9:19 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-11-05  3:52 [PATCH v12 0/4] debugfs to hisilicon migration driver Longfang Liu
2024-11-05  3:52 ` [PATCH v12 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
2024-11-05  3:52 ` [PATCH v12 2/4] hisi_acc_vfio_pci: create subfunction for data reading Longfang Liu
2024-11-05  3:52 ` [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
2024-11-05  8:55   ` Shameerali Kolothum Thodi
2024-11-05 18:21     ` Alex Williamson
2024-11-06  9:19       ` liulongfang
2024-11-05  3:52 ` [PATCH v12 4/4] Documentation: add debugfs description for hisi migration Longfang Liu
  -- strict thread matches above, loose matches on Subject: below --
2023-07-28  7:21 [PATCH v12 0/4] add debugfs to migration driver liulongfang
2023-07-28  7:21 ` [PATCH v12 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon " liulongfang
2023-08-07 21:43   ` Alex Williamson
2023-08-14  9:34     ` liulongfang

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

all inboxes | Powered by JetHome®