diff options
author | Michal Simek <monstr@monstr.eu> | 2009-03-27 09:25:26 -0400 |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2009-03-27 09:25:26 -0400 |
commit | 6496a23add642b7c9203411bdff3ff761835a80a (patch) | |
tree | b0a536aa55cfdebcbf111120be19db3306e9a690 /arch/microblaze/kernel/process.c | |
parent | c47f10baa0bd7e3de6b7072cfdcafef58f4147f5 (diff) |
microblaze_v8: process and init task function
Reviewed-by: Ingo Molnar <mingo@elte.hu>
Acked-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
Acked-by: John Linn <john.linn@xilinx.com>
Acked-by: John Williams <john.williams@petalogix.com>
Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch/microblaze/kernel/process.c')
-rw-r--r-- | arch/microblaze/kernel/process.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c new file mode 100644 index 000000000000..60e9ed7d3132 --- /dev/null +++ b/arch/microblaze/kernel/process.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> | ||
3 | * Copyright (C) 2008-2009 PetaLogix | ||
4 | * Copyright (C) 2006 Atmark Techno, Inc. | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/pm.h> | ||
14 | #include <linux/tick.h> | ||
15 | #include <linux/bitops.h> | ||
16 | #include <asm/system.h> | ||
17 | #include <asm/pgalloc.h> | ||
18 | |||
19 | void show_regs(struct pt_regs *regs) | ||
20 | { | ||
21 | printk(KERN_INFO " Registers dump: mode=%X\r\n", regs->kernel_mode); | ||
22 | printk(KERN_INFO " r1=%08lX, r2=%08lX, r3=%08lX, r4=%08lX\n", | ||
23 | regs->r1, regs->r2, regs->r3, regs->r4); | ||
24 | printk(KERN_INFO " r5=%08lX, r6=%08lX, r7=%08lX, r8=%08lX\n", | ||
25 | regs->r5, regs->r6, regs->r7, regs->r8); | ||
26 | printk(KERN_INFO " r9=%08lX, r10=%08lX, r11=%08lX, r12=%08lX\n", | ||
27 | regs->r9, regs->r10, regs->r11, regs->r12); | ||
28 | printk(KERN_INFO " r13=%08lX, r14=%08lX, r15=%08lX, r16=%08lX\n", | ||
29 | regs->r13, regs->r14, regs->r15, regs->r16); | ||
30 | printk(KERN_INFO " r17=%08lX, r18=%08lX, r19=%08lX, r20=%08lX\n", | ||
31 | regs->r17, regs->r18, regs->r19, regs->r20); | ||
32 | printk(KERN_INFO " r21=%08lX, r22=%08lX, r23=%08lX, r24=%08lX\n", | ||
33 | regs->r21, regs->r22, regs->r23, regs->r24); | ||
34 | printk(KERN_INFO " r25=%08lX, r26=%08lX, r27=%08lX, r28=%08lX\n", | ||
35 | regs->r25, regs->r26, regs->r27, regs->r28); | ||
36 | printk(KERN_INFO " r29=%08lX, r30=%08lX, r31=%08lX, rPC=%08lX\n", | ||
37 | regs->r29, regs->r30, regs->r31, regs->pc); | ||
38 | printk(KERN_INFO " msr=%08lX, ear=%08lX, esr=%08lX, fsr=%08lX\n", | ||
39 | regs->msr, regs->ear, regs->esr, regs->fsr); | ||
40 | while (1) | ||
41 | ; | ||
42 | } | ||
43 | |||
44 | void (*pm_idle)(void); | ||
45 | void (*pm_power_off)(void) = NULL; | ||
46 | EXPORT_SYMBOL(pm_power_off); | ||
47 | |||
48 | static int hlt_counter = 1; | ||
49 | |||
50 | void disable_hlt(void) | ||
51 | { | ||
52 | hlt_counter++; | ||
53 | } | ||
54 | EXPORT_SYMBOL(disable_hlt); | ||
55 | |||
56 | void enable_hlt(void) | ||
57 | { | ||
58 | hlt_counter--; | ||
59 | } | ||
60 | EXPORT_SYMBOL(enable_hlt); | ||
61 | |||
62 | static int __init nohlt_setup(char *__unused) | ||
63 | { | ||
64 | hlt_counter = 1; | ||
65 | return 1; | ||
66 | } | ||
67 | __setup("nohlt", nohlt_setup); | ||
68 | |||
69 | static int __init hlt_setup(char *__unused) | ||
70 | { | ||
71 | hlt_counter = 0; | ||
72 | return 1; | ||
73 | } | ||
74 | __setup("hlt", hlt_setup); | ||
75 | |||
76 | void default_idle(void) | ||
77 | { | ||
78 | if (!hlt_counter) { | ||
79 | clear_thread_flag(TIF_POLLING_NRFLAG); | ||
80 | smp_mb__after_clear_bit(); | ||
81 | local_irq_disable(); | ||
82 | while (!need_resched()) | ||
83 | cpu_sleep(); | ||
84 | local_irq_enable(); | ||
85 | set_thread_flag(TIF_POLLING_NRFLAG); | ||
86 | } else | ||
87 | while (!need_resched()) | ||
88 | cpu_relax(); | ||
89 | } | ||
90 | |||
91 | void cpu_idle(void) | ||
92 | { | ||
93 | set_thread_flag(TIF_POLLING_NRFLAG); | ||
94 | |||
95 | /* endless idle loop with no priority at all */ | ||
96 | while (1) { | ||
97 | void (*idle)(void) = pm_idle; | ||
98 | |||
99 | if (!idle) | ||
100 | idle = default_idle; | ||
101 | |||
102 | tick_nohz_stop_sched_tick(1); | ||
103 | while (!need_resched()) | ||
104 | idle(); | ||
105 | tick_nohz_restart_sched_tick(); | ||
106 | |||
107 | preempt_enable_no_resched(); | ||
108 | schedule(); | ||
109 | preempt_disable(); | ||
110 | check_pgt_cache(); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | void flush_thread(void) | ||
115 | { | ||
116 | } | ||
117 | |||
118 | /* FIXME - here will be a proposed change -> remove nr parameter */ | ||
119 | int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, | ||
120 | unsigned long unused, | ||
121 | struct task_struct *p, struct pt_regs *regs) | ||
122 | { | ||
123 | struct pt_regs *childregs = task_pt_regs(p); | ||
124 | struct thread_info *ti = task_thread_info(p); | ||
125 | |||
126 | *childregs = *regs; | ||
127 | if (user_mode(regs)) | ||
128 | childregs->r1 = usp; | ||
129 | else | ||
130 | childregs->r1 = ((unsigned long) ti) + THREAD_SIZE; | ||
131 | |||
132 | memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); | ||
133 | ti->cpu_context.r1 = (unsigned long)childregs; | ||
134 | ti->cpu_context.msr = (unsigned long)childregs->msr; | ||
135 | ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8; | ||
136 | |||
137 | if (clone_flags & CLONE_SETTLS) | ||
138 | ; | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * Return saved PC of a blocked thread. | ||
145 | */ | ||
146 | unsigned long thread_saved_pc(struct task_struct *tsk) | ||
147 | { | ||
148 | struct cpu_context *ctx = | ||
149 | &(((struct thread_info *)(tsk->stack))->cpu_context); | ||
150 | |||
151 | /* Check whether the thread is blocked in resume() */ | ||
152 | if (in_sched_functions(ctx->r15)) | ||
153 | return (unsigned long)ctx->r15; | ||
154 | else | ||
155 | return ctx->r14; | ||
156 | } | ||
157 | |||
158 | static void kernel_thread_helper(int (*fn)(void *), void *arg) | ||
159 | { | ||
160 | fn(arg); | ||
161 | do_exit(-1); | ||
162 | } | ||
163 | |||
164 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
165 | { | ||
166 | struct pt_regs regs; | ||
167 | int ret; | ||
168 | |||
169 | memset(®s, 0, sizeof(regs)); | ||
170 | /* store them in non-volatile registers */ | ||
171 | regs.r5 = (unsigned long)fn; | ||
172 | regs.r6 = (unsigned long)arg; | ||
173 | local_save_flags(regs.msr); | ||
174 | regs.pc = (unsigned long)kernel_thread_helper; | ||
175 | regs.kernel_mode = 1; | ||
176 | |||
177 | ret = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, | ||
178 | ®s, 0, NULL, NULL); | ||
179 | |||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | unsigned long get_wchan(struct task_struct *p) | ||
184 | { | ||
185 | /* TBD (used by procfs) */ | ||
186 | return 0; | ||
187 | } | ||