Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6af5d670 authored by Jani Nikula's avatar Jani Nikula
Browse files

Merge tag 'gvt-next-2017-09-08' of https://github.com/01org/gvt-linux into drm-intel-next-queued



gvt-next-2017-09-08

- PCI config sanitize series (Changbin)
- Workload submission error handling series (Fred)

Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20170908063155.l54lvpivxntjm7hq@zhen-hp.sh.intel.com
parents 212154ba 02d578e5
Loading
Loading
Loading
Loading
+70 −73
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset,
	if (WARN_ON(bytes > 4))
		return -EINVAL;

	if (WARN_ON(offset + bytes > INTEL_GVT_MAX_CFG_SPACE_SZ))
	if (WARN_ON(offset + bytes > vgpu->gvt->device_info.cfg_space_size))
		return -EINVAL;

	memcpy(p_data, vgpu_cfg_space(vgpu) + offset, bytes);
@@ -110,13 +110,25 @@ int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset,

static int map_aperture(struct intel_vgpu *vgpu, bool map)
{
	u64 first_gfn, first_mfn;
	phys_addr_t aperture_pa = vgpu_aperture_pa_base(vgpu);
	unsigned long aperture_sz = vgpu_aperture_sz(vgpu);
	u64 first_gfn;
	u64 val;
	int ret;

	if (map == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked)
		return 0;

	if (map) {
		vgpu->gm.aperture_va = memremap(aperture_pa, aperture_sz,
						MEMREMAP_WC);
		if (!vgpu->gm.aperture_va)
			return -ENOMEM;
	} else {
		memunmap(vgpu->gm.aperture_va);
		vgpu->gm.aperture_va = NULL;
	}

	val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_2];
	if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
		val = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2);
@@ -124,14 +136,16 @@ static int map_aperture(struct intel_vgpu *vgpu, bool map)
		val = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2);

	first_gfn = (val + vgpu_aperture_offset(vgpu)) >> PAGE_SHIFT;
	first_mfn = vgpu_aperture_pa_base(vgpu) >> PAGE_SHIFT;

	ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu, first_gfn,
						  first_mfn,
						  vgpu_aperture_sz(vgpu) >>
						  PAGE_SHIFT, map);
	if (ret)
						  aperture_pa >> PAGE_SHIFT,
						  aperture_sz >> PAGE_SHIFT,
						  map);
	if (ret) {
		memunmap(vgpu->gm.aperture_va);
		vgpu->gm.aperture_va = NULL;
		return ret;
	}

	vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked = map;
	return 0;
