blob: 8eca4e32e6c200b3a42ee3732c0b172d1c37ca32 [file] [log] [blame]
rjw6c1fd8f2022-11-30 14:33:01 +08001/*****************************************************************************
2* Copyright Statement:
3* --------------------
4* This software is protected by Copyright and the information contained
5* herein is confidential. The software may not be copied and the information
6* contained herein may not be used or disclosed except with the written
7* permission of MediaTek Inc. (C) 2018
8*
9* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
10* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
11* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
12* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
13* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
14* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
15* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
16* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
17* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
18* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
19* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
20* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
21*
22* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
23* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
24* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
25* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
26* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
27*
28* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
29* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
30* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
31* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
32* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
33*
34*****************************************************************************/
35
36/*****************************************************************************
37*
38* Filename:
39* ---------
40* mer_kernel_scheduler.h
41*
42* Project:
43* --------
44* MERTOS
45*
46* Description:
47* ------------
48* MERTOS scheduler header
49*
50* Author:
51* -------
52 * -------
53*
54*****************************************************************************/
55#ifndef _MER_KERNEL_SCHEDULER_H_
56#define _MER_KERNEL_SCHEDULER_H_
57#include "mer_kernel_config_public.h"
58
59#if defined(__MD97__) || defined(__MD97P__)
60
61#define MER_KERNEL_SCHEDULER_WAKE_UP_STATE 0x2
62#define MER_KERNEL_SCHEDULER_BUSY_STATE 0x0
63#define MER_KERNEL_SCHEDULER_IDLE_STATE 0x1
64
65#define MER_KERNEL_SCHEDULER_CORE0_MASK 0x7
66#define MER_KERNEL_SCHEDULER_CORE1_MASK 0x38
67
68#else
69 #error "unsupport platform"
70#endif /* __MD97__ || __MD97P__ */
71
72#define MER_KERNEL_SCHEDULER_JOB_INDEX_MASK (0xFFFFFFF)
73#define MER_KERNEL_SCHEDULER_JOB_PRIORITY_MASK (~(MER_KERNEL_SCHEDULER_JOB_INDEX_MASK))
74
75#define MER_KERNEL_SCHEDULER_LOCK_IS_RELEASED (0x0)
76#define MER_KERNEL_SCHEDULER_LOCK_IS_NOT_RELEASED (0x1)
77
78//#define __MER_KERNEL_SCHEDULER_ENCODE_DI_PRIORITY__
79
80#ifndef MER_KERNEL_IS_ASSEMBLY
81 #error "please include public header"
82#endif /* MER_KERNEL_IS_ASSEMBLY */
83
84#if !MER_KERNEL_IS_ASSEMBLY
85
86#include "mer_service_types.h"
87#include "mer_kernel_utility_target.h"
88#include "mer_kernel.h"
89#include "mer_kernel_dpc.h"
90
91///////////////////////////////////////////////////////////////////////////////
92// Internal type
93///////////////////////////////////////////////////////////////////////////////
94typedef struct {
95 mer_uint32 priority;
96 mer_uint32 affinity_mask;
97 mer_uint32 job_index;
98 mer_uint32 self_adjust;
99} mer_kernel_scheduler_job;
100
101typedef void (*mer_kernel_scheduler_job_callback)(mer_uint32);
102//typedef void (*mer_kernel_scheduler_set_job_callback)(mer_uint32);
103
104typedef enum {
105 MER_KERNEL_SCHEDULER_INSERT_TO_HEAD = 0,
106 MER_KERNEL_SCHEDULER_INSERT_TO_TAIL = 2,
107 MER_KERNEL_SCHEDULER_INSERT_TO_HEAD_AND_RETURN = 0x10,
108 MER_KERNEL_SCHEDULER_INSERT_TO_TAIL_AND_RETURN = 0x12,
109} mer_kernel_scheduler_job_insert_type;
110
111typedef enum {
112 MER_KERNEL_SCHEDULER_CONTEXT_TASK = 1,
113 MER_KERNEL_SCHEDULER_CONTEXT_DPC = 2,
114 MER_KERNEL_SCHEDULER_CONTEXT_ISR = 3,
115 MER_KERNEL_SCHEDULER_CONTEXT_NONE = 4,
116} mer_kernel_scheduler_context_type;
117
118///////////////////////////////////////////////////////////////////////////////
119// External Variable
120///////////////////////////////////////////////////////////////////////////////
121extern mer_kernel_scheduler_job mer_kernel_scheduler_running_job[MIPS_HW_VPE_NUM];
122extern mer_kernel_scheduler_job mer_kernel_scheduler_ready_job[MIPS_HW_VPE_NUM];
123extern mer_kernel_scheduler_job_callback mer_kernel_scheduler_job_insert[];
124extern mer_uint32 mer_kernel_scheduler_idle_flag_mips[MIPS_HW_VPE_NUM];
125
126extern mer_uint32 mer_kernel_dpc_info_table_begin;
127extern mer_uint32 mer_kernel_dpc_info_table_end;
128extern mer_uint32 mer_kernel_task_info_table_begin;
129extern mer_uint32 mer_kernel_task_info_table_end;
130
131///////////////////////////////////////////////////////////////////////////////
132// External Function
133///////////////////////////////////////////////////////////////////////////////
134extern void mer_kernel_scheduler_reschedule_job();
135mer_uint32 mer_kernel_scheduler_insert_job(mer_uint32 new_job_priority,
136 mer_uint32 new_job_affinity_mask,
137 mer_uint32 new_job_index,
138 mer_kernel_scheduler_job_insert_type new_job_insert_position);
139void mer_kernel_scheduler_switch_local_job(mer_uint32 current_vpe);
140void mer_kernel_scheduler_adjust_priority(mer_uint32 current_vpe);
141
142/* Low power */
143mer_uint32 mer_kernel_scheduler_remove_vpes_from_scheduling();
144void mer_kernel_scheduler_restore_current_vpe_to_scheduling(mer_uint32 core);
145void mer_kernel_scheduler_set_slave_vpe_idle_flag();
146void mer_kernel_scheduler_remove_slave_vpe_idle_flag();
147
148void mer_kernel_scheduler_initialization();
149
150mer_kernel_scheduler_context_type mer_kernel_scheduler_get_current_context_level();
151
152///////////////////////////////////////////////////////////////////////////////
153// Static Inline Function
154///////////////////////////////////////////////////////////////////////////////
155/**
156 * Check whether the job priority of VPE is in ISR
157 * Time complexity O(1)
158 *
159 * @param[out] 1 if in ISR, otherwise 0 if in DPC/Task
160 * @param[in] priority
161 *
162 */
163static inline mer_uint32 mer_kernel_scheduler_is_in_isr(mer_uint32 priority){
164
165 mer_uint32 non_isr_mask = 0xC0000000;
166 return ((priority & non_isr_mask) == 0);
167}
168
169/**
170 * Encode DI to current running priority
171 * Time complexity O(1)
172 *
173 * @param[out] current_vpe
174 * @param[in] N/A
175 *
176 */
177static inline void mer_kernel_scheduler_di(mer_uint32 current_vpe){
178
179#if defined(__MER_KERNEL_SCHEDULER_ENCODE_DI_PRIORITY__)
180#error "should not compile"
181#if defined(__MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__)
182 if (MER_KERNEL_GET_INTERRUPT_COUNT()){
183#else
184 if (mer_kernel_interrupt_count[current_vpe]){
185#endif /* __MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__ */
186 return;
187 }
188
189 mer_uint32 priority = mer_kernel_scheduler_running_job[current_vpe].priority;
190 mer_uint32 level_mask = ((priority & (~MER_KERNEL_SCHEDULER_JOB_INDEX_MASK)) >> 2);
191 mer_uint32 job_mask = (priority & MER_KERNEL_SCHEDULER_JOB_INDEX_MASK);
192
193 mer_kernel_scheduler_running_job[current_vpe].priority = level_mask | job_mask;
194 mer_kernel_utility_coherence_sync();
195
196#endif /* __MER_KERNEL_SCHEDULER_ENCODE_DI_PRIORITY__ */
197}
198
199/**
200 * Encode EI to current running priority
201 * Time complexity O(1)
202 *
203 * @param[out] N/A
204 * @param[in] current_vpe
205 *
206 */
207static inline void mer_kernel_scheduler_ei(mer_uint32 current_vpe){
208
209#if defined(__MER_KERNEL_SCHEDULER_ENCODE_DI_PRIORITY__)
210#error "should not compile"
211#if defined(__MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__)
212 if (MER_KERNEL_GET_INTERRUPT_COUNT()){
213#else
214 if (mer_kernel_interrupt_count[current_vpe]){
215#endif /* __MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__ */
216
217 mer_uint32 priority = mer_kernel_scheduler_running_job[current_vpe].priority;
218 mer_uint32 level_mask = ((priority & (~MER_KERNEL_SCHEDULER_JOB_INDEX_MASK)) << 2);
219 mer_uint32 job_mask = (priority & MER_KERNEL_SCHEDULER_JOB_INDEX_MASK);
220
221 mer_kernel_scheduler_running_job[current_vpe].priority = level_mask | job_mask;
222 mer_kernel_utility_coherence_sync();
223
224#endif /* __MER_KERNEL_SCHEDULER_ENCODE_DI_PRIORITY__ */
225
226}
227
228/**
229 * Set wake up status for child VPE (VPE1 in 93/95) before it reset
230 * Time complexity O(1)
231 *
232 * @param[out] N/A
233 * @param[in] N/A
234 *
235 */
236static inline void mer_kernel_scheduler_notify_child_vpe(){
237
238#if defined(__MD97__) || defined(__MD97P__)
239 mer_uint32 current_vpe = mer_kernel_utility_get_current_vpe_id();
240 mer_kernel_scheduler_idle_flag_mips[current_vpe+1] = MER_KERNEL_SCHEDULER_WAKE_UP_STATE;
241 mer_kernel_scheduler_idle_flag_mips[current_vpe+2] = MER_KERNEL_SCHEDULER_WAKE_UP_STATE;
242#else
243 #error "should porting to new platform"
244#endif
245
246}
247
248/**
249 * check if current context level is in dpc or not
250 * Time complexity O(1)
251 *
252 * @param[out] TRUE/FALSE
253 * @param[in] N/A
254 *
255 */
256__attribute__((always_inline)) static inline mer_uint32 mer_kernel_scheduler_is_in_dpc(){
257
258#if defined(__MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__)
259#if 0
260/* under construction !*/
261/* under construction !*/
262/* under construction !*/
263/* under construction !*/
264/* under construction !*/
265#else
266 /* Use the type in structure instead to have a better profiling result */
267 mer_uint32 control_block = MER_KERNEL_GET_CURRENT_CONTROL_BLOCK();
268 return ((MER_KERNEL_GET_INTERRUPT_COUNT() == 0) && \
269 (control_block) && \
270 (((mer_service_dpc_cb *)(control_block))->job_type == MER_SERVICE_TYPE_DPC));
271#endif
272#else
273 #error "should porting this part"
274#endif
275}
276
277/**
278 * check if current context level is in task or not
279 * Time complexity O(1)
280 *
281 * @param[out] TRUE/FALSE
282 * @param[in] N/A
283 *
284 */
285__attribute__((always_inline)) static inline mer_uint32 mer_kernel_scheduler_is_in_task(){
286
287#if defined(__MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__)
288#if 0
289/* under construction !*/
290/* under construction !*/
291/* under construction !*/
292/* under construction !*/
293/* under construction !*/
294#else
295 /* Use the type in structure instead to have a better profiling result */
296 mer_uint32 control_block = MER_KERNEL_GET_CURRENT_CONTROL_BLOCK();
297 return ((MER_KERNEL_GET_INTERRUPT_COUNT() == 0) && \
298 (control_block) && \
299 (((mer_service_dpc_cb *)(control_block))->job_type == MER_SERVICE_TYPE_TASK));
300#endif
301
302#else
303 #error "should porting this part"
304#endif
305}
306
307/**
308 * atomic read
309 *
310 * @param[out] value
311 * @param[in] address
312 *
313 */
314static inline mer_uint32 mer_kernel_scheduler_atmoic_read(mer_uint32 *ptr){
315
316 mer_uint32 ret_value = 0;
317 __asm__ __volatile__(
318 "ll %0, 0(%1) \n" \
319 :"=d"(ret_value) \
320 :"d"(ptr) \
321 :"memory" \
322 );
323
324 return ret_value;
325}
326
327/**
328 * atomic write
329 *
330 * @param[out] result
331 * @param[in] address
332 *
333 */
334static inline mer_uint32 mer_kernel_scheduler_atomic_write(mer_uint32 *ptr, mer_uint32 result){
335
336 __asm__ __volatile__(
337 "sc %0, 0(%1) \n" \
338 :"=d"(result) \
339 :"d"(ptr), "0"(result) \
340 :"memory" \
341 );
342
343 return result;
344}
345
346/**
347 * Wipe out the VPE running priority when entering ISR
348 *
349 * Time complexity O(1)
350 *
351 * @param[out] N/A
352 * @param[in] vpe_id, job_stack_pointer
353 *
354 */
355__attribute__((always_inline)) static inline void mer_kernel_scheduler_enter_isr(mer_uint32 vpe_id, mer_uint32 job_stack_pointer)
356{
357 /* Note that we do not take schedule lock here since we DO NOT allow ignore
358 ISR priority. It means, when I am in ISR, NO other VPE will send OS
359 interrupt to me even when I am a extremely short ISR from idle.
360 By doing so, we can make sure when sending an interrupt, the target
361 should receive OS interrupt immediately (unless it disable interrupt)
362 This reduce the chance that multiple OS interrupt send to same VPE.
363 */
364
365
366#if defined(__MER_KERNEL_DYNAMIC_BALANCE_JOB__)
367 mer_uint32 *job_sp = (mer_uint32 *)(MER_KERNEL_GET_CURRENT_CONTROL_BLOCK());
368 *job_sp = job_stack_pointer;
369#else
370 mer_uint32 *job_sp = (mer_uint32 *)(MER_KERNEL_GET_CURRENT_CONTROL_BLOCK());
371 *job_sp = job_stack_pointer;
372#endif
373
374 mer_uint32 result;
375
376 do {
377 //mer_kernel_utility_coherence_sync();
378
379 mer_uint32 *ptr = &mer_kernel_scheduler_running_job[vpe_id].priority;
380
381 mer_uint32 ll_value = mer_kernel_scheduler_atmoic_read(ptr);
382
383 mer_uint32 level_mask = ((ll_value & (~MER_KERNEL_SCHEDULER_JOB_INDEX_MASK)) >> 2);
384 mer_uint32 job_mask = (ll_value & MER_KERNEL_SCHEDULER_JOB_INDEX_MASK);
385
386 result = mer_kernel_scheduler_atomic_write(ptr, (level_mask | job_mask));
387
388 }while(result == 0);
389
390 //mer_kernel_utility_coherence_sync();
391
392}
393
394/**
395 * Recover out the VPE running priority when leaving ISR
396 *
397 * Time complexity O(1)
398 *
399 * @param[out] N/A
400 * @param[in] N/A
401 *
402 */
403__attribute__((always_inline)) static inline mer_bool mer_kernel_scheduler_recover_job_info(mer_uint32 vpe_id){
404
405 mer_uint32 result, self_reorder, ready_job = mer_kernel_scheduler_ready_job[vpe_id].priority;
406 mer_uint32 *ptr = &mer_kernel_scheduler_running_job[vpe_id].priority;
407
408 do {
409
410 mer_uint32 ll_value = mer_kernel_scheduler_atmoic_read(ptr);
411
412 mer_uint32 level_mask = ((ll_value & (~MER_KERNEL_SCHEDULER_JOB_INDEX_MASK)) << 2);
413 mer_uint32 job_mask = (ll_value & MER_KERNEL_SCHEDULER_JOB_INDEX_MASK);
414 mer_uint32 origin_mask = (level_mask | job_mask);
415
416 self_reorder = (ready_job < origin_mask);
417
418 result = mer_kernel_scheduler_atomic_write(ptr, origin_mask);
419
420 }while(result == 0);
421
422 return self_reorder;
423
424}
425
426#endif /* !MER_IS_ASSEMBLY */
427
428#endif /* _MER_KERNEL_SCHEDULER_H_ */
429