aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChangbin Du <changbin.du@intel.com>2017-05-03 22:52:38 -0400
committerZhenyu Wang <zhenyuw@linux.intel.com>2017-06-08 01:59:15 -0400
commit0e86cc9ccc3bf557348befaddf5cb613cf3c4458 (patch)
treed4ca241359ce82bafdcb9b65938da9961df6b2c9
parent5d0f5de16ef3d127469aa09dcdf07bec5174937f (diff)
drm/i915/gvt: implement per-vm mmio switching optimization
Commit ab9da627906a ("drm/i915: make context status notifier head be per engine") gives us a chance to inspect every single request. Then we can eliminate unnecessary mmio switching for same vGPU. We only need mmio switching for different VMs (including host). This patch introduced a new general API intel_gvt_switch_mmio() to replace the old intel_gvt_load/restore_render_mmio(). This function can be further optimized for vGPU to vGPU switching. To support individual ring switch, we track the owner who occupy each ring. When another VM or host request a ring we do the mmio context switching. Otherwise no need to switch the ring. This optimization is very useful if only one guest has plenty of workloads and the host is mostly idle. The best case is no mmio switching will happen. v2: o fix missing ring switch issue. (chuanxiao) o support individual ring switch. Signed-off-by: Changbin Du <changbin.du@intel.com> Reviewed-by: Chuanxiao Dong <chuanxiao.dong@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
-rw-r--r--drivers/gpu/drm/i915/gvt/gvt.c2
-rw-r--r--drivers/gpu/drm/i915/gvt/render.c35
-rw-r--r--drivers/gpu/drm/i915/gvt/render.h4
-rw-r--r--drivers/gpu/drm/i915/gvt/sched_policy.c12
-rw-r--r--drivers/gpu/drm/i915/gvt/scheduler.c35
-rw-r--r--drivers/gpu/drm/i915/gvt/scheduler.h4
6 files changed, 80 insertions, 12 deletions
diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c
index 7dea5e5d5567..20329171e4ab 100644
--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -244,7 +244,7 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
244 gvt_dbg_core("init gvt device\n"); 244 gvt_dbg_core("init gvt device\n");
245 245
246 idr_init(&gvt->vgpu_idr); 246 idr_init(&gvt->vgpu_idr);
247 247 spin_lock_init(&gvt->scheduler.mmio_context_lock);
248 mutex_init(&gvt->lock); 248 mutex_init(&gvt->lock);
249 gvt->dev_priv = dev_priv; 249 gvt->dev_priv = dev_priv;
250 250
diff --git a/drivers/gpu/drm/i915/gvt/render.c b/drivers/gpu/drm/i915/gvt/render.c
index c6e7972ac21d..19d98c903672 100644
--- a/drivers/gpu/drm/i915/gvt/render.c
+++ b/drivers/gpu/drm/i915/gvt/render.c
@@ -260,7 +260,8 @@ static void restore_mocs(struct intel_vgpu *vgpu, int ring_id)
260 260
261#define CTX_CONTEXT_CONTROL_VAL 0x03 261#define CTX_CONTEXT_CONTROL_VAL 0x03
262 262
263void intel_gvt_load_render_mmio(struct intel_vgpu *vgpu, int ring_id) 263/* Switch ring mmio values (context) from host to a vgpu. */
264static void switch_mmio_to_vgpu(struct intel_vgpu *vgpu, int ring_id)
264{ 265{
265 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; 266 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
266 struct render_mmio *mmio; 267 struct render_mmio *mmio;
@@ -312,7 +313,8 @@ void intel_gvt_load_render_mmio(struct intel_vgpu *vgpu, int ring_id)
312 handle_tlb_pending_event(vgpu, ring_id); 313 handle_tlb_pending_event(vgpu, ring_id);
313} 314}
314 315
315void intel_gvt_restore_render_mmio(struct intel_vgpu *vgpu, int ring_id) 316/* Switch ring mmio values (context) from vgpu to host. */
317static void switch_mmio_to_host(struct intel_vgpu *vgpu, int ring_id)
316{ 318{
317 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; 319 struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
318 struct render_mmio *mmio; 320 struct render_mmio *mmio;
@@ -348,3 +350,32 @@ void intel_gvt_restore_render_mmio(struct intel_vgpu *vgpu, int ring_id)
348 mmio->value, v); 350 mmio->value, v);
349 } 351 }
350} 352}
353
354/**
355 * intel_gvt_switch_render_mmio - switch mmio context of specific engine
356 * @pre: the last vGPU that own the engine
357 * @next: the vGPU to switch to
358 * @ring_id: specify the engine
359 *
360 * If pre is null indicates that host own the engine. If next is null
361 * indicates that we are switching to host workload.
362 */
363void intel_gvt_switch_mmio(struct intel_vgpu *pre,
364 struct intel_vgpu *next, int ring_id)
365{
366 if (WARN_ON(!pre && !next))
367 return;
368
369 gvt_dbg_render("switch ring %d from %s to %s\n", ring_id,
370 pre ? "vGPU" : "host", next ? "vGPU" : "HOST");
371
372 /**
373 * TODO: Optimize for vGPU to vGPU switch by merging
374 * switch_mmio_to_host() and switch_mmio_to_vgpu().
375 */
376 if (pre)
377 switch_mmio_to_host(pre, ring_id);
378
379 if (next)
380 switch_mmio_to_vgpu(next, ring_id);
381}
diff --git a/drivers/gpu/drm/i915/gvt/render.h b/drivers/gpu/drm/i915/gvt/render.h
index dac1a3cc458b..91db1d39d28f 100644
--- a/drivers/gpu/drm/i915/gvt/render.h
+++ b/drivers/gpu/drm/i915/gvt/render.h
@@ -36,8 +36,8 @@
36#ifndef __GVT_RENDER_H__ 36#ifndef __GVT_RENDER_H__
37#define __GVT_RENDER_H__ 37#define __GVT_RENDER_H__
38 38
39void intel_gvt_load_render_mmio(struct intel_vgpu *vgpu, int ring_id); 39void intel_gvt_switch_mmio(struct intel_vgpu *pre,
40 struct intel_vgpu *next, int ring_id);
40 41
41void intel_gvt_restore_render_mmio(struct intel_vgpu *vgpu, int ring_id);
42 42
43#endif 43#endif
diff --git a/drivers/gpu/drm/i915/gvt/sched_policy.c b/drivers/gpu/drm/i915/gvt/sched_policy.c
index 79ba4b3440aa..f642a3f0cfa0 100644
--- a/drivers/gpu/drm/i915/gvt/sched_policy.c
+++ b/drivers/gpu/drm/i915/gvt/sched_policy.c
@@ -299,8 +299,20 @@ static int tbs_sched_init_vgpu(struct intel_vgpu *vgpu)
299 299
300static void tbs_sched_clean_vgpu(struct intel_vgpu *vgpu) 300static void tbs_sched_clean_vgpu(struct intel_vgpu *vgpu)
301{ 301{
302 struct intel_gvt_workload_scheduler *scheduler = &vgpu->gvt->scheduler;
303 int ring_id;
304
302 kfree(vgpu->sched_data); 305 kfree(vgpu->sched_data);
303 vgpu->sched_data = NULL; 306 vgpu->sched_data = NULL;
307
308 spin_lock_bh(&scheduler->mmio_context_lock);
309 for (ring_id = 0; ring_id < I915_NUM_ENGINES; ring_id++) {
310 if (scheduler->engine_owner[ring_id] == vgpu) {
311 intel_gvt_switch_mmio(vgpu, NULL, ring_id);
312 scheduler->engine_owner[ring_id] = NULL;
313 }
314 }
315 spin_unlock_bh(&scheduler->mmio_context_lock);
304} 316}
305 317
306static void tbs_sched_start_schedule(struct intel_vgpu *vgpu) 318static void tbs_sched_start_schedule(struct intel_vgpu *vgpu)
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index 6ae286cb5804..aa7e06df88b6 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -138,21 +138,42 @@ static int shadow_context_status_change(struct notifier_block *nb,
138 struct intel_gvt *gvt = container_of(nb, struct intel_gvt, 138 struct intel_gvt *gvt = container_of(nb, struct intel_gvt,
139 shadow_ctx_notifier_block[req->engine->id]); 139 shadow_ctx_notifier_block[req->engine->id]);
140 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler; 140 struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
141 struct intel_vgpu_workload *workload = 141 enum intel_engine_id ring_id = req->engine->id;
142 scheduler->current_workload[req->engine->id]; 142 struct intel_vgpu_workload *workload;
143
144 if (!is_gvt_request(req)) {
145 spin_lock_bh(&scheduler->mmio_context_lock);
146 if (action == INTEL_CONTEXT_SCHEDULE_IN &&
147 scheduler->engine_owner[ring_id]) {
148 /* Switch ring from vGPU to host. */
149 intel_gvt_switch_mmio(scheduler->engine_owner[ring_id],
150 NULL, ring_id);
151 scheduler->engine_owner[ring_id] = NULL;
152 }
153 spin_unlock_bh(&scheduler->mmio_context_lock);
143 154
144 if (!is_gvt_request(req) || unlikely(!workload)) 155 return NOTIFY_OK;
156 }
157
158 workload = scheduler->current_workload[ring_id];
159 if (unlikely(!workload))
145 return NOTIFY_OK; 160 return NOTIFY_OK;
146 161
147 switch (action) { 162 switch (action) {
148 case INTEL_CONTEXT_SCHEDULE_IN: 163 case INTEL_CONTEXT_SCHEDULE_IN:
149 intel_gvt_load_render_mmio(workload->vgpu, 164 spin_lock_bh(&scheduler->mmio_context_lock);
150 workload->ring_id); 165 if (workload->vgpu != scheduler->engine_owner[ring_id]) {
166 /* Switch ring from host to vGPU or vGPU to vGPU. */
167 intel_gvt_switch_mmio(scheduler->engine_owner[ring_id],
168 workload->vgpu, ring_id);
169 scheduler->engine_owner[ring_id] = workload->vgpu;
170 } else
171 gvt_dbg_sched("skip ring %d mmio switch for vgpu%d\n",
172 ring_id, workload->vgpu->id);
173 spin_unlock_bh(&scheduler->mmio_context_lock);
151 atomic_set(&workload->shadow_ctx_active, 1); 174 atomic_set(&workload->shadow_ctx_active, 1);
152 break; 175 break;
153 case INTEL_CONTEXT_SCHEDULE_OUT: 176 case INTEL_CONTEXT_SCHEDULE_OUT:
154 intel_gvt_restore_render_mmio(workload->vgpu,
155 workload->ring_id);
156 /* If the status is -EINPROGRESS means this workload 177 /* If the status is -EINPROGRESS means this workload
157 * doesn't meet any issue during dispatching so when 178 * doesn't meet any issue during dispatching so when
158 * get the SCHEDULE_OUT set the status to be zero for 179 * get the SCHEDULE_OUT set the status to be zero for
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h
index 2cd725c0573e..9b6bf51e9b9b 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.h
+++ b/drivers/gpu/drm/i915/gvt/scheduler.h
@@ -42,6 +42,10 @@ struct intel_gvt_workload_scheduler {
42 struct intel_vgpu_workload *current_workload[I915_NUM_ENGINES]; 42 struct intel_vgpu_workload *current_workload[I915_NUM_ENGINES];
43 bool need_reschedule; 43 bool need_reschedule;
44 44
45 spinlock_t mmio_context_lock;
46 /* can be null when owner is host */
47 struct intel_vgpu *engine_owner[I915_NUM_ENGINES];
48
45 wait_queue_head_t workload_complete_wq; 49 wait_queue_head_t workload_complete_wq;
46 struct task_struct *thread[I915_NUM_ENGINES]; 50 struct task_struct *thread[I915_NUM_ENGINES];
47 wait_queue_head_t waitq[I915_NUM_ENGINES]; 51 wait_queue_head_t waitq[I915_NUM_ENGINES];