Commit 4aca98a8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'vfio-v6.13-rc1' of https://github.com/awilliam/linux-vfio

Pull VFIO updates from Alex Williamson:

 - Constify an unmodified structure used in linking vfio and kvm
   (Christophe JAILLET)

 - Add ID for an additional hardware SKU supported by the nvgrace-gpu
   vfio-pci variant driver (Ankit Agrawal)

 - Fix incorrect signed cast in QAT vfio-pci variant driver, negating
   test in check_add_overflow(), though still caught by later tests
   (Giovanni Cabiddu)

 - Additional debugfs attributes exposed in hisi_acc vfio-pci variant
   driver for migration debugging (Longfang Liu)

 - Migration support is added to the virtio vfio-pci variant driver,
   becoming the primary feature of the driver while retaining emulation
   of virtio legacy support as a secondary option (Yishai Hadas)

 - Fixes to a few unwind flows in the mlx5 vfio-pci driver discovered
   through reviews of the virtio variant driver (Yishai Hadas)

 - Fix an unlikely issue where a PCI device exposed to userspace with an
   unknown capability at the base of the extended capability chain can
   overflow an array index (Avihai Horon)

* tag 'vfio-v6.13-rc1' of https://github.com/awilliam/linux-vfio:
  vfio/pci: Properly hide first-in-list PCIe extended capability
  vfio/mlx5: Fix unwind flows in mlx5vf_pci_save/resume_device_data()
  vfio/mlx5: Fix an unwind issue in mlx5vf_add_migration_pages()
  vfio/virtio: Enable live migration once VIRTIO_PCI was configured
  vfio/virtio: Add PRE_COPY support for live migration
  vfio/virtio: Add support for the basic live migration functionality
  virtio-pci: Introduce APIs to execute device parts admin commands
  virtio: Manage device and driver capabilities via the admin commands
  virtio: Extend the admin command to include the result size
  virtio_pci: Introduce device parts access commands
  Documentation: add debugfs description for hisi migration
  hisi_acc_vfio_pci: register debugfs for hisilicon migration driver
  hisi_acc_vfio_pci: create subfunction for data reading
  hisi_acc_vfio_pci: extract public functions for container_of
  vfio/qat: fix overflow check in qat_vf_resume_write()
  vfio/nvgrace-gpu: Add a new GH200 SKU to the devid table
  kvm/vfio: Constify struct kvm_device_ops
parents 91dbbe6c fe4bf8d0
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
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.
+235 −31
Original line number Diff line number Diff line
@@ -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;
}
@@ -615,21 +627,43 @@ 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;
	}
}

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;
@@ -1031,8 +1065,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;
@@ -1073,8 +1106,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;
@@ -1276,10 +1308,132 @@ 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_puts(seq, "device not opened!\n");
		return -EINVAL;
	}

	ret = qm_wait_dev_not_ready(vf_qm);
	if (ret) {
		seq_puts(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_puts(seq, "mailbox cmd channel not ready!\n");
		return -EINVAL;
	}
	mutex_unlock(&hisi_acc_vdev->open_mutex);
	seq_puts(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(*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_puts(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 = 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;

@@ -1288,12 +1442,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);
@@ -1302,11 +1460,13 @@ 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;

	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);
}

@@ -1318,8 +1478,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);

@@ -1327,6 +1486,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;
@@ -1372,6 +1532,47 @@ 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 hisi_acc_vf_migration_file *migf;
	struct dentry *vfio_dev_migration;
	struct dentry *vfio_hisi_acc;
	struct device *dev = vdev->dev;

	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(*migf), 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)
{
	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;
@@ -1398,6 +1599,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:
@@ -1410,6 +1613,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);
}

+19 −0
Original line number Diff line number Diff line
@@ -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,13 @@ 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;
	/* Ensure the accuracy of dev_opened operation */
	struct mutex open_mutex;

	/* For migration state */
	struct mutex state_mutex;
@@ -107,9 +115,20 @@ struct hisi_acc_vf_core_device {
	struct pci_dev *vf_dev;
	struct hisi_qm *pf_qm;
	struct hisi_qm vf_qm;
	/*
	 * vf_qm_state represents the QM_VF_STATE register value.
	 * It is set by Guest driver for the ACC VF dev indicating
	 * the driver has loaded and configured the dev correctly.
	 */
	u32 vf_qm_state;
	int vf_id;
	struct hisi_acc_vf_migration_file *resuming_migf;
	struct hisi_acc_vf_migration_file *saving_migf;

	/*
	 * It holds migration data corresponding to the last migration
	 * and is used by the debugfs interface to report it.
	 */
	struct hisi_acc_vf_migration_file *debug_migf;
};
#endif /* HISI_ACC_VFIO_PCI_H */
+5 −1
Original line number Diff line number Diff line
@@ -423,6 +423,7 @@ static int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf,
	unsigned long filled;
	unsigned int to_fill;
	int ret;
	int i;

	to_fill = min_t(unsigned int, npages, PAGE_SIZE / sizeof(*page_list));
	page_list = kvzalloc(to_fill * sizeof(*page_list), GFP_KERNEL_ACCOUNT);
