aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/process.c
diff options
context:
space:
mode:
authorThiemo Seufer <ths@networkno.de>2005-02-21 05:55:16 -0500
committerRalf Baechle <ralf@linux-mips.org>2005-10-29 14:30:40 -0400
commitdc953df1ba5526814982676f47580c8e1bcdbfeb (patch)
tree83adba634d22f0788edbd944586b6f2d2a95bde7 /arch/mips/kernel/process.c
parent4e6a05fe5f87efd58da16fbf61e1f6329575fcfd (diff)
Fix wchan implementation, based on earlier by from Atsushi Nemoto.
Signed-off-by: Thiemo Seufer <ths@networkno.de> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/process.c')
-rw-r--r--arch/mips/kernel/process.c135
1 files changed, 77 insertions, 58 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index e4f2f8011387..f99efce556ea 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -211,22 +211,48 @@ long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
211 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL); 211 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
212} 212}
213 213
214struct mips_frame_info { 214static struct mips_frame_info {
215 void *func;
216 int omit_fp; /* compiled without fno-omit-frame-pointer */
215 int frame_offset; 217 int frame_offset;
216 int pc_offset; 218 int pc_offset;
219} schedule_frame, mfinfo[] = {
220 { schedule, 0 }, /* must be first */
221 /* arch/mips/kernel/semaphore.c */
222 { __down, 1 },
223 { __down_interruptible, 1 },
224 /* kernel/sched.c */
225#ifdef CONFIG_PREEMPT
226 { preempt_schedule, 0 },
227#endif
228 { wait_for_completion, 0 },
229 { interruptible_sleep_on, 0 },
230 { interruptible_sleep_on_timeout, 0 },
231 { sleep_on, 0 },
232 { sleep_on_timeout, 0 },
233 { yield, 0 },
234 { io_schedule, 0 },
235 { io_schedule_timeout, 0 },
236#if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT)
237 { __preempt_spin_lock, 0 },
238 { __preempt_write_lock, 0 },
239#endif
240 /* kernel/timer.c */
241 { schedule_timeout, 1 },
242/* { nanosleep_restart, 1 }, */
243 /* lib/rwsem-spinlock.c */
244 { __down_read, 1 },
245 { __down_write, 1 },
217}; 246};
218static struct mips_frame_info schedule_frame; 247
219static struct mips_frame_info schedule_timeout_frame;
220static struct mips_frame_info sleep_on_frame;
221static struct mips_frame_info sleep_on_timeout_frame;
222static struct mips_frame_info wait_for_completion_frame;
223static int mips_frame_info_initialized; 248static int mips_frame_info_initialized;
224static int __init get_frame_info(struct mips_frame_info *info, void *func) 249static int __init get_frame_info(struct mips_frame_info *info)
225{ 250{
226 int i; 251 int i;
252 void *func = info->func;
227 union mips_instruction *ip = (union mips_instruction *)func; 253 union mips_instruction *ip = (union mips_instruction *)func;
228 info->pc_offset = -1; 254 info->pc_offset = -1;
229 info->frame_offset = -1; 255 info->frame_offset = info->omit_fp ? 0 : -1;
230 for (i = 0; i < 128; i++, ip++) { 256 for (i = 0; i < 128; i++, ip++) {
231 /* if jal, jalr, jr, stop. */ 257 /* if jal, jalr, jr, stop. */
232 if (ip->j_format.opcode == jal_op || 258 if (ip->j_format.opcode == jal_op ||
@@ -247,14 +273,16 @@ static int __init get_frame_info(struct mips_frame_info *info, void *func)
247 /* sw / sd $ra, offset($sp) */ 273 /* sw / sd $ra, offset($sp) */
248 if (ip->i_format.rt == 31) { 274 if (ip->i_format.rt == 31) {
249 if (info->pc_offset != -1) 275 if (info->pc_offset != -1)
250 break; 276 continue;
251 info->pc_offset = 277 info->pc_offset =
252 ip->i_format.simmediate / sizeof(long); 278 ip->i_format.simmediate / sizeof(long);
253 } 279 }
254 /* sw / sd $s8, offset($sp) */ 280 /* sw / sd $s8, offset($sp) */
255 if (ip->i_format.rt == 30) { 281 if (ip->i_format.rt == 30) {
282//#if 0 /* gcc 3.4 does aggressive optimization... */
256 if (info->frame_offset != -1) 283 if (info->frame_offset != -1)
257 break; 284 continue;
285//#endif
258 info->frame_offset = 286 info->frame_offset =
259 ip->i_format.simmediate / sizeof(long); 287 ip->i_format.simmediate / sizeof(long);
260 } 288 }
@@ -272,13 +300,25 @@ static int __init get_frame_info(struct mips_frame_info *info, void *func)
272 300
273static int __init frame_info_init(void) 301static int __init frame_info_init(void)
274{ 302{
275 mips_frame_info_initialized = 303 int i, found;
276 !get_frame_info(&schedule_frame, schedule) && 304 for (i = 0; i < ARRAY_SIZE(mfinfo); i++)
277 !get_frame_info(&schedule_timeout_frame, schedule_timeout) && 305 if (get_frame_info(&mfinfo[i]))
278 !get_frame_info(&sleep_on_frame, sleep_on) && 306 return -1;
279 !get_frame_info(&sleep_on_timeout_frame, sleep_on_timeout) && 307 schedule_frame = mfinfo[0];
280 !get_frame_info(&wait_for_completion_frame, wait_for_completion); 308 /* bubble sort */
281 309 do {
310 struct mips_frame_info tmp;
311 found = 0;
312 for (i = 1; i < ARRAY_SIZE(mfinfo); i++) {
313 if (mfinfo[i-1].func > mfinfo[i].func) {
314 tmp = mfinfo[i];
315 mfinfo[i] = mfinfo[i-1];
316 mfinfo[i-1] = tmp;
317 found = 1;
318 }
319 }
320 } while (found);
321 mips_frame_info_initialized = 1;
282 return 0; 322 return 0;
283} 323}
284 324
@@ -303,60 +343,39 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
303/* get_wchan - a maintenance nightmare^W^Wpain in the ass ... */ 343/* get_wchan - a maintenance nightmare^W^Wpain in the ass ... */
304unsigned long get_wchan(struct task_struct *p) 344unsigned long get_wchan(struct task_struct *p)
305{ 345{
346 unsigned long stack_page;
306 unsigned long frame, pc; 347 unsigned long frame, pc;
307 348
308 if (!p || p == current || p->state == TASK_RUNNING) 349 if (!p || p == current || p->state == TASK_RUNNING)
309 return 0; 350 return 0;
310 351
311 if (!mips_frame_info_initialized) 352 stack_page = (unsigned long)p->thread_info;
353 if (!stack_page || !mips_frame_info_initialized)
312 return 0; 354 return 0;
355
313 pc = thread_saved_pc(p); 356 pc = thread_saved_pc(p);
314 if (!in_sched_functions(pc)) 357 if (!in_sched_functions(pc))
315 goto out; 358 return pc;
316
317 if (pc >= (unsigned long) sleep_on_timeout)
318 goto schedule_timeout_caller;
319 if (pc >= (unsigned long) sleep_on)
320 goto schedule_caller;
321 if (pc >= (unsigned long) interruptible_sleep_on_timeout)
322 goto schedule_timeout_caller;
323 if (pc >= (unsigned long)interruptible_sleep_on)
324 goto schedule_caller;
325 if (pc >= (unsigned long)wait_for_completion)
326 goto schedule_caller;
327 goto schedule_timeout_caller;
328
329schedule_caller:
330 frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset];
331 if (pc >= (unsigned long) sleep_on)
332 pc = ((unsigned long *)frame)[sleep_on_frame.pc_offset];
333 else
334 pc = ((unsigned long *)frame)[wait_for_completion_frame.pc_offset];
335 goto out;
336 359
337schedule_timeout_caller:
338 /*
339 * The schedule_timeout frame
340 */
341 frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset]; 360 frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset];
361 do {
362 int i;
342 363
343 /* 364 if (frame < stack_page || frame > stack_page + THREAD_SIZE - 32)
344 * frame now points to sleep_on_timeout's frame 365 return 0;
345 */
346 pc = ((unsigned long *)frame)[schedule_timeout_frame.pc_offset];
347 366
348 if (in_sched_functions(pc)) { 367 for (i = ARRAY_SIZE(mfinfo) - 1; i >= 0; i--) {
349 /* schedule_timeout called by [interruptible_]sleep_on_timeout */ 368 if (pc >= (unsigned long) mfinfo[i].func)
350 frame = ((unsigned long *)frame)[schedule_timeout_frame.frame_offset]; 369 break;
351 pc = ((unsigned long *)frame)[sleep_on_timeout_frame.pc_offset]; 370 }
352 } 371 if (i < 0)
353 372 break;
354out:
355 373
356#ifdef CONFIG_64BIT 374 if (mfinfo[i].omit_fp)
357 if (current->thread.mflags & MF_32BIT_REGS) /* Kludge for 32-bit ps */ 375 break;
358 pc &= 0xffffffffUL; 376 pc = ((unsigned long *)frame)[mfinfo[i].pc_offset];
359#endif 377 frame = ((unsigned long *)frame)[mfinfo[i].frame_offset];
378 } while (in_sched_functions(pc));
360 379
361 return pc; 380 return pc;
362} 381}