[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