summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/scheduler/sched_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/scheduler/sched_main.c')
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c74
1 files changed, 60 insertions, 14 deletions
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index 506371c42745..fd755e953487 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -632,8 +632,14 @@ int drm_sched_job_init(struct drm_sched_job *job,
struct drm_sched_entity *entity,
void *owner)
{
- if (!entity->rq)
+ if (!entity->rq) {
+ /* This will most likely be followed by missing frames
+ * or worse--a blank screen--leave a trail in the
+ * logs, so this can be debugged easier.
+ */
+ drm_err(job->sched, "%s: entity has no rq!\n", __func__);
return -ENOENT;
+ }
job->entity = entity;
job->s_fence = drm_sched_fence_alloc(entity, owner);
@@ -671,7 +677,7 @@ void drm_sched_job_arm(struct drm_sched_job *job)
sched = entity->rq->sched;
job->sched = sched;
- job->s_priority = entity->rq - sched->sched_rq;
+ job->s_priority = entity->priority;
job->id = atomic64_inc_return(&sched->job_id_count);
drm_sched_fence_init(job->s_fence, job->entity);
@@ -888,10 +894,10 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched)
return NULL;
/* Kernel run queue has higher priority than normal run queue*/
- for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
+ for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
entity = drm_sched_policy == DRM_SCHED_POLICY_FIFO ?
- drm_sched_rq_select_entity_fifo(&sched->sched_rq[i]) :
- drm_sched_rq_select_entity_rr(&sched->sched_rq[i]);
+ drm_sched_rq_select_entity_fifo(sched->sched_rq[i]) :
+ drm_sched_rq_select_entity_rr(sched->sched_rq[i]);
if (entity)
break;
}
@@ -1071,6 +1077,7 @@ static int drm_sched_main(void *param)
*
* @sched: scheduler instance
* @ops: backend operations for this scheduler
+ * @num_rqs: number of runqueues, one for each priority, up to DRM_SCHED_PRIORITY_COUNT
* @hw_submission: number of hw submissions that can be in flight
* @hang_limit: number of times to allow a job to hang before dropping it
* @timeout: timeout value in jiffies for the scheduler
@@ -1084,11 +1091,12 @@ static int drm_sched_main(void *param)
*/
int drm_sched_init(struct drm_gpu_scheduler *sched,
const struct drm_sched_backend_ops *ops,
- unsigned hw_submission, unsigned hang_limit,
+ u32 num_rqs, uint32_t hw_submission, unsigned int hang_limit,
long timeout, struct workqueue_struct *timeout_wq,
atomic_t *score, const char *name, struct device *dev)
{
int i, ret;
+
sched->ops = ops;
sched->hw_submission_limit = hw_submission;
sched->name = name;
@@ -1097,8 +1105,36 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
sched->hang_limit = hang_limit;
sched->score = score ? score : &sched->_score;
sched->dev = dev;
- for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_COUNT; i++)
- drm_sched_rq_init(sched, &sched->sched_rq[i]);
+
+ if (num_rqs > DRM_SCHED_PRIORITY_COUNT) {
+ /* This is a gross violation--tell drivers what the problem is.
+ */
+ drm_err(sched, "%s: num_rqs cannot be greater than DRM_SCHED_PRIORITY_COUNT\n",
+ __func__);
+ return -EINVAL;
+ } else if (sched->sched_rq) {
+ /* Not an error, but warn anyway so drivers can
+ * fine-tune their DRM calling order, and return all
+ * is good.
+ */
+ drm_warn(sched, "%s: scheduler already initialized!\n", __func__);
+ return 0;
+ }
+
+ sched->sched_rq = kmalloc_array(num_rqs, sizeof(*sched->sched_rq),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!sched->sched_rq) {
+ drm_err(sched, "%s: out of memory for sched_rq\n", __func__);
+ return -ENOMEM;
+ }
+ sched->num_rqs = num_rqs;
+ ret = -ENOMEM;
+ for (i = DRM_SCHED_PRIORITY_MIN; i < sched->num_rqs; i++) {
+ sched->sched_rq[i] = kzalloc(sizeof(*sched->sched_rq[i]), GFP_KERNEL);
+ if (!sched->sched_rq[i])
+ goto Out_unroll;
+ drm_sched_rq_init(sched, sched->sched_rq[i]);
+ }
init_waitqueue_head(&sched->wake_up_worker);
init_waitqueue_head(&sched->job_scheduled);
@@ -1115,11 +1151,18 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
ret = PTR_ERR(sched->thread);
sched->thread = NULL;
DRM_DEV_ERROR(sched->dev, "Failed to create scheduler for %s.\n", name);
- return ret;
+ goto Out_unroll;
}
sched->ready = true;
return 0;
+Out_unroll:
+ for (--i ; i >= DRM_SCHED_PRIORITY_MIN; i--)
+ kfree(sched->sched_rq[i]);
+ kfree(sched->sched_rq);
+ sched->sched_rq = NULL;
+ drm_err(sched, "%s: Failed to setup GPU scheduler--out of memory\n", __func__);
+ return ret;
}
EXPORT_SYMBOL(drm_sched_init);
@@ -1138,8 +1181,8 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
if (sched->thread)
kthread_stop(sched->thread);
- for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
- struct drm_sched_rq *rq = &sched->sched_rq[i];
+ for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
+ struct drm_sched_rq *rq = sched->sched_rq[i];
spin_lock(&rq->lock);
list_for_each_entry(s_entity, &rq->entities, list)
@@ -1150,7 +1193,7 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
*/
s_entity->stopped = true;
spin_unlock(&rq->lock);
-
+ kfree(sched->sched_rq[i]);
}
/* Wakeup everyone stuck in drm_sched_entity_flush for this scheduler */
@@ -1160,6 +1203,8 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
cancel_delayed_work_sync(&sched->work_tdr);
sched->ready = false;
+ kfree(sched->sched_rq);
+ sched->sched_rq = NULL;
}
EXPORT_SYMBOL(drm_sched_fini);
@@ -1186,9 +1231,10 @@ void drm_sched_increase_karma(struct drm_sched_job *bad)
if (bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) {
atomic_inc(&bad->karma);
- for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_KERNEL;
+ for (i = DRM_SCHED_PRIORITY_MIN;
+ i < min_t(typeof(sched->num_rqs), sched->num_rqs, DRM_SCHED_PRIORITY_KERNEL);
i++) {
- struct drm_sched_rq *rq = &sched->sched_rq[i];
+ struct drm_sched_rq *rq = sched->sched_rq[i];
spin_lock(&rq->lock);
list_for_each_entry_safe(entity, tmp, &rq->entities, list) {