| 1 | |
| 2 | |
| 3 | * Copyright (c) 2023, HiSilicon Ltd.
|
| 4 |
|
| 5 |
|
| 6 | #include <linux/device.h>
|
| 7 | #include <linux/debugfs.h>
|
| 8 | #include <linux/seq_file.h>
|
| 9 | #include <linux/vfio.h>
|
| 10 | #include "vfio.h"
|
| 11 |
|
| 12 | static struct dentry *vfio_debugfs_root;
|
| 13 |
|
| 14 | static int vfio_device_state_read(struct seq_file *seq, void *data)
|
| 15 | {
|
| 16 | struct device *vf_dev = seq->private;
|
| 17 | struct vfio_device *vdev = container_of(vf_dev,
|
| 18 | struct vfio_device, device);
|
| 19 | enum vfio_device_mig_state state;
|
| 20 | int ret;
|
| 21 |
|
| 22 | BUILD_BUG_ON(VFIO_DEVICE_STATE_NR !=
|
| 23 | VFIO_DEVICE_STATE_PRE_COPY_P2P + 1);
|
| 24 |
|
| 25 | ret = vdev->mig_ops->migration_get_state(vdev, &state);
|
| 26 | if (ret)
|
| 27 | return -EINVAL;
|
| 28 |
|
| 29 | switch (state) {
|
| 30 | case VFIO_DEVICE_STATE_ERROR:
|
| 31 | seq_puts(seq, "ERROR\n");
|
| 32 | break;
|
| 33 | case VFIO_DEVICE_STATE_STOP:
|
| 34 | seq_puts(seq, "STOP\n");
|
| 35 | break;
|
| 36 | case VFIO_DEVICE_STATE_RUNNING:
|
| 37 | seq_puts(seq, "RUNNING\n");
|
| 38 | break;
|
| 39 | case VFIO_DEVICE_STATE_STOP_COPY:
|
| 40 | seq_puts(seq, "STOP_COPY\n");
|
| 41 | break;
|
| 42 | case VFIO_DEVICE_STATE_RESUMING:
|
| 43 | seq_puts(seq, "RESUMING\n");
|
| 44 | break;
|
| 45 | case VFIO_DEVICE_STATE_RUNNING_P2P:
|
| 46 | seq_puts(seq, "RUNNING_P2P\n");
|
| 47 | break;
|
| 48 | case VFIO_DEVICE_STATE_PRE_COPY:
|
| 49 | seq_puts(seq, "PRE_COPY\n");
|
| 50 | break;
|
| 51 | case VFIO_DEVICE_STATE_PRE_COPY_P2P:
|
| 52 | seq_puts(seq, "PRE_COPY_P2P\n");
|
| 53 | break;
|
| 54 | default:
|
| 55 | seq_puts(seq, "Invalid\n");
|
| 56 | }
|
| 57 |
|
| 58 | return 0;
|
| 59 | }
|
| 60 |
|
| 61 | static int vfio_device_features_read(struct seq_file *seq, void *data)
|
| 62 | {
|
| 63 | struct device *vf_dev = seq->private;
|
| 64 | struct vfio_device *vdev = container_of(vf_dev, struct vfio_device, device);
|
| 65 |
|
| 66 | if (vdev->migration_flags & VFIO_MIGRATION_STOP_COPY)
|
| 67 | seq_puts(seq, "stop-copy\n");
|
| 68 | if (vdev->migration_flags & VFIO_MIGRATION_P2P)
|
| 69 | seq_puts(seq, "p2p\n");
|
| 70 | if (vdev->migration_flags & VFIO_MIGRATION_PRE_COPY)
|
| 71 | seq_puts(seq, "pre-copy\n");
|
| 72 | if (vdev->log_ops)
|
| 73 | seq_puts(seq, "dirty-tracking\n");
|
| 74 |
|
| 75 | return 0;
|
| 76 | }
|
| 77 |
|
| 78 | void vfio_device_debugfs_init(struct vfio_device *vdev)
|
| 79 | {
|
| 80 | struct device *dev = &vdev->device;
|
| 81 |
|
| 82 | vdev->debug_root = debugfs_create_dir(dev_name(vdev->dev),
|
| 83 | vfio_debugfs_root);
|
| 84 |
|
| 85 | if (vdev->mig_ops) {
|
| 86 | struct dentry *vfio_dev_migration = NULL;
|
| 87 |
|
| 88 | vfio_dev_migration = debugfs_create_dir("migration",
|
| 89 | vdev->debug_root);
|
| 90 | debugfs_create_devm_seqfile(dev, "state", vfio_dev_migration,
|
| 91 | vfio_device_state_read);
|
| 92 | debugfs_create_devm_seqfile(dev, "features", vfio_dev_migration,
|
| 93 | vfio_device_features_read);
|
| 94 | }
|
| 95 | }
|
| 96 |
|
| 97 | void vfio_device_debugfs_exit(struct vfio_device *vdev)
|
| 98 | {
|
| 99 | debugfs_remove_recursive(vdev->debug_root);
|
| 100 | vdev->debug_root = NULL;
|
| 101 | }
|
| 102 |
|
| 103 | void vfio_debugfs_create_root(void)
|
| 104 | {
|
| 105 | vfio_debugfs_root = debugfs_create_dir("vfio", NULL);
|
| 106 | }
|
| 107 |
|
| 108 | void vfio_debugfs_remove_root(void)
|
| 109 | {
|
| 110 | debugfs_remove_recursive(vfio_debugfs_root);
|
| 111 | vfio_debugfs_root = NULL;
|
| 112 | }
|