@@ -443,7 +444,7 @@ static int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf,
			GFP_KERNEL_ACCOUNT);

		if (ret)
			goto err;
			goto err_append;
		buf->allocated_length += filled * PAGE_SIZE;
		/* clean input for another bulk allocation */
		memset(page_list, 0, filled * sizeof(*page_list));
@@ -454,6 +455,9 @@ static int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf,
	kvfree(page_list);
	return 0;

err_append:
	for (i = filled - 1; i >= 0; i--)
		__free_page(page_list[i]);
err:
	kvfree(page_list);
	return ret;
+17 −18
Original line number Diff line number Diff line
@@ -640,14 +640,11 @@ mlx5vf_pci_save_device_data(struct mlx5vf_pci_core_device *mvdev, bool track)
					O_RDONLY);
	if (IS_ERR(migf->filp)) {
		ret = PTR_ERR(migf->filp);
		goto end;
		kfree(migf);
		return ERR_PTR(ret);
	}

	migf->mvdev = mvdev;
	ret = mlx5vf_cmd_alloc_pd(migf);
	if (ret)
		goto out_free;

	stream_open(migf->filp->f_inode, migf->filp);
	mutex_init(&migf->lock);
	init_waitqueue_head(&migf->poll_wait);
@@ -663,6 +660,11 @@ mlx5vf_pci_save_device_data(struct mlx5vf_pci_core_device *mvdev, bool track)
	INIT_LIST_HEAD(&migf->buf_list);
	INIT_LIST_HEAD(&migf->avail_list);
	spin_lock_init(&migf->list_lock);

	ret = mlx5vf_cmd_alloc_pd(migf);
	if (ret)
		goto out;

	ret = mlx5vf_cmd_query_vhca_migration_state(mvdev, &length, &full_size, 0);
	if (ret)
		goto out_pd;
@@ -692,10 +694,8 @@ mlx5vf_pci_save_device_data(struct mlx5vf_pci_core_device *mvdev, bool track)
	mlx5vf_free_data_buffer(buf);
out_pd:
	mlx5fv_cmd_clean_migf_resources(migf);
out_free:
out:
	fput(migf->filp);
end:
	kfree(migf);
	return ERR_PTR(ret);
}

@@ -1016,13 +1016,19 @@ mlx5vf_pci_resume_device_data(struct mlx5vf_pci_core_device *mvdev)
					O_WRONLY);
	if (IS_ERR(migf->filp)) {
		ret = PTR_ERR(migf->filp);
		goto end;
		kfree(migf);
		return ERR_PTR(ret);
	}

	stream_open(migf->filp->f_inode, migf->filp);
	mutex_init(&migf->lock);
	INIT_LIST_HEAD(&migf->buf_list);
	INIT_LIST_HEAD(&migf->avail_list);
	spin_lock_init(&migf->list_lock);
	migf->mvdev = mvdev;
	ret = mlx5vf_cmd_alloc_pd(migf);
	if (ret)
		goto out_free;
		goto out;

	buf = mlx5vf_alloc_data_buffer(migf, 0, DMA_TO_DEVICE);
	if (IS_ERR(buf)) {
@@ -1041,20 +1047,13 @@ mlx5vf_pci_resume_device_data(struct mlx5vf_pci_core_device *mvdev)
	migf->buf_header[0] = buf;
	migf->load_state = MLX5_VF_LOAD_STATE_READ_HEADER;

	stream_open(migf->filp->f_inode, migf->filp);
	mutex_init(&migf->lock);
	INIT_LIST_HEAD(&migf->buf_list);
	INIT_LIST_HEAD(&migf->avail_list);
	spin_lock_init(&migf->list_lock);
	return migf;
out_buf:
	mlx5vf_free_data_buffer(migf->buf[0]);
out_pd:
	mlx5vf_cmd_dealloc_pd(migf);
out_free:
out:
	fput(migf->filp);
end:
	kfree(migf);
	return ERR_PTR(ret);
}

Loading