| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067 |
- /*
- * This confidential and proprietary software may be used only as
- * authorised by a licensing agreement from ARM Limited
- * (C) COPYRIGHT 2012-2013 ARM Limited
- * ALL RIGHTS RESERVED
- * The entire notice above must be reproduced on all authorised
- * copies and copies may only be made to the extent permitted
- * by a licensing agreement from ARM Limited.
- */
- #include "mali_pp_scheduler.h"
- #include "mali_kernel_common.h"
- #include "mali_kernel_core.h"
- #include "mali_osk.h"
- #include "mali_osk_list.h"
- #include "mali_scheduler.h"
- #include "mali_pp.h"
- #include "mali_pp_job.h"
- #include "mali_group.h"
- #include "mali_pm.h"
- #include "mali_timeline.h"
- #include "mali_osk_profiling.h"
- #include "mali_kernel_utilization.h"
- #include "mali_session.h"
- #include "mali_pm_domain.h"
- #include "linux/mali/mali_utgard.h"
- #if defined(CONFIG_DMA_SHARED_BUFFER)
- #include "mali_memory_dma_buf.h"
- #endif
- #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
- #include <linux/sched.h>
- #include <trace/events/gpu.h>
- #endif
- /* Queue type used for physical and virtual job queues. */
- struct mali_pp_scheduler_job_queue {
- _MALI_OSK_LIST_HEAD(normal_pri); /* List of jobs with some unscheduled work. */
- _MALI_OSK_LIST_HEAD(high_pri); /* List of high priority jobs with some unscheduled work. */
- u32 depth; /* Depth of combined queues. */
- };
- /* If dma_buf with map on demand is used, we defer job deletion and job queue if in atomic context,
- * since both might sleep. */
- #if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH)
- #define MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE 1
- #define MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE 1
- #endif /* !defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) */
- static void mali_pp_scheduler_job_queued(void);
- static void mali_pp_scheduler_job_completed(void);
- /* Maximum of 8 PP cores (a group can only have maximum of 1 PP core) */
- #define MALI_MAX_NUMBER_OF_PP_GROUPS 9
- static mali_bool mali_pp_scheduler_is_suspended(void *data);
- static u32 pp_version = 0;
- /* Physical job queue */
- static struct mali_pp_scheduler_job_queue job_queue;
- /* Physical groups */
- static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_working); /* List of physical groups with working jobs on the pp core */
- static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_idle); /* List of physical groups with idle jobs on the pp core */
- static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_disabled); /* List of disabled physical groups */
- /* Virtual job queue (Mali-450 only) */
- static struct mali_pp_scheduler_job_queue virtual_job_queue;
- /**
- * Add job to scheduler queue.
- *
- * @param job Job to queue.
- * @return Schedule mask.
- */
- static mali_scheduler_mask mali_pp_scheduler_queue_job(struct mali_pp_job *job);
- /* Virtual group (Mali-450 only) */
- static struct mali_group *virtual_group = NULL; /* Virtual group (if any) */
- static enum {
- VIRTUAL_GROUP_IDLE,
- VIRTUAL_GROUP_WORKING,
- VIRTUAL_GROUP_DISABLED,
- }
- virtual_group_state = VIRTUAL_GROUP_IDLE; /* Flag which indicates whether the virtual group is working or idle */
- /* Number of physical cores */
- static u32 num_cores = 0;
- /* Number of physical cores which are enabled */
- static u32 enabled_cores = 0;
- /* Enable or disable core scaling */
- static mali_bool core_scaling_enabled = MALI_TRUE;
- /* Variables to allow safe pausing of the scheduler */
- static _mali_osk_wait_queue_t *pp_scheduler_working_wait_queue = NULL;
- static u32 pause_count = 0;
- #if defined(MALI_UPPER_HALF_SCHEDULING)
- static _mali_osk_spinlock_irq_t *pp_scheduler_lock = NULL;
- #else
- static _mali_osk_spinlock_t *pp_scheduler_lock = NULL;
- #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
- MALI_STATIC_INLINE void mali_pp_scheduler_lock(void)
- {
- #if defined(MALI_UPPER_HALF_SCHEDULING)
- _mali_osk_spinlock_irq_lock(pp_scheduler_lock);
- #else
- _mali_osk_spinlock_lock(pp_scheduler_lock);
- #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
- MALI_DEBUG_PRINT(5, ("Mali PP scheduler: PP scheduler lock taken.\n"));
- }
- MALI_STATIC_INLINE void mali_pp_scheduler_unlock(void)
- {
- MALI_DEBUG_PRINT(5, ("Mali PP scheduler: Releasing PP scheduler lock.\n"));
- #if defined(MALI_UPPER_HALF_SCHEDULING)
- _mali_osk_spinlock_irq_unlock(pp_scheduler_lock);
- #else
- _mali_osk_spinlock_unlock(pp_scheduler_lock);
- #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
- }
- #if defined(DEBUG)
- #define MALI_ASSERT_PP_SCHEDULER_LOCKED() MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock)
- #else
- #define MALI_ASSERT_PP_SCHEDULER_LOCKED() do {} while (0)
- #endif /* defined(DEBUG) */
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
- static _mali_osk_wq_work_t *pp_scheduler_wq_job_delete = NULL;
- static _mali_osk_spinlock_irq_t *pp_scheduler_job_delete_lock = NULL;
- static _MALI_OSK_LIST_HEAD_STATIC_INIT(pp_scheduler_job_deletion_queue);
- static void mali_pp_scheduler_deferred_job_delete(struct mali_pp_job *job)
- {
- MALI_DEBUG_ASSERT_POINTER(job);
- _mali_osk_spinlock_irq_lock(pp_scheduler_job_delete_lock);
- /* This job object should not be on any lists. */
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list));
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_list));
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_fb_lookup_list));
- _mali_osk_list_addtail(&job->list, &pp_scheduler_job_deletion_queue);
- _mali_osk_spinlock_irq_unlock(pp_scheduler_job_delete_lock);
- _mali_osk_wq_schedule_work(pp_scheduler_wq_job_delete);
- }
- static void mali_pp_scheduler_do_job_delete(void *arg)
- {
- _MALI_OSK_LIST_HEAD_STATIC_INIT(list);
- struct mali_pp_job *job;
- struct mali_pp_job *tmp;
- MALI_IGNORE(arg);
- _mali_osk_spinlock_irq_lock(pp_scheduler_job_delete_lock);
- /*
- * Quickly "unhook" the jobs pending to be deleted, so we can release the lock before
- * we start deleting the job objects (without any locks held
- */
- _mali_osk_list_move_list(&pp_scheduler_job_deletion_queue, &list);
- _mali_osk_spinlock_irq_unlock(pp_scheduler_job_delete_lock);
- _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &list, struct mali_pp_job, list) {
- mali_pp_job_delete(job); /* delete the job object itself */
- }
- }
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
- static _mali_osk_wq_work_t *pp_scheduler_wq_job_queue = NULL;
- static _mali_osk_spinlock_irq_t *pp_scheduler_job_queue_lock = NULL;
- static _MALI_OSK_LIST_HEAD_STATIC_INIT(pp_scheduler_job_queue_list);
- static void mali_pp_scheduler_deferred_job_queue(struct mali_pp_job *job)
- {
- MALI_DEBUG_ASSERT_POINTER(job);
- _mali_osk_spinlock_irq_lock(pp_scheduler_job_queue_lock);
- _mali_osk_list_addtail(&job->list, &pp_scheduler_job_queue_list);
- _mali_osk_spinlock_irq_unlock(pp_scheduler_job_queue_lock);
- _mali_osk_wq_schedule_work(pp_scheduler_wq_job_queue);
- }
- static void mali_pp_scheduler_do_job_queue(void *arg)
- {
- _MALI_OSK_LIST_HEAD_STATIC_INIT(list);
- struct mali_pp_job *job;
- struct mali_pp_job *tmp;
- mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
- MALI_IGNORE(arg);
- _mali_osk_spinlock_irq_lock(pp_scheduler_job_queue_lock);
- /*
- * Quickly "unhook" the jobs pending to be queued, so we can release the lock before
- * we start queueing the job objects (without any locks held)
- */
- _mali_osk_list_move_list(&pp_scheduler_job_queue_list, &list);
- _mali_osk_spinlock_irq_unlock(pp_scheduler_job_queue_lock);
- _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &list, struct mali_pp_job, list) {
- _mali_osk_list_delinit(&job->list);
- schedule_mask |= mali_pp_scheduler_queue_job(job);
- }
- mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE);
- }
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
- MALI_STATIC_INLINE mali_bool mali_pp_scheduler_has_virtual_group(void)
- {
- #if (defined(CONFIG_MALI450) || defined(CONFIG_MALI470))
- return NULL != virtual_group;
- #else
- return MALI_FALSE;
- #endif /* defined(CONFIG_MALI450) || defined(CONFIG_MALI470) */
- }
- _mali_osk_errcode_t mali_pp_scheduler_initialize(void)
- {
- _MALI_OSK_INIT_LIST_HEAD(&job_queue.normal_pri);
- _MALI_OSK_INIT_LIST_HEAD(&job_queue.high_pri);
- job_queue.depth = 0;
- _MALI_OSK_INIT_LIST_HEAD(&virtual_job_queue.normal_pri);
- _MALI_OSK_INIT_LIST_HEAD(&virtual_job_queue.high_pri);
- virtual_job_queue.depth = 0;
- #if defined(MALI_UPPER_HALF_SCHEDULING)
- pp_scheduler_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER);
- #else
- pp_scheduler_lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER);
- #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
- if (NULL == pp_scheduler_lock) goto cleanup;
- pp_scheduler_working_wait_queue = _mali_osk_wait_queue_init();
- if (NULL == pp_scheduler_working_wait_queue) goto cleanup;
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
- pp_scheduler_wq_job_delete = _mali_osk_wq_create_work(mali_pp_scheduler_do_job_delete, NULL);
- if (NULL == pp_scheduler_wq_job_delete) goto cleanup;
- pp_scheduler_job_delete_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED);
- if (NULL == pp_scheduler_job_delete_lock) goto cleanup;
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
- pp_scheduler_wq_job_queue = _mali_osk_wq_create_work(mali_pp_scheduler_do_job_queue, NULL);
- if (NULL == pp_scheduler_wq_job_queue) goto cleanup;
- pp_scheduler_job_queue_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED);
- if (NULL == pp_scheduler_job_queue_lock) goto cleanup;
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
- return _MALI_OSK_ERR_OK;
- cleanup:
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
- if (NULL != pp_scheduler_job_queue_lock) {
- _mali_osk_spinlock_irq_term(pp_scheduler_job_queue_lock);
- pp_scheduler_job_queue_lock = NULL;
- }
- if (NULL != pp_scheduler_wq_job_queue) {
- _mali_osk_wq_delete_work(pp_scheduler_wq_job_queue);
- pp_scheduler_wq_job_queue = NULL;
- }
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
- if (NULL != pp_scheduler_job_delete_lock) {
- _mali_osk_spinlock_irq_term(pp_scheduler_job_delete_lock);
- pp_scheduler_job_delete_lock = NULL;
- }
- if (NULL != pp_scheduler_wq_job_delete) {
- _mali_osk_wq_delete_work(pp_scheduler_wq_job_delete);
- pp_scheduler_wq_job_delete = NULL;
- }
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */
- if (NULL != pp_scheduler_working_wait_queue) {
- _mali_osk_wait_queue_term(pp_scheduler_working_wait_queue);
- pp_scheduler_working_wait_queue = NULL;
- }
- if (NULL != pp_scheduler_lock) {
- #if defined(MALI_UPPER_HALF_SCHEDULING)
- _mali_osk_spinlock_irq_term(pp_scheduler_lock);
- #else
- _mali_osk_spinlock_term(pp_scheduler_lock);
- #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
- pp_scheduler_lock = NULL;
- }
- return _MALI_OSK_ERR_NOMEM;
- }
- void mali_pp_scheduler_terminate(void)
- {
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
- _mali_osk_spinlock_irq_term(pp_scheduler_job_queue_lock);
- _mali_osk_wq_delete_work(pp_scheduler_wq_job_queue);
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
- _mali_osk_spinlock_irq_term(pp_scheduler_job_delete_lock);
- _mali_osk_wq_delete_work(pp_scheduler_wq_job_delete);
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */
- _mali_osk_wait_queue_term(pp_scheduler_working_wait_queue);
- #if defined(MALI_UPPER_HALF_SCHEDULING)
- _mali_osk_spinlock_irq_term(pp_scheduler_lock);
- #else
- _mali_osk_spinlock_term(pp_scheduler_lock);
- #endif /* defined(MALI_UPPER_HALF_SCHEDULING) */
- }
- void mali_pp_scheduler_populate(void)
- {
- struct mali_group *group;
- struct mali_pp_core *pp_core;
- u32 num_groups;
- u32 i;
- num_groups = mali_group_get_glob_num_groups();
- /* Do we have a virtual group? */
- for (i = 0; i < num_groups; i++) {
- group = mali_group_get_glob_group(i);
- if (mali_group_is_virtual(group)) {
- MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Found virtual group %p.\n", group));
- virtual_group = group;
- break;
- }
- }
- /* Find all the available PP cores */
- for (i = 0; i < num_groups; i++) {
- group = mali_group_get_glob_group(i);
- pp_core = mali_group_get_pp_core(group);
- if (NULL != pp_core && !mali_group_is_virtual(group)) {
- if (0 == pp_version) {
- /* Retrieve PP version from the first available PP core */
- pp_version = mali_pp_core_get_version(pp_core);
- }
- if (mali_pp_scheduler_has_virtual_group()) {
- /* Add all physical PP cores to the virtual group */
- mali_group_lock(virtual_group);
- group->state = MALI_GROUP_STATE_JOINING_VIRTUAL;
- mali_group_add_group(virtual_group, group, MALI_TRUE);
- mali_group_unlock(virtual_group);
- } else {
- _mali_osk_list_add(&group->pp_scheduler_list, &group_list_idle);
- }
- num_cores++;
- }
- }
- enabled_cores = num_cores;
- }
- void mali_pp_scheduler_depopulate(void)
- {
- struct mali_group *group, *temp;
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working));
- MALI_DEBUG_ASSERT(VIRTUAL_GROUP_WORKING != virtual_group_state);
- /* Delete all groups owned by scheduler */
- if (mali_pp_scheduler_has_virtual_group()) {
- mali_group_delete(virtual_group);
- }
- _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, pp_scheduler_list) {
- mali_group_delete(group);
- }
- _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, pp_scheduler_list) {
- mali_group_delete(group);
- }
- }
- MALI_STATIC_INLINE void mali_pp_scheduler_disable_empty_virtual(void)
- {
- MALI_ASSERT_GROUP_LOCKED(virtual_group);
- if (mali_group_virtual_disable_if_empty(virtual_group)) {
- MALI_DEBUG_PRINT(4, ("Disabling empty virtual group\n"));
- MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE == virtual_group_state);
- virtual_group_state = VIRTUAL_GROUP_DISABLED;
- }
- }
- MALI_STATIC_INLINE void mali_pp_scheduler_enable_empty_virtual(void)
- {
- MALI_ASSERT_GROUP_LOCKED(virtual_group);
- if (mali_group_virtual_enable_if_empty(virtual_group)) {
- MALI_DEBUG_PRINT(4, ("Re-enabling empty virtual group\n"));
- MALI_DEBUG_ASSERT(VIRTUAL_GROUP_DISABLED == virtual_group_state);
- virtual_group_state = VIRTUAL_GROUP_IDLE;
- }
- }
- static struct mali_pp_job *mali_pp_scheduler_get_job(struct mali_pp_scheduler_job_queue *queue)
- {
- struct mali_pp_job *job = NULL;
- MALI_ASSERT_PP_SCHEDULER_LOCKED();
- MALI_DEBUG_ASSERT_POINTER(queue);
- /* Check if we have a normal priority job. */
- if (!_mali_osk_list_empty(&queue->normal_pri)) {
- MALI_DEBUG_ASSERT(queue->depth > 0);
- job = _MALI_OSK_LIST_ENTRY(queue->normal_pri.next, struct mali_pp_job, list);
- }
- /* Prefer normal priority job if it is in progress. */
- if (NULL != job && 0 < job->sub_jobs_started) {
- return job;
- }
- /* Check if we have a high priority job. */
- if (!_mali_osk_list_empty(&queue->high_pri)) {
- MALI_DEBUG_ASSERT(queue->depth > 0);
- job = _MALI_OSK_LIST_ENTRY(queue->high_pri.next, struct mali_pp_job, list);
- }
- return job;
- }
- /**
- * Returns a physical job if a physical job is ready to run
- */
- MALI_STATIC_INLINE struct mali_pp_job *mali_pp_scheduler_get_physical_job(void)
- {
- MALI_ASSERT_PP_SCHEDULER_LOCKED();
- return mali_pp_scheduler_get_job(&job_queue);
- }
- MALI_STATIC_INLINE void mali_pp_scheduler_dequeue_physical_job(struct mali_pp_job *job)
- {
- MALI_ASSERT_PP_SCHEDULER_LOCKED();
- MALI_DEBUG_ASSERT(job_queue.depth > 0);
- /* Remove job from queue */
- if (!mali_pp_job_has_unstarted_sub_jobs(job)) {
- /* All sub jobs have been started: remove job from queue */
- _mali_osk_list_delinit(&job->list);
- _mali_osk_list_delinit(&job->session_fb_lookup_list);
- }
- --job_queue.depth;
- }
- /**
- * Returns a virtual job if a virtual job is ready to run
- */
- MALI_STATIC_INLINE struct mali_pp_job *mali_pp_scheduler_get_virtual_job(void)
- {
- MALI_ASSERT_PP_SCHEDULER_LOCKED();
- MALI_DEBUG_ASSERT_POINTER(virtual_group);
- return mali_pp_scheduler_get_job(&virtual_job_queue);
- }
- MALI_STATIC_INLINE void mali_pp_scheduler_dequeue_virtual_job(struct mali_pp_job *job)
- {
- MALI_ASSERT_PP_SCHEDULER_LOCKED();
- MALI_DEBUG_ASSERT(virtual_job_queue.depth > 0);
- /* Remove job from queue */
- _mali_osk_list_delinit(&job->list);
- _mali_osk_list_delinit(&job->session_fb_lookup_list);
- --virtual_job_queue.depth;
- }
- /**
- * Checks if the criteria is met for removing a physical core from virtual group
- */
- MALI_STATIC_INLINE mali_bool mali_pp_scheduler_can_move_virtual_to_physical(void)
- {
- MALI_ASSERT_PP_SCHEDULER_LOCKED();
- MALI_DEBUG_ASSERT(mali_pp_scheduler_has_virtual_group());
- MALI_ASSERT_GROUP_LOCKED(virtual_group);
- /*
- * The criteria for taking out a physical group from a virtual group are the following:
- * - There virtual group is idle
- * - There are currently no physical groups (idle and working)
- * - There are physical jobs to be scheduled
- */
- return (VIRTUAL_GROUP_IDLE == virtual_group_state) &&
- _mali_osk_list_empty(&group_list_idle) &&
- _mali_osk_list_empty(&group_list_working) &&
- (NULL != mali_pp_scheduler_get_physical_job());
- }
- MALI_STATIC_INLINE struct mali_group *mali_pp_scheduler_acquire_physical_group(void)
- {
- MALI_ASSERT_PP_SCHEDULER_LOCKED();
- if (!_mali_osk_list_empty(&group_list_idle)) {
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Acquiring physical group from idle list.\n"));
- return _MALI_OSK_LIST_ENTRY(group_list_idle.next, struct mali_group, pp_scheduler_list);
- } else if (mali_pp_scheduler_has_virtual_group()) {
- MALI_ASSERT_GROUP_LOCKED(virtual_group);
- if (mali_pp_scheduler_can_move_virtual_to_physical()) {
- struct mali_group *group;
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Acquiring physical group from virtual group.\n"));
- group = mali_group_acquire_group(virtual_group);
- if (mali_pp_scheduler_has_virtual_group()) {
- mali_pp_scheduler_disable_empty_virtual();
- }
- return group;
- }
- }
- return NULL;
- }
- static void mali_pp_scheduler_return_job_to_user(struct mali_pp_job *job, mali_bool deferred)
- {
- if (MALI_FALSE == mali_pp_job_use_no_notification(job)) {
- u32 i;
- u32 num_counters_to_copy;
- mali_bool success = mali_pp_job_was_success(job);
- _mali_uk_pp_job_finished_s *jobres = job->finished_notification->result_buffer;
- _mali_osk_memset(jobres, 0, sizeof(_mali_uk_pp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */
- jobres->user_job_ptr = mali_pp_job_get_user_id(job);
- if (MALI_TRUE == success) {
- jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS;
- } else {
- jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR;
- }
- if (mali_pp_job_is_virtual(job)) {
- num_counters_to_copy = num_cores; /* Number of physical cores available */
- } else {
- num_counters_to_copy = mali_pp_job_get_sub_job_count(job);
- }
- for (i = 0; i < num_counters_to_copy; i++) {
- jobres->perf_counter0[i] = mali_pp_job_get_perf_counter_value0(job, i);
- jobres->perf_counter1[i] = mali_pp_job_get_perf_counter_value1(job, i);
- jobres->perf_counter_src0 = mali_pp_job_get_pp_counter_global_src0();
- jobres->perf_counter_src1 = mali_pp_job_get_pp_counter_global_src1();
- }
- mali_session_send_notification(mali_pp_job_get_session(job), job->finished_notification);
- job->finished_notification = NULL;
- }
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
- if (MALI_TRUE == deferred) {
- /* The deletion of the job object (releasing sync refs etc) must be done in a different context */
- mali_pp_scheduler_deferred_job_delete(job);
- } else {
- mali_pp_job_delete(job);
- }
- #else
- MALI_DEBUG_ASSERT(MALI_FALSE == deferred); /* no use cases need this in this configuration */
- mali_pp_job_delete(job);
- #endif
- }
- static void mali_pp_scheduler_finalize_job(struct mali_pp_job * job)
- {
- /* This job object should not be on any lists. */
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list));
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_list));
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_fb_lookup_list));
- /* Send notification back to user space */
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
- mali_pp_scheduler_return_job_to_user(job, MALI_TRUE);
- #else
- mali_pp_scheduler_return_job_to_user(job, MALI_FALSE);
- #endif
- #if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY)
- if (_MALI_PP_JOB_FLAG_IS_WINDOW_SURFACE & job->uargs.flags) {
- _mali_osk_atomic_inc(&job->session->number_of_window_jobs);
- }
- #endif
- mali_pp_scheduler_job_completed();
- }
- void mali_pp_scheduler_schedule(void)
- {
- struct mali_group* physical_groups_to_start[MALI_MAX_NUMBER_OF_PP_GROUPS - 1];
- struct mali_pp_job* physical_jobs_to_start[MALI_MAX_NUMBER_OF_PP_GROUPS - 1];
- u32 physical_sub_jobs_to_start[MALI_MAX_NUMBER_OF_PP_GROUPS - 1];
- int num_physical_jobs_to_start = 0;
- int i;
- if (mali_pp_scheduler_has_virtual_group()) {
- /* Lock the virtual group since we might have to grab physical groups. */
- mali_group_lock(virtual_group);
- }
- mali_pp_scheduler_lock();
- if (pause_count > 0) {
- /* Scheduler is suspended, don't schedule any jobs. */
- mali_pp_scheduler_unlock();
- if (mali_pp_scheduler_has_virtual_group()) {
- mali_group_unlock(virtual_group);
- }
- return;
- }
- /* Find physical job(s) to schedule first. */
- while (1) {
- struct mali_group *group;
- struct mali_pp_job *job;
- u32 sub_job;
- job = mali_pp_scheduler_get_physical_job();
- if (NULL == job) {
- break; /* No job, early out. */
- }
- if (mali_scheduler_hint_is_enabled(MALI_SCHEDULER_HINT_GP_BOUND) &&
- mali_pp_job_is_large_and_unstarted(job) && !_mali_osk_list_empty(&group_list_working)) {
- /* Since not all groups are idle, don't schedule yet. */
- break;
- }
- MALI_DEBUG_ASSERT(!mali_pp_job_is_virtual(job));
- MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job));
- MALI_DEBUG_ASSERT(1 <= mali_pp_job_get_sub_job_count(job));
- /* Acquire a physical group, either from the idle list or from the virtual group.
- * In case the group was acquired from the virtual group, it's state will be
- * LEAVING_VIRTUAL and must be set to IDLE before it can be used. */
- group = mali_pp_scheduler_acquire_physical_group();
- if (NULL == group) {
- /* Could not get a group to run the job on, early out. */
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: No more physical groups available.\n"));
- break;
- }
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Acquired physical group %p.\n", group));
- /* Mark sub job as started. */
- sub_job = mali_pp_job_get_first_unstarted_sub_job(job);
- mali_pp_job_mark_sub_job_started(job, sub_job);
- /* Remove job from queue (if this was the last sub job). */
- mali_pp_scheduler_dequeue_physical_job(job);
- /* Move group to working list. */
- _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_working);
- /* Keep track of this group, so that we actually can start the job once we are done with the scheduler lock we are now holding. */
- physical_groups_to_start[num_physical_jobs_to_start] = group;
- physical_jobs_to_start[num_physical_jobs_to_start] = job;
- physical_sub_jobs_to_start[num_physical_jobs_to_start] = sub_job;
- ++num_physical_jobs_to_start;
- MALI_DEBUG_ASSERT(num_physical_jobs_to_start < MALI_MAX_NUMBER_OF_PP_GROUPS);
- }
- if (mali_pp_scheduler_has_virtual_group()) {
- if (VIRTUAL_GROUP_IDLE == virtual_group_state) {
- /* We have a virtual group and it is idle. */
- struct mali_pp_job *job;
- /* Find a virtual job we can start. */
- job = mali_pp_scheduler_get_virtual_job();
- if (NULL != job) {
- MALI_DEBUG_ASSERT(mali_pp_job_is_virtual(job));
- MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job));
- MALI_DEBUG_ASSERT(1 == mali_pp_job_get_sub_job_count(job));
- /* Mark the one and only sub job as started. */
- mali_pp_job_mark_sub_job_started(job, 0);
- /* Remove job from queue. */
- mali_pp_scheduler_dequeue_virtual_job(job);
- /* Virtual group is now working. */
- virtual_group_state = VIRTUAL_GROUP_WORKING;
- /* We no longer need the scheduler lock, but we still need the virtual lock
- * in order to start the virtual job. */
- mali_pp_scheduler_unlock();
- /* Start job. */
- mali_group_start_pp_job(virtual_group, job, 0);
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Virtual job %u (0x%08X) part %u/%u started (from schedule).\n",
- mali_pp_job_get_id(job), job, 1,
- mali_pp_job_get_sub_job_count(job)));
- mali_group_unlock(virtual_group);
- } else {
- /* No virtual job to start. */
- mali_pp_scheduler_unlock();
- mali_group_unlock(virtual_group);
- }
- } else {
- /* We have a virtual group, but it is busy or disabled. */
- MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE != virtual_group_state);
- mali_pp_scheduler_unlock();
- mali_group_unlock(virtual_group);
- }
- } else {
- /* There is no virtual group. */
- mali_pp_scheduler_unlock();
- }
- /* We have now released the scheduler lock, and we are ready to start the physical jobs.
- * The reason we want to wait until we have released the scheduler lock is that job start
- * may take quite a bit of time (many registers have to be written). This will allow new
- * jobs from user space to come in, and post-processing of other PP jobs to happen at the
- * same time as we start jobs. */
- for (i = 0; i < num_physical_jobs_to_start; i++) {
- struct mali_group *group = physical_groups_to_start[i];
- struct mali_pp_job *job = physical_jobs_to_start[i];
- u32 sub_job = physical_sub_jobs_to_start[i];
- MALI_DEBUG_ASSERT_POINTER(group);
- MALI_DEBUG_ASSERT_POINTER(job);
- MALI_DEBUG_ASSERT(!mali_group_is_virtual(group));
- MALI_DEBUG_ASSERT(!mali_pp_job_is_virtual(job));
- mali_group_lock(group);
- /* Set state to IDLE if group was acquired from the virtual group. */
- group->state = MALI_GROUP_STATE_IDLE;
- mali_group_start_pp_job(group, job, sub_job);
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Physical job %u (0x%08X) part %u/%u started (from schedule).\n",
- mali_pp_job_get_id(job), job, sub_job + 1,
- mali_pp_job_get_sub_job_count(job)));
- mali_group_unlock(group);
- }
- }
- /**
- * Set group idle.
- *
- * If @ref group is the virtual group, nothing is done since the virtual group should be idle
- * already.
- *
- * If @ref group is a physical group we rejoin the virtual group, if it exists. If not, we move the
- * physical group to the idle list.
- *
- * @note The group and the scheduler must both be locked when entering this function. Both will be
- * unlocked before exiting.
- *
- * @param group The group to set idle.
- */
- static void mali_pp_scheduler_set_group_idle_and_unlock(struct mali_group *group)
- {
- MALI_DEBUG_ASSERT_POINTER(group);
- MALI_ASSERT_GROUP_LOCKED(group);
- MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock);
- if (mali_group_is_virtual(group)) {
- /* The virtual group should have been set to non-working already. */
- MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE == virtual_group_state);
- mali_pp_scheduler_unlock();
- mali_group_unlock(group);
- return;
- } else {
- if (mali_pp_scheduler_has_virtual_group()) {
- /* Rejoin virtual group. */
- /* We're no longer needed on the scheduler list. */
- _mali_osk_list_delinit(&(group->pp_scheduler_list));
- /* Make sure no interrupts are handled for this group during the transition
- * from physical to virtual. */
- group->state = MALI_GROUP_STATE_JOINING_VIRTUAL;
- mali_pp_scheduler_unlock();
- mali_group_unlock(group);
- mali_group_lock(virtual_group);
- if (mali_pp_scheduler_has_virtual_group()) {
- mali_pp_scheduler_enable_empty_virtual();
- }
- /* We need to recheck the group state since it is possible that someone has
- * modified the group before we locked the virtual group. */
- if (MALI_GROUP_STATE_JOINING_VIRTUAL == group->state) {
- mali_group_add_group(virtual_group, group, MALI_TRUE);
- }
- mali_group_unlock(virtual_group);
- } else {
- /* Move physical group back to idle list. */
- _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_idle);
- #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
- trace_gpu_sched_switch(mali_pp_get_hw_core_desc(group->pp_core), sched_clock(), 0, 0, 0);
- #endif
- mali_pp_scheduler_unlock();
- mali_group_unlock(group);
- }
- }
- }
- /**
- * Schedule job on locked group.
- *
- * @note The group and the scheduler must both be locked when entering this function. Both will be
- * unlocked before exiting.
- *
- * @param group The group to schedule on.
- */
- static void mali_pp_scheduler_schedule_on_group_and_unlock(struct mali_group *group)
- {
- MALI_DEBUG_ASSERT_POINTER(group);
- MALI_ASSERT_GROUP_LOCKED(group);
- MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock);
- if (mali_group_is_virtual(group)) {
- /* Now that the virtual group is idle, check if we should reconfigure. */
- struct mali_pp_job *virtual_job = NULL;
- struct mali_pp_job *physical_job = NULL;
- struct mali_group *physical_group = NULL;
- u32 physical_sub_job = 0;
- MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE == virtual_group_state);
- if (mali_pp_scheduler_can_move_virtual_to_physical()) {
- /* There is a runnable physical job and we can acquire a physical group. */
- physical_job = mali_pp_scheduler_get_physical_job();
- MALI_DEBUG_ASSERT_POINTER(physical_job);
- MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(physical_job));
- /* Mark sub job as started. */
- physical_sub_job = mali_pp_job_get_first_unstarted_sub_job(physical_job);
- mali_pp_job_mark_sub_job_started(physical_job, physical_sub_job);
- /* Remove job from queue (if this was the last sub job). */
- mali_pp_scheduler_dequeue_physical_job(physical_job);
- /* Acquire a physical group from the virtual group. Its state will
- * be LEAVING_VIRTUAL and must be set to IDLE before it can be
- * used. */
- physical_group = mali_group_acquire_group(virtual_group);
- /* Move physical group to the working list, as we will soon start a job on it. */
- _mali_osk_list_move(&(physical_group->pp_scheduler_list), &group_list_working);
- mali_pp_scheduler_disable_empty_virtual();
- }
- /* Get next virtual job. */
- virtual_job = mali_pp_scheduler_get_virtual_job();
- if (NULL != virtual_job && VIRTUAL_GROUP_IDLE == virtual_group_state) {
- /* There is a runnable virtual job. */
- MALI_DEBUG_ASSERT(mali_pp_job_is_virtual(virtual_job));
- MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(virtual_job));
- MALI_DEBUG_ASSERT(1 == mali_pp_job_get_sub_job_count(virtual_job));
- mali_pp_job_mark_sub_job_started(virtual_job, 0);
- /* Remove job from queue. */
- mali_pp_scheduler_dequeue_virtual_job(virtual_job);
- /* Virtual group is now working. */
- virtual_group_state = VIRTUAL_GROUP_WORKING;
- mali_pp_scheduler_unlock();
- /* Start job. */
- mali_group_start_pp_job(group, virtual_job, 0);
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Virtual job %u (0x%08X) part %u/%u started (from job_done).\n",
- mali_pp_job_get_id(virtual_job), virtual_job, 1,
- mali_pp_job_get_sub_job_count(virtual_job)));
- } else {
- #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
- trace_gpu_sched_switch("Mali_Virtual_PP", sched_clock(), 0, 0, 0);
- #endif
- mali_pp_scheduler_unlock();
- }
- /* Releasing the virtual group lock that was held when entering the function. */
- mali_group_unlock(group);
- /* Start a physical job (if we acquired a physical group earlier). */
- if (NULL != physical_job && NULL != physical_group) {
- mali_group_lock(physical_group);
- /* Change the group state from LEAVING_VIRTUAL to IDLE to complete the transition. */
- physical_group->state = MALI_GROUP_STATE_IDLE;
- /* Start job. */
- mali_group_start_pp_job(physical_group, physical_job, physical_sub_job);
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Physical job %u (0x%08X) part %u/%u started (from job_done).\n",
- mali_pp_job_get_id(physical_job), physical_job, physical_sub_job + 1,
- mali_pp_job_get_sub_job_count(physical_job)));
- mali_group_unlock(physical_group);
- }
- } else {
- /* Physical group. */
- struct mali_pp_job *job = NULL;
- u32 sub_job = 0;
- job = mali_pp_scheduler_get_physical_job();
- if (NULL != job) {
- /* There is a runnable physical job. */
- MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job));
- /* Mark sub job as started. */
- sub_job = mali_pp_job_get_first_unstarted_sub_job(job);
- mali_pp_job_mark_sub_job_started(job, sub_job);
- /* Remove job from queue (if this was the last sub job). */
- mali_pp_scheduler_dequeue_physical_job(job);
- mali_pp_scheduler_unlock();
- /* Group is already on the working list, so start the new job. */
- mali_group_start_pp_job(group, job, sub_job);
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Physical job %u (0x%08X) part %u/%u started (from job_done).\n",
- mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job)));
- mali_group_unlock(group);
- } else {
- mali_pp_scheduler_set_group_idle_and_unlock(group);
- }
- }
- }
- void mali_pp_scheduler_job_done(struct mali_group *group, struct mali_pp_job *job, u32 sub_job, mali_bool success, mali_bool in_upper_half)
- {
- mali_bool job_is_done = MALI_FALSE;
- mali_bool schedule_on_group = MALI_FALSE;
- mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
- MALI_DEBUG_PRINT(3, ("Mali PP scheduler: %s job %u (0x%08X) part %u/%u completed (%s).\n",
- mali_pp_job_is_virtual(job) ? "Virtual" : "Physical",
- mali_pp_job_get_id(job),
- job, sub_job + 1,
- mali_pp_job_get_sub_job_count(job),
- success ? "success" : "failure"));
- MALI_ASSERT_GROUP_LOCKED(group);
- mali_pp_scheduler_lock();
- mali_pp_job_mark_sub_job_completed(job, success);
- MALI_DEBUG_ASSERT(mali_pp_job_is_virtual(job) == mali_group_is_virtual(group));
- job_is_done = mali_pp_job_is_complete(job);
- if (job_is_done) {
- /* Job is removed from these lists when the last sub job is scheduled. */
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list));
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_fb_lookup_list));
- /* Remove job from session list. */
- _mali_osk_list_delinit(&job->session_list);
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: All parts completed for %s job %u (0x%08X).\n",
- mali_pp_job_is_virtual(job) ? "virtual" : "physical",
- mali_pp_job_get_id(job), job));
- mali_pp_scheduler_unlock();
- /* Release tracker. If other trackers are waiting on this tracker, this could
- * trigger activation. The returned scheduling mask can be used to determine if we
- * have to schedule GP, PP or both. */
- schedule_mask = mali_timeline_tracker_release(&job->tracker);
- mali_pp_scheduler_lock();
- }
- if (mali_group_is_virtual(group)) {
- /* Obey the policy. */
- virtual_group_state = VIRTUAL_GROUP_IDLE;
- }
- /* If paused, then this was the last job, so wake up sleeping workers and return. */
- if (pause_count > 0) {
- /* Wake up sleeping workers. Their wake-up condition is that
- * num_slots == num_slots_idle, so unless we are done working, no
- * threads will actually be woken up.
- */
- if (!mali_group_is_virtual(group)) {
- /* Move physical group to idle list. */
- _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_idle);
- }
- #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
- trace_gpu_sched_switch(mali_pp_get_hw_core_desc(group->pp_core), sched_clock(), 0, 0, 0);
- #endif
- _mali_osk_wait_queue_wake_up(pp_scheduler_working_wait_queue);
- mali_pp_scheduler_unlock();
- mali_group_unlock(group);
- if (job_is_done) {
- /* Return job to user and delete it. */
- mali_pp_scheduler_finalize_job(job);
- }
- /* A GP job might be queued by tracker release above,
- * make sure GP scheduler gets a chance to schedule this (if possible)
- */
- mali_scheduler_schedule_from_mask(schedule_mask & ~MALI_SCHEDULER_MASK_PP, in_upper_half);
- return;
- }
- /* Since this group just finished running a job, we can reschedule a new job on it
- * immediately. */
- /* By default, don't schedule on group. */
- schedule_on_group = MALI_FALSE;
- if (mali_group_is_virtual(group)) {
- /* Always schedule immediately on virtual group. */
- schedule_mask &= ~MALI_SCHEDULER_MASK_PP;
- schedule_on_group = MALI_TRUE;
- } else if (0 < job_queue.depth && (!mali_scheduler_mask_is_set(schedule_mask, MALI_SCHEDULER_MASK_PP) || _mali_osk_list_empty(&group_list_idle))) {
- struct mali_pp_job *next_job = NULL;
- next_job = mali_pp_scheduler_get_physical_job();
- MALI_DEBUG_ASSERT_POINTER(next_job);
- /* If no new jobs have been queued or if this group is the only idle group, we can
- * schedule immediately on this group, unless we are GP bound and the next job would
- * benefit from all its sub jobs being started concurrently. */
- if (mali_scheduler_hint_is_enabled(MALI_SCHEDULER_HINT_GP_BOUND) && mali_pp_job_is_large_and_unstarted(next_job)) {
- /* We are GP bound and the job would benefit from all sub jobs being started
- * concurrently. Postpone scheduling until after group has been unlocked. */
- schedule_mask |= MALI_SCHEDULER_MASK_PP;
- schedule_on_group = MALI_FALSE;
- } else {
- /* Schedule job immediately since we are not GP bound. */
- schedule_mask &= ~MALI_SCHEDULER_MASK_PP;
- schedule_on_group = MALI_TRUE;
- }
- }
- if (schedule_on_group) {
- /* Schedule a new job on this group. */
- mali_pp_scheduler_schedule_on_group_and_unlock(group);
- } else {
- /* Set group idle. Will rejoin virtual group, under appropriate conditions. */
- mali_pp_scheduler_set_group_idle_and_unlock(group);
- }
- if (!schedule_on_group || MALI_SCHEDULER_MASK_EMPTY != schedule_mask) {
- if (MALI_SCHEDULER_MASK_PP & schedule_mask) {
- /* Schedule PP directly. */
- mali_pp_scheduler_schedule();
- schedule_mask &= ~MALI_SCHEDULER_MASK_PP;
- }
- /* Schedule other jobs that were activated. */
- mali_scheduler_schedule_from_mask(schedule_mask, in_upper_half);
- }
- if (job_is_done) {
- /* Return job to user and delete it. */
- mali_pp_scheduler_finalize_job(job);
- }
- }
- void mali_pp_scheduler_suspend(void)
- {
- mali_pp_scheduler_lock();
- pause_count++; /* Increment the pause_count so that no more jobs will be scheduled */
- mali_pp_scheduler_unlock();
- /* Go to sleep. When woken up again (in mali_pp_scheduler_job_done), the
- * mali_pp_scheduler_suspended() function will be called. This will return true
- * if state is idle and pause_count > 0, so if the core is active this
- * will not do anything.
- */
- _mali_osk_wait_queue_wait_event(pp_scheduler_working_wait_queue, mali_pp_scheduler_is_suspended, NULL);
- }
- void mali_pp_scheduler_resume(void)
- {
- mali_pp_scheduler_lock();
- pause_count--; /* Decrement pause_count to allow scheduling again (if it reaches 0) */
- mali_pp_scheduler_unlock();
- if (0 == pause_count) {
- mali_pp_scheduler_schedule();
- }
- }
- mali_timeline_point mali_pp_scheduler_submit_job(struct mali_session_data *session, struct mali_pp_job *job)
- {
- mali_timeline_point point;
- u32 fb_lookup_id = 0;
- MALI_DEBUG_ASSERT_POINTER(session);
- MALI_DEBUG_ASSERT_POINTER(job);
- mali_pp_scheduler_lock();
- fb_lookup_id = mali_pp_job_get_fb_lookup_id(job);
- MALI_DEBUG_ASSERT(MALI_PP_JOB_FB_LOOKUP_LIST_SIZE > fb_lookup_id);
- /* Adding job to the lookup list used to quickly discard writeback units of queued jobs. */
- _mali_osk_list_addtail(&job->session_fb_lookup_list, &session->pp_job_fb_lookup_list[fb_lookup_id]);
- mali_pp_scheduler_unlock();
- mali_pp_scheduler_job_queued();
- /* Add job to Timeline system. */
- point = mali_timeline_system_add_tracker(session->timeline_system, &job->tracker, MALI_TIMELINE_PP);
- return point;
- }
- _mali_osk_errcode_t _mali_ukk_pp_start_job(void *ctx, _mali_uk_pp_start_job_s *uargs)
- {
- struct mali_session_data *session;
- struct mali_pp_job *job;
- mali_timeline_point point;
- u32 __user *timeline_point_ptr = NULL;
- MALI_DEBUG_ASSERT_POINTER(uargs);
- MALI_DEBUG_ASSERT_POINTER(ctx);
- session = (struct mali_session_data*)ctx;
- job = mali_pp_job_create(session, uargs, mali_scheduler_get_new_id());
- if (NULL == job) {
- MALI_PRINT_ERROR(("Failed to create PP job.\n"));
- return _MALI_OSK_ERR_NOMEM;
- }
- timeline_point_ptr = (u32 __user *) job->uargs.timeline_point_ptr;
- point = mali_pp_scheduler_submit_job(session, job);
- job = NULL;
- if (0 != _mali_osk_put_user(((u32) point), timeline_point_ptr)) {
- /* Let user space know that something failed after the job was started. */
- return _MALI_OSK_ERR_ITEM_NOT_FOUND;
- }
- return _MALI_OSK_ERR_OK;
- }
- _mali_osk_errcode_t _mali_ukk_pp_and_gp_start_job(void *ctx, _mali_uk_pp_and_gp_start_job_s *uargs)
- {
- struct mali_session_data *session;
- _mali_uk_pp_and_gp_start_job_s kargs;
- struct mali_pp_job *pp_job;
- struct mali_gp_job *gp_job;
- u32 __user *timeline_point_ptr = NULL;
- mali_timeline_point point;
- MALI_DEBUG_ASSERT_POINTER(ctx);
- MALI_DEBUG_ASSERT_POINTER(uargs);
- session = (struct mali_session_data *) ctx;
- if (0 != _mali_osk_copy_from_user(&kargs, uargs, sizeof(_mali_uk_pp_and_gp_start_job_s))) {
- return _MALI_OSK_ERR_NOMEM;
- }
- pp_job = mali_pp_job_create(session, kargs.pp_args, mali_scheduler_get_new_id());
- if (NULL == pp_job) {
- MALI_PRINT_ERROR(("Failed to create PP job.\n"));
- return _MALI_OSK_ERR_NOMEM;
- }
- gp_job = mali_gp_job_create(session, kargs.gp_args, mali_scheduler_get_new_id(), mali_pp_job_get_tracker(pp_job));
- if (NULL == gp_job) {
- MALI_PRINT_ERROR(("Failed to create GP job.\n"));
- mali_pp_job_delete(pp_job);
- return _MALI_OSK_ERR_NOMEM;
- }
- timeline_point_ptr = (u32 __user *) pp_job->uargs.timeline_point_ptr;
- /* Submit GP job. */
- mali_gp_scheduler_submit_job(session, gp_job);
- gp_job = NULL;
- /* Submit PP job. */
- point = mali_pp_scheduler_submit_job(session, pp_job);
- pp_job = NULL;
- if (0 != _mali_osk_put_user(((u32) point), timeline_point_ptr)) {
- /* Let user space know that something failed after the jobs were started. */
- return _MALI_OSK_ERR_ITEM_NOT_FOUND;
- }
- return _MALI_OSK_ERR_OK;
- }
- _mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores(_mali_uk_get_pp_number_of_cores_s *args)
- {
- MALI_DEBUG_ASSERT_POINTER(args);
- MALI_DEBUG_ASSERT_POINTER(args->ctx);
- args->number_of_total_cores = num_cores;
- args->number_of_enabled_cores = enabled_cores;
- return _MALI_OSK_ERR_OK;
- }
- u32 mali_pp_scheduler_get_num_cores_total(void)
- {
- return num_cores;
- }
- u32 mali_pp_scheduler_get_num_cores_enabled(void)
- {
- return enabled_cores;
- }
- _mali_osk_errcode_t _mali_ukk_get_pp_core_version(_mali_uk_get_pp_core_version_s *args)
- {
- MALI_DEBUG_ASSERT_POINTER(args);
- MALI_DEBUG_ASSERT_POINTER(args->ctx);
- args->version = pp_version;
- return _MALI_OSK_ERR_OK;
- }
- void _mali_ukk_pp_job_disable_wb(_mali_uk_pp_disable_wb_s *args)
- {
- struct mali_session_data *session;
- struct mali_pp_job *job;
- struct mali_pp_job *tmp;
- u32 fb_lookup_id;
- MALI_DEBUG_ASSERT_POINTER(args);
- MALI_DEBUG_ASSERT_POINTER(args->ctx);
- session = (struct mali_session_data*)args->ctx;
- fb_lookup_id = args->fb_id & MALI_PP_JOB_FB_LOOKUP_LIST_MASK;
- mali_pp_scheduler_lock();
- /* Iterate over all jobs for given frame builder_id. */
- _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &session->pp_job_fb_lookup_list[fb_lookup_id], struct mali_pp_job, session_fb_lookup_list) {
- MALI_DEBUG_CODE(u32 disable_mask = 0);
- if (mali_pp_job_get_frame_builder_id(job) == (u32) args->fb_id) {
- MALI_DEBUG_CODE(disable_mask |= 0xD<<(4*3));
- if (args->wb0_memory == job->uargs.wb0_registers[MALI200_REG_ADDR_WB_SOURCE_ADDR/sizeof(u32)]) {
- MALI_DEBUG_CODE(disable_mask |= 0x1<<(4*1));
- mali_pp_job_disable_wb0(job);
- }
- if (args->wb1_memory == job->uargs.wb1_registers[MALI200_REG_ADDR_WB_SOURCE_ADDR/sizeof(u32)]) {
- MALI_DEBUG_CODE(disable_mask |= 0x2<<(4*2));
- mali_pp_job_disable_wb1(job);
- }
- if (args->wb2_memory == job->uargs.wb2_registers[MALI200_REG_ADDR_WB_SOURCE_ADDR/sizeof(u32)]) {
- MALI_DEBUG_CODE(disable_mask |= 0x3<<(4*3));
- mali_pp_job_disable_wb2(job);
- }
- MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Disable WB: 0x%X.\n", disable_mask));
- } else {
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Disable WB mismatching FB.\n"));
- }
- }
- mali_pp_scheduler_unlock();
- }
- void mali_pp_scheduler_abort_session(struct mali_session_data *session)
- {
- u32 i = 0;
- struct mali_pp_job *job, *tmp_job;
- struct mali_group *group, *tmp_group;
- struct mali_group *groups[MALI_MAX_NUMBER_OF_GROUPS];
- _MALI_OSK_LIST_HEAD_STATIC_INIT(removed_jobs);
- MALI_DEBUG_ASSERT_POINTER(session);
- MALI_DEBUG_ASSERT(session->is_aborting);
- MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Aborting all jobs from session 0x%08X.\n", session));
- mali_pp_scheduler_lock();
- /* Find all jobs from the aborting session. */
- _MALI_OSK_LIST_FOREACHENTRY(job, tmp_job, &session->pp_job_list, struct mali_pp_job, session_list) {
- /* Remove job from queue. */
- if (mali_pp_job_is_virtual(job)) {
- MALI_DEBUG_ASSERT(1 == mali_pp_job_get_sub_job_count(job));
- if (0 == mali_pp_job_get_first_unstarted_sub_job(job)) {
- --virtual_job_queue.depth;
- }
- } else {
- job_queue.depth -= mali_pp_job_get_sub_job_count(job) - mali_pp_job_get_first_unstarted_sub_job(job);
- }
- _mali_osk_list_delinit(&job->list);
- _mali_osk_list_delinit(&job->session_fb_lookup_list);
- mali_pp_job_mark_unstarted_failed(job);
- if (mali_pp_job_is_complete(job)) {
- /* Job is complete, remove from session list. */
- _mali_osk_list_delinit(&job->session_list);
- /* Move job to local list for release and deletion. */
- _mali_osk_list_add(&job->list, &removed_jobs);
- MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Aborted PP job %u (0x%08X).\n", mali_pp_job_get_id(job), job));
- } else {
- MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Keeping partially started PP job %u (0x%08X) in session.\n", mali_pp_job_get_id(job), job));
- }
- }
- _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_working, struct mali_group, pp_scheduler_list) {
- groups[i++] = group;
- }
- _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_idle, struct mali_group, pp_scheduler_list) {
- groups[i++] = group;
- }
- mali_pp_scheduler_unlock();
- /* Release and delete all found jobs from the aborting session. */
- _MALI_OSK_LIST_FOREACHENTRY(job, tmp_job, &removed_jobs, struct mali_pp_job, list) {
- mali_timeline_tracker_release(&job->tracker);
- mali_pp_job_delete(job);
- mali_pp_scheduler_job_completed();
- }
- /* Abort any running jobs from the session. */
- while (i > 0) {
- mali_group_abort_session(groups[--i], session);
- }
- if (mali_pp_scheduler_has_virtual_group()) {
- mali_group_abort_session(virtual_group, session);
- }
- }
- static mali_bool mali_pp_scheduler_is_suspended(void *data)
- {
- mali_bool ret;
- /* This callback does not use the data pointer. */
- MALI_IGNORE(data);
- mali_pp_scheduler_lock();
- ret = pause_count > 0
- && _mali_osk_list_empty(&group_list_working)
- && VIRTUAL_GROUP_WORKING != virtual_group_state;
- mali_pp_scheduler_unlock();
- return ret;
- }
- struct mali_pp_core *mali_pp_scheduler_get_virtual_pp(void)
- {
- if (mali_pp_scheduler_has_virtual_group()) {
- return mali_group_get_pp_core(virtual_group);
- } else {
- return NULL;
- }
- }
- #if MALI_STATE_TRACKING
- u32 mali_pp_scheduler_dump_state(char *buf, u32 size)
- {
- int n = 0;
- struct mali_group *group;
- struct mali_group *temp;
- n += _mali_osk_snprintf(buf + n, size - n, "PP:\n");
- n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue.normal_pri) ? "empty" : "not empty");
- n += _mali_osk_snprintf(buf + n, size - n, "\tHigh priority queue is %s\n", _mali_osk_list_empty(&job_queue.high_pri) ? "empty" : "not empty");
- n += _mali_osk_snprintf(buf + n, size - n, "\n");
- _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working, struct mali_group, pp_scheduler_list) {
- n += mali_group_dump_state(group, buf + n, size - n);
- }
- _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, pp_scheduler_list) {
- n += mali_group_dump_state(group, buf + n, size - n);
- }
- _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, pp_scheduler_list) {
- n += mali_group_dump_state(group, buf + n, size - n);
- }
- if (mali_pp_scheduler_has_virtual_group()) {
- n += mali_group_dump_state(virtual_group, buf + n, size -n);
- }
- n += _mali_osk_snprintf(buf + n, size - n, "\n");
- return n;
- }
- #endif
- /* This function is intended for power on reset of all cores.
- * No locking is done for the list iteration, which can only be safe if the
- * scheduler is paused and all cores idle. That is always the case on init and
- * power on. */
- void mali_pp_scheduler_reset_all_groups(void)
- {
- struct mali_group *group, *temp;
- struct mali_group *groups[MALI_MAX_NUMBER_OF_GROUPS];
- s32 i = 0;
- if (mali_pp_scheduler_has_virtual_group()) {
- mali_group_lock(virtual_group);
- mali_group_reset(virtual_group);
- mali_group_unlock(virtual_group);
- }
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working));
- MALI_DEBUG_ASSERT(VIRTUAL_GROUP_WORKING != virtual_group_state);
- mali_pp_scheduler_lock();
- _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, pp_scheduler_list) {
- groups[i++] = group;
- }
- mali_pp_scheduler_unlock();
- while (i > 0) {
- group = groups[--i];
- mali_group_lock(group);
- mali_group_reset(group);
- mali_group_unlock(group);
- }
- }
- void mali_pp_scheduler_zap_all_active(struct mali_session_data *session)
- {
- struct mali_group *group, *temp;
- struct mali_group *groups[MALI_MAX_NUMBER_OF_GROUPS];
- s32 i = 0;
- if (mali_pp_scheduler_has_virtual_group()) {
- mali_group_zap_session(virtual_group, session);
- }
- mali_pp_scheduler_lock();
- _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working, struct mali_group, pp_scheduler_list) {
- groups[i++] = group;
- }
- mali_pp_scheduler_unlock();
- while (i > 0) {
- mali_group_zap_session(groups[--i], session);
- }
- }
- /* A pm reference must be taken with _mali_osk_pm_dev_ref_add_no_power_on
- * before calling this function to avoid Mali powering down as HW is accessed.
- */
- static void mali_pp_scheduler_enable_group_internal(struct mali_group *group)
- {
- MALI_DEBUG_ASSERT_POINTER(group);
- mali_group_lock(group);
- if (MALI_GROUP_STATE_DISABLED != group->state) {
- mali_group_unlock(group);
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: PP group %p already enabled.\n", group));
- return;
- }
- MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Enabling PP group %p.\n", group));
- mali_pp_scheduler_lock();
- MALI_DEBUG_ASSERT(MALI_GROUP_STATE_DISABLED == group->state);
- ++enabled_cores;
- if (mali_pp_scheduler_has_virtual_group()) {
- mali_bool update_hw;
- /* Add group to virtual group. */
- _mali_osk_list_delinit(&(group->pp_scheduler_list));
- group->state = MALI_GROUP_STATE_JOINING_VIRTUAL;
- mali_pp_scheduler_unlock();
- mali_group_unlock(group);
- mali_group_lock(virtual_group);
- update_hw = mali_pm_is_power_on();
- /* Get ref of group domain */
- mali_group_get_pm_domain_ref(group);
- MALI_DEBUG_ASSERT(NULL == group->pm_domain ||
- MALI_PM_DOMAIN_ON == mali_pm_domain_state_get(group->pm_domain));
- if (update_hw) {
- mali_group_lock(group);
- mali_group_power_on_group(group);
- mali_group_reset(group);
- mali_group_unlock(group);
- }
- mali_pp_scheduler_enable_empty_virtual();
- mali_group_add_group(virtual_group, group, update_hw);
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Done enabling group %p. Added to virtual group.\n", group));
- mali_group_unlock(virtual_group);
- } else {
- /* Get ref of group domain */
- mali_group_get_pm_domain_ref(group);
- MALI_DEBUG_ASSERT(NULL == group->pm_domain ||
- MALI_PM_DOMAIN_ON == mali_pm_domain_state_get(group->pm_domain));
- /* Put group on idle list. */
- if (mali_pm_is_power_on()) {
- mali_group_power_on_group(group);
- mali_group_reset(group);
- }
- _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_idle);
- group->state = MALI_GROUP_STATE_IDLE;
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Done enabling group %p. Now on idle list.\n", group));
- mali_pp_scheduler_unlock();
- mali_group_unlock(group);
- }
- }
- void mali_pp_scheduler_enable_group(struct mali_group *group)
- {
- MALI_DEBUG_ASSERT_POINTER(group);
- _mali_osk_pm_dev_ref_add_no_power_on();
- mali_pp_scheduler_enable_group_internal(group);
- _mali_osk_pm_dev_ref_dec_no_power_on();
- /* Pick up any jobs that might have been queued if all PP groups were disabled. */
- mali_pp_scheduler_schedule();
- }
- static void mali_pp_scheduler_disable_group_internal(struct mali_group *group)
- {
- if (mali_pp_scheduler_has_virtual_group()) {
- mali_group_lock(virtual_group);
- MALI_DEBUG_ASSERT(VIRTUAL_GROUP_WORKING != virtual_group_state);
- if (MALI_GROUP_STATE_JOINING_VIRTUAL == group->state) {
- /* The group was in the process of being added to the virtual group. We
- * only need to change the state to reverse this. */
- group->state = MALI_GROUP_STATE_LEAVING_VIRTUAL;
- } else if (MALI_GROUP_STATE_IN_VIRTUAL == group->state) {
- /* Remove group from virtual group. The state of the group will be
- * LEAVING_VIRTUAL and the group will not be on any scheduler list. */
- mali_group_remove_group(virtual_group, group);
- mali_pp_scheduler_disable_empty_virtual();
- }
- mali_group_unlock(virtual_group);
- }
- mali_group_lock(group);
- mali_pp_scheduler_lock();
- MALI_DEBUG_ASSERT( MALI_GROUP_STATE_IDLE == group->state
- || MALI_GROUP_STATE_LEAVING_VIRTUAL == group->state
- || MALI_GROUP_STATE_DISABLED == group->state);
- if (MALI_GROUP_STATE_DISABLED == group->state) {
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: PP group %p already disabled.\n", group));
- } else {
- MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Disabling PP group %p.\n", group));
- --enabled_cores;
- _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_disabled);
- group->state = MALI_GROUP_STATE_DISABLED;
- mali_group_power_off_group(group, MALI_TRUE);
- mali_group_put_pm_domain_ref(group);
- }
- mali_pp_scheduler_unlock();
- mali_group_unlock(group);
- }
- void mali_pp_scheduler_disable_group(struct mali_group *group)
- {
- MALI_DEBUG_ASSERT_POINTER(group);
- mali_pp_scheduler_suspend();
- _mali_osk_pm_dev_ref_add_no_power_on();
- mali_pp_scheduler_disable_group_internal(group);
- _mali_osk_pm_dev_ref_dec_no_power_on();
- mali_pp_scheduler_resume();
- }
- static void mali_pp_scheduler_notify_core_change(u32 num_cores)
- {
- mali_bool done = MALI_FALSE;
- if (mali_is_mali450() || mali_is_mali470()) {
- return;
- }
- /*
- * This function gets a bit complicated because we can't hold the session lock while
- * allocating notification objects.
- */
- while (!done) {
- u32 i;
- u32 num_sessions_alloc;
- u32 num_sessions_with_lock;
- u32 used_notification_objects = 0;
- _mali_osk_notification_t **notobjs;
- /* Pre allocate the number of notifications objects we need right now (might change after lock has been taken) */
- num_sessions_alloc = mali_session_get_count();
- if (0 == num_sessions_alloc) {
- /* No sessions to report to */
- return;
- }
- notobjs = (_mali_osk_notification_t **)_mali_osk_malloc(sizeof(_mali_osk_notification_t *) * num_sessions_alloc);
- if (NULL == notobjs) {
- MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure)\n"));
- /* there is probably no point in trying again, system must be really low on memory and probably unusable now anyway */
- return;
- }
- for (i = 0; i < num_sessions_alloc; i++) {
- notobjs[i] = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_NUM_CORE_CHANGE, sizeof(_mali_uk_pp_num_cores_changed_s));
- if (NULL != notobjs[i]) {
- _mali_uk_pp_num_cores_changed_s *data = notobjs[i]->result_buffer;
- data->number_of_enabled_cores = num_cores;
- } else {
- MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure %u)\n", i));
- }
- }
- mali_session_lock();
- /* number of sessions will not change while we hold the lock */
- num_sessions_with_lock = mali_session_get_count();
- if (num_sessions_alloc >= num_sessions_with_lock) {
- /* We have allocated enough notification objects for all the sessions atm */
- struct mali_session_data *session, *tmp;
- MALI_SESSION_FOREACH(session, tmp, link) {
- MALI_DEBUG_ASSERT(used_notification_objects < num_sessions_alloc);
- if (NULL != notobjs[used_notification_objects]) {
- mali_session_send_notification(session, notobjs[used_notification_objects]);
- notobjs[used_notification_objects] = NULL; /* Don't track this notification object any more */
- }
- used_notification_objects++;
- }
- done = MALI_TRUE;
- }
- mali_session_unlock();
- /* Delete any remaining/unused notification objects */
- for (; used_notification_objects < num_sessions_alloc; used_notification_objects++) {
- if (NULL != notobjs[used_notification_objects]) {
- _mali_osk_notification_delete(notobjs[used_notification_objects]);
- }
- }
- _mali_osk_free(notobjs);
- }
- }
- static void mali_pp_scheduler_core_scale_up(unsigned int target_core_nr)
- {
- MALI_DEBUG_PRINT(2, ("Requesting %d cores: enabling %d cores\n", target_core_nr, target_core_nr - enabled_cores));
- _mali_osk_pm_dev_ref_add_no_power_on();
- _mali_osk_pm_dev_barrier();
- while (target_core_nr > enabled_cores) {
- /*
- * If there are any cores which do not belong to any domain,
- * then these will always be found at the head of the list and
- * we'll thus enabled these first.
- */
- mali_pp_scheduler_lock();
- if (!_mali_osk_list_empty(&group_list_disabled)) {
- struct mali_group *group;
- group = _MALI_OSK_LIST_ENTRY(group_list_disabled.next, struct mali_group, pp_scheduler_list);
- MALI_DEBUG_ASSERT_POINTER(group);
- MALI_DEBUG_ASSERT(MALI_GROUP_STATE_DISABLED == group->state);
- mali_pp_scheduler_unlock();
- mali_pp_scheduler_enable_group_internal(group);
- } else {
- mali_pp_scheduler_unlock();
- break; /* no more groups on disabled list */
- }
- }
- _mali_osk_pm_dev_ref_dec_no_power_on();
- mali_pp_scheduler_schedule();
- }
- static void mali_pp_scheduler_core_scale_down(unsigned int target_core_nr)
- {
- MALI_DEBUG_PRINT(2, ("Requesting %d cores: disabling %d cores\n", target_core_nr, enabled_cores - target_core_nr));
- mali_pp_scheduler_suspend();
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working));
- _mali_osk_pm_dev_ref_add_no_power_on();
- if (NULL != mali_pmu_get_global_pmu_core()) {
- int i;
- for (i = MALI_MAX_NUMBER_OF_DOMAINS - 1; i >= 0; i--) {
- if (target_core_nr < enabled_cores) {
- struct mali_pm_domain *domain;
- domain = mali_pm_domain_get_from_index(i);
- /* Domain is valid and has pp cores */
- if ((NULL != domain) && (NULL != domain->group_list)) {
- struct mali_group *group;
- MALI_PM_DOMAIN_FOR_EACH_GROUP(group, domain) {
- /* If group is pp core */
- if (NULL != mali_group_get_pp_core(group)) {
- mali_pp_scheduler_disable_group_internal(group);
- if (target_core_nr >= enabled_cores) {
- break;
- }
- }
- }
- }
- } else {
- break;
- }
- }
- }
- /*
- * Didn't find enough cores associated with a power domain,
- * so we need to disable cores which we can't power off with the PMU.
- * Start with physical groups used by the scheduler,
- * then remove physical from virtual if even more groups are needed.
- */
- while (target_core_nr < enabled_cores) {
- mali_pp_scheduler_lock();
- if (!_mali_osk_list_empty(&group_list_idle)) {
- struct mali_group *group;
- group = _MALI_OSK_LIST_ENTRY(group_list_idle.next, struct mali_group, pp_scheduler_list);
- MALI_DEBUG_ASSERT_POINTER(group);
- mali_pp_scheduler_unlock();
- mali_pp_scheduler_disable_group_internal(group);
- } else {
- mali_pp_scheduler_unlock();
- break; /* No more physical groups */
- }
- }
- if (mali_pp_scheduler_has_virtual_group()) {
- while (target_core_nr < enabled_cores) {
- mali_group_lock(virtual_group);
- if (!_mali_osk_list_empty(&virtual_group->group_list)) {
- struct mali_group *group;
- group = _MALI_OSK_LIST_ENTRY(virtual_group->group_list.next, struct mali_group, group_list);
- MALI_DEBUG_ASSERT_POINTER(group);
- mali_group_unlock(virtual_group);
- mali_pp_scheduler_disable_group_internal(group);
- } else {
- mali_group_unlock(virtual_group);
- break; /* No more physical groups in virtual group */
- }
- }
- }
- _mali_osk_pm_dev_ref_dec_no_power_on();
- mali_pp_scheduler_resume();
- }
- int mali_pp_scheduler_set_perf_level(unsigned int target_core_nr, mali_bool override)
- {
- if (target_core_nr == enabled_cores) return 0;
- if (MALI_FALSE == core_scaling_enabled && MALI_FALSE == override) return -EPERM;
- if (target_core_nr > num_cores) return -EINVAL;
- if (0 == target_core_nr) return -EINVAL;
- if (target_core_nr > enabled_cores) {
- mali_pp_scheduler_core_scale_up(target_core_nr);
- } else if (target_core_nr < enabled_cores) {
- mali_pp_scheduler_core_scale_down(target_core_nr);
- }
- if (target_core_nr != enabled_cores) {
- MALI_DEBUG_PRINT(2, ("Core scaling failed, target number: %d, actual number: %d\n", target_core_nr, enabled_cores));
- }
- mali_pp_scheduler_notify_core_change(enabled_cores);
- return 0;
- }
- void mali_pp_scheduler_core_scaling_enable(void)
- {
- /* PS: Core scaling is by default enabled */
- core_scaling_enabled = MALI_TRUE;
- }
- void mali_pp_scheduler_core_scaling_disable(void)
- {
- core_scaling_enabled = MALI_FALSE;
- }
- mali_bool mali_pp_scheduler_core_scaling_is_enabled(void)
- {
- return core_scaling_enabled;
- }
- static void mali_pp_scheduler_job_queued(void)
- {
- /* We hold a PM reference for every job we hold queued (and running) */
- _mali_osk_pm_dev_ref_add();
- if (mali_utilization_enabled()) {
- /*
- * We cheat a little bit by counting the PP as busy from the time a PP job is queued.
- * This will be fine because we only loose the tiny idle gap between jobs, but
- * we will instead get less utilization work to do (less locks taken)
- */
- mali_utilization_pp_start();
- }
- }
- static void mali_pp_scheduler_job_completed(void)
- {
- /* Release the PM reference we got in the mali_pp_scheduler_job_queued() function */
- _mali_osk_pm_dev_ref_dec();
- if (mali_utilization_enabled()) {
- mali_utilization_pp_end();
- }
- }
- static void mali_pp_scheduler_abort_job_and_unlock_scheduler(struct mali_pp_job *job)
- {
- MALI_DEBUG_ASSERT_POINTER(job);
- MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock);
- /* This job should not be on any lists. */
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list));
- MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_list));
- _mali_osk_list_delinit(&job->session_fb_lookup_list);
- mali_pp_scheduler_unlock();
- /* Release tracker. */
- mali_timeline_tracker_release(&job->tracker);
- }
- static mali_scheduler_mask mali_pp_scheduler_queue_job(struct mali_pp_job *job)
- {
- _mali_osk_list_t *queue = NULL;
- mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
- struct mali_pp_job *iter, *tmp;
- MALI_DEBUG_ASSERT_POINTER(job);
- MALI_DEBUG_ASSERT_POINTER(job->session);
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
- if (mali_pp_job_needs_dma_buf_mapping(job)) {
- mali_dma_buf_map_job(job);
- }
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
- mali_pp_scheduler_lock();
- if (unlikely(job->session->is_aborting)) {
- /* Before checking if the session is aborting, the scheduler must be locked. */
- MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock);
- MALI_DEBUG_PRINT(2, ("Mali PP scheduler: Job %u (0x%08X) queued while session is aborting.\n", mali_pp_job_get_id(job), job));
- mali_pp_scheduler_abort_job_and_unlock_scheduler(job);
- /* Delete job. */
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE)
- mali_pp_scheduler_deferred_job_delete(job);
- #else
- mali_pp_job_delete(job);
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */
- mali_pp_scheduler_job_completed();
- /* Since we are aborting we ignore the scheduler mask. */
- return MALI_SCHEDULER_MASK_EMPTY;
- }
- #if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS)
- trace_gpu_job_enqueue(mali_pp_job_get_tid(job), mali_pp_job_get_id(job), "PP");
- #endif
- _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | MALI_PROFILING_EVENT_REASON_SINGLE_SW_PP_ENQUEUE, job->pid, job->tid, job->uargs.frame_builder_id, job->uargs.flush_id, 0);
- job->cache_order = mali_scheduler_get_new_cache_order();
- /* Determine which queue the job should be added to. */
- if (mali_pp_job_is_virtual(job)) {
- if (job->session->use_high_priority_job_queue) {
- queue = &virtual_job_queue.high_pri;
- } else {
- queue = &virtual_job_queue.normal_pri;
- }
- virtual_job_queue.depth += 1;
- /* Set schedule bitmask if the virtual group is idle. */
- if (VIRTUAL_GROUP_IDLE == virtual_group_state) {
- schedule_mask |= MALI_SCHEDULER_MASK_PP;
- }
- } else {
- if (job->session->use_high_priority_job_queue) {
- queue = &job_queue.high_pri;
- } else {
- queue = &job_queue.normal_pri;
- }
- job_queue.depth += mali_pp_job_get_sub_job_count(job);
- /* Set schedule bitmask if there are physical PP cores available, or if there is an
- * idle virtual group. */
- if (!_mali_osk_list_empty(&group_list_idle)
- || (mali_pp_scheduler_has_virtual_group()
- && (VIRTUAL_GROUP_IDLE == virtual_group_state))) {
- schedule_mask |= MALI_SCHEDULER_MASK_PP;
- }
- }
- /* Find position in queue where job should be added. */
- _MALI_OSK_LIST_FOREACHENTRY_REVERSE(iter, tmp, queue, struct mali_pp_job, list) {
- if (mali_pp_job_should_start_after(job, iter)) {
- break;
- }
- }
- /* Add job to queue. */
- _mali_osk_list_add(&job->list, &iter->list);
- /* Add job to session list. */
- _mali_osk_list_addtail(&job->session_list, &(job->session->pp_job_list));
- MALI_DEBUG_PRINT(3, ("Mali PP scheduler: %s job %u (0x%08X) with %u parts queued.\n",
- mali_pp_job_is_virtual(job) ? "Virtual" : "Physical",
- mali_pp_job_get_id(job), job, mali_pp_job_get_sub_job_count(job)));
- mali_pp_scheduler_unlock();
- return schedule_mask;
- }
- mali_scheduler_mask mali_pp_scheduler_activate_job(struct mali_pp_job *job)
- {
- mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY;
- MALI_DEBUG_ASSERT_POINTER(job);
- MALI_DEBUG_ASSERT_POINTER(job->session);
- MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Timeline activation for job %u (0x%08X).\n", mali_pp_job_get_id(job), job));
- if (MALI_TIMELINE_ACTIVATION_ERROR_FATAL_BIT & job->tracker.activation_error) {
- MALI_DEBUG_PRINT(2, ("Mali PP scheduler: Job %u (0x%08X) activated with error, aborting.\n", mali_pp_job_get_id(job), job));
- mali_pp_scheduler_lock();
- mali_pp_scheduler_abort_job_and_unlock_scheduler(job);
- mali_pp_job_mark_sub_job_completed(job, MALI_FALSE); /* Flagging the job as failed. */
- mali_pp_scheduler_finalize_job(job);
- return MALI_SCHEDULER_MASK_EMPTY;
- }
- /* PP job is ready to run, queue it. */
- #if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE)
- if (mali_pp_job_needs_dma_buf_mapping(job)) {
- mali_pp_scheduler_deferred_job_queue(job);
- return MALI_SCHEDULER_MASK_EMPTY;
- }
- #endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */
- schedule_mask = mali_pp_scheduler_queue_job(job);
- return schedule_mask;
- }
|