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

Du, Changbin changbin.du at intel.com
Mon Jun 5 05:23:21 UTC 2017


Thanks, will fix them.

On Mon, Jun 05, 2017 at 12:39:50PM +0800, Zhenyu Wang wrote:
> 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



> _______________________________________________
> intel-gvt-dev mailing list
> intel-gvt-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gvt-dev


-- 
Thanks,
Changbin Du
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/intel-gvt-dev/attachments/20170605/407f38be/attachment.sig>


More information about the intel-gvt-dev mailing list