@@ -197,19 +211,14 @@ static int emulate_pci_command_write(struct intel_vgpu *vgpu,
static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
	void *p_data, unsigned int bytes)
{
	unsigned int bar_index =
		(rounddown(offset, 8) % PCI_BASE_ADDRESS_0) / 8;
	u32 new = *(u32 *)(p_data);
	bool lo = IS_ALIGNED(offset, 8);
	u64 size;
	int ret = 0;
	bool mmio_enabled =
		vgpu_cfg_space(vgpu)[PCI_COMMAND] & PCI_COMMAND_MEMORY;
	struct intel_vgpu_pci_bar *bars = vgpu->cfg_space.bar;

	if (WARN_ON(bar_index >= INTEL_GVT_PCI_BAR_MAX))
		return -EINVAL;

	if (new == 0xffffffff) {
	/*
	 * Power-up software can determine how much address
	 * space the device requires by writing a value of
@@ -217,58 +226,50 @@ static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
	 * back. The device will return 0's in all don't-care
	 * address bits.
	 */
		size = vgpu->cfg_space.bar[bar_index].size;
		if (lo) {
			new = rounddown(new, size);
		} else {
			u32 val = vgpu_cfg_space(vgpu)[rounddown(offset, 8)];
			/* for 32bit mode bar it returns all-0 in upper 32
			 * bit, for 64bit mode bar it will calculate the
			 * size with lower 32bit and return the corresponding
			 * value
			 */
			if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
				new &= (~(size-1)) >> 32;
			else
				new = 0;
		}
	if (new == 0xffffffff) {
		switch (offset) {
		case PCI_BASE_ADDRESS_0:
		case PCI_BASE_ADDRESS_1:
			size = ~(bars[INTEL_GVT_PCI_BAR_GTTMMIO].size -1);
			intel_vgpu_write_pci_bar(vgpu, offset,
						size >> (lo ? 0 : 32), lo);
			/*
		 * Unmapp & untrap the BAR, since guest hasn't configured a
			 * Untrap the BAR, since guest hasn't configured a
			 * valid GPA
			 */
		switch (bar_index) {
		case INTEL_GVT_PCI_BAR_GTTMMIO:
			ret = trap_gttmmio(vgpu, false);
			break;
		case INTEL_GVT_PCI_BAR_APERTURE:
		case PCI_BASE_ADDRESS_2:
		case PCI_BASE_ADDRESS_3:
			size = ~(bars[INTEL_GVT_PCI_BAR_APERTURE].size -1);
			intel_vgpu_write_pci_bar(vgpu, offset,
						size >> (lo ? 0 : 32), lo);
			ret = map_aperture(vgpu, false);
			break;
		default:
			/* Unimplemented BARs */
			intel_vgpu_write_pci_bar(vgpu, offset, 0x0, false);
		}
		intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
	} else {
		switch (offset) {
		case PCI_BASE_ADDRESS_0:
		case PCI_BASE_ADDRESS_1:
			/*
		 * Unmapp & untrap the old BAR first, since guest has
			 * Untrap the old BAR first, since guest has
			 * re-configured the BAR
			 */
		switch (bar_index) {
		case INTEL_GVT_PCI_BAR_GTTMMIO:
			ret = trap_gttmmio(vgpu, false);
			break;
		case INTEL_GVT_PCI_BAR_APERTURE:
			ret = map_aperture(vgpu, false);
			break;
		}
			trap_gttmmio(vgpu, false);
			intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
		/* Track the new BAR */
		if (mmio_enabled) {
			switch (bar_index) {
			case INTEL_GVT_PCI_BAR_GTTMMIO:
				ret = trap_gttmmio(vgpu, true);
			ret = trap_gttmmio(vgpu, mmio_enabled);
			break;
			case INTEL_GVT_PCI_BAR_APERTURE:
				ret = map_aperture(vgpu, true);
		case PCI_BASE_ADDRESS_2:
		case PCI_BASE_ADDRESS_3:
			map_aperture(vgpu, false);
			intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
			ret = map_aperture(vgpu, mmio_enabled);
			break;
			}
		default:
			intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
		}
	}
	return ret;
@@ -288,7 +289,7 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
	if (WARN_ON(bytes > 4))
		return -EINVAL;

	if (WARN_ON(offset + bytes > INTEL_GVT_MAX_CFG_SPACE_SZ))
	if (WARN_ON(offset + bytes > vgpu->gvt->device_info.cfg_space_size))
		return -EINVAL;

	/* First check if it's PCI_COMMAND */
@@ -299,10 +300,7 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
	}

	switch (rounddown(offset, 4)) {
	case PCI_BASE_ADDRESS_0:
	case PCI_BASE_ADDRESS_1:
	case PCI_BASE_ADDRESS_2:
	case PCI_BASE_ADDRESS_3:
	case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5:
		if (WARN_ON(!IS_ALIGNED(offset, 4)))
			return -EINVAL;
		return emulate_pci_bar_write(vgpu, offset, p_data, bytes);
@@ -344,7 +342,6 @@ void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
	struct intel_gvt *gvt = vgpu->gvt;
	const struct intel_gvt_device_info *info = &gvt->device_info;
	u16 *gmch_ctl;
	int i;

	memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space,
	       info->cfg_space_size);
@@ -371,13 +368,13 @@ void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
	 */
	memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4);
	memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4);
	memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_4, 0, 8);
	memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4);

	for (i = 0; i < INTEL_GVT_MAX_BAR_NUM; i++) {
		vgpu->cfg_space.bar[i].size = pci_resource_len(
					      gvt->dev_priv->drm.pdev, i * 2);
		vgpu->cfg_space.bar[i].tracked = false;
	}
	vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size =
				pci_resource_len(gvt->dev_priv->drm.pdev, 0);
	vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].size =
				pci_resource_len(gvt->dev_priv->drm.pdev, 2);
}

