aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChangbin Du <changbin.du@intel.com>2017-06-06 03:56:09 -0400
committerZhenyu Wang <zhenyuw@linux.intel.com>2017-06-08 01:59:19 -0400
commit65f9f6febf12ed5bbcebd3599698eb78b03e5b69 (patch)
treea9f1d792175a49ecd7808a309a4de4ac8a87764b
parentaf2c6399aabeb7a7107657a469cb2f16b55dfbae (diff)
drm/i915/gvt: Optimize MMIO register handling for some large MMIO blocks
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. v2: o add a local function find_mmio_block(). o fix comments. Signed-off-by: Changbin Du <changbin.du@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
-rw-r--r--drivers/gpu/drm/i915/gvt/handlers.c162
-rw-r--r--drivers/gpu/drm/i915/gvt/mmio.c86
-rw-r--r--drivers/gpu/drm/i915/gvt/mmio.h13
3 files changed, 147 insertions, 114 deletions
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index bb7037c6c347..60c0db10ae15 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -92,11 +92,22 @@ static void write_vreg(struct intel_vgpu *vgpu, unsigned int offset,
92 memcpy(&vgpu_vreg(vgpu, offset), p_data, bytes); 92 memcpy(&vgpu_vreg(vgpu, offset), p_data, bytes);
93} 93}
94 94
95static struct intel_gvt_mmio_info *find_mmio_info(struct intel_gvt *gvt,
96 unsigned int offset)
97{
98 struct intel_gvt_mmio_info *e;
99
100 hash_for_each_possible(gvt->mmio.mmio_info_table, e, node, offset) {
101 if (e->offset == offset)
102 return e;
103 }
104 return NULL;
105}
106
95static int new_mmio_info(struct intel_gvt *gvt, 107static int new_mmio_info(struct intel_gvt *gvt,
96 u32 offset, u32 flags, u32 size, 108 u32 offset, u32 flags, u32 size,
97 u32 addr_mask, u32 ro_mask, u32 device, 109 u32 addr_mask, u32 ro_mask, u32 device,
98 int (*read)(struct intel_vgpu *, unsigned int, void *, unsigned int), 110 gvt_mmio_func read, gvt_mmio_func write)
99 int (*write)(struct intel_vgpu *, unsigned int, void *, unsigned int))
100{ 111{
101 struct intel_gvt_mmio_info *info, *p; 112 struct intel_gvt_mmio_info *info, *p;
102 u32 start, end, i; 113 u32 start, end, i;
@@ -116,7 +127,7 @@ static int new_mmio_info(struct intel_gvt *gvt,
116 return -ENOMEM; 127 return -ENOMEM;
117 128
118 info->offset = i; 129 info->offset = i;
119 p = intel_gvt_find_mmio_info(gvt, info->offset); 130 p = find_mmio_info(gvt, info->offset);
120 if (p) 131 if (p)
121 gvt_err("dup mmio definition offset %x\n", 132 gvt_err("dup mmio definition offset %x\n",
122 info->offset); 133 info->offset);
@@ -1794,10 +1805,6 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
1794 MMIO_D(SPRSCALE(PIPE_C), D_ALL); 1805 MMIO_D(SPRSCALE(PIPE_C), D_ALL);
1795 MMIO_D(SPRSURFLIVE(PIPE_C), D_ALL); 1806 MMIO_D(SPRSURFLIVE(PIPE_C), D_ALL);
1796 1807
1797 MMIO_F(LGC_PALETTE(PIPE_A, 0), 4 * 256, 0, 0, 0, D_ALL, NULL, NULL);
1798 MMIO_F(LGC_PALETTE(PIPE_B, 0), 4 * 256, 0, 0, 0, D_ALL, NULL, NULL);
1799 MMIO_F(LGC_PALETTE(PIPE_C, 0), 4 * 256, 0, 0, 0, D_ALL, NULL, NULL);
1800
1801 MMIO_D(HTOTAL(TRANSCODER_A), D_ALL); 1808 MMIO_D(HTOTAL(TRANSCODER_A), D_ALL);
1802 MMIO_D(HBLANK(TRANSCODER_A), D_ALL); 1809 MMIO_D(HBLANK(TRANSCODER_A), D_ALL);
1803 MMIO_D(HSYNC(TRANSCODER_A), D_ALL); 1810 MMIO_D(HSYNC(TRANSCODER_A), D_ALL);
@@ -2245,11 +2252,8 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
2245 2252
2246 MMIO_DH(GEN6_GDRST, D_ALL, NULL, gdrst_mmio_write); 2253 MMIO_DH(GEN6_GDRST, D_ALL, NULL, gdrst_mmio_write);
2247 MMIO_F(FENCE_REG_GEN6_LO(0), 0x80, 0, 0, 0, D_ALL, fence_mmio_read, fence_mmio_write); 2254 MMIO_F(FENCE_REG_GEN6_LO(0), 0x80, 0, 0, 0, D_ALL, fence_mmio_read, fence_mmio_write);
2248 MMIO_F(VGT_PVINFO_PAGE, VGT_PVINFO_SIZE, F_UNALIGN, 0, 0, D_ALL, pvinfo_mmio_read, pvinfo_mmio_write);
2249 MMIO_DH(CPU_VGACNTRL, D_ALL, NULL, vga_control_mmio_write); 2255 MMIO_DH(CPU_VGACNTRL, D_ALL, NULL, vga_control_mmio_write);
2250 2256
2251 MMIO_F(MCHBAR_MIRROR_BASE_SNB, 0x40000, 0, 0, 0, D_ALL, NULL, NULL);
2252
2253 MMIO_D(TILECTL, D_ALL); 2257 MMIO_D(TILECTL, D_ALL);
2254 2258
2255 MMIO_D(GEN6_UCGCTL1, D_ALL); 2259 MMIO_D(GEN6_UCGCTL1, D_ALL);
@@ -2778,7 +2782,6 @@ static int init_skl_mmio_info(struct intel_gvt *gvt)
2778 MMIO_D(0x72380, D_SKL_PLUS); 2782 MMIO_D(0x72380, D_SKL_PLUS);
2779 MMIO_D(0x7039c, D_SKL_PLUS); 2783 MMIO_D(0x7039c, D_SKL_PLUS);
2780 2784
2781 MMIO_F(0x80000, 0x3000, 0, 0, 0, D_SKL_PLUS, NULL, NULL);
2782 MMIO_D(0x8f074, D_SKL | D_KBL); 2785 MMIO_D(0x8f074, D_SKL | D_KBL);
2783 MMIO_D(0x8f004, D_SKL | D_KBL); 2786 MMIO_D(0x8f004, D_SKL | D_KBL);
2784 MMIO_D(0x8f034, D_SKL | D_KBL); 2787 MMIO_D(0x8f034, D_SKL | D_KBL);
@@ -2852,26 +2855,36 @@ static int init_skl_mmio_info(struct intel_gvt *gvt)
2852 return 0; 2855 return 0;
2853} 2856}
2854 2857
2855/** 2858/* Special MMIO blocks. */
2856 * intel_gvt_find_mmio_info - find MMIO information entry by aligned offset 2859static struct gvt_mmio_block {
2857 * @gvt: GVT device 2860 unsigned int device;
2858 * @offset: register offset 2861 i915_reg_t offset;
2859 * 2862 unsigned int size;
2860 * This function is used to find the MMIO information entry from hash table 2863 gvt_mmio_func read;
2861 * 2864 gvt_mmio_func write;
2862 * Returns: 2865} gvt_mmio_blocks[] = {
2863 * pointer to MMIO information entry, NULL if not exists 2866 {D_SKL_PLUS, _MMIO(CSR_MMIO_START_RANGE), 0x3000, NULL, NULL},
2864 */ 2867 {D_ALL, _MMIO(MCHBAR_MIRROR_BASE_SNB), 0x40000, NULL, NULL},
2865struct intel_gvt_mmio_info *intel_gvt_find_mmio_info(struct intel_gvt *gvt, 2868 {D_ALL, _MMIO(VGT_PVINFO_PAGE), VGT_PVINFO_SIZE,
2866 unsigned int offset) 2869 pvinfo_mmio_read, pvinfo_mmio_write},
2867{ 2870 {D_ALL, LGC_PALETTE(PIPE_A, 0), 1024, NULL, NULL},
2868 struct intel_gvt_mmio_info *e; 2871 {D_ALL, LGC_PALETTE(PIPE_B, 0), 1024, NULL, NULL},
2872 {D_ALL, LGC_PALETTE(PIPE_C, 0), 1024, NULL, NULL},
2873};
2869 2874
2870 WARN_ON(!IS_ALIGNED(offset, 4)); 2875static struct gvt_mmio_block *find_mmio_block(struct intel_gvt *gvt,
2876 unsigned int offset)
2877{
2878 unsigned long device = intel_gvt_get_device_type(gvt);
2879 struct gvt_mmio_block *block = gvt_mmio_blocks;
2880 int i;
2871 2881
2872 hash_for_each_possible(gvt->mmio.mmio_info_table, e, node, offset) { 2882 for (i = 0; i < ARRAY_SIZE(gvt_mmio_blocks); i++, block++) {
2873 if (e->offset == offset) 2883 if (!(device & block->device))
2874 return e; 2884 continue;
2885 if (offset >= INTEL_GVT_MMIO_OFFSET(block->offset) &&
2886 offset < INTEL_GVT_MMIO_OFFSET(block->offset) + block->size)
2887 return block;
2875 } 2888 }
2876 return NULL; 2889 return NULL;
2877} 2890}
@@ -3056,3 +3069,94 @@ bool intel_gvt_in_force_nonpriv_whitelist(struct intel_gvt *gvt,
3056{ 3069{
3057 return in_whitelist(offset); 3070 return in_whitelist(offset);
3058} 3071}
3072
3073/**
3074 * intel_vgpu_mmio_reg_rw - emulate tracked mmio registers
3075 * @vgpu: a vGPU
3076 * @offset: register offset
3077 * @pdata: data buffer
3078 * @bytes: data length
3079 *
3080 * Returns:
3081 * Zero on success, negative error code if failed.
3082 */
3083int intel_vgpu_mmio_reg_rw(struct intel_vgpu *vgpu, unsigned int offset,
3084 void *pdata, unsigned int bytes, bool is_read)
3085{
3086 struct intel_gvt *gvt = vgpu->gvt;
3087 struct intel_gvt_mmio_info *mmio_info;
3088 struct gvt_mmio_block *mmio_block;
3089 gvt_mmio_func func;
3090 int ret;
3091
3092 if (WARN_ON(bytes > 4))
3093 return -EINVAL;
3094
3095 /*
3096 * Handle special MMIO blocks.
3097 */
3098 mmio_block = find_mmio_block(gvt, offset);
3099 if (mmio_block) {
3100 func = is_read ? mmio_block->read : mmio_block->write;
3101 if (func)
3102 return func(vgpu, offset, pdata, bytes);
3103 goto default_rw;
3104 }
3105
3106 /*
3107 * Normal tracked MMIOs.
3108 */
3109 mmio_info = find_mmio_info(gvt, offset);
3110 if (!mmio_info) {
3111 if (!vgpu->mmio.disable_warn_untrack)
3112 gvt_vgpu_err("untracked MMIO %08x len %d\n",
3113 offset, bytes);
3114 goto default_rw;
3115 }
3116
3117 if (WARN_ON(bytes > mmio_info->size))
3118 return -EINVAL;
3119
3120 if (is_read)
3121 return mmio_info->read(vgpu, offset, pdata, bytes);
3122 else {
3123 u64 ro_mask = mmio_info->ro_mask;
3124 u32 old_vreg = 0, old_sreg = 0;
3125 u64 data = 0;
3126
3127 if (intel_gvt_mmio_has_mode_mask(gvt, mmio_info->offset)) {
3128 old_vreg = vgpu_vreg(vgpu, offset);
3129 old_sreg = vgpu_sreg(vgpu, offset);
3130 }
3131
3132 if (likely(!ro_mask))
3133 ret = mmio_info->write(vgpu, offset, pdata, bytes);
3134 else if (!~ro_mask) {
3135 gvt_vgpu_err("try to write RO reg %x\n", offset);
3136 return 0;
3137 } else {
3138 /* keep the RO bits in the virtual register */
3139 memcpy(&data, pdata, bytes);
3140 data &= ~ro_mask;
3141 data |= vgpu_vreg(vgpu, offset) & ro_mask;
3142 ret = mmio_info->write(vgpu, offset, &data, bytes);
3143 }
3144
3145 /* higher 16bits of mode ctl regs are mask bits for change */
3146 if (intel_gvt_mmio_has_mode_mask(gvt, mmio_info->offset)) {
3147 u32 mask = vgpu_vreg(vgpu, offset) >> 16;
3148
3149 vgpu_vreg(vgpu, offset) = (old_vreg & ~mask)
3150 | (vgpu_vreg(vgpu, offset) & mask);
3151 vgpu_sreg(vgpu, offset) = (old_sreg & ~mask)
3152 | (vgpu_sreg(vgpu, offset) & mask);
3153 }
3154 }
3155
3156 return ret;
3157
3158default_rw:
3159 return is_read ?
3160 intel_vgpu_default_mmio_read(vgpu, offset, pdata, bytes) :
3161 intel_vgpu_default_mmio_write(vgpu, offset, pdata, bytes);
3162}
diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c
index 35f6c4713cb6..322077fce2bb 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,
123 void *p_data, unsigned int bytes) 123 void *p_data, unsigned int bytes)
124{ 124{
125 struct intel_gvt *gvt = vgpu->gvt; 125 struct intel_gvt *gvt = vgpu->gvt;
126 struct intel_gvt_mmio_info *mmio;
127 unsigned int offset = 0; 126 unsigned int offset = 0;
128 int ret = -EINVAL; 127 int ret = -EINVAL;
129 128
@@ -187,25 +186,8 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa,
187 goto err; 186 goto err;
188 } 187 }
189 188
190 mmio = intel_gvt_find_mmio_info(gvt, rounddown(offset, 4)); 189 ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, true);
191 if (mmio) { 190 if (ret < 0)
192 if (!intel_gvt_mmio_is_unalign(gvt, mmio->offset)) {
193 if (WARN_ON(offset + bytes > mmio->offset + mmio->size))
194 goto err;
195 if (WARN_ON(mmio->offset != offset))
196 goto err;
197 }
198 ret = mmio->read(vgpu, offset, p_data, bytes);
199 } else {
200 ret = intel_vgpu_default_mmio_read(vgpu, offset, p_data, bytes);
201
202 if (!vgpu->mmio.disable_warn_untrack) {
203 gvt_vgpu_err("read untracked MMIO %x(%dB) val %x\n",
204 offset, bytes, *(u32 *)p_data);
205 }
206 }
207
208 if (ret)
209 goto err; 191 goto err;
210 192
211 intel_gvt_mmio_set_accessed(gvt, offset); 193 intel_gvt_mmio_set_accessed(gvt, offset);
@@ -232,9 +214,7 @@ int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, uint64_t pa,
232 void *p_data, unsigned int bytes) 214 void *p_data, unsigned int bytes)
233{ 215{
234 struct intel_gvt *gvt = vgpu->gvt; 216 struct intel_gvt *gvt = vgpu->gvt;
235 struct intel_gvt_mmio_info *mmio;
236 unsigned int offset = 0; 217 unsigned int offset = 0;
237 u32 old_vreg = 0, old_sreg = 0;
238 int ret = -EINVAL; 218 int ret = -EINVAL;
239 219
240 if (vgpu->failsafe) { 220 if (vgpu->failsafe) {
@@ -289,66 +269,10 @@ int intel_vgpu_emulate_mmio_write(struct intel_vgpu *vgpu, uint64_t pa,
289 return ret; 269 return ret;
290 } 270 }
291 271
292 mmio = intel_gvt_find_mmio_info(gvt, rounddown(offset, 4)); 272 ret = intel_vgpu_mmio_reg_rw(vgpu, offset, p_data, bytes, false);
293 if (!mmio && !vgpu->mmio.disable_warn_untrack) 273 if (ret < 0)
294 gvt_dbg_mmio("vgpu%d: write untracked MMIO %x len %d val %x\n",
295 vgpu->id, offset, bytes, *(u32 *)p_data);
296
297 if (!intel_gvt_mmio_is_unalign(gvt, offset)) {
298 if (WARN_ON(!IS_ALIGNED(offset, bytes)))
299 goto err;
300 }
301
302 if (mmio) {
303 u64 ro_mask = mmio->ro_mask;
304
305 if (!intel_gvt_mmio_is_unalign(gvt, mmio->offset)) {
306 if (WARN_ON(offset + bytes > mmio->offset + mmio->size))
307 goto err;
308 if (WARN_ON(mmio->offset != offset))
309 goto err;
310 }
311
312 if (intel_gvt_mmio_has_mode_mask(gvt, mmio->offset)) {
313 old_vreg = vgpu_vreg(vgpu, offset);
314 old_sreg = vgpu_sreg(vgpu, offset);
315 }
316
317 if (!ro_mask) {
318 ret = mmio->write(vgpu, offset, p_data, bytes);
319 } else {
320 /* Protect RO bits like HW */
321 u64 data = 0;
322
323 /* all register bits are RO. */
324 if (ro_mask == ~(u64)0) {
325 gvt_vgpu_err("try to write RO reg %x\n",
326 offset);
327 ret = 0;
328 goto out;
329 }
330 /* keep the RO bits in the virtual register */
331 memcpy(&data, p_data, bytes);
332 data &= ~mmio->ro_mask;
333 data |= vgpu_vreg(vgpu, offset) & mmio->ro_mask;
334 ret = mmio->write(vgpu, offset, &data, bytes);
335 }
336
337 /* higher 16bits of mode ctl regs are mask bits for change */
338 if (intel_gvt_mmio_has_mode_mask(gvt, mmio->offset)) {
339 u32 mask = vgpu_vreg(vgpu, offset) >> 16;
340
341 vgpu_vreg(vgpu, offset) = (old_vreg & ~mask)
342 | (vgpu_vreg(vgpu, offset) & mask);
343 vgpu_sreg(vgpu, offset) = (old_sreg & ~mask)
344 | (vgpu_sreg(vgpu, offset) & mask);
345 }
346 } else
347 ret = intel_vgpu_default_mmio_write(vgpu, offset, p_data,
348 bytes);
349 if (ret)
350 goto err; 274 goto err;
351out: 275
352 intel_gvt_mmio_set_accessed(gvt, offset); 276 intel_gvt_mmio_set_accessed(gvt, offset);
353 mutex_unlock(&gvt->lock); 277 mutex_unlock(&gvt->lock);
354 return 0; 278 return 0;
diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h
index bd193f9bbcee..4410a323eea3 100644
--- a/drivers/gpu/drm/i915/gvt/mmio.h
+++ b/drivers/gpu/drm/i915/gvt/mmio.h
@@ -52,6 +52,9 @@ struct intel_vgpu;
52#define D_PRE_SKL (D_BDW) 52#define D_PRE_SKL (D_BDW)
53#define D_ALL (D_BDW | D_SKL | D_KBL) 53#define D_ALL (D_BDW | D_SKL | D_KBL)
54 54
55typedef int (*gvt_mmio_func)(struct intel_vgpu *, unsigned int, void *,
56 unsigned int);
57
55struct intel_gvt_mmio_info { 58struct intel_gvt_mmio_info {
56 u32 offset; 59 u32 offset;
57 u32 size; 60 u32 size;
@@ -59,8 +62,8 @@ struct intel_gvt_mmio_info {
59 u32 addr_mask; 62 u32 addr_mask;
60 u64 ro_mask; 63 u64 ro_mask;
61 u32 device; 64 u32 device;
62 int (*read)(struct intel_vgpu *, unsigned int, void *, unsigned int); 65 gvt_mmio_func read;
63 int (*write)(struct intel_vgpu *, unsigned int, void *, unsigned int); 66 gvt_mmio_func write;
64 u32 addr_range; 67 u32 addr_range;
65 struct hlist_node node; 68 struct hlist_node node;
66}; 69};
@@ -71,8 +74,6 @@ bool intel_gvt_match_device(struct intel_gvt *gvt, unsigned long device);
71int intel_gvt_setup_mmio_info(struct intel_gvt *gvt); 74int intel_gvt_setup_mmio_info(struct intel_gvt *gvt);
72void intel_gvt_clean_mmio_info(struct intel_gvt *gvt); 75void intel_gvt_clean_mmio_info(struct intel_gvt *gvt);
73 76
74struct intel_gvt_mmio_info *intel_gvt_find_mmio_info(struct intel_gvt *gvt,
75 unsigned int offset);
76#define INTEL_GVT_MMIO_OFFSET(reg) ({ \ 77#define INTEL_GVT_MMIO_OFFSET(reg) ({ \
77 typeof(reg) __reg = reg; \ 78 typeof(reg) __reg = reg; \
78 u32 *offset = (u32 *)&__reg; \ 79 u32 *offset = (u32 *)&__reg; \
@@ -103,4 +104,8 @@ int intel_vgpu_default_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
103 104
104bool intel_gvt_in_force_nonpriv_whitelist(struct intel_gvt *gvt, 105bool intel_gvt_in_force_nonpriv_whitelist(struct intel_gvt *gvt,
105 unsigned int offset); 106 unsigned int offset);
107
108int intel_vgpu_mmio_reg_rw(struct intel_vgpu *vgpu, unsigned int offset,
109 void *pdata, unsigned int bytes, bool is_read);
110
106#endif 111#endif