.. | .. |
---|
1 | 1 | /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ |
---|
2 | 2 | /* |
---|
3 | 3 | * |
---|
4 | | - * (C) COPYRIGHT 2020-2021 ARM Limited. All rights reserved. |
---|
| 4 | + * (C) COPYRIGHT 2020-2022 ARM Limited. All rights reserved. |
---|
5 | 5 | * |
---|
6 | 6 | * This program is free software and is provided to you under the terms of the |
---|
7 | 7 | * GNU General Public License version 2 as published by the Free Software |
---|
.. | .. |
---|
29 | 29 | |
---|
30 | 30 | #include "mali_kbase_js_ctx_attr.h" |
---|
31 | 31 | |
---|
| 32 | +#define JS_MAX_RUNNING_JOBS 8 |
---|
| 33 | + |
---|
32 | 34 | /** |
---|
33 | 35 | * kbasep_js_devdata_init - Initialize the Job Scheduler |
---|
34 | 36 | * @kbdev: The kbase_device to operate on |
---|
.. | .. |
---|
36 | 38 | * The struct kbasep_js_device_data sub-structure of kbdev must be zero |
---|
37 | 39 | * initialized before passing to the kbasep_js_devdata_init() function. This is |
---|
38 | 40 | * to give efficient error path code. |
---|
| 41 | + * |
---|
| 42 | + * Return: 0 on success, error code otherwise. |
---|
39 | 43 | */ |
---|
40 | 44 | int kbasep_js_devdata_init(struct kbase_device * const kbdev); |
---|
41 | 45 | |
---|
.. | .. |
---|
86 | 90 | * |
---|
87 | 91 | * The struct kbase_context must be zero initialized before passing to the |
---|
88 | 92 | * kbase_js_init() function. This is to give efficient error path code. |
---|
| 93 | + * |
---|
| 94 | + * Return: 0 on success, error code otherwise. |
---|
89 | 95 | */ |
---|
90 | 96 | int kbasep_js_kctx_init(struct kbase_context *const kctx); |
---|
91 | 97 | |
---|
.. | .. |
---|
107 | 113 | * registered with this context. |
---|
108 | 114 | */ |
---|
109 | 115 | void kbasep_js_kctx_term(struct kbase_context *kctx); |
---|
| 116 | + |
---|
| 117 | +/* kbase_jsctx_slot_prio_blocked_set - Set a context as being blocked for a job |
---|
| 118 | + * slot at and below a given priority level |
---|
| 119 | + * @kctx: The kbase_context |
---|
| 120 | + * @js: The job slot |
---|
| 121 | + * @sched_prio: The priority levels that the context is blocked at for @js (all |
---|
| 122 | + * priority levels at this level and below will be blocked) |
---|
| 123 | + * |
---|
| 124 | + * To preserve ordering and dependencies of atoms on soft-stopping (both within |
---|
| 125 | + * an between priority levels), a context must be marked as blocked for that |
---|
| 126 | + * atom's job slot, for all priority levels at or below the atom's priority. |
---|
| 127 | + * |
---|
| 128 | + * This must only be called due to an atom that was pulled from the context, |
---|
| 129 | + * otherwise there will be no way of unblocking the context when the atom is |
---|
| 130 | + * completed/unpulled. |
---|
| 131 | + * |
---|
| 132 | + * Atoms of higher priority might still be able to be pulled from the context |
---|
| 133 | + * on @js. This helps with starting a high priority atom as soon as possible. |
---|
| 134 | + */ |
---|
| 135 | +static inline void kbase_jsctx_slot_prio_blocked_set(struct kbase_context *kctx, unsigned int js, |
---|
| 136 | + int sched_prio) |
---|
| 137 | +{ |
---|
| 138 | + struct kbase_jsctx_slot_tracking *slot_tracking = |
---|
| 139 | + &kctx->slot_tracking[js]; |
---|
| 140 | + |
---|
| 141 | + lockdep_assert_held(&kctx->kbdev->hwaccess_lock); |
---|
| 142 | + WARN(!slot_tracking->atoms_pulled_pri[sched_prio], |
---|
| 143 | + "When marking slot %u as blocked for priority %d on a kctx, no atoms were pulled - the slot cannot become unblocked", |
---|
| 144 | + js, sched_prio); |
---|
| 145 | + |
---|
| 146 | + slot_tracking->blocked |= ((kbase_js_prio_bitmap_t)1) << sched_prio; |
---|
| 147 | + KBASE_KTRACE_ADD_JM_SLOT_INFO(kctx->kbdev, JS_SLOT_PRIO_BLOCKED, kctx, |
---|
| 148 | + NULL, 0, js, (unsigned int)sched_prio); |
---|
| 149 | +} |
---|
| 150 | + |
---|
| 151 | +/* kbase_jsctx_atoms_pulled - Return number of atoms pulled on a context |
---|
| 152 | + * @kctx: The kbase_context |
---|
| 153 | + * |
---|
| 154 | + * Having atoms pulled indicates the context is not idle. |
---|
| 155 | + * |
---|
| 156 | + * Return: the number of atoms pulled on @kctx |
---|
| 157 | + */ |
---|
| 158 | +static inline int kbase_jsctx_atoms_pulled(struct kbase_context *kctx) |
---|
| 159 | +{ |
---|
| 160 | + return atomic_read(&kctx->atoms_pulled_all_slots); |
---|
| 161 | +} |
---|
110 | 162 | |
---|
111 | 163 | /** |
---|
112 | 164 | * kbasep_js_add_job - Add a job chain to the Job Scheduler, |
---|
.. | .. |
---|
160 | 212 | * @kbdev: The kbase_device to operate on |
---|
161 | 213 | * @kctx: The kbase_context to operate on |
---|
162 | 214 | * @atom: Atom to remove |
---|
163 | | -* |
---|
| 215 | + * |
---|
164 | 216 | * Completely removing a job requires several calls: |
---|
165 | 217 | * * kbasep_js_copy_atom_retained_state(), to capture the 'retained state' of |
---|
166 | 218 | * the atom |
---|
.. | .. |
---|
310 | 362 | struct kbase_context *kctx); |
---|
311 | 363 | |
---|
312 | 364 | /** |
---|
313 | | - * kbasep_js_runpool_release_ctx_and_katom_retained_state - Variant of |
---|
| 365 | + * kbasep_js_runpool_release_ctx_and_katom_retained_state - Variant of |
---|
314 | 366 | * kbasep_js_runpool_release_ctx() that handles additional |
---|
315 | 367 | * actions from completing an atom. |
---|
| 368 | + * |
---|
316 | 369 | * @kbdev: KBase device |
---|
317 | 370 | * @kctx: KBase context |
---|
318 | 371 | * @katom_retained_state: Retained state from the atom |
---|
.. | .. |
---|
335 | 388 | struct kbasep_js_atom_retained_state *katom_retained_state); |
---|
336 | 389 | |
---|
337 | 390 | /** |
---|
338 | | - * kbasep_js_runpool_release_ctx_nolock - |
---|
339 | | - * Variant of kbase_js_runpool_release_ctx() w/out locks |
---|
| 391 | + * kbasep_js_runpool_release_ctx_nolock - Variant of kbase_js_runpool_release_ctx() |
---|
| 392 | + * without locks |
---|
340 | 393 | * @kbdev: KBase device |
---|
341 | 394 | * @kctx: KBase context |
---|
342 | 395 | * |
---|
.. | .. |
---|
350 | 403 | |
---|
351 | 404 | /** |
---|
352 | 405 | * kbasep_js_schedule_privileged_ctx - Schedule in a privileged context |
---|
| 406 | + * |
---|
353 | 407 | * @kbdev: KBase device |
---|
354 | 408 | * @kctx: KBase context |
---|
355 | 409 | * |
---|
.. | .. |
---|
413 | 467 | * contexts from (re)entering the runpool. |
---|
414 | 468 | * |
---|
415 | 469 | * This does not handle suspending the one privileged context: the caller must |
---|
416 | | - * instead do this by by suspending the GPU HW Counter Instrumentation. |
---|
| 470 | + * instead do this by suspending the GPU HW Counter Instrumentation. |
---|
417 | 471 | * |
---|
418 | 472 | * This will eventually cause all Power Management active references held by |
---|
419 | 473 | * contexts on the runpool to be released, without running any more atoms. |
---|
.. | .. |
---|
456 | 510 | struct kbase_jd_atom *katom); |
---|
457 | 511 | |
---|
458 | 512 | /** |
---|
459 | | - * jsctx_ll_flush_to_rb() - Pushes atoms from the linked list to ringbuffer. |
---|
460 | | - * @kctx: Context Pointer |
---|
461 | | - * @prio: Priority (specifies the queue together with js). |
---|
462 | | - * @js: Job slot (specifies the queue together with prio). |
---|
463 | | - * |
---|
464 | | - * Pushes all possible atoms from the linked list to the ringbuffer. |
---|
465 | | - * Number of atoms are limited to free space in the ringbuffer and |
---|
466 | | - * number of available atoms in the linked list. |
---|
467 | | - * |
---|
468 | | - */ |
---|
469 | | -void jsctx_ll_flush_to_rb(struct kbase_context *kctx, int prio, int js); |
---|
470 | | - |
---|
471 | | -/** |
---|
472 | 513 | * kbase_js_pull - Pull an atom from a context in the job scheduler for |
---|
473 | 514 | * execution. |
---|
474 | 515 | * |
---|
.. | .. |
---|
482 | 523 | * Return: a pointer to an atom, or NULL if there are no atoms for this |
---|
483 | 524 | * slot that can be currently run. |
---|
484 | 525 | */ |
---|
485 | | -struct kbase_jd_atom *kbase_js_pull(struct kbase_context *kctx, int js); |
---|
| 526 | +struct kbase_jd_atom *kbase_js_pull(struct kbase_context *kctx, unsigned int js); |
---|
486 | 527 | |
---|
487 | 528 | /** |
---|
488 | 529 | * kbase_js_unpull - Return an atom to the job scheduler ringbuffer. |
---|
.. | .. |
---|
563 | 604 | * been used. |
---|
564 | 605 | * |
---|
565 | 606 | */ |
---|
566 | | -void kbase_js_sched(struct kbase_device *kbdev, int js_mask); |
---|
| 607 | +void kbase_js_sched(struct kbase_device *kbdev, unsigned int js_mask); |
---|
567 | 608 | |
---|
568 | 609 | /** |
---|
569 | | - * kbase_jd_zap_context - Attempt to deschedule a context that is being |
---|
| 610 | + * kbase_js_zap_context - Attempt to deschedule a context that is being |
---|
570 | 611 | * destroyed |
---|
571 | 612 | * @kctx: Context pointer |
---|
572 | 613 | * |
---|
.. | .. |
---|
642 | 683 | * As with any bool, never test the return value with true. |
---|
643 | 684 | * |
---|
644 | 685 | * The caller must hold hwaccess_lock. |
---|
| 686 | + * |
---|
| 687 | + * Return: true if the context is allowed to submit jobs, false otherwise. |
---|
645 | 688 | */ |
---|
646 | 689 | static inline bool kbasep_js_is_submit_allowed( |
---|
647 | 690 | struct kbasep_js_device_data *js_devdata, |
---|
.. | .. |
---|
651 | 694 | bool is_allowed; |
---|
652 | 695 | |
---|
653 | 696 | /* Ensure context really is scheduled in */ |
---|
654 | | - KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); |
---|
655 | | - KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); |
---|
| 697 | + if (WARN((kctx->as_nr == KBASEP_AS_NR_INVALID) || !kbase_ctx_flag(kctx, KCTX_SCHEDULED), |
---|
| 698 | + "%s: kctx %pK has assigned AS %d and context flag %d\n", __func__, (void *)kctx, |
---|
| 699 | + kctx->as_nr, atomic_read(&kctx->flags))) |
---|
| 700 | + return false; |
---|
656 | 701 | |
---|
657 | 702 | test_bit = (u16) (1u << kctx->as_nr); |
---|
658 | 703 | |
---|
.. | .. |
---|
679 | 724 | u16 set_bit; |
---|
680 | 725 | |
---|
681 | 726 | /* Ensure context really is scheduled in */ |
---|
682 | | - KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); |
---|
683 | | - KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); |
---|
| 727 | + if (WARN((kctx->as_nr == KBASEP_AS_NR_INVALID) || !kbase_ctx_flag(kctx, KCTX_SCHEDULED), |
---|
| 728 | + "%s: kctx %pK has assigned AS %d and context flag %d\n", __func__, (void *)kctx, |
---|
| 729 | + kctx->as_nr, atomic_read(&kctx->flags))) |
---|
| 730 | + return; |
---|
684 | 731 | |
---|
685 | 732 | set_bit = (u16) (1u << kctx->as_nr); |
---|
686 | 733 | |
---|
.. | .. |
---|
709 | 756 | u16 clear_mask; |
---|
710 | 757 | |
---|
711 | 758 | /* Ensure context really is scheduled in */ |
---|
712 | | - KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID); |
---|
713 | | - KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED)); |
---|
| 759 | + if (WARN((kctx->as_nr == KBASEP_AS_NR_INVALID) || !kbase_ctx_flag(kctx, KCTX_SCHEDULED), |
---|
| 760 | + "%s: kctx %pK has assigned AS %d and context flag %d\n", __func__, (void *)kctx, |
---|
| 761 | + kctx->as_nr, atomic_read(&kctx->flags))) |
---|
| 762 | + return; |
---|
714 | 763 | |
---|
715 | 764 | clear_bit = (u16) (1u << kctx->as_nr); |
---|
716 | 765 | clear_mask = ~clear_bit; |
---|
.. | .. |
---|
722 | 771 | } |
---|
723 | 772 | |
---|
724 | 773 | /** |
---|
725 | | - * kbasep_js_atom_retained_state_init_invalid - |
---|
726 | | - * Create an initial 'invalid' atom retained state |
---|
| 774 | + * kbasep_js_atom_retained_state_init_invalid - Create an initial 'invalid' |
---|
| 775 | + * atom retained state |
---|
| 776 | + * |
---|
727 | 777 | * @retained_state: pointer where to create and initialize the state |
---|
728 | 778 | * |
---|
729 | 779 | * Create an initial 'invalid' atom retained state, that requires no |
---|
.. | .. |
---|
743 | 793 | * @retained_state: where to copy |
---|
744 | 794 | * @katom: where to copy from |
---|
745 | 795 | * |
---|
746 | | - * Copy atom state that can be made available after jd_done_nolock() is called |
---|
| 796 | + * Copy atom state that can be made available after kbase_jd_done_nolock() is called |
---|
747 | 797 | * on that atom. |
---|
748 | 798 | */ |
---|
749 | 799 | static inline void kbasep_js_atom_retained_state_copy( |
---|
.. | .. |
---|
817 | 867 | struct kbasep_js_device_data *js_devdata; |
---|
818 | 868 | struct kbasep_js_kctx_info *js_kctx_info; |
---|
819 | 869 | |
---|
820 | | - KBASE_DEBUG_ASSERT(kbdev != NULL); |
---|
821 | | - KBASE_DEBUG_ASSERT(kctx != NULL); |
---|
822 | | - |
---|
823 | 870 | js_devdata = &kbdev->js_data; |
---|
824 | 871 | js_kctx_info = &kctx->jctx.sched_info; |
---|
825 | 872 | |
---|
.. | .. |
---|
827 | 874 | lockdep_assert_held(&js_devdata->runpool_mutex); |
---|
828 | 875 | |
---|
829 | 876 | /* Track total contexts */ |
---|
830 | | - KBASE_DEBUG_ASSERT(js_devdata->nr_all_contexts_running < S8_MAX); |
---|
| 877 | + WARN_ON_ONCE(js_devdata->nr_all_contexts_running >= JS_MAX_RUNNING_JOBS); |
---|
831 | 878 | ++(js_devdata->nr_all_contexts_running); |
---|
832 | 879 | |
---|
833 | 880 | if (!kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) { |
---|
834 | 881 | /* Track contexts that can submit jobs */ |
---|
835 | | - KBASE_DEBUG_ASSERT(js_devdata->nr_user_contexts_running < |
---|
836 | | - S8_MAX); |
---|
| 882 | + WARN_ON_ONCE(js_devdata->nr_user_contexts_running >= JS_MAX_RUNNING_JOBS); |
---|
837 | 883 | ++(js_devdata->nr_user_contexts_running); |
---|
838 | 884 | } |
---|
839 | 885 | } |
---|
.. | .. |
---|
854 | 900 | struct kbasep_js_device_data *js_devdata; |
---|
855 | 901 | struct kbasep_js_kctx_info *js_kctx_info; |
---|
856 | 902 | |
---|
857 | | - KBASE_DEBUG_ASSERT(kbdev != NULL); |
---|
858 | | - KBASE_DEBUG_ASSERT(kctx != NULL); |
---|
859 | | - |
---|
860 | 903 | js_devdata = &kbdev->js_data; |
---|
861 | 904 | js_kctx_info = &kctx->jctx.sched_info; |
---|
862 | 905 | |
---|
.. | .. |
---|
865 | 908 | |
---|
866 | 909 | /* Track total contexts */ |
---|
867 | 910 | --(js_devdata->nr_all_contexts_running); |
---|
868 | | - KBASE_DEBUG_ASSERT(js_devdata->nr_all_contexts_running >= 0); |
---|
| 911 | + WARN_ON_ONCE(js_devdata->nr_all_contexts_running < 0); |
---|
869 | 912 | |
---|
870 | 913 | if (!kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) { |
---|
871 | 914 | /* Track contexts that can submit jobs */ |
---|
872 | 915 | --(js_devdata->nr_user_contexts_running); |
---|
873 | | - KBASE_DEBUG_ASSERT(js_devdata->nr_user_contexts_running >= 0); |
---|
| 916 | + WARN_ON_ONCE(js_devdata->nr_user_contexts_running < 0); |
---|
874 | 917 | } |
---|
875 | 918 | } |
---|
876 | 919 | |
---|
.. | .. |
---|
895 | 938 | kbasep_js_relative_priority_to_atom[KBASE_JS_ATOM_SCHED_PRIO_COUNT]; |
---|
896 | 939 | |
---|
897 | 940 | /** |
---|
898 | | - * kbasep_js_atom_prio_to_sched_prio(): - Convert atom priority (base_jd_prio) |
---|
899 | | - * to relative ordering |
---|
| 941 | + * kbasep_js_atom_prio_to_sched_prio - Convert atom priority (base_jd_prio) |
---|
| 942 | + * to relative ordering. |
---|
900 | 943 | * @atom_prio: Priority ID to translate. |
---|
901 | 944 | * |
---|
902 | 945 | * Atom priority values for @ref base_jd_prio cannot be compared directly to |
---|
.. | .. |
---|
925 | 968 | return kbasep_js_atom_priority_to_relative[atom_prio]; |
---|
926 | 969 | } |
---|
927 | 970 | |
---|
928 | | -static inline base_jd_prio kbasep_js_sched_prio_to_atom_prio(int sched_prio) |
---|
| 971 | +/** |
---|
| 972 | + * kbasep_js_sched_prio_to_atom_prio - Convert relative scheduler priority |
---|
| 973 | + * to atom priority (base_jd_prio). |
---|
| 974 | + * |
---|
| 975 | + * @kbdev: Device pointer |
---|
| 976 | + * @sched_prio: Relative scheduler priority to translate. |
---|
| 977 | + * |
---|
| 978 | + * This function will convert relative scheduler priority back into base_jd_prio |
---|
| 979 | + * values. It takes values which priorities are monotonically increasing |
---|
| 980 | + * and converts them to the corresponding base_jd_prio values. If an invalid number is |
---|
| 981 | + * passed in (i.e. not within the expected range) an error code is returned instead. |
---|
| 982 | + * |
---|
| 983 | + * The mapping is 1:1 and the size of the valid input range is the same as the |
---|
| 984 | + * size of the valid output range, i.e. |
---|
| 985 | + * KBASE_JS_ATOM_SCHED_PRIO_COUNT == BASE_JD_NR_PRIO_LEVELS |
---|
| 986 | + * |
---|
| 987 | + * Return: On success: a value in the inclusive range |
---|
| 988 | + * 0..BASE_JD_NR_PRIO_LEVELS-1. On failure: BASE_JD_PRIO_INVALID. |
---|
| 989 | + */ |
---|
| 990 | +static inline base_jd_prio kbasep_js_sched_prio_to_atom_prio(struct kbase_device *kbdev, |
---|
| 991 | + int sched_prio) |
---|
929 | 992 | { |
---|
930 | | - unsigned int prio_idx; |
---|
931 | | - |
---|
932 | | - KBASE_DEBUG_ASSERT(sched_prio >= 0 && |
---|
933 | | - sched_prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT); |
---|
934 | | - |
---|
935 | | - prio_idx = (unsigned int)sched_prio; |
---|
936 | | - |
---|
937 | | - return kbasep_js_relative_priority_to_atom[prio_idx]; |
---|
| 993 | + if (likely(sched_prio >= 0 && sched_prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT)) |
---|
| 994 | + return kbasep_js_relative_priority_to_atom[sched_prio]; |
---|
| 995 | + /* Invalid priority value if reached here */ |
---|
| 996 | + dev_warn(kbdev->dev, "Unknown JS scheduling priority %d", sched_prio); |
---|
| 997 | + return BASE_JD_PRIO_INVALID; |
---|
938 | 998 | } |
---|
939 | 999 | |
---|
940 | 1000 | /** |
---|
.. | .. |
---|
947 | 1007 | * |
---|
948 | 1008 | * Return: The same or lower priority than requested. |
---|
949 | 1009 | */ |
---|
950 | | - |
---|
951 | 1010 | base_jd_prio kbase_js_priority_check(struct kbase_device *kbdev, base_jd_prio priority); |
---|
952 | 1011 | |
---|
| 1012 | +/** |
---|
| 1013 | + * kbase_js_atom_runs_before - determine if atoms for the same slot have an |
---|
| 1014 | + * ordering relation |
---|
| 1015 | + * @kbdev: kbase device |
---|
| 1016 | + * @katom_a: the first atom |
---|
| 1017 | + * @katom_b: the second atom. |
---|
| 1018 | + * @order_flags: combination of KBASE_ATOM_ORDERING_FLAG_<...> for the ordering |
---|
| 1019 | + * relation |
---|
| 1020 | + * |
---|
| 1021 | + * This is for making consistent decisions about the ordering of atoms when we |
---|
| 1022 | + * need to do pre-emption on a slot, which includes stopping existing atoms |
---|
| 1023 | + * when a new atom is ready to run, and also which other atoms to remove from |
---|
| 1024 | + * the slot when the atom in JSn_HEAD is being pre-empted. |
---|
| 1025 | + * |
---|
| 1026 | + * This only handles @katom_a and @katom_b being for the same job slot, as |
---|
| 1027 | + * pre-emption only operates within a slot. |
---|
| 1028 | + * |
---|
| 1029 | + * Note: there is currently no use-case for this as a sorting comparison |
---|
| 1030 | + * functions, hence only a boolean returned instead of int -1, 0, +1 return. If |
---|
| 1031 | + * required in future, a modification to do so would be better than calling |
---|
| 1032 | + * twice with katom_a and katom_b swapped. |
---|
| 1033 | + * |
---|
| 1034 | + * Return: |
---|
| 1035 | + * true if @katom_a should run before @katom_b, false otherwise. |
---|
| 1036 | + * A false return value does not distinguish between "no ordering relation" and |
---|
| 1037 | + * "@katom_a should run after @katom_b". |
---|
| 1038 | + */ |
---|
| 1039 | +bool kbase_js_atom_runs_before(struct kbase_device *kbdev, |
---|
| 1040 | + const struct kbase_jd_atom *katom_a, |
---|
| 1041 | + const struct kbase_jd_atom *katom_b, |
---|
| 1042 | + const kbase_atom_ordering_flag_t order_flags); |
---|
| 1043 | + |
---|
953 | 1044 | #endif /* _KBASE_JM_JS_H_ */ |
---|