/**
+24 −13
Original line number Diff line number Diff line
@@ -1576,11 +1576,11 @@ static int batch_buffer_needs_scan(struct parser_exec_state *s)
	return 1;
}

static uint32_t find_bb_size(struct parser_exec_state *s)
static int find_bb_size(struct parser_exec_state *s)
{
	unsigned long gma = 0;
	struct cmd_info *info;
	uint32_t bb_size = 0;
	int bb_size = 0;
	uint32_t cmd_len = 0;
	bool met_bb_end = false;
	struct intel_vgpu *vgpu = s->vgpu;
@@ -1637,6 +1637,8 @@ static int perform_bb_shadow(struct parser_exec_state *s)

	/* get the size of the batch buffer */
	bb_size = find_bb_size(s);
	if (bb_size < 0)
		return -EINVAL;

	/* allocate shadow batch buffer */
	entry_obj = kmalloc(sizeof(*entry_obj), GFP_KERNEL);
@@ -2603,7 +2605,8 @@ static int shadow_workload_ring_buffer(struct intel_vgpu_workload *workload)
{
	struct intel_vgpu *vgpu = workload->vgpu;
	unsigned long gma_head, gma_tail, gma_top, guest_rb_size;
	u32 *cs;
	void *shadow_ring_buffer_va;
	int ring_id = workload->ring_id;
	int ret;

	guest_rb_size = _RING_CTL_BUF_SIZE(workload->rb_ctl);
@@ -2616,34 +2619,42 @@ static int shadow_workload_ring_buffer(struct intel_vgpu_workload *workload)
	gma_tail = workload->rb_start + workload->rb_tail;
	gma_top = workload->rb_start + guest_rb_size;

	/* allocate shadow ring buffer */
	cs = intel_ring_begin(workload->req, workload->rb_len / sizeof(u32));
	if (IS_ERR(cs))
		return PTR_ERR(cs);
	if (workload->rb_len > vgpu->reserve_ring_buffer_size[ring_id]) {
		void *va = vgpu->reserve_ring_buffer_va[ring_id];
		/* realloc the new ring buffer if needed */
		vgpu->reserve_ring_buffer_va[ring_id] =
			krealloc(va, workload->rb_len, GFP_KERNEL);
		if (!vgpu->reserve_ring_buffer_va[ring_id]) {
			gvt_vgpu_err("fail to alloc reserve ring buffer\n");
			return -ENOMEM;
		}
		vgpu->reserve_ring_buffer_size[ring_id] = workload->rb_len;
	}

	shadow_ring_buffer_va = vgpu->reserve_ring_buffer_va[ring_id];

	/* get shadow ring buffer va */
	workload->shadow_ring_buffer_va = cs;
	workload->shadow_ring_buffer_va = shadow_ring_buffer_va;

	/* head > tail --> copy head <-> top */
	if (gma_head > gma_tail) {
		ret = copy_gma_to_hva(vgpu, vgpu->gtt.ggtt_mm,
				      gma_head, gma_top, cs);
				      gma_head, gma_top, shadow_ring_buffer_va);
		if (ret < 0) {
			gvt_vgpu_err("fail to copy guest ring buffer\n");
			return ret;
		}
		cs += ret / sizeof(u32);
		shadow_ring_buffer_va += ret;
		gma_head = workload->rb_start;
	}

	/* copy head or start <-> tail */
	ret = copy_gma_to_hva(vgpu, vgpu->gtt.ggtt_mm, gma_head, gma_tail, cs);
	ret = copy_gma_to_hva(vgpu, vgpu->gtt.ggtt_mm, gma_head, gma_tail,
				shadow_ring_buffer_va);
	if (ret < 0) {
		gvt_vgpu_err("fail to copy guest ring buffer\n");
		return ret;
	}
	cs += ret / sizeof(u32);
	intel_ring_advance(workload->req, cs);
	return 0;
}

+95 −32
Original line number Diff line number Diff line
@@ -368,7 +368,7 @@ static void free_workload(struct intel_vgpu_workload *workload)
#define get_desc_from_elsp_dwords(ed, i) \
	((struct execlist_ctx_descriptor_format *)&((ed)->data[i * 2]))

