Commit 49cf1b9b authored by Michał Winiarski's avatar Michał Winiarski
Browse files

drm/xe/pf: Handle VRAM migration data as part of PF control



Connect the helpers to allow save and restore of VRAM migration data in
stop_copy / resume device state.

Co-developed-by: default avatarLukasz Laguna <lukasz.laguna@intel.com>
Signed-off-by: default avatarLukasz Laguna <lukasz.laguna@intel.com>
Reviewed-by: default avatarMatthew Brost <matthew.brost@intel.com>
Link: https://patch.msgid.link/20251112132220.516975-23-michal.winiarski@intel.com


Signed-off-by: default avatarMichał Winiarski <michal.winiarski@intel.com>
parent 57a5f45b
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -892,6 +892,20 @@ static int pf_handle_vf_save_data(struct xe_gt *gt, unsigned int vfid)
		return -EAGAIN;
	}

	if (xe_gt_sriov_pf_migration_save_data_pending(gt, vfid,
						       XE_SRIOV_PACKET_TYPE_VRAM)) {
		ret = xe_gt_sriov_pf_migration_vram_save(gt, vfid);
		if (ret == -EAGAIN)
			return -EAGAIN;
		else if (ret)
			return ret;

		xe_gt_sriov_pf_migration_save_data_complete(gt, vfid,
							    XE_SRIOV_PACKET_TYPE_VRAM);

		return -EAGAIN;
	}

	return 0;
}

@@ -1130,6 +1144,9 @@ static int pf_handle_vf_restore_data(struct xe_gt *gt, unsigned int vfid)
	case XE_SRIOV_PACKET_TYPE_GUC:
		ret = xe_gt_sriov_pf_migration_guc_restore(gt, vfid, data);
		break;
	case XE_SRIOV_PACKET_TYPE_VRAM:
		ret = xe_gt_sriov_pf_migration_vram_restore(gt, vfid, data);
		break;
	default:
		xe_gt_sriov_notice(gt, "Skipping VF%u unknown data type: %d\n",
				   vfid, data->hdr.type);
+212 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "xe_gt_sriov_printk.h"
#include "xe_guc_buf.h"
#include "xe_guc_ct.h"
#include "xe_migrate.h"
#include "xe_mmio.h"
#include "xe_sriov.h"
#include "xe_sriov_packet.h"
@@ -505,6 +506,206 @@ int xe_gt_sriov_pf_migration_mmio_restore(struct xe_gt *gt, unsigned int vfid,
	return pf_restore_vf_mmio_mig_data(gt, vfid, data);
}

static ssize_t pf_migration_vram_size(struct xe_gt *gt, unsigned int vfid)
{
	if (!xe_gt_is_main_type(gt))
		return 0;

	return xe_gt_sriov_pf_config_get_lmem(gt, vfid);
}

static struct dma_fence *__pf_save_restore_vram(struct xe_gt *gt, unsigned int vfid,
						struct xe_bo *vram, u64 vram_offset,
						struct xe_bo *sysmem, u64 sysmem_offset,
						size_t size, bool save)
{
	struct dma_fence *ret = NULL;
	struct drm_exec exec;
	int err;

	drm_exec_init(&exec, 0, 0);
	drm_exec_until_all_locked(&exec) {
		err = drm_exec_lock_obj(&exec, &vram->ttm.base);
		drm_exec_retry_on_contention(&exec);
		if (err) {
			ret = ERR_PTR(err);
			goto err;
		}

		err = drm_exec_lock_obj(&exec, &sysmem->ttm.base);
		drm_exec_retry_on_contention(&exec);
		if (err) {
			ret = ERR_PTR(err);
			goto err;
		}
	}

	ret = xe_migrate_vram_copy_chunk(vram, vram_offset, sysmem, sysmem_offset, size,
					 save ? XE_MIGRATE_COPY_TO_SRAM : XE_MIGRATE_COPY_TO_VRAM);

err:
	drm_exec_fini(&exec);

	return ret;
}

