drm/i915/gvt: Use sched_lock to protect gvt scheduler logic.
authorColin Xu <colin.xu@intel.com>
Sat, 19 May 2018 04:28:55 +0000 (12:28 +0800)
committerZhenyu Wang <zhenyuw@linux.intel.com>
Fri, 18 May 2018 04:39:26 +0000 (12:39 +0800)
The scheduler lock(gvt->sched_lock) is used to protect gvt
scheduler logic, including the gvt scheduler structure(gvt->scheduler
and per vgpu schedule data(vgpu->sched_data, vgpu->sched_ctl).

v9:
  - Change commit author since the patches are improved a lot compared
    with original version.
    Original author: Pei Zhang <pei.zhang@intel.com>
  - Rebase to latest gvt-staging.
v8:
  - Correct coding wqstyle.
  - Rebase to latest gvt-staging.
v7:
  - Remove gtt_lock since already proteced by gvt_lock and vgpu_lock.
v6:
  - Rebase to latest gvt-staging.
v5:
  - Rebase to latest gvt-staging.
v4:
  - Rebase to latest gvt-staging.
v3: update to latest code base

Signed-off-by: Pei Zhang <pei.zhang@intel.com>
Signed-off-by: Colin Xu <colin.xu@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
drivers/gpu/drm/i915/gvt/gvt.c
drivers/gpu/drm/i915/gvt/gvt.h
drivers/gpu/drm/i915/gvt/sched_policy.c
drivers/gpu/drm/i915/gvt/scheduler.c

index 769e06c3ae23e965d06c977a62240009d487648e..22a3ddff38a3da0649ffadd9dfd2cbcc257bbf75 100644 (file)
@@ -376,6 +376,7 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
        idr_init(&gvt->vgpu_idr);
        spin_lock_init(&gvt->scheduler.mmio_context_lock);
        mutex_init(&gvt->lock);
+       mutex_init(&gvt->sched_lock);
        gvt->dev_priv = dev_priv;
 
        init_device_info(gvt);
index 3600553c8b56c2400973c9d6302ff9bc9bc0ccf6..362e3d506d2dbd7d12b2cd735ee65488592a616e 100644 (file)
@@ -177,6 +177,11 @@ struct intel_vgpu {
        bool pv_notified;
        bool failsafe;
        unsigned int resetting_eng;
+
+       /* Both sched_data and sched_ctl can be seen a part of the global gvt
+        * scheduler structure. So below 2 vgpu data are protected
+        * by sched_lock, not vgpu_lock.
+        */
        void *sched_data;
        struct vgpu_sched_ctl sched_ctl;
 
@@ -299,6 +304,9 @@ struct intel_gvt {
         * not yet protected by special locks(vgpu and scheduler lock).
         */
        struct mutex lock;
+       /* scheduler scope lock, protect gvt and vgpu schedule related data */
+       struct mutex sched_lock;
+
        struct drm_i915_private *dev_priv;
        struct idr vgpu_idr;    /* vGPU IDR pool */
 
index d053cbe1dc94c9bcd1ce1edd2fe32ab5dc8efc17..09d7bb72b4ff30e45688add463c1fdaaa9a71ad1 100644 (file)
@@ -228,7 +228,7 @@ void intel_gvt_schedule(struct intel_gvt *gvt)
        struct gvt_sched_data *sched_data = gvt->scheduler.sched_data;
        ktime_t cur_time;
 
-       mutex_lock(&gvt->lock);
+       mutex_lock(&gvt->sched_lock);
        cur_time = ktime_get();
 
        if (test_and_clear_bit(INTEL_GVT_REQUEST_SCHED,
@@ -244,7 +244,7 @@ void intel_gvt_schedule(struct intel_gvt *gvt)
        vgpu_update_timeslice(gvt->scheduler.current_vgpu, cur_time);
        tbs_sched_func(sched_data);
 
-       mutex_unlock(&gvt->lock);
+       mutex_unlock(&gvt->sched_lock);
 }
 
 static enum hrtimer_restart tbs_timer_fn(struct hrtimer *timer_data)
@@ -359,39 +359,65 @@ static struct intel_gvt_sched_policy_ops tbs_schedule_ops = {
 
 int intel_gvt_init_sched_policy(struct intel_gvt *gvt)
 {
+       int ret;
+
+       mutex_lock(&gvt->sched_lock);
        gvt->scheduler.sched_ops = &tbs_schedule_ops;
+       ret = gvt->scheduler.sched_ops->init(gvt);
+       mutex_unlock(&gvt->sched_lock);
 
-       return gvt->scheduler.sched_ops->init(gvt);
+       return ret;
 }
 
 void intel_gvt_clean_sched_policy(struct intel_gvt *gvt)
 {
+       mutex_lock(&gvt->sched_lock);
        gvt->scheduler.sched_ops->clean(gvt);
+       mutex_unlock(&gvt->sched_lock);
 }
 
+/* for per-vgpu scheduler policy, there are 2 per-vgpu data:
+ * sched_data, and sched_ctl. We see these 2 data as part of
+ * the global scheduler which are proteced by gvt->sched_lock.
+ * Caller should make their decision if the vgpu_lock should
+ * be hold outside.
+ */
+
 int intel_vgpu_init_sched_policy(struct intel_vgpu *vgpu)
 {
-       return vgpu->gvt->scheduler.sched_ops->init_vgpu(vgpu);
+       int ret;
+
+       mutex_lock(&vgpu->gvt->sched_lock);
+       ret = vgpu->gvt->scheduler.sched_ops->init_vgpu(vgpu);
+       mutex_unlock(&vgpu->gvt->sched_lock);
+
+       return ret;
 }
 
 void intel_vgpu_clean_sched_policy(struct intel_vgpu *vgpu)
 {
+       mutex_lock(&vgpu->gvt->sched_lock);
        vgpu->gvt->scheduler.sched_ops->clean_vgpu(vgpu);
+       mutex_unlock(&vgpu->gvt->sched_lock);
 }
 
 void intel_vgpu_start_schedule(struct intel_vgpu *vgpu)
 {
        struct vgpu_sched_data *vgpu_data = vgpu->sched_data;
 
+       mutex_lock(&vgpu->gvt->sched_lock);
        if (!vgpu_data->active) {
                gvt_dbg_core("vgpu%d: start schedule\n", vgpu->id);
                vgpu->gvt->scheduler.sched_ops->start_schedule(vgpu);
        }
+       mutex_unlock(&vgpu->gvt->sched_lock);
 }
 
 void intel_gvt_kick_schedule(struct intel_gvt *gvt)
 {
+       mutex_lock(&gvt->sched_lock);
        intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EVENT_SCHED);
+       mutex_unlock(&gvt->sched_lock);
 }
 
 void intel_vgpu_stop_schedule(struct intel_vgpu *vgpu)
@@ -406,6 +432,7 @@ void intel_vgpu_stop_schedule(struct intel_vgpu *vgpu)
 
        gvt_dbg_core("vgpu%d: stop schedule\n", vgpu->id);
 
+       mutex_lock(&vgpu->gvt->sched_lock);
        scheduler->sched_ops->stop_schedule(vgpu);
 
        if (scheduler->next_vgpu == vgpu)
@@ -425,4 +452,5 @@ void intel_vgpu_stop_schedule(struct intel_vgpu *vgpu)
                }
        }
        spin_unlock_bh(&scheduler->mmio_context_lock);
+       mutex_unlock(&vgpu->gvt->sched_lock);
 }
index c0848dcf79c72cba3e8ea554357dd187821195e6..847f295e6755be1c11d5a1f63067d2e13735bd4f 100644 (file)
@@ -715,7 +715,7 @@ static struct intel_vgpu_workload *pick_next_workload(
        struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
        struct intel_vgpu_workload *workload = NULL;
 
-       mutex_lock(&gvt->lock);
+       mutex_lock(&gvt->sched_lock);
 
        /*
         * no current vgpu / will be scheduled out / no workload
@@ -761,7 +761,7 @@ static struct intel_vgpu_workload *pick_next_workload(
 
        atomic_inc(&workload->vgpu->submission.running_workload_num);
 out:
-       mutex_unlock(&gvt->lock);
+       mutex_unlock(&gvt->sched_lock);
        return workload;
 }
 
@@ -862,8 +862,8 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
        struct intel_vgpu_submission *s = &vgpu->submission;
        int event;
 
-       mutex_lock(&gvt->lock);
        mutex_lock(&vgpu->vgpu_lock);
+       mutex_lock(&gvt->sched_lock);
 
        /* For the workload w/ request, needs to wait for the context
         * switch to make sure request is completed.
@@ -941,8 +941,8 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
        if (gvt->scheduler.need_reschedule)
                intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EVENT_SCHED);
 
+       mutex_unlock(&gvt->sched_lock);
        mutex_unlock(&vgpu->vgpu_lock);
-       mutex_unlock(&gvt->lock);
 }
 
 struct workload_thread_param {