diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
index 24c524224da5..efe032623664 100644
--- a/drivers/vfio/pci/Makefile
+++ b/drivers/vfio/pci/Makefile
@@ -4,6 +4,10 @@ vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_con
 vfio-pci-core-$(CONFIG_VFIO_PCI_ZDEV_KVM) += vfio_pci_zdev.o
 obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o
 
+ifneq ($(CONFIG_DEBUG_FS),)
+	vfio-pci-core-y += vfio_pci_debugfs.o
+endif
+
 vfio-pci-y := vfio_pci.o
 vfio-pci-$(CONFIG_VFIO_PCI_IGD) += vfio_pci_igd.o
 obj-$(CONFIG_VFIO_PCI) += vfio-pci.o
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index f9365a5bc961..e85df2deb8e6 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -31,6 +31,7 @@
 #include <asm/eeh.h>
 #endif
 
+#include "vfio_pci_debugfs.h"
 #include "vfio_pci_priv.h"
 
 #define DRIVER_AUTHOR   "Alex Williamson <alex.williamson@redhat.com>"
@@ -2555,11 +2556,13 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_set_params);
 
 static void vfio_pci_core_cleanup(void)
 {
+	vfio_pci_debugfs_remove_root();
 	vfio_pci_uninit_perm_bits();
 }
 
 static int __init vfio_pci_core_init(void)
 {
+	vfio_pci_debugfs_create_root();
 	/* Allocate shared config space permission data used by all devices */
 	return vfio_pci_init_perm_bits();
 }
diff --git a/drivers/vfio/pci/vfio_pci_debugfs.c b/drivers/vfio/pci/vfio_pci_debugfs.c
new file mode 100644
index 000000000000..33d663fb04f2
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_debugfs.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, HiSilicon Ltd.
+ */
+
+#include <linux/pci.h>
+#include <linux/vfio_pci_core.h>
+
+#include "vfio_pci_debugfs.h"
+
+static struct dentry *vfio_pci_debugfs_root;
+
+static int vfio_pci_vf_state_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;
+	enum vfio_device_mig_state state;
+
+	(void)vdev->mig_ops->migration_get_state(vdev, &state);
+	switch (state) {
+	case VFIO_DEVICE_STATE_RUNNING:
+		seq_printf(seq, "%s\n", "RUNNING");
+		break;
+	case VFIO_DEVICE_STATE_STOP_COPY:
+		seq_printf(seq, "%s\n", "STOP_COPY");
+		break;
+	case VFIO_DEVICE_STATE_STOP:
+		seq_printf(seq, "%s\n", "STOP");
+		break;
+	case VFIO_DEVICE_STATE_RESUMING:
+		seq_printf(seq, "%s\n", "RESUMING");
+		break;
+	case VFIO_DEVICE_STATE_RUNNING_P2P:
+		seq_printf(seq, "%s\n", "RESUMING_P2P");
+		break;
+	case VFIO_DEVICE_STATE_ERROR:
+		seq_printf(seq, "%s\n", "ERROR");
+		break;
+	default:
+		seq_printf(seq, "%s\n", "Invalid");
+	}
+
+	return 0;
+}
+
+void vfio_pci_vf_debugfs_init(struct vfio_device *vdev)
+{
+	struct device *dev = vdev->dev;
+
+	vdev->debug_root = debugfs_create_dir(dev_name(dev), vfio_pci_debugfs_root);
+
+	debugfs_create_devm_seqfile(dev, "state", vdev->debug_root,
+				  vfio_pci_vf_state_read);
+}
+EXPORT_SYMBOL_GPL(vfio_pci_vf_debugfs_init);
+
+void vfio_pci_vf_debugfs_exit(struct vfio_device *vdev)
+{
+	debugfs_remove_recursive(vdev->debug_root);
+}
+EXPORT_SYMBOL_GPL(vfio_pci_vf_debugfs_exit);
+
+void  vfio_pci_debugfs_create_root(void)
+{
+	vfio_pci_debugfs_root = debugfs_create_dir("vfio_mig", NULL);
+}
+EXPORT_SYMBOL_GPL(vfio_pci_debugfs_create_root);
+
+void  vfio_pci_debugfs_remove_root(void)
+{
+	debugfs_remove_recursive(vfio_pci_debugfs_root);
+	vfio_pci_debugfs_root = NULL;
+}
+EXPORT_SYMBOL_GPL(vfio_pci_debugfs_remove_root);
+
diff --git a/drivers/vfio/pci/vfio_pci_debugfs.h b/drivers/vfio/pci/vfio_pci_debugfs.h
new file mode 100644
index 000000000000..8d1a4aef05db
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_debugfs.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * vfio_pci_debugfs.h - VFIO migration debugfs interface
+ *
+ * Copyright (c) 2022, HiSilicon Ltd.
+ *
+ * Author: Longfang Liu <liulongfang@huawei.com>
+ */
+
+#ifndef __VFIO_PCI_DEBUGFS_H
+#define __VFIO_PCI_DEBUGFS_H
+
+#include <linux/debugfs.h>
+#include <linux/vfio.h>
+
+#ifdef CONFIG_DEBUG_FS
+void  vfio_pci_debugfs_create_root(void);
+void  vfio_pci_debugfs_remove_root(void);
+
+void vfio_pci_vf_debugfs_init(struct vfio_device *vdev);
+void vfio_pci_vf_debugfs_exit(struct vfio_device *vdev);
+#else
+static inline void vfio_pci_debugfs_create_root(void) { }
+static inline void vfio_pci_debugfs_remove_root(void) { }
+
+static inline void vfio_pci_vf_debugfs_init(struct vfio_device *vdev) { }
+static inline void vfio_pci_vf_debugfs_exit(struct vfio_device *vdev) { }
+#endif /* CONFIG_DEBUG_FS */
+
+#endif /* __VFIO_PCI_DEBUGFS_H */
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index b4d5d4ca3d7d..7d6d02f165cf 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -54,6 +54,12 @@ struct vfio_device {
 	struct completion comp;
 	struct list_head group_next;
 	struct list_head iommu_entry;
+
+	/*
+	 * debug_root is a static property of the vfio_device
+	 * which must be set prior to registering the vfio_device.
+	 */
+	struct dentry *debug_root;
 };
 
 /**
