2 * (C) Copyright 2007-2011 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
14 /* list of all runnable processes */
15 static struct list_head runnable
;
17 /* list of all processes in the system */
18 static struct list_head processes
;
21 static struct task idle_task
;
24 * start_task - helper used to start the task's code
25 * @f: function to execute
27 static void start_task(int (*f
)(void*), void *data
)
30 * Start executing the code
44 * __init_task - helper to initialize the task structure
45 * @task: task struct to initialize
46 * @f: pointer to function to execute
47 * @stack: pointer to the page for stack
49 static void __init_task(struct task
*task
, void *f
, void *data
, void *stack
)
51 memset(task
, 0, sizeof(struct task
));
53 task
->regs
.psw
.io
= 1;
54 task
->regs
.psw
.ex
= 1;
56 task
->regs
.psw
.ea
= 1;
57 task
->regs
.psw
.ba
= 1;
60 task
->regs
.psw
.ptr
= (u64
) start_task
;
62 task
->regs
.gpr
[2] = (u64
) f
;
63 task
->regs
.gpr
[3] = (u64
) data
;
64 task
->regs
.gpr
[15] = ((u64
) stack
) + PAGE_SIZE
- STACK_FRAME_SIZE
;
66 task
->state
= TASK_SLEEPING
;
74 * init_idle_task - initialize the idle task
76 * Since the initial thread of execution already has a stack, and the task
77 * struct is a global variable, all that is left for us to do is to
78 * associate the current stack with idle_task.
80 static void init_idle_task(void)
84 stack
= ((u64
) &stack
) & ~(PAGE_SIZE
-1);
86 __init_task(&idle_task
, NULL
, NULL
, (void*) stack
);
87 set_task_ptr(&idle_task
);
90 * NOTE: The idle task is _not_ supposed to be on either of the
96 * create_task - create a new task
97 * @name: name for the task
98 * @f: function pointer to where thread of execution should begin
99 * @data: arbitrary data to pass to the task
101 struct task
* create_task(char *name
, int (*f
)(void *), void *data
)
107 * Allocate a page for stack, and struct task itself
109 page
= alloc_pages(0, ZONE_NORMAL
);
110 task
= malloc(sizeof(struct task
), ZONE_NORMAL
);
115 * Set up task's state
117 __init_task(task
, f
, data
, page_to_addr(page
));
119 strncpy(task
->name
, name
, TASK_NAME_LEN
);
122 * Add the task to the scheduler lists
124 list_add_tail(&task
->proc_list
, &processes
);
125 list_add_tail(&task
->run_queue
, &runnable
);
131 free_pages(page_to_addr(page
), 0);
133 return ERR_PTR(-ENOMEM
);
137 * __sched - core of the scheduler code. This decides which task to run
138 * next, and switches over to it
140 static void __sched(int force_idle
)
145 * If there are no runnable tasks, let's use the idle thread
147 if (force_idle
|| list_empty(&runnable
)) {
152 next
= list_first_entry(&runnable
, struct task
, run_queue
);
156 * Remove the new task from the run queue & mark it as running
158 list_del(&next
->run_queue
);
159 next
->state
= TASK_RUNNING
;
162 next
->slice_end_time
= (force_idle
) ? force_idle
: ticks
+ SCHED_TICKS_PER_SLICE
;
165 * NOTE: Because we need to load the registers _BEFORE_ we issue
166 * lpswe, we have to place the new psw into PSA and use register 0
168 memcpy(PSA_TMP_PSW
, &next
->regs
.psw
, sizeof(struct psw
));
171 load_pasce(next
->regs
.cr1
);
179 "lmg %%r0,%%r15,%0\n" /* load gpr */
180 "lpswe %1\n" /* load new psw */
183 "m" (next
->regs
.gpr
[0]),
192 * schedule_preempted - called to switch tasks
194 void __schedule(struct psw
*old_psw
, int newstate
)
200 * Save last process's state
207 * Save the registers (gpr, psw, ...)
211 memcpy(prev
->regs
.gpr
, PSA_INT_GPR
, sizeof(u64
)*16);
212 memcpy(&prev
->regs
.psw
, old_psw
, sizeof(struct psw
));
215 * Idle task doesn't get added back to the queue
217 if (prev
== &idle_task
)
220 store_pasce(&prev
->regs
.cr1
);
223 * Add back on the queue
225 prev
->state
= newstate
;
228 * If the previous task didn't use it's full slice, force idle_task
231 if (prev
->slice_end_time
>= (ticks
+ SCHED_TICKS_PER_SLICE
))
232 force_idle
= prev
->slice_end_time
;
236 list_del(&prev
->proc_list
);
237 free_pages(prev
->stack
, 0);
243 list_add_tail(&prev
->run_queue
, &runnable
);
249 * Run the rest of the scheduler that selects the next task and
256 * __schedule_svc - wrapper for the supervisor-service call handler
258 void __schedule_svc(void)
260 __schedule(SVC_INT_OLD_PSW
, TASK_SLEEPING
);
264 * __schedule_blocked__svc - wrapper for the supervisor-service call handler
266 void __schedule_blocked_svc(void)
268 __schedule(SVC_INT_OLD_PSW
, TASK_LOCKED
);
272 * __schedule_blocked__svc - wrapper for the supervisor-service call handler
274 void __schedule_exit_svc(void)
276 __schedule(SVC_INT_OLD_PSW
, TASK_ZOMBIE
);
280 * Initialize the schduler, and all associated structures
282 void init_sched(void)
286 INIT_LIST_HEAD(&runnable
);
287 INIT_LIST_HEAD(&processes
);
291 /* enable cpu timer interrupt subclass */
293 "stctg 0,0,%0\n" /* get cr0 */
294 "oi %1,0x04\n" /* enable cpu timer subclass */
295 "ni %1,0x7f\n" /* disable clock comp */
296 "lctlg 0,0,%0\n" /* reload cr0 */
300 "m" (*(((u8
*)&cr0
) + 6))
306 void list_tasks(void (*f
)(struct task
*, void*), void *priv
)
310 list_for_each_entry(t
, &processes
, proc_list
)
314 void make_runnable(struct task
*task
)
316 task
->state
= TASK_SLEEPING
;
317 list_add_tail(&task
->run_queue
, &runnable
);