[PATCH 1/6] drm/i915/gvt: Optimize MMIO register handling for some large MMIO blocks

Zhenyu Wang zhenyuw at linux.intel.com
Mon Jun 5 04:39:50 UTC 2017


On 2017.06.02 14:03:46 +0800, changbin.du at intel.com wrote:
> From: Changbin Du <changbin.du at intel.com>
> 
> Some of traced MMIO registers are a large continuous section. These
> stuffed the MMIO lookup hash table and so waste lots of memory and
> get much lower lookup performance.
> 
> Here we picked out these sections by special handling. These sections
> include:
>   o Display pipe registers, total 768.
>   o The PVINFO page, total 1024.
>   o MCHBAR_MIRROR, total 65536.
>   o CSR_MMIO, total 3072.
> 
> So we removed 70,400 items from the hash table, and speed up guest
> boot time by ~500ms.
>
> Signed-off-by: Changbin Du <changbin.du at intel.com>

> +/* Special MMIO blocks. */
> +static struct gvt_mmio_block {
> +	unsigned int device;
> +	i915_reg_t   offset;
> +	unsigned int size;
> +	gvt_mmio_func read;
> +	gvt_mmio_func write;
> +} gvt_mmio_blocks[] = {
> +	{D_SKL_PLUS, _MMIO(CSR_MMIO_START_RANGE), 0x3000, NULL, NULL},
> +	{D_ALL, _MMIO(MCHBAR_MIRROR_BASE_SNB), 0x40000, NULL, NULL},
> +	{D_ALL, _MMIO(VGT_PVINFO_PAGE), VGT_PVINFO_SIZE,
> +		pvinfo_mmio_read, pvinfo_mmio_write},
> +	{D_ALL, LGC_PALETTE(PIPE_A, 0), 1024, NULL, NULL},
> +	{D_ALL, LGC_PALETTE(PIPE_B, 0), 1024, NULL, NULL},
> +	{D_ALL, LGC_PALETTE(PIPE_C, 0), 1024, NULL, NULL},
> +};
>  
>  /**
>   * intel_gvt_clean_mmio_info - clean up MMIO information table for GVT device
> @@ -3059,3 +3055,102 @@ bool intel_gvt_in_force_nonpriv_whitelist(struct intel_gvt *gvt,
>  {
>  	return in_whitelist(offset);
>  }
> +
> +#define IS_IN_RANGE(addr, start, size)	(addr >= start && addr < start + size)

Move this along with mmio_block for its purpose, might rename like IN_MMIO_BLOCK()

> +
> +/**
> + * intel_vgpu_mmio_reg_access - emulate tracked mmio registers
> + * @vgpu: a vGPU
> + * @offset: access offset
> + * @pdata: access data buffer
> + * @bytes: access data length
> + *

Fix above comment.

> + * Returns:
> + * Zero on success, negative error code if failed.
> + */
> +int intel_vgpu_mmio_reg_rw(struct intel_vgpu *vgpu, unsigned int offset,
> +			   void *pdata, unsigned int bytes, bool is_read)
> +{
> +	struct intel_gvt *gvt = vgpu->gvt;
> +	struct intel_gvt_mmio_info *mmio;
> +	unsigned long device = intel_gvt_get_device_type(gvt);
> +	gvt_mmio_func func;
> +	int i, ret;
> +
> +	if (WARN_ON(bytes > 4))
> +		return -EINVAL;
> +
> +	/*
> +	 * Handle special MMIO blocks.
> +	 */
> +	for (i = 0; i < ARRAY_SIZE(gvt_mmio_blocks); i++) {
> +		struct gvt_mmio_block *block = &gvt_mmio_blocks[i];
> +
> +		if (!(device & block->device))
> +			continue;
> +		if (IS_IN_RANGE(offset, INTEL_GVT_MMIO_OFFSET(block->offset),
> +		    block->size)) {
> +			func = is_read ? block->read : block->write;
> +			if (func)
> +				return func(vgpu, offset, pdata, bytes);
> +			goto default_rw;
> +		}
> +	}
> +
> +	/*
> +	 * Normal tracked MMIOs.
> +	 */
> +	mmio = find_mmio_info(gvt, offset);
> +	if (!mmio) {
> +		if (!vgpu->mmio.disable_warn_untrack)
> +			gvt_vgpu_err("untracked MMIO %08x len %d\n",
> +				     offset, bytes);
> +		goto default_rw;
> +	}
> +
> +	if (WARN_ON(bytes > mmio->size))
> +		return -EINVAL;
> +
> +	if (is_read)
> +		return mmio->read(vgpu, offset, pdata, bytes);
> +	else {
> +		u64 ro_mask = mmio->ro_mask;
> +		u32 old_vreg = 0, old_sreg = 0;
> +		u64 data = 0;
> +
> +		if (intel_gvt_mmio_has_mode_mask(gvt, mmio->offset)) {
> +			old_vreg = vgpu_vreg(vgpu, offset);
> +			old_sreg = vgpu_sreg(vgpu, offset);
> +		}
> +
> +		if (likely(!ro_mask))
> +			ret = mmio->write(vgpu, offset, pdata, bytes);
> +		else if (!~ro_mask) {
> +			gvt_vgpu_err("try to write RO reg %x\n", offset);
> +			return 0;
> +		} else {
> +			/* keep the RO bits in the virtual register */
> +			memcpy(&data, pdata, bytes);
> +			data &= ~ro_mask;
> +			data |= vgpu_vreg(vgpu, offset) & ro_mask;
> +			ret = mmio->write(vgpu, offset, &data, bytes);
> +		}
> +
> +		/* higher 16bits of mode ctl regs are mask bits for change */
> +		if (intel_gvt_mmio_has_mode_mask(gvt, mmio->offset)) {
> +			u32 mask = vgpu_vreg(vgpu, offset) >> 16;
> +
> +			vgpu_vreg(vgpu, offset) = (old_vreg & ~mask)
> +					| (vgpu_vreg(vgpu, offset) & mask);
> +			vgpu_sreg(vgpu, offset) = (old_sreg & ~mask)
> +					| (vgpu_sreg(vgpu, offset) & mask);
> +		}
> +	}
> +
> +	return ret;
> +
> +default_rw:
> +	return is_read ?
> +		intel_vgpu_default_mmio_read(vgpu, offset, pdata, bytes) :
> +		intel_vgpu_default_mmio_write(vgpu, offset, pdata, bytes);
> +}
> diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c
> index 9337cac..980ec89 100644
> --- a/drivers/gpu/drm/i915/gvt/mmio.c
> +++ b/drivers/gpu/drm/i915/gvt/mmio.c
> @@ -123,7 +123,6 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa,
>  		void *p_data, unsigned int bytes)
>  {
>  	struct intel_gvt *gvt = vgpu->gvt;
> -	struct intel_gvt_mmio_info *mmio;
>  	unsigned int offset = 0;
>  	int ret = -EINVAL;
>  
> @@ -187,25 +186,8 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa,
>  			goto err;
>  	}
>  
> -	mmio = intel_gvt_find_mmio_info(gvt, rounddown(offset, 4));
> -	if (mmio) {
> -		if (!intel_gvt_mmio_is_unalign(gvt, mmio->offset)) {
> -			if (WARN_ON(offset + bytes > mmio->offset + mmio->size))
> -				goto err;
> -			if (WARN_ON(mmio->offset != offset))
> -				goto err;
> -		}
> -		ret = mmio->read(vgpu, offset, p_data, bytes);
> -	} else {
> -		ret = intel_vgpu_default_mmio_read(vgpu, offset, p_data, bytes);
> -
> -		if (!vgpu->mmio.disable_warn_untrack) {
> -			gvt_vgpu_err("read untracked MMIO %x(%dB) val %x\n",
> -				offset, bytes, *(u32 *)p_data);
> -		}
> -	}
> -
> -	if (ret)
> +	ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, true);
> +	if (ret < 0)
>  		goto err;
>  
>  	intel_gvt_mmio_set_accessed(gvt, offset);
> @@ -232,9 +214,7 @@ int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, uint64_t pa,
>  		void *p_data, unsigned int bytes)
>  {
>  	struct intel_gvt *gvt = vgpu->gvt;
> -	struct intel_gvt_mmio_info *mmio;
>  	unsigned int offset = 0;
> -	u32 old_vreg = 0, old_sreg = 0;
>  	int ret = -EINVAL;
>  
>  	if (vgpu->failsafe) {
> @@ -289,66 +269,10 @@ int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, uint64_t pa,
>  		return ret;
>  	}
>  
> -	mmio = intel_gvt_find_mmio_info(gvt, rounddown(offset, 4));
> -	if (!mmio && !vgpu->mmio.disable_warn_untrack)
> -		gvt_dbg_mmio("vgpu%d: write untracked MMIO %x len %d val %x\n",
> -				vgpu->id, offset, bytes, *(u32 *)p_data);
> -
> -	if (!intel_gvt_mmio_is_unalign(gvt, offset)) {
> -		if (WARN_ON(!IS_ALIGNED(offset, bytes)))
> -			goto err;
> -	}
> -
> -	if (mmio) {
> -		u64 ro_mask = mmio->ro_mask;
> -
> -		if (!intel_gvt_mmio_is_unalign(gvt, mmio->offset)) {
> -			if (WARN_ON(offset + bytes > mmio->offset + mmio->size))
> -				goto err;
> -			if (WARN_ON(mmio->offset != offset))
> -				goto err;
> -		}
> -
> -		if (intel_gvt_mmio_has_mode_mask(gvt, mmio->offset)) {
> -			old_vreg = vgpu_vreg(vgpu, offset);
> -			old_sreg = vgpu_sreg(vgpu, offset);
> -		}
> -
> -		if (!ro_mask) {
> -			ret = mmio->write(vgpu, offset, p_data, bytes);
> -		} else {
> -			/* Protect RO bits like HW */
> -			u64 data = 0;
> -
> -			/* all register bits are RO. */
> -			if (ro_mask == ~(u64)0) {
> -				gvt_vgpu_err("try to write RO reg %x\n",
> -					offset);
> -				ret = 0;
> -				goto out;
> -			}
> -			/* keep the RO bits in the virtual register */
> -			memcpy(&data, p_data, bytes);
> -			data &= ~mmio->ro_mask;
> -			data |= vgpu_vreg(vgpu, offset) & mmio->ro_mask;
> -			ret = mmio->write(vgpu, offset, &data, bytes);
> -		}
> -
> -		/* higher 16bits of mode ctl regs are mask bits for change */
> -		if (intel_gvt_mmio_has_mode_mask(gvt, mmio->offset)) {
> -			u32 mask = vgpu_vreg(vgpu, offset) >> 16;
> -
> -			vgpu_vreg(vgpu, offset) = (old_vreg & ~mask)
> -				| (vgpu_vreg(vgpu, offset) & mask);
> -			vgpu_sreg(vgpu, offset) = (old_sreg & ~mask)
> -				| (vgpu_sreg(vgpu, offset) & mask);
> -		}
> -	} else
> -		ret = intel_vgpu_default_mmio_write(vgpu, offset, p_data,
> -				bytes);
> -	if (ret)
> +	ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, false);
> +	if (ret < 0)
>  		goto err;
> -out:
> +
>  	intel_gvt_mmio_set_accessed(gvt, offset);
>  	mutex_unlock(&gvt->lock);
>  	return 0;
> diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h
> index 9289b5d..d4e06d5 100644
> --- a/drivers/gpu/drm/i915/gvt/mmio.h
> +++ b/drivers/gpu/drm/i915/gvt/mmio.h
> @@ -52,6 +52,9 @@ struct intel_vgpu;
>  #define D_PRE_SKL	(D_BDW)
>  #define D_ALL		(D_BDW | D_SKL | D_KBL)
>  
> +typedef int (*gvt_mmio_func)(struct intel_vgpu *, unsigned int, void *,
> +			     unsigned int);
> +
>  struct intel_gvt_mmio_info {
>  	u32 offset;
>  	u32 size;
> @@ -59,8 +62,8 @@ struct intel_gvt_mmio_info {
>  	u32 addr_mask;
>  	u64 ro_mask;
>  	u32 device;
> -	int (*read)(struct intel_vgpu *, unsigned int, void *, unsigned int);
> -	int (*write)(struct intel_vgpu *, unsigned int, void *, unsigned int);
> +	gvt_mmio_func read;
> +	gvt_mmio_func write;
>  	u32 addr_range;
>  	struct hlist_node node;
>  };
> @@ -71,8 +74,6 @@ bool intel_gvt_match_device(struct intel_gvt *gvt, unsigned long device);
>  int intel_gvt_setup_mmio_info(struct intel_gvt *gvt);
>  void intel_gvt_clean_mmio_info(struct intel_gvt *gvt);
>  
> -struct intel_gvt_mmio_info *intel_gvt_find_mmio_info(struct intel_gvt *gvt,
> -						     unsigned int offset);
>  #define INTEL_GVT_MMIO_OFFSET(reg) ({ \
>  	typeof(reg) __reg = reg; \
>  	u32 *offset = (u32 *)&__reg; \
> @@ -103,4 +104,8 @@ int intel_vgpu_default_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
>  
>  bool intel_gvt_in_force_nonpriv_whitelist(struct intel_gvt *gvt,
>  					  unsigned int offset);
> +
> +int intel_vgpu_mmio_reg_rw(struct intel_vgpu *vgpu, unsigned int offset,
> +			   void *pdata, unsigned int bytes, bool is_read);
> +
>  #endif
> -- 
> 2.7.4
> 
> _______________________________________________
> intel-gvt-dev mailing list
> intel-gvt-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gvt-dev

-- 
Open Source Technology Center, Intel ltd.

$gpg --keyserver wwwkeys.pgp.net --recv-keys 4D781827
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/intel-gvt-dev/attachments/20170605/38ba3f10/attachment.sig>


More information about the intel-gvt-dev mailing list