diff options
Diffstat (limited to 'arch/parisc/kernel')
30 files changed, 780 insertions, 945 deletions
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c index c11a5bc7c06..54fdb959149 100644 --- a/arch/parisc/kernel/asm-offsets.c +++ b/arch/parisc/kernel/asm-offsets.c @@ -44,7 +44,7 @@ #define BLANK() asm volatile("\n->" : : ) -#ifdef __LP64__ +#ifdef CONFIG_64BIT #define FRAME_SIZE 128 #else #define FRAME_SIZE 64 diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 0be51e92a2f..0dc924ccceb 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -68,16 +68,6 @@ flush_cache_all_local(void) } EXPORT_SYMBOL(flush_cache_all_local); -/* flushes EVERYTHING (tlb & cache) */ - -void -flush_all_caches(void) -{ - flush_cache_all(); - flush_tlb_all(); -} -EXPORT_SYMBOL(flush_all_caches); - void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) { @@ -99,7 +89,7 @@ show_cache_info(struct seq_file *m) seq_printf(m, "I-cache\t\t: %ld KB\n", cache_info.ic_size/1024 ); - if (cache_info.dc_loop == 1) + if (cache_info.dc_loop != 1) snprintf(buf, 32, "%lu-way associative", cache_info.dc_loop); seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %s)\n", cache_info.dc_size/1024, @@ -270,6 +260,83 @@ void disable_sr_hashing(void) panic("SpaceID hashing is still on!\n"); } +/* Simple function to work out if we have an existing address translation + * for a user space vma. */ +static inline int translation_exists(struct vm_area_struct *vma, + unsigned long addr, unsigned long pfn) +{ + pgd_t *pgd = pgd_offset(vma->vm_mm, addr); + pmd_t *pmd; + pte_t pte; + + if(pgd_none(*pgd)) + return 0; + + pmd = pmd_offset(pgd, addr); + if(pmd_none(*pmd) || pmd_bad(*pmd)) + return 0; + + /* We cannot take the pte lock here: flush_cache_page is usually + * called with pte lock already held. Whereas flush_dcache_page + * takes flush_dcache_mmap_lock, which is lower in the hierarchy: + * the vma itself is secure, but the pte might come or go racily. + */ + pte = *pte_offset_map(pmd, addr); + /* But pte_unmap() does nothing on this architecture */ + + /* Filter out coincidental file entries and swap entries */ + if (!(pte_val(pte) & (_PAGE_FLUSH|_PAGE_PRESENT))) + return 0; + + return pte_pfn(pte) == pfn; +} + +/* Private function to flush a page from the cache of a non-current + * process. cr25 contains the Page Directory of the current user + * process; we're going to hijack both it and the user space %sr3 to + * temporarily make the non-current process current. We have to do + * this because cache flushing may cause a non-access tlb miss which + * the handlers have to fill in from the pgd of the non-current + * process. */ +static inline void +flush_user_cache_page_non_current(struct vm_area_struct *vma, + unsigned long vmaddr) +{ + /* save the current process space and pgd */ + unsigned long space = mfsp(3), pgd = mfctl(25); + + /* we don't mind taking interrups since they may not + * do anything with user space, but we can't + * be preempted here */ + preempt_disable(); + + /* make us current */ + mtctl(__pa(vma->vm_mm->pgd), 25); + mtsp(vma->vm_mm->context, 3); + + flush_user_dcache_page(vmaddr); + if(vma->vm_flags & VM_EXEC) + flush_user_icache_page(vmaddr); + + /* put the old current process back */ + mtsp(space, 3); + mtctl(pgd, 25); + preempt_enable(); +} + + +static inline void +__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr) +{ + if (likely(vma->vm_mm->context == mfsp(3))) { + flush_user_dcache_page(vmaddr); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_page(vmaddr); + } else { + flush_user_cache_page_non_current(vma, vmaddr); + } +} + void flush_dcache_page(struct page *page) { struct address_space *mapping = page_mapping(page); @@ -342,7 +409,7 @@ void clear_user_page_asm(void *page, unsigned long vaddr) #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */ int parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD; -void parisc_setup_cache_timing(void) +void __init parisc_setup_cache_timing(void) { unsigned long rangetime, alltime; unsigned long size; @@ -366,6 +433,9 @@ void parisc_setup_cache_timing(void) if (!parisc_cache_flush_threshold) parisc_cache_flush_threshold = FLUSH_THRESHOLD; + if (parisc_cache_flush_threshold > cache_info.dc_size) + parisc_cache_flush_threshold = cache_info.dc_size; + printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); } @@ -410,3 +480,97 @@ void kunmap_parisc(void *addr) } EXPORT_SYMBOL(kunmap_parisc); #endif + +void __flush_tlb_range(unsigned long sid, unsigned long start, + unsigned long end) +{ + unsigned long npages; + + npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT; + if (npages >= 512) /* 2MB of space: arbitrary, should be tuned */ + flush_tlb_all(); + else { + mtsp(sid, 1); + purge_tlb_start(); + if (split_tlb) { + while (npages--) { + pdtlb(start); + pitlb(start); + start += PAGE_SIZE; + } + } else { + while (npages--) { + pdtlb(start); + start += PAGE_SIZE; + } + } + purge_tlb_end(); + } +} + +static void cacheflush_h_tmp_function(void *dummy) +{ + flush_cache_all_local(); +} + +void flush_cache_all(void) +{ + on_each_cpu(cacheflush_h_tmp_function, NULL, 1, 1); +} + +void flush_cache_mm(struct mm_struct *mm) +{ +#ifdef CONFIG_SMP + flush_cache_all(); +#else + flush_cache_all_local(); +#endif +} + +void +flush_user_dcache_range(unsigned long start, unsigned long end) +{ + if ((end - start) < parisc_cache_flush_threshold) + flush_user_dcache_range_asm(start,end); + else + flush_data_cache(); +} + +void +flush_user_icache_range(unsigned long start, unsigned long end) +{ + if ((end - start) < parisc_cache_flush_threshold) + flush_user_icache_range_asm(start,end); + else + flush_instruction_cache(); +} + + +void flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ + int sr3; + + if (!vma->vm_mm->context) { + BUG(); + return; + } + + sr3 = mfsp(3); + if (vma->vm_mm->context == sr3) { + flush_user_dcache_range(start,end); + flush_user_icache_range(start,end); + } else { + flush_cache_all(); + } +} + +void +flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn) +{ + BUG_ON(!vma->vm_mm->context); + + if (likely(translation_exists(vma, vmaddr, pfn))) + __flush_cache_page(vma, vmaddr); + +} diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index d6c486e9501..2ca654bd632 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -562,12 +562,23 @@ pa_dev_attr(rev, id.hversion_rev, "0x%x\n"); pa_dev_attr_id(hversion, "0x%03x\n"); pa_dev_attr_id(sversion, "0x%05x\n"); +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct parisc_device *padev = to_parisc_device(dev); + struct parisc_device_id *id = &padev->id; + + return sprintf(buf, "parisc:t%02Xhv%04Xrev%02Xsv%08X\n", + (u8)id->hw_type, (u16)id->hversion, (u8)id->hversion_rev, + (u32)id->sversion); +} + static struct device_attribute parisc_device_attrs[] = { __ATTR_RO(irq), __ATTR_RO(hw_type), __ATTR_RO(rev), __ATTR_RO(hversion), __ATTR_RO(sversion), + __ATTR_RO(modalias), __ATTR_NULL, }; @@ -689,7 +700,9 @@ parse_tree_node(struct device *parent, int index, struct hardware_path *modpath) .fn = check_parent, }; - device_for_each_child(parent, &recurse_data, descend_children); + if (device_for_each_child(parent, &recurse_data, descend_children)) + /* nothing */; + return d.dev; } @@ -835,8 +848,8 @@ static void print_parisc_device(struct parisc_device *dev) static int count; print_pa_hwpath(dev, hw_path); - printk(KERN_INFO "%d. %s at 0x%lx [%s] { %d, 0x%x, 0x%.3x, 0x%.5x }", - ++count, dev->name, dev->hpa.start, hw_path, dev->id.hw_type, + printk(KERN_INFO "%d. %s at 0x%p [%s] { %d, 0x%x, 0x%.3x, 0x%.5x }", + ++count, dev->name, (void*) dev->hpa.start, hw_path, dev->id.hw_type, dev->id.hversion_rev, dev->id.hversion, dev->id.sversion); if (dev->num_addrs) { diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 340b5e8d67b..8474f9e5ca1 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -37,6 +37,8 @@ #include <asm/unistd.h> #include <asm/thread_info.h> +#include <linux/linkage.h> + #ifdef CONFIG_64BIT #define CMPIB cmpib,* #define CMPB cmpb,* @@ -648,13 +650,11 @@ * the static part of the kernel address space. */ - .export fault_vector_20 - .text .align 4096 -fault_vector_20: +ENTRY(fault_vector_20) /* First vector is invalid (0) */ .ascii "cows can fly" .byte 0 @@ -695,14 +695,13 @@ fault_vector_20: def 29 def 30 def 31 +END(fault_vector_20) #ifndef CONFIG_64BIT - .export fault_vector_11 - .align 2048 -fault_vector_11: +ENTRY(fault_vector_11) /* First vector is invalid (0) */ .ascii "cows can fly" .byte 0 @@ -743,6 +742,7 @@ fault_vector_11: def 29 def 30 def 31 +END(fault_vector_11) #endif @@ -762,9 +762,8 @@ fault_vector_11: #define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */ #define CLONE_UNTRACED 0x00800000 - .export __kernel_thread, code .import do_fork -__kernel_thread: +ENTRY(__kernel_thread) STREG %r2, -RP_OFFSET(%r30) copy %r30, %r1 @@ -797,6 +796,7 @@ __kernel_thread: ldo -PT_SZ_ALGN(%r30), %r30 bv %r0(%r2) nop +ENDPROC(__kernel_thread) /* * Child Returns here @@ -805,8 +805,7 @@ __kernel_thread: * into task save area. */ - .export ret_from_kernel_thread -ret_from_kernel_thread: +ENTRY(ret_from_kernel_thread) /* Call schedule_tail first though */ BL schedule_tail, %r2 @@ -833,10 +832,10 @@ ret_from_kernel_thread: bv %r0(%r1) #endif ldi 0, %r26 +ENDPROC(ret_from_kernel_thread) .import sys_execve, code - .export __execve, code -__execve: +ENTRY(__execve) copy %r2, %r15 copy %r30, %r16 ldo PT_SZ_ALGN(%r30), %r30 @@ -856,16 +855,15 @@ __execve: copy %r16, %r30 bv %r0(%r2) nop +ENDPROC(__execve) - .align 4 /* * struct task_struct *_switch_to(struct task_struct *prev, * struct task_struct *next) * * switch kernel stacks and return prev */ - .export _switch_to, code -_switch_to: +ENTRY(_switch_to) STREG %r2, -RP_OFFSET(%r30) callee_save_float @@ -890,6 +888,7 @@ _switch_to_ret: LDREG -RP_OFFSET(%r30), %r2 bv %r0(%r2) copy %r26, %r28 +ENDPROC(_switch_to) /* * Common rfi return path for interruptions, kernel execve, and @@ -907,8 +906,7 @@ _switch_to_ret: .align 4096 - .export syscall_exit_rfi -syscall_exit_rfi: +ENTRY(syscall_exit_rfi) mfctl %cr30,%r16 LDREG TI_TASK(%r16), %r16 /* thread_info -> task_struct */ ldo TASK_REGS(%r16),%r16 @@ -978,11 +976,36 @@ intr_check_resched: LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */ bb,<,n %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */ + .import do_notify_resume,code intr_check_sig: /* As above */ mfctl %cr30,%r1 - LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_SIGPENDING */ - bb,<,n %r19, 31-TIF_SIGPENDING, intr_do_signal /* forward */ + LDREG TI_FLAGS(%r1),%r19 + ldi (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r20 + and,COND(<>) %r19, %r20, %r0 + b,n intr_restore /* skip past if we've nothing to do */ + + /* This check is critical to having LWS + * working. The IASQ is zero on the gateway + * page and we cannot deliver any signals until + * we get off the gateway page. + * + * Only do signals if we are returning to user space + */ + LDREG PT_IASQ0(%r16), %r20 + CMPIB=,n 0,%r20,intr_restore /* backward */ + LDREG PT_IASQ1(%r16), %r20 + CMPIB=,n 0,%r20,intr_restore /* backward */ + + copy %r0, %r25 /* long in_syscall = 0 */ +#ifdef CONFIG_64BIT + ldo -16(%r30),%r29 /* Reference param save area */ +#endif + + BL do_notify_resume,%r2 + copy %r16, %r26 /* struct pt_regs *regs */ + + b,n intr_check_sig intr_restore: copy %r16,%r29 @@ -1072,35 +1095,6 @@ intr_do_preempt: b,n intr_restore /* ssm PSW_SM_I done by intr_restore */ #endif /* CONFIG_PREEMPT */ - .import do_signal,code -intr_do_signal: - /* - This check is critical to having LWS - working. The IASQ is zero on the gateway - page and we cannot deliver any signals until - we get off the gateway page. - - Only do signals if we are returning to user space - */ - LDREG PT_IASQ0(%r16), %r20 - CMPIB= 0,%r20,intr_restore /* backward */ - nop - LDREG PT_IASQ1(%r16), %r20 - CMPIB= 0,%r20,intr_restore /* backward */ - nop - - copy %r0, %r24 /* unsigned long in_syscall */ - copy %r16, %r25 /* struct pt_regs *regs */ -#ifdef CONFIG_64BIT - ldo -16(%r30),%r29 /* Reference param save area */ -#endif - - BL do_signal,%r2 - copy %r0, %r26 /* sigset_t *oldset = NULL */ - - b intr_check_sig - nop - /* * External interrupts. */ @@ -1115,11 +1109,7 @@ intr_extint: mfctl %cr31,%r1 copy %r30,%r17 /* FIXME! depi below has hardcoded idea of interrupt stack size (32k)*/ -#ifdef CONFIG_64BIT - depdi 0,63,15,%r17 -#else - depi 0,31,15,%r17 -#endif + DEPI 0,31,15,%r17 CMPB=,n %r1,%r17,2f get_stack_use_cr31 b,n 3f @@ -1148,13 +1138,12 @@ intr_extint: b do_cpu_irq_mask ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */ +ENDPROC(syscall_exit_rfi) /* Generic interruptions (illegal insn, unaligned, page fault, etc) */ - .export intr_save, code /* for os_hpmc */ - -intr_save: +ENTRY(intr_save) /* for os_hpmc */ mfsp %sr7,%r16 CMPIB=,n 0,%r16,1f get_stack_use_cr30 @@ -1229,6 +1218,7 @@ skip_save_ior: b handle_interruption ldo R%intr_check_sig(%r2), %r2 +ENDPROC(intr_save) /* @@ -1814,9 +1804,7 @@ dtlb_fault: LDREG PT_GR18(\regs),%r18 .endm - .export sys_fork_wrapper - .export child_return -sys_fork_wrapper: +ENTRY(sys_fork_wrapper) LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1 ldo TASK_REGS(%r1),%r1 reg_save %r1 @@ -1853,9 +1841,10 @@ wrapper_exit: ldi __NR_fork,%r20 bv %r0(%r2) STREG %r20,PT_GR20(%r1) +ENDPROC(sys_fork_wrapper) /* Set the return value for the child */ -child_return: +ENTRY(child_return) BL schedule_tail, %r2 nop @@ -1863,10 +1852,10 @@ child_return: LDREG TASK_PT_GR19(%r1),%r2 b wrapper_exit copy %r0,%r28 +ENDPROC(child_return) - - .export sys_clone_wrapper -sys_clone_wrapper: + +ENTRY(sys_clone_wrapper) LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 ldo TASK_REGS(%r1),%r1 /* get pt regs */ reg_save %r1 @@ -1887,9 +1876,10 @@ sys_clone_wrapper: b wrapper_exit LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2 +ENDPROC(sys_clone_wrapper) + - .export sys_vfork_wrapper -sys_vfork_wrapper: +ENTRY(sys_vfork_wrapper) LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 ldo TASK_REGS(%r1),%r1 /* get pt regs */ reg_save %r1 @@ -1910,6 +1900,7 @@ sys_vfork_wrapper: b wrapper_exit LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2 +ENDPROC(sys_vfork_wrapper) .macro execve_wrapper execve @@ -1946,22 +1937,19 @@ error_\execve: nop .endm - .export sys_execve_wrapper .import sys_execve - -sys_execve_wrapper: +ENTRY(sys_execve_wrapper) execve_wrapper sys_execve +ENDPROC(sys_execve_wrapper) #ifdef CONFIG_64BIT - .export sys32_execve_wrapper .import sys32_execve - -sys32_execve_wrapper: +ENTRY(sys32_execve_wrapper) execve_wrapper sys32_execve +ENDPROC(sys32_execve_wrapper) #endif - .export sys_rt_sigreturn_wrapper -sys_rt_sigreturn_wrapper: +ENTRY(sys_rt_sigreturn_wrapper) LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 ldo TASK_REGS(%r26),%r26 /* get pt regs */ /* Don't save regs, we are going to restore them from sigcontext. */ @@ -1989,9 +1977,9 @@ sys_rt_sigreturn_wrapper: */ bv %r0(%r2) LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */ +ENDPROC(sys_rt_sigreturn_wrapper) - .export sys_sigaltstack_wrapper -sys_sigaltstack_wrapper: +ENTRY(sys_sigaltstack_wrapper) /* Get the user stack pointer */ LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 ldo TASK_REGS(%r1),%r24 /* get pt regs */ @@ -1999,10 +1987,10 @@ sys_sigaltstack_wrapper: STREG %r2, -RP_OFFSET(%r30) #ifdef CONFIG_64BIT ldo FRAME_SIZE(%r30), %r30 - b,l do_sigaltstack,%r2 + BL do_sigaltstack,%r2 ldo -16(%r30),%r29 /* Reference param save area */ #else - bl do_sigaltstack,%r2 + BL do_sigaltstack,%r2 ldo FRAME_SIZE(%r30), %r30 #endif @@ -2010,53 +1998,26 @@ sys_sigaltstack_wrapper: LDREG -RP_OFFSET(%r30), %r2 bv %r0(%r2) nop +ENDPROC(sys_sigaltstack_wrapper) #ifdef CONFIG_64BIT - .export sys32_sigaltstack_wrapper -sys32_sigaltstack_wrapper: +ENTRY(sys32_sigaltstack_wrapper) /* Get the user stack pointer */ LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r24 LDREG TASK_PT_GR30(%r24),%r24 STREG %r2, -RP_OFFSET(%r30) ldo FRAME_SIZE(%r30), %r30 - b,l do_sigaltstack32,%r2 + BL do_sigaltstack32,%r2 ldo -16(%r30),%r29 /* Reference param save area */ ldo -FRAME_SIZE(%r30), %r30 LDREG -RP_OFFSET(%r30), %r2 bv %r0(%r2) nop +ENDPROC(sys32_sigaltstack_wrapper) #endif - .export sys_rt_sigsuspend_wrapper -sys_rt_sigsuspend_wrapper: - LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1 - ldo TASK_REGS(%r1),%r24 - reg_save %r24 - - STREG %r2, -RP_OFFSET(%r30) -#ifdef CONFIG_64BIT - ldo FRAME_SIZE(%r30), %r30 - b,l sys_rt_sigsuspend,%r2 - ldo -16(%r30),%r29 /* Reference param save area */ -#else - bl sys_rt_sigsuspend,%r2 - ldo FRAME_SIZE(%r30), %r30 -#endif - - ldo -FRAME_SIZE(%r30), %r30 - LDREG -RP_OFFSET(%r30), %r2 - - LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1 - ldo TASK_REGS(%r1),%r1 - reg_restore %r1 - - bv %r0(%r2) - nop - - .export syscall_exit -syscall_exit: - +ENTRY(syscall_exit) /* NOTE: HP-UX syscalls also come through here * after hpux_syscall_exit fixes up return * values. */ @@ -2119,9 +2080,35 @@ syscall_check_resched: LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* long */ bb,<,n %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */ + .import do_signal,code syscall_check_sig: - LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* get ti flags */ - bb,<,n %r19, 31-TIF_SIGPENDING, syscall_do_signal /* forward */ + LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 + ldi (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r26 + and,COND(<>) %r19, %r26, %r0 + b,n syscall_restore /* skip past if we've nothing to do */ + +syscall_do_signal: + /* Save callee-save registers (for sigcontext). + * FIXME: After this point the process structure should be + * consistent with all the relevant state of the process + * before the syscall. We need to verify this. + */ + LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 + ldo TASK_REGS(%r1), %r26 /* struct pt_regs *regs */ + reg_save %r26 + +#ifdef CONFIG_64BIT + ldo -16(%r30),%r29 /* Reference param save area */ +#endif + + BL do_notify_resume,%r2 + ldi 1, %r25 /* long in_syscall = 1 */ + + LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 + ldo TASK_REGS(%r1), %r20 /* reload pt_regs */ + reg_restore %r20 + + b,n syscall_check_sig syscall_restore: /* Are we being ptraced? */ @@ -2259,31 +2246,10 @@ syscall_do_resched: #endif b syscall_check_bh /* if resched, we start over again */ nop +ENDPROC(syscall_exit) - .import do_signal,code -syscall_do_signal: - /* Save callee-save registers (for sigcontext). - FIXME: After this point the process structure should be - consistent with all the relevant state of the process - before the syscall. We need to verify this. */ - LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 - ldo TASK_REGS(%r1), %r25 /* struct pt_regs *regs */ - reg_save %r25 - - ldi 1, %r24 /* unsigned long in_syscall */ - -#ifdef CONFIG_64BIT - ldo -16(%r30),%r29 /* Reference param save area */ -#endif - BL do_signal,%r2 - copy %r0, %r26 /* sigset_t *oldset = NULL */ - - LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 - ldo TASK_REGS(%r1), %r20 /* reload pt_regs */ - reg_restore %r20 - - b,n syscall_check_sig +get_register: /* * get_register is used by the non access tlb miss handlers to * copy the value of the general register specified in r8 into @@ -2294,8 +2260,6 @@ syscall_do_signal: * a -1 in it, but that is OK, it just means that we will have * to use the slow path instead). */ - -get_register: blr %r8,%r0 nop bv %r0(%r25) /* r0 */ @@ -2363,13 +2327,13 @@ get_register: bv %r0(%r25) /* r31 */ copy %r31,%r1 + +set_register: /* * set_register is used by the non access tlb miss handlers to * copy the value of r1 into the general register specified in * r8. */ - -set_register: blr %r8,%r0 nop bv %r0(%r25) /* r0 (silly, but it is a place holder) */ @@ -2436,3 +2400,4 @@ set_register: copy %r1,%r30 bv %r0(%r25) /* r31 */ copy %r1,%r31 + diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 9158b707c0d..39dc835bf89 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -74,7 +74,7 @@ static DEFINE_SPINLOCK(pdc_lock); static unsigned long pdc_result[32] __attribute__ ((aligned (8))); static unsigned long pdc_result2[32] __attribute__ ((aligned (8))); -#ifdef __LP64__ +#ifdef CONFIG_64BIT #define WIDE_FIRMWARE 0x1 #define NARROW_FIRMWARE 0x2 @@ -94,12 +94,12 @@ int parisc_narrow_firmware __read_mostly = 1; * when running a 64-bit kernel on such boxes (e.g. C200 or C360). */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT long real64_call(unsigned long function, ...); #endif long real32_call(unsigned long function, ...); -#ifdef __LP64__ +#ifdef CONFIG_64BIT # define MEM_PDC (unsigned long)(PAGE0->mem_pdc_hi) << 32 | PAGE0->mem_pdc # define mem_pdc_call(args...) unlikely(parisc_narrow_firmware) ? real32_call(MEM_PDC, args) : real64_call(MEM_PDC, args) #else @@ -117,7 +117,7 @@ long real32_call(unsigned long function, ...); */ static unsigned long f_extend(unsigned long address) { -#ifdef __LP64__ +#ifdef CONFIG_64BIT if(unlikely(parisc_narrow_firmware)) { if((address & 0xff000000) == 0xf0000000) return 0xf0f0f0f000000000UL | (u32)address; @@ -139,7 +139,7 @@ static unsigned long f_extend(unsigned long address) */ static void convert_to_wide(unsigned long *addr) { -#ifdef __LP64__ +#ifdef CONFIG_64BIT int i; unsigned int *p = (unsigned int *)addr; @@ -158,7 +158,7 @@ static void convert_to_wide(unsigned long *addr) */ void __init set_firmware_width(void) { -#ifdef __LP64__ +#ifdef CONFIG_64BIT int retval; unsigned long flags; @@ -238,7 +238,7 @@ int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_inf * * Must be correctly formatted or expect system crash */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT int pdc_pat_chassis_send_log(unsigned long state, unsigned long data) { int retval = 0; @@ -949,7 +949,7 @@ int pdc_tod_set(unsigned long sec, unsigned long usec) } EXPORT_SYMBOL(pdc_tod_set); -#ifdef __LP64__ +#ifdef CONFIG_64BIT int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr, struct pdc_memory_table *tbl, unsigned long entries) { @@ -965,7 +965,7 @@ int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr, return retval; } -#endif /* __LP64__ */ +#endif /* CONFIG_64BIT */ /* FIXME: Is this pdc used? I could not find type reference to ftc_bitmap * so I guessed at unsigned long. Someone who knows what this does, can fix @@ -1204,7 +1204,7 @@ int pdc_sti_call(unsigned long func, unsigned long flags, } EXPORT_SYMBOL(pdc_sti_call); -#ifdef __LP64__ +#ifdef CONFIG_64BIT /** * pdc_pat_cell_get_number - Returns the cell number. * @cell_info: The return buffer. @@ -1387,7 +1387,7 @@ int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, u32 val) return retval; } -#endif /* __LP64__ */ +#endif /* CONFIG_64BIT */ /***************** 32-bit real-mode calls ***********/ @@ -1445,7 +1445,7 @@ long real32_call(unsigned long fn, ...) return real32_call_asm(&real_stack.sp, &real_stack.arg0, fn); } -#ifdef __LP64__ +#ifdef CONFIG_64BIT /***************** 64-bit real-mode calls ***********/ struct wide_stack { @@ -1496,5 +1496,5 @@ long real64_call(unsigned long fn, ...) return real64_call_asm(&real64_stack.sp, &real64_stack.arg0, fn); } -#endif /* __LP64__ */ +#endif /* CONFIG_64BIT */ diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index eaad2328fea..9676c486bb6 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -2,7 +2,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1999 by Helge Deller + * Copyright (C) 1999-2007 by Helge Deller <deller@gmx.de> * Copyright 1999 SuSE GmbH (Philipp Rumpf) * Copyright 1999 Philipp Rumpf (prumpf@tux.org) * Copyright 2000 Hewlett Packard (Paul Bame, bame@puffin.external.hp.com) @@ -19,16 +19,17 @@ #include <asm/assembly.h> #include <asm/pgtable.h> +#include <linux/linkage.h> + .level LEVEL .data - - .export boot_args -boot_args: +ENTRY(boot_args) .word 0 /* arg0 */ .word 0 /* arg1 */ .word 0 /* arg2 */ .word 0 /* arg3 */ +END(boot_args) .text .align 4 @@ -38,10 +39,9 @@ boot_args: .import fault_vector_11,code /* IVA parisc 1.1 32 bit */ .import $global$ /* forward declaration */ #endif /*!CONFIG_64BIT*/ - .export stext .export _stext,data /* Kernel want it this way! */ _stext: -stext: +ENTRY(stext) .proc .callinfo @@ -343,6 +343,9 @@ smp_slave_stext: .procend #endif /* CONFIG_SMP */ + +ENDPROC(stext) + #ifndef CONFIG_64BIT .data diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S index c412c0adc4a..d8baa158d8a 100644 --- a/arch/parisc/kernel/hpmc.S +++ b/arch/parisc/kernel/hpmc.S @@ -46,6 +46,8 @@ #include <asm/assembly.h> #include <asm/pdc.h> +#include <linux/linkage.h> + /* * stack for os_hpmc, the HPMC handler. * buffer for IODC procedures (for the HPMC handler). @@ -69,17 +71,15 @@ hpmc_raddr: #define HPMC_PIM_DATA_SIZE 896 /* Enough to hold all architected 2.0 state */ - .export hpmc_pim_data, data .align 8 -hpmc_pim_data: +ENTRY(hpmc_pim_data) .block HPMC_PIM_DATA_SIZE +END(hpmc_pim_data) .text - .export os_hpmc, code .import intr_save, code - -os_hpmc: +ENTRY(os_hpmc) /* * registers modified: @@ -294,11 +294,9 @@ os_hpmc_6: b . nop +ENDPROC(os_hpmc) /* this label used to compute os_hpmc checksum */ - - .export os_hpmc_end, code - -os_hpmc_end: +ENTRY(os_hpmc_end) nop diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c index 4e847ba5318..4845a644463 100644 --- a/arch/parisc/kernel/inventory.c +++ b/arch/parisc/kernel/inventory.c @@ -47,7 +47,7 @@ void __init setup_pdc(void) struct pdc_system_map_mod_info module_result; struct pdc_module_path module_path; struct pdc_model model; -#ifdef __LP64__ +#ifdef CONFIG_64BIT struct pdc_pat_cell_num cell_info; #endif @@ -73,7 +73,7 @@ void __init setup_pdc(void) * clearer message. */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT status = pdc_pat_cell_get_number(&cell_info); if (status == PDC_OK) { pdc_type = PDC_TYPE_PAT; @@ -152,7 +152,7 @@ static void __init pagezero_memconfig(void) npmem_ranges = 1; } -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* All of the PDC PAT specific code is 64-bit only */ @@ -408,13 +408,13 @@ static void __init sprockets_memconfig(void) } } -#else /* !__LP64__ */ +#else /* !CONFIG_64BIT */ #define pat_inventory() do { } while (0) #define pat_memconfig() do { } while (0) #define sprockets_memconfig() pagezero_memconfig() -#endif /* !__LP64__ */ +#endif /* !CONFIG_64BIT */ #ifndef CONFIG_PA20 diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index b39c5b9aff4..e9d09b020e8 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -336,11 +336,7 @@ unsigned int txn_alloc_data(unsigned int virt_irq) static inline int eirr_to_irq(unsigned long eirr) { -#ifdef CONFIG_64BIT - int bit = fls64(eirr); -#else - int bit = fls(eirr); -#endif + int bit = fls_long(eirr); return (BITS_PER_LONG - bit) + TIMER_IRQ; } diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index f50b982b083..fdacdd4341c 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -46,6 +46,7 @@ #include <linux/fs.h> #include <linux/string.h> #include <linux/kernel.h> +#include <linux/bug.h> #include <asm/unwind.h> @@ -96,7 +97,7 @@ static inline int in_local_section(struct module *me, void *loc, void *dot) } -#ifndef __LP64__ +#ifndef CONFIG_64BIT struct got_entry { Elf32_Addr addr; }; @@ -176,7 +177,7 @@ void *module_alloc(unsigned long size) return vmalloc(size); } -#ifndef __LP64__ +#ifndef CONFIG_64BIT static inline unsigned long count_gots(const Elf_Rela *rela, unsigned long n) { return 0; @@ -319,7 +320,7 @@ int module_frob_arch_sections(CONST Elf_Ehdr *hdr, return 0; } -#ifdef __LP64__ +#ifdef CONFIG_64BIT static Elf64_Word get_got(struct module *me, unsigned long value, long addend) { unsigned int i; @@ -342,9 +343,9 @@ static Elf64_Word get_got(struct module *me, unsigned long value, long addend) value); return i * sizeof(struct got_entry); } -#endif /* __LP64__ */ +#endif /* CONFIG_64BIT */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT static Elf_Addr get_fdesc(struct module *me, unsigned long value) { Elf_Fdesc *fdesc = me->module_core + me->arch.fdesc_offset; @@ -368,7 +369,7 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value) fdesc->gp = (Elf_Addr)me->module_core + me->arch.got_offset; return (Elf_Addr)fdesc; } -#endif /* __LP64__ */ +#endif /* CONFIG_64BIT */ enum elf_stub_type { ELF_STUB_GOT, @@ -394,7 +395,7 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, i * sizeof(struct stub_entry); } -#ifndef __LP64__ +#ifndef CONFIG_64BIT /* for 32-bit the stub looks like this: * ldil L'XXX,%r1 * be,n R'XXX(%sr4,%r1) @@ -472,7 +473,7 @@ int apply_relocate(Elf_Shdr *sechdrs, return -ENOEXEC; } -#ifndef __LP64__ +#ifndef CONFIG_64BIT int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, @@ -822,7 +823,8 @@ int module_finalize(const Elf_Ehdr *hdr, me->name, strtab, symhdr); if(me->arch.got_count > MAX_GOTS) { - printk(KERN_ERR "%s: Global Offset Table overflow (used %ld, allowed %d\n", me->name, me->arch.got_count, MAX_GOTS); + printk(KERN_ERR "%s: Global Offset Table overflow (used %ld, allowed %d)\n", + me->name, me->arch.got_count, MAX_GOTS); return -EINVAL; } @@ -850,10 +852,11 @@ int module_finalize(const Elf_Ehdr *hdr, nsyms = newptr - (Elf_Sym *)symhdr->sh_addr; DEBUGP("NEW num_symtab %lu\n", nsyms); symhdr->sh_size = nsyms * sizeof(Elf_Sym); - return 0; + return module_bug_finalize(hdr, sechdrs, me); } void module_arch_cleanup(struct module *mod) { deregister_unwind_table(mod); + module_bug_cleanup(mod); } diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index e81c9937d10..90b24087852 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -27,31 +27,21 @@ */ #ifdef CONFIG_64BIT -#define ADDIB addib,* -#define CMPB cmpb,* -#define ANDCM andcm,* - .level 2.0w #else -#define ADDIB addib, -#define CMPB cmpb, -#define ANDCM andcm - .level 2.0 #endif - #include <asm/psw.h> #include <asm/assembly.h> #include <asm/pgtable.h> #include <asm/cache.h> +#include <linux/linkage.h> .text .align 128 - .export flush_tlb_all_local,code - -flush_tlb_all_local: +ENTRY(flush_tlb_all_local) .proc .callinfo NO_CALLS .entry @@ -200,11 +190,11 @@ fdtdone: .exit .procend +ENDPROC(flush_tlb_all_local) - .export flush_instruction_cache_local,code .import cache_info,data -flush_instruction_cache_local: +ENTRY(flush_instruction_cache_local) .proc .callinfo NO_CALLS .entry @@ -241,11 +231,11 @@ fisync: .exit .procend +ENDPROC(flush_instruction_cache_local) - .export flush_data_cache_local, code - .import cache_info, data -flush_data_cache_local: + .import cache_info, data +ENTRY(flush_data_cache_local) .proc .callinfo NO_CALLS .entry @@ -283,11 +273,11 @@ fdsync: .exit .procend +ENDPROC(flush_data_cache_local) - .export copy_user_page_asm,code .align 16 -copy_user_page_asm: +ENTRY(copy_user_page_asm) .proc .callinfo NO_CALLS .entry @@ -409,6 +399,7 @@ copy_user_page_asm: .exit .procend +ENDPROC(copy_user_page_asm) /* * NOTE: Code in clear_user_page has a hard coded dependency on the @@ -446,9 +437,7 @@ copy_user_page_asm: * lobby for such a change. */ - .export copy_user_page_asm,code - -copy_user_page_asm: +ENTRY(copy_user_page_asm) .proc .callinfo NO_CALLS .entry @@ -534,11 +523,10 @@ copy_user_page_asm: .exit .procend +ENDPROC(copy_user_page_asm) #endif - .export __clear_user_page_asm,code - -__clear_user_page_asm: +ENTRY(__clear_user_page_asm) .proc .callinfo NO_CALLS .entry @@ -618,10 +606,9 @@ __clear_user_page_asm: .exit .procend +ENDPROC(__clear_user_page_asm) - .export flush_kernel_dcache_page_asm - -flush_kernel_dcache_page_asm: +ENTRY(flush_kernel_dcache_page_asm) .proc .callinfo NO_CALLS .entry @@ -662,10 +649,9 @@ flush_kernel_dcache_page_asm: .exit .procend +ENDPROC(flush_kernel_dcache_page_asm) - .export flush_user_dcache_page - -flush_user_dcache_page: +ENTRY(flush_user_dcache_page) .proc .callinfo NO_CALLS .entry @@ -706,10 +692,9 @@ flush_user_dcache_page: .exit .procend +ENDPROC(flush_user_dcache_page) - .export flush_user_icache_page - -flush_user_icache_page: +ENTRY(flush_user_icache_page) .proc .callinfo NO_CALLS .entry @@ -750,11 +735,10 @@ flush_user_icache_page: .exit .procend +ENDPROC(flush_user_icache_page) - .export purge_kernel_dcache_page - -purge_kernel_dcache_page: +ENTRY(purge_kernel_dcache_page) .proc .callinfo NO_CALLS .entry @@ -794,15 +778,14 @@ purge_kernel_dcache_page: .exit .procend +ENDPROC(purge_kernel_dcache_page) #if 0 /* Currently not used, but it still is a possible alternate * solution. */ - .export flush_alias_page - -flush_alias_page: +ENTRY(flush_alias_page) .proc .callinfo NO_CALLS .entry @@ -882,10 +865,9 @@ flush_user_dcache_range_asm: .exit .procend +ENDPROC(flush_alias_page) - .export flush_kernel_dcache_range_asm - -flush_kernel_dcache_range_asm: +ENTRY(flush_kernel_dcache_range_asm) .proc .callinfo NO_CALLS .entry @@ -905,10 +887,9 @@ flush_kernel_dcache_range_asm: .exit .procend +ENDPROC(flush_kernel_dcache_range_asm) - .export flush_user_icache_range_asm - -flush_user_icache_range_asm: +ENTRY(flush_user_icache_range_asm) .proc .callinfo NO_CALLS .entry @@ -927,10 +908,9 @@ flush_user_icache_range_asm: .exit .procend +ENDPROC(flush_user_icache_range_asm) - .export flush_kernel_icache_page - -flush_kernel_icache_page: +ENTRY(flush_kernel_icache_page) .proc .callinfo NO_CALLS .entry @@ -971,10 +951,9 @@ flush_kernel_icache_page: .exit .procend +ENDPROC(flush_kernel_icache_page) - .export flush_kernel_icache_range_asm - -flush_kernel_icache_range_asm: +ENTRY(flush_kernel_icache_range_asm) .proc .callinfo NO_CALLS .entry @@ -992,14 +971,13 @@ flush_kernel_icache_range_asm: nop .exit .procend +ENDPROC(flush_kernel_icache_range_asm) /* align should cover use of rfi in disable_sr_hashing_asm and * srdis_done. */ .align 256 - .export disable_sr_hashing_asm,code - -disable_sr_hashing_asm: +ENTRY(disable_sr_hashing_asm) .proc .callinfo NO_CALLS .entry @@ -1088,5 +1066,6 @@ srdis_done: .exit .procend +ENDPROC(disable_sr_hashing_asm) .end diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index 8f6a0b312f7..7aca704e96f 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -7,7 +7,7 @@ * Copyright (C) 2001-2003 Grant Grundler <grundler with parisc-linux.org> * Copyright (C) 2002-2003 Matthew Wilcox <willy at parisc-linux.org> * Copyright (C) 2002 Randolph Chung <tausq at parisc-linux.org> - * Copyright (C) 2002-2003 Helge Deller <deller with parisc-linux.org> + * Copyright (C) 2002-2007 Helge Deller <deller with parisc-linux.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,7 +38,7 @@ EXPORT_SYMBOL(__cmpxchg_u32); #ifdef CONFIG_SMP EXPORT_SYMBOL(__atomic_hash); #endif -#ifdef __LP64__ +#ifdef CONFIG_64BIT EXPORT_SYMBOL(__xchg64); EXPORT_SYMBOL(__cmpxchg_u64); #endif @@ -58,7 +58,7 @@ EXPORT_SYMBOL(fixup_get_user_skip_2); EXPORT_SYMBOL(fixup_put_user_skip_1); EXPORT_SYMBOL(fixup_put_user_skip_2); -#ifndef __LP64__ +#ifndef CONFIG_64BIT /* Needed so insmod can set dp value */ extern int $global$; EXPORT_SYMBOL($global$); @@ -135,7 +135,7 @@ EXPORT_SYMBOL(__muldi3); asmlinkage void * __canonicalize_funcptr_for_compare(void *); EXPORT_SYMBOL(__canonicalize_funcptr_for_compare); -#ifdef __LP64__ +#ifdef CONFIG_64BIT extern void __divdi3(void); extern void __udivdi3(void); extern void __umoddi3(void); @@ -147,7 +147,7 @@ EXPORT_SYMBOL(__umoddi3); EXPORT_SYMBOL(__moddi3); #endif -#ifndef __LP64__ +#ifndef CONFIG_64BIT extern void $$dyncall(void); EXPORT_SYMBOL($$dyncall); #endif diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index a6caf107308..0c3aecb85a5 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -342,7 +342,7 @@ pcxl_dma_init(void) pcxl_res_map = (char *)__get_free_pages(GFP_KERNEL, get_order(pcxl_res_size)); memset(pcxl_res_map, 0, pcxl_res_size); - proc_gsc_root = proc_mkdir("gsc", 0); + proc_gsc_root = proc_mkdir("gsc", NULL); if (!proc_gsc_root) printk(KERN_WARNING "pcxl_dma_init: Unable to create gsc /proc dir entry\n"); diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c index 199887a61c7..563df0072de 100644 --- a/arch/parisc/kernel/pci.c +++ b/arch/parisc/kernel/pci.c @@ -200,8 +200,8 @@ static void pcibios_link_hba_resources( struct resource *hba_res, struct resource *r) { if (!r->parent) { - printk(KERN_EMERG "PCI: resource not parented! [%lx-%lx]\n", - r->start, r->end); + printk(KERN_EMERG "PCI: resource not parented! [%p-%p]\n", + (void*) r->start, (void*) r->end); r->parent = hba_res; /* reverse link is harder *sigh* */ diff --git a/arch/parisc/kernel/perf_asm.S b/arch/parisc/kernel/perf_asm.S index 5e7bb90e7e0..43874ca3ed6 100644 --- a/arch/parisc/kernel/perf_asm.S +++ b/arch/parisc/kernel/perf_asm.S @@ -20,6 +20,7 @@ */ #include <asm/assembly.h> +#include <linux/linkage.h> #ifdef CONFIG_64BIT .level 2.0w @@ -41,10 +42,8 @@ ; starting/stopping the coprocessor with the pmenb/pmdis. ; .text - .align 32 - .export perf_intrigue_enable_perf_counters,code -perf_intrigue_enable_perf_counters: +ENTRY(perf_intrigue_enable_perf_counters) .proc .callinfo frame=0,NO_CALLS .entry @@ -69,9 +68,9 @@ perf_intrigue_enable_perf_counters: nop .exit .procend +ENDPROC(perf_intrigue_enable_perf_counters) - .export perf_intrigue_disable_perf_counters,code -perf_intrigue_disable_perf_counters: +ENTRY(perf_intrigue_disable_perf_counters) .proc .callinfo frame=0,NO_CALLS .entry @@ -86,6 +85,7 @@ perf_intrigue_disable_perf_counters: mtctl %r26,ccr ; turn off performance coprocessor .exit .procend +ENDPROC(perf_intrigue_disable_perf_counters) ;*********************************************************************** ;* @@ -117,8 +117,7 @@ perf_intrigue_disable_perf_counters: ;* ;*********************************************************************** - .export perf_rdr_shift_in_W,code -perf_rdr_shift_in_W: +ENTRY(perf_rdr_shift_in_W) .proc .callinfo frame=0,NO_CALLS .entry @@ -550,6 +549,7 @@ perf_rdr_shift_in_W_leave: .exit MTDIAG_2 (24) ; restore DR2 .procend +ENDPROC(perf_rdr_shift_in_W) ;*********************************************************************** @@ -575,8 +575,7 @@ perf_rdr_shift_in_W_leave: ;* ;*********************************************************************** - .export perf_rdr_shift_out_W,code -perf_rdr_shift_out_W: +ENTRY(perf_rdr_shift_out_W) .proc .callinfo frame=0,NO_CALLS .entry @@ -983,6 +982,7 @@ perf_rdr_shift_out_W_leave: .exit MTDIAG_2 (23) ; restore DR2 .procend +ENDPROC(perf_rdr_shift_out_W) ;*********************************************************************** @@ -1012,8 +1012,7 @@ perf_rdr_shift_out_W_leave: ;* ;*********************************************************************** - .export perf_rdr_shift_in_U,code -perf_rdr_shift_in_U: +ENTRY(perf_rdr_shift_in_U) .proc .callinfo frame=0,NO_CALLS .entry @@ -1343,6 +1342,7 @@ perf_rdr_shift_in_U_leave: .exit MTDIAG_2 (24) ; restore DR2 .procend +ENDPROC(perf_rdr_shift_in_U) ;*********************************************************************** ;* @@ -1369,8 +1369,7 @@ perf_rdr_shift_in_U_leave: ;* ;*********************************************************************** - .export perf_rdr_shift_out_U,code -perf_rdr_shift_out_U: +ENTRY(perf_rdr_shift_out_U) .proc .callinfo frame=0,NO_CALLS .entry @@ -1687,4 +1686,5 @@ perf_rdr_shift_out_U_leave: .exit MTDIAG_2 (23) ; restore DR2 .procend +ENDPROC(perf_rdr_shift_out_U) diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 2f9f9dfa66f..0dd3847f494 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -13,7 +13,7 @@ * Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org> * Copyright (C) 2001 Alan Modra <amodra at parisc-linux.org> * Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org> - * Copyright (C) 2001-2002 Helge Deller <deller at parisc-linux.org> + * Copyright (C) 2001-2007 Helge Deller <deller at parisc-linux.org> * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org> * * @@ -303,7 +303,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, * Copy function and argument to be called from * ret_from_kernel_thread. */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT cregs->gr[27] = pregs->gr[27]; #endif cregs->gr[26] = pregs->gr[26]; @@ -355,8 +355,8 @@ asmlinkage int sys_execve(struct pt_regs *regs) error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char __user **) regs->gr[25], - (char __user **) regs->gr[24], regs); + error = do_execve(filename, (char __user * __user *) regs->gr[25], + (char __user * __user *) regs->gr[24], regs); if (error == 0) { task_lock(current); current->ptrace &= ~PT_DTRACE; diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index fb81e5687e7..7c056dcebf5 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c @@ -93,7 +93,7 @@ static int __init processor_probe(struct parisc_device *dev) cpuid = boot_cpu_data.cpu_count; txn_addr = dev->hpa.start; /* for legacy PDC */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (is_pdc_pat()) { ulong status; unsigned long bytecnt; @@ -153,8 +153,6 @@ static int __init processor_probe(struct parisc_device *dev) p->cpuid = cpuid; /* save CPU id */ p->txn_addr = txn_addr; /* save CPU IRQ address */ #ifdef CONFIG_SMP - spin_lock_init(&p->lock); - /* ** FIXME: review if any other initialization is clobbered ** for boot_cpu by the above memset(). @@ -311,11 +309,11 @@ int __init init_per_cpu(int cpunum) } else { printk(KERN_WARNING "WARNING: No FP CoProcessor?!" " (coproc_cfg.ccr_functional == 0x%lx, expected 0xc0)\n" -#ifdef __LP64__ +#ifdef CONFIG_64BIT "Halting Machine - FP required\n" #endif , coproc_cfg.ccr_functional); -#ifdef __LP64__ +#ifdef CONFIG_64BIT mdelay(100); /* previous chars get pushed to console */ panic("FP CoProc not reported"); #endif @@ -339,9 +337,6 @@ show_cpuinfo (struct seq_file *m, void *v) #ifdef CONFIG_SMP if (0 == cpu_data[n].hpa) continue; -#ifdef ENTRY_SYS_CPUS -#error iCOD support wants to show CPU state here -#endif #endif seq_printf(m, "processor\t: %d\n" "cpu family\t: PA-RISC %s\n", diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index 3f28de97455..0d0d617b6f2 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -36,7 +36,7 @@ #define DBG(x...) #endif -#ifdef __LP64__ +#ifdef CONFIG_64BIT /* This function is needed to translate 32 bit pt_regs offsets in to * 64 bit pt_regs offsets. For example, a 32 bit gdb under a 64 bit kernel @@ -90,7 +90,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_PEEKDATA: { int copied; -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (__is_compat_task(child)) { unsigned int tmp; @@ -122,7 +122,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: ret = 0; -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (__is_compat_task(child)) { unsigned int tmp = (unsigned int)data; DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n", @@ -145,7 +145,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) processes, the kernel saves all regs on a syscall. */ case PTRACE_PEEKUSR: { ret = -EIO; -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (__is_compat_task(child)) { unsigned int tmp; @@ -204,7 +204,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = 0; goto out_tsk; } -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (__is_compat_task(child)) { if (addr & (sizeof(int)-1)) goto out_tsk; diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S index 789061f6ceb..7a92695d95a 100644 --- a/arch/parisc/kernel/real2.S +++ b/arch/parisc/kernel/real2.S @@ -11,6 +11,8 @@ #include <asm/psw.h> #include <asm/assembly.h> +#include <linux/linkage.h> + .section .bss .export real_stack .export real32_stack @@ -39,8 +41,6 @@ save_cr_end: .text - .export real32_call_asm - /* unsigned long real32_call_asm(unsigned int *sp, * unsigned int *arg0p, * unsigned int iodc_fn) @@ -49,7 +49,7 @@ save_cr_end: * iodc_fn is the IODC function to call */ -real32_call_asm: +ENTRY(real32_call_asm) STREG %rp, -RP_OFFSET(%sp) /* save RP */ #ifdef CONFIG_64BIT callee_save @@ -107,6 +107,7 @@ ric_ret: LDREG -RP_OFFSET(%sp), %rp /* restore RP */ bv 0(%rp) nop +ENDPROC(real32_call_asm) # define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where) @@ -218,7 +219,6 @@ rfi_r2v_1: /************************ 64-bit real-mode calls ***********************/ /* This is only usable in wide kernels right now and will probably stay so */ .text - .export real64_call_asm /* unsigned long real64_call_asm(unsigned long *sp, * unsigned long *arg0p, * unsigned long fn) @@ -226,7 +226,7 @@ rfi_r2v_1: * arg0p points to where saved arg values may be found * iodc_fn is the IODC function to call */ -real64_call_asm: +ENTRY(real64_call_asm) std %rp, -0x10(%sp) /* save RP */ std %sp, -8(%arg0) /* save SP on real-mode stack */ copy %arg0, %sp /* adopt the real-mode SP */ @@ -272,19 +272,21 @@ r64_ret: ldd -0x10(%sp), %rp /* restore RP */ bv 0(%rp) nop +ENDPROC(real64_call_asm) #endif - .export __canonicalize_funcptr_for_compare .text /* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html ** GCC 3.3 and later has a new function in libgcc.a for ** comparing function pointers. */ -__canonicalize_funcptr_for_compare: +ENTRY(__canonicalize_funcptr_for_compare) #ifdef CONFIG_64BIT bve (%r2) #else bv %r0(%r2) #endif copy %r26,%r28 +ENDPROC(__canonicalize_funcptr_for_compare) + diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index 74b3686dd1e..bd2116e03f3 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -120,13 +120,13 @@ extern void collect_boot_cpu_data(void); void __init setup_arch(char **cmdline_p) { -#ifdef __LP64__ +#ifdef CONFIG_64BIT extern int parisc_narrow_firmware; #endif init_per_cpu(smp_processor_id()); /* Set Modes & Enable FP */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT printk(KERN_INFO "The 64-bit Kernel has started...\n"); #else printk(KERN_INFO "The 32-bit Kernel has started...\n"); @@ -134,7 +134,7 @@ void __init setup_arch(char **cmdline_p) pdc_console_init(); -#ifdef __LP64__ +#ifdef CONFIG_64BIT if(parisc_narrow_firmware) { printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n"); } diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index ee6653edeb7..9784e405f84 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -59,58 +59,13 @@ * this. */ #define A(__x) ((unsigned long)(__x)) -int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall); - /* * Atomically swap in the new signal mask, and wait for a signal. */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT #include "sys32.h" #endif -asmlinkage int -sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs) -{ - sigset_t saveset, newset; -#ifdef __LP64__ - compat_sigset_t newset32; - - if (is_compat_task()) { - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(compat_sigset_t)) - return -EINVAL; - if (copy_from_user(&newset32, (compat_sigset_t __user *)unewset, sizeof(newset32))) - return -EFAULT; - sigset_32to64(&newset,&newset32); - - } else -#endif - { - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - } - - sigdelsetmask(&newset, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - regs->gr[28] = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&saveset, regs, 1)) - return -EINTR; - } -} - /* * Do a signal return - restore sigcontext. */ @@ -148,7 +103,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) sigset_t set; unsigned long usp = (regs->gr[30] & ~(0x01UL)); unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE; -#ifdef __LP64__ +#ifdef CONFIG_64BIT compat_sigset_t compat_set; struct compat_rt_sigframe __user * compat_frame; @@ -162,7 +117,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) (usp - sigframe_size); DBG(2,"sys_rt_sigreturn: frame is %p\n", frame); -#ifdef __LP64__ +#ifdef CONFIG_64BIT compat_frame = (struct compat_rt_sigframe __user *)frame; if (is_compat_task()) { @@ -184,7 +139,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) spin_unlock_irq(¤t->sighand->siglock); /* Good thing we saved the old gr[30], eh? */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (is_compat_task()) { DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n", &compat_frame->uc.uc_mcontext); @@ -296,7 +251,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, unsigned long rp, usp; unsigned long haddr, sigframe_size; int err = 0; -#ifdef __LP64__ +#ifdef CONFIG_64BIT compat_int_t compat_val; struct compat_rt_sigframe __user * compat_frame; compat_sigset_t compat_set; @@ -310,7 +265,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, DBG(1,"setup_rt_frame: frame %p info %p\n", frame, info); -#ifdef __LP64__ +#ifdef CONFIG_64BIT compat_frame = (struct compat_rt_sigframe __user *)frame; @@ -390,7 +345,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, haddr = A(ka->sa.sa_handler); /* The sa_handler may be a pointer to a function descriptor */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (is_compat_task()) { #endif if (haddr & PA_PLABEL_FDESC) { @@ -405,7 +360,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, haddr = fdesc.addr; regs->gr[19] = fdesc.gp; } -#ifdef __LP64__ +#ifdef CONFIG_64BIT } else { Elf64_Fdesc fdesc; Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3); @@ -425,19 +380,19 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, /* The syscall return path will create IAOQ values from r31. */ sigframe_size = PARISC_RT_SIGFRAME_SIZE; -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (is_compat_task()) sigframe_size = PARISC_RT_SIGFRAME_SIZE32; #endif if (in_syscall) { regs->gr[31] = haddr; -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (!test_thread_flag(TIF_32BIT)) sigframe_size |= 1; #endif } else { unsigned long psw = USER_PSW; -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (!test_thread_flag(TIF_32BIT)) psw |= PSW_W; #endif @@ -462,7 +417,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->gr[2] = rp; /* userland return pointer */ regs->gr[26] = sig; /* signal number */ -#ifdef __LP64__ +#ifdef CONFIG_64BIT if (is_compat_task()) { regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */ regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */ @@ -516,6 +471,97 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, return 1; } +static inline void +syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) +{ + /* Check the return code */ + switch (regs->gr[28]) { + case -ERESTART_RESTARTBLOCK: + current_thread_info()->restart_block.fn = + do_no_restart_syscall; + case -ERESTARTNOHAND: + DBG(1,"ERESTARTNOHAND: returning -EINTR\n"); + regs->gr[28] = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + DBG(1,"ERESTARTSYS: putting -EINTR\n"); + regs->gr[28] = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + /* A syscall is just a branch, so all + * we have to do is fiddle the return pointer. + */ + regs->gr[31] -= 8; /* delayed branching */ + /* Preserve original r28. */ + regs->gr[28] = regs->orig_r28; + break; + } +} + +static inline void +insert_restart_trampoline(struct pt_regs *regs) +{ + switch(regs->gr[28]) { + case -ERESTART_RESTARTBLOCK: { + /* Restart the system call - no handlers present */ + unsigned int *usp = (unsigned int *)regs->gr[30]; + + /* Setup a trampoline to restart the syscall + * with __NR_restart_syscall + * + * 0: <return address (orig r31)> + * 4: <2nd half for 64-bit> + * 8: ldw 0(%sp), %r31 + * 12: be 0x100(%sr2, %r0) + * 16: ldi __NR_restart_syscall, %r20 + */ +#ifdef CONFIG_64BIT + put_user(regs->gr[31] >> 32, &usp[0]); + put_user(regs->gr[31] & 0xffffffff, &usp[1]); + put_user(0x0fc010df, &usp[2]); +#else + put_user(regs->gr[31], &usp[0]); + put_user(0x0fc0109f, &usp[2]); +#endif + put_user(0xe0008200, &usp[3]); + put_user(0x34140000, &usp[4]); + + /* Stack is 64-byte aligned, and we only need + * to flush 1 cache line. + * Flushing one cacheline is cheap. + * "sync" on bigger (> 4 way) boxes is not. + */ + flush_icache_range(regs->gr[30], regs->gr[30] + 4); + + regs->gr[31] = regs->gr[30] + 8; + /* Preserve original r28. */ + regs->gr[28] = regs->orig_r28; + + return; + } + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: { + /* Hooray for delayed branching. We don't + * have to restore %r20 (the system call + * number) because it gets loaded in the delay + * slot of the branch external instruction. + */ + regs->gr[31] -= 8; + /* Preserve original r28. */ + regs->gr[28] = regs->orig_r28; + + return; + } + default: + break; + } +} + /* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by @@ -527,13 +573,13 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, * registers). As noted below, the syscall number gets restored for * us due to the magic of delayed branching. */ - -asmlinkage int -do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) +asmlinkage void +do_signal(struct pt_regs *regs, long in_syscall) { siginfo_t info; struct k_sigaction ka; int signr; + sigset_t *oldset; DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n", oldset, regs, regs->sr[7], in_syscall); @@ -543,7 +589,9 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) we would be called in that case, but for some reason we are. */ - if (!oldset) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else oldset = ¤t->blocked; DBG(1,"do_signal: oldset %08lx / %08lx\n", @@ -560,98 +608,41 @@ do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) break; /* Restart a system call if necessary. */ - if (in_syscall) { - /* Check the return code */ - switch (regs->gr[28]) { - case -ERESTART_RESTARTBLOCK: - current_thread_info()->restart_block.fn = do_no_restart_syscall; - case -ERESTARTNOHAND: - DBG(1,"ERESTARTNOHAND: returning -EINTR\n"); - regs->gr[28] = -EINTR; - break; - - case -ERESTARTSYS: - if (!(ka.sa.sa_flags & SA_RESTART)) { - DBG(1,"ERESTARTSYS: putting -EINTR\n"); - regs->gr[28] = -EINTR; - break; - } - /* fallthrough */ - case -ERESTARTNOINTR: - /* A syscall is just a branch, so all - we have to do is fiddle the return pointer. */ - regs->gr[31] -= 8; /* delayed branching */ - /* Preserve original r28. */ - regs->gr[28] = regs->orig_r28; - break; - } - } + if (in_syscall) + syscall_restart(regs, &ka); + /* Whee! Actually deliver the signal. If the delivery failed, we need to continue to iterate in this loop so we can deliver the SIGSEGV... */ - if (handle_signal(signr, &info, &ka, oldset, regs, in_syscall)) { + if (handle_signal(signr, &info, &ka, oldset, + regs, in_syscall)) { DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", regs->gr[28]); - return 1; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + return; } } /* end of while(1) looping forever if we can't force a signal */ /* Did we come from a system call? */ - if (in_syscall) { - /* Restart the system call - no handlers present */ - if (regs->gr[28] == -ERESTART_RESTARTBLOCK) { - unsigned int *usp = (unsigned int *)regs->gr[30]; - - /* Setup a trampoline to restart the syscall - * with __NR_restart_syscall - * - * 0: <return address (orig r31)> - * 4: <2nd half for 64-bit> - * 8: ldw 0(%sp), %r31 - * 12: be 0x100(%sr2, %r0) - * 16: ldi __NR_restart_syscall, %r20 - */ -#ifndef __LP64__ - put_user(regs->gr[31], &usp[0]); - put_user(0x0fc0109f, &usp[2]); -#else - put_user(regs->gr[31] >> 32, &usp[0]); - put_user(regs->gr[31] & 0xffffffff, &usp[1]); - put_user(0x0fc010df, &usp[2]); -#endif - put_user(0xe0008200, &usp[3]); - put_user(0x34140000, &usp[4]); - - /* Stack is 64-byte aligned, and we only need - * to flush 1 cache line. - * Flushing one cacheline is cheap. - * "sync" on bigger (> 4 way) boxes is not. - */ - asm("fdc %%r0(%%sr3, %0)\n" - "sync\n" - "fic %%r0(%%sr3, %0)\n" - "sync\n" - : : "r"(regs->gr[30])); - - regs->gr[31] = regs->gr[30] + 8; - /* Preserve original r28. */ - regs->gr[28] = regs->orig_r28; - } else if (regs->gr[28] == -ERESTARTNOHAND || - regs->gr[28] == -ERESTARTSYS || - regs->gr[28] == -ERESTARTNOINTR) { - /* Hooray for delayed branching. We don't - have to restore %r20 (the system call - number) because it gets loaded in the delay - slot of the branch external instruction. */ - regs->gr[31] -= 8; - /* Preserve original r28. */ - regs->gr[28] = regs->orig_r28; - } - } + if (in_syscall) + insert_restart_trampoline(regs); DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", regs->gr[28]); - return 0; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + + return; +} + +void do_notify_resume(struct pt_regs *regs, long in_syscall) +{ + if (test_thread_flag(TIF_SIGPENDING) || + test_thread_flag(TIF_RESTORE_SIGMASK)) + do_signal(regs, in_syscall); } diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index a6b4231cafa..1c1a37f7305 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -1,6 +1,8 @@ /* Signal support for 32-bit kernel builds * * Copyright (C) 2001 Matthew Wilcox <willy at parisc-linux.org> + * Copyright (C) 2006 Kyle McMartin <kyle at parisc-linux.org> + * * Code was mostly borrowed from kernel/signal.c. * See kernel/signal.c for additional Copyrights. * @@ -401,7 +403,7 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __ int copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from) { - unsigned long tmp; + compat_uptr_t addr; int err; if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t))) @@ -424,8 +426,8 @@ copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from) err |= __get_user(to->si_uid, &from->si_uid); break; case __SI_FAULT >> 16: - err |= __get_user(tmp, &from->si_addr); - to->si_addr = (void __user *) tmp; + err |= __get_user(addr, &from->si_addr); + to->si_addr = compat_ptr(addr); break; case __SI_POLL >> 16: err |= __get_user(to->si_band, &from->si_band); @@ -445,7 +447,8 @@ copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from) int copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from) { - unsigned int addr; + compat_uptr_t addr; + compat_int_t val; int err; if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t))) @@ -474,8 +477,8 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from) err |= __put_user(from->si_uid, &to->si_uid); break; case __SI_FAULT >> 16: - /* avoid type-checking warnings by copying _pad[0] in lieu of si_addr... */ - err |= __put_user(from->_sifields._pad[0], &to->si_addr); + addr = ptr_to_compat(from->si_addr); + err |= __put_user(addr, &to->si_addr); break; case __SI_POLL >> 16: err |= __put_user(from->si_band, &to->si_band); @@ -484,17 +487,36 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from) case __SI_TIMER >> 16: err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_overrun, &to->si_overrun); - addr = (unsigned long) from->si_ptr; - err |= __put_user(addr, &to->si_ptr); + val = (compat_int_t)from->si_int; + err |= __put_user(val, &to->si_int); break; case __SI_RT >> 16: /* Not generated by the kernel as of now. */ case __SI_MESGQ >> 16: err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_pid, &to->si_pid); - addr = (unsigned long) from->si_ptr; - err |= __put_user(addr, &to->si_ptr); + val = (compat_int_t)from->si_int; + err |= __put_user(val, &to->si_int); break; } } return err; } + +asmlinkage long compat_sys_rt_sigqueueinfo(int pid, int sig, + struct compat_siginfo __user *uinfo) +{ + siginfo_t info; + + if (copy_siginfo_from_user32(&info, uinfo)) + return -EFAULT; + + /* Not even root can pretend to send signals from the kernel. + Nor can they impersonate a kill(), which adds source info. */ + if (info.si_code >= 0) + return -EPERM; + info.si_signo = sig; + + /* POSIX.1b doesn't mention process groups. */ + return kill_proc_info(sig, &info, pid); +} + diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 12cc019307a..6ba9257fdb7 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -16,9 +16,6 @@ ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. */ -#undef ENTRY_SYS_CPUS /* syscall support for iCOD-like functionality */ - - #include <linux/types.h> #include <linux/spinlock.h> #include <linux/slab.h> @@ -51,7 +48,15 @@ #include <asm/unistd.h> #include <asm/cacheflush.h> -#define kDEBUG 0 +#undef DEBUG_SMP +#ifdef DEBUG_SMP +static int smp_debug_lvl = 0; +#define smp_debug(lvl, printargs...) \ + if (lvl >= smp_debug_lvl) \ + printk(printargs); +#else +#define smp_debug(lvl, ...) +#endif /* DEBUG_SMP */ DEFINE_SPINLOCK(smp_lock); @@ -76,6 +81,7 @@ cpumask_t cpu_possible_map __read_mostly = CPU_MASK_ALL; /* Bitmap of Present CP EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(cpu_possible_map); +DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED; struct smp_call_struct { void (*func) (void *info); @@ -107,13 +113,6 @@ enum ipi_message_type { static void ipi_init(int cpuid) { - - /* If CPU is present ... */ -#ifdef ENTRY_SYS_CPUS - /* *and* running (not stopped) ... */ -#error iCOD support wants state checked here. -#endif - #error verify IRQ_OFFSET(IPI_IRQ) is ipi_interrupt() in new IRQ region if(cpu_online(cpuid) ) @@ -133,23 +132,12 @@ ipi_init(int cpuid) static void halt_processor(void) { -#ifdef ENTRY_SYS_CPUS -#error halt_processor() needs rework -/* -** o migrate I/O interrupts off this CPU. -** o leave IPI enabled - __cli() will disable IPI. -** o leave CPU in online map - just change the state -*/ - cpu_data[this_cpu].state = STATE_STOPPED; - mark_bh(IPI_BH); -#else /* REVISIT : redirect I/O Interrupts to another CPU? */ /* REVISIT : does PM *know* this CPU isn't available? */ cpu_clear(smp_processor_id(), cpu_online_map); local_irq_disable(); for (;;) ; -#endif } @@ -167,10 +155,11 @@ ipi_interrupt(int irq, void *dev_id) mb(); /* Order interrupt and bit testing. */ for (;;) { - spin_lock_irqsave(&(p->lock),flags); + spinlock_t *lock = &per_cpu(ipi_lock, this_cpu); + spin_lock_irqsave(lock, flags); ops = p->pending_ipi; p->pending_ipi = 0; - spin_unlock_irqrestore(&(p->lock),flags); + spin_unlock_irqrestore(lock, flags); mb(); /* Order bit clearing and data access. */ @@ -184,15 +173,11 @@ ipi_interrupt(int irq, void *dev_id) switch (which) { case IPI_NOP: -#if (kDEBUG>=100) - printk(KERN_DEBUG "CPU%d IPI_NOP\n",this_cpu); -#endif /* kDEBUG */ + smp_debug(100, KERN_DEBUG "CPU%d IPI_NOP\n", this_cpu); break; case IPI_RESCHEDULE: -#if (kDEBUG>=100) - printk(KERN_DEBUG "CPU%d IPI_RESCHEDULE\n",this_cpu); -#endif /* kDEBUG */ + smp_debug(100, KERN_DEBUG "CPU%d IPI_RESCHEDULE\n", this_cpu); /* * Reschedule callback. Everything to be * done is done by the interrupt return path. @@ -200,9 +185,7 @@ ipi_interrupt(int irq, void *dev_id) break; case IPI_CALL_FUNC: -#if (kDEBUG>=100) - printk(KERN_DEBUG "CPU%d IPI_CALL_FUNC\n",this_cpu); -#endif /* kDEBUG */ + smp_debug(100, KERN_DEBUG "CPU%d IPI_CALL_FUNC\n", this_cpu); { volatile struct smp_call_struct *data; void (*func)(void *info); @@ -233,28 +216,16 @@ ipi_interrupt(int irq, void *dev_id) break; case IPI_CPU_START: -#if (kDEBUG>=100) - printk(KERN_DEBUG "CPU%d IPI_CPU_START\n",this_cpu); -#endif /* kDEBUG */ -#ifdef ENTRY_SYS_CPUS - p->state = STATE_RUNNING; -#endif + smp_debug(100, KERN_DEBUG "CPU%d IPI_CPU_START\n", this_cpu); break; case IPI_CPU_STOP: -#if (kDEBUG>=100) - printk(KERN_DEBUG "CPU%d IPI_CPU_STOP\n",this_cpu); -#endif /* kDEBUG */ -#ifdef ENTRY_SYS_CPUS -#else + smp_debug(100, KERN_DEBUG "CPU%d IPI_CPU_STOP\n", this_cpu); halt_processor(); -#endif break; case IPI_CPU_TEST: -#if (kDEBUG>=100) - printk(KERN_DEBUG "CPU%d is alive!\n",this_cpu); -#endif /* kDEBUG */ + smp_debug(100, KERN_DEBUG "CPU%d is alive!\n", this_cpu); break; default: @@ -275,12 +246,13 @@ static inline void ipi_send(int cpu, enum ipi_message_type op) { struct cpuinfo_parisc *p = &cpu_data[cpu]; + spinlock_t *lock = &per_cpu(ipi_lock, cpu); unsigned long flags; - spin_lock_irqsave(&(p->lock),flags); + spin_lock_irqsave(lock, flags); p->pending_ipi |= 1 << op; gsc_writel(IPI_IRQ - CPU_IRQ_BASE, cpu_data[cpu].hpa); - spin_unlock_irqrestore(&(p->lock),flags); + spin_unlock_irqrestore(lock, flags); } @@ -560,13 +532,8 @@ int __init smp_boot_one_cpu(int cpuid) alive: /* Remember the Slave data */ -#if (kDEBUG>=100) - printk(KERN_DEBUG "SMP: CPU:%d came alive after %ld _us\n", + smp_debug(100, KERN_DEBUG "SMP: CPU:%d came alive after %ld _us\n", cpuid, timeout * 100); -#endif /* kDEBUG */ -#ifdef ENTRY_SYS_CPUS - cpu_data[cpuid].state = STATE_RUNNING; -#endif return 0; } @@ -574,10 +541,6 @@ void __devinit smp_prepare_boot_cpu(void) { int bootstrap_processor=cpu_data[0].cpuid; /* CPU ID of BSP */ -#ifdef ENTRY_SYS_CPUS - cpu_data[0].state = STATE_RUNNING; -#endif - /* Setup BSP mappings */ printk("SMP: bootstrap CPU ID is %d\n",bootstrap_processor); @@ -616,101 +579,6 @@ int __cpuinit __cpu_up(unsigned int cpu) return cpu_online(cpu) ? 0 : -ENOSYS; } - - -#ifdef ENTRY_SYS_CPUS -/* Code goes along with: -** entry.s: ENTRY_NAME(sys_cpus) / * 215, for cpu stat * / -*/ -int sys_cpus(int argc, char **argv) -{ - int i,j=0; - extern int current_pid(int cpu); - - if( argc > 2 ) { - printk("sys_cpus:Only one argument supported\n"); - return (-1); - } - if ( argc == 1 ){ - -#ifdef DUMP_MORE_STATE - for_each_online_cpu(i) { - int cpus_per_line = 4; - - if (j++ % cpus_per_line) - printk(" %3d",i); - else - printk("\n %3d",i); - } - printk("\n"); -#else - printk("\n 0\n"); -#endif - } else if((argc==2) && !(strcmp(argv[1],"-l"))) { - printk("\nCPUSTATE TASK CPUNUM CPUID HARDCPU(HPA)\n"); -#ifdef DUMP_MORE_STATE - for_each_online_cpu(i) { - if (cpu_data[i].cpuid != NO_PROC_ID) { - switch(cpu_data[i].state) { - case STATE_RENDEZVOUS: - printk("RENDEZVS "); - break; - case STATE_RUNNING: - printk((current_pid(i)!=0) ? "RUNNING " : "IDLING "); - break; - case STATE_STOPPED: - printk("STOPPED "); - break; - case STATE_HALTED: - printk("HALTED "); - break; - default: - printk("%08x?", cpu_data[i].state); - break; - } - if(cpu_online(i)) { - printk(" %4d",current_pid(i)); - } - printk(" %6d",cpu_number_map(i)); - printk(" %5d",i); - printk(" 0x%lx\n",cpu_data[i].hpa); - } - } -#else - printk("\n%s %4d 0 0 --------", - (current->pid)?"RUNNING ": "IDLING ",current->pid); -#endif - } else if ((argc==2) && !(strcmp(argv[1],"-s"))) { -#ifdef DUMP_MORE_STATE - printk("\nCPUSTATE CPUID\n"); - for_each_online_cpu(i) { - if (cpu_data[i].cpuid != NO_PROC_ID) { - switch(cpu_data[i].state) { - case STATE_RENDEZVOUS: - printk("RENDEZVS");break; - case STATE_RUNNING: - printk((current_pid(i)!=0) ? "RUNNING " : "IDLING"); - break; - case STATE_STOPPED: - printk("STOPPED ");break; - case STATE_HALTED: - printk("HALTED ");break; - default: - } - printk(" %5d\n",i); - } - } -#else - printk("\n%s CPU0",(current->pid==0)?"RUNNING ":"IDLING "); -#endif - } else { - printk("sys_cpus:Unknown request\n"); - return (-1); - } - return 0; -} -#endif /* ENTRY_SYS_CPUS */ - #ifdef CONFIG_PROC_FS int __init setup_profiling_timer(unsigned int multiplier) diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index a0580042930..10859f53e94 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -12,27 +12,23 @@ #include <asm/errno.h> #include <asm/psw.h> #include <asm/thread_info.h> - #include <asm/assembly.h> #include <asm/processor.h> +#include <linux/linkage.h> + /* We fill the empty parts of the gateway page with * something that will kill the kernel or a * userspace application. */ #define KILL_INSN break 0,0 -#ifdef CONFIG_64BIT - .level 2.0w -#else - .level 1.1 -#endif + .level LEVEL .text .import syscall_exit,code .import syscall_exit_rfi,code - .export linux_gateway_page /* Linux gateway page is aliased to virtual page 0 in the kernel * address space. Since it is a gateway page it cannot be @@ -43,7 +39,7 @@ */ .align ASM_PAGE_SIZE -linux_gateway_page: +ENTRY(linux_gateway_page) /* ADDRESS 0x00 to 0xb0 = 176 bytes / 4 bytes per insn = 44 insns */ .rept 44 @@ -595,73 +591,43 @@ cas_action: the other for the store. Either return -EFAULT. Each of the entries must be relocated. */ .section __ex_table,"aw" -#ifdef CONFIG_64BIT - /* Pad the address calculation */ - .word 0,(2b - linux_gateway_page) - .word 0,(3b - linux_gateway_page) -#else - .word (2b - linux_gateway_page) - .word (3b - linux_gateway_page) -#endif + ASM_ULONG_INSN (1b - linux_gateway_page), (3b - linux_gateway_page) + ASM_ULONG_INSN (2b - linux_gateway_page), (3b - linux_gateway_page) .previous - .section __ex_table,"aw" -#ifdef CONFIG_64BIT - /* Pad the address calculation */ - .word 0,(1b - linux_gateway_page) - .word 0,(3b - linux_gateway_page) -#else - .word (1b - linux_gateway_page) - .word (3b - linux_gateway_page) -#endif - .previous - -end_compare_and_swap: /* Make sure nothing else is placed on this page */ .align ASM_PAGE_SIZE - .export end_linux_gateway_page -end_linux_gateway_page: +END(linux_gateway_page) +ENTRY(end_linux_gateway_page) /* Relocate symbols assuming linux_gateway_page is mapped to virtual address 0x0 */ -#ifdef CONFIG_64BIT - /* FIXME: The code will always be on the gateay page - and thus it will be on the first 4k, the - assembler seems to think that the final - subtraction result is only a word in - length, so we pad the value. - */ -#define LWS_ENTRY(_name_) .word 0,(lws_##_name_ - linux_gateway_page) -#else -#define LWS_ENTRY(_name_) .word (lws_##_name_ - linux_gateway_page) -#endif + +#define LWS_ENTRY(_name_) ASM_ULONG_INSN (lws_##_name_ - linux_gateway_page) .section .rodata,"a" .align ASM_PAGE_SIZE /* Light-weight-syscall table */ /* Start of lws table. */ - .export lws_table -.Llws_table: -lws_table: +ENTRY(lws_table) LWS_ENTRY(compare_and_swap32) /* 0 - ELF32 Atomic compare and swap */ LWS_ENTRY(compare_and_swap64) /* 1 - ELF64 Atomic compare and swap */ +END(lws_table) /* End of lws table */ .align ASM_PAGE_SIZE - .export sys_call_table -.Lsys_call_table: -sys_call_table: +ENTRY(sys_call_table) #include "syscall_table.S" +END(sys_call_table) #ifdef CONFIG_64BIT .align ASM_PAGE_SIZE - .export sys_call_table64 -.Lsys_call_table64: -sys_call_table64: +ENTRY(sys_call_table64) #define SYSCALL_TABLE_64BIT #include "syscall_table.S" +END(sys_call_table64) #endif #ifdef CONFIG_SMP @@ -671,9 +637,7 @@ sys_call_table64: */ .section .data .align 4096 - .export lws_lock_start -.Llws_lock_start: -lws_lock_start: +ENTRY(lws_lock_start) /* lws locks */ .align 16 .rept 16 @@ -683,6 +647,7 @@ lws_lock_start: .word 0 .word 0 .endr +END(lws_lock_start) .previous #endif /* CONFIG_SMP for lws_lock_start */ diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index be8eb9a0d24..8bf87e5d9c3 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -10,7 +10,7 @@ * Copyright (C) 2000 Grant Grundler <grundler at parisc-linux.org> * Copyright (C) 2001 Richard Hirst <rhirst with parisc-linux.org> * Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org> - * Copyright (C) 2001 Helge Deller <deller at parisc-linux.org> + * Copyright (C) 2001-2007 Helge Deller <deller at parisc-linux.org> * Copyright (C) 2000-2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org> * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org> * Copyright (C) 2005-2006 Kyle McMartin <kyle at parisc-linux.org> @@ -282,8 +282,8 @@ * to worry about faulting trying to copy in a larger 64-bit * struct from a 32-bit user-space app. */ - ENTRY_SAME(rt_sigqueueinfo) - ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */ + ENTRY_COMP(rt_sigqueueinfo) + ENTRY_COMP(rt_sigsuspend) ENTRY_SAME(chown) /* 180 */ /* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */ ENTRY_COMP(setsockopt) @@ -377,9 +377,9 @@ ENTRY_SAME(inotify_init) ENTRY_SAME(inotify_add_watch) /* 270 */ ENTRY_SAME(inotify_rm_watch) - ENTRY_SAME(ni_syscall) /* 271 ENTRY_COMP(pselect6) */ - ENTRY_SAME(ni_syscall) /* 272 ENTRY_COMP(ppoll) */ ENTRY_SAME(migrate_pages) + ENTRY_COMP(pselect6) + ENTRY_COMP(ppoll) ENTRY_COMP(openat) /* 275 */ ENTRY_SAME(mkdirat) ENTRY_SAME(mknodat) @@ -399,5 +399,11 @@ ENTRY_SAME(splice) ENTRY_OURS(sync_file_range) ENTRY_SAME(tee) + ENTRY_COMP(vmsplice) + ENTRY_COMP(move_pages) /* 295 */ + ENTRY_SAME(getcpu) + ENTRY_SAME(epoll_pwait) + ENTRY_COMP(statfs64) + ENTRY_COMP(fstatfs64) /* Nothing yet */ diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 5f1b51af06a..d1db8e51865 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -22,6 +22,7 @@ #include <linux/init.h> #include <linux/smp.h> #include <linux/profile.h> +#include <linux/clocksource.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -98,7 +99,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) * cycles after the IT fires. But it's arbitrary how much time passes * before we call it "late". I've picked one second. */ - if (ticks_elapsed > HZ) { + if (unlikely(ticks_elapsed > HZ)) { /* Scenario 3: very long delay? bad in any case */ printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!" " cycles %lX rem %lX " @@ -147,10 +148,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) write_sequnlock(&xtime_lock); } - /* check soft power switch status */ - if (cpu == 0 && !atomic_read(&power_tasklet.count)) - tasklet_schedule(&power_tasklet); - return IRQ_HANDLED; } @@ -172,121 +169,41 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); -/* - * Return the number of micro-seconds that elapsed since the last - * update to wall time (aka xtime). The xtime_lock - * must be at least read-locked when calling this routine. - */ -static inline unsigned long gettimeoffset (void) -{ -#ifndef CONFIG_SMP - /* - * FIXME: This won't work on smp because jiffies are updated by cpu 0. - * Once parisc-linux learns the cr16 difference between processors, - * this could be made to work. - */ - unsigned long now; - unsigned long prev_tick; - unsigned long next_tick; - unsigned long elapsed_cycles; - unsigned long usec; - unsigned long cpuid = smp_processor_id(); - unsigned long cpt = clocktick; - - next_tick = cpu_data[cpuid].it_value; - now = mfctl(16); /* Read the hardware interval timer. */ +/* clock source code */ - prev_tick = next_tick - cpt; +static cycle_t read_cr16(void) +{ + return get_cycles(); +} - /* Assume Scenario 1: "now" is later than prev_tick. */ - elapsed_cycles = now - prev_tick; +static int cr16_update_callback(void); -/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ -#if HZ == 1000 - if (elapsed_cycles > (cpt << 10) ) -#elif HZ == 250 - if (elapsed_cycles > (cpt << 8) ) -#elif HZ == 100 - if (elapsed_cycles > (cpt << 7) ) -#else -#warn WTF is HZ set to anyway? - if (elapsed_cycles > (HZ * cpt) ) -#endif - { - /* Scenario 3: clock ticks are missing. */ - printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!" - " cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n", - cpuid, elapsed_cycles / cpt, - elapsed_cycles, prev_tick, now, next_tick, cpt); - } +static struct clocksource clocksource_cr16 = { + .name = "cr16", + .rating = 300, + .read = read_cr16, + .mask = CLOCKSOURCE_MASK(BITS_PER_LONG), + .mult = 0, /* to be set */ + .shift = 22, + .update_callback = cr16_update_callback, + .is_continuous = 1, +}; - /* FIXME: Can we improve the precision? Not with PAGE0. */ - usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec; - return usec; -#else - return 0; -#endif -} - -void -do_gettimeofday (struct timeval *tv) +static int cr16_update_callback(void) { - unsigned long flags, seq, usec, sec; - - /* Hold xtime_lock and adjust timeval. */ - do { - seq = read_seqbegin_irqsave(&xtime_lock, flags); - usec = gettimeoffset(); - sec = xtime.tv_sec; - usec += (xtime.tv_nsec / 1000); - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - - /* Move adjusted usec's into sec's. */ - while (usec >= USEC_PER_SEC) { - usec -= USEC_PER_SEC; - ++sec; + int change = 0; + + /* since the cr16 cycle counters are not syncronized across CPUs, + we'll check if we should switch to a safe clocksource: */ + if (clocksource_cr16.rating != 0 && num_online_cpus() > 1) { + clocksource_cr16.rating = 0; + clocksource_reselect(); + change = 1; } - /* Return adjusted result. */ - tv->tv_sec = sec; - tv->tv_usec = usec; + return change; } -EXPORT_SYMBOL(do_gettimeofday); - -int -do_settimeofday (struct timespec *tv) -{ - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec, nsec = tv->tv_nsec; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irq(&xtime_lock); - { - /* - * This is revolting. We need to set "xtime" - * correctly. However, the value in this location is - * the value at the most recent update of wall time. - * Discover what correction gettimeofday would have - * done, and then undo it! - */ - nsec -= gettimeoffset() * 1000; - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - ntp_clear(); - } - write_sequnlock_irq(&xtime_lock); - clock_was_set(); - return 0; -} -EXPORT_SYMBOL(do_settimeofday); void __init start_cpu_itimer(void) { @@ -301,11 +218,18 @@ void __init start_cpu_itimer(void) void __init time_init(void) { static struct pdc_tod tod_data; + unsigned long current_cr16_khz; clocktick = (100 * PAGE0->mem_10msec) / HZ; start_cpu_itimer(); /* get CPU 0 started */ + /* register at clocksource framework */ + current_cr16_khz = PAGE0->mem_10msec/10; /* kHz */ + clocksource_cr16.mult = clocksource_khz2mult(current_cr16_khz, + clocksource_cr16.shift); + clocksource_register(&clocksource_cr16); + if (pdc_tod_read(&tod_data) == 0) { unsigned long flags; diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 65cd6ca32fe..55bc1471967 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -26,6 +26,7 @@ #include <linux/interrupt.h> #include <linux/console.h> #include <linux/kallsyms.h> +#include <linux/bug.h> #include <asm/assembly.h> #include <asm/system.h> @@ -39,6 +40,8 @@ #include <asm/pdc.h> #include <asm/pdc_chassis.h> #include <asm/unwind.h> +#include <asm/tlbflush.h> +#include <asm/cacheflush.h> #include "../math-emu/math-emu.h" /* for handle_fpe() */ @@ -49,7 +52,7 @@ DEFINE_SPINLOCK(pa_dbit_lock); #endif -int printbinary(char *buf, unsigned long x, int nbits) +static int printbinary(char *buf, unsigned long x, int nbits) { unsigned long mask = 1UL << (nbits - 1); while (mask != 0) { @@ -61,7 +64,7 @@ int printbinary(char *buf, unsigned long x, int nbits) return nbits; } -#ifdef __LP64__ +#ifdef CONFIG_64BIT #define RFMT "%016lx" #else #define RFMT "%08lx" @@ -160,13 +163,13 @@ static void do_show_stack(struct unwind_frame_info *info) { int i = 1; - printk("Backtrace:\n"); + printk(KERN_CRIT "Backtrace:\n"); while (i <= 16) { if (unwind_once(info) < 0 || info->ip == 0) break; if (__kernel_text_address(info->ip)) { - printk(" [<" RFMT ">] ", info->ip); + printk("%s [<" RFMT ">] ", (i&0x3)==1 ? KERN_CRIT : "", info->ip); #ifdef CONFIG_KALLSYMS print_symbol("%s\n", info->ip); #else @@ -185,18 +188,19 @@ void show_stack(struct task_struct *task, unsigned long *s) if (!task) { unsigned long sp; - struct pt_regs *r; HERE: asm volatile ("copy %%r30, %0" : "=r"(sp)); - r = kzalloc(sizeof(struct pt_regs), GFP_KERNEL); - if (!r) - return; - r->iaoq[0] = (unsigned long)&&HERE; - r->gr[2] = (unsigned long)__builtin_return_address(0); - r->gr[30] = sp; - unwind_frame_init(&info, current, r); - kfree(r); + { + struct pt_regs r; + + memset(&r, 0, sizeof(struct pt_regs)); + r.iaoq[0] = (unsigned long)&&HERE; + r.gr[2] = (unsigned long)__builtin_return_address(0); + r.gr[30] = sp; + + unwind_frame_init(&info, current, &r); + } } else { unwind_frame_init_from_blocked_task(&info, task); } @@ -204,6 +208,11 @@ HERE: do_show_stack(&info); } +int is_valid_bugaddr(unsigned long iaoq) +{ + return 1; +} + void die_if_kernel(char *str, struct pt_regs *regs, long err) { if (user_mode(regs)) { @@ -222,15 +231,15 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) oops_in_progress = 1; /* Amuse the user in a SPARC fashion */ - printk( -" _______________________________ \n" -" < Your System ate a SPARC! Gah! >\n" -" ------------------------------- \n" -" \\ ^__^\n" -" \\ (xx)\\_______\n" -" (__)\\ )\\/\\\n" -" U ||----w |\n" -" || ||\n"); + if (err) printk( +KERN_CRIT " _______________________________ \n" +KERN_CRIT " < Your System ate a SPARC! Gah! >\n" +KERN_CRIT " ------------------------------- \n" +KERN_CRIT " \\ ^__^\n" +KERN_CRIT " \\ (xx)\\_______\n" +KERN_CRIT " (__)\\ )\\/\\\n" +KERN_CRIT " U ||----w |\n" +KERN_CRIT " || ||\n"); /* unlock the pdc lock if necessary */ pdc_emergency_unlock(); @@ -242,9 +251,20 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) if (!console_drivers) pdc_console_restart(); - printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n", - current->comm, current->pid, str, err); + if (err) + printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n", + current->comm, current->pid, str, err); + + /* Wot's wrong wif bein' racy? */ + if (current->thread.flags & PARISC_KERNEL_DEATH) { + printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__); + local_irq_enable(); + while (1); + } + current->thread.flags |= PARISC_KERNEL_DEATH; + show_regs(regs); + dump_stack(); if (in_interrupt()) panic("Fatal exception in interrupt"); @@ -255,14 +275,6 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) panic("Fatal exception"); } - /* Wot's wrong wif bein' racy? */ - if (current->thread.flags & PARISC_KERNEL_DEATH) { - printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__); - local_irq_enable(); - while (1); - } - - current->thread.flags |= PARISC_KERNEL_DEATH; do_exit(SIGSEGV); } @@ -273,61 +285,45 @@ int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs) /* gdb uses break 4,8 */ #define GDB_BREAK_INSN 0x10004 -void handle_gdb_break(struct pt_regs *regs, int wot) +static void handle_gdb_break(struct pt_regs *regs, int wot) { struct siginfo si; - si.si_code = wot; - si.si_addr = (void __user *) (regs->iaoq[0] & ~3); si.si_signo = SIGTRAP; si.si_errno = 0; + si.si_code = wot; + si.si_addr = (void __user *) (regs->iaoq[0] & ~3); force_sig_info(SIGTRAP, &si, current); } -void handle_break(unsigned iir, struct pt_regs *regs) +static void handle_break(struct pt_regs *regs) { - struct siginfo si; - - switch(iir) { - case 0x00: -#ifdef PRINT_USER_FAULTS - printk(KERN_DEBUG "break 0,0: pid=%d command='%s'\n", - current->pid, current->comm); -#endif - die_if_kernel("Breakpoint", regs, 0); -#ifdef PRINT_USER_FAULTS - show_regs(regs); -#endif - si.si_code = TRAP_BRKPT; - si.si_addr = (void __user *) (regs->iaoq[0] & ~3); - si.si_signo = SIGTRAP; - force_sig_info(SIGTRAP, &si, current); - break; - - case GDB_BREAK_INSN: - die_if_kernel("Breakpoint", regs, 0); - handle_gdb_break(regs, TRAP_BRKPT); - break; + unsigned iir = regs->iir; + + if (unlikely(iir == PARISC_BUG_BREAK_INSN && !user_mode(regs))) { + /* check if a BUG() or WARN() trapped here. */ + enum bug_trap_type tt; + tt = report_bug(regs->iaoq[0] & ~3); + if (tt == BUG_TRAP_TYPE_WARN) { + regs->iaoq[0] += 4; + regs->iaoq[1] += 4; + return; /* return to next instruction when WARN_ON(). */ + } + die_if_kernel("Unknown kernel breakpoint", regs, + (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0); + } - default: #ifdef PRINT_USER_FAULTS - printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n", - iir, current->pid, current->comm); + if (unlikely(iir != GDB_BREAK_INSN)) { + printk(KERN_DEBUG "break %d,%d: pid=%d command='%s'\n", + iir & 31, (iir>>13) & ((1<<13)-1), + current->pid, current->comm); show_regs(regs); -#endif - si.si_signo = SIGTRAP; - si.si_code = TRAP_BRKPT; - si.si_addr = (void __user *) (regs->iaoq[0] & ~3); - force_sig_info(SIGTRAP, &si, current); - return; } -} - +#endif -int handle_toc(void) -{ - printk(KERN_CRIT "TOC call.\n"); - return 0; + /* send standard GDB signal */ + handle_gdb_break(regs, TRAP_BRKPT); } static void default_trap(int code, struct pt_regs *regs) @@ -336,7 +332,7 @@ static void default_trap(int code, struct pt_regs *regs) show_regs(regs); } -void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap; +void (*cpu_lpmc) (int code, struct pt_regs *regs) __read_mostly = default_trap; void transfer_pim_to_trap_frame(struct pt_regs *regs) @@ -554,7 +550,8 @@ void handle_interruption(int code, struct pt_regs *regs) /* Low-priority machine check */ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC); - flush_all_caches(); + flush_cache_all(); + flush_tlb_all(); cpu_lpmc(5, regs); return; @@ -572,7 +569,7 @@ void handle_interruption(int code, struct pt_regs *regs) case 9: /* Break instruction trap */ - handle_break(regs->iir,regs); + handle_break(regs); return; case 10: @@ -840,7 +837,7 @@ int __init check_ivt(void *iva) return 0; } -#ifndef __LP64__ +#ifndef CONFIG_64BIT extern const void fault_vector_11; #endif extern const void fault_vector_20; @@ -852,7 +849,7 @@ void __init trap_init(void) if (boot_cpu_data.cpu_type >= pcxu) iva = (void *) &fault_vector_20; else -#ifdef __LP64__ +#ifdef CONFIG_64BIT panic("Can't boot 64-bit OS on PA1.1 processor!"); #else iva = (void *) &fault_vector_11; diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index bd2230d6a2a..347bb922e6d 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -20,8 +20,11 @@ * */ +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/sched.h> +#include <linux/signal.h> #include <asm/uaccess.h> /* #define DEBUG_UNALIGNED 1 */ @@ -32,7 +35,7 @@ #define DPRINTF(fmt, args...) #endif -#ifdef __LP64__ +#ifdef CONFIG_64BIT #define RFMT "%016lx" #else #define RFMT "%08lx" @@ -147,15 +150,8 @@ static int emulate_ldh(struct pt_regs *regs, int toreg) "4: ldi -2, %1\n" FIXUP_BRANCH(3b) " .previous\n" -" .section __ex_table,\"aw\"\n" -#ifdef __LP64__ -" .dword 1b,4b\n" -" .dword 2b,4b\n" -#else -" .word 1b,4b\n" -" .word 2b,4b\n" -#endif -" .previous\n" + ASM_EXCEPTIONTABLE_ENTRY(1b, 4b) + ASM_EXCEPTIONTABLE_ENTRY(2b, 4b) : "=r" (val), "=r" (ret) : "0" (val), "r" (saddr), "r" (regs->isr) : "r20", FIXUP_BRANCH_CLOBBER ); @@ -192,15 +188,8 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop) "4: ldi -2, %1\n" FIXUP_BRANCH(3b) " .previous\n" -" .section __ex_table,\"aw\"\n" -#ifdef __LP64__ -" .dword 1b,4b\n" -" .dword 2b,4b\n" -#else -" .word 1b,4b\n" -" .word 2b,4b\n" -#endif -" .previous\n" + ASM_EXCEPTIONTABLE_ENTRY(1b, 4b) + ASM_EXCEPTIONTABLE_ENTRY(2b, 4b) : "=r" (val), "=r" (ret) : "0" (val), "r" (saddr), "r" (regs->isr) : "r19", "r20", FIXUP_BRANCH_CLOBBER ); @@ -224,7 +213,7 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) regs->isr, regs->ior, toreg); #ifdef CONFIG_PA20 -#ifndef __LP64__ +#ifndef CONFIG_64BIT if (!flop) return -1; #endif @@ -243,15 +232,8 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) "4: ldi -2, %1\n" FIXUP_BRANCH(3b) " .previous\n" -" .section __ex_table,\"aw\"\n" -#ifdef __LP64__ -" .dword 1b,4b\n" -" .dword 2b,4b\n" -#else -" .word 1b,4b\n" -" .word 2b,4b\n" -#endif -" .previous\n" + ASM_EXCEPTIONTABLE_ENTRY(1b,4b) + ASM_EXCEPTIONTABLE_ENTRY(2b,4b) : "=r" (val), "=r" (ret) : "0" (val), "r" (saddr), "r" (regs->isr) : "r19", "r20", FIXUP_BRANCH_CLOBBER ); @@ -275,17 +257,9 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) "5: ldi -2, %2\n" FIXUP_BRANCH(4b) " .previous\n" -" .section __ex_table,\"aw\"\n" -#ifdef __LP64__ -" .dword 1b,5b\n" -" .dword 2b,5b\n" -" .dword 3b,5b\n" -#else -" .word 1b,5b\n" -" .word 2b,5b\n" -" .word 3b,5b\n" -#endif -" .previous\n" + ASM_EXCEPTIONTABLE_ENTRY(1b,5b) + ASM_EXCEPTIONTABLE_ENTRY(2b,5b) + ASM_EXCEPTIONTABLE_ENTRY(3b,5b) : "=r" (valh), "=r" (vall), "=r" (ret) : "0" (valh), "1" (vall), "r" (saddr), "r" (regs->isr) : "r19", "r20", FIXUP_BRANCH_CLOBBER ); @@ -325,15 +299,8 @@ static int emulate_sth(struct pt_regs *regs, int frreg) "4: ldi -2, %0\n" FIXUP_BRANCH(3b) " .previous\n" -" .section __ex_table,\"aw\"\n" -#ifdef __LP64__ -" .dword 1b,4b\n" -" .dword 2b,4b\n" -#else -" .word 1b,4b\n" -" .word 2b,4b\n" -#endif -" .previous\n" + ASM_EXCEPTIONTABLE_ENTRY(1b,4b) + ASM_EXCEPTIONTABLE_ENTRY(2b,4b) : "=r" (ret) : "r" (val), "r" (regs->ior), "r" (regs->isr) : "r19", FIXUP_BRANCH_CLOBBER ); @@ -379,15 +346,8 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop) "4: ldi -2, %0\n" FIXUP_BRANCH(3b) " .previous\n" -" .section __ex_table,\"aw\"\n" -#ifdef __LP64__ -" .dword 1b,4b\n" -" .dword 2b,4b\n" -#else -" .word 1b,4b\n" -" .word 2b,4b\n" -#endif -" .previous\n" + ASM_EXCEPTIONTABLE_ENTRY(1b,4b) + ASM_EXCEPTIONTABLE_ENTRY(2b,4b) : "=r" (ret) : "r" (val), "r" (regs->ior), "r" (regs->isr) : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER ); @@ -410,7 +370,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) val, regs->isr, regs->ior); #ifdef CONFIG_PA20 -#ifndef __LP64__ +#ifndef CONFIG_64BIT if (!flop) return -1; #endif @@ -436,19 +396,10 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) "6: ldi -2, %0\n" FIXUP_BRANCH(5b) " .previous\n" -" .section __ex_table,\"aw\"\n" -#ifdef __LP64__ -" .dword 1b,6b\n" -" .dword 2b,6b\n" -" .dword 3b,6b\n" -" .dword 4b,6b\n" -#else -" .word 1b,6b\n" -" .word 2b,6b\n" -" .word 3b,6b\n" -" .word 4b,6b\n" -#endif -" .previous\n" + ASM_EXCEPTIONTABLE_ENTRY(1b,6b) + ASM_EXCEPTIONTABLE_ENTRY(2b,6b) + ASM_EXCEPTIONTABLE_ENTRY(3b,6b) + ASM_EXCEPTIONTABLE_ENTRY(4b,6b) : "=r" (ret) : "r" (val), "r" (regs->ior), "r" (regs->isr) : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER ); @@ -479,21 +430,11 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) "7: ldi -2, %0\n" FIXUP_BRANCH(6b) " .previous\n" -" .section __ex_table,\"aw\"\n" -#ifdef __LP64__ -" .dword 1b,7b\n" -" .dword 2b,7b\n" -" .dword 3b,7b\n" -" .dword 4b,7b\n" -" .dword 5b,7b\n" -#else -" .word 1b,7b\n" -" .word 2b,7b\n" -" .word 3b,7b\n" -" .word 4b,7b\n" -" .word 5b,7b\n" -#endif -" .previous\n" + ASM_EXCEPTIONTABLE_ENTRY(1b,7b) + ASM_EXCEPTIONTABLE_ENTRY(2b,7b) + ASM_EXCEPTIONTABLE_ENTRY(3b,7b) + ASM_EXCEPTIONTABLE_ENTRY(4b,7b) + ASM_EXCEPTIONTABLE_ENTRY(5b,7b) : "=r" (ret) : "r" (valh), "r" (vall), "r" (regs->ior), "r" (regs->isr) : "r19", "r20", "r21", "r1", FIXUP_BRANCH_CLOBBER ); diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c index c10ab47d81f..5f75b3e6598 100644 --- a/arch/parisc/kernel/unwind.c +++ b/arch/parisc/kernel/unwind.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/init.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/kallsyms.h> diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 3b78c2794c3..2a8253358c6 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -68,6 +68,8 @@ SECTIONS RODATA + BUG_TABLE + /* writeable */ . = ALIGN(ASM_PAGE_SIZE); /* Make sure this is page aligned so that we can properly leave these |