162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2015 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1262306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#ifndef _DRM_GPU_SCHEDULER_H_ 2562306a36Sopenharmony_ci#define _DRM_GPU_SCHEDULER_H_ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <drm/spsc_queue.h> 2862306a36Sopenharmony_ci#include <linux/dma-fence.h> 2962306a36Sopenharmony_ci#include <linux/completion.h> 3062306a36Sopenharmony_ci#include <linux/xarray.h> 3162306a36Sopenharmony_ci#include <linux/workqueue.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define MAX_WAIT_SCHED_ENTITY_Q_EMPTY msecs_to_jiffies(1000) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/** 3662306a36Sopenharmony_ci * DRM_SCHED_FENCE_DONT_PIPELINE - Prefent dependency pipelining 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Setting this flag on a scheduler fence prevents pipelining of jobs depending 3962306a36Sopenharmony_ci * on this fence. In other words we always insert a full CPU round trip before 4062306a36Sopenharmony_ci * dependen jobs are pushed to the hw queue. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci#define DRM_SCHED_FENCE_DONT_PIPELINE DMA_FENCE_FLAG_USER_BITS 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/** 4562306a36Sopenharmony_ci * DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT - A fence deadline hint has been set 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * Because we could have a deadline hint can be set before the backing hw 4862306a36Sopenharmony_ci * fence is created, we need to keep track of whether a deadline has already 4962306a36Sopenharmony_ci * been set. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci#define DRM_SCHED_FENCE_FLAG_HAS_DEADLINE_BIT (DMA_FENCE_FLAG_USER_BITS + 1) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cienum dma_resv_usage; 5462306a36Sopenharmony_cistruct dma_resv; 5562306a36Sopenharmony_cistruct drm_gem_object; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct drm_gpu_scheduler; 5862306a36Sopenharmony_cistruct drm_sched_rq; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistruct drm_file; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* These are often used as an (initial) index 6362306a36Sopenharmony_ci * to an array, and as such should start at 0. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_cienum drm_sched_priority { 6662306a36Sopenharmony_ci DRM_SCHED_PRIORITY_MIN, 6762306a36Sopenharmony_ci DRM_SCHED_PRIORITY_NORMAL, 6862306a36Sopenharmony_ci DRM_SCHED_PRIORITY_HIGH, 6962306a36Sopenharmony_ci DRM_SCHED_PRIORITY_KERNEL, 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci DRM_SCHED_PRIORITY_COUNT 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* Used to chose between FIFO and RR jobs scheduling */ 7562306a36Sopenharmony_ciextern int drm_sched_policy; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define DRM_SCHED_POLICY_RR 0 7862306a36Sopenharmony_ci#define DRM_SCHED_POLICY_FIFO 1 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/** 8162306a36Sopenharmony_ci * struct drm_sched_entity - A wrapper around a job queue (typically 8262306a36Sopenharmony_ci * attached to the DRM file_priv). 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * Entities will emit jobs in order to their corresponding hardware 8562306a36Sopenharmony_ci * ring, and the scheduler will alternate between entities based on 8662306a36Sopenharmony_ci * scheduling policy. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistruct drm_sched_entity { 8962306a36Sopenharmony_ci /** 9062306a36Sopenharmony_ci * @list: 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * Used to append this struct to the list of entities in the runqueue 9362306a36Sopenharmony_ci * @rq under &drm_sched_rq.entities. 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * Protected by &drm_sched_rq.lock of @rq. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci struct list_head list; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /** 10062306a36Sopenharmony_ci * @rq: 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci * Runqueue on which this entity is currently scheduled. 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * FIXME: Locking is very unclear for this. Writers are protected by 10562306a36Sopenharmony_ci * @rq_lock, but readers are generally lockless and seem to just race 10662306a36Sopenharmony_ci * with not even a READ_ONCE. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci struct drm_sched_rq *rq; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /** 11162306a36Sopenharmony_ci * @sched_list: 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * A list of schedulers (struct drm_gpu_scheduler). Jobs from this entity can 11462306a36Sopenharmony_ci * be scheduled on any scheduler on this list. 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * This can be modified by calling drm_sched_entity_modify_sched(). 11762306a36Sopenharmony_ci * Locking is entirely up to the driver, see the above function for more 11862306a36Sopenharmony_ci * details. 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * This will be set to NULL if &num_sched_list equals 1 and @rq has been 12162306a36Sopenharmony_ci * set already. 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * FIXME: This means priority changes through 12462306a36Sopenharmony_ci * drm_sched_entity_set_priority() will be lost henceforth in this case. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci struct drm_gpu_scheduler **sched_list; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /** 12962306a36Sopenharmony_ci * @num_sched_list: 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * Number of drm_gpu_schedulers in the @sched_list. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci unsigned int num_sched_list; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /** 13662306a36Sopenharmony_ci * @priority: 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * Priority of the entity. This can be modified by calling 13962306a36Sopenharmony_ci * drm_sched_entity_set_priority(). Protected by &rq_lock. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci enum drm_sched_priority priority; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /** 14462306a36Sopenharmony_ci * @rq_lock: 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * Lock to modify the runqueue to which this entity belongs. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci spinlock_t rq_lock; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /** 15162306a36Sopenharmony_ci * @job_queue: the list of jobs of this entity. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci struct spsc_queue job_queue; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /** 15662306a36Sopenharmony_ci * @fence_seq: 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * A linearly increasing seqno incremented with each new 15962306a36Sopenharmony_ci * &drm_sched_fence which is part of the entity. 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * FIXME: Callers of drm_sched_job_arm() need to ensure correct locking, 16262306a36Sopenharmony_ci * this doesn't need to be atomic. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci atomic_t fence_seq; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /** 16762306a36Sopenharmony_ci * @fence_context: 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * A unique context for all the fences which belong to this entity. The 17062306a36Sopenharmony_ci * &drm_sched_fence.scheduled uses the fence_context but 17162306a36Sopenharmony_ci * &drm_sched_fence.finished uses fence_context + 1. 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_ci uint64_t fence_context; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /** 17662306a36Sopenharmony_ci * @dependency: 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * The dependency fence of the job which is on the top of the job queue. 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_ci struct dma_fence *dependency; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /** 18362306a36Sopenharmony_ci * @cb: 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * Callback for the dependency fence above. 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci struct dma_fence_cb cb; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /** 19062306a36Sopenharmony_ci * @guilty: 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * Points to entities' guilty. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci atomic_t *guilty; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /** 19762306a36Sopenharmony_ci * @last_scheduled: 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * Points to the finished fence of the last scheduled job. Only written 20062306a36Sopenharmony_ci * by the scheduler thread, can be accessed locklessly from 20162306a36Sopenharmony_ci * drm_sched_job_arm() iff the queue is empty. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci struct dma_fence __rcu *last_scheduled; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /** 20662306a36Sopenharmony_ci * @last_user: last group leader pushing a job into the entity. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci struct task_struct *last_user; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /** 21162306a36Sopenharmony_ci * @stopped: 21262306a36Sopenharmony_ci * 21362306a36Sopenharmony_ci * Marks the enity as removed from rq and destined for 21462306a36Sopenharmony_ci * termination. This is set by calling drm_sched_entity_flush() and by 21562306a36Sopenharmony_ci * drm_sched_fini(). 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci bool stopped; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /** 22062306a36Sopenharmony_ci * @entity_idle: 22162306a36Sopenharmony_ci * 22262306a36Sopenharmony_ci * Signals when entity is not in use, used to sequence entity cleanup in 22362306a36Sopenharmony_ci * drm_sched_entity_fini(). 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci struct completion entity_idle; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /** 22862306a36Sopenharmony_ci * @oldest_job_waiting: 22962306a36Sopenharmony_ci * 23062306a36Sopenharmony_ci * Marks earliest job waiting in SW queue 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci ktime_t oldest_job_waiting; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /** 23562306a36Sopenharmony_ci * @rb_tree_node: 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci * The node used to insert this entity into time based priority queue 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci struct rb_node rb_tree_node; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/** 24462306a36Sopenharmony_ci * struct drm_sched_rq - queue of entities to be scheduled. 24562306a36Sopenharmony_ci * 24662306a36Sopenharmony_ci * @lock: to modify the entities list. 24762306a36Sopenharmony_ci * @sched: the scheduler to which this rq belongs to. 24862306a36Sopenharmony_ci * @entities: list of the entities to be scheduled. 24962306a36Sopenharmony_ci * @current_entity: the entity which is to be scheduled. 25062306a36Sopenharmony_ci * @rb_tree_root: root of time based priory queue of entities for FIFO scheduling 25162306a36Sopenharmony_ci * 25262306a36Sopenharmony_ci * Run queue is a set of entities scheduling command submissions for 25362306a36Sopenharmony_ci * one specific ring. It implements the scheduling policy that selects 25462306a36Sopenharmony_ci * the next entity to emit commands from. 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_cistruct drm_sched_rq { 25762306a36Sopenharmony_ci spinlock_t lock; 25862306a36Sopenharmony_ci struct drm_gpu_scheduler *sched; 25962306a36Sopenharmony_ci struct list_head entities; 26062306a36Sopenharmony_ci struct drm_sched_entity *current_entity; 26162306a36Sopenharmony_ci struct rb_root_cached rb_tree_root; 26262306a36Sopenharmony_ci}; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/** 26562306a36Sopenharmony_ci * struct drm_sched_fence - fences corresponding to the scheduling of a job. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_cistruct drm_sched_fence { 26862306a36Sopenharmony_ci /** 26962306a36Sopenharmony_ci * @scheduled: this fence is what will be signaled by the scheduler 27062306a36Sopenharmony_ci * when the job is scheduled. 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_ci struct dma_fence scheduled; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /** 27562306a36Sopenharmony_ci * @finished: this fence is what will be signaled by the scheduler 27662306a36Sopenharmony_ci * when the job is completed. 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * When setting up an out fence for the job, you should use 27962306a36Sopenharmony_ci * this, since it's available immediately upon 28062306a36Sopenharmony_ci * drm_sched_job_init(), and the fence returned by the driver 28162306a36Sopenharmony_ci * from run_job() won't be created until the dependencies have 28262306a36Sopenharmony_ci * resolved. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci struct dma_fence finished; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /** 28762306a36Sopenharmony_ci * @deadline: deadline set on &drm_sched_fence.finished which 28862306a36Sopenharmony_ci * potentially needs to be propagated to &drm_sched_fence.parent 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci ktime_t deadline; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /** 29362306a36Sopenharmony_ci * @parent: the fence returned by &drm_sched_backend_ops.run_job 29462306a36Sopenharmony_ci * when scheduling the job on hardware. We signal the 29562306a36Sopenharmony_ci * &drm_sched_fence.finished fence once parent is signalled. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ci struct dma_fence *parent; 29862306a36Sopenharmony_ci /** 29962306a36Sopenharmony_ci * @sched: the scheduler instance to which the job having this struct 30062306a36Sopenharmony_ci * belongs to. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci struct drm_gpu_scheduler *sched; 30362306a36Sopenharmony_ci /** 30462306a36Sopenharmony_ci * @lock: the lock used by the scheduled and the finished fences. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci spinlock_t lock; 30762306a36Sopenharmony_ci /** 30862306a36Sopenharmony_ci * @owner: job owner for debugging 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci void *owner; 31162306a36Sopenharmony_ci}; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistruct drm_sched_fence *to_drm_sched_fence(struct dma_fence *f); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/** 31662306a36Sopenharmony_ci * struct drm_sched_job - A job to be run by an entity. 31762306a36Sopenharmony_ci * 31862306a36Sopenharmony_ci * @queue_node: used to append this struct to the queue of jobs in an entity. 31962306a36Sopenharmony_ci * @list: a job participates in a "pending" and "done" lists. 32062306a36Sopenharmony_ci * @sched: the scheduler instance on which this job is scheduled. 32162306a36Sopenharmony_ci * @s_fence: contains the fences for the scheduling of job. 32262306a36Sopenharmony_ci * @finish_cb: the callback for the finished fence. 32362306a36Sopenharmony_ci * @work: Helper to reschdeule job kill to different context. 32462306a36Sopenharmony_ci * @id: a unique id assigned to each job scheduled on the scheduler. 32562306a36Sopenharmony_ci * @karma: increment on every hang caused by this job. If this exceeds the hang 32662306a36Sopenharmony_ci * limit of the scheduler then the job is marked guilty and will not 32762306a36Sopenharmony_ci * be scheduled further. 32862306a36Sopenharmony_ci * @s_priority: the priority of the job. 32962306a36Sopenharmony_ci * @entity: the entity to which this job belongs. 33062306a36Sopenharmony_ci * @cb: the callback for the parent fence in s_fence. 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci * A job is created by the driver using drm_sched_job_init(), and 33362306a36Sopenharmony_ci * should call drm_sched_entity_push_job() once it wants the scheduler 33462306a36Sopenharmony_ci * to schedule the job. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_cistruct drm_sched_job { 33762306a36Sopenharmony_ci struct spsc_node queue_node; 33862306a36Sopenharmony_ci struct list_head list; 33962306a36Sopenharmony_ci struct drm_gpu_scheduler *sched; 34062306a36Sopenharmony_ci struct drm_sched_fence *s_fence; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* 34362306a36Sopenharmony_ci * work is used only after finish_cb has been used and will not be 34462306a36Sopenharmony_ci * accessed anymore. 34562306a36Sopenharmony_ci */ 34662306a36Sopenharmony_ci union { 34762306a36Sopenharmony_ci struct dma_fence_cb finish_cb; 34862306a36Sopenharmony_ci struct work_struct work; 34962306a36Sopenharmony_ci }; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci uint64_t id; 35262306a36Sopenharmony_ci atomic_t karma; 35362306a36Sopenharmony_ci enum drm_sched_priority s_priority; 35462306a36Sopenharmony_ci struct drm_sched_entity *entity; 35562306a36Sopenharmony_ci struct dma_fence_cb cb; 35662306a36Sopenharmony_ci /** 35762306a36Sopenharmony_ci * @dependencies: 35862306a36Sopenharmony_ci * 35962306a36Sopenharmony_ci * Contains the dependencies as struct dma_fence for this job, see 36062306a36Sopenharmony_ci * drm_sched_job_add_dependency() and 36162306a36Sopenharmony_ci * drm_sched_job_add_implicit_dependencies(). 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci struct xarray dependencies; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /** @last_dependency: tracks @dependencies as they signal */ 36662306a36Sopenharmony_ci unsigned long last_dependency; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /** 36962306a36Sopenharmony_ci * @submit_ts: 37062306a36Sopenharmony_ci * 37162306a36Sopenharmony_ci * When the job was pushed into the entity queue. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_ci ktime_t submit_ts; 37462306a36Sopenharmony_ci}; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic inline bool drm_sched_invalidate_job(struct drm_sched_job *s_job, 37762306a36Sopenharmony_ci int threshold) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci return s_job && atomic_inc_return(&s_job->karma) > threshold; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cienum drm_gpu_sched_stat { 38362306a36Sopenharmony_ci DRM_GPU_SCHED_STAT_NONE, /* Reserve 0 */ 38462306a36Sopenharmony_ci DRM_GPU_SCHED_STAT_NOMINAL, 38562306a36Sopenharmony_ci DRM_GPU_SCHED_STAT_ENODEV, 38662306a36Sopenharmony_ci}; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/** 38962306a36Sopenharmony_ci * struct drm_sched_backend_ops - Define the backend operations 39062306a36Sopenharmony_ci * called by the scheduler 39162306a36Sopenharmony_ci * 39262306a36Sopenharmony_ci * These functions should be implemented in the driver side. 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_cistruct drm_sched_backend_ops { 39562306a36Sopenharmony_ci /** 39662306a36Sopenharmony_ci * @prepare_job: 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * Called when the scheduler is considering scheduling this job next, to 39962306a36Sopenharmony_ci * get another struct dma_fence for this job to block on. Once it 40062306a36Sopenharmony_ci * returns NULL, run_job() may be called. 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci * Can be NULL if no additional preparation to the dependencies are 40362306a36Sopenharmony_ci * necessary. Skipped when jobs are killed instead of run. 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_ci struct dma_fence *(*prepare_job)(struct drm_sched_job *sched_job, 40662306a36Sopenharmony_ci struct drm_sched_entity *s_entity); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /** 40962306a36Sopenharmony_ci * @run_job: Called to execute the job once all of the dependencies 41062306a36Sopenharmony_ci * have been resolved. This may be called multiple times, if 41162306a36Sopenharmony_ci * timedout_job() has happened and drm_sched_job_recovery() 41262306a36Sopenharmony_ci * decides to try it again. 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_ci struct dma_fence *(*run_job)(struct drm_sched_job *sched_job); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /** 41762306a36Sopenharmony_ci * @timedout_job: Called when a job has taken too long to execute, 41862306a36Sopenharmony_ci * to trigger GPU recovery. 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * This method is called in a workqueue context. 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * Drivers typically issue a reset to recover from GPU hangs, and this 42362306a36Sopenharmony_ci * procedure usually follows the following workflow: 42462306a36Sopenharmony_ci * 42562306a36Sopenharmony_ci * 1. Stop the scheduler using drm_sched_stop(). This will park the 42662306a36Sopenharmony_ci * scheduler thread and cancel the timeout work, guaranteeing that 42762306a36Sopenharmony_ci * nothing is queued while we reset the hardware queue 42862306a36Sopenharmony_ci * 2. Try to gracefully stop non-faulty jobs (optional) 42962306a36Sopenharmony_ci * 3. Issue a GPU reset (driver-specific) 43062306a36Sopenharmony_ci * 4. Re-submit jobs using drm_sched_resubmit_jobs() 43162306a36Sopenharmony_ci * 5. Restart the scheduler using drm_sched_start(). At that point, new 43262306a36Sopenharmony_ci * jobs can be queued, and the scheduler thread is unblocked 43362306a36Sopenharmony_ci * 43462306a36Sopenharmony_ci * Note that some GPUs have distinct hardware queues but need to reset 43562306a36Sopenharmony_ci * the GPU globally, which requires extra synchronization between the 43662306a36Sopenharmony_ci * timeout handler of the different &drm_gpu_scheduler. One way to 43762306a36Sopenharmony_ci * achieve this synchronization is to create an ordered workqueue 43862306a36Sopenharmony_ci * (using alloc_ordered_workqueue()) at the driver level, and pass this 43962306a36Sopenharmony_ci * queue to drm_sched_init(), to guarantee that timeout handlers are 44062306a36Sopenharmony_ci * executed sequentially. The above workflow needs to be slightly 44162306a36Sopenharmony_ci * adjusted in that case: 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * 1. Stop all schedulers impacted by the reset using drm_sched_stop() 44462306a36Sopenharmony_ci * 2. Try to gracefully stop non-faulty jobs on all queues impacted by 44562306a36Sopenharmony_ci * the reset (optional) 44662306a36Sopenharmony_ci * 3. Issue a GPU reset on all faulty queues (driver-specific) 44762306a36Sopenharmony_ci * 4. Re-submit jobs on all schedulers impacted by the reset using 44862306a36Sopenharmony_ci * drm_sched_resubmit_jobs() 44962306a36Sopenharmony_ci * 5. Restart all schedulers that were stopped in step #1 using 45062306a36Sopenharmony_ci * drm_sched_start() 45162306a36Sopenharmony_ci * 45262306a36Sopenharmony_ci * Return DRM_GPU_SCHED_STAT_NOMINAL, when all is normal, 45362306a36Sopenharmony_ci * and the underlying driver has started or completed recovery. 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * Return DRM_GPU_SCHED_STAT_ENODEV, if the device is no longer 45662306a36Sopenharmony_ci * available, i.e. has been unplugged. 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_ci enum drm_gpu_sched_stat (*timedout_job)(struct drm_sched_job *sched_job); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /** 46162306a36Sopenharmony_ci * @free_job: Called once the job's finished fence has been signaled 46262306a36Sopenharmony_ci * and it's time to clean it up. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci void (*free_job)(struct drm_sched_job *sched_job); 46562306a36Sopenharmony_ci}; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci/** 46862306a36Sopenharmony_ci * struct drm_gpu_scheduler - scheduler instance-specific data 46962306a36Sopenharmony_ci * 47062306a36Sopenharmony_ci * @ops: backend operations provided by the driver. 47162306a36Sopenharmony_ci * @hw_submission_limit: the max size of the hardware queue. 47262306a36Sopenharmony_ci * @timeout: the time after which a job is removed from the scheduler. 47362306a36Sopenharmony_ci * @name: name of the ring for which this scheduler is being used. 47462306a36Sopenharmony_ci * @sched_rq: priority wise array of run queues. 47562306a36Sopenharmony_ci * @wake_up_worker: the wait queue on which the scheduler sleeps until a job 47662306a36Sopenharmony_ci * is ready to be scheduled. 47762306a36Sopenharmony_ci * @job_scheduled: once @drm_sched_entity_do_release is called the scheduler 47862306a36Sopenharmony_ci * waits on this wait queue until all the scheduled jobs are 47962306a36Sopenharmony_ci * finished. 48062306a36Sopenharmony_ci * @hw_rq_count: the number of jobs currently in the hardware queue. 48162306a36Sopenharmony_ci * @job_id_count: used to assign unique id to the each job. 48262306a36Sopenharmony_ci * @timeout_wq: workqueue used to queue @work_tdr 48362306a36Sopenharmony_ci * @work_tdr: schedules a delayed call to @drm_sched_job_timedout after the 48462306a36Sopenharmony_ci * timeout interval is over. 48562306a36Sopenharmony_ci * @thread: the kthread on which the scheduler which run. 48662306a36Sopenharmony_ci * @pending_list: the list of jobs which are currently in the job queue. 48762306a36Sopenharmony_ci * @job_list_lock: lock to protect the pending_list. 48862306a36Sopenharmony_ci * @hang_limit: once the hangs by a job crosses this limit then it is marked 48962306a36Sopenharmony_ci * guilty and it will no longer be considered for scheduling. 49062306a36Sopenharmony_ci * @score: score to help loadbalancer pick a idle sched 49162306a36Sopenharmony_ci * @_score: score used when the driver doesn't provide one 49262306a36Sopenharmony_ci * @ready: marks if the underlying HW is ready to work 49362306a36Sopenharmony_ci * @free_guilty: A hit to time out handler to free the guilty job. 49462306a36Sopenharmony_ci * @dev: system &struct device 49562306a36Sopenharmony_ci * 49662306a36Sopenharmony_ci * One scheduler is implemented for each hardware ring. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_cistruct drm_gpu_scheduler { 49962306a36Sopenharmony_ci const struct drm_sched_backend_ops *ops; 50062306a36Sopenharmony_ci uint32_t hw_submission_limit; 50162306a36Sopenharmony_ci long timeout; 50262306a36Sopenharmony_ci const char *name; 50362306a36Sopenharmony_ci struct drm_sched_rq sched_rq[DRM_SCHED_PRIORITY_COUNT]; 50462306a36Sopenharmony_ci wait_queue_head_t wake_up_worker; 50562306a36Sopenharmony_ci wait_queue_head_t job_scheduled; 50662306a36Sopenharmony_ci atomic_t hw_rq_count; 50762306a36Sopenharmony_ci atomic64_t job_id_count; 50862306a36Sopenharmony_ci struct workqueue_struct *timeout_wq; 50962306a36Sopenharmony_ci struct delayed_work work_tdr; 51062306a36Sopenharmony_ci struct task_struct *thread; 51162306a36Sopenharmony_ci struct list_head pending_list; 51262306a36Sopenharmony_ci spinlock_t job_list_lock; 51362306a36Sopenharmony_ci int hang_limit; 51462306a36Sopenharmony_ci atomic_t *score; 51562306a36Sopenharmony_ci atomic_t _score; 51662306a36Sopenharmony_ci bool ready; 51762306a36Sopenharmony_ci bool free_guilty; 51862306a36Sopenharmony_ci struct device *dev; 51962306a36Sopenharmony_ci}; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ciint drm_sched_init(struct drm_gpu_scheduler *sched, 52262306a36Sopenharmony_ci const struct drm_sched_backend_ops *ops, 52362306a36Sopenharmony_ci uint32_t hw_submission, unsigned hang_limit, 52462306a36Sopenharmony_ci long timeout, struct workqueue_struct *timeout_wq, 52562306a36Sopenharmony_ci atomic_t *score, const char *name, struct device *dev); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_civoid drm_sched_fini(struct drm_gpu_scheduler *sched); 52862306a36Sopenharmony_ciint drm_sched_job_init(struct drm_sched_job *job, 52962306a36Sopenharmony_ci struct drm_sched_entity *entity, 53062306a36Sopenharmony_ci void *owner); 53162306a36Sopenharmony_civoid drm_sched_job_arm(struct drm_sched_job *job); 53262306a36Sopenharmony_ciint drm_sched_job_add_dependency(struct drm_sched_job *job, 53362306a36Sopenharmony_ci struct dma_fence *fence); 53462306a36Sopenharmony_ciint drm_sched_job_add_syncobj_dependency(struct drm_sched_job *job, 53562306a36Sopenharmony_ci struct drm_file *file, 53662306a36Sopenharmony_ci u32 handle, 53762306a36Sopenharmony_ci u32 point); 53862306a36Sopenharmony_ciint drm_sched_job_add_resv_dependencies(struct drm_sched_job *job, 53962306a36Sopenharmony_ci struct dma_resv *resv, 54062306a36Sopenharmony_ci enum dma_resv_usage usage); 54162306a36Sopenharmony_ciint drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job, 54262306a36Sopenharmony_ci struct drm_gem_object *obj, 54362306a36Sopenharmony_ci bool write); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_civoid drm_sched_entity_modify_sched(struct drm_sched_entity *entity, 54762306a36Sopenharmony_ci struct drm_gpu_scheduler **sched_list, 54862306a36Sopenharmony_ci unsigned int num_sched_list); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_civoid drm_sched_job_cleanup(struct drm_sched_job *job); 55162306a36Sopenharmony_civoid drm_sched_wakeup_if_can_queue(struct drm_gpu_scheduler *sched); 55262306a36Sopenharmony_civoid drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad); 55362306a36Sopenharmony_civoid drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery); 55462306a36Sopenharmony_civoid drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched); 55562306a36Sopenharmony_civoid drm_sched_increase_karma(struct drm_sched_job *bad); 55662306a36Sopenharmony_civoid drm_sched_reset_karma(struct drm_sched_job *bad); 55762306a36Sopenharmony_civoid drm_sched_increase_karma_ext(struct drm_sched_job *bad, int type); 55862306a36Sopenharmony_cibool drm_sched_dependency_optimized(struct dma_fence* fence, 55962306a36Sopenharmony_ci struct drm_sched_entity *entity); 56062306a36Sopenharmony_civoid drm_sched_fault(struct drm_gpu_scheduler *sched); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_civoid drm_sched_rq_add_entity(struct drm_sched_rq *rq, 56362306a36Sopenharmony_ci struct drm_sched_entity *entity); 56462306a36Sopenharmony_civoid drm_sched_rq_remove_entity(struct drm_sched_rq *rq, 56562306a36Sopenharmony_ci struct drm_sched_entity *entity); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_civoid drm_sched_rq_update_fifo(struct drm_sched_entity *entity, ktime_t ts); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ciint drm_sched_entity_init(struct drm_sched_entity *entity, 57062306a36Sopenharmony_ci enum drm_sched_priority priority, 57162306a36Sopenharmony_ci struct drm_gpu_scheduler **sched_list, 57262306a36Sopenharmony_ci unsigned int num_sched_list, 57362306a36Sopenharmony_ci atomic_t *guilty); 57462306a36Sopenharmony_cilong drm_sched_entity_flush(struct drm_sched_entity *entity, long timeout); 57562306a36Sopenharmony_civoid drm_sched_entity_fini(struct drm_sched_entity *entity); 57662306a36Sopenharmony_civoid drm_sched_entity_destroy(struct drm_sched_entity *entity); 57762306a36Sopenharmony_civoid drm_sched_entity_select_rq(struct drm_sched_entity *entity); 57862306a36Sopenharmony_cistruct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity); 57962306a36Sopenharmony_civoid drm_sched_entity_push_job(struct drm_sched_job *sched_job); 58062306a36Sopenharmony_civoid drm_sched_entity_set_priority(struct drm_sched_entity *entity, 58162306a36Sopenharmony_ci enum drm_sched_priority priority); 58262306a36Sopenharmony_cibool drm_sched_entity_is_ready(struct drm_sched_entity *entity); 58362306a36Sopenharmony_ciint drm_sched_entity_error(struct drm_sched_entity *entity); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistruct drm_sched_fence *drm_sched_fence_alloc( 58662306a36Sopenharmony_ci struct drm_sched_entity *s_entity, void *owner); 58762306a36Sopenharmony_civoid drm_sched_fence_init(struct drm_sched_fence *fence, 58862306a36Sopenharmony_ci struct drm_sched_entity *entity); 58962306a36Sopenharmony_civoid drm_sched_fence_free(struct drm_sched_fence *fence); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_civoid drm_sched_fence_scheduled(struct drm_sched_fence *fence, 59262306a36Sopenharmony_ci struct dma_fence *parent); 59362306a36Sopenharmony_civoid drm_sched_fence_finished(struct drm_sched_fence *fence, int result); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ciunsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched); 59662306a36Sopenharmony_civoid drm_sched_resume_timeout(struct drm_gpu_scheduler *sched, 59762306a36Sopenharmony_ci unsigned long remaining); 59862306a36Sopenharmony_cistruct drm_gpu_scheduler * 59962306a36Sopenharmony_cidrm_sched_pick_best(struct drm_gpu_scheduler **sched_list, 60062306a36Sopenharmony_ci unsigned int num_sched_list); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci#endif 603