#define PF_VRAM_SAVE_RESTORE_TIMEOUT (5 * HZ)
static int pf_save_vram_chunk(struct xe_gt *gt, unsigned int vfid,
			      struct xe_bo *src_vram, u64 src_vram_offset,
			      size_t size)
{
	struct xe_sriov_packet *data;
	struct dma_fence *fence;
	int ret;

	data = xe_sriov_packet_alloc(gt_to_xe(gt));
	if (!data)
		return -ENOMEM;

	ret = xe_sriov_packet_init(data, gt->tile->id, gt->info.id,
				   XE_SRIOV_PACKET_TYPE_VRAM, src_vram_offset,
				   size);
	if (ret)
		goto fail;

	fence = __pf_save_restore_vram(gt, vfid,
				       src_vram, src_vram_offset,
				       data->bo, 0, size, true);

	ret = dma_fence_wait_timeout(fence, false, PF_VRAM_SAVE_RESTORE_TIMEOUT);
	dma_fence_put(fence);
	if (!ret) {
		ret = -ETIME;
		goto fail;
	}

	pf_dump_mig_data(gt, vfid, data, "VRAM data save");

	ret = xe_gt_sriov_pf_migration_save_produce(gt, vfid, data);
	if (ret)
		goto fail;

	return 0;

fail:
	xe_sriov_packet_free(data);
	return ret;
}

#define VF_VRAM_STATE_CHUNK_MAX_SIZE SZ_512M
static int pf_save_vf_vram_mig_data(struct xe_gt *gt, unsigned int vfid)
{
	struct xe_gt_sriov_migration_data *migration = pf_pick_gt_migration(gt, vfid);
	loff_t *offset = &migration->save.vram_offset;
	struct xe_bo *vram;
	size_t vram_size, chunk_size;
	int ret;

	vram = xe_gt_sriov_pf_config_get_lmem_obj(gt, vfid);
	if (!vram)
		return -ENXIO;

	vram_size = xe_bo_size(vram);

	xe_gt_assert(gt, *offset < vram_size);

	chunk_size = min(vram_size - *offset, VF_VRAM_STATE_CHUNK_MAX_SIZE);

	ret = pf_save_vram_chunk(gt, vfid, vram, *offset, chunk_size);
	if (ret)
		goto fail;

	*offset += chunk_size;

	xe_bo_put(vram);

	if (*offset < vram_size)
		return -EAGAIN;

	return 0;

fail:
	xe_bo_put(vram);
	xe_gt_sriov_err(gt, "Failed to save VF%u VRAM data (%pe)\n", vfid, ERR_PTR(ret));
	return ret;
}

static int pf_restore_vf_vram_mig_data(struct xe_gt *gt, unsigned int vfid,
				       struct xe_sriov_packet *data)
{
	u64 end = data->hdr.offset + data->hdr.size;
	struct dma_fence *fence;
	struct xe_bo *vram;
	size_t size;
	int ret = 0;

	vram = xe_gt_sriov_pf_config_get_lmem_obj(gt, vfid);
	if (!vram)
		return -ENXIO;

	size = xe_bo_size(vram);

	if (end > size || end < data->hdr.size) {
		ret = -EINVAL;
		goto err;
	}

	pf_dump_mig_data(gt, vfid, data, "VRAM data restore");

	fence = __pf_save_restore_vram(gt, vfid, vram, data->hdr.offset,
				       data->bo, 0, data->hdr.size, false);
	ret = dma_fence_wait_timeout(fence, false, PF_VRAM_SAVE_RESTORE_TIMEOUT);
	dma_fence_put(fence);
	if (!ret) {
		ret = -ETIME;
		goto err;
	}

	return 0;
err:
	xe_bo_put(vram);
	xe_gt_sriov_err(gt, "Failed to restore VF%u VRAM data (%pe)\n", vfid, ERR_PTR(ret));
	return ret;
}

/**
 * xe_gt_sriov_pf_migration_vram_save() - Save VF VRAM migration data.
 * @gt: the &xe_gt
 * @vfid: the VF identifier (can't be 0)
 *
 * This function is for PF only.
 *
 * Return: 0 on success or a negative error code on failure.
 */
int xe_gt_sriov_pf_migration_vram_save(struct xe_gt *gt, unsigned int vfid)
{
	xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
	xe_gt_assert(gt, vfid != PFID);
	xe_gt_assert(gt, vfid <= xe_sriov_pf_get_totalvfs(gt_to_xe(gt)));

	return pf_save_vf_vram_mig_data(gt, vfid);
}

/**
 * xe_gt_sriov_pf_migration_vram_restore() - Restore VF VRAM migration data.
 * @gt: the &xe_gt
 * @vfid: the VF identifier (can't be 0)
 * @data: the &xe_sriov_packet containing migration data
 *
 * This function is for PF only.
 *
 * Return: 0 on success or a negative error code on failure.
 */
int xe_gt_sriov_pf_migration_vram_restore(struct xe_gt *gt, unsigned int vfid,
					  struct xe_sriov_packet *data)
{
	xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
	xe_gt_assert(gt, vfid != PFID);
	xe_gt_assert(gt, vfid <= xe_sriov_pf_get_totalvfs(gt_to_xe(gt)));

	return pf_restore_vf_vram_mig_data(gt, vfid, data);
}

/**
 * xe_gt_sriov_pf_migration_size() - Total size of migration data from all components within a GT.
 * @gt: the &xe_gt
@@ -544,6 +745,13 @@ ssize_t xe_gt_sriov_pf_migration_size(struct xe_gt *gt, unsigned int vfid)
		size += sizeof(struct xe_sriov_packet_hdr);
	total += size;

	size = pf_migration_vram_size(gt, vfid);
	if (size < 0)
		return size;
	if (size > 0)
		size += sizeof(struct xe_sriov_packet_hdr);
	total += size;

	return total;
}

@@ -606,6 +814,7 @@ void xe_gt_sriov_pf_migration_save_init(struct xe_gt *gt, unsigned int vfid)
	struct xe_gt_sriov_migration_data *migration = pf_pick_gt_migration(gt, vfid);

	migration->save.data_remaining = 0;
	migration->save.vram_offset = 0;

	xe_gt_assert(gt, pf_migration_guc_size(gt, vfid) > 0);
	pf_migration_save_data_todo(gt, vfid, XE_SRIOV_PACKET_TYPE_GUC);
@@ -615,6 +824,9 @@ void xe_gt_sriov_pf_migration_save_init(struct xe_gt *gt, unsigned int vfid)

	xe_gt_assert(gt, pf_migration_mmio_size(gt, vfid) > 0);
	pf_migration_save_data_todo(gt, vfid, XE_SRIOV_PACKET_TYPE_MMIO);

	if (pf_migration_vram_size(gt, vfid) > 0)
		pf_migration_save_data_todo(gt, vfid, XE_SRIOV_PACKET_TYPE_VRAM);
}

/**
+3 −0
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@ int xe_gt_sriov_pf_migration_ggtt_restore(struct xe_gt *gt, unsigned int vfid,
int xe_gt_sriov_pf_migration_mmio_save(struct xe_gt *gt, unsigned int vfid);
int xe_gt_sriov_pf_migration_mmio_restore(struct xe_gt *gt, unsigned int vfid,
					  struct xe_sriov_packet *data);
int xe_gt_sriov_pf_migration_vram_save(struct xe_gt *gt, unsigned int vfid);
int xe_gt_sriov_pf_migration_vram_restore(struct xe_gt *gt, unsigned int vfid,
					  struct xe_sriov_packet *data);

ssize_t xe_gt_sriov_pf_migration_size(struct xe_gt *gt, unsigned int vfid);

+2 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ struct xe_gt_sriov_migration_data {
	struct {
		/** @save.data_remaining: bitmap of migration types that need to be saved */
		unsigned long data_remaining;
		/** @save.vram_offset: last saved offset within VRAM, used for chunked VRAM save */
		loff_t vram_offset;
	} save;
};

+3 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@

#include "xe_device.h"
#include "xe_gt_sriov_pf_control.h"
#include "xe_gt_sriov_pf_migration.h"
#include "xe_sriov_packet.h"
#include "xe_sriov_pf_control.h"
#include "xe_sriov_printk.h"
@@ -171,6 +172,8 @@ int xe_sriov_pf_control_trigger_save_vf(struct xe_device *xe, unsigned int vfid)
		return ret;

	for_each_gt(gt, xe, id) {
		xe_gt_sriov_pf_migration_save_init(gt, vfid);

		ret = xe_gt_sriov_pf_control_trigger_save_vf(gt, vfid);
		if (ret)
			return ret;