1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * PARISC Architecture-dependent parts of process handling 3*1da177e4SLinus Torvalds * based on the work for i386 4*1da177e4SLinus Torvalds * 5*1da177e4SLinus Torvalds * Copyright (C) 1999-2003 Matthew Wilcox <willy at parisc-linux.org> 6*1da177e4SLinus Torvalds * Copyright (C) 2000 Martin K Petersen <mkp at mkp.net> 7*1da177e4SLinus Torvalds * Copyright (C) 2000 John Marvin <jsm at parisc-linux.org> 8*1da177e4SLinus Torvalds * Copyright (C) 2000 David Huggins-Daines <dhd with pobox.org> 9*1da177e4SLinus Torvalds * Copyright (C) 2000-2003 Paul Bame <bame at parisc-linux.org> 10*1da177e4SLinus Torvalds * Copyright (C) 2000 Philipp Rumpf <prumpf with tux.org> 11*1da177e4SLinus Torvalds * Copyright (C) 2000 David Kennedy <dkennedy with linuxcare.com> 12*1da177e4SLinus Torvalds * Copyright (C) 2000 Richard Hirst <rhirst with parisc-lixux.org> 13*1da177e4SLinus Torvalds * Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org> 14*1da177e4SLinus Torvalds * Copyright (C) 2001 Alan Modra <amodra at parisc-linux.org> 15*1da177e4SLinus Torvalds * Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org> 16*1da177e4SLinus Torvalds * Copyright (C) 2001-2002 Helge Deller <deller at parisc-linux.org> 17*1da177e4SLinus Torvalds * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org> 18*1da177e4SLinus Torvalds * 19*1da177e4SLinus Torvalds * 20*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 21*1da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 22*1da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 23*1da177e4SLinus Torvalds * (at your option) any later version. 24*1da177e4SLinus Torvalds * 25*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 26*1da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 27*1da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28*1da177e4SLinus Torvalds * GNU General Public License for more details. 29*1da177e4SLinus Torvalds * 30*1da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 31*1da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 32*1da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 33*1da177e4SLinus Torvalds */ 34*1da177e4SLinus Torvalds 35*1da177e4SLinus Torvalds #include <stdarg.h> 36*1da177e4SLinus Torvalds 37*1da177e4SLinus Torvalds #include <linux/elf.h> 38*1da177e4SLinus Torvalds #include <linux/errno.h> 39*1da177e4SLinus Torvalds #include <linux/kernel.h> 40*1da177e4SLinus Torvalds #include <linux/mm.h> 41*1da177e4SLinus Torvalds #include <linux/module.h> 42*1da177e4SLinus Torvalds #include <linux/personality.h> 43*1da177e4SLinus Torvalds #include <linux/ptrace.h> 44*1da177e4SLinus Torvalds #include <linux/sched.h> 45*1da177e4SLinus Torvalds #include <linux/stddef.h> 46*1da177e4SLinus Torvalds #include <linux/unistd.h> 47*1da177e4SLinus Torvalds #include <linux/kallsyms.h> 48*1da177e4SLinus Torvalds 49*1da177e4SLinus Torvalds #include <asm/io.h> 50*1da177e4SLinus Torvalds #include <asm/offsets.h> 51*1da177e4SLinus Torvalds #include <asm/pdc.h> 52*1da177e4SLinus Torvalds #include <asm/pdc_chassis.h> 53*1da177e4SLinus Torvalds #include <asm/pgalloc.h> 54*1da177e4SLinus Torvalds #include <asm/uaccess.h> 55*1da177e4SLinus Torvalds #include <asm/unwind.h> 56*1da177e4SLinus Torvalds 57*1da177e4SLinus Torvalds static int hlt_counter; 58*1da177e4SLinus Torvalds 59*1da177e4SLinus Torvalds /* 60*1da177e4SLinus Torvalds * Power off function, if any 61*1da177e4SLinus Torvalds */ 62*1da177e4SLinus Torvalds void (*pm_power_off)(void); 63*1da177e4SLinus Torvalds 64*1da177e4SLinus Torvalds void disable_hlt(void) 65*1da177e4SLinus Torvalds { 66*1da177e4SLinus Torvalds hlt_counter++; 67*1da177e4SLinus Torvalds } 68*1da177e4SLinus Torvalds 69*1da177e4SLinus Torvalds EXPORT_SYMBOL(disable_hlt); 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds void enable_hlt(void) 72*1da177e4SLinus Torvalds { 73*1da177e4SLinus Torvalds hlt_counter--; 74*1da177e4SLinus Torvalds } 75*1da177e4SLinus Torvalds 76*1da177e4SLinus Torvalds EXPORT_SYMBOL(enable_hlt); 77*1da177e4SLinus Torvalds 78*1da177e4SLinus Torvalds void default_idle(void) 79*1da177e4SLinus Torvalds { 80*1da177e4SLinus Torvalds barrier(); 81*1da177e4SLinus Torvalds } 82*1da177e4SLinus Torvalds 83*1da177e4SLinus Torvalds /* 84*1da177e4SLinus Torvalds * The idle thread. There's no useful work to be 85*1da177e4SLinus Torvalds * done, so just try to conserve power and have a 86*1da177e4SLinus Torvalds * low exit latency (ie sit in a loop waiting for 87*1da177e4SLinus Torvalds * somebody to say that they'd like to reschedule) 88*1da177e4SLinus Torvalds */ 89*1da177e4SLinus Torvalds void cpu_idle(void) 90*1da177e4SLinus Torvalds { 91*1da177e4SLinus Torvalds /* endless idle loop with no priority at all */ 92*1da177e4SLinus Torvalds while (1) { 93*1da177e4SLinus Torvalds while (!need_resched()) 94*1da177e4SLinus Torvalds barrier(); 95*1da177e4SLinus Torvalds schedule(); 96*1da177e4SLinus Torvalds check_pgt_cache(); 97*1da177e4SLinus Torvalds } 98*1da177e4SLinus Torvalds } 99*1da177e4SLinus Torvalds 100*1da177e4SLinus Torvalds 101*1da177e4SLinus Torvalds #ifdef __LP64__ 102*1da177e4SLinus Torvalds #define COMMAND_GLOBAL 0xfffffffffffe0030UL 103*1da177e4SLinus Torvalds #else 104*1da177e4SLinus Torvalds #define COMMAND_GLOBAL 0xfffe0030 105*1da177e4SLinus Torvalds #endif 106*1da177e4SLinus Torvalds 107*1da177e4SLinus Torvalds #define CMD_RESET 5 /* reset any module */ 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds /* 110*1da177e4SLinus Torvalds ** The Wright Brothers and Gecko systems have a H/W problem 111*1da177e4SLinus Torvalds ** (Lasi...'nuf said) may cause a broadcast reset to lockup 112*1da177e4SLinus Torvalds ** the system. An HVERSION dependent PDC call was developed 113*1da177e4SLinus Torvalds ** to perform a "safe", platform specific broadcast reset instead 114*1da177e4SLinus Torvalds ** of kludging up all the code. 115*1da177e4SLinus Torvalds ** 116*1da177e4SLinus Torvalds ** Older machines which do not implement PDC_BROADCAST_RESET will 117*1da177e4SLinus Torvalds ** return (with an error) and the regular broadcast reset can be 118*1da177e4SLinus Torvalds ** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET 119*1da177e4SLinus Torvalds ** the PDC call will not return (the system will be reset). 120*1da177e4SLinus Torvalds */ 121*1da177e4SLinus Torvalds void machine_restart(char *cmd) 122*1da177e4SLinus Torvalds { 123*1da177e4SLinus Torvalds #ifdef FASTBOOT_SELFTEST_SUPPORT 124*1da177e4SLinus Torvalds /* 125*1da177e4SLinus Torvalds ** If user has modified the Firmware Selftest Bitmap, 126*1da177e4SLinus Torvalds ** run the tests specified in the bitmap after the 127*1da177e4SLinus Torvalds ** system is rebooted w/PDC_DO_RESET. 128*1da177e4SLinus Torvalds ** 129*1da177e4SLinus Torvalds ** ftc_bitmap = 0x1AUL "Skip destructive memory tests" 130*1da177e4SLinus Torvalds ** 131*1da177e4SLinus Torvalds ** Using "directed resets" at each processor with the MEM_TOC 132*1da177e4SLinus Torvalds ** vector cleared will also avoid running destructive 133*1da177e4SLinus Torvalds ** memory self tests. (Not implemented yet) 134*1da177e4SLinus Torvalds */ 135*1da177e4SLinus Torvalds if (ftc_bitmap) { 136*1da177e4SLinus Torvalds pdc_do_firm_test_reset(ftc_bitmap); 137*1da177e4SLinus Torvalds } 138*1da177e4SLinus Torvalds #endif 139*1da177e4SLinus Torvalds /* set up a new led state on systems shipped with a LED State panel */ 140*1da177e4SLinus Torvalds pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN); 141*1da177e4SLinus Torvalds 142*1da177e4SLinus Torvalds /* "Normal" system reset */ 143*1da177e4SLinus Torvalds pdc_do_reset(); 144*1da177e4SLinus Torvalds 145*1da177e4SLinus Torvalds /* Nope...box should reset with just CMD_RESET now */ 146*1da177e4SLinus Torvalds gsc_writel(CMD_RESET, COMMAND_GLOBAL); 147*1da177e4SLinus Torvalds 148*1da177e4SLinus Torvalds /* Wait for RESET to lay us to rest. */ 149*1da177e4SLinus Torvalds while (1) ; 150*1da177e4SLinus Torvalds 151*1da177e4SLinus Torvalds } 152*1da177e4SLinus Torvalds 153*1da177e4SLinus Torvalds EXPORT_SYMBOL(machine_restart); 154*1da177e4SLinus Torvalds 155*1da177e4SLinus Torvalds void machine_halt(void) 156*1da177e4SLinus Torvalds { 157*1da177e4SLinus Torvalds /* 158*1da177e4SLinus Torvalds ** The LED/ChassisCodes are updated by the led_halt() 159*1da177e4SLinus Torvalds ** function, called by the reboot notifier chain. 160*1da177e4SLinus Torvalds */ 161*1da177e4SLinus Torvalds } 162*1da177e4SLinus Torvalds 163*1da177e4SLinus Torvalds EXPORT_SYMBOL(machine_halt); 164*1da177e4SLinus Torvalds 165*1da177e4SLinus Torvalds 166*1da177e4SLinus Torvalds /* 167*1da177e4SLinus Torvalds * This routine is called from sys_reboot to actually turn off the 168*1da177e4SLinus Torvalds * machine 169*1da177e4SLinus Torvalds */ 170*1da177e4SLinus Torvalds void machine_power_off(void) 171*1da177e4SLinus Torvalds { 172*1da177e4SLinus Torvalds /* If there is a registered power off handler, call it. */ 173*1da177e4SLinus Torvalds if(pm_power_off) 174*1da177e4SLinus Torvalds pm_power_off(); 175*1da177e4SLinus Torvalds 176*1da177e4SLinus Torvalds /* Put the soft power button back under hardware control. 177*1da177e4SLinus Torvalds * If the user had already pressed the power button, the 178*1da177e4SLinus Torvalds * following call will immediately power off. */ 179*1da177e4SLinus Torvalds pdc_soft_power_button(0); 180*1da177e4SLinus Torvalds 181*1da177e4SLinus Torvalds pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN); 182*1da177e4SLinus Torvalds 183*1da177e4SLinus Torvalds /* It seems we have no way to power the system off via 184*1da177e4SLinus Torvalds * software. The user has to press the button himself. */ 185*1da177e4SLinus Torvalds 186*1da177e4SLinus Torvalds printk(KERN_EMERG "System shut down completed.\n" 187*1da177e4SLinus Torvalds KERN_EMERG "Please power this system off now."); 188*1da177e4SLinus Torvalds } 189*1da177e4SLinus Torvalds 190*1da177e4SLinus Torvalds EXPORT_SYMBOL(machine_power_off); 191*1da177e4SLinus Torvalds 192*1da177e4SLinus Torvalds 193*1da177e4SLinus Torvalds /* 194*1da177e4SLinus Torvalds * Create a kernel thread 195*1da177e4SLinus Torvalds */ 196*1da177e4SLinus Torvalds 197*1da177e4SLinus Torvalds extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); 198*1da177e4SLinus Torvalds pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) 199*1da177e4SLinus Torvalds { 200*1da177e4SLinus Torvalds 201*1da177e4SLinus Torvalds /* 202*1da177e4SLinus Torvalds * FIXME: Once we are sure we don't need any debug here, 203*1da177e4SLinus Torvalds * kernel_thread can become a #define. 204*1da177e4SLinus Torvalds */ 205*1da177e4SLinus Torvalds 206*1da177e4SLinus Torvalds return __kernel_thread(fn, arg, flags); 207*1da177e4SLinus Torvalds } 208*1da177e4SLinus Torvalds EXPORT_SYMBOL(kernel_thread); 209*1da177e4SLinus Torvalds 210*1da177e4SLinus Torvalds /* 211*1da177e4SLinus Torvalds * Free current thread data structures etc.. 212*1da177e4SLinus Torvalds */ 213*1da177e4SLinus Torvalds void exit_thread(void) 214*1da177e4SLinus Torvalds { 215*1da177e4SLinus Torvalds } 216*1da177e4SLinus Torvalds 217*1da177e4SLinus Torvalds void flush_thread(void) 218*1da177e4SLinus Torvalds { 219*1da177e4SLinus Torvalds /* Only needs to handle fpu stuff or perf monitors. 220*1da177e4SLinus Torvalds ** REVISIT: several arches implement a "lazy fpu state". 221*1da177e4SLinus Torvalds */ 222*1da177e4SLinus Torvalds set_fs(USER_DS); 223*1da177e4SLinus Torvalds } 224*1da177e4SLinus Torvalds 225*1da177e4SLinus Torvalds void release_thread(struct task_struct *dead_task) 226*1da177e4SLinus Torvalds { 227*1da177e4SLinus Torvalds } 228*1da177e4SLinus Torvalds 229*1da177e4SLinus Torvalds /* 230*1da177e4SLinus Torvalds * Fill in the FPU structure for a core dump. 231*1da177e4SLinus Torvalds */ 232*1da177e4SLinus Torvalds 233*1da177e4SLinus Torvalds int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r) 234*1da177e4SLinus Torvalds { 235*1da177e4SLinus Torvalds if (regs == NULL) 236*1da177e4SLinus Torvalds return 0; 237*1da177e4SLinus Torvalds 238*1da177e4SLinus Torvalds memcpy(r, regs->fr, sizeof *r); 239*1da177e4SLinus Torvalds return 1; 240*1da177e4SLinus Torvalds } 241*1da177e4SLinus Torvalds 242*1da177e4SLinus Torvalds int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r) 243*1da177e4SLinus Torvalds { 244*1da177e4SLinus Torvalds memcpy(r, tsk->thread.regs.fr, sizeof(*r)); 245*1da177e4SLinus Torvalds return 1; 246*1da177e4SLinus Torvalds } 247*1da177e4SLinus Torvalds 248*1da177e4SLinus Torvalds /* Note that "fork()" is implemented in terms of clone, with 249*1da177e4SLinus Torvalds parameters (SIGCHLD, regs->gr[30], regs). */ 250*1da177e4SLinus Torvalds int 251*1da177e4SLinus Torvalds sys_clone(unsigned long clone_flags, unsigned long usp, 252*1da177e4SLinus Torvalds struct pt_regs *regs) 253*1da177e4SLinus Torvalds { 254*1da177e4SLinus Torvalds int __user *user_tid = (int __user *)regs->gr[26]; 255*1da177e4SLinus Torvalds 256*1da177e4SLinus Torvalds /* usp must be word aligned. This also prevents users from 257*1da177e4SLinus Torvalds * passing in the value 1 (which is the signal for a special 258*1da177e4SLinus Torvalds * return for a kernel thread) */ 259*1da177e4SLinus Torvalds usp = ALIGN(usp, 4); 260*1da177e4SLinus Torvalds 261*1da177e4SLinus Torvalds /* A zero value for usp means use the current stack */ 262*1da177e4SLinus Torvalds if(usp == 0) 263*1da177e4SLinus Torvalds usp = regs->gr[30]; 264*1da177e4SLinus Torvalds 265*1da177e4SLinus Torvalds return do_fork(clone_flags, usp, regs, 0, user_tid, NULL); 266*1da177e4SLinus Torvalds } 267*1da177e4SLinus Torvalds 268*1da177e4SLinus Torvalds int 269*1da177e4SLinus Torvalds sys_vfork(struct pt_regs *regs) 270*1da177e4SLinus Torvalds { 271*1da177e4SLinus Torvalds return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gr[30], regs, 0, NULL, NULL); 272*1da177e4SLinus Torvalds } 273*1da177e4SLinus Torvalds 274*1da177e4SLinus Torvalds int 275*1da177e4SLinus Torvalds copy_thread(int nr, unsigned long clone_flags, unsigned long usp, 276*1da177e4SLinus Torvalds unsigned long unused, /* in ia64 this is "user_stack_size" */ 277*1da177e4SLinus Torvalds struct task_struct * p, struct pt_regs * pregs) 278*1da177e4SLinus Torvalds { 279*1da177e4SLinus Torvalds struct pt_regs * cregs = &(p->thread.regs); 280*1da177e4SLinus Torvalds struct thread_info *ti = p->thread_info; 281*1da177e4SLinus Torvalds 282*1da177e4SLinus Torvalds /* We have to use void * instead of a function pointer, because 283*1da177e4SLinus Torvalds * function pointers aren't a pointer to the function on 64-bit. 284*1da177e4SLinus Torvalds * Make them const so the compiler knows they live in .text */ 285*1da177e4SLinus Torvalds extern void * const ret_from_kernel_thread; 286*1da177e4SLinus Torvalds extern void * const child_return; 287*1da177e4SLinus Torvalds #ifdef CONFIG_HPUX 288*1da177e4SLinus Torvalds extern void * const hpux_child_return; 289*1da177e4SLinus Torvalds #endif 290*1da177e4SLinus Torvalds 291*1da177e4SLinus Torvalds *cregs = *pregs; 292*1da177e4SLinus Torvalds 293*1da177e4SLinus Torvalds /* Set the return value for the child. Note that this is not 294*1da177e4SLinus Torvalds actually restored by the syscall exit path, but we put it 295*1da177e4SLinus Torvalds here for consistency in case of signals. */ 296*1da177e4SLinus Torvalds cregs->gr[28] = 0; /* child */ 297*1da177e4SLinus Torvalds 298*1da177e4SLinus Torvalds /* 299*1da177e4SLinus Torvalds * We need to differentiate between a user fork and a 300*1da177e4SLinus Torvalds * kernel fork. We can't use user_mode, because the 301*1da177e4SLinus Torvalds * the syscall path doesn't save iaoq. Right now 302*1da177e4SLinus Torvalds * We rely on the fact that kernel_thread passes 303*1da177e4SLinus Torvalds * in zero for usp. 304*1da177e4SLinus Torvalds */ 305*1da177e4SLinus Torvalds if (usp == 1) { 306*1da177e4SLinus Torvalds /* kernel thread */ 307*1da177e4SLinus Torvalds cregs->ksp = (((unsigned long)(ti)) + THREAD_SZ_ALGN); 308*1da177e4SLinus Torvalds /* Must exit via ret_from_kernel_thread in order 309*1da177e4SLinus Torvalds * to call schedule_tail() 310*1da177e4SLinus Torvalds */ 311*1da177e4SLinus Torvalds cregs->kpc = (unsigned long) &ret_from_kernel_thread; 312*1da177e4SLinus Torvalds /* 313*1da177e4SLinus Torvalds * Copy function and argument to be called from 314*1da177e4SLinus Torvalds * ret_from_kernel_thread. 315*1da177e4SLinus Torvalds */ 316*1da177e4SLinus Torvalds #ifdef __LP64__ 317*1da177e4SLinus Torvalds cregs->gr[27] = pregs->gr[27]; 318*1da177e4SLinus Torvalds #endif 319*1da177e4SLinus Torvalds cregs->gr[26] = pregs->gr[26]; 320*1da177e4SLinus Torvalds cregs->gr[25] = pregs->gr[25]; 321*1da177e4SLinus Torvalds } else { 322*1da177e4SLinus Torvalds /* user thread */ 323*1da177e4SLinus Torvalds /* 324*1da177e4SLinus Torvalds * Note that the fork wrappers are responsible 325*1da177e4SLinus Torvalds * for setting gr[21]. 326*1da177e4SLinus Torvalds */ 327*1da177e4SLinus Torvalds 328*1da177e4SLinus Torvalds /* Use same stack depth as parent */ 329*1da177e4SLinus Torvalds cregs->ksp = ((unsigned long)(ti)) 330*1da177e4SLinus Torvalds + (pregs->gr[21] & (THREAD_SIZE - 1)); 331*1da177e4SLinus Torvalds cregs->gr[30] = usp; 332*1da177e4SLinus Torvalds if (p->personality == PER_HPUX) { 333*1da177e4SLinus Torvalds #ifdef CONFIG_HPUX 334*1da177e4SLinus Torvalds cregs->kpc = (unsigned long) &hpux_child_return; 335*1da177e4SLinus Torvalds #else 336*1da177e4SLinus Torvalds BUG(); 337*1da177e4SLinus Torvalds #endif 338*1da177e4SLinus Torvalds } else { 339*1da177e4SLinus Torvalds cregs->kpc = (unsigned long) &child_return; 340*1da177e4SLinus Torvalds } 341*1da177e4SLinus Torvalds } 342*1da177e4SLinus Torvalds 343*1da177e4SLinus Torvalds return 0; 344*1da177e4SLinus Torvalds } 345*1da177e4SLinus Torvalds 346*1da177e4SLinus Torvalds unsigned long thread_saved_pc(struct task_struct *t) 347*1da177e4SLinus Torvalds { 348*1da177e4SLinus Torvalds return t->thread.regs.kpc; 349*1da177e4SLinus Torvalds } 350*1da177e4SLinus Torvalds 351*1da177e4SLinus Torvalds /* 352*1da177e4SLinus Torvalds * sys_execve() executes a new program. 353*1da177e4SLinus Torvalds */ 354*1da177e4SLinus Torvalds 355*1da177e4SLinus Torvalds asmlinkage int sys_execve(struct pt_regs *regs) 356*1da177e4SLinus Torvalds { 357*1da177e4SLinus Torvalds int error; 358*1da177e4SLinus Torvalds char *filename; 359*1da177e4SLinus Torvalds 360*1da177e4SLinus Torvalds filename = getname((const char __user *) regs->gr[26]); 361*1da177e4SLinus Torvalds error = PTR_ERR(filename); 362*1da177e4SLinus Torvalds if (IS_ERR(filename)) 363*1da177e4SLinus Torvalds goto out; 364*1da177e4SLinus Torvalds error = do_execve(filename, (char __user **) regs->gr[25], 365*1da177e4SLinus Torvalds (char __user **) regs->gr[24], regs); 366*1da177e4SLinus Torvalds if (error == 0) { 367*1da177e4SLinus Torvalds task_lock(current); 368*1da177e4SLinus Torvalds current->ptrace &= ~PT_DTRACE; 369*1da177e4SLinus Torvalds task_unlock(current); 370*1da177e4SLinus Torvalds } 371*1da177e4SLinus Torvalds putname(filename); 372*1da177e4SLinus Torvalds out: 373*1da177e4SLinus Torvalds 374*1da177e4SLinus Torvalds return error; 375*1da177e4SLinus Torvalds } 376*1da177e4SLinus Torvalds 377*1da177e4SLinus Torvalds unsigned long 378*1da177e4SLinus Torvalds get_wchan(struct task_struct *p) 379*1da177e4SLinus Torvalds { 380*1da177e4SLinus Torvalds struct unwind_frame_info info; 381*1da177e4SLinus Torvalds unsigned long ip; 382*1da177e4SLinus Torvalds int count = 0; 383*1da177e4SLinus Torvalds /* 384*1da177e4SLinus Torvalds * These bracket the sleeping functions.. 385*1da177e4SLinus Torvalds */ 386*1da177e4SLinus Torvalds 387*1da177e4SLinus Torvalds unwind_frame_init_from_blocked_task(&info, p); 388*1da177e4SLinus Torvalds do { 389*1da177e4SLinus Torvalds if (unwind_once(&info) < 0) 390*1da177e4SLinus Torvalds return 0; 391*1da177e4SLinus Torvalds ip = info.ip; 392*1da177e4SLinus Torvalds if (!in_sched_functions(ip)) 393*1da177e4SLinus Torvalds return ip; 394*1da177e4SLinus Torvalds } while (count++ < 16); 395*1da177e4SLinus Torvalds return 0; 396*1da177e4SLinus Torvalds } 397