static void prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
{
	const int gmadr_bytes = workload->vgpu->gvt->device_info.gmadr_bytes_in_cmd;
	struct intel_shadow_bb_entry *entry_obj;
@@ -379,7 +379,7 @@ static void prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)

		vma = i915_gem_object_ggtt_pin(entry_obj->obj, NULL, 0, 4, 0);
		if (IS_ERR(vma)) {
			return;
			return PTR_ERR(vma);
		}

		/* FIXME: we are not tracking our pinned VMA leaving it
@@ -392,6 +392,7 @@ static void prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
		if (gmadr_bytes == 8)
			entry_obj->bb_start_cmd_va[2] = 0;
	}
	return 0;
}

static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx)
@@ -420,7 +421,7 @@ static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx)
	return 0;
}

static void prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
static int prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
{
	struct i915_vma *vma;
	unsigned char *per_ctx_va =
@@ -428,12 +429,12 @@ static void prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
		wa_ctx->indirect_ctx.size;

	if (wa_ctx->indirect_ctx.size == 0)
		return;
		return 0;

	vma = i915_gem_object_ggtt_pin(wa_ctx->indirect_ctx.obj, NULL,
				       0, CACHELINE_BYTES, 0);
	if (IS_ERR(vma)) {
		return;
		return PTR_ERR(vma);
	}

	/* FIXME: we are not tracking our pinned VMA leaving it
@@ -447,26 +448,7 @@ static void prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
	memset(per_ctx_va, 0, CACHELINE_BYTES);

	update_wa_ctx_2_shadow_ctx(wa_ctx);
}

static int prepare_execlist_workload(struct intel_vgpu_workload *workload)
{
	struct intel_vgpu *vgpu = workload->vgpu;
	struct execlist_ctx_descriptor_format ctx[2];
	int ring_id = workload->ring_id;

	intel_vgpu_pin_mm(workload->shadow_mm);
	intel_vgpu_sync_oos_pages(workload->vgpu);
	intel_vgpu_flush_post_shadow(workload->vgpu);
	prepare_shadow_batch_buffer(workload);
	prepare_shadow_wa_ctx(&workload->wa_ctx);
	if (!workload->emulate_schedule_in)
	return 0;

	ctx[0] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 1);
	ctx[1] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 0);

	return emulate_execlist_schedule_in(&vgpu->execlist[ring_id], ctx);
}

static void release_shadow_batch_buffer(struct intel_vgpu_workload *workload)
@@ -489,13 +471,62 @@ static void release_shadow_batch_buffer(struct intel_vgpu_workload *workload)
	}
}

static void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
static int prepare_execlist_workload(struct intel_vgpu_workload *workload)
{
	if (!wa_ctx->indirect_ctx.obj)
		return;
	struct intel_vgpu *vgpu = workload->vgpu;
	struct execlist_ctx_descriptor_format ctx[2];
	int ring_id = workload->ring_id;
	int ret;

	ret = intel_vgpu_pin_mm(workload->shadow_mm);
	if (ret) {
		gvt_vgpu_err("fail to vgpu pin mm\n");
		goto out;
	}

	ret = intel_vgpu_sync_oos_pages(workload->vgpu);
	if (ret) {
		gvt_vgpu_err("fail to vgpu sync oos pages\n");
		goto err_unpin_mm;
	}

	ret = intel_vgpu_flush_post_shadow(workload->vgpu);
	if (ret) {
		gvt_vgpu_err("fail to flush post shadow\n");
		goto err_unpin_mm;
	}

	ret = prepare_shadow_batch_buffer(workload);
	if (ret) {
		gvt_vgpu_err("fail to prepare_shadow_batch_buffer\n");
		goto err_unpin_mm;
	}

	ret = prepare_shadow_wa_ctx(&workload->wa_ctx);
	if (ret) {
		gvt_vgpu_err("fail to prepare_shadow_wa_ctx\n");
		goto err_shadow_batch;
	}

	if (!workload->emulate_schedule_in)
		return 0;

	ctx[0] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 1);
	ctx[1] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 0);

	i915_gem_object_unpin_map(wa_ctx->indirect_ctx.obj);
	i915_gem_object_put(wa_ctx->indirect_ctx.obj);
	ret = emulate_execlist_schedule_in(&vgpu->execlist[ring_id], ctx);
	if (!ret)
		goto out;
	else
		gvt_vgpu_err("fail to emulate execlist schedule in\n");

	release_shadow_wa_ctx(&workload->wa_ctx);
err_shadow_batch:
	release_shadow_batch_buffer(workload);
err_unpin_mm:
	intel_vgpu_unpin_mm(workload->shadow_mm);
out:
	return ret;
}

static int complete_execlist_workload(struct intel_vgpu_workload *workload)
@@ -511,8 +542,10 @@ static int complete_execlist_workload(struct intel_vgpu_workload *workload)
	gvt_dbg_el("complete workload %p status %d\n", workload,
			workload->status);

	if (!workload->status) {
		release_shadow_batch_buffer(workload);
		release_shadow_wa_ctx(&workload->wa_ctx);
	}

	if (workload->status || (vgpu->resetting_eng & ENGINE_MASK(ring_id))) {
		/* if workload->status is not successful means HW GPU
@@ -820,10 +853,21 @@ static void clean_workloads(struct intel_vgpu *vgpu, unsigned long engine_mask)

void intel_vgpu_clean_execlist(struct intel_vgpu *vgpu)
{
	enum intel_engine_id i;
	struct intel_engine_cs *engine;

	clean_workloads(vgpu, ALL_ENGINES);
	kmem_cache_destroy(vgpu->workloads);

	for_each_engine(engine, vgpu->gvt->dev_priv, i) {
		kfree(vgpu->reserve_ring_buffer_va[i]);
		vgpu->reserve_ring_buffer_va[i] = NULL;
		vgpu->reserve_ring_buffer_size[i] = 0;
	}

}

#define RESERVE_RING_BUFFER_SIZE		((1 * PAGE_SIZE)/8)
int intel_vgpu_init_execlist(struct intel_vgpu *vgpu)
{
	enum intel_engine_id i;
@@ -843,7 +887,26 @@ int intel_vgpu_init_execlist(struct intel_vgpu *vgpu)
	if (!vgpu->workloads)
		return -ENOMEM;

	/* each ring has a shadow ring buffer until vgpu destroyed */
	for_each_engine(engine, vgpu->gvt->dev_priv, i) {
		vgpu->reserve_ring_buffer_va[i] =
			kmalloc(RESERVE_RING_BUFFER_SIZE, GFP_KERNEL);
		if (!vgpu->reserve_ring_buffer_va[i]) {
			gvt_vgpu_err("fail to alloc reserve ring buffer\n");
			goto out;
		}
		vgpu->reserve_ring_buffer_size[i] = RESERVE_RING_BUFFER_SIZE;
	}
	return 0;
out:
	for_each_engine(engine, vgpu->gvt->dev_priv, i) {
		if (vgpu->reserve_ring_buffer_size[i]) {
			kfree(vgpu->reserve_ring_buffer_va[i]);
			vgpu->reserve_ring_buffer_va[i] = NULL;
			vgpu->reserve_ring_buffer_size[i] = 0;
		}
	}
	return -ENOMEM;
}

void intel_vgpu_reset_execlist(struct intel_vgpu *vgpu,
+1 −2
Original line number Diff line number Diff line
@@ -1647,14 +1647,13 @@ int intel_vgpu_pin_mm(struct intel_vgpu_mm *mm)
	if (WARN_ON(mm->type != INTEL_GVT_MM_PPGTT))
		return 0;

	atomic_inc(&mm->pincount);

	if (!mm->shadowed) {
		ret = shadow_mm(mm);
		if (ret)
			return ret;
	}

	atomic_inc(&mm->pincount);
	list_del_init(&mm->lru_list);
	list_add_tail(&mm->lru_list, &mm->vgpu->gvt->gtt.mm_lru_list_head);
	return 0;
+1 −1
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ static void init_device_info(struct intel_gvt *gvt)
	if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv)
		|| IS_KABYLAKE(gvt->dev_priv)) {
		info->max_support_vgpus = 8;
		info->cfg_space_size = 256;
		info->cfg_space_size = PCI_CFG_SPACE_EXP_SIZE;
		info->mmio_size = 2 * 1024 * 1024;
		info->mmio_bar = 0;
		info->gtt_start_offset = 8 * 1024 * 1024;
Loading