1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2011-2021 ARM Limited. All rights reserved.
5 *
6 * This program is free software and is provided to you under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation, and any use by you of this program is subject to the terms
9 * of such GNU license.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can access it online at
18 * http://www.gnu.org/licenses/gpl-2.0.html.
19 *
20 */
21
22 /*
23 * Job Scheduler Implementation
24 */
25 #include <mali_kbase.h>
26 #include <mali_kbase_js.h>
27 #include <tl/mali_kbase_tracepoints.h>
28 #include <mali_linux_trace.h>
29 #include <mali_kbase_hw.h>
30 #include <mali_kbase_ctx_sched.h>
31
32 #include <mali_kbase_defs.h>
33 #include <mali_kbase_config_defaults.h>
34
35 #include "mali_kbase_jm.h"
36 #include "mali_kbase_hwaccess_jm.h"
37 #include <linux/priority_control_manager.h>
38
39 /*
40 * Private types
41 */
42
43 /* Bitpattern indicating the result of releasing a context */
44 enum {
45 /* The context was descheduled - caller should try scheduling in a new
46 * one to keep the runpool full
47 */
48 KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED = (1u << 0),
49 /* Ctx attributes were changed - caller should try scheduling all
50 * contexts
51 */
52 KBASEP_JS_RELEASE_RESULT_SCHED_ALL = (1u << 1)
53 };
54
55 typedef u32 kbasep_js_release_result;
56
57 const int kbasep_js_atom_priority_to_relative[BASE_JD_NR_PRIO_LEVELS] = {
58 KBASE_JS_ATOM_SCHED_PRIO_MED, /* BASE_JD_PRIO_MEDIUM */
59 KBASE_JS_ATOM_SCHED_PRIO_HIGH, /* BASE_JD_PRIO_HIGH */
60 KBASE_JS_ATOM_SCHED_PRIO_LOW, /* BASE_JD_PRIO_LOW */
61 KBASE_JS_ATOM_SCHED_PRIO_REALTIME /* BASE_JD_PRIO_REALTIME */
62 };
63
64 const base_jd_prio
65 kbasep_js_relative_priority_to_atom[KBASE_JS_ATOM_SCHED_PRIO_COUNT] = {
66 BASE_JD_PRIO_REALTIME, /* KBASE_JS_ATOM_SCHED_PRIO_REALTIME */
67 BASE_JD_PRIO_HIGH, /* KBASE_JS_ATOM_SCHED_PRIO_HIGH */
68 BASE_JD_PRIO_MEDIUM, /* KBASE_JS_ATOM_SCHED_PRIO_MED */
69 BASE_JD_PRIO_LOW /* KBASE_JS_ATOM_SCHED_PRIO_LOW */
70 };
71
72
73 /*
74 * Private function prototypes
75 */
76 static kbasep_js_release_result kbasep_js_runpool_release_ctx_internal(
77 struct kbase_device *kbdev, struct kbase_context *kctx,
78 struct kbasep_js_atom_retained_state *katom_retained_state);
79
80 static int kbase_js_get_slot(struct kbase_device *kbdev,
81 struct kbase_jd_atom *katom);
82
83 static void kbase_js_foreach_ctx_job(struct kbase_context *kctx,
84 kbasep_js_ctx_job_cb *callback);
85
86 /* Helper for ktrace */
87 #if KBASE_KTRACE_ENABLE
kbase_ktrace_get_ctx_refcnt(struct kbase_context *kctx)88 static int kbase_ktrace_get_ctx_refcnt(struct kbase_context *kctx)
89 {
90 return atomic_read(&kctx->refcount);
91 }
92 #else /* KBASE_KTRACE_ENABLE */
kbase_ktrace_get_ctx_refcnt(struct kbase_context *kctx)93 static int kbase_ktrace_get_ctx_refcnt(struct kbase_context *kctx)
94 {
95 CSTD_UNUSED(kctx);
96 return 0;
97 }
98 #endif /* KBASE_KTRACE_ENABLE */
99
100 /*
101 * Private functions
102 */
103
104 /**
105 * core_reqs_from_jsn_features - Convert JSn_FEATURES to core requirements
106 * @features: JSn_FEATURE register value
107 *
108 * Given a JSn_FEATURE register value returns the core requirements that match
109 *
110 * Return: Core requirement bit mask
111 */
core_reqs_from_jsn_features(u16 features)112 static base_jd_core_req core_reqs_from_jsn_features(u16 features)
113 {
114 base_jd_core_req core_req = 0u;
115
116 if ((features & JS_FEATURE_SET_VALUE_JOB) != 0)
117 core_req |= BASE_JD_REQ_V;
118
119 if ((features & JS_FEATURE_CACHE_FLUSH_JOB) != 0)
120 core_req |= BASE_JD_REQ_CF;
121
122 if ((features & JS_FEATURE_COMPUTE_JOB) != 0)
123 core_req |= BASE_JD_REQ_CS;
124
125 if ((features & JS_FEATURE_TILER_JOB) != 0)
126 core_req |= BASE_JD_REQ_T;
127
128 if ((features & JS_FEATURE_FRAGMENT_JOB) != 0)
129 core_req |= BASE_JD_REQ_FS;
130
131 return core_req;
132 }
133
kbase_js_sync_timers(struct kbase_device *kbdev)134 static void kbase_js_sync_timers(struct kbase_device *kbdev)
135 {
136 mutex_lock(&kbdev->js_data.runpool_mutex);
137 kbase_backend_ctx_count_changed(kbdev);
138 mutex_unlock(&kbdev->js_data.runpool_mutex);
139 }
140
141 /**
142 * jsctx_rb_none_to_pull_prio(): - Check if there are no pullable atoms
143 * @kctx: Pointer to kbase context with ring buffer.
144 * @js: Job slot id to check.
145 * @prio: Priority to check.
146 *
147 * Return true if there are no atoms to pull. There may be running atoms in the
148 * ring buffer even if there are no atoms to pull. It is also possible for the
149 * ring buffer to be full (with running atoms) when this functions returns
150 * true.
151 *
152 * Return: true if there are no atoms to pull, false otherwise.
153 */
154 static inline bool
jsctx_rb_none_to_pull_prio(struct kbase_context *kctx, int js, int prio)155 jsctx_rb_none_to_pull_prio(struct kbase_context *kctx, int js, int prio)
156 {
157 bool none_to_pull;
158 struct jsctx_queue *rb = &kctx->jsctx_queue[prio][js];
159
160 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
161
162 none_to_pull = RB_EMPTY_ROOT(&rb->runnable_tree);
163
164 dev_dbg(kctx->kbdev->dev,
165 "Slot %d (prio %d) is %spullable in kctx %pK\n",
166 js, prio, none_to_pull ? "not " : "", kctx);
167
168 return none_to_pull;
169 }
170
171 /**
172 * jsctx_rb_none_to_pull(): - Check if all priority ring buffers have no
173 * pullable atoms
174 * @kctx: Pointer to kbase context with ring buffer.
175 * @js: Job slot id to check.
176 *
177 * Caller must hold hwaccess_lock
178 *
179 * Return: true if the ring buffers for all priorities have no pullable atoms,
180 * false otherwise.
181 */
182 static inline bool
jsctx_rb_none_to_pull(struct kbase_context *kctx, int js)183 jsctx_rb_none_to_pull(struct kbase_context *kctx, int js)
184 {
185 int prio;
186
187 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
188
189 for (prio = KBASE_JS_ATOM_SCHED_PRIO_FIRST;
190 prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT; prio++) {
191 if (!jsctx_rb_none_to_pull_prio(kctx, js, prio))
192 return false;
193 }
194
195 return true;
196 }
197
198 /**
199 * jsctx_queue_foreach_prio(): - Execute callback for each entry in the queue.
200 * @kctx: Pointer to kbase context with the queue.
201 * @js: Job slot id to iterate.
202 * @prio: Priority id to iterate.
203 * @callback: Function pointer to callback.
204 *
205 * Iterate over a queue and invoke @callback for each entry in the queue, and
206 * remove the entry from the queue.
207 *
208 * If entries are added to the queue while this is running those entries may, or
209 * may not be covered. To ensure that all entries in the buffer have been
210 * enumerated when this function returns jsctx->lock must be held when calling
211 * this function.
212 *
213 * The HW access lock must always be held when calling this function.
214 */
jsctx_queue_foreach_prio(struct kbase_context *kctx, int js, int prio, kbasep_js_ctx_job_cb *callback)215 static void jsctx_queue_foreach_prio(struct kbase_context *kctx, int js,
216 int prio, kbasep_js_ctx_job_cb *callback)
217 {
218 struct jsctx_queue *queue = &kctx->jsctx_queue[prio][js];
219
220 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
221
222 while (!RB_EMPTY_ROOT(&queue->runnable_tree)) {
223 struct rb_node *node = rb_first(&queue->runnable_tree);
224 struct kbase_jd_atom *entry = rb_entry(node,
225 struct kbase_jd_atom, runnable_tree_node);
226
227 rb_erase(node, &queue->runnable_tree);
228 callback(kctx->kbdev, entry);
229
230 /* Runnable end-of-renderpass atoms can also be in the linked
231 * list of atoms blocked on cross-slot dependencies. Remove them
232 * to avoid calling the callback twice.
233 */
234 if (entry->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST) {
235 WARN_ON(!(entry->core_req &
236 BASE_JD_REQ_END_RENDERPASS));
237 dev_dbg(kctx->kbdev->dev,
238 "Del runnable atom %pK from X_DEP list\n",
239 (void *)entry);
240
241 list_del(&entry->queue);
242 entry->atom_flags &=
243 ~KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST;
244 }
245 }
246
247 while (!list_empty(&queue->x_dep_head)) {
248 struct kbase_jd_atom *entry = list_entry(queue->x_dep_head.next,
249 struct kbase_jd_atom, queue);
250
251 WARN_ON(!(entry->atom_flags &
252 KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST));
253 dev_dbg(kctx->kbdev->dev,
254 "Del blocked atom %pK from X_DEP list\n",
255 (void *)entry);
256
257 list_del(queue->x_dep_head.next);
258 entry->atom_flags &=
259 ~KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST;
260
261 callback(kctx->kbdev, entry);
262 }
263 }
264
265 /**
266 * jsctx_queue_foreach(): - Execute callback for each entry in every queue
267 * @kctx: Pointer to kbase context with queue.
268 * @js: Job slot id to iterate.
269 * @callback: Function pointer to callback.
270 *
271 * Iterate over all the different priorities, and for each call
272 * jsctx_queue_foreach_prio() to iterate over the queue and invoke @callback
273 * for each entry, and remove the entry from the queue.
274 */
jsctx_queue_foreach(struct kbase_context *kctx, int js, kbasep_js_ctx_job_cb *callback)275 static inline void jsctx_queue_foreach(struct kbase_context *kctx, int js,
276 kbasep_js_ctx_job_cb *callback)
277 {
278 int prio;
279
280 for (prio = KBASE_JS_ATOM_SCHED_PRIO_FIRST;
281 prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT; prio++)
282 jsctx_queue_foreach_prio(kctx, js, prio, callback);
283 }
284
285 /**
286 * jsctx_rb_peek_prio(): - Check buffer and get next atom
287 * @kctx: Pointer to kbase context with ring buffer.
288 * @js: Job slot id to check.
289 * @prio: Priority id to check.
290 *
291 * Check the ring buffer for the specified @js and @prio and return a pointer to
292 * the next atom, unless the ring buffer is empty.
293 *
294 * Return: Pointer to next atom in buffer, or NULL if there is no atom.
295 */
296 static inline struct kbase_jd_atom *
jsctx_rb_peek_prio(struct kbase_context *kctx, int js, int prio)297 jsctx_rb_peek_prio(struct kbase_context *kctx, int js, int prio)
298 {
299 struct jsctx_queue *rb = &kctx->jsctx_queue[prio][js];
300 struct rb_node *node;
301
302 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
303 dev_dbg(kctx->kbdev->dev,
304 "Peeking runnable tree of kctx %pK for prio %d (s:%d)\n",
305 (void *)kctx, prio, js);
306
307 node = rb_first(&rb->runnable_tree);
308 if (!node) {
309 dev_dbg(kctx->kbdev->dev, "Tree is empty\n");
310 return NULL;
311 }
312
313 return rb_entry(node, struct kbase_jd_atom, runnable_tree_node);
314 }
315
316 /**
317 * jsctx_rb_peek(): - Check all priority buffers and get next atom
318 * @kctx: Pointer to kbase context with ring buffer.
319 * @js: Job slot id to check.
320 *
321 * Check the ring buffers for all priorities, starting from
322 * KBASE_JS_ATOM_SCHED_PRIO_REALTIME, for the specified @js and @prio and return a
323 * pointer to the next atom, unless all the priority's ring buffers are empty.
324 *
325 * Caller must hold the hwaccess_lock.
326 *
327 * Return: Pointer to next atom in buffer, or NULL if there is no atom.
328 */
329 static inline struct kbase_jd_atom *
jsctx_rb_peek(struct kbase_context *kctx, int js)330 jsctx_rb_peek(struct kbase_context *kctx, int js)
331 {
332 int prio;
333
334 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
335
336 for (prio = KBASE_JS_ATOM_SCHED_PRIO_FIRST;
337 prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT; prio++) {
338 struct kbase_jd_atom *katom;
339
340 katom = jsctx_rb_peek_prio(kctx, js, prio);
341 if (katom)
342 return katom;
343 }
344
345 return NULL;
346 }
347
348 /**
349 * jsctx_rb_pull(): - Mark atom in list as running
350 * @kctx: Pointer to kbase context with ring buffer.
351 * @katom: Pointer to katom to pull.
352 *
353 * Mark an atom previously obtained from jsctx_rb_peek() as running.
354 *
355 * @katom must currently be at the head of the ring buffer.
356 */
357 static inline void
jsctx_rb_pull(struct kbase_context *kctx, struct kbase_jd_atom *katom)358 jsctx_rb_pull(struct kbase_context *kctx, struct kbase_jd_atom *katom)
359 {
360 int prio = katom->sched_priority;
361 int js = katom->slot_nr;
362 struct jsctx_queue *rb = &kctx->jsctx_queue[prio][js];
363
364 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
365
366 dev_dbg(kctx->kbdev->dev, "Erasing atom %pK from runnable tree of kctx %pK\n",
367 (void *)katom, (void *)kctx);
368
369 /* Atoms must be pulled in the correct order. */
370 WARN_ON(katom != jsctx_rb_peek_prio(kctx, js, prio));
371
372 rb_erase(&katom->runnable_tree_node, &rb->runnable_tree);
373 }
374
375 static void
jsctx_tree_add(struct kbase_context *kctx, struct kbase_jd_atom *katom)376 jsctx_tree_add(struct kbase_context *kctx, struct kbase_jd_atom *katom)
377 {
378 struct kbase_device *kbdev = kctx->kbdev;
379 int prio = katom->sched_priority;
380 int js = katom->slot_nr;
381 struct jsctx_queue *queue = &kctx->jsctx_queue[prio][js];
382 struct rb_node **new = &(queue->runnable_tree.rb_node), *parent = NULL;
383
384 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
385
386 dev_dbg(kbdev->dev, "Adding atom %pK to runnable tree of kctx %pK (s:%d)\n",
387 (void *)katom, (void *)kctx, js);
388
389 while (*new) {
390 struct kbase_jd_atom *entry = container_of(*new,
391 struct kbase_jd_atom, runnable_tree_node);
392
393 parent = *new;
394 if (kbase_jd_atom_is_younger(katom, entry))
395 new = &((*new)->rb_left);
396 else
397 new = &((*new)->rb_right);
398 }
399
400 /* Add new node and rebalance tree. */
401 rb_link_node(&katom->runnable_tree_node, parent, new);
402 rb_insert_color(&katom->runnable_tree_node, &queue->runnable_tree);
403
404 KBASE_TLSTREAM_TL_ATTRIB_ATOM_STATE(kbdev, katom, TL_ATOM_STATE_READY);
405 }
406
407 /**
408 * jsctx_rb_unpull(): - Undo marking of atom in list as running
409 * @kctx: Pointer to kbase context with ring buffer.
410 * @katom: Pointer to katom to unpull.
411 *
412 * Undo jsctx_rb_pull() and put @katom back in the queue.
413 *
414 * jsctx_rb_unpull() must be called on atoms in the same order the atoms were
415 * pulled.
416 */
417 static inline void
jsctx_rb_unpull(struct kbase_context *kctx, struct kbase_jd_atom *katom)418 jsctx_rb_unpull(struct kbase_context *kctx, struct kbase_jd_atom *katom)
419 {
420 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
421
422 KBASE_KTRACE_ADD_JM(kctx->kbdev, JS_UNPULL_JOB, kctx, katom, katom->jc,
423 0u);
424
425 jsctx_tree_add(kctx, katom);
426 }
427
428 static bool kbase_js_ctx_pullable(struct kbase_context *kctx,
429 int js,
430 bool is_scheduled);
431 static bool kbase_js_ctx_list_add_pullable_nolock(struct kbase_device *kbdev,
432 struct kbase_context *kctx,
433 int js);
434 static bool kbase_js_ctx_list_add_unpullable_nolock(struct kbase_device *kbdev,
435 struct kbase_context *kctx,
436 int js);
437
438 typedef bool(katom_ordering_func)(const struct kbase_jd_atom *,
439 const struct kbase_jd_atom *);
440
kbase_js_atom_runs_before(struct kbase_device *kbdev, const struct kbase_jd_atom *katom_a, const struct kbase_jd_atom *katom_b, const kbase_atom_ordering_flag_t order_flags)441 bool kbase_js_atom_runs_before(struct kbase_device *kbdev,
442 const struct kbase_jd_atom *katom_a,
443 const struct kbase_jd_atom *katom_b,
444 const kbase_atom_ordering_flag_t order_flags)
445 {
446 struct kbase_context *kctx_a = katom_a->kctx;
447 struct kbase_context *kctx_b = katom_b->kctx;
448 katom_ordering_func *samectxatomprio_ordering_func =
449 kbase_jd_atom_is_younger;
450
451 lockdep_assert_held(&kbdev->hwaccess_lock);
452
453 if (order_flags & KBASE_ATOM_ORDERING_FLAG_SEQNR)
454 samectxatomprio_ordering_func = kbase_jd_atom_is_earlier;
455
456 /* It only makes sense to make this test for atoms on the same slot */
457 WARN_ON(katom_a->slot_nr != katom_b->slot_nr);
458
459 if (kbdev->js_ctx_scheduling_mode ==
460 KBASE_JS_PROCESS_LOCAL_PRIORITY_MODE) {
461 /* In local priority mode, querying either way around for "a
462 * should run before b" and "b should run before a" should
463 * always be false when they're from different contexts
464 */
465 if (kctx_a != kctx_b)
466 return false;
467 } else {
468 /* In system priority mode, ordering is done first strictly by
469 * context priority, even when katom_b might be lower priority
470 * than katom_a. This is due to scheduling of contexts in order
471 * of highest priority first, regardless of whether the atoms
472 * for a particular slot from such contexts have the highest
473 * priority or not.
474 */
475 if (kctx_a != kctx_b) {
476 if (kctx_a->priority < kctx_b->priority)
477 return true;
478 if (kctx_a->priority > kctx_b->priority)
479 return false;
480 }
481 }
482
483 /* For same contexts/contexts with the same context priority (in system
484 * priority mode), ordering is next done by atom priority
485 */
486 if (katom_a->sched_priority < katom_b->sched_priority)
487 return true;
488 if (katom_a->sched_priority > katom_b->sched_priority)
489 return false;
490 /* For atoms of same priority on the same kctx, they are
491 * ordered by seq_nr/age (dependent on caller)
492 */
493 if (kctx_a == kctx_b && samectxatomprio_ordering_func(katom_a, katom_b))
494 return true;
495
496 return false;
497 }
498
499 /*
500 * Functions private to KBase ('Protected' functions)
501 */
kbasep_js_devdata_init(struct kbase_device * const kbdev)502 int kbasep_js_devdata_init(struct kbase_device * const kbdev)
503 {
504 struct kbasep_js_device_data *jsdd;
505 int i, j;
506
507 KBASE_DEBUG_ASSERT(kbdev != NULL);
508
509 jsdd = &kbdev->js_data;
510
511 #ifdef CONFIG_MALI_BIFROST_DEBUG
512 /* Soft-stop will be disabled on a single context by default unless
513 * softstop_always is set
514 */
515 jsdd->softstop_always = false;
516 #endif /* CONFIG_MALI_BIFROST_DEBUG */
517 jsdd->nr_all_contexts_running = 0;
518 jsdd->nr_user_contexts_running = 0;
519 jsdd->nr_contexts_pullable = 0;
520 atomic_set(&jsdd->nr_contexts_runnable, 0);
521 /* No ctx allowed to submit */
522 jsdd->runpool_irq.submit_allowed = 0u;
523 memset(jsdd->runpool_irq.ctx_attr_ref_count, 0,
524 sizeof(jsdd->runpool_irq.ctx_attr_ref_count));
525 memset(jsdd->runpool_irq.slot_affinities, 0,
526 sizeof(jsdd->runpool_irq.slot_affinities));
527 memset(jsdd->runpool_irq.slot_affinity_refcount, 0,
528 sizeof(jsdd->runpool_irq.slot_affinity_refcount));
529 INIT_LIST_HEAD(&jsdd->suspended_soft_jobs_list);
530
531 /* Config attributes */
532 jsdd->scheduling_period_ns = DEFAULT_JS_SCHEDULING_PERIOD_NS;
533 jsdd->soft_stop_ticks = DEFAULT_JS_SOFT_STOP_TICKS;
534 jsdd->soft_stop_ticks_cl = DEFAULT_JS_SOFT_STOP_TICKS_CL;
535 jsdd->hard_stop_ticks_ss = DEFAULT_JS_HARD_STOP_TICKS_SS;
536 jsdd->hard_stop_ticks_cl = DEFAULT_JS_HARD_STOP_TICKS_CL;
537 jsdd->hard_stop_ticks_dumping = DEFAULT_JS_HARD_STOP_TICKS_DUMPING;
538 jsdd->gpu_reset_ticks_ss = DEFAULT_JS_RESET_TICKS_SS;
539 jsdd->gpu_reset_ticks_cl = DEFAULT_JS_RESET_TICKS_CL;
540
541 jsdd->gpu_reset_ticks_dumping = DEFAULT_JS_RESET_TICKS_DUMPING;
542 jsdd->ctx_timeslice_ns = DEFAULT_JS_CTX_TIMESLICE_NS;
543 atomic_set(&jsdd->soft_job_timeout_ms, DEFAULT_JS_SOFT_JOB_TIMEOUT);
544
545 dev_dbg(kbdev->dev, "JS Config Attribs: ");
546 dev_dbg(kbdev->dev, "\tscheduling_period_ns:%u",
547 jsdd->scheduling_period_ns);
548 dev_dbg(kbdev->dev, "\tsoft_stop_ticks:%u",
549 jsdd->soft_stop_ticks);
550 dev_dbg(kbdev->dev, "\tsoft_stop_ticks_cl:%u",
551 jsdd->soft_stop_ticks_cl);
552 dev_dbg(kbdev->dev, "\thard_stop_ticks_ss:%u",
553 jsdd->hard_stop_ticks_ss);
554 dev_dbg(kbdev->dev, "\thard_stop_ticks_cl:%u",
555 jsdd->hard_stop_ticks_cl);
556 dev_dbg(kbdev->dev, "\thard_stop_ticks_dumping:%u",
557 jsdd->hard_stop_ticks_dumping);
558 dev_dbg(kbdev->dev, "\tgpu_reset_ticks_ss:%u",
559 jsdd->gpu_reset_ticks_ss);
560 dev_dbg(kbdev->dev, "\tgpu_reset_ticks_cl:%u",
561 jsdd->gpu_reset_ticks_cl);
562 dev_dbg(kbdev->dev, "\tgpu_reset_ticks_dumping:%u",
563 jsdd->gpu_reset_ticks_dumping);
564 dev_dbg(kbdev->dev, "\tctx_timeslice_ns:%u",
565 jsdd->ctx_timeslice_ns);
566 dev_dbg(kbdev->dev, "\tsoft_job_timeout:%i",
567 atomic_read(&jsdd->soft_job_timeout_ms));
568
569 if (!(jsdd->soft_stop_ticks < jsdd->hard_stop_ticks_ss &&
570 jsdd->hard_stop_ticks_ss < jsdd->gpu_reset_ticks_ss &&
571 jsdd->soft_stop_ticks < jsdd->hard_stop_ticks_dumping &&
572 jsdd->hard_stop_ticks_dumping <
573 jsdd->gpu_reset_ticks_dumping)) {
574 dev_err(kbdev->dev, "Job scheduler timeouts invalid; soft/hard/reset tick counts should be in increasing order\n");
575 return -EINVAL;
576 }
577
578 #if KBASE_DISABLE_SCHEDULING_SOFT_STOPS
579 dev_dbg(kbdev->dev, "Job Scheduling Soft-stops disabled, ignoring value for soft_stop_ticks==%u at %uns per tick. Other soft-stops may still occur.",
580 jsdd->soft_stop_ticks,
581 jsdd->scheduling_period_ns);
582 #endif
583 #if KBASE_DISABLE_SCHEDULING_HARD_STOPS
584 dev_dbg(kbdev->dev, "Job Scheduling Hard-stops disabled, ignoring values for hard_stop_ticks_ss==%d and hard_stop_ticks_dumping==%u at %uns per tick. Other hard-stops may still occur.",
585 jsdd->hard_stop_ticks_ss,
586 jsdd->hard_stop_ticks_dumping,
587 jsdd->scheduling_period_ns);
588 #endif
589 #if KBASE_DISABLE_SCHEDULING_SOFT_STOPS && KBASE_DISABLE_SCHEDULING_HARD_STOPS
590 dev_dbg(kbdev->dev, "Note: The JS tick timer (if coded) will still be run, but do nothing.");
591 #endif
592
593 for (i = 0; i < kbdev->gpu_props.num_job_slots; ++i)
594 jsdd->js_reqs[i] = core_reqs_from_jsn_features(
595 kbdev->gpu_props.props.raw_props.js_features[i]);
596
597 /* On error, we could continue on: providing none of the below resources
598 * rely on the ones above
599 */
600
601 mutex_init(&jsdd->runpool_mutex);
602 mutex_init(&jsdd->queue_mutex);
603 sema_init(&jsdd->schedule_sem, 1);
604
605 for (i = 0; i < kbdev->gpu_props.num_job_slots; ++i) {
606 for (j = KBASE_JS_ATOM_SCHED_PRIO_FIRST; j < KBASE_JS_ATOM_SCHED_PRIO_COUNT; ++j) {
607 INIT_LIST_HEAD(&jsdd->ctx_list_pullable[i][j]);
608 INIT_LIST_HEAD(&jsdd->ctx_list_unpullable[i][j]);
609 }
610 }
611
612 return 0;
613 }
614
kbasep_js_devdata_halt(struct kbase_device *kbdev)615 void kbasep_js_devdata_halt(struct kbase_device *kbdev)
616 {
617 CSTD_UNUSED(kbdev);
618 }
619
kbasep_js_devdata_term(struct kbase_device *kbdev)620 void kbasep_js_devdata_term(struct kbase_device *kbdev)
621 {
622 struct kbasep_js_device_data *js_devdata;
623 s8 zero_ctx_attr_ref_count[KBASEP_JS_CTX_ATTR_COUNT] = { 0, };
624
625 KBASE_DEBUG_ASSERT(kbdev != NULL);
626
627 js_devdata = &kbdev->js_data;
628
629 /* The caller must de-register all contexts before calling this
630 */
631 KBASE_DEBUG_ASSERT(js_devdata->nr_all_contexts_running == 0);
632 KBASE_DEBUG_ASSERT(memcmp(
633 js_devdata->runpool_irq.ctx_attr_ref_count,
634 zero_ctx_attr_ref_count,
635 sizeof(zero_ctx_attr_ref_count)) == 0);
636 CSTD_UNUSED(zero_ctx_attr_ref_count);
637 }
638
kbasep_js_kctx_init(struct kbase_context *const kctx)639 int kbasep_js_kctx_init(struct kbase_context *const kctx)
640 {
641 struct kbase_device *kbdev;
642 struct kbasep_js_kctx_info *js_kctx_info;
643 int i, j;
644
645 KBASE_DEBUG_ASSERT(kctx != NULL);
646
647 kbdev = kctx->kbdev;
648 KBASE_DEBUG_ASSERT(kbdev != NULL);
649
650 for (i = 0; i < BASE_JM_MAX_NR_SLOTS; ++i)
651 INIT_LIST_HEAD(&kctx->jctx.sched_info.ctx.ctx_list_entry[i]);
652
653 js_kctx_info = &kctx->jctx.sched_info;
654
655 kctx->slots_pullable = 0;
656 js_kctx_info->ctx.nr_jobs = 0;
657 kbase_ctx_flag_clear(kctx, KCTX_SCHEDULED);
658 kbase_ctx_flag_clear(kctx, KCTX_DYING);
659 memset(js_kctx_info->ctx.ctx_attr_ref_count, 0,
660 sizeof(js_kctx_info->ctx.ctx_attr_ref_count));
661
662 /* Initially, the context is disabled from submission until the create
663 * flags are set
664 */
665 kbase_ctx_flag_set(kctx, KCTX_SUBMIT_DISABLED);
666
667 /* On error, we could continue on: providing none of the below resources
668 * rely on the ones above
669 */
670 mutex_init(&js_kctx_info->ctx.jsctx_mutex);
671
672 init_waitqueue_head(&js_kctx_info->ctx.is_scheduled_wait);
673
674 for (i = KBASE_JS_ATOM_SCHED_PRIO_FIRST; i < KBASE_JS_ATOM_SCHED_PRIO_COUNT; i++) {
675 for (j = 0; j < BASE_JM_MAX_NR_SLOTS; j++) {
676 INIT_LIST_HEAD(&kctx->jsctx_queue[i][j].x_dep_head);
677 kctx->jsctx_queue[i][j].runnable_tree = RB_ROOT;
678 }
679 }
680
681 return 0;
682 }
683
kbasep_js_kctx_term(struct kbase_context *kctx)684 void kbasep_js_kctx_term(struct kbase_context *kctx)
685 {
686 struct kbase_device *kbdev;
687 struct kbasep_js_kctx_info *js_kctx_info;
688 int js;
689 bool update_ctx_count = false;
690 unsigned long flags;
691
692 KBASE_DEBUG_ASSERT(kctx != NULL);
693
694 kbdev = kctx->kbdev;
695 KBASE_DEBUG_ASSERT(kbdev != NULL);
696
697 js_kctx_info = &kctx->jctx.sched_info;
698
699 /* The caller must de-register all jobs before calling this */
700 KBASE_DEBUG_ASSERT(!kbase_ctx_flag(kctx, KCTX_SCHEDULED));
701 KBASE_DEBUG_ASSERT(js_kctx_info->ctx.nr_jobs == 0);
702
703 mutex_lock(&kbdev->js_data.queue_mutex);
704 mutex_lock(&kctx->jctx.sched_info.ctx.jsctx_mutex);
705
706 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
707 for (js = 0; js < kbdev->gpu_props.num_job_slots; js++)
708 list_del_init(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]);
709 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
710
711 if (kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF)) {
712 WARN_ON(atomic_read(&kbdev->js_data.nr_contexts_runnable) <= 0);
713 atomic_dec(&kbdev->js_data.nr_contexts_runnable);
714 update_ctx_count = true;
715 kbase_ctx_flag_clear(kctx, KCTX_RUNNABLE_REF);
716 }
717
718 mutex_unlock(&kctx->jctx.sched_info.ctx.jsctx_mutex);
719 mutex_unlock(&kbdev->js_data.queue_mutex);
720
721 if (update_ctx_count) {
722 mutex_lock(&kbdev->js_data.runpool_mutex);
723 kbase_backend_ctx_count_changed(kbdev);
724 mutex_unlock(&kbdev->js_data.runpool_mutex);
725 }
726 }
727
728 /*
729 * Priority blocking management functions
730 */
731
732 /* Should not normally use directly - use kbase_jsctx_slot_atom_pulled_dec() instead */
kbase_jsctx_slot_prio_blocked_clear(struct kbase_context *kctx, int js, int sched_prio)733 static void kbase_jsctx_slot_prio_blocked_clear(struct kbase_context *kctx,
734 int js, int sched_prio)
735 {
736 struct kbase_jsctx_slot_tracking *slot_tracking =
737 &kctx->slot_tracking[js];
738
739 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
740
741 slot_tracking->blocked &= ~(((kbase_js_prio_bitmap_t)1) << sched_prio);
742 KBASE_KTRACE_ADD_JM_SLOT_INFO(kctx->kbdev, JS_SLOT_PRIO_UNBLOCKED, kctx,
743 NULL, 0, js, (unsigned int)sched_prio);
744 }
745
kbase_jsctx_slot_atoms_pulled(struct kbase_context *kctx, int js)746 static int kbase_jsctx_slot_atoms_pulled(struct kbase_context *kctx, int js)
747 {
748 return atomic_read(&kctx->slot_tracking[js].atoms_pulled);
749 }
750
751 /*
752 * A priority level on a slot is blocked when:
753 * - that priority level is blocked
754 * - or, any higher priority level is blocked
755 */
kbase_jsctx_slot_prio_is_blocked(struct kbase_context *kctx, int js, int sched_prio)756 static bool kbase_jsctx_slot_prio_is_blocked(struct kbase_context *kctx, int js,
757 int sched_prio)
758 {
759 struct kbase_jsctx_slot_tracking *slot_tracking =
760 &kctx->slot_tracking[js];
761 kbase_js_prio_bitmap_t prio_bit, higher_prios_mask;
762
763 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
764
765 /* done in two separate shifts to prevent future undefined behavior
766 * should the number of priority levels == (bit width of the type)
767 */
768 prio_bit = (((kbase_js_prio_bitmap_t)1) << sched_prio);
769 /* all bits of sched_prio or higher, with sched_prio = 0 being the
770 * highest priority
771 */
772 higher_prios_mask = (prio_bit << 1) - 1u;
773 return (slot_tracking->blocked & higher_prios_mask) != 0u;
774 }
775
776 /**
777 * kbase_jsctx_slot_atom_pulled_inc - Increase counts of atoms that have being
778 * pulled for a slot from a ctx, based on
779 * this atom
780 * @kctx: kbase context
781 * @katom: atom pulled
782 *
783 * Manages counts of atoms pulled (including per-priority-level counts), for
784 * later determining when a ctx can become unblocked on a slot.
785 *
786 * Once a slot has been blocked at @katom's priority level, it should not be
787 * pulled from, hence this function should not be called in that case.
788 *
789 * The return value is to aid tracking of when @kctx becomes runnable.
790 *
791 * Return: new total count of atoms pulled from all slots on @kctx
792 */
kbase_jsctx_slot_atom_pulled_inc(struct kbase_context *kctx, const struct kbase_jd_atom *katom)793 static int kbase_jsctx_slot_atom_pulled_inc(struct kbase_context *kctx,
794 const struct kbase_jd_atom *katom)
795 {
796 int js = katom->slot_nr;
797 int sched_prio = katom->sched_priority;
798 struct kbase_jsctx_slot_tracking *slot_tracking =
799 &kctx->slot_tracking[js];
800 int nr_atoms_pulled;
801
802 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
803
804 WARN(kbase_jsctx_slot_prio_is_blocked(kctx, js, sched_prio),
805 "Should not have pulled atoms for slot %d from a context that is blocked at priority %d or higher",
806 js, sched_prio);
807
808 nr_atoms_pulled = atomic_inc_return(&kctx->atoms_pulled_all_slots);
809 atomic_inc(&slot_tracking->atoms_pulled);
810 slot_tracking->atoms_pulled_pri[sched_prio]++;
811
812 return nr_atoms_pulled;
813 }
814
815 /**
816 * kbase_jsctx_slot_atom_pulled_dec- Decrease counts of atoms that have being
817 * pulled for a slot from a ctx, and
818 * re-evaluate whether a context is blocked
819 * on this slot
820 * @kctx: kbase context
821 * @katom: atom that has just been removed from a job slot
822 *
823 * @kctx can become unblocked on a slot for a priority level when it no longer
824 * has any pulled atoms at that priority level on that slot, and all higher
825 * (numerically lower) priority levels are also unblocked @kctx on that
826 * slot. The latter condition is to retain priority ordering within @kctx.
827 *
828 * Return: true if the slot was previously blocked but has now become unblocked
829 * at @katom's priority level, false otherwise.
830 */
kbase_jsctx_slot_atom_pulled_dec(struct kbase_context *kctx, const struct kbase_jd_atom *katom)831 static bool kbase_jsctx_slot_atom_pulled_dec(struct kbase_context *kctx,
832 const struct kbase_jd_atom *katom)
833 {
834 int js = katom->slot_nr;
835 int sched_prio = katom->sched_priority;
836 int atoms_pulled_pri;
837 struct kbase_jsctx_slot_tracking *slot_tracking =
838 &kctx->slot_tracking[js];
839 bool slot_prio_became_unblocked = false;
840
841 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
842
843 atomic_dec(&kctx->atoms_pulled_all_slots);
844 atomic_dec(&slot_tracking->atoms_pulled);
845
846 atoms_pulled_pri = --(slot_tracking->atoms_pulled_pri[sched_prio]);
847
848 /* We can safely clear this priority level's blocked status even if
849 * higher priority levels are still blocked: a subsequent query to
850 * kbase_jsctx_slot_prio_is_blocked() will still return true
851 */
852 if (!atoms_pulled_pri &&
853 kbase_jsctx_slot_prio_is_blocked(kctx, js, sched_prio)) {
854 kbase_jsctx_slot_prio_blocked_clear(kctx, js, sched_prio);
855
856 if (!kbase_jsctx_slot_prio_is_blocked(kctx, js, sched_prio))
857 slot_prio_became_unblocked = true;
858 }
859
860 if (slot_prio_became_unblocked)
861 KBASE_KTRACE_ADD_JM_SLOT_INFO(kctx->kbdev,
862 JS_SLOT_PRIO_AND_HIGHER_UNBLOCKED,
863 kctx, katom, katom->jc, js,
864 (unsigned int)sched_prio);
865
866 return slot_prio_became_unblocked;
867 }
868
869 /**
870 * kbase_js_ctx_list_add_pullable_nolock - Variant of
871 * kbase_jd_ctx_list_add_pullable()
872 * where the caller must hold
873 * hwaccess_lock
874 * @kbdev: Device pointer
875 * @kctx: Context to add to queue
876 * @js: Job slot to use
877 *
878 * Caller must hold hwaccess_lock
879 *
880 * Return: true if caller should call kbase_backend_ctx_count_changed()
881 */
kbase_js_ctx_list_add_pullable_nolock(struct kbase_device *kbdev, struct kbase_context *kctx, int js)882 static bool kbase_js_ctx_list_add_pullable_nolock(struct kbase_device *kbdev,
883 struct kbase_context *kctx,
884 int js)
885 {
886 bool ret = false;
887
888 lockdep_assert_held(&kbdev->hwaccess_lock);
889 dev_dbg(kbdev->dev, "Add pullable tail kctx %pK (s:%d)\n",
890 (void *)kctx, js);
891
892 if (!list_empty(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]))
893 list_del_init(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]);
894
895 list_add_tail(&kctx->jctx.sched_info.ctx.ctx_list_entry[js],
896 &kbdev->js_data.ctx_list_pullable[js][kctx->priority]);
897
898 if (!kctx->slots_pullable) {
899 kbdev->js_data.nr_contexts_pullable++;
900 ret = true;
901 if (!kbase_jsctx_atoms_pulled(kctx)) {
902 WARN_ON(kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF));
903 kbase_ctx_flag_set(kctx, KCTX_RUNNABLE_REF);
904 atomic_inc(&kbdev->js_data.nr_contexts_runnable);
905 }
906 }
907 kctx->slots_pullable |= (1 << js);
908
909 return ret;
910 }
911
912 /**
913 * kbase_js_ctx_list_add_pullable_head_nolock - Variant of
914 * kbase_js_ctx_list_add_pullable_head()
915 * where the caller must hold
916 * hwaccess_lock
917 * @kbdev: Device pointer
918 * @kctx: Context to add to queue
919 * @js: Job slot to use
920 *
921 * Caller must hold hwaccess_lock
922 *
923 * Return: true if caller should call kbase_backend_ctx_count_changed()
924 */
kbase_js_ctx_list_add_pullable_head_nolock( struct kbase_device *kbdev, struct kbase_context *kctx, int js)925 static bool kbase_js_ctx_list_add_pullable_head_nolock(
926 struct kbase_device *kbdev, struct kbase_context *kctx, int js)
927 {
928 bool ret = false;
929
930 lockdep_assert_held(&kbdev->hwaccess_lock);
931 dev_dbg(kbdev->dev, "Add pullable head kctx %pK (s:%d)\n",
932 (void *)kctx, js);
933
934 if (!list_empty(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]))
935 list_del_init(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]);
936
937 list_add(&kctx->jctx.sched_info.ctx.ctx_list_entry[js],
938 &kbdev->js_data.ctx_list_pullable[js][kctx->priority]);
939
940 if (!kctx->slots_pullable) {
941 kbdev->js_data.nr_contexts_pullable++;
942 ret = true;
943 if (!kbase_jsctx_atoms_pulled(kctx)) {
944 WARN_ON(kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF));
945 kbase_ctx_flag_set(kctx, KCTX_RUNNABLE_REF);
946 atomic_inc(&kbdev->js_data.nr_contexts_runnable);
947 }
948 }
949 kctx->slots_pullable |= (1 << js);
950
951 return ret;
952 }
953
954 /**
955 * kbase_js_ctx_list_add_pullable_head - Add context to the head of the
956 * per-slot pullable context queue
957 * @kbdev: Device pointer
958 * @kctx: Context to add to queue
959 * @js: Job slot to use
960 *
961 * If the context is on either the pullable or unpullable queues, then it is
962 * removed before being added to the head.
963 *
964 * This function should be used when a context has been scheduled, but no jobs
965 * can currently be pulled from it.
966 *
967 * Return: true if caller should call kbase_backend_ctx_count_changed()
968 */
kbase_js_ctx_list_add_pullable_head(struct kbase_device *kbdev, struct kbase_context *kctx, int js)969 static bool kbase_js_ctx_list_add_pullable_head(struct kbase_device *kbdev,
970 struct kbase_context *kctx,
971 int js)
972 {
973 bool ret;
974 unsigned long flags;
975
976 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
977 ret = kbase_js_ctx_list_add_pullable_head_nolock(kbdev, kctx, js);
978 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
979
980 return ret;
981 }
982
983 /**
984 * kbase_js_ctx_list_add_unpullable_nolock - Add context to the tail of the
985 * per-slot unpullable context queue
986 * @kbdev: Device pointer
987 * @kctx: Context to add to queue
988 * @js: Job slot to use
989 *
990 * The context must already be on the per-slot pullable queue. It will be
991 * removed from the pullable queue before being added to the unpullable queue.
992 *
993 * This function should be used when a context has been pulled from, and there
994 * are no jobs remaining on the specified slot.
995 *
996 * Caller must hold hwaccess_lock
997 *
998 * Return: true if caller should call kbase_backend_ctx_count_changed()
999 */
kbase_js_ctx_list_add_unpullable_nolock(struct kbase_device *kbdev, struct kbase_context *kctx, int js)1000 static bool kbase_js_ctx_list_add_unpullable_nolock(struct kbase_device *kbdev,
1001 struct kbase_context *kctx,
1002 int js)
1003 {
1004 bool ret = false;
1005
1006 lockdep_assert_held(&kbdev->hwaccess_lock);
1007 dev_dbg(kbdev->dev, "Add unpullable tail kctx %pK (s:%d)\n",
1008 (void *)kctx, js);
1009
1010 list_move_tail(&kctx->jctx.sched_info.ctx.ctx_list_entry[js],
1011 &kbdev->js_data.ctx_list_unpullable[js][kctx->priority]);
1012
1013 if (kctx->slots_pullable == (1 << js)) {
1014 kbdev->js_data.nr_contexts_pullable--;
1015 ret = true;
1016 if (!kbase_jsctx_atoms_pulled(kctx)) {
1017 WARN_ON(!kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF));
1018 kbase_ctx_flag_clear(kctx, KCTX_RUNNABLE_REF);
1019 atomic_dec(&kbdev->js_data.nr_contexts_runnable);
1020 }
1021 }
1022 kctx->slots_pullable &= ~(1 << js);
1023
1024 return ret;
1025 }
1026
1027 /**
1028 * kbase_js_ctx_list_remove_nolock - Remove context from the per-slot pullable
1029 * or unpullable context queues
1030 * @kbdev: Device pointer
1031 * @kctx: Context to remove from queue
1032 * @js: Job slot to use
1033 *
1034 * The context must already be on one of the queues.
1035 *
1036 * This function should be used when a context has no jobs on the GPU, and no
1037 * jobs remaining for the specified slot.
1038 *
1039 * Caller must hold hwaccess_lock
1040 *
1041 * Return: true if caller should call kbase_backend_ctx_count_changed()
1042 */
kbase_js_ctx_list_remove_nolock(struct kbase_device *kbdev, struct kbase_context *kctx, int js)1043 static bool kbase_js_ctx_list_remove_nolock(struct kbase_device *kbdev,
1044 struct kbase_context *kctx,
1045 int js)
1046 {
1047 bool ret = false;
1048
1049 lockdep_assert_held(&kbdev->hwaccess_lock);
1050
1051 WARN_ON(list_empty(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]));
1052
1053 list_del_init(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]);
1054
1055 if (kctx->slots_pullable == (1 << js)) {
1056 kbdev->js_data.nr_contexts_pullable--;
1057 ret = true;
1058 if (!kbase_jsctx_atoms_pulled(kctx)) {
1059 WARN_ON(!kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF));
1060 kbase_ctx_flag_clear(kctx, KCTX_RUNNABLE_REF);
1061 atomic_dec(&kbdev->js_data.nr_contexts_runnable);
1062 }
1063 }
1064 kctx->slots_pullable &= ~(1 << js);
1065
1066 return ret;
1067 }
1068
1069 /**
1070 * kbase_js_ctx_list_pop_head_nolock - Variant of kbase_js_ctx_list_pop_head()
1071 * where the caller must hold
1072 * hwaccess_lock
1073 * @kbdev: Device pointer
1074 * @js: Job slot to use
1075 *
1076 * Caller must hold hwaccess_lock
1077 *
1078 * Return: Context to use for specified slot.
1079 * NULL if no contexts present for specified slot
1080 */
kbase_js_ctx_list_pop_head_nolock( struct kbase_device *kbdev, int js)1081 static struct kbase_context *kbase_js_ctx_list_pop_head_nolock(
1082 struct kbase_device *kbdev,
1083 int js)
1084 {
1085 struct kbase_context *kctx;
1086 int i;
1087
1088 lockdep_assert_held(&kbdev->hwaccess_lock);
1089
1090 for (i = KBASE_JS_ATOM_SCHED_PRIO_FIRST; i < KBASE_JS_ATOM_SCHED_PRIO_COUNT; i++) {
1091 if (list_empty(&kbdev->js_data.ctx_list_pullable[js][i]))
1092 continue;
1093
1094 kctx = list_entry(kbdev->js_data.ctx_list_pullable[js][i].next,
1095 struct kbase_context,
1096 jctx.sched_info.ctx.ctx_list_entry[js]);
1097
1098 list_del_init(&kctx->jctx.sched_info.ctx.ctx_list_entry[js]);
1099 dev_dbg(kbdev->dev,
1100 "Popped %pK from the pullable queue (s:%d)\n",
1101 (void *)kctx, js);
1102 return kctx;
1103 }
1104 return NULL;
1105 }
1106
1107 /**
1108 * kbase_js_ctx_list_pop_head - Pop the head context off the per-slot pullable
1109 * queue.
1110 * @kbdev: Device pointer
1111 * @js: Job slot to use
1112 *
1113 * Return: Context to use for specified slot.
1114 * NULL if no contexts present for specified slot
1115 */
kbase_js_ctx_list_pop_head( struct kbase_device *kbdev, int js)1116 static struct kbase_context *kbase_js_ctx_list_pop_head(
1117 struct kbase_device *kbdev, int js)
1118 {
1119 struct kbase_context *kctx;
1120 unsigned long flags;
1121
1122 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
1123 kctx = kbase_js_ctx_list_pop_head_nolock(kbdev, js);
1124 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
1125
1126 return kctx;
1127 }
1128
1129 /**
1130 * kbase_js_ctx_pullable - Return if a context can be pulled from on the
1131 * specified slot
1132 * @kctx: Context pointer
1133 * @js: Job slot to use
1134 * @is_scheduled: true if the context is currently scheduled
1135 *
1136 * Caller must hold hwaccess_lock
1137 *
1138 * Return: true if context can be pulled from on specified slot
1139 * false otherwise
1140 */
kbase_js_ctx_pullable(struct kbase_context *kctx, int js, bool is_scheduled)1141 static bool kbase_js_ctx_pullable(struct kbase_context *kctx, int js,
1142 bool is_scheduled)
1143 {
1144 struct kbasep_js_device_data *js_devdata;
1145 struct kbase_jd_atom *katom;
1146 struct kbase_device *kbdev = kctx->kbdev;
1147
1148 lockdep_assert_held(&kbdev->hwaccess_lock);
1149
1150 js_devdata = &kbdev->js_data;
1151
1152 if (is_scheduled) {
1153 if (!kbasep_js_is_submit_allowed(js_devdata, kctx)) {
1154 dev_dbg(kbdev->dev, "JS: No submit allowed for kctx %pK\n",
1155 (void *)kctx);
1156 return false;
1157 }
1158 }
1159 katom = jsctx_rb_peek(kctx, js);
1160 if (!katom) {
1161 dev_dbg(kbdev->dev, "JS: No pullable atom in kctx %pK (s:%d)\n",
1162 (void *)kctx, js);
1163 return false; /* No pullable atoms */
1164 }
1165 if (kbase_jsctx_slot_prio_is_blocked(kctx, js, katom->sched_priority)) {
1166 KBASE_KTRACE_ADD_JM_SLOT_INFO(
1167 kctx->kbdev, JS_SLOT_PRIO_IS_BLOCKED, kctx, katom,
1168 katom->jc, js, (unsigned int)katom->sched_priority);
1169 dev_dbg(kbdev->dev,
1170 "JS: kctx %pK is blocked from submitting atoms at priority %d and lower (s:%d)\n",
1171 (void *)kctx, katom->sched_priority, js);
1172 return false;
1173 }
1174 if (atomic_read(&katom->blocked)) {
1175 dev_dbg(kbdev->dev, "JS: Atom %pK is blocked in js_ctx_pullable\n",
1176 (void *)katom);
1177 return false; /* next atom blocked */
1178 }
1179 if (kbase_js_atom_blocked_on_x_dep(katom)) {
1180 if (katom->x_pre_dep->gpu_rb_state ==
1181 KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB ||
1182 katom->x_pre_dep->will_fail_event_code) {
1183 dev_dbg(kbdev->dev,
1184 "JS: X pre-dep %pK is not present in slot FIFO or will fail\n",
1185 (void *)katom->x_pre_dep);
1186 return false;
1187 }
1188 if ((katom->atom_flags & KBASE_KATOM_FLAG_FAIL_BLOCKER) &&
1189 kbase_backend_nr_atoms_on_slot(kctx->kbdev, js)) {
1190 dev_dbg(kbdev->dev,
1191 "JS: Atom %pK has cross-slot fail dependency and atoms on slot (s:%d)\n",
1192 (void *)katom, js);
1193 return false;
1194 }
1195 }
1196
1197 dev_dbg(kbdev->dev, "JS: Atom %pK is pullable in kctx %pK (s:%d)\n",
1198 (void *)katom, (void *)kctx, js);
1199
1200 return true;
1201 }
1202
kbase_js_dep_validate(struct kbase_context *kctx, struct kbase_jd_atom *katom)1203 static bool kbase_js_dep_validate(struct kbase_context *kctx,
1204 struct kbase_jd_atom *katom)
1205 {
1206 struct kbase_device *kbdev = kctx->kbdev;
1207 bool ret = true;
1208 bool has_dep = false, has_x_dep = false;
1209 int js = kbase_js_get_slot(kbdev, katom);
1210 int prio = katom->sched_priority;
1211 int i;
1212
1213 for (i = 0; i < 2; i++) {
1214 struct kbase_jd_atom *dep_atom = katom->dep[i].atom;
1215
1216 if (dep_atom) {
1217 int dep_js = kbase_js_get_slot(kbdev, dep_atom);
1218 int dep_prio = dep_atom->sched_priority;
1219
1220 dev_dbg(kbdev->dev,
1221 "Checking dep %d of atom %pK (s:%d) on %pK (s:%d)\n",
1222 i, (void *)katom, js, (void *)dep_atom, dep_js);
1223
1224 /* Dependent atom must already have been submitted */
1225 if (!(dep_atom->atom_flags &
1226 KBASE_KATOM_FLAG_JSCTX_IN_TREE)) {
1227 dev_dbg(kbdev->dev,
1228 "Blocker not submitted yet\n");
1229 ret = false;
1230 break;
1231 }
1232
1233 /* Dependencies with different priorities can't
1234 * be represented in the ringbuffer
1235 */
1236 if (prio != dep_prio) {
1237 dev_dbg(kbdev->dev,
1238 "Different atom priorities\n");
1239 ret = false;
1240 break;
1241 }
1242
1243 if (js == dep_js) {
1244 /* Only one same-slot dependency can be
1245 * represented in the ringbuffer
1246 */
1247 if (has_dep) {
1248 dev_dbg(kbdev->dev,
1249 "Too many same-slot deps\n");
1250 ret = false;
1251 break;
1252 }
1253 /* Each dependee atom can only have one
1254 * same-slot dependency
1255 */
1256 if (dep_atom->post_dep) {
1257 dev_dbg(kbdev->dev,
1258 "Too many same-slot successors\n");
1259 ret = false;
1260 break;
1261 }
1262 has_dep = true;
1263 } else {
1264 /* Only one cross-slot dependency can be
1265 * represented in the ringbuffer
1266 */
1267 if (has_x_dep) {
1268 dev_dbg(kbdev->dev,
1269 "Too many cross-slot deps\n");
1270 ret = false;
1271 break;
1272 }
1273 /* Each dependee atom can only have one
1274 * cross-slot dependency
1275 */
1276 if (dep_atom->x_post_dep) {
1277 dev_dbg(kbdev->dev,
1278 "Too many cross-slot successors\n");
1279 ret = false;
1280 break;
1281 }
1282 /* The dependee atom can not already be in the
1283 * HW access ringbuffer
1284 */
1285 if (dep_atom->gpu_rb_state !=
1286 KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB) {
1287 dev_dbg(kbdev->dev,
1288 "Blocker already in ringbuffer (state:%d)\n",
1289 dep_atom->gpu_rb_state);
1290 ret = false;
1291 break;
1292 }
1293 /* The dependee atom can not already have
1294 * completed
1295 */
1296 if (dep_atom->status !=
1297 KBASE_JD_ATOM_STATE_IN_JS) {
1298 dev_dbg(kbdev->dev,
1299 "Blocker already completed (status:%d)\n",
1300 dep_atom->status);
1301 ret = false;
1302 break;
1303 }
1304
1305 has_x_dep = true;
1306 }
1307
1308 /* Dependency can be represented in ringbuffers */
1309 }
1310 }
1311
1312 /* If dependencies can be represented by ringbuffer then clear them from
1313 * atom structure
1314 */
1315 if (ret) {
1316 for (i = 0; i < 2; i++) {
1317 struct kbase_jd_atom *dep_atom = katom->dep[i].atom;
1318
1319 if (dep_atom) {
1320 int dep_js = kbase_js_get_slot(kbdev, dep_atom);
1321
1322 dev_dbg(kbdev->dev,
1323 "Clearing dep %d of atom %pK (s:%d) on %pK (s:%d)\n",
1324 i, (void *)katom, js, (void *)dep_atom,
1325 dep_js);
1326
1327 if ((js != dep_js) &&
1328 (dep_atom->status !=
1329 KBASE_JD_ATOM_STATE_COMPLETED)
1330 && (dep_atom->status !=
1331 KBASE_JD_ATOM_STATE_HW_COMPLETED)
1332 && (dep_atom->status !=
1333 KBASE_JD_ATOM_STATE_UNUSED)) {
1334
1335 katom->atom_flags |=
1336 KBASE_KATOM_FLAG_X_DEP_BLOCKED;
1337
1338 dev_dbg(kbdev->dev, "Set X_DEP flag on atom %pK\n",
1339 (void *)katom);
1340
1341 katom->x_pre_dep = dep_atom;
1342 dep_atom->x_post_dep = katom;
1343 if (kbase_jd_katom_dep_type(
1344 &katom->dep[i]) ==
1345 BASE_JD_DEP_TYPE_DATA)
1346 katom->atom_flags |=
1347 KBASE_KATOM_FLAG_FAIL_BLOCKER;
1348 }
1349 if ((kbase_jd_katom_dep_type(&katom->dep[i])
1350 == BASE_JD_DEP_TYPE_DATA) &&
1351 (js == dep_js)) {
1352 katom->pre_dep = dep_atom;
1353 dep_atom->post_dep = katom;
1354 }
1355
1356 list_del(&katom->dep_item[i]);
1357 kbase_jd_katom_dep_clear(&katom->dep[i]);
1358 }
1359 }
1360 } else {
1361 dev_dbg(kbdev->dev,
1362 "Deps of atom %pK (s:%d) could not be represented\n",
1363 (void *)katom, js);
1364 }
1365
1366 return ret;
1367 }
1368
kbase_js_set_ctx_priority(struct kbase_context *kctx, int new_priority)1369 void kbase_js_set_ctx_priority(struct kbase_context *kctx, int new_priority)
1370 {
1371 struct kbase_device *kbdev = kctx->kbdev;
1372 int js;
1373
1374 lockdep_assert_held(&kbdev->hwaccess_lock);
1375
1376 /* Move kctx to the pullable/upullable list as per the new priority */
1377 if (new_priority != kctx->priority) {
1378 for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) {
1379 if (kctx->slots_pullable & (1 << js))
1380 list_move_tail(&kctx->jctx.sched_info.ctx.ctx_list_entry[js],
1381 &kbdev->js_data.ctx_list_pullable[js][new_priority]);
1382 else
1383 list_move_tail(&kctx->jctx.sched_info.ctx.ctx_list_entry[js],
1384 &kbdev->js_data.ctx_list_unpullable[js][new_priority]);
1385 }
1386
1387 kctx->priority = new_priority;
1388 }
1389 }
1390
kbase_js_update_ctx_priority(struct kbase_context *kctx)1391 void kbase_js_update_ctx_priority(struct kbase_context *kctx)
1392 {
1393 struct kbase_device *kbdev = kctx->kbdev;
1394 int new_priority = KBASE_JS_ATOM_SCHED_PRIO_LOW;
1395 int prio;
1396
1397 lockdep_assert_held(&kbdev->hwaccess_lock);
1398
1399 if (kbdev->js_ctx_scheduling_mode == KBASE_JS_SYSTEM_PRIORITY_MODE) {
1400 /* Determine the new priority for context, as per the priority
1401 * of currently in-use atoms.
1402 */
1403 for (prio = KBASE_JS_ATOM_SCHED_PRIO_FIRST;
1404 prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT; prio++) {
1405 if (kctx->atoms_count[prio]) {
1406 new_priority = prio;
1407 break;
1408 }
1409 }
1410 }
1411
1412 kbase_js_set_ctx_priority(kctx, new_priority);
1413 }
1414 KBASE_EXPORT_TEST_API(kbase_js_update_ctx_priority);
1415
1416 /**
1417 * js_add_start_rp() - Add an atom that starts a renderpass to the job scheduler
1418 * @start_katom: Pointer to the atom to be added.
1419 * Return: 0 if successful or a negative value on failure.
1420 */
js_add_start_rp(struct kbase_jd_atom *const start_katom)1421 static int js_add_start_rp(struct kbase_jd_atom *const start_katom)
1422 {
1423 struct kbase_context *const kctx = start_katom->kctx;
1424 struct kbase_jd_renderpass *rp;
1425 struct kbase_device *const kbdev = kctx->kbdev;
1426 unsigned long flags;
1427
1428 lockdep_assert_held(&kctx->jctx.lock);
1429
1430 if (WARN_ON(!(start_katom->core_req & BASE_JD_REQ_START_RENDERPASS)))
1431 return -EINVAL;
1432
1433 if (start_katom->core_req & BASE_JD_REQ_END_RENDERPASS)
1434 return -EINVAL;
1435
1436 compiletime_assert((1ull << (sizeof(start_katom->renderpass_id) * 8)) <=
1437 ARRAY_SIZE(kctx->jctx.renderpasses),
1438 "Should check invalid access to renderpasses");
1439
1440 rp = &kctx->jctx.renderpasses[start_katom->renderpass_id];
1441
1442 if (rp->state != KBASE_JD_RP_COMPLETE)
1443 return -EINVAL;
1444
1445 dev_dbg(kctx->kbdev->dev, "JS add start atom %pK of RP %d\n",
1446 (void *)start_katom, start_katom->renderpass_id);
1447
1448 /* The following members are read when updating the job slot
1449 * ringbuffer/fifo therefore they require additional locking.
1450 */
1451 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
1452
1453 rp->state = KBASE_JD_RP_START;
1454 rp->start_katom = start_katom;
1455 rp->end_katom = NULL;
1456 INIT_LIST_HEAD(&rp->oom_reg_list);
1457
1458 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
1459
1460 return 0;
1461 }
1462
1463 /**
1464 * js_add_end_rp() - Add an atom that ends a renderpass to the job scheduler
1465 * @end_katom: Pointer to the atom to be added.
1466 * Return: 0 if successful or a negative value on failure.
1467 */
js_add_end_rp(struct kbase_jd_atom *const end_katom)1468 static int js_add_end_rp(struct kbase_jd_atom *const end_katom)
1469 {
1470 struct kbase_context *const kctx = end_katom->kctx;
1471 struct kbase_jd_renderpass *rp;
1472 struct kbase_device *const kbdev = kctx->kbdev;
1473
1474 lockdep_assert_held(&kctx->jctx.lock);
1475
1476 if (WARN_ON(!(end_katom->core_req & BASE_JD_REQ_END_RENDERPASS)))
1477 return -EINVAL;
1478
1479 if (end_katom->core_req & BASE_JD_REQ_START_RENDERPASS)
1480 return -EINVAL;
1481
1482 compiletime_assert((1ull << (sizeof(end_katom->renderpass_id) * 8)) <=
1483 ARRAY_SIZE(kctx->jctx.renderpasses),
1484 "Should check invalid access to renderpasses");
1485
1486 rp = &kctx->jctx.renderpasses[end_katom->renderpass_id];
1487
1488 dev_dbg(kbdev->dev, "JS add end atom %pK in state %d of RP %d\n",
1489 (void *)end_katom, (int)rp->state, end_katom->renderpass_id);
1490
1491 if (rp->state == KBASE_JD_RP_COMPLETE)
1492 return -EINVAL;
1493
1494 if (rp->end_katom == NULL) {
1495 /* We can't be in a retry state until the fragment job chain
1496 * has completed.
1497 */
1498 unsigned long flags;
1499
1500 WARN_ON(rp->state == KBASE_JD_RP_RETRY);
1501 WARN_ON(rp->state == KBASE_JD_RP_RETRY_PEND_OOM);
1502 WARN_ON(rp->state == KBASE_JD_RP_RETRY_OOM);
1503
1504 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
1505 rp->end_katom = end_katom;
1506 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
1507 } else
1508 WARN_ON(rp->end_katom != end_katom);
1509
1510 return 0;
1511 }
1512
kbasep_js_add_job(struct kbase_context *kctx, struct kbase_jd_atom *atom)1513 bool kbasep_js_add_job(struct kbase_context *kctx,
1514 struct kbase_jd_atom *atom)
1515 {
1516 unsigned long flags;
1517 struct kbasep_js_kctx_info *js_kctx_info;
1518 struct kbase_device *kbdev;
1519 struct kbasep_js_device_data *js_devdata;
1520 int err = 0;
1521
1522 bool enqueue_required = false;
1523 bool timer_sync = false;
1524
1525 KBASE_DEBUG_ASSERT(kctx != NULL);
1526 KBASE_DEBUG_ASSERT(atom != NULL);
1527 lockdep_assert_held(&kctx->jctx.lock);
1528
1529 kbdev = kctx->kbdev;
1530 js_devdata = &kbdev->js_data;
1531 js_kctx_info = &kctx->jctx.sched_info;
1532
1533 mutex_lock(&js_devdata->queue_mutex);
1534 mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
1535
1536 if (atom->core_req & BASE_JD_REQ_START_RENDERPASS)
1537 err = js_add_start_rp(atom);
1538 else if (atom->core_req & BASE_JD_REQ_END_RENDERPASS)
1539 err = js_add_end_rp(atom);
1540
1541 if (err < 0) {
1542 atom->event_code = BASE_JD_EVENT_JOB_INVALID;
1543 atom->status = KBASE_JD_ATOM_STATE_COMPLETED;
1544 goto out_unlock;
1545 }
1546
1547 /*
1548 * Begin Runpool transaction
1549 */
1550 mutex_lock(&js_devdata->runpool_mutex);
1551
1552 /* Refcount ctx.nr_jobs */
1553 KBASE_DEBUG_ASSERT(js_kctx_info->ctx.nr_jobs < U32_MAX);
1554 ++(js_kctx_info->ctx.nr_jobs);
1555 dev_dbg(kbdev->dev, "Add atom %pK to kctx %pK; now %d in ctx\n",
1556 (void *)atom, (void *)kctx, js_kctx_info->ctx.nr_jobs);
1557
1558 /* Lock for state available during IRQ */
1559 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
1560
1561 if (++kctx->atoms_count[atom->sched_priority] == 1)
1562 kbase_js_update_ctx_priority(kctx);
1563
1564 if (!kbase_js_dep_validate(kctx, atom)) {
1565 /* Dependencies could not be represented */
1566 --(js_kctx_info->ctx.nr_jobs);
1567 dev_dbg(kbdev->dev,
1568 "Remove atom %pK from kctx %pK; now %d in ctx\n",
1569 (void *)atom, (void *)kctx, js_kctx_info->ctx.nr_jobs);
1570
1571 /* Setting atom status back to queued as it still has unresolved
1572 * dependencies
1573 */
1574 atom->status = KBASE_JD_ATOM_STATE_QUEUED;
1575 dev_dbg(kbdev->dev, "Atom %pK status to queued\n", (void *)atom);
1576
1577 /* Undo the count, as the atom will get added again later but
1578 * leave the context priority adjusted or boosted, in case if
1579 * this was the first higher priority atom received for this
1580 * context.
1581 * This will prevent the scenario of priority inversion, where
1582 * another context having medium priority atoms keeps getting
1583 * scheduled over this context, which is having both lower and
1584 * higher priority atoms, but higher priority atoms are blocked
1585 * due to dependency on lower priority atoms. With priority
1586 * boost the high priority atom will get to run at earliest.
1587 */
1588 kctx->atoms_count[atom->sched_priority]--;
1589
1590 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
1591 mutex_unlock(&js_devdata->runpool_mutex);
1592
1593 goto out_unlock;
1594 }
1595
1596 enqueue_required = kbase_js_dep_resolved_submit(kctx, atom);
1597
1598 KBASE_KTRACE_ADD_JM_REFCOUNT(kbdev, JS_ADD_JOB, kctx, atom, atom->jc,
1599 kbase_ktrace_get_ctx_refcnt(kctx));
1600
1601 /* Context Attribute Refcounting */
1602 kbasep_js_ctx_attr_ctx_retain_atom(kbdev, kctx, atom);
1603
1604 if (enqueue_required) {
1605 if (kbase_js_ctx_pullable(kctx, atom->slot_nr, false))
1606 timer_sync = kbase_js_ctx_list_add_pullable_nolock(
1607 kbdev, kctx, atom->slot_nr);
1608 else
1609 timer_sync = kbase_js_ctx_list_add_unpullable_nolock(
1610 kbdev, kctx, atom->slot_nr);
1611 }
1612 /* If this context is active and the atom is the first on its slot,
1613 * kick the job manager to attempt to fast-start the atom
1614 */
1615 if (enqueue_required && kctx ==
1616 kbdev->hwaccess.active_kctx[atom->slot_nr])
1617 kbase_jm_try_kick(kbdev, 1 << atom->slot_nr);
1618
1619 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
1620 if (timer_sync)
1621 kbase_backend_ctx_count_changed(kbdev);
1622 mutex_unlock(&js_devdata->runpool_mutex);
1623 /* End runpool transaction */
1624
1625 if (!kbase_ctx_flag(kctx, KCTX_SCHEDULED)) {
1626 if (kbase_ctx_flag(kctx, KCTX_DYING)) {
1627 /* A job got added while/after kbase_job_zap_context()
1628 * was called on a non-scheduled context. Kill that job
1629 * by killing the context.
1630 */
1631 kbasep_js_runpool_requeue_or_kill_ctx(kbdev, kctx,
1632 false);
1633 } else if (js_kctx_info->ctx.nr_jobs == 1) {
1634 /* Handle Refcount going from 0 to 1: schedule the
1635 * context on the Queue
1636 */
1637 KBASE_DEBUG_ASSERT(!kbase_ctx_flag(kctx, KCTX_SCHEDULED));
1638 dev_dbg(kbdev->dev, "JS: Enqueue Context %pK", kctx);
1639
1640 /* Queue was updated - caller must try to schedule the
1641 * head context
1642 */
1643 WARN_ON(!enqueue_required);
1644 }
1645 }
1646 out_unlock:
1647 dev_dbg(kbdev->dev, "Enqueue of kctx %pK is %srequired\n",
1648 kctx, enqueue_required ? "" : "not ");
1649
1650 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
1651
1652 mutex_unlock(&js_devdata->queue_mutex);
1653
1654 return enqueue_required;
1655 }
1656
kbasep_js_remove_job(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_jd_atom *atom)1657 void kbasep_js_remove_job(struct kbase_device *kbdev,
1658 struct kbase_context *kctx, struct kbase_jd_atom *atom)
1659 {
1660 struct kbasep_js_kctx_info *js_kctx_info;
1661 unsigned long flags;
1662
1663 KBASE_DEBUG_ASSERT(kbdev != NULL);
1664 KBASE_DEBUG_ASSERT(kctx != NULL);
1665 KBASE_DEBUG_ASSERT(atom != NULL);
1666
1667 js_kctx_info = &kctx->jctx.sched_info;
1668
1669 KBASE_KTRACE_ADD_JM_REFCOUNT(kbdev, JS_REMOVE_JOB, kctx, atom, atom->jc,
1670 kbase_ktrace_get_ctx_refcnt(kctx));
1671
1672 /* De-refcount ctx.nr_jobs */
1673 KBASE_DEBUG_ASSERT(js_kctx_info->ctx.nr_jobs > 0);
1674 --(js_kctx_info->ctx.nr_jobs);
1675 dev_dbg(kbdev->dev,
1676 "Remove atom %pK from kctx %pK; now %d in ctx\n",
1677 (void *)atom, (void *)kctx, js_kctx_info->ctx.nr_jobs);
1678
1679 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
1680 if (--kctx->atoms_count[atom->sched_priority] == 0)
1681 kbase_js_update_ctx_priority(kctx);
1682 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
1683 }
1684
kbasep_js_remove_cancelled_job(struct kbase_device *kbdev, struct kbase_context *kctx, struct kbase_jd_atom *katom)1685 bool kbasep_js_remove_cancelled_job(struct kbase_device *kbdev,
1686 struct kbase_context *kctx, struct kbase_jd_atom *katom)
1687 {
1688 unsigned long flags;
1689 struct kbasep_js_atom_retained_state katom_retained_state;
1690 bool attr_state_changed;
1691
1692 KBASE_DEBUG_ASSERT(kbdev != NULL);
1693 KBASE_DEBUG_ASSERT(kctx != NULL);
1694 KBASE_DEBUG_ASSERT(katom != NULL);
1695
1696 kbasep_js_atom_retained_state_copy(&katom_retained_state, katom);
1697 kbasep_js_remove_job(kbdev, kctx, katom);
1698
1699 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
1700
1701 /* The atom has 'finished' (will not be re-run), so no need to call
1702 * kbasep_js_has_atom_finished().
1703 *
1704 * This is because it returns false for soft-stopped atoms, but we
1705 * want to override that, because we're cancelling an atom regardless of
1706 * whether it was soft-stopped or not
1707 */
1708 attr_state_changed = kbasep_js_ctx_attr_ctx_release_atom(kbdev, kctx,
1709 &katom_retained_state);
1710 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
1711
1712 return attr_state_changed;
1713 }
1714
1715 /**
1716 * kbasep_js_run_jobs_after_ctx_and_atom_release - Try running more jobs after
1717 * releasing a context and/or atom
1718 * @kbdev: The kbase_device to operate on
1719 * @kctx: The kbase_context to operate on
1720 * @katom_retained_state: Retained state from the atom
1721 * @runpool_ctx_attr_change: True if the runpool context attributes have changed
1722 *
1723 * This collates a set of actions that must happen whilst hwaccess_lock is held.
1724 *
1725 * This includes running more jobs when:
1726 * - The previously released kctx caused a ctx attribute change,
1727 * - The released atom caused a ctx attribute change,
1728 * - Slots were previously blocked due to affinity restrictions,
1729 * - Submission during IRQ handling failed.
1730 *
1731 * Return: %KBASEP_JS_RELEASE_RESULT_SCHED_ALL if context attributes were
1732 * changed. The caller should try scheduling all contexts
1733 */
kbasep_js_run_jobs_after_ctx_and_atom_release( struct kbase_device *kbdev, struct kbase_context *kctx, struct kbasep_js_atom_retained_state *katom_retained_state, bool runpool_ctx_attr_change)1734 static kbasep_js_release_result kbasep_js_run_jobs_after_ctx_and_atom_release(
1735 struct kbase_device *kbdev,
1736 struct kbase_context *kctx,
1737 struct kbasep_js_atom_retained_state *katom_retained_state,
1738 bool runpool_ctx_attr_change)
1739 {
1740 struct kbasep_js_device_data *js_devdata;
1741 kbasep_js_release_result result = 0;
1742
1743 KBASE_DEBUG_ASSERT(kbdev != NULL);
1744 KBASE_DEBUG_ASSERT(kctx != NULL);
1745 KBASE_DEBUG_ASSERT(katom_retained_state != NULL);
1746 js_devdata = &kbdev->js_data;
1747
1748 lockdep_assert_held(&kctx->jctx.sched_info.ctx.jsctx_mutex);
1749 lockdep_assert_held(&js_devdata->runpool_mutex);
1750 lockdep_assert_held(&kbdev->hwaccess_lock);
1751
1752 if (js_devdata->nr_user_contexts_running != 0 && runpool_ctx_attr_change) {
1753 /* A change in runpool ctx attributes might mean we can
1754 * run more jobs than before
1755 */
1756 result = KBASEP_JS_RELEASE_RESULT_SCHED_ALL;
1757
1758 KBASE_KTRACE_ADD_JM_SLOT(kbdev, JD_DONE_TRY_RUN_NEXT_JOB,
1759 kctx, NULL, 0u, 0);
1760 }
1761 return result;
1762 }
1763
1764 /**
1765 * kbasep_js_runpool_release_ctx_internal - Internal function to release the reference
1766 * on a ctx and an atom's "retained state", only
1767 * taking the runpool and as transaction mutexes
1768 * @kbdev: The kbase_device to operate on
1769 * @kctx: The kbase_context to operate on
1770 * @katom_retained_state: Retained state from the atom
1771 *
1772 * This also starts more jobs running in the case of an ctx-attribute state change
1773 *
1774 * This does none of the followup actions for scheduling:
1775 * - It does not schedule in a new context
1776 * - It does not requeue or handle dying contexts
1777 *
1778 * For those tasks, just call kbasep_js_runpool_release_ctx() instead
1779 *
1780 * Has following requirements
1781 * - Context is scheduled in, and kctx->as_nr matches kctx_as_nr
1782 * - Context has a non-zero refcount
1783 * - Caller holds js_kctx_info->ctx.jsctx_mutex
1784 * - Caller holds js_devdata->runpool_mutex
1785 *
1786 * Return: A bitpattern, containing KBASEP_JS_RELEASE_RESULT_* flags, indicating
1787 * the result of releasing a context that whether the caller should try
1788 * scheduling a new context or should try scheduling all contexts.
1789 */
kbasep_js_runpool_release_ctx_internal( struct kbase_device *kbdev, struct kbase_context *kctx, struct kbasep_js_atom_retained_state *katom_retained_state)1790 static kbasep_js_release_result kbasep_js_runpool_release_ctx_internal(
1791 struct kbase_device *kbdev,
1792 struct kbase_context *kctx,
1793 struct kbasep_js_atom_retained_state *katom_retained_state)
1794 {
1795 unsigned long flags;
1796 struct kbasep_js_device_data *js_devdata;
1797 struct kbasep_js_kctx_info *js_kctx_info;
1798
1799 kbasep_js_release_result release_result = 0u;
1800 bool runpool_ctx_attr_change = false;
1801 int kctx_as_nr;
1802 int new_ref_count;
1803
1804 KBASE_DEBUG_ASSERT(kbdev != NULL);
1805 KBASE_DEBUG_ASSERT(kctx != NULL);
1806 js_kctx_info = &kctx->jctx.sched_info;
1807 js_devdata = &kbdev->js_data;
1808
1809 /* Ensure context really is scheduled in */
1810 KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED));
1811
1812 kctx_as_nr = kctx->as_nr;
1813 KBASE_DEBUG_ASSERT(kctx_as_nr != KBASEP_AS_NR_INVALID);
1814 KBASE_DEBUG_ASSERT(atomic_read(&kctx->refcount) > 0);
1815
1816 /*
1817 * Transaction begins on AS and runpool_irq
1818 *
1819 * Assert about out calling contract
1820 */
1821 mutex_lock(&kbdev->pm.lock);
1822 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
1823
1824 KBASE_DEBUG_ASSERT(kctx_as_nr == kctx->as_nr);
1825 KBASE_DEBUG_ASSERT(atomic_read(&kctx->refcount) > 0);
1826
1827 /* Update refcount */
1828 kbase_ctx_sched_release_ctx(kctx);
1829 new_ref_count = atomic_read(&kctx->refcount);
1830
1831 /* Release the atom if it finished (i.e. wasn't soft-stopped) */
1832 if (kbasep_js_has_atom_finished(katom_retained_state))
1833 runpool_ctx_attr_change |= kbasep_js_ctx_attr_ctx_release_atom(
1834 kbdev, kctx, katom_retained_state);
1835
1836 if (new_ref_count == 2 && kbase_ctx_flag(kctx, KCTX_PRIVILEGED) &&
1837 #ifdef CONFIG_MALI_ARBITER_SUPPORT
1838 !kbase_pm_is_gpu_lost(kbdev) &&
1839 #endif
1840 !kbase_pm_is_suspending(kbdev)) {
1841 /* Context is kept scheduled into an address space even when
1842 * there are no jobs, in this case we have to handle the
1843 * situation where all jobs have been evicted from the GPU and
1844 * submission is disabled.
1845 *
1846 * At this point we re-enable submission to allow further jobs
1847 * to be executed
1848 */
1849 kbasep_js_set_submit_allowed(js_devdata, kctx);
1850 }
1851
1852 /* Make a set of checks to see if the context should be scheduled out.
1853 * Note that there'll always be at least 1 reference to the context
1854 * which was previously acquired by kbasep_js_schedule_ctx().
1855 */
1856 if (new_ref_count == 1 &&
1857 (!kbasep_js_is_submit_allowed(js_devdata, kctx) ||
1858 #ifdef CONFIG_MALI_ARBITER_SUPPORT
1859 kbase_pm_is_gpu_lost(kbdev) ||
1860 #endif
1861 kbase_pm_is_suspending(kbdev))) {
1862 int num_slots = kbdev->gpu_props.num_job_slots;
1863 int slot;
1864
1865 /* Last reference, and we've been told to remove this context
1866 * from the Run Pool
1867 */
1868 dev_dbg(kbdev->dev, "JS: RunPool Remove Context %pK because refcount=%d, jobs=%d, allowed=%d",
1869 kctx, new_ref_count, js_kctx_info->ctx.nr_jobs,
1870 kbasep_js_is_submit_allowed(js_devdata, kctx));
1871
1872 KBASE_TLSTREAM_TL_NRET_AS_CTX(kbdev, &kbdev->as[kctx->as_nr], kctx);
1873
1874 kbase_backend_release_ctx_irq(kbdev, kctx);
1875
1876 for (slot = 0; slot < num_slots; slot++) {
1877 if (kbdev->hwaccess.active_kctx[slot] == kctx) {
1878 dev_dbg(kbdev->dev, "Marking kctx %pK as inactive (s:%d)\n",
1879 (void *)kctx, slot);
1880 kbdev->hwaccess.active_kctx[slot] = NULL;
1881 }
1882 }
1883
1884 /* Ctx Attribute handling
1885 *
1886 * Releasing atoms attributes must either happen before this, or
1887 * after the KCTX_SHEDULED flag is changed, otherwise we
1888 * double-decount the attributes
1889 */
1890 runpool_ctx_attr_change |=
1891 kbasep_js_ctx_attr_runpool_release_ctx(kbdev, kctx);
1892
1893 /* Releasing the context and katom retained state can allow
1894 * more jobs to run
1895 */
1896 release_result |=
1897 kbasep_js_run_jobs_after_ctx_and_atom_release(kbdev,
1898 kctx, katom_retained_state,
1899 runpool_ctx_attr_change);
1900
1901 /*
1902 * Transaction ends on AS and runpool_irq:
1903 *
1904 * By this point, the AS-related data is now clear and ready
1905 * for re-use.
1906 *
1907 * Since releases only occur once for each previous successful
1908 * retain, and no more retains are allowed on this context, no
1909 * other thread will be operating in this
1910 * code whilst we are
1911 */
1912
1913 /* Recalculate pullable status for all slots */
1914 for (slot = 0; slot < num_slots; slot++) {
1915 if (kbase_js_ctx_pullable(kctx, slot, false))
1916 kbase_js_ctx_list_add_pullable_nolock(kbdev,
1917 kctx, slot);
1918 }
1919
1920 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
1921
1922 kbase_backend_release_ctx_noirq(kbdev, kctx);
1923
1924 mutex_unlock(&kbdev->pm.lock);
1925
1926 /* Note: Don't reuse kctx_as_nr now */
1927
1928 /* Synchronize with any timers */
1929 kbase_backend_ctx_count_changed(kbdev);
1930
1931 /* update book-keeping info */
1932 kbase_ctx_flag_clear(kctx, KCTX_SCHEDULED);
1933 /* Signal any waiter that the context is not scheduled, so is
1934 * safe for termination - once the jsctx_mutex is also dropped,
1935 * and jobs have finished.
1936 */
1937 wake_up(&js_kctx_info->ctx.is_scheduled_wait);
1938
1939 /* Queue an action to occur after we've dropped the lock */
1940 release_result |= KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED |
1941 KBASEP_JS_RELEASE_RESULT_SCHED_ALL;
1942 } else {
1943 kbasep_js_run_jobs_after_ctx_and_atom_release(kbdev, kctx,
1944 katom_retained_state, runpool_ctx_attr_change);
1945
1946 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
1947 mutex_unlock(&kbdev->pm.lock);
1948 }
1949
1950 return release_result;
1951 }
1952
kbasep_js_runpool_release_ctx_nolock(struct kbase_device *kbdev, struct kbase_context *kctx)1953 void kbasep_js_runpool_release_ctx_nolock(struct kbase_device *kbdev,
1954 struct kbase_context *kctx)
1955 {
1956 struct kbasep_js_atom_retained_state katom_retained_state;
1957
1958 /* Setup a dummy katom_retained_state */
1959 kbasep_js_atom_retained_state_init_invalid(&katom_retained_state);
1960
1961 kbasep_js_runpool_release_ctx_internal(kbdev, kctx,
1962 &katom_retained_state);
1963 }
1964
kbasep_js_runpool_requeue_or_kill_ctx(struct kbase_device *kbdev, struct kbase_context *kctx, bool has_pm_ref)1965 void kbasep_js_runpool_requeue_or_kill_ctx(struct kbase_device *kbdev,
1966 struct kbase_context *kctx, bool has_pm_ref)
1967 {
1968 KBASE_DEBUG_ASSERT(kbdev != NULL);
1969 KBASE_DEBUG_ASSERT(kctx != NULL);
1970
1971 /* This is called if and only if you've you've detached the context from
1972 * the Runpool Queue, and not added it back to the Runpool
1973 */
1974 KBASE_DEBUG_ASSERT(!kbase_ctx_flag(kctx, KCTX_SCHEDULED));
1975
1976 if (kbase_ctx_flag(kctx, KCTX_DYING)) {
1977 /* Dying: don't requeue, but kill all jobs on the context. This
1978 * happens asynchronously
1979 */
1980 dev_dbg(kbdev->dev,
1981 "JS: ** Killing Context %pK on RunPool Remove **", kctx);
1982 kbase_js_foreach_ctx_job(kctx, &kbase_jd_cancel);
1983 }
1984 }
1985
kbasep_js_runpool_release_ctx_and_katom_retained_state( struct kbase_device *kbdev, struct kbase_context *kctx, struct kbasep_js_atom_retained_state *katom_retained_state)1986 void kbasep_js_runpool_release_ctx_and_katom_retained_state(
1987 struct kbase_device *kbdev, struct kbase_context *kctx,
1988 struct kbasep_js_atom_retained_state *katom_retained_state)
1989 {
1990 struct kbasep_js_device_data *js_devdata;
1991 struct kbasep_js_kctx_info *js_kctx_info;
1992 kbasep_js_release_result release_result;
1993
1994 KBASE_DEBUG_ASSERT(kbdev != NULL);
1995 KBASE_DEBUG_ASSERT(kctx != NULL);
1996 js_kctx_info = &kctx->jctx.sched_info;
1997 js_devdata = &kbdev->js_data;
1998
1999 mutex_lock(&js_devdata->queue_mutex);
2000 mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
2001 mutex_lock(&js_devdata->runpool_mutex);
2002
2003 release_result = kbasep_js_runpool_release_ctx_internal(kbdev, kctx,
2004 katom_retained_state);
2005
2006 /* Drop the runpool mutex to allow requeing kctx */
2007 mutex_unlock(&js_devdata->runpool_mutex);
2008
2009 if ((release_result & KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED) != 0u)
2010 kbasep_js_runpool_requeue_or_kill_ctx(kbdev, kctx, true);
2011
2012 /* Drop the jsctx_mutex to allow scheduling in a new context */
2013
2014 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
2015 mutex_unlock(&js_devdata->queue_mutex);
2016
2017 if (release_result & KBASEP_JS_RELEASE_RESULT_SCHED_ALL)
2018 kbase_js_sched_all(kbdev);
2019 }
2020
kbasep_js_runpool_release_ctx(struct kbase_device *kbdev, struct kbase_context *kctx)2021 void kbasep_js_runpool_release_ctx(struct kbase_device *kbdev,
2022 struct kbase_context *kctx)
2023 {
2024 struct kbasep_js_atom_retained_state katom_retained_state;
2025
2026 kbasep_js_atom_retained_state_init_invalid(&katom_retained_state);
2027
2028 kbasep_js_runpool_release_ctx_and_katom_retained_state(kbdev, kctx,
2029 &katom_retained_state);
2030 }
2031
2032 /* Variant of kbasep_js_runpool_release_ctx() that doesn't call into
2033 * kbase_js_sched_all()
2034 */
kbasep_js_runpool_release_ctx_no_schedule( struct kbase_device *kbdev, struct kbase_context *kctx)2035 static void kbasep_js_runpool_release_ctx_no_schedule(
2036 struct kbase_device *kbdev, struct kbase_context *kctx)
2037 {
2038 struct kbasep_js_device_data *js_devdata;
2039 struct kbasep_js_kctx_info *js_kctx_info;
2040 kbasep_js_release_result release_result;
2041 struct kbasep_js_atom_retained_state katom_retained_state_struct;
2042 struct kbasep_js_atom_retained_state *katom_retained_state =
2043 &katom_retained_state_struct;
2044
2045 KBASE_DEBUG_ASSERT(kbdev != NULL);
2046 KBASE_DEBUG_ASSERT(kctx != NULL);
2047 js_kctx_info = &kctx->jctx.sched_info;
2048 js_devdata = &kbdev->js_data;
2049 kbasep_js_atom_retained_state_init_invalid(katom_retained_state);
2050
2051 mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
2052 mutex_lock(&js_devdata->runpool_mutex);
2053
2054 release_result = kbasep_js_runpool_release_ctx_internal(kbdev, kctx,
2055 katom_retained_state);
2056
2057 /* Drop the runpool mutex to allow requeing kctx */
2058 mutex_unlock(&js_devdata->runpool_mutex);
2059 if ((release_result & KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED) != 0u)
2060 kbasep_js_runpool_requeue_or_kill_ctx(kbdev, kctx, true);
2061
2062 /* Drop the jsctx_mutex to allow scheduling in a new context */
2063 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
2064
2065 /* NOTE: could return release_result if the caller would like to know
2066 * whether it should schedule a new context, but currently no callers do
2067 */
2068 }
2069
kbase_js_set_timeouts(struct kbase_device *kbdev)2070 void kbase_js_set_timeouts(struct kbase_device *kbdev)
2071 {
2072 lockdep_assert_held(&kbdev->hwaccess_lock);
2073
2074 kbase_backend_timeouts_changed(kbdev);
2075 }
2076
kbasep_js_schedule_ctx(struct kbase_device *kbdev, struct kbase_context *kctx, int js)2077 static bool kbasep_js_schedule_ctx(struct kbase_device *kbdev,
2078 struct kbase_context *kctx,
2079 int js)
2080 {
2081 struct kbasep_js_device_data *js_devdata;
2082 struct kbasep_js_kctx_info *js_kctx_info;
2083 unsigned long flags;
2084 bool kctx_suspended = false;
2085 int as_nr;
2086
2087 dev_dbg(kbdev->dev, "Scheduling kctx %pK (s:%d)\n", kctx, js);
2088
2089 js_devdata = &kbdev->js_data;
2090 js_kctx_info = &kctx->jctx.sched_info;
2091
2092 /* Pick available address space for this context */
2093 mutex_lock(&kbdev->mmu_hw_mutex);
2094 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2095 as_nr = kbase_ctx_sched_retain_ctx(kctx);
2096 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2097 mutex_unlock(&kbdev->mmu_hw_mutex);
2098 if (as_nr == KBASEP_AS_NR_INVALID) {
2099 as_nr = kbase_backend_find_and_release_free_address_space(
2100 kbdev, kctx);
2101 if (as_nr != KBASEP_AS_NR_INVALID) {
2102 /* Attempt to retain the context again, this should
2103 * succeed
2104 */
2105 mutex_lock(&kbdev->mmu_hw_mutex);
2106 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2107 as_nr = kbase_ctx_sched_retain_ctx(kctx);
2108 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2109 mutex_unlock(&kbdev->mmu_hw_mutex);
2110
2111 WARN_ON(as_nr == KBASEP_AS_NR_INVALID);
2112 }
2113 }
2114 if (as_nr == KBASEP_AS_NR_INVALID)
2115 return false; /* No address spaces currently available */
2116
2117 /*
2118 * Atomic transaction on the Context and Run Pool begins
2119 */
2120 mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
2121 mutex_lock(&js_devdata->runpool_mutex);
2122 mutex_lock(&kbdev->mmu_hw_mutex);
2123 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2124
2125 /* Check to see if context is dying due to kbase_job_zap_context() */
2126 if (kbase_ctx_flag(kctx, KCTX_DYING)) {
2127 /* Roll back the transaction so far and return */
2128 kbase_ctx_sched_release_ctx(kctx);
2129
2130 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2131 mutex_unlock(&kbdev->mmu_hw_mutex);
2132 mutex_unlock(&js_devdata->runpool_mutex);
2133 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
2134
2135 return false;
2136 }
2137
2138 KBASE_KTRACE_ADD_JM_REFCOUNT(kbdev, JS_TRY_SCHEDULE_HEAD_CTX, kctx, NULL,
2139 0u,
2140 kbase_ktrace_get_ctx_refcnt(kctx));
2141
2142 kbase_ctx_flag_set(kctx, KCTX_SCHEDULED);
2143
2144 /* Assign context to previously chosen address space */
2145 if (!kbase_backend_use_ctx(kbdev, kctx, as_nr)) {
2146 /* Roll back the transaction so far and return */
2147 kbase_ctx_sched_release_ctx(kctx);
2148 kbase_ctx_flag_clear(kctx, KCTX_SCHEDULED);
2149
2150 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2151 mutex_unlock(&kbdev->mmu_hw_mutex);
2152 mutex_unlock(&js_devdata->runpool_mutex);
2153 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
2154
2155 return false;
2156 }
2157
2158 kbdev->hwaccess.active_kctx[js] = kctx;
2159
2160 KBASE_TLSTREAM_TL_RET_AS_CTX(kbdev, &kbdev->as[kctx->as_nr], kctx);
2161
2162 /* Cause any future waiter-on-termination to wait until the context is
2163 * descheduled
2164 */
2165 wake_up(&js_kctx_info->ctx.is_scheduled_wait);
2166
2167 /* Re-check for suspending: a suspend could've occurred, and all the
2168 * contexts could've been removed from the runpool before we took this
2169 * lock. In this case, we don't want to allow this context to run jobs,
2170 * we just want it out immediately.
2171 *
2172 * The DMB required to read the suspend flag was issued recently as part
2173 * of the hwaccess_lock locking. If a suspend occurs *after* that lock
2174 * was taken (i.e. this condition doesn't execute), then the
2175 * kbasep_js_suspend() code will cleanup this context instead (by virtue
2176 * of it being called strictly after the suspend flag is set, and will
2177 * wait for this lock to drop)
2178 */
2179 #ifdef CONFIG_MALI_ARBITER_SUPPORT
2180 if (kbase_pm_is_suspending(kbdev) || kbase_pm_is_gpu_lost(kbdev)) {
2181 #else
2182 if (kbase_pm_is_suspending(kbdev)) {
2183 #endif
2184 /* Cause it to leave at some later point */
2185 bool retained;
2186
2187 retained = kbase_ctx_sched_inc_refcount_nolock(kctx);
2188 KBASE_DEBUG_ASSERT(retained);
2189
2190 kbasep_js_clear_submit_allowed(js_devdata, kctx);
2191 kctx_suspended = true;
2192 }
2193
2194 kbase_ctx_flag_clear(kctx, KCTX_PULLED_SINCE_ACTIVE_JS0 << js);
2195
2196 /* Transaction complete */
2197 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2198 mutex_unlock(&kbdev->mmu_hw_mutex);
2199
2200 /* Synchronize with any timers */
2201 kbase_backend_ctx_count_changed(kbdev);
2202
2203 mutex_unlock(&js_devdata->runpool_mutex);
2204 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
2205 /* Note: after this point, the context could potentially get scheduled
2206 * out immediately
2207 */
2208
2209 if (kctx_suspended) {
2210 /* Finishing forcing out the context due to a suspend. Use a
2211 * variant of kbasep_js_runpool_release_ctx() that doesn't
2212 * schedule a new context, to prevent a risk of recursion back
2213 * into this function
2214 */
2215 kbasep_js_runpool_release_ctx_no_schedule(kbdev, kctx);
2216 return false;
2217 }
2218 return true;
2219 }
2220
2221 static bool kbase_js_use_ctx(struct kbase_device *kbdev,
2222 struct kbase_context *kctx,
2223 int js)
2224 {
2225 unsigned long flags;
2226
2227 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2228
2229 if (kbase_ctx_flag(kctx, KCTX_SCHEDULED) &&
2230 kbase_backend_use_ctx_sched(kbdev, kctx, js)) {
2231
2232 dev_dbg(kbdev->dev,
2233 "kctx %pK already has ASID - mark as active (s:%d)\n",
2234 (void *)kctx, js);
2235
2236 if (kbdev->hwaccess.active_kctx[js] != kctx) {
2237 kbdev->hwaccess.active_kctx[js] = kctx;
2238 kbase_ctx_flag_clear(kctx,
2239 KCTX_PULLED_SINCE_ACTIVE_JS0 << js);
2240 }
2241 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2242 return true; /* Context already scheduled */
2243 }
2244
2245 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2246 return kbasep_js_schedule_ctx(kbdev, kctx, js);
2247 }
2248
2249 void kbasep_js_schedule_privileged_ctx(struct kbase_device *kbdev,
2250 struct kbase_context *kctx)
2251 {
2252 struct kbasep_js_kctx_info *js_kctx_info;
2253 struct kbasep_js_device_data *js_devdata;
2254 bool is_scheduled;
2255
2256 KBASE_DEBUG_ASSERT(kbdev != NULL);
2257 KBASE_DEBUG_ASSERT(kctx != NULL);
2258
2259 js_devdata = &kbdev->js_data;
2260 js_kctx_info = &kctx->jctx.sched_info;
2261
2262 #ifdef CONFIG_MALI_ARBITER_SUPPORT
2263 /* This should only happen in response to a system call
2264 * from a user-space thread.
2265 * In a non-arbitrated environment this can never happen
2266 * whilst suspending.
2267 *
2268 * In an arbitrated environment, user-space threads can run
2269 * while we are suspended (for example GPU not available
2270 * to this VM), however in that case we will block on
2271 * the wait event for KCTX_SCHEDULED, since no context
2272 * can be scheduled until we have the GPU again.
2273 */
2274 if (kbdev->arb.arb_if == NULL)
2275 if (WARN_ON(kbase_pm_is_suspending(kbdev)))
2276 return;
2277 #else
2278 /* This should only happen in response to a system call
2279 * from a user-space thread.
2280 * In a non-arbitrated environment this can never happen
2281 * whilst suspending.
2282 */
2283 if (WARN_ON(kbase_pm_is_suspending(kbdev)))
2284 return;
2285 #endif
2286
2287 mutex_lock(&js_devdata->queue_mutex);
2288 mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
2289
2290 /* Mark the context as privileged */
2291 kbase_ctx_flag_set(kctx, KCTX_PRIVILEGED);
2292
2293 is_scheduled = kbase_ctx_flag(kctx, KCTX_SCHEDULED);
2294 if (!is_scheduled) {
2295 /* Add the context to the pullable list */
2296 if (kbase_js_ctx_list_add_pullable_head(kbdev, kctx, 0))
2297 kbase_js_sync_timers(kbdev);
2298
2299 /* Fast-starting requires the jsctx_mutex to be dropped,
2300 * because it works on multiple ctxs
2301 */
2302 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
2303 mutex_unlock(&js_devdata->queue_mutex);
2304
2305 /* Try to schedule the context in */
2306 kbase_js_sched_all(kbdev);
2307
2308 /* Wait for the context to be scheduled in */
2309 wait_event(kctx->jctx.sched_info.ctx.is_scheduled_wait,
2310 kbase_ctx_flag(kctx, KCTX_SCHEDULED));
2311 } else {
2312 /* Already scheduled in - We need to retain it to keep the
2313 * corresponding address space
2314 */
2315 WARN_ON(!kbase_ctx_sched_inc_refcount(kctx));
2316 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
2317 mutex_unlock(&js_devdata->queue_mutex);
2318 }
2319 }
2320 KBASE_EXPORT_TEST_API(kbasep_js_schedule_privileged_ctx);
2321
2322 void kbasep_js_release_privileged_ctx(struct kbase_device *kbdev,
2323 struct kbase_context *kctx)
2324 {
2325 struct kbasep_js_kctx_info *js_kctx_info;
2326
2327 KBASE_DEBUG_ASSERT(kctx != NULL);
2328 js_kctx_info = &kctx->jctx.sched_info;
2329
2330 /* We don't need to use the address space anymore */
2331 mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
2332 kbase_ctx_flag_clear(kctx, KCTX_PRIVILEGED);
2333 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
2334
2335 /* Release the context - it will be scheduled out */
2336 kbasep_js_runpool_release_ctx(kbdev, kctx);
2337
2338 kbase_js_sched_all(kbdev);
2339 }
2340 KBASE_EXPORT_TEST_API(kbasep_js_release_privileged_ctx);
2341
2342 void kbasep_js_suspend(struct kbase_device *kbdev)
2343 {
2344 unsigned long flags;
2345 struct kbasep_js_device_data *js_devdata;
2346 int i;
2347 u16 retained = 0u;
2348
2349 KBASE_DEBUG_ASSERT(kbdev);
2350 KBASE_DEBUG_ASSERT(kbase_pm_is_suspending(kbdev));
2351 js_devdata = &kbdev->js_data;
2352
2353 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2354
2355 /* Prevent all contexts from submitting */
2356 js_devdata->runpool_irq.submit_allowed = 0;
2357
2358 /* Retain each of the contexts, so we can cause it to leave even if it
2359 * had no refcount to begin with
2360 */
2361 for (i = BASE_MAX_NR_AS - 1; i >= 0; --i) {
2362 struct kbase_context *kctx = kbdev->as_to_kctx[i];
2363
2364 retained = retained << 1;
2365
2366 if (kctx && !(kbdev->as_free & (1u << i))) {
2367 kbase_ctx_sched_retain_ctx_refcount(kctx);
2368 retained |= 1u;
2369 /* This loop will not have an effect on the privileged
2370 * contexts as they would have an extra ref count
2371 * compared to the normal contexts, so they will hold
2372 * on to their address spaces. MMU will re-enabled for
2373 * them on resume.
2374 */
2375 }
2376 }
2377
2378 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2379
2380 /* De-ref the previous retain to ensure each context gets pulled out
2381 * sometime later.
2382 */
2383 for (i = 0;
2384 i < BASE_MAX_NR_AS;
2385 ++i, retained = retained >> 1) {
2386 struct kbase_context *kctx = kbdev->as_to_kctx[i];
2387
2388 if (retained & 1u)
2389 kbasep_js_runpool_release_ctx(kbdev, kctx);
2390 }
2391
2392 /* Caller must wait for all Power Manager active references to be
2393 * dropped
2394 */
2395 }
2396
2397 void kbasep_js_resume(struct kbase_device *kbdev)
2398 {
2399 struct kbasep_js_device_data *js_devdata;
2400 int js, prio;
2401
2402 KBASE_DEBUG_ASSERT(kbdev);
2403 js_devdata = &kbdev->js_data;
2404 KBASE_DEBUG_ASSERT(!kbase_pm_is_suspending(kbdev));
2405
2406 mutex_lock(&js_devdata->queue_mutex);
2407 for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) {
2408 for (prio = KBASE_JS_ATOM_SCHED_PRIO_FIRST;
2409 prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT; prio++) {
2410 struct kbase_context *kctx, *n;
2411 unsigned long flags;
2412
2413 #ifndef CONFIG_MALI_ARBITER_SUPPORT
2414 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2415
2416 list_for_each_entry_safe(kctx, n,
2417 &kbdev->js_data.ctx_list_unpullable[js][prio],
2418 jctx.sched_info.ctx.ctx_list_entry[js]) {
2419 struct kbasep_js_kctx_info *js_kctx_info;
2420 bool timer_sync = false;
2421
2422 /* Drop lock so we can take kctx mutexes */
2423 spin_unlock_irqrestore(&kbdev->hwaccess_lock,
2424 flags);
2425
2426 js_kctx_info = &kctx->jctx.sched_info;
2427
2428 mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
2429 mutex_lock(&js_devdata->runpool_mutex);
2430 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2431
2432 if (!kbase_ctx_flag(kctx, KCTX_SCHEDULED) &&
2433 kbase_js_ctx_pullable(kctx, js, false))
2434 timer_sync =
2435 kbase_js_ctx_list_add_pullable_nolock(
2436 kbdev, kctx, js);
2437
2438 spin_unlock_irqrestore(&kbdev->hwaccess_lock,
2439 flags);
2440
2441 if (timer_sync)
2442 kbase_backend_ctx_count_changed(kbdev);
2443
2444 mutex_unlock(&js_devdata->runpool_mutex);
2445 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
2446
2447 /* Take lock before accessing list again */
2448 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2449 }
2450 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2451 #else
2452 bool timer_sync = false;
2453
2454 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2455
2456 list_for_each_entry_safe(kctx, n,
2457 &kbdev->js_data.ctx_list_unpullable[js][prio],
2458 jctx.sched_info.ctx.ctx_list_entry[js]) {
2459
2460 if (!kbase_ctx_flag(kctx, KCTX_SCHEDULED) &&
2461 kbase_js_ctx_pullable(kctx, js, false))
2462 timer_sync |=
2463 kbase_js_ctx_list_add_pullable_nolock(
2464 kbdev, kctx, js);
2465 }
2466
2467 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2468
2469 if (timer_sync) {
2470 mutex_lock(&js_devdata->runpool_mutex);
2471 kbase_backend_ctx_count_changed(kbdev);
2472 mutex_unlock(&js_devdata->runpool_mutex);
2473 }
2474 #endif
2475 }
2476 }
2477 mutex_unlock(&js_devdata->queue_mutex);
2478
2479 /* Restart atom processing */
2480 kbase_js_sched_all(kbdev);
2481
2482 /* JS Resume complete */
2483 }
2484
2485 bool kbase_js_is_atom_valid(struct kbase_device *kbdev,
2486 struct kbase_jd_atom *katom)
2487 {
2488 if ((katom->core_req & BASE_JD_REQ_FS) &&
2489 (katom->core_req & (BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE |
2490 BASE_JD_REQ_T)))
2491 return false;
2492
2493 if ((katom->core_req & BASE_JD_REQ_JOB_SLOT) &&
2494 (katom->jobslot >= BASE_JM_MAX_NR_SLOTS))
2495 return false;
2496
2497 return true;
2498 }
2499
2500 static int kbase_js_get_slot(struct kbase_device *kbdev,
2501 struct kbase_jd_atom *katom)
2502 {
2503 if (katom->core_req & BASE_JD_REQ_JOB_SLOT)
2504 return katom->jobslot;
2505
2506 if (katom->core_req & BASE_JD_REQ_FS)
2507 return 0;
2508
2509 if (katom->core_req & BASE_JD_REQ_ONLY_COMPUTE) {
2510 if (katom->device_nr == 1 &&
2511 kbdev->gpu_props.num_core_groups == 2)
2512 return 2;
2513 }
2514
2515 return 1;
2516 }
2517
2518 bool kbase_js_dep_resolved_submit(struct kbase_context *kctx,
2519 struct kbase_jd_atom *katom)
2520 {
2521 bool enqueue_required, add_required = true;
2522
2523 katom->slot_nr = kbase_js_get_slot(kctx->kbdev, katom);
2524
2525 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
2526 lockdep_assert_held(&kctx->jctx.lock);
2527
2528 /* If slot will transition from unpullable to pullable then add to
2529 * pullable list
2530 */
2531 if (jsctx_rb_none_to_pull(kctx, katom->slot_nr)) {
2532 enqueue_required = true;
2533 } else {
2534 enqueue_required = false;
2535 }
2536
2537 if ((katom->atom_flags & KBASE_KATOM_FLAG_X_DEP_BLOCKED) ||
2538 (katom->pre_dep && (katom->pre_dep->atom_flags &
2539 KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST))) {
2540 int prio = katom->sched_priority;
2541 int js = katom->slot_nr;
2542 struct jsctx_queue *queue = &kctx->jsctx_queue[prio][js];
2543
2544 dev_dbg(kctx->kbdev->dev, "Add atom %pK to X_DEP list (s:%d)\n",
2545 (void *)katom, js);
2546
2547 list_add_tail(&katom->queue, &queue->x_dep_head);
2548 katom->atom_flags |= KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST;
2549 if (kbase_js_atom_blocked_on_x_dep(katom)) {
2550 enqueue_required = false;
2551 add_required = false;
2552 }
2553 } else {
2554 dev_dbg(kctx->kbdev->dev, "Atom %pK not added to X_DEP list\n",
2555 (void *)katom);
2556 }
2557
2558 if (add_required) {
2559 /* Check if there are lower priority jobs to soft stop */
2560 kbase_job_slot_ctx_priority_check_locked(kctx, katom);
2561
2562 /* Add atom to ring buffer. */
2563 jsctx_tree_add(kctx, katom);
2564 katom->atom_flags |= KBASE_KATOM_FLAG_JSCTX_IN_TREE;
2565 }
2566
2567 dev_dbg(kctx->kbdev->dev,
2568 "Enqueue of kctx %pK is %srequired to submit atom %pK\n",
2569 kctx, enqueue_required ? "" : "not ", katom);
2570
2571 return enqueue_required;
2572 }
2573
2574 /**
2575 * kbase_js_move_to_tree - Move atom (and any dependent atoms) to the
2576 * runnable_tree, ready for execution
2577 * @katom: Atom to submit
2578 *
2579 * It is assumed that @katom does not have KBASE_KATOM_FLAG_X_DEP_BLOCKED set,
2580 * but is still present in the x_dep list. If @katom has a same-slot dependent
2581 * atom then that atom (and any dependents) will also be moved.
2582 */
2583 static void kbase_js_move_to_tree(struct kbase_jd_atom *katom)
2584 {
2585 struct kbase_context *const kctx = katom->kctx;
2586
2587 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
2588
2589 while (katom) {
2590 WARN_ON(!(katom->atom_flags &
2591 KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST));
2592
2593 if (!kbase_js_atom_blocked_on_x_dep(katom)) {
2594 dev_dbg(kctx->kbdev->dev,
2595 "Del atom %pK from X_DEP list in js_move_to_tree\n",
2596 (void *)katom);
2597
2598 list_del(&katom->queue);
2599 katom->atom_flags &=
2600 ~KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST;
2601 /* For incremental rendering, an end-of-renderpass atom
2602 * may have had its dependency on start-of-renderpass
2603 * ignored and may therefore already be in the tree.
2604 */
2605 if (!(katom->atom_flags &
2606 KBASE_KATOM_FLAG_JSCTX_IN_TREE)) {
2607 jsctx_tree_add(kctx, katom);
2608 katom->atom_flags |=
2609 KBASE_KATOM_FLAG_JSCTX_IN_TREE;
2610 }
2611 } else {
2612 dev_dbg(kctx->kbdev->dev,
2613 "Atom %pK blocked on x-dep in js_move_to_tree\n",
2614 (void *)katom);
2615 break;
2616 }
2617
2618 katom = katom->post_dep;
2619 }
2620 }
2621
2622
2623 /**
2624 * kbase_js_evict_deps - Evict dependencies of a failed atom.
2625 * @kctx: Context pointer
2626 * @katom: Pointer to the atom that has failed.
2627 * @js: The job slot the katom was run on.
2628 * @prio: Priority of the katom.
2629 *
2630 * Remove all post dependencies of an atom from the context ringbuffers.
2631 *
2632 * The original atom's event_code will be propogated to all dependent atoms.
2633 *
2634 * Context: Caller must hold the HW access lock
2635 */
2636 static void kbase_js_evict_deps(struct kbase_context *kctx,
2637 struct kbase_jd_atom *katom, int js, int prio)
2638 {
2639 struct kbase_jd_atom *x_dep = katom->x_post_dep;
2640 struct kbase_jd_atom *next_katom = katom->post_dep;
2641
2642 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
2643
2644 if (next_katom) {
2645 KBASE_DEBUG_ASSERT(next_katom->status !=
2646 KBASE_JD_ATOM_STATE_HW_COMPLETED);
2647 next_katom->will_fail_event_code = katom->event_code;
2648
2649 }
2650
2651 /* Has cross slot depenency. */
2652 if (x_dep && (x_dep->atom_flags & (KBASE_KATOM_FLAG_JSCTX_IN_TREE |
2653 KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST))) {
2654 /* Remove dependency.*/
2655 x_dep->atom_flags &= ~KBASE_KATOM_FLAG_X_DEP_BLOCKED;
2656
2657 dev_dbg(kctx->kbdev->dev, "Cleared X_DEP flag on atom %pK\n",
2658 (void *)x_dep);
2659
2660 /* Fail if it had a data dependency. */
2661 if (x_dep->atom_flags & KBASE_KATOM_FLAG_FAIL_BLOCKER) {
2662 x_dep->will_fail_event_code = katom->event_code;
2663 }
2664 if (x_dep->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST)
2665 kbase_js_move_to_tree(x_dep);
2666 }
2667 }
2668
2669 struct kbase_jd_atom *kbase_js_pull(struct kbase_context *kctx, int js)
2670 {
2671 struct kbase_jd_atom *katom;
2672 struct kbasep_js_device_data *js_devdata;
2673 struct kbase_device *kbdev;
2674 int pulled;
2675
2676 KBASE_DEBUG_ASSERT(kctx);
2677
2678 kbdev = kctx->kbdev;
2679 dev_dbg(kbdev->dev, "JS: pulling an atom from kctx %pK (s:%d)\n",
2680 (void *)kctx, js);
2681
2682 js_devdata = &kbdev->js_data;
2683 lockdep_assert_held(&kbdev->hwaccess_lock);
2684
2685 if (!kbasep_js_is_submit_allowed(js_devdata, kctx)) {
2686 dev_dbg(kbdev->dev, "JS: No submit allowed for kctx %pK\n",
2687 (void *)kctx);
2688 return NULL;
2689 }
2690 #ifdef CONFIG_MALI_ARBITER_SUPPORT
2691 if (kbase_pm_is_suspending(kbdev) || kbase_pm_is_gpu_lost(kbdev))
2692 #else
2693 if (kbase_pm_is_suspending(kbdev))
2694 #endif
2695 return NULL;
2696
2697 katom = jsctx_rb_peek(kctx, js);
2698 if (!katom) {
2699 dev_dbg(kbdev->dev, "JS: No pullable atom in kctx %pK (s:%d)\n",
2700 (void *)kctx, js);
2701 return NULL;
2702 }
2703 if (kbase_jsctx_slot_prio_is_blocked(kctx, js, katom->sched_priority)) {
2704 dev_dbg(kbdev->dev,
2705 "JS: kctx %pK is blocked from submitting atoms at priority %d and lower (s:%d)\n",
2706 (void *)kctx, katom->sched_priority, js);
2707 return NULL;
2708 }
2709 if (atomic_read(&katom->blocked)) {
2710 dev_dbg(kbdev->dev, "JS: Atom %pK is blocked in js_pull\n",
2711 (void *)katom);
2712 return NULL;
2713 }
2714
2715 /* Due to ordering restrictions when unpulling atoms on failure, we do
2716 * not allow multiple runs of fail-dep atoms from the same context to be
2717 * present on the same slot
2718 */
2719 if (katom->pre_dep && kbase_jsctx_slot_atoms_pulled(kctx, js)) {
2720 struct kbase_jd_atom *prev_atom =
2721 kbase_backend_inspect_tail(kbdev, js);
2722
2723 if (prev_atom && prev_atom->kctx != kctx)
2724 return NULL;
2725 }
2726
2727 if (kbase_js_atom_blocked_on_x_dep(katom)) {
2728 if (katom->x_pre_dep->gpu_rb_state ==
2729 KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB ||
2730 katom->x_pre_dep->will_fail_event_code) {
2731 dev_dbg(kbdev->dev,
2732 "JS: X pre-dep %pK is not present in slot FIFO or will fail\n",
2733 (void *)katom->x_pre_dep);
2734 return NULL;
2735 }
2736 if ((katom->atom_flags & KBASE_KATOM_FLAG_FAIL_BLOCKER) &&
2737 kbase_backend_nr_atoms_on_slot(kbdev, js)) {
2738 dev_dbg(kbdev->dev,
2739 "JS: Atom %pK has cross-slot fail dependency and atoms on slot (s:%d)\n",
2740 (void *)katom, js);
2741 return NULL;
2742 }
2743 }
2744
2745 KBASE_KTRACE_ADD_JM_SLOT_INFO(kbdev, JS_PULL_JOB, kctx, katom,
2746 katom->jc, js, katom->sched_priority);
2747 kbase_ctx_flag_set(kctx, KCTX_PULLED);
2748 kbase_ctx_flag_set(kctx, (KCTX_PULLED_SINCE_ACTIVE_JS0 << js));
2749
2750 pulled = kbase_jsctx_slot_atom_pulled_inc(kctx, katom);
2751 if (pulled == 1 && !kctx->slots_pullable) {
2752 WARN_ON(kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF));
2753 kbase_ctx_flag_set(kctx, KCTX_RUNNABLE_REF);
2754 atomic_inc(&kbdev->js_data.nr_contexts_runnable);
2755 }
2756 jsctx_rb_pull(kctx, katom);
2757
2758 kbase_ctx_sched_retain_ctx_refcount(kctx);
2759
2760 katom->ticks = 0;
2761
2762 dev_dbg(kbdev->dev, "JS: successfully pulled atom %pK from kctx %pK (s:%d)\n",
2763 (void *)katom, (void *)kctx, js);
2764
2765 return katom;
2766 }
2767
2768 /**
2769 * js_return_of_start_rp() - Handle soft-stop of an atom that starts a
2770 * renderpass
2771 * @start_katom: Pointer to the start-of-renderpass atom that was soft-stopped
2772 *
2773 * This function is called to switch to incremental rendering if the tiler job
2774 * chain at the start of a renderpass has used too much memory. It prevents the
2775 * tiler job being pulled for execution in the job scheduler again until the
2776 * next phase of incremental rendering is complete.
2777 *
2778 * If the end-of-renderpass atom is already in the job scheduler (because a
2779 * previous attempt at tiling used too much memory during the same renderpass)
2780 * then it is unblocked; otherwise, it is run by handing it to the scheduler.
2781 */
2782 static void js_return_of_start_rp(struct kbase_jd_atom *const start_katom)
2783 {
2784 struct kbase_context *const kctx = start_katom->kctx;
2785 struct kbase_device *const kbdev = kctx->kbdev;
2786 struct kbase_jd_renderpass *rp;
2787 struct kbase_jd_atom *end_katom;
2788 unsigned long flags;
2789
2790 lockdep_assert_held(&kctx->jctx.lock);
2791
2792 if (WARN_ON(!(start_katom->core_req & BASE_JD_REQ_START_RENDERPASS)))
2793 return;
2794
2795 compiletime_assert((1ull << (sizeof(start_katom->renderpass_id) * 8)) <=
2796 ARRAY_SIZE(kctx->jctx.renderpasses),
2797 "Should check invalid access to renderpasses");
2798
2799 rp = &kctx->jctx.renderpasses[start_katom->renderpass_id];
2800
2801 if (WARN_ON(rp->start_katom != start_katom))
2802 return;
2803
2804 dev_dbg(kctx->kbdev->dev,
2805 "JS return start atom %pK in state %d of RP %d\n",
2806 (void *)start_katom, (int)rp->state,
2807 start_katom->renderpass_id);
2808
2809 if (WARN_ON(rp->state == KBASE_JD_RP_COMPLETE))
2810 return;
2811
2812 /* The tiler job might have been soft-stopped for some reason other
2813 * than running out of memory.
2814 */
2815 if (rp->state == KBASE_JD_RP_START || rp->state == KBASE_JD_RP_RETRY) {
2816 dev_dbg(kctx->kbdev->dev,
2817 "JS return isn't OOM in state %d of RP %d\n",
2818 (int)rp->state, start_katom->renderpass_id);
2819 return;
2820 }
2821
2822 dev_dbg(kctx->kbdev->dev,
2823 "JS return confirm OOM in state %d of RP %d\n",
2824 (int)rp->state, start_katom->renderpass_id);
2825
2826 if (WARN_ON(rp->state != KBASE_JD_RP_PEND_OOM &&
2827 rp->state != KBASE_JD_RP_RETRY_PEND_OOM))
2828 return;
2829
2830 /* Prevent the tiler job being pulled for execution in the
2831 * job scheduler again.
2832 */
2833 dev_dbg(kbdev->dev, "Blocking start atom %pK\n",
2834 (void *)start_katom);
2835 atomic_inc(&start_katom->blocked);
2836
2837 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2838
2839 rp->state = (rp->state == KBASE_JD_RP_PEND_OOM) ?
2840 KBASE_JD_RP_OOM : KBASE_JD_RP_RETRY_OOM;
2841
2842 /* Was the fragment job chain submitted to kbase yet? */
2843 end_katom = rp->end_katom;
2844 if (end_katom) {
2845 dev_dbg(kctx->kbdev->dev, "JS return add end atom %pK\n",
2846 (void *)end_katom);
2847
2848 if (rp->state == KBASE_JD_RP_RETRY_OOM) {
2849 /* Allow the end of the renderpass to be pulled for
2850 * execution again to continue incremental rendering.
2851 */
2852 dev_dbg(kbdev->dev, "Unblocking end atom %pK\n",
2853 (void *)end_katom);
2854 atomic_dec(&end_katom->blocked);
2855 WARN_ON(!(end_katom->atom_flags &
2856 KBASE_KATOM_FLAG_JSCTX_IN_TREE));
2857 WARN_ON(end_katom->status != KBASE_JD_ATOM_STATE_IN_JS);
2858
2859 kbase_js_ctx_list_add_pullable_nolock(kbdev, kctx,
2860 end_katom->slot_nr);
2861
2862 /* Expect the fragment job chain to be scheduled without
2863 * further action because this function is called when
2864 * returning an atom to the job scheduler ringbuffer.
2865 */
2866 end_katom = NULL;
2867 } else {
2868 WARN_ON(end_katom->status !=
2869 KBASE_JD_ATOM_STATE_QUEUED &&
2870 end_katom->status != KBASE_JD_ATOM_STATE_IN_JS);
2871 }
2872 }
2873
2874 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2875
2876 if (end_katom)
2877 kbase_jd_dep_clear_locked(end_katom);
2878 }
2879
2880 /**
2881 * js_return_of_end_rp() - Handle completion of an atom that ends a renderpass
2882 * @end_katom: Pointer to the end-of-renderpass atom that was completed
2883 *
2884 * This function is called to continue incremental rendering if the tiler job
2885 * chain at the start of a renderpass used too much memory. It resets the
2886 * mechanism for detecting excessive memory usage then allows the soft-stopped
2887 * tiler job chain to be pulled for execution again.
2888 *
2889 * The start-of-renderpass atom must already been submitted to kbase.
2890 */
2891 static void js_return_of_end_rp(struct kbase_jd_atom *const end_katom)
2892 {
2893 struct kbase_context *const kctx = end_katom->kctx;
2894 struct kbase_device *const kbdev = kctx->kbdev;
2895 struct kbase_jd_renderpass *rp;
2896 struct kbase_jd_atom *start_katom;
2897 unsigned long flags;
2898
2899 lockdep_assert_held(&kctx->jctx.lock);
2900
2901 if (WARN_ON(!(end_katom->core_req & BASE_JD_REQ_END_RENDERPASS)))
2902 return;
2903
2904 compiletime_assert((1ull << (sizeof(end_katom->renderpass_id) * 8)) <=
2905 ARRAY_SIZE(kctx->jctx.renderpasses),
2906 "Should check invalid access to renderpasses");
2907
2908 rp = &kctx->jctx.renderpasses[end_katom->renderpass_id];
2909
2910 if (WARN_ON(rp->end_katom != end_katom))
2911 return;
2912
2913 dev_dbg(kctx->kbdev->dev,
2914 "JS return end atom %pK in state %d of RP %d\n",
2915 (void *)end_katom, (int)rp->state, end_katom->renderpass_id);
2916
2917 if (WARN_ON(rp->state != KBASE_JD_RP_OOM &&
2918 rp->state != KBASE_JD_RP_RETRY_OOM))
2919 return;
2920
2921 /* Reduce the number of mapped pages in the memory regions that
2922 * triggered out-of-memory last time so that we can detect excessive
2923 * memory usage again.
2924 */
2925 kbase_gpu_vm_lock(kctx);
2926 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2927
2928 while (!list_empty(&rp->oom_reg_list)) {
2929 struct kbase_va_region *reg =
2930 list_first_entry(&rp->oom_reg_list,
2931 struct kbase_va_region, link);
2932
2933 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2934
2935 dev_dbg(kbdev->dev,
2936 "Reset backing to %zu pages for region %pK\n",
2937 reg->threshold_pages, (void *)reg);
2938
2939 if (!WARN_ON(reg->flags & KBASE_REG_VA_FREED))
2940 kbase_mem_shrink(kctx, reg, reg->threshold_pages);
2941
2942 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2943 dev_dbg(kbdev->dev, "Deleting region %pK from list\n",
2944 (void *)reg);
2945 list_del_init(®->link);
2946 kbase_va_region_alloc_put(kctx, reg);
2947 }
2948
2949 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2950 kbase_gpu_vm_unlock(kctx);
2951
2952 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
2953 rp->state = KBASE_JD_RP_RETRY;
2954 dev_dbg(kbdev->dev, "Changed state to %d for retry\n", rp->state);
2955
2956 /* Allow the start of the renderpass to be pulled for execution again
2957 * to begin/continue incremental rendering.
2958 */
2959 start_katom = rp->start_katom;
2960 if (!WARN_ON(!start_katom)) {
2961 dev_dbg(kbdev->dev, "Unblocking start atom %pK\n",
2962 (void *)start_katom);
2963 atomic_dec(&start_katom->blocked);
2964 (void)kbase_js_ctx_list_add_pullable_head_nolock(kbdev, kctx,
2965 start_katom->slot_nr);
2966 }
2967
2968 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
2969 }
2970
2971 static void js_return_worker(struct work_struct *data)
2972 {
2973 struct kbase_jd_atom *katom = container_of(data, struct kbase_jd_atom,
2974 work);
2975 struct kbase_context *kctx = katom->kctx;
2976 struct kbase_device *kbdev = kctx->kbdev;
2977 struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
2978 struct kbasep_js_kctx_info *js_kctx_info = &kctx->jctx.sched_info;
2979 struct kbasep_js_atom_retained_state retained_state;
2980 int js = katom->slot_nr;
2981 bool slot_became_unblocked;
2982 bool timer_sync = false;
2983 bool context_idle = false;
2984 unsigned long flags;
2985 base_jd_core_req core_req = katom->core_req;
2986 u64 cache_jc = katom->jc;
2987
2988 dev_dbg(kbdev->dev, "%s for atom %pK with event code 0x%x\n",
2989 __func__, (void *)katom, katom->event_code);
2990
2991 KBASE_KTRACE_ADD_JM(kbdev, JS_RETURN_WORKER, kctx, katom, katom->jc, 0);
2992
2993 if (katom->event_code != BASE_JD_EVENT_END_RP_DONE)
2994 KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTSTOP_EX(kbdev, katom);
2995
2996 kbase_backend_complete_wq(kbdev, katom);
2997
2998 kbasep_js_atom_retained_state_copy(&retained_state, katom);
2999
3000 mutex_lock(&js_devdata->queue_mutex);
3001 mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
3002
3003 if (katom->event_code != BASE_JD_EVENT_END_RP_DONE)
3004 atomic_dec(&katom->blocked);
3005
3006 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
3007
3008 slot_became_unblocked = kbase_jsctx_slot_atom_pulled_dec(kctx, katom);
3009
3010 if (!kbase_jsctx_slot_atoms_pulled(kctx, js) &&
3011 jsctx_rb_none_to_pull(kctx, js))
3012 timer_sync |= kbase_js_ctx_list_remove_nolock(kbdev, kctx, js);
3013
3014 /* If the context is now unblocked on this slot after soft-stopped
3015 * atoms, then only mark it as pullable on this slot if it is not
3016 * idle
3017 */
3018 if (slot_became_unblocked && kbase_jsctx_atoms_pulled(kctx) &&
3019 kbase_js_ctx_pullable(kctx, js, true))
3020 timer_sync |=
3021 kbase_js_ctx_list_add_pullable_nolock(kbdev, kctx, js);
3022
3023 if (!kbase_jsctx_atoms_pulled(kctx)) {
3024 dev_dbg(kbdev->dev,
3025 "No atoms currently pulled from context %pK\n",
3026 (void *)kctx);
3027
3028 if (!kctx->slots_pullable) {
3029 dev_dbg(kbdev->dev,
3030 "Context %pK %s counted as runnable\n",
3031 (void *)kctx,
3032 kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF) ?
3033 "is" : "isn't");
3034
3035 WARN_ON(!kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF));
3036 kbase_ctx_flag_clear(kctx, KCTX_RUNNABLE_REF);
3037 atomic_dec(&kbdev->js_data.nr_contexts_runnable);
3038 timer_sync = true;
3039 }
3040
3041 if (kctx->as_nr != KBASEP_AS_NR_INVALID &&
3042 !kbase_ctx_flag(kctx, KCTX_DYING)) {
3043 int num_slots = kbdev->gpu_props.num_job_slots;
3044 int slot;
3045
3046 if (!kbasep_js_is_submit_allowed(js_devdata, kctx))
3047 kbasep_js_set_submit_allowed(js_devdata, kctx);
3048
3049 for (slot = 0; slot < num_slots; slot++) {
3050 if (kbase_js_ctx_pullable(kctx, slot, true))
3051 timer_sync |=
3052 kbase_js_ctx_list_add_pullable_nolock(
3053 kbdev, kctx, slot);
3054 }
3055 }
3056
3057 kbase_jm_idle_ctx(kbdev, kctx);
3058
3059 context_idle = true;
3060 }
3061
3062 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
3063
3064 if (context_idle) {
3065 dev_dbg(kbdev->dev,
3066 "Context %pK %s counted as active\n",
3067 (void *)kctx,
3068 kbase_ctx_flag(kctx, KCTX_ACTIVE) ?
3069 "is" : "isn't");
3070 WARN_ON(!kbase_ctx_flag(kctx, KCTX_ACTIVE));
3071 kbase_ctx_flag_clear(kctx, KCTX_ACTIVE);
3072 kbase_pm_context_idle(kbdev);
3073 }
3074
3075 if (timer_sync)
3076 kbase_js_sync_timers(kbdev);
3077
3078 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
3079 mutex_unlock(&js_devdata->queue_mutex);
3080
3081 if (katom->core_req & BASE_JD_REQ_START_RENDERPASS) {
3082 mutex_lock(&kctx->jctx.lock);
3083 js_return_of_start_rp(katom);
3084 mutex_unlock(&kctx->jctx.lock);
3085 } else if (katom->event_code == BASE_JD_EVENT_END_RP_DONE) {
3086 mutex_lock(&kctx->jctx.lock);
3087 js_return_of_end_rp(katom);
3088 mutex_unlock(&kctx->jctx.lock);
3089 }
3090
3091 dev_dbg(kbdev->dev, "JS: retained state %s finished",
3092 kbasep_js_has_atom_finished(&retained_state) ?
3093 "has" : "hasn't");
3094
3095 WARN_ON(kbasep_js_has_atom_finished(&retained_state));
3096
3097 kbasep_js_runpool_release_ctx_and_katom_retained_state(kbdev, kctx,
3098 &retained_state);
3099
3100 kbase_js_sched_all(kbdev);
3101
3102 kbase_backend_complete_wq_post_sched(kbdev, core_req);
3103
3104 KBASE_KTRACE_ADD_JM(kbdev, JS_RETURN_WORKER_END, kctx, NULL, cache_jc,
3105 0);
3106
3107 dev_dbg(kbdev->dev, "Leaving %s for atom %pK\n",
3108 __func__, (void *)katom);
3109 }
3110
3111 void kbase_js_unpull(struct kbase_context *kctx, struct kbase_jd_atom *katom)
3112 {
3113 dev_dbg(kctx->kbdev->dev, "Unpulling atom %pK in kctx %pK\n",
3114 (void *)katom, (void *)kctx);
3115
3116 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
3117
3118 jsctx_rb_unpull(kctx, katom);
3119
3120 WARN_ON(work_pending(&katom->work));
3121
3122 /* Block re-submission until workqueue has run */
3123 atomic_inc(&katom->blocked);
3124
3125 kbase_job_check_leave_disjoint(kctx->kbdev, katom);
3126
3127 INIT_WORK(&katom->work, js_return_worker);
3128 queue_work(kctx->jctx.job_done_wq, &katom->work);
3129 }
3130
3131 /**
3132 * js_complete_start_rp() - Handle completion of atom that starts a renderpass
3133 * @kctx: Context pointer
3134 * @start_katom: Pointer to the atom that completed
3135 *
3136 * Put any references to virtual memory regions that might have been added by
3137 * kbase_job_slot_softstop_start_rp() because the tiler job chain completed
3138 * despite any pending soft-stop request.
3139 *
3140 * If the atom that just completed was soft-stopped during a previous attempt to
3141 * run it then there should be a blocked end-of-renderpass atom waiting for it,
3142 * which we must unblock to process the output of the tiler job chain.
3143 *
3144 * Return: true if caller should call kbase_backend_ctx_count_changed()
3145 */
3146 static bool js_complete_start_rp(struct kbase_context *kctx,
3147 struct kbase_jd_atom *const start_katom)
3148 {
3149 struct kbase_device *const kbdev = kctx->kbdev;
3150 struct kbase_jd_renderpass *rp;
3151 bool timer_sync = false;
3152
3153 lockdep_assert_held(&kctx->jctx.lock);
3154
3155 if (WARN_ON(!(start_katom->core_req & BASE_JD_REQ_START_RENDERPASS)))
3156 return false;
3157
3158 compiletime_assert((1ull << (sizeof(start_katom->renderpass_id) * 8)) <=
3159 ARRAY_SIZE(kctx->jctx.renderpasses),
3160 "Should check invalid access to renderpasses");
3161
3162 rp = &kctx->jctx.renderpasses[start_katom->renderpass_id];
3163
3164 if (WARN_ON(rp->start_katom != start_katom))
3165 return false;
3166
3167 dev_dbg(kctx->kbdev->dev,
3168 "Start atom %pK is done in state %d of RP %d\n",
3169 (void *)start_katom, (int)rp->state,
3170 start_katom->renderpass_id);
3171
3172 if (WARN_ON(rp->state == KBASE_JD_RP_COMPLETE))
3173 return false;
3174
3175 if (rp->state == KBASE_JD_RP_PEND_OOM ||
3176 rp->state == KBASE_JD_RP_RETRY_PEND_OOM) {
3177 unsigned long flags;
3178
3179 dev_dbg(kctx->kbdev->dev,
3180 "Start atom %pK completed before soft-stop\n",
3181 (void *)start_katom);
3182
3183 kbase_gpu_vm_lock(kctx);
3184 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
3185
3186 while (!list_empty(&rp->oom_reg_list)) {
3187 struct kbase_va_region *reg =
3188 list_first_entry(&rp->oom_reg_list,
3189 struct kbase_va_region, link);
3190
3191 WARN_ON(reg->flags & KBASE_REG_VA_FREED);
3192 dev_dbg(kctx->kbdev->dev, "Deleting region %pK from list\n",
3193 (void *)reg);
3194 list_del_init(®->link);
3195 kbase_va_region_alloc_put(kctx, reg);
3196 }
3197
3198 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
3199 kbase_gpu_vm_unlock(kctx);
3200 } else {
3201 dev_dbg(kctx->kbdev->dev,
3202 "Start atom %pK did not exceed memory threshold\n",
3203 (void *)start_katom);
3204
3205 WARN_ON(rp->state != KBASE_JD_RP_START &&
3206 rp->state != KBASE_JD_RP_RETRY);
3207 }
3208
3209 if (rp->state == KBASE_JD_RP_RETRY ||
3210 rp->state == KBASE_JD_RP_RETRY_PEND_OOM) {
3211 struct kbase_jd_atom *const end_katom = rp->end_katom;
3212
3213 if (!WARN_ON(!end_katom)) {
3214 unsigned long flags;
3215
3216 /* Allow the end of the renderpass to be pulled for
3217 * execution again to continue incremental rendering.
3218 */
3219 dev_dbg(kbdev->dev, "Unblocking end atom %pK!\n",
3220 (void *)end_katom);
3221 atomic_dec(&end_katom->blocked);
3222
3223 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
3224 timer_sync = kbase_js_ctx_list_add_pullable_nolock(
3225 kbdev, kctx, end_katom->slot_nr);
3226 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
3227 }
3228 }
3229
3230 return timer_sync;
3231 }
3232
3233 /**
3234 * js_complete_end_rp() - Handle final completion of atom that ends a renderpass
3235 * @kctx: Context pointer
3236 * @end_katom: Pointer to the atom that completed for the last time
3237 *
3238 * This function must only be called if the renderpass actually completed
3239 * without the tiler job chain at the start using too much memory; otherwise
3240 * completion of the end-of-renderpass atom is handled similarly to a soft-stop.
3241 */
3242 static void js_complete_end_rp(struct kbase_context *kctx,
3243 struct kbase_jd_atom *const end_katom)
3244 {
3245 struct kbase_device *const kbdev = kctx->kbdev;
3246 unsigned long flags;
3247 struct kbase_jd_renderpass *rp;
3248
3249 lockdep_assert_held(&kctx->jctx.lock);
3250
3251 if (WARN_ON(!(end_katom->core_req & BASE_JD_REQ_END_RENDERPASS)))
3252 return;
3253
3254 compiletime_assert((1ull << (sizeof(end_katom->renderpass_id) * 8)) <=
3255 ARRAY_SIZE(kctx->jctx.renderpasses),
3256 "Should check invalid access to renderpasses");
3257
3258 rp = &kctx->jctx.renderpasses[end_katom->renderpass_id];
3259
3260 if (WARN_ON(rp->end_katom != end_katom))
3261 return;
3262
3263 dev_dbg(kbdev->dev, "End atom %pK is done in state %d of RP %d\n",
3264 (void *)end_katom, (int)rp->state, end_katom->renderpass_id);
3265
3266 if (WARN_ON(rp->state == KBASE_JD_RP_COMPLETE) ||
3267 WARN_ON(rp->state == KBASE_JD_RP_OOM) ||
3268 WARN_ON(rp->state == KBASE_JD_RP_RETRY_OOM))
3269 return;
3270
3271 /* Rendering completed without running out of memory.
3272 */
3273 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
3274 WARN_ON(!list_empty(&rp->oom_reg_list));
3275 rp->state = KBASE_JD_RP_COMPLETE;
3276 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
3277
3278 dev_dbg(kbdev->dev, "Renderpass %d is complete\n",
3279 end_katom->renderpass_id);
3280 }
3281
3282 bool kbase_js_complete_atom_wq(struct kbase_context *kctx,
3283 struct kbase_jd_atom *katom)
3284 {
3285 struct kbasep_js_kctx_info *js_kctx_info;
3286 struct kbasep_js_device_data *js_devdata;
3287 struct kbase_device *kbdev;
3288 unsigned long flags;
3289 bool timer_sync = false;
3290 int atom_slot;
3291 bool context_idle = false;
3292 int prio = katom->sched_priority;
3293
3294 kbdev = kctx->kbdev;
3295 atom_slot = katom->slot_nr;
3296
3297 dev_dbg(kbdev->dev, "%s for atom %pK (s:%d)\n",
3298 __func__, (void *)katom, atom_slot);
3299
3300 /* Update the incremental rendering state machine.
3301 */
3302 if (katom->core_req & BASE_JD_REQ_START_RENDERPASS)
3303 timer_sync |= js_complete_start_rp(kctx, katom);
3304 else if (katom->core_req & BASE_JD_REQ_END_RENDERPASS)
3305 js_complete_end_rp(kctx, katom);
3306
3307 js_kctx_info = &kctx->jctx.sched_info;
3308 js_devdata = &kbdev->js_data;
3309
3310 lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex);
3311
3312 mutex_lock(&js_devdata->runpool_mutex);
3313 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
3314
3315 if (katom->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_TREE) {
3316 bool slot_became_unblocked;
3317
3318 dev_dbg(kbdev->dev, "Atom %pK is in runnable_tree\n",
3319 (void *)katom);
3320
3321 slot_became_unblocked =
3322 kbase_jsctx_slot_atom_pulled_dec(kctx, katom);
3323 context_idle = !kbase_jsctx_atoms_pulled(kctx);
3324
3325 if (!kbase_jsctx_atoms_pulled(kctx) && !kctx->slots_pullable) {
3326 WARN_ON(!kbase_ctx_flag(kctx, KCTX_RUNNABLE_REF));
3327 kbase_ctx_flag_clear(kctx, KCTX_RUNNABLE_REF);
3328 atomic_dec(&kbdev->js_data.nr_contexts_runnable);
3329 timer_sync = true;
3330 }
3331
3332 /* If this slot has been blocked due to soft-stopped atoms, and
3333 * all atoms have now been processed at this priority level and
3334 * higher, then unblock the slot
3335 */
3336 if (slot_became_unblocked) {
3337 dev_dbg(kbdev->dev,
3338 "kctx %pK is no longer blocked from submitting on slot %d at priority %d or higher\n",
3339 (void *)kctx, atom_slot, prio);
3340
3341 if (kbase_js_ctx_pullable(kctx, atom_slot, true))
3342 timer_sync |=
3343 kbase_js_ctx_list_add_pullable_nolock(
3344 kbdev, kctx, atom_slot);
3345 }
3346 }
3347 WARN_ON(!(katom->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_TREE));
3348
3349 if (!kbase_jsctx_slot_atoms_pulled(kctx, atom_slot) &&
3350 jsctx_rb_none_to_pull(kctx, atom_slot)) {
3351 if (!list_empty(
3352 &kctx->jctx.sched_info.ctx.ctx_list_entry[atom_slot]))
3353 timer_sync |= kbase_js_ctx_list_remove_nolock(
3354 kctx->kbdev, kctx, atom_slot);
3355 }
3356
3357 /*
3358 * If submission is disabled on this context (most likely due to an
3359 * atom failure) and there are now no atoms left in the system then
3360 * re-enable submission so that context can be scheduled again.
3361 */
3362 if (!kbasep_js_is_submit_allowed(js_devdata, kctx) &&
3363 !kbase_jsctx_atoms_pulled(kctx) &&
3364 !kbase_ctx_flag(kctx, KCTX_DYING)) {
3365 int js;
3366
3367 kbasep_js_set_submit_allowed(js_devdata, kctx);
3368
3369 for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) {
3370 if (kbase_js_ctx_pullable(kctx, js, true))
3371 timer_sync |=
3372 kbase_js_ctx_list_add_pullable_nolock(
3373 kbdev, kctx, js);
3374 }
3375 } else if (katom->x_post_dep &&
3376 kbasep_js_is_submit_allowed(js_devdata, kctx)) {
3377 int js;
3378
3379 for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) {
3380 if (kbase_js_ctx_pullable(kctx, js, true))
3381 timer_sync |=
3382 kbase_js_ctx_list_add_pullable_nolock(
3383 kbdev, kctx, js);
3384 }
3385 }
3386
3387 /* Mark context as inactive. The pm reference will be dropped later in
3388 * jd_done_worker().
3389 */
3390 if (context_idle) {
3391 dev_dbg(kbdev->dev, "kctx %pK is no longer active\n",
3392 (void *)kctx);
3393 kbase_ctx_flag_clear(kctx, KCTX_ACTIVE);
3394 }
3395
3396 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
3397 if (timer_sync)
3398 kbase_backend_ctx_count_changed(kbdev);
3399 mutex_unlock(&js_devdata->runpool_mutex);
3400
3401 dev_dbg(kbdev->dev, "Leaving %s\n", __func__);
3402 return context_idle;
3403 }
3404
3405 /**
3406 * js_end_rp_is_complete() - Check whether an atom that ends a renderpass has
3407 * completed for the last time.
3408 *
3409 * @end_katom: Pointer to the atom that completed on the hardware.
3410 *
3411 * An atom that ends a renderpass may be run on the hardware several times
3412 * before notifying userspace or allowing dependent atoms to be executed.
3413 *
3414 * This function is used to decide whether or not to allow end-of-renderpass
3415 * atom completion. It only returns false if the atom at the start of the
3416 * renderpass was soft-stopped because it used too much memory during the most
3417 * recent attempt at tiling.
3418 *
3419 * Return: True if the atom completed for the last time.
3420 */
3421 static bool js_end_rp_is_complete(struct kbase_jd_atom *const end_katom)
3422 {
3423 struct kbase_context *const kctx = end_katom->kctx;
3424 struct kbase_device *const kbdev = kctx->kbdev;
3425 struct kbase_jd_renderpass *rp;
3426
3427 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
3428
3429 if (WARN_ON(!(end_katom->core_req & BASE_JD_REQ_END_RENDERPASS)))
3430 return true;
3431
3432 compiletime_assert((1ull << (sizeof(end_katom->renderpass_id) * 8)) <=
3433 ARRAY_SIZE(kctx->jctx.renderpasses),
3434 "Should check invalid access to renderpasses");
3435
3436 rp = &kctx->jctx.renderpasses[end_katom->renderpass_id];
3437
3438 if (WARN_ON(rp->end_katom != end_katom))
3439 return true;
3440
3441 dev_dbg(kbdev->dev,
3442 "JS complete end atom %pK in state %d of RP %d\n",
3443 (void *)end_katom, (int)rp->state,
3444 end_katom->renderpass_id);
3445
3446 if (WARN_ON(rp->state == KBASE_JD_RP_COMPLETE))
3447 return true;
3448
3449 /* Failure of end-of-renderpass atoms must not return to the
3450 * start of the renderpass.
3451 */
3452 if (end_katom->event_code != BASE_JD_EVENT_DONE)
3453 return true;
3454
3455 if (rp->state != KBASE_JD_RP_OOM &&
3456 rp->state != KBASE_JD_RP_RETRY_OOM)
3457 return true;
3458
3459 dev_dbg(kbdev->dev, "Suppressing end atom completion\n");
3460 return false;
3461 }
3462
3463 struct kbase_jd_atom *kbase_js_complete_atom(struct kbase_jd_atom *katom,
3464 ktime_t *end_timestamp)
3465 {
3466 struct kbase_device *kbdev;
3467 struct kbase_context *kctx = katom->kctx;
3468 struct kbase_jd_atom *x_dep = katom->x_post_dep;
3469
3470 kbdev = kctx->kbdev;
3471 dev_dbg(kbdev->dev, "Atom %pK complete in kctx %pK (post-dep %pK)\n",
3472 (void *)katom, (void *)kctx, (void *)x_dep);
3473
3474 lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
3475
3476 if ((katom->core_req & BASE_JD_REQ_END_RENDERPASS) &&
3477 !js_end_rp_is_complete(katom)) {
3478 katom->event_code = BASE_JD_EVENT_END_RP_DONE;
3479 kbase_js_unpull(kctx, katom);
3480 return NULL;
3481 }
3482
3483 if (katom->will_fail_event_code)
3484 katom->event_code = katom->will_fail_event_code;
3485
3486 katom->status = KBASE_JD_ATOM_STATE_HW_COMPLETED;
3487 dev_dbg(kbdev->dev, "Atom %pK status to HW completed\n", (void *)katom);
3488
3489 if (katom->event_code != BASE_JD_EVENT_DONE) {
3490 kbase_js_evict_deps(kctx, katom, katom->slot_nr,
3491 katom->sched_priority);
3492 }
3493
3494 KBASE_TLSTREAM_AUX_EVENT_JOB_SLOT(kbdev, NULL,
3495 katom->slot_nr, 0, TL_JS_EVENT_STOP);
3496
3497 trace_sysgraph_gpu(SGR_COMPLETE, kctx->id,
3498 kbase_jd_atom_id(katom->kctx, katom), katom->slot_nr);
3499
3500 KBASE_TLSTREAM_TL_JD_DONE_START(kbdev, katom);
3501 kbase_jd_done(katom, katom->slot_nr, end_timestamp, 0);
3502 KBASE_TLSTREAM_TL_JD_DONE_END(kbdev, katom);
3503
3504 /* Unblock cross dependency if present */
3505 if (x_dep && (katom->event_code == BASE_JD_EVENT_DONE ||
3506 !(x_dep->atom_flags & KBASE_KATOM_FLAG_FAIL_BLOCKER)) &&
3507 (x_dep->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST)) {
3508 bool was_pullable = kbase_js_ctx_pullable(kctx, x_dep->slot_nr,
3509 false);
3510 x_dep->atom_flags &= ~KBASE_KATOM_FLAG_X_DEP_BLOCKED;
3511 dev_dbg(kbdev->dev, "Cleared X_DEP flag on atom %pK\n",
3512 (void *)x_dep);
3513
3514 kbase_js_move_to_tree(x_dep);
3515
3516 if (!was_pullable && kbase_js_ctx_pullable(kctx, x_dep->slot_nr,
3517 false))
3518 kbase_js_ctx_list_add_pullable_nolock(kbdev, kctx,
3519 x_dep->slot_nr);
3520
3521 if (x_dep->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_TREE) {
3522 dev_dbg(kbdev->dev, "Atom %pK is in runnable tree\n",
3523 (void *)x_dep);
3524 return x_dep;
3525 }
3526 } else {
3527 dev_dbg(kbdev->dev,
3528 "No cross-slot dep to unblock for atom %pK\n",
3529 (void *)katom);
3530 }
3531
3532 return NULL;
3533 }
3534
3535 /**
3536 * kbase_js_atom_blocked_on_x_dep - Decide whether to ignore a cross-slot
3537 * dependency
3538 * @katom: Pointer to an atom in the slot ringbuffer
3539 *
3540 * A cross-slot dependency is ignored if necessary to unblock incremental
3541 * rendering. If the atom at the start of a renderpass used too much memory
3542 * and was soft-stopped then the atom at the end of a renderpass is submitted
3543 * to hardware regardless of its dependency on the start-of-renderpass atom.
3544 * This can happen multiple times for the same pair of atoms.
3545 *
3546 * Return: true to block the atom or false to allow it to be submitted to
3547 * hardware
3548 */
3549 bool kbase_js_atom_blocked_on_x_dep(struct kbase_jd_atom *const katom)
3550 {
3551 struct kbase_context *const kctx = katom->kctx;
3552 struct kbase_device *kbdev = kctx->kbdev;
3553 struct kbase_jd_renderpass *rp;
3554
3555 lockdep_assert_held(&kbdev->hwaccess_lock);
3556
3557 if (!(katom->atom_flags &
3558 KBASE_KATOM_FLAG_X_DEP_BLOCKED)) {
3559 dev_dbg(kbdev->dev, "Atom %pK is not blocked on a cross-slot dependency",
3560 (void *)katom);
3561 return false;
3562 }
3563
3564 if (!(katom->core_req & BASE_JD_REQ_END_RENDERPASS)) {
3565 dev_dbg(kbdev->dev, "Atom %pK is blocked on a cross-slot dependency",
3566 (void *)katom);
3567 return true;
3568 }
3569
3570 compiletime_assert((1ull << (sizeof(katom->renderpass_id) * 8)) <=
3571 ARRAY_SIZE(kctx->jctx.renderpasses),
3572 "Should check invalid access to renderpasses");
3573
3574 rp = &kctx->jctx.renderpasses[katom->renderpass_id];
3575 /* We can read a subset of renderpass state without holding
3576 * higher-level locks (but not end_katom, for example).
3577 */
3578
3579 WARN_ON(rp->state == KBASE_JD_RP_COMPLETE);
3580
3581 dev_dbg(kbdev->dev, "End atom has cross-slot dep in state %d\n",
3582 (int)rp->state);
3583
3584 if (rp->state != KBASE_JD_RP_OOM && rp->state != KBASE_JD_RP_RETRY_OOM)
3585 return true;
3586
3587 /* Tiler ran out of memory so allow the fragment job chain to run
3588 * if it only depends on the tiler job chain.
3589 */
3590 if (katom->x_pre_dep != rp->start_katom) {
3591 dev_dbg(kbdev->dev, "Dependency is on %pK not start atom %pK\n",
3592 (void *)katom->x_pre_dep, (void *)rp->start_katom);
3593 return true;
3594 }
3595
3596 dev_dbg(kbdev->dev, "Ignoring cross-slot dep on atom %pK\n",
3597 (void *)katom->x_pre_dep);
3598
3599 return false;
3600 }
3601
3602 void kbase_js_sched(struct kbase_device *kbdev, int js_mask)
3603 {
3604 struct kbasep_js_device_data *js_devdata;
3605 struct kbase_context *last_active[BASE_JM_MAX_NR_SLOTS];
3606 bool timer_sync = false;
3607 bool ctx_waiting[BASE_JM_MAX_NR_SLOTS];
3608 int js;
3609
3610 KBASE_TLSTREAM_TL_JS_SCHED_START(kbdev, 0);
3611
3612 dev_dbg(kbdev->dev, "%s kbdev %pK mask 0x%x\n",
3613 __func__, (void *)kbdev, (unsigned int)js_mask);
3614
3615 js_devdata = &kbdev->js_data;
3616
3617 down(&js_devdata->schedule_sem);
3618 mutex_lock(&js_devdata->queue_mutex);
3619
3620 for (js = 0; js < BASE_JM_MAX_NR_SLOTS; js++) {
3621 last_active[js] = kbdev->hwaccess.active_kctx[js];
3622 ctx_waiting[js] = false;
3623 }
3624
3625 while (js_mask) {
3626 js = ffs(js_mask) - 1;
3627
3628 while (1) {
3629 struct kbase_context *kctx;
3630 unsigned long flags;
3631 bool context_idle = false;
3632
3633 kctx = kbase_js_ctx_list_pop_head(kbdev, js);
3634
3635 if (!kctx) {
3636 js_mask &= ~(1 << js);
3637 dev_dbg(kbdev->dev,
3638 "No kctx on pullable list (s:%d)\n",
3639 js);
3640 break;
3641 }
3642
3643 if (!kbase_ctx_flag(kctx, KCTX_ACTIVE)) {
3644 context_idle = true;
3645
3646 dev_dbg(kbdev->dev,
3647 "kctx %pK is not active (s:%d)\n",
3648 (void *)kctx, js);
3649
3650 if (kbase_pm_context_active_handle_suspend(
3651 kbdev,
3652 KBASE_PM_SUSPEND_HANDLER_DONT_INCREASE)) {
3653 dev_dbg(kbdev->dev,
3654 "Suspend pending (s:%d)\n", js);
3655 /* Suspend pending - return context to
3656 * queue and stop scheduling
3657 */
3658 mutex_lock(
3659 &kctx->jctx.sched_info.ctx.jsctx_mutex);
3660 if (kbase_js_ctx_list_add_pullable_head(
3661 kctx->kbdev, kctx, js))
3662 kbase_js_sync_timers(kbdev);
3663 mutex_unlock(
3664 &kctx->jctx.sched_info.ctx.jsctx_mutex);
3665 mutex_unlock(&js_devdata->queue_mutex);
3666 up(&js_devdata->schedule_sem);
3667 KBASE_TLSTREAM_TL_JS_SCHED_END(kbdev,
3668 0);
3669 return;
3670 }
3671 kbase_ctx_flag_set(kctx, KCTX_ACTIVE);
3672 }
3673
3674 if (!kbase_js_use_ctx(kbdev, kctx, js)) {
3675 mutex_lock(
3676 &kctx->jctx.sched_info.ctx.jsctx_mutex);
3677
3678 dev_dbg(kbdev->dev,
3679 "kctx %pK cannot be used at this time\n",
3680 kctx);
3681
3682 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
3683 if (kbase_js_ctx_pullable(kctx, js, false)
3684 || kbase_ctx_flag(kctx, KCTX_PRIVILEGED))
3685 timer_sync |=
3686 kbase_js_ctx_list_add_pullable_head_nolock(
3687 kctx->kbdev, kctx, js);
3688 else
3689 timer_sync |=
3690 kbase_js_ctx_list_add_unpullable_nolock(
3691 kctx->kbdev, kctx, js);
3692 spin_unlock_irqrestore(&kbdev->hwaccess_lock,
3693 flags);
3694 mutex_unlock(
3695 &kctx->jctx.sched_info.ctx.jsctx_mutex);
3696 if (context_idle) {
3697 WARN_ON(!kbase_ctx_flag(kctx, KCTX_ACTIVE));
3698 kbase_ctx_flag_clear(kctx, KCTX_ACTIVE);
3699 kbase_pm_context_idle(kbdev);
3700 }
3701
3702 /* No more jobs can be submitted on this slot */
3703 js_mask &= ~(1 << js);
3704 break;
3705 }
3706 mutex_lock(&kctx->jctx.sched_info.ctx.jsctx_mutex);
3707 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
3708
3709 kbase_ctx_flag_clear(kctx, KCTX_PULLED);
3710
3711 if (!kbase_jm_kick(kbdev, 1 << js)) {
3712 dev_dbg(kbdev->dev,
3713 "No more jobs can be submitted (s:%d)\n",
3714 js);
3715 js_mask &= ~(1 << js);
3716 }
3717 if (!kbase_ctx_flag(kctx, KCTX_PULLED)) {
3718 bool pullable;
3719
3720 dev_dbg(kbdev->dev,
3721 "No atoms pulled from kctx %pK (s:%d)\n",
3722 (void *)kctx, js);
3723
3724 pullable = kbase_js_ctx_pullable(kctx, js,
3725 true);
3726
3727 /* Failed to pull jobs - push to head of list.
3728 * Unless this context is already 'active', in
3729 * which case it's effectively already scheduled
3730 * so push it to the back of the list.
3731 */
3732 if (pullable && kctx == last_active[js] &&
3733 kbase_ctx_flag(kctx,
3734 (KCTX_PULLED_SINCE_ACTIVE_JS0 <<
3735 js)))
3736 timer_sync |=
3737 kbase_js_ctx_list_add_pullable_nolock(
3738 kctx->kbdev,
3739 kctx, js);
3740 else if (pullable)
3741 timer_sync |=
3742 kbase_js_ctx_list_add_pullable_head_nolock(
3743 kctx->kbdev,
3744 kctx, js);
3745 else
3746 timer_sync |=
3747 kbase_js_ctx_list_add_unpullable_nolock(
3748 kctx->kbdev,
3749 kctx, js);
3750
3751 /* If this context is not the active context,
3752 * but the active context is pullable on this
3753 * slot, then we need to remove the active
3754 * marker to prevent it from submitting atoms in
3755 * the IRQ handler, which would prevent this
3756 * context from making progress.
3757 */
3758 if (last_active[js] && kctx != last_active[js]
3759 && kbase_js_ctx_pullable(
3760 last_active[js], js, true))
3761 ctx_waiting[js] = true;
3762
3763 if (context_idle) {
3764 kbase_jm_idle_ctx(kbdev, kctx);
3765 spin_unlock_irqrestore(
3766 &kbdev->hwaccess_lock,
3767 flags);
3768 WARN_ON(!kbase_ctx_flag(kctx, KCTX_ACTIVE));
3769 kbase_ctx_flag_clear(kctx, KCTX_ACTIVE);
3770 kbase_pm_context_idle(kbdev);
3771 } else {
3772 spin_unlock_irqrestore(
3773 &kbdev->hwaccess_lock,
3774 flags);
3775 }
3776 mutex_unlock(
3777 &kctx->jctx.sched_info.ctx.jsctx_mutex);
3778
3779 js_mask &= ~(1 << js);
3780 break; /* Could not run atoms on this slot */
3781 }
3782
3783 dev_dbg(kbdev->dev, "Push kctx %pK to back of list\n",
3784 (void *)kctx);
3785 if (kbase_js_ctx_pullable(kctx, js, true))
3786 timer_sync |=
3787 kbase_js_ctx_list_add_pullable_nolock(
3788 kctx->kbdev, kctx, js);
3789 else
3790 timer_sync |=
3791 kbase_js_ctx_list_add_unpullable_nolock(
3792 kctx->kbdev, kctx, js);
3793
3794 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
3795 mutex_unlock(&kctx->jctx.sched_info.ctx.jsctx_mutex);
3796 }
3797 }
3798
3799 if (timer_sync)
3800 kbase_js_sync_timers(kbdev);
3801
3802 for (js = 0; js < BASE_JM_MAX_NR_SLOTS; js++) {
3803 if (kbdev->hwaccess.active_kctx[js] == last_active[js] &&
3804 ctx_waiting[js]) {
3805 dev_dbg(kbdev->dev, "Marking kctx %pK as inactive (s:%d)\n",
3806 (void *)last_active[js], js);
3807 kbdev->hwaccess.active_kctx[js] = NULL;
3808 }
3809 }
3810
3811 mutex_unlock(&js_devdata->queue_mutex);
3812 up(&js_devdata->schedule_sem);
3813 KBASE_TLSTREAM_TL_JS_SCHED_END(kbdev, 0);
3814 }
3815
3816 void kbase_js_zap_context(struct kbase_context *kctx)
3817 {
3818 struct kbase_device *kbdev = kctx->kbdev;
3819 struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
3820 struct kbasep_js_kctx_info *js_kctx_info = &kctx->jctx.sched_info;
3821
3822 /*
3823 * Critical assumption: No more submission is possible outside of the
3824 * workqueue. This is because the OS *must* prevent U/K calls (IOCTLs)
3825 * whilst the struct kbase_context is terminating.
3826 */
3827
3828 /* First, atomically do the following:
3829 * - mark the context as dying
3830 * - try to evict it from the queue
3831 */
3832 mutex_lock(&kctx->jctx.lock);
3833 mutex_lock(&js_devdata->queue_mutex);
3834 mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
3835 kbase_ctx_flag_set(kctx, KCTX_DYING);
3836
3837 dev_dbg(kbdev->dev, "Zap: Try Evict Ctx %pK", kctx);
3838
3839 /*
3840 * At this point we know:
3841 * - If eviction succeeded, it was in the queue, but now no
3842 * longer is
3843 * - We must cancel the jobs here. No Power Manager active reference to
3844 * release.
3845 * - This happens asynchronously - kbase_jd_zap_context() will wait for
3846 * those jobs to be killed.
3847 * - If eviction failed, then it wasn't in the queue. It is one
3848 * of the following:
3849 * - a. it didn't have any jobs, and so is not in the Queue or
3850 * the Run Pool (not scheduled)
3851 * - Hence, no more work required to cancel jobs. No Power Manager
3852 * active reference to release.
3853 * - b. it was in the middle of a scheduling transaction (and thus must
3854 * have at least 1 job). This can happen from a syscall or a
3855 * kernel thread. We still hold the jsctx_mutex, and so the thread
3856 * must be waiting inside kbasep_js_try_schedule_head_ctx(),
3857 * before checking whether the runpool is full. That thread will
3858 * continue after we drop the mutex, and will notice the context
3859 * is dying. It will rollback the transaction, killing all jobs at
3860 * the same time. kbase_jd_zap_context() will wait for those jobs
3861 * to be killed.
3862 * - Hence, no more work required to cancel jobs, or to release the
3863 * Power Manager active reference.
3864 * - c. it is scheduled, and may or may not be running jobs
3865 * - We must cause it to leave the runpool by stopping it from
3866 * submitting any more jobs. When it finally does leave,
3867 * kbasep_js_runpool_requeue_or_kill_ctx() will kill all remaining jobs
3868 * (because it is dying), release the Power Manager active reference,
3869 * and will not requeue the context in the queue.
3870 * kbase_jd_zap_context() will wait for those jobs to be killed.
3871 * - Hence, work required just to make it leave the runpool. Cancelling
3872 * jobs and releasing the Power manager active reference will be
3873 * handled when it leaves the runpool.
3874 */
3875 if (!kbase_ctx_flag(kctx, KCTX_SCHEDULED)) {
3876 unsigned long flags;
3877 int js;
3878
3879 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
3880 for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) {
3881 if (!list_empty(
3882 &kctx->jctx.sched_info.ctx.ctx_list_entry[js]))
3883 list_del_init(
3884 &kctx->jctx.sched_info.ctx.ctx_list_entry[js]);
3885 }
3886 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
3887
3888 /* The following events require us to kill off remaining jobs
3889 * and update PM book-keeping:
3890 * - we evicted it correctly (it must have jobs to be in the
3891 * Queue)
3892 *
3893 * These events need no action, but take this path anyway:
3894 * - Case a: it didn't have any jobs, and was never in the Queue
3895 * - Case b: scheduling transaction will be partially rolled-
3896 * back (this already cancels the jobs)
3897 */
3898
3899 KBASE_KTRACE_ADD_JM(kbdev, JM_ZAP_NON_SCHEDULED, kctx, NULL, 0u, kbase_ctx_flag(kctx, KCTX_SCHEDULED));
3900
3901 dev_dbg(kbdev->dev, "Zap: Ctx %pK scheduled=0", kctx);
3902
3903 /* Only cancel jobs when we evicted from the
3904 * queue. No Power Manager active reference was held.
3905 *
3906 * Having is_dying set ensures that this kills, and doesn't
3907 * requeue
3908 */
3909 kbasep_js_runpool_requeue_or_kill_ctx(kbdev, kctx, false);
3910
3911 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
3912 mutex_unlock(&js_devdata->queue_mutex);
3913 mutex_unlock(&kctx->jctx.lock);
3914 } else {
3915 unsigned long flags;
3916 bool was_retained;
3917
3918 /* Case c: didn't evict, but it is scheduled - it's in the Run
3919 * Pool
3920 */
3921 KBASE_KTRACE_ADD_JM(kbdev, JM_ZAP_SCHEDULED, kctx, NULL, 0u, kbase_ctx_flag(kctx, KCTX_SCHEDULED));
3922 dev_dbg(kbdev->dev, "Zap: Ctx %pK is in RunPool", kctx);
3923
3924 /* Disable the ctx from submitting any more jobs */
3925 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
3926
3927 kbasep_js_clear_submit_allowed(js_devdata, kctx);
3928
3929 /* Retain and (later) release the context whilst it is is now
3930 * disallowed from submitting jobs - ensures that someone
3931 * somewhere will be removing the context later on
3932 */
3933 was_retained = kbase_ctx_sched_inc_refcount_nolock(kctx);
3934
3935 /* Since it's scheduled and we have the jsctx_mutex, it must be
3936 * retained successfully
3937 */
3938 KBASE_DEBUG_ASSERT(was_retained);
3939
3940 dev_dbg(kbdev->dev, "Zap: Ctx %pK Kill Any Running jobs", kctx);
3941
3942 /* Cancel any remaining running jobs for this kctx - if any.
3943 * Submit is disallowed which takes effect immediately, so no
3944 * more new jobs will appear after we do this.
3945 */
3946 kbase_backend_jm_kill_running_jobs_from_kctx(kctx);
3947
3948 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
3949 mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
3950 mutex_unlock(&js_devdata->queue_mutex);
3951 mutex_unlock(&kctx->jctx.lock);
3952
3953 dev_dbg(kbdev->dev, "Zap: Ctx %pK Release (may or may not schedule out immediately)",
3954 kctx);
3955
3956 kbasep_js_runpool_release_ctx(kbdev, kctx);
3957 }
3958
3959 KBASE_KTRACE_ADD_JM(kbdev, JM_ZAP_DONE, kctx, NULL, 0u, 0u);
3960
3961 /* After this, you must wait on both the
3962 * kbase_jd_context::zero_jobs_wait and the
3963 * kbasep_js_kctx_info::ctx::is_scheduled_waitq - to wait for the jobs
3964 * to be destroyed, and the context to be de-scheduled (if it was on the
3965 * runpool).
3966 *
3967 * kbase_jd_zap_context() will do this.
3968 */
3969 }
3970
3971 static inline int trace_get_refcnt(struct kbase_device *kbdev,
3972 struct kbase_context *kctx)
3973 {
3974 return atomic_read(&kctx->refcount);
3975 }
3976
3977 /**
3978 * kbase_js_foreach_ctx_job(): - Call a function on all jobs in context
3979 * @kctx: Pointer to context.
3980 * @callback: Pointer to function to call for each job.
3981 *
3982 * Call a function on all jobs belonging to a non-queued, non-running
3983 * context, and detach the jobs from the context as it goes.
3984 *
3985 * Due to the locks that might be held at the time of the call, the callback
3986 * may need to defer work on a workqueue to complete its actions (e.g. when
3987 * cancelling jobs)
3988 *
3989 * Atoms will be removed from the queue, so this must only be called when
3990 * cancelling jobs (which occurs as part of context destruction).
3991 *
3992 * The locking conditions on the caller are as follows:
3993 * - it will be holding kbasep_js_kctx_info::ctx::jsctx_mutex.
3994 */
3995 static void kbase_js_foreach_ctx_job(struct kbase_context *kctx,
3996 kbasep_js_ctx_job_cb *callback)
3997 {
3998 struct kbase_device *kbdev;
3999 unsigned long flags;
4000 u32 js;
4001
4002 kbdev = kctx->kbdev;
4003
4004 spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
4005
4006 KBASE_KTRACE_ADD_JM_REFCOUNT(kbdev, JS_POLICY_FOREACH_CTX_JOBS, kctx, NULL,
4007 0u, trace_get_refcnt(kbdev, kctx));
4008
4009 /* Invoke callback on jobs on each slot in turn */
4010 for (js = 0; js < kbdev->gpu_props.num_job_slots; js++)
4011 jsctx_queue_foreach(kctx, js, callback);
4012
4013 spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
4014 }
4015
4016 base_jd_prio kbase_js_priority_check(struct kbase_device *kbdev, base_jd_prio priority)
4017 {
4018 struct priority_control_manager_device *pcm_device = kbdev->pcm_dev;
4019 int req_priority, out_priority;
4020 base_jd_prio out_jd_priority = priority;
4021
4022 if (pcm_device) {
4023 req_priority = kbasep_js_atom_prio_to_sched_prio(priority);
4024 out_priority = pcm_device->ops.pcm_scheduler_priority_check(pcm_device, current, req_priority);
4025 out_jd_priority = kbasep_js_sched_prio_to_atom_prio(out_priority);
4026 }
4027 return out_jd_priority;
4028 }
4029
4030