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
36 * Done, now, it's time to cleanup
39 * - delete from processes list
48 * __init_task - helper to initialize the task structure
49 * @task: task struct to initialize
50 * @f: pointer to function to execute
51 * @stack: pointer to the page for stack
53 static void __init_task(struct task
*task
, void *f
, void *data
, void *stack
)
55 memset(task
, 0, sizeof(struct task
));
57 task
->regs
.psw
.io
= 1;
58 task
->regs
.psw
.ex
= 1;
59 task
->regs
.psw
.ea
= 1;
60 task
->regs
.psw
.ba
= 1;
63 task
->regs
.psw
.ptr
= (u64
) start_task
;
65 task
->regs
.gpr
[2] = (u64
) f
;
66 task
->regs
.gpr
[3] = (u64
) data
;
67 task
->regs
.gpr
[15] = ((u64
) stack
) + PAGE_SIZE
- STACK_FRAME_SIZE
;
69 task
->state
= TASK_SLEEPING
;
75 * init_idle_task - initialize the idle task
77 * Since the initial thread of execution already has a stack, and the task
78 * struct is a global variable, all that is left for us to do is to
79 * associate the current stack with idle_task.
81 static void init_idle_task(void)
85 stack
= ((u64
) &stack
) & ~(PAGE_SIZE
-1);
87 __init_task(&idle_task
, NULL
, NULL
, (void*) stack
);
88 set_task_ptr(&idle_task
);
91 * NOTE: The idle task is _not_ supposed to be on either of the
97 * create_task - create a new task
98 * @name: name for the task
99 * @f: function pointer to where thread of execution should begin
100 * @data: arbitrary data to pass to the task
102 struct task
* create_task(char *name
, int (*f
)(void *), void *data
)
108 * Allocate a page for stack, and struct task itself
110 page
= alloc_pages(0, ZONE_NORMAL
);
111 task
= malloc(sizeof(struct task
), ZONE_NORMAL
);
116 * Set up task's state
118 __init_task(task
, f
, data
, page_to_addr(page
));
120 strncpy(task
->name
, name
, TASK_NAME_LEN
);
123 * Add the task to the scheduler lists
125 list_add_tail(&task
->proc_list
, &processes
);
126 list_add_tail(&task
->run_queue
, &runnable
);
132 free_pages(page_to_addr(page
), 0);
134 return ERR_PTR(-ENOMEM
);
138 * __sched - core of the scheduler code. This decides which task to run
139 * next, and switches over to it
141 static void __sched(int force_idle
)
146 * If there are no runnable tasks, let's use the idle thread
148 if (force_idle
|| list_empty(&runnable
)) {
153 next
= list_first_entry(&runnable
, struct task
, run_queue
);
157 * Remove the new task from the run queue & mark it as running
159 list_del(&next
->run_queue
);
160 next
->state
= TASK_RUNNING
;
163 next
->slice_end_time
= (force_idle
) ? force_idle
: ticks
+ SCHED_TICKS_PER_SLICE
;
166 * NOTE: Because we need to load the registers _BEFORE_ we issue
167 * lpswe, we have to place the new psw into PSA and use register 0
169 memcpy(PSA_TMP_PSW
, &next
->regs
.psw
, sizeof(struct psw
));
172 load_pasce(next
->regs
.cr1
);
180 "lmg %%r0,%%r15,%0\n" /* load gpr */
181 "lpswe %1\n" /* load new psw */
184 "m" (next
->regs
.gpr
[0]),
193 * schedule_preempted - called to switch tasks
195 void __schedule(struct psw
*old_psw
, int newstate
)
201 * Save last process's state
208 * Save the registers (gpr, psw, ...)
212 memcpy(prev
->regs
.gpr
, PSA_INT_GPR
, sizeof(u64
)*16);
213 memcpy(&prev
->regs
.psw
, old_psw
, sizeof(struct psw
));
216 * Idle task doesn't get added back to the queue
218 if (prev
== &idle_task
)
221 store_pasce(&prev
->regs
.cr1
);
224 * Add back on the queue
226 prev
->state
= newstate
;
227 if (newstate
!= TASK_LOCKED
)
228 list_add_tail(&prev
->run_queue
, &runnable
);
231 * If the previous task didn't use it's full slice, force idle_task
234 if (prev
->slice_end_time
>= (ticks
+ SCHED_TICKS_PER_SLICE
))
235 force_idle
= prev
->slice_end_time
;
239 * Run the rest of the scheduler that selects the next task and
246 * __schedule_svc - wrapper for the supervisor-service call handler
248 void __schedule_svc(void)
250 __schedule(SVC_INT_OLD_PSW
, TASK_SLEEPING
);
254 * __schedule_blocked__svc - wrapper for the supervisor-service call handler
256 void __schedule_blocked_svc(void)
258 __schedule(SVC_INT_OLD_PSW
, TASK_LOCKED
);
262 * Initialize the schduler, and all associated structures
264 void init_sched(void)
268 INIT_LIST_HEAD(&runnable
);
269 INIT_LIST_HEAD(&processes
);
273 /* enable cpu timer interrupt subclass */
275 "stctg 0,0,%0\n" /* get cr0 */
276 "oi %1,0x04\n" /* enable cpu timer subclass */
277 "ni %1,0x7f\n" /* disable clock comp */
278 "lctlg 0,0,%0\n" /* reload cr0 */
282 "m" (*(((u8
*)&cr0
) + 6))
288 void list_tasks(struct console
*con
,
289 void (*f
)(struct console
*, struct task
*))
293 list_for_each_entry(t
, &processes
, proc_list
)
297 void make_runnable(struct task
*task
)
299 task
->state
= TASK_SLEEPING
;
300 list_add_tail(&task
->run_queue
, &runnable
);