Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / ppc-chrp / efika / kernel / scheduler.c
blobc611a1379ffa03969cd105d9fe9dd67cafc9f453
1 /*
2 * scheduler.c
4 * Created on: Aug 29, 2008
5 * Author: misc
6 */
8 #include <asm/mpc5200b.h>
9 #include <aros/kernel.h>
10 #include <aros/libcall.h>
11 #include <exec/execbase.h>
12 #include <hardware/intbits.h>
14 #include "exec_intern.h"
15 #include "etask.h"
16 #include "syscall.h"
18 #include "kernel_intern.h"
20 AROS_LH0(KRN_SchedType, KrnGetScheduler,
21 struct KernelBase *, KernelBase, 1, Kernel)
23 AROS_LIBFUNC_INIT
25 return SCHED_RR;
27 AROS_LIBFUNC_EXIT
30 AROS_LH1(void, KrnSetScheduler,
31 AROS_LHA(KRN_SchedType, sched, D0),
32 struct KernelBase *, KernelBase, 2, Kernel)
34 AROS_LIBFUNC_INIT
36 /* Cannot set scheduler yet */
38 AROS_LIBFUNC_EXIT
41 AROS_LH0(void, KrnCause,
42 struct KernelBase *, KernelBase, 3, Kernel)
44 AROS_LIBFUNC_INIT
46 asm volatile("li %%r3,%0; sc"::"i"(SC_CAUSE):"memory","r3");
48 AROS_LIBFUNC_EXIT
51 AROS_LH0(void , KrnDispatch,
52 struct KernelBase *, KernelBase, 4, Kernel)
54 AROS_LIBFUNC_INIT
57 asm volatile("li %%r3,%0; sc"::"i"(SC_DISPATCH):"memory","r3");
59 AROS_LIBFUNC_EXIT
62 AROS_LH0(void, KrnSwitch,
63 struct KernelBase *, KernelBase, 5, Kernel)
65 AROS_LIBFUNC_INIT
67 asm volatile("li %%r3,%0; sc"::"i"(SC_SWITCH):"memory","r3");
69 AROS_LIBFUNC_EXIT
72 AROS_LH0(void, KrnSchedule,
73 struct KernelBase *, KernelBase, 6, Kernel)
75 AROS_LIBFUNC_INIT
77 asm volatile("li %%r3,%0; sc"::"i"(SC_SCHEDULE):"memory","r3");
79 AROS_LIBFUNC_EXIT
83 * Task dispatcher. Basically it may be the same one no matter what scheduling algorithm is used
85 void core_Dispatch(regs_t *regs)
87 volatile struct ExecBase *SysBase = getSysBase();
88 struct Task *task;
90 if (SysBase)
92 wrmsr(rdmsr() & ~MSR_EE);
95 * Is the list of ready tasks empty? Well, increment the idle switch cound and halt CPU.
96 * It should be extended by some plugin mechanism which would put CPU and whole machine
97 * into some more sophisticated sleep states (ACPI?)
99 while (IsListEmpty(&SysBase->TaskReady))
101 // SysBase->IdleCount++;
102 SysBase->AttnResched |= ARF_AttnSwitch;
104 //D(bug("[KRN] TaskReady list empty. Sleeping for a while...\n"));
105 /* Sleep almost forever ;) */
107 wrmsr(rdmsr() | MSR_EE);
108 asm volatile("sync");
109 // wrmsr(rdmsr() | MSR_POW);
110 // asm volatile("isync");
112 if (SysBase->SysFlags & SFF_SoftInt)
114 core_Cause(SysBase);
118 SysBase->DispCount++;
120 /* Get the first task from the TaskReady list, and populate it's settings through Sysbase */
121 task = (struct Task *)REMHEAD(&SysBase->TaskReady);
122 SysBase->ThisTask = task;
123 SysBase->Elapsed = SysBase->Quantum;
124 SysBase->SysFlags &= ~0x2000;
125 task->tc_State = TS_RUN;
126 SysBase->IDNestCnt = task->tc_IDNestCnt;
128 //D(bug("[KRN] New task = %p (%s)\n", task, task->tc_Node.ln_Name));
130 /* Handle tasks's flags */
131 if (task->tc_Flags & TF_EXCEPT)
132 Exception();
134 /* Store the launch time */
135 GetIntETask(task)->iet_private1 = mftbu();
137 if (task->tc_Flags & TF_LAUNCH)
139 AROS_UFC1(void, task->tc_Launch,
140 AROS_UFCA(struct ExecBase *, SysBase, A6));
143 /* Restore the task's state */
144 //bcopy(GetIntETask(task)->iet_Context, regs, sizeof(regs_t));
145 regs = GetIntETask(task)->iet_Context;
147 if (SysBase->IDNestCnt < 0)
148 regs->srr1 |= MSR_EE;
150 /* Copy the fpu, mmx, xmm state */
151 #warning FIXME: Change to the lazy saving of the FPU state!!!!
152 #warning TODO: No FPU support yet!!!!!!! Yay, it sucks! :-D
153 // IPTR sse_ctx = ((IPTR)GetIntETask(task)->iet_Context + sizeof(regs_t) + 15) & ~15;
154 // asm volatile("fxrstor (%0)"::"D"(sse_ctx));
158 regs->srr1 &= ~MSR_POW;
159 /* Leave interrupt and jump to the new task */
160 core_LeaveInterrupt(regs);
163 extern struct Task *idle_task;
165 void core_Switch(regs_t *regs)
167 struct ExecBase *SysBase = getSysBase();
168 struct Task *task;
169 context_t *ctx = (context_t *)regs;
170 if (SysBase)
172 /* Disable interrupts for a while */
173 wrmsr(rdmsr() & ~MSR_EE);
175 task = SysBase->ThisTask;
177 //D(bug("[KRN] Old task = %p (%s)\n", task, task->tc_Node.ln_Name));
179 /* Copy current task's context into the ETask structure */
180 bcopy(regs, GetIntETask(task)->iet_Context, sizeof(context_t));
182 /* Copy the fpu, mmx, xmm state */
184 #warning FIXME: Change to the lazy saving of the FPU state!!!!
185 #warning TODO: Write the damn FPU handling at all!!!!!!!! ;-D LOL
186 // IPTR sse_ctx = ((IPTR)GetIntETask(task)->iet_Context + sizeof(regs_t) + 15) & ~15;
187 // asm volatile("fxsave (%0)"::"D"(sse_ctx));
189 /* store IDNestCnt into tasks's structure */
190 task->tc_IDNestCnt = SysBase->IDNestCnt;
191 task->tc_SPReg = regs->gpr[1];
193 /* And enable interrupts */
194 SysBase->IDNestCnt = -1;
196 // if (task->tc_Node.ln_Pri < 127)
197 // task->tc_Node.ln_Pri++;
199 // if (SysBase->Elapsed <= 1)
200 // if (task->tc_Node.ln_Pri > -125)
201 // task->tc_Node.ln_Pri--;
203 // wrmsr(rdmsr() | MSR_EE);
205 /* Task says byebye. Update the CPU Time now. */
206 GetIntETask(task)->iet_CpuTime += mftbu() - GetIntETask(task)->iet_private1;
208 /* TF_SWITCH flag set? Call the switch routine */
209 if (task->tc_Flags & TF_SWITCH)
211 AROS_UFC1(void, task->tc_Switch,
212 AROS_UFCA(struct ExecBase *, SysBase, A6));
216 core_Dispatch(regs);
220 * Schedule the currently running task away. Put it into the TaskReady list
221 * in some smart way. This function is subject of change and it will be probably replaced
222 * by some plugin system in the future
224 void core_Schedule(regs_t *regs)
226 struct ExecBase *SysBase = getSysBase();
227 struct Task *task;
229 if (SysBase)
231 /* Disable interrupts for a while */
232 wrmsr(rdmsr() & ~MSR_EE); // CLI
234 task = SysBase->ThisTask;
236 /* Clear the pending switch flag. */
237 SysBase->AttnResched &= ~ARF_AttnSwitch;
239 /* If task has pending exception, reschedule it so that the dispatcher may handle the exception */
240 if (!(task->tc_Flags & TF_EXCEPT))
242 /* Is the TaskReady empty? If yes, then the running task is the only one. Let it work */
243 if (IsListEmpty(&SysBase->TaskReady))
244 core_LeaveInterrupt(regs);
246 /* Does the TaskReady list contains tasks with priority equal or lower than current task?
247 * If so, then check further... */
248 if (((struct Task*)GetHead(&SysBase->TaskReady))->tc_Node.ln_Pri <= task->tc_Node.ln_Pri)
250 /* If the running task did not used it's whole quantum yet, let it work */
251 if (!(SysBase->SysFlags & 0x2000))
253 core_LeaveInterrupt(regs);
258 #if 0
259 if (task != idle_task)
261 /* almost no CPU time used? Good. Increase the pri */
262 if (SysBase->Elapsed == SysBase->Quantum)
264 // if (task->tc_Node.ln_Pri < (GetIntETask(task)->iet_OrigPri) + 5)
265 // task->tc_Node.ln_Pri++;
267 else
269 if (task->tc_Node.ln_Pri > (GetIntETask(task)->iet_OrigPri) - 5)
270 task->tc_Node.ln_Pri--;
273 #endif
276 * If we got here, then the rescheduling is necessary.
277 * Put the task into the TaskReady list.
279 task->tc_State = TS_READY;
280 Enqueue(&SysBase->TaskReady, (struct Node *)task);
283 /* Select new task to run */
284 core_Switch(regs);
288 * Leave the interrupt. This function recieves the register frame used to leave the supervisor
289 * mode. It never returns and reschedules the task if it was asked for.
291 void core_ExitInterrupt(regs_t *regs)
293 /* Powermode was on? Turn it off now */
294 regs->srr1 &= ~MSR_POW;
296 /* Going back into supervisor mode? Then exit immediatelly */
297 if (!(regs->srr1 & MSR_PR))
299 core_LeaveInterrupt(regs);
301 else
303 /* Prepare to go back into user mode */
304 struct ExecBase *SysBase = getSysBase();
306 if (SysBase)
308 /* Soft interrupt requested? It's high time to do it */
309 if (SysBase->SysFlags & SFF_SoftInt)
310 core_Cause(SysBase);
312 /* If task switching is disabled, leave immediatelly */
313 if (SysBase->TDNestCnt >= 0)
315 core_LeaveInterrupt(regs);
317 else
320 * Do not disturb task if it's not necessary.
321 * Reschedule only if switch pending flag is set. Exit otherwise.
323 if (SysBase->AttnResched & ARF_AttnSwitch)
325 core_Schedule(regs);
327 else
328 core_LeaveInterrupt(regs);
331 else
332 core_LeaveInterrupt(regs);
336 void core_Cause(struct ExecBase *SysBase)
338 struct IntVector *iv = &SysBase->IntVects[INTB_SOFTINT];
340 /* If the SoftInt vector in SysBase is set, call it. It will do the rest for us */
341 if (iv->iv_Code)
343 AROS_UFC5(void, iv->iv_Code,
344 AROS_UFCA(ULONG, 0, D1),
345 AROS_UFCA(ULONG, 0, A0),
346 AROS_UFCA(APTR, 0, A1),
347 AROS_UFCA(APTR, iv->iv_Code, A5),
348 AROS_UFCA(struct ExecBase *, SysBase, A6)