* [PATCH v9 0/4] debugfs to hisilicon migration driver
@ 2024-09-13 9:54 Longfang Liu
2024-09-13 9:54 ` [PATCH v9 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Longfang Liu @ 2024-09-13 9:54 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 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 | 279 ++++++++++++++++--
.../vfio/pci/hisilicon/hisi_acc_vfio_pci.h | 7 +
3 files changed, 280 insertions(+), 31 deletions(-)
create mode 100644 Documentation/ABI/testing/debugfs-hisi-migration
--
2.24.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v9 1/4] hisi_acc_vfio_pci: extract public functions for container_of
2024-09-13 9:54 [PATCH v9 0/4] debugfs to hisilicon migration driver Longfang Liu
@ 2024-09-13 9:54 ` Longfang Liu
2024-09-13 9:55 ` [PATCH v9 2/4] hisi_acc_vfio_pci: create subfunction for data reading Longfang Liu
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Longfang Liu @ 2024-09-13 9:54 UTC (permalink / raw)
To: alex.williamson, jgg, shameerali.kolothum.thodi, jonathan.cameron
Cc: kvm, linux-kernel, linuxarm, liulongfang
In the current driver, vdev is obtained from struct
hisi_acc_vf_core_device through the container_of function.
This method is used in many places in the driver. In order to
reduce this repetitive operation, It was extracted into
a public function.
Signed-off-by: Longfang Liu <liulongfang@huawei.com>
Reviewed-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
---
.../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 21 ++++++++++---------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
index 9a3e97108ace..45351be8e270 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
@@ -630,6 +630,12 @@ static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vde
}
}
+static struct hisi_acc_vf_core_device *hisi_acc_get_vf_dev(struct vfio_device *vdev)
+{
+ return container_of(vdev, struct hisi_acc_vf_core_device,
+ core_device.vdev);
+}
+
static void hisi_acc_vf_reset(struct hisi_acc_vf_core_device *hisi_acc_vdev)
{
hisi_acc_vdev->vf_qm_state = QM_NOT_READY;
@@ -1033,8 +1039,7 @@ static struct file *
hisi_acc_vfio_pci_set_device_state(struct vfio_device *vdev,
enum vfio_device_mig_state new_state)
{
- struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(vdev,
- struct hisi_acc_vf_core_device, core_device.vdev);
+ struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
enum vfio_device_mig_state next_state;
struct file *res = NULL;
int ret;
@@ -1075,8 +1080,7 @@ static int
hisi_acc_vfio_pci_get_device_state(struct vfio_device *vdev,
enum vfio_device_mig_state *curr_state)
{
- struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(vdev,
- struct hisi_acc_vf_core_device, core_device.vdev);
+ struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev);
mutex_lock(&hisi_acc_vdev->state_mutex);
*curr_state = hisi_acc_vdev->mig_state;
@@ -1280,8 +1284,7 @@ static long hisi_acc_vfio_pci_ioctl(struct vfio_device *core_vdev, unsigned int
static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
{
- struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(core_vdev,
- struct hisi_acc_vf_core_device, core_device.vdev);
+ struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
struct vfio_pci_core_device *vdev = &hisi_acc_vdev->core_device;
int ret;
@@ -1304,8 +1307,7 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev)
{
- struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(core_vdev,
- struct hisi_acc_vf_core_device, core_device.vdev);
+ struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
iounmap(vf_qm->io_base);
@@ -1320,8 +1322,7 @@ static const struct vfio_migration_ops hisi_acc_vfio_pci_migrn_state_ops = {
static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev)
{
- struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(core_vdev,
- struct hisi_acc_vf_core_device, core_device.vdev);
+ struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
struct pci_dev *pdev = to_pci_dev(core_vdev->dev);
struct hisi_qm *pf_qm = hisi_acc_get_pf_qm(pdev);
--
2.24.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v9 2/4] hisi_acc_vfio_pci: create subfunction for data reading
2024-09-13 9:54 [PATCH v9 0/4] debugfs to hisilicon migration driver Longfang Liu
2024-09-13 9:54 ` [PATCH v9 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
@ 2024-09-13 9:55 ` Longfang Liu
2024-09-13 9:55 ` [PATCH v9 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
2024-09-13 9:55 ` [PATCH v9 4/4] Documentation: add debugfs description for hisi migration Longfang Liu
3 siblings, 0 replies; 7+ messages in thread
From: Longfang Liu @ 2024-09-13 9:55 UTC (permalink / raw)
To: alex.williamson, jgg, shameerali.kolothum.thodi, jonathan.cameron
Cc: kvm, linux-kernel, linuxarm, liulongfang
This patch generates the code for the operation of reading data from
the device into a sub-function.
Then, it can be called during the device status data saving phase of
the live migration process and the device status data reading function
in debugfs.
Thereby reducing the redundant code of the driver.
Signed-off-by: Longfang Liu <liulongfang@huawei.com>
Reviewed-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
---
.../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 54 +++++++++++--------
1 file changed, 33 insertions(+), 21 deletions(-)
diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
index 45351be8e270..a8c53952d82e 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
@@ -486,31 +486,11 @@ static int vf_qm_load_data(struct hisi_acc_vf_core_device *hisi_acc_vdev,
return 0;
}
-static int vf_qm_state_save(struct hisi_acc_vf_core_device *hisi_acc_vdev,
- struct hisi_acc_vf_migration_file *migf)
+static int vf_qm_read_data(struct hisi_qm *vf_qm, struct acc_vf_data *vf_data)
{
- struct acc_vf_data *vf_data = &migf->vf_data;
- struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
struct device *dev = &vf_qm->pdev->dev;
int ret;
- if (unlikely(qm_wait_dev_not_ready(vf_qm))) {
- /* Update state and return with match data */
- vf_data->vf_qm_state = QM_NOT_READY;
- hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state;
- migf->total_length = QM_MATCH_SIZE;
- return 0;
- }
-
- vf_data->vf_qm_state = QM_READY;
- hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state;
-
- ret = vf_qm_cache_wb(vf_qm);
- if (ret) {
- dev_err(dev, "failed to writeback QM Cache!\n");
- return ret;
- }
-
ret = qm_get_regs(vf_qm, vf_data);
if (ret)
return -EINVAL;
@@ -536,6 +516,38 @@ static int vf_qm_state_save(struct hisi_acc_vf_core_device *hisi_acc_vdev,
return -EINVAL;
}
+ return 0;
+}
+
+static int vf_qm_state_save(struct hisi_acc_vf_core_device *hisi_acc_vdev,
+ struct hisi_acc_vf_migration_file *migf)
+{
+ struct acc_vf_data *vf_data = &migf->vf_data;
+ struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm;
+ struct device *dev = &vf_qm->pdev->dev;
+ int ret;
+
+ if (unlikely(qm_wait_dev_not_ready(vf_qm))) {
+ /* Update state and return with match data */
+ vf_data->vf_qm_state = QM_NOT_READY;
+ hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state;
+ migf->total_length = QM_MATCH_SIZE;
+ return 0;
+ }
+
+ vf_data->vf_qm_state = QM_READY;
+ hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state;
+
+ ret = vf_qm_cache_wb(vf_qm);
+ if (ret) {
+ dev_err(dev, "failed to writeback QM Cache!\n");
+ return ret;
+ }
+
+ ret = vf_qm_read_data(vf_qm, vf_data);
+ if (ret)
+ return -EINVAL;
+
migf->total_length = sizeof(struct acc_vf_data);
return 0;
}
--
2.24.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v9 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
2024-09-13 9:54 [PATCH v9 0/4] debugfs to hisilicon migration driver Longfang Liu
2024-09-13 9:54 ` [PATCH v9 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
2024-09-13 9:55 ` [PATCH v9 2/4] hisi_acc_vfio_pci: create subfunction for data reading Longfang Liu
@ 2024-09-13 9:55 ` Longfang Liu
2024-10-11 8:09 ` Shameerali Kolothum Thodi
2024-09-13 9:55 ` [PATCH v9 4/4] Documentation: add debugfs description for hisi migration Longfang Liu
3 siblings, 1 reply; 7+ messages in thread
From: Longfang Liu @ 2024-09-13 9:55 UTC (permalink / raw)
To: alex.williamson, jgg, shameerali.kolothum.thodi, jonathan.cameron
Cc: kvm, linux-kernel, linuxarm, liulongfang
On the debugfs framework of VFIO, if the CONFIG_VFIO_DEBUGFS macro is
enabled, the debug function is registered for the live migration driver
of the HiSilicon accelerator device.
After registering the HiSilicon accelerator device on the debugfs
framework of live migration of vfio, a directory file "hisi_acc"
of debugfs is created, and then three debug function files are
created in this directory:
vfio
|
+---<dev_name1>
| +---migration
| +--state
| +--hisi_acc
| +--dev_data
| +--migf_data
| +--cmd_state
|
+---<dev_name2>
+---migration
+--state
+--hisi_acc
+--dev_data
+--migf_data
+--cmd_state
dev_data file: read device data that needs to be migrated from the
current device in real time
migf_data file: read the migration data of the last live migration
from the current driver.
cmd_state: used to get the cmd channel state for the device.
+----------------+ +--------------+ +---------------+
| migration dev | | src dev | | dst dev |
+-------+--------+ +------+-------+ +-------+-------+
| | |
| +------v-------+ +-------v-------+
| | saving_migf | | resuming_migf |
read | | file | | file |
| +------+-------+ +-------+-------+
| | copy |
| +------------+----------+
| |
+-------v--------+ +-------v--------+
| data buffer | | debug_migf |
+-------+--------+ +-------+--------+
| |
cat | cat |
+-------v--------+ +-------v--------+
| dev_data | | migf_data |
+----------------+ +----------------+
When accessing debugfs, user can obtain the most recent status data
of the device through the "dev_data" file. It can read recent
complete status data of the device. If the current device is being
migrated, it will wait for it to complete.
The data for the last completed migration function will be stored
in debug_migf. Users can read it via "migf_data".
Signed-off-by: Longfang Liu <liulongfang@huawei.com>
---
.../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 204 ++++++++++++++++++
.../vfio/pci/hisilicon/hisi_acc_vfio_pci.h | 7 +
2 files changed, 211 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..da9f5b9e6c5b 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,181 @@ 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 = NULL;
+ int ret;
+
+ vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
+ if (!vf_data)
+ return -ENOMEM;
+
+ mutex_lock(&hisi_acc_vdev->open_mutex);
+ ret = hisi_acc_vf_debug_check(seq, vdev);
+ if (ret) {
+ mutex_unlock(&hisi_acc_vdev->open_mutex);
+ goto migf_err;
+ }
+
+ mutex_lock(&hisi_acc_vdev->state_mutex);
+ vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state;
+ ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data);
+ if (ret) {
+ mutex_unlock(&hisi_acc_vdev->open_mutex);
+ mutex_unlock(&hisi_acc_vdev->state_mutex);
+ goto migf_err;
+ }
+
+ mutex_unlock(&hisi_acc_vdev->open_mutex);
+ mutex_unlock(&hisi_acc_vdev->state_mutex);
+
+ seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
+ (unsigned char *)vf_data,
+ vf_data_sz, false);
+
+ seq_printf(seq,
+ "acc device:\n"
+ "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);
+
+ 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,
+ (unsigned char *)&debug_migf->vf_data,
+ vf_data_sz, false);
+
+ seq_printf(seq,
+ "acc device:\n"
+ "guest driver load: %u\n"
+ "device opened: %d\n"
+ "migrate data length: %lu\n",
+ hisi_acc_vdev->vf_qm_state,
+ hisi_acc_vdev->dev_opened,
+ debug_migf->total_length);
+
+ return 0;
+}
+
+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;
+
+ 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 (hisi_acc_vdev->debug_migf) {
+ kfree(hisi_acc_vdev->debug_migf);
+ hisi_acc_vdev->debug_migf = NULL;
+ }
+}
+
static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
{
struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
@@ -1305,12 +1495,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 +1516,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 +1539,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;
@@ -1413,6 +1611,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:
@@ -1423,8 +1624,11 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device
static void hisi_acc_vfio_pci_remove(struct pci_dev *pdev)
{
struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev);
+ struct vfio_device *vdev = &hisi_acc_vdev->core_device.vdev;
vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);
+ if (vdev->ops == &hisi_acc_vfio_pci_migrn_ops)
+ 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..2a78ffd060c3 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,8 @@ struct hisi_acc_vf_migration_file {
struct hisi_acc_vf_core_device {
struct vfio_pci_core_device core_device;
u8 match_done;
+ /* To make sure the device is opened */
+ bool dev_opened;
/* For migration state */
struct mutex state_mutex;
@@ -111,5 +114,9 @@ struct hisi_acc_vf_core_device {
int vf_id;
struct hisi_acc_vf_migration_file *resuming_migf;
struct hisi_acc_vf_migration_file *saving_migf;
+
+ /* To save migration data */
+ struct hisi_acc_vf_migration_file *debug_migf;
+ struct mutex open_mutex;
};
#endif /* HISI_ACC_VFIO_PCI_H */
--
2.24.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v9 4/4] Documentation: add debugfs description for hisi migration
2024-09-13 9:54 [PATCH v9 0/4] debugfs to hisilicon migration driver Longfang Liu
` (2 preceding siblings ...)
2024-09-13 9:55 ` [PATCH v9 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
@ 2024-09-13 9:55 ` Longfang Liu
3 siblings, 0 replies; 7+ messages in thread
From: Longfang Liu @ 2024-09-13 9:55 UTC (permalink / raw)
To: alex.williamson, jgg, shameerali.kolothum.thodi, jonathan.cameron
Cc: kvm, linux-kernel, linuxarm, liulongfang
Add a debugfs document description file to help users understand
how to use the hisilicon accelerator live migration driver's
debugfs.
Update the file paths that need to be maintained in MAINTAINERS
Signed-off-by: Longfang Liu <liulongfang@huawei.com>
---
.../ABI/testing/debugfs-hisi-migration | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100644 Documentation/ABI/testing/debugfs-hisi-migration
diff --git a/Documentation/ABI/testing/debugfs-hisi-migration b/Documentation/ABI/testing/debugfs-hisi-migration
new file mode 100644
index 000000000000..f625b3ca230e
--- /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: Sep 2024
+KernelVersion: 6.11
+Contact: Longfang Liu <liulongfang@huawei.com>
+Description: Read the configuration data and some status data
+ required for device live migration. These data include device
+ status data, queue configuration data, some task configuration
+ data and device attribute data. The output format of the data
+ is defined by the live migration driver.
+
+What: /sys/kernel/debug/vfio/<device>/migration/hisi_acc/migf_data
+Date: Sep 2024
+KernelVersion: 6.11
+Contact: Longfang Liu <liulongfang@huawei.com>
+Description: Read the data from the last completed live migration.
+ This data includes the same device status data as in "dev_data".
+ The migf_data is the dev_data that is migrated.
+
+What: /sys/kernel/debug/vfio/<device>/migration/hisi_acc/cmd_state
+Date: Sep 2024
+KernelVersion: 6.11
+Contact: Longfang Liu <liulongfang@huawei.com>
+Description: Used to obtain the device command sending and receiving
+ channel status. Returns failure or success logs based on the
+ results.
--
2.24.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* RE: [PATCH v9 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
2024-09-13 9:55 ` [PATCH v9 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
@ 2024-10-11 8:09 ` Shameerali Kolothum Thodi
2024-10-12 9:03 ` liulongfang
0 siblings, 1 reply; 7+ messages in thread
From: Shameerali Kolothum Thodi @ 2024-10-11 8:09 UTC (permalink / raw)
To: liulongfang, alex.williamson@redhat.com, jgg@nvidia.com,
Jonathan Cameron
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
linuxarm@openeuler.org
> -----Original Message-----
> From: liulongfang <liulongfang@huawei.com>
> Sent: Friday, September 13, 2024 10:55 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 v9 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon
> migration driver
>
> On the debugfs framework of VFIO, if the CONFIG_VFIO_DEBUGFS macro is
> enabled, the debug function is registered for the live migration driver
> of the HiSilicon accelerator device.
>
> After registering the HiSilicon accelerator device on the debugfs
> framework of live migration of vfio, a directory file "hisi_acc"
> of debugfs is created, and then three debug function files are
> created in this directory:
>
> vfio
> |
> +---<dev_name1>
> | +---migration
> | +--state
> | +--hisi_acc
> | +--dev_data
> | +--migf_data
> | +--cmd_state
> |
> +---<dev_name2>
> +---migration
> +--state
> +--hisi_acc
> +--dev_data
> +--migf_data
> +--cmd_state
>
> dev_data file: read device data that needs to be migrated from the
> current device in real time
> migf_data file: read the migration data of the last live migration
> from the current driver.
> cmd_state: used to get the cmd channel state for the device.
>
> +----------------+ +--------------+ +---------------+
> | migration dev | | src dev | | dst dev |
> +-------+--------+ +------+-------+ +-------+-------+
> | | |
> | +------v-------+ +-------v-------+
> | | saving_migf | | resuming_migf |
> read | | file | | file |
> | +------+-------+ +-------+-------+
> | | copy |
> | +------------+----------+
> | |
> +-------v--------+ +-------v--------+
> | data buffer | | debug_migf |
> +-------+--------+ +-------+--------+
> | |
> cat | cat |
> +-------v--------+ +-------v--------+
> | dev_data | | migf_data |
> +----------------+ +----------------+
>
> When accessing debugfs, user can obtain the most recent status data
> of the device through the "dev_data" file. It can read recent
> complete status data of the device. If the current device is being
> migrated, it will wait for it to complete.
> The data for the last completed migration function will be stored
> in debug_migf. Users can read it via "migf_data".
>
> Signed-off-by: Longfang Liu <liulongfang@huawei.com>
> ---
> .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 204 ++++++++++++++++++
> .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h | 7 +
> 2 files changed, 211 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..da9f5b9e6c5b 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,181 @@ 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;
> + }
Still not very sure this vf_qm ready() check actually helps or not? What guarantee
is there that the qm will stay Ready after this call? Any read/write afterwards
will eventually fail if it is not ready later for some reason, right?
Perhaps helps in early detection and bails out.
> + 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 = NULL;
> + int ret;
> +
> + vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
> + if (!vf_data)
> + return -ENOMEM;\
You could move the allocation after the below checks and to just before
vf_qm_read_data().
> +
> + mutex_lock(&hisi_acc_vdev->open_mutex);
> + ret = hisi_acc_vf_debug_check(seq, vdev);
> + if (ret) {
> + mutex_unlock(&hisi_acc_vdev->open_mutex);
> + goto migf_err;
> + }
> +
> + mutex_lock(&hisi_acc_vdev->state_mutex);
> + vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state;
> + ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data);
> + if (ret) {
> + mutex_unlock(&hisi_acc_vdev->open_mutex);
> + mutex_unlock(&hisi_acc_vdev->state_mutex);
I think it is better to unlock in the reverse order. Also probably you can move
the unlocks to a goto area.
> + goto migf_err;
> + }
> +
> + mutex_unlock(&hisi_acc_vdev->open_mutex);
> + mutex_unlock(&hisi_acc_vdev->state_mutex);
Same as above.
> + seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
> + (unsigned char *)vf_data,
> + vf_data_sz, false);
> +
> + seq_printf(seq,
> + "acc device:\n"
> + "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);
> +
> + 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,
> + (unsigned char *)&debug_migf->vf_data,
> + vf_data_sz, false);
> +
> + seq_printf(seq,
> + "acc device:\n"
> + "guest driver load: %u\n"
> + "device opened: %d\n"
> + "migrate data length: %lu\n",
> + hisi_acc_vdev->vf_qm_state,
> + hisi_acc_vdev->dev_opened,
> + debug_migf->total_length);
> +
> + return 0;
> +}
> +
> +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;
> +
> + 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 (hisi_acc_vdev->debug_migf) {
> + kfree(hisi_acc_vdev->debug_migf);
> + hisi_acc_vdev->debug_migf = NULL;
> + }
> +}
> +
> static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
> {
> struct hisi_acc_vf_core_device *hisi_acc_vdev =
> hisi_acc_get_vf_dev(core_vdev);
> @@ -1305,12 +1495,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 +1516,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 +1539,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;
> @@ -1413,6 +1611,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);
I think there was a comment earlier on this. Still not sure why it is not possible to
move ops == &hisi_acc_vfio_pci_migrn_ops check inside hisi_acc_vfio_debug_init().
> return 0;
>
> out_put_vdev:
> @@ -1423,8 +1624,11 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev
> *pdev, const struct pci_device
> static void hisi_acc_vfio_pci_remove(struct pci_dev *pdev)
> {
> struct hisi_acc_vf_core_device *hisi_acc_vdev =
> hisi_acc_drvdata(pdev);
> + struct vfio_device *vdev = &hisi_acc_vdev->core_device.vdev;
>
> vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);
> + if (vdev->ops == &hisi_acc_vfio_pci_migrn_ops)
> + hisi_acc_vf_debugfs_exit(hisi_acc_vdev);
Do we need to do vdev->ops == &hisi_acc_vfio_pci_migrn_ops check here?
Since we are checking
hisi_acc_vdev->debug_migf inside the exit function, which I think is only
set when the ops == migrn_ops. Right?
Thanks,
Shameer
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v9 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
2024-10-11 8:09 ` Shameerali Kolothum Thodi
@ 2024-10-12 9:03 ` liulongfang
0 siblings, 0 replies; 7+ messages in thread
From: liulongfang @ 2024-10-12 9:03 UTC (permalink / raw)
To: Shameerali Kolothum Thodi, alex.williamson@redhat.com,
jgg@nvidia.com, Jonathan Cameron
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
linuxarm@openeuler.org
On 2024/10/11 16:09, Shameerali Kolothum Thodi wrote:
>
>
>> -----Original Message-----
>> From: liulongfang <liulongfang@huawei.com>
>> Sent: Friday, September 13, 2024 10:55 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 v9 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon
>> migration driver
>>
>> On the debugfs framework of VFIO, if the CONFIG_VFIO_DEBUGFS macro is
>> enabled, the debug function is registered for the live migration driver
>> of the HiSilicon accelerator device.
>>
>> After registering the HiSilicon accelerator device on the debugfs
>> framework of live migration of vfio, a directory file "hisi_acc"
>> of debugfs is created, and then three debug function files are
>> created in this directory:
>>
>> vfio
>> |
>> +---<dev_name1>
>> | +---migration
>> | +--state
>> | +--hisi_acc
>> | +--dev_data
>> | +--migf_data
>> | +--cmd_state
>> |
>> +---<dev_name2>
>> +---migration
>> +--state
>> +--hisi_acc
>> +--dev_data
>> +--migf_data
>> +--cmd_state
>>
>> dev_data file: read device data that needs to be migrated from the
>> current device in real time
>> migf_data file: read the migration data of the last live migration
>> from the current driver.
>> cmd_state: used to get the cmd channel state for the device.
>>
>> +----------------+ +--------------+ +---------------+
>> | migration dev | | src dev | | dst dev |
>> +-------+--------+ +------+-------+ +-------+-------+
>> | | |
>> | +------v-------+ +-------v-------+
>> | | saving_migf | | resuming_migf |
>> read | | file | | file |
>> | +------+-------+ +-------+-------+
>> | | copy |
>> | +------------+----------+
>> | |
>> +-------v--------+ +-------v--------+
>> | data buffer | | debug_migf |
>> +-------+--------+ +-------+--------+
>> | |
>> cat | cat |
>> +-------v--------+ +-------v--------+
>> | dev_data | | migf_data |
>> +----------------+ +----------------+
>>
>> When accessing debugfs, user can obtain the most recent status data
>> of the device through the "dev_data" file. It can read recent
>> complete status data of the device. If the current device is being
>> migrated, it will wait for it to complete.
>> The data for the last completed migration function will be stored
>> in debug_migf. Users can read it via "migf_data".
>>
>> Signed-off-by: Longfang Liu <liulongfang@huawei.com>
>> ---
>> .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c | 204 ++++++++++++++++++
>> .../vfio/pci/hisilicon/hisi_acc_vfio_pci.h | 7 +
>> 2 files changed, 211 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..da9f5b9e6c5b 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,181 @@ 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;
>> + }
>
> Still not very sure this vf_qm ready() check actually helps or not? What guarantee
> is there that the qm will stay Ready after this call? Any read/write afterwards
> will eventually fail if it is not ready later for some reason, right?
> Perhaps helps in early detection and bails out.
>
The purpose here is to intercept invalid debugfs operations.
When VF does not add a driver in Guest OS. The internal data reading and recovery
operations of the live migration operation will be skipped.
The data read is all empty data.
>> + 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 = NULL;
>> + int ret;
>> +
>> + vf_data = kzalloc(sizeof(struct acc_vf_data), GFP_KERNEL);
>> + if (!vf_data)
>> + return -ENOMEM;\
>
> You could move the allocation after the below checks and to just before
> vf_qm_read_data().
>
OK.
>> +
>> + mutex_lock(&hisi_acc_vdev->open_mutex);
>> + ret = hisi_acc_vf_debug_check(seq, vdev);
>> + if (ret) {
>> + mutex_unlock(&hisi_acc_vdev->open_mutex);
>> + goto migf_err;
>> + }
>> +
>> + mutex_lock(&hisi_acc_vdev->state_mutex);
>> + vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state;
>> + ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data);
>> + if (ret) {
>> + mutex_unlock(&hisi_acc_vdev->open_mutex);
>> + mutex_unlock(&hisi_acc_vdev->state_mutex);
>
> I think it is better to unlock in the reverse order. Also probably you can move
> the unlocks to a goto area.
>
My consideration is to release the mutex before outputting the log.
it can be optimized.
>> + goto migf_err;
>> + }
>> +
>> + mutex_unlock(&hisi_acc_vdev->open_mutex);
>> + mutex_unlock(&hisi_acc_vdev->state_mutex);
>
> Same as above.
OK.
>
>> + seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1,
>> + (unsigned char *)vf_data,
>> + vf_data_sz, false);
>> +
>> + seq_printf(seq,
>> + "acc device:\n"
>> + "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);
>> +
>> + 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,
>> + (unsigned char *)&debug_migf->vf_data,
>> + vf_data_sz, false);
>> +
>> + seq_printf(seq,
>> + "acc device:\n"
>> + "guest driver load: %u\n"
>> + "device opened: %d\n"
>> + "migrate data length: %lu\n",
>> + hisi_acc_vdev->vf_qm_state,
>> + hisi_acc_vdev->dev_opened,
>> + debug_migf->total_length);
>> +
>> + return 0;
>> +}
>> +
>> +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;
>> +
>> + 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 (hisi_acc_vdev->debug_migf) {
>> + kfree(hisi_acc_vdev->debug_migf);
>> + hisi_acc_vdev->debug_migf = NULL;
>> + }
>> +}
>> +
>> static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>> {
>> struct hisi_acc_vf_core_device *hisi_acc_vdev =
>> hisi_acc_get_vf_dev(core_vdev);
>> @@ -1305,12 +1495,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 +1516,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 +1539,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;
>> @@ -1413,6 +1611,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);
>
> I think there was a comment earlier on this. Still not sure why it is not possible to
> move ops == &hisi_acc_vfio_pci_migrn_ops check inside hisi_acc_vfio_debug_init().
>
The variable hisi_acc_vfio_pci_migrn_ops is declared after the function hisi_acc_vfio_debug_init.
If placed inside the function, a compilation error will occur.
>> return 0;
>>
>> out_put_vdev:
>> @@ -1423,8 +1624,11 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev
>> *pdev, const struct pci_device
>> static void hisi_acc_vfio_pci_remove(struct pci_dev *pdev)
>> {
>> struct hisi_acc_vf_core_device *hisi_acc_vdev =
>> hisi_acc_drvdata(pdev);
>> + struct vfio_device *vdev = &hisi_acc_vdev->core_device.vdev;
>>
>> vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device);
>> + if (vdev->ops == &hisi_acc_vfio_pci_migrn_ops)
>> + hisi_acc_vf_debugfs_exit(hisi_acc_vdev);
>
> Do we need to do vdev->ops == &hisi_acc_vfio_pci_migrn_ops check here?
>
> Since we are checking
> hisi_acc_vdev->debug_migf inside the exit function, which I think is only
> set when the ops == migrn_ops. Right?
>
"vdev->ops == &hisi_acc_vfio_pci_migrn_ops" is added here to maintain symmetry
with the code processing in the probe.
I added it also because of another reviewer’s suggestion.
Thanks.
Longfang.
> Thanks,
> Shameer
>
> .
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2024-10-12 9:03 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-13 9:54 [PATCH v9 0/4] debugfs to hisilicon migration driver Longfang Liu
2024-09-13 9:54 ` [PATCH v9 1/4] hisi_acc_vfio_pci: extract public functions for container_of Longfang Liu
2024-09-13 9:55 ` [PATCH v9 2/4] hisi_acc_vfio_pci: create subfunction for data reading Longfang Liu
2024-09-13 9:55 ` [PATCH v9 3/4] hisi_acc_vfio_pci: register debugfs for hisilicon migration driver Longfang Liu
2024-10-11 8:09 ` Shameerali Kolothum Thodi
2024-10-12 9:03 ` liulongfang
2024-09-13 9:55 ` [PATCH v9 4/4] Documentation: add debugfs description for hisi migration Longfang Liu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox