diff options
Diffstat (limited to 'arch/microblaze/kernel/process.c')
-rw-r--r-- | arch/microblaze/kernel/process.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c new file mode 100644 index 000000000000..07d4fa339eda --- /dev/null +++ b/arch/microblaze/kernel/process.c | |||
@@ -0,0 +1,190 @@ | |||
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->pt_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 | } | ||
41 | |||
42 | void (*pm_idle)(void); | ||
43 | void (*pm_power_off)(void) = NULL; | ||
44 | EXPORT_SYMBOL(pm_power_off); | ||
45 | |||
46 | static int hlt_counter = 1; | ||
47 | |||
48 | void disable_hlt(void) | ||
49 | { | ||
50 | hlt_counter++; | ||
51 | } | ||
52 | EXPORT_SYMBOL(disable_hlt); | ||
53 | |||
54 | void enable_hlt(void) | ||
55 | { | ||
56 | hlt_counter--; | ||
57 | } | ||
58 | EXPORT_SYMBOL(enable_hlt); | ||
59 | |||
60 | static int __init nohlt_setup(char *__unused) | ||
61 | { | ||
62 | hlt_counter = 1; | ||
63 | return 1; | ||
64 | } | ||
65 | __setup("nohlt", nohlt_setup); | ||
66 | |||
67 | static int __init hlt_setup(char *__unused) | ||
68 | { | ||
69 | hlt_counter = 0; | ||
70 | return 1; | ||
71 | } | ||
72 | __setup("hlt", hlt_setup); | ||
73 | |||
74 | void default_idle(void) | ||
75 | { | ||
76 | if (!hlt_counter) { | ||
77 | clear_thread_flag(TIF_POLLING_NRFLAG); | ||
78 | smp_mb__after_clear_bit(); | ||
79 | local_irq_disable(); | ||
80 | while (!need_resched()) | ||
81 | cpu_sleep(); | ||
82 | local_irq_enable(); | ||
83 | set_thread_flag(TIF_POLLING_NRFLAG); | ||
84 | } else | ||
85 | while (!need_resched()) | ||
86 | cpu_relax(); | ||
87 | } | ||
88 | |||
89 | void cpu_idle(void) | ||
90 | { | ||
91 | set_thread_flag(TIF_POLLING_NRFLAG); | ||
92 | |||
93 | /* endless idle loop with no priority at all */ | ||
94 | while (1) { | ||
95 | void (*idle)(void) = pm_idle; | ||
96 | |||
97 | if (!idle) | ||
98 | idle = default_idle; | ||
99 | |||
100 | tick_nohz_stop_sched_tick(1); | ||
101 | while (!need_resched()) | ||
102 | idle(); | ||
103 | tick_nohz_restart_sched_tick(); | ||
104 | |||
105 | preempt_enable_no_resched(); | ||
106 | schedule(); | ||
107 | preempt_disable(); | ||
108 | check_pgt_cache(); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | void flush_thread(void) | ||
113 | { | ||
114 | } | ||
115 | |||
116 | int copy_thread(unsigned long clone_flags, unsigned long usp, | ||
117 | unsigned long unused, | ||
118 | struct task_struct *p, struct pt_regs *regs) | ||
119 | { | ||
120 | struct pt_regs *childregs = task_pt_regs(p); | ||
121 | struct thread_info *ti = task_thread_info(p); | ||
122 | |||
123 | *childregs = *regs; | ||
124 | if (user_mode(regs)) | ||
125 | childregs->r1 = usp; | ||
126 | else | ||
127 | childregs->r1 = ((unsigned long) ti) + THREAD_SIZE; | ||
128 | |||
129 | memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); | ||
130 | ti->cpu_context.r1 = (unsigned long)childregs; | ||
131 | ti->cpu_context.msr = (unsigned long)childregs->msr; | ||
132 | ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8; | ||
133 | |||
134 | if (clone_flags & CLONE_SETTLS) | ||
135 | ; | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Return saved PC of a blocked thread. | ||
142 | */ | ||
143 | unsigned long thread_saved_pc(struct task_struct *tsk) | ||
144 | { | ||
145 | struct cpu_context *ctx = | ||
146 | &(((struct thread_info *)(tsk->stack))->cpu_context); | ||
147 | |||
148 | /* Check whether the thread is blocked in resume() */ | ||
149 | if (in_sched_functions(ctx->r15)) | ||
150 | return (unsigned long)ctx->r15; | ||
151 | else | ||
152 | return ctx->r14; | ||
153 | } | ||
154 | |||
155 | static void kernel_thread_helper(int (*fn)(void *), void *arg) | ||
156 | { | ||
157 | fn(arg); | ||
158 | do_exit(-1); | ||
159 | } | ||
160 | |||
161 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
162 | { | ||
163 | struct pt_regs regs; | ||
164 | |||
165 | memset(®s, 0, sizeof(regs)); | ||
166 | /* store them in non-volatile registers */ | ||
167 | regs.r5 = (unsigned long)fn; | ||
168 | regs.r6 = (unsigned long)arg; | ||
169 | local_save_flags(regs.msr); | ||
170 | regs.pc = (unsigned long)kernel_thread_helper; | ||
171 | regs.pt_mode = 1; | ||
172 | |||
173 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, | ||
174 | ®s, 0, NULL, NULL); | ||
175 | } | ||
176 | |||
177 | unsigned long get_wchan(struct task_struct *p) | ||
178 | { | ||
179 | /* TBD (used by procfs) */ | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | /* Set up a thread for executing a new program */ | ||
184 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp) | ||
185 | { | ||
186 | set_fs(USER_DS); | ||
187 | regs->pc = pc; | ||
188 | regs->r1 = usp; | ||
189 | regs->pt_mode = 0; | ||
190 | } | ||