diff options
Diffstat (limited to 'arch/parisc')
51 files changed, 1148 insertions, 837 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index b77feffbadea..cad060f288cf 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -1,28 +1,32 @@ config PARISC def_bool y + select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS select HAVE_IDE select HAVE_OPROFILE select HAVE_FUNCTION_TRACER if 64BIT select HAVE_FUNCTION_GRAPH_TRACER if 64BIT select HAVE_FUNCTION_TRACE_MCOUNT_TEST if 64BIT + select ARCH_WANT_FRAME_POINTERS select RTC_CLASS select RTC_DRV_GENERIC select INIT_ALL_POSSIBLE select BUG - select HAVE_IRQ_WORK select HAVE_PERF_EVENTS select GENERIC_ATOMIC64 if !64BIT + select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select HAVE_GENERIC_HARDIRQS select BROKEN_RODATA select GENERIC_IRQ_PROBE select GENERIC_PCI_IOMAP - select IRQ_PER_CPU select ARCH_HAVE_NMI_SAFE_CMPXCHG select GENERIC_SMP_IDLE_THREAD select GENERIC_STRNCPY_FROM_USER + select SYSCTL_ARCH_UNALIGN_ALLOW select HAVE_MOD_ARCH_SPECIFIC + select VIRT_TO_BUS select MODULES_USE_ELF_RELA select CLONE_BACKWARDS + select TTY # Needed for pdc_cons.c help The PA-RISC microprocessor is designed by Hewlett-Packard and used @@ -161,6 +165,23 @@ config PREFETCH def_bool y depends on PA8X00 || PA7200 +config MLONGCALLS + bool "Enable the -mlong-calls compiler option for big kernels" + def_bool y if (!MODULES) + depends on PA8X00 + help + If you configure the kernel to include many drivers built-in instead + as modules, the kernel executable may become too big, so that the + linker will not be able to resolve some long branches and fails to link + your vmlinux kernel. In that case enabling this option will help you + to overcome this limit by using the -mlong-calls compiler option. + + Usually you want to say N here, unless you e.g. want to build + a kernel which includes all necessary drivers built-in and which can + be used for TFTP booting without the need to have an initrd ramdisk. + + Enabling this option will probably slow down your kernel. + config 64BIT bool "64-bit kernel" depends on PA8X00 @@ -194,12 +215,12 @@ config PARISC_PAGE_SIZE_4KB If you don't know what to do, choose 4KB. config PARISC_PAGE_SIZE_16KB - bool "16KB (EXPERIMENTAL)" - depends on PA8X00 && EXPERIMENTAL + bool "16KB" + depends on PA8X00 config PARISC_PAGE_SIZE_64KB - bool "64KB (EXPERIMENTAL)" - depends on PA8X00 && EXPERIMENTAL + bool "64KB" + depends on PA8X00 endchoice @@ -222,6 +243,14 @@ config SMP If you don't know what to do here, say N. +config IRQSTACKS + bool "Use separate kernel stacks when processing interrupts" + default n + help + If you say Y here the kernel will use separate kernel stacks + for handling hard and soft interrupts. This can help avoid + overflowing the process kernel stacks. + config HOTPLUG_CPU bool default y if SMP @@ -255,6 +284,10 @@ config COMPAT def_bool y depends on 64BIT +config SYSVIPC_COMPAT + def_bool y + depends on COMPAT && SYSVIPC + config HPUX bool "Support for HP-UX binaries" depends on !64BIT diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug index 7305ac8f7f5b..08a332f6ee87 100644 --- a/arch/parisc/Kconfig.debug +++ b/arch/parisc/Kconfig.debug @@ -12,18 +12,15 @@ config DEBUG_RODATA portion of the kernel code won't be covered by a TLB anymore. If in doubt, say "N". -config DEBUG_STRICT_USER_COPY_CHECKS - bool "Strict copy size checks" - depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING - ---help--- - Enabling this option turns a certain set of sanity checks for user - copy operations into compile time failures. - - The copy_from_user() etc checks are there to help test if there - are sufficient security checks on the length argument of - the copy operation, by having gcc prove that the argument is - within bounds. - - If unsure, or if you run an older (pre 4.4) gcc, say N. - endmenu + +config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + default y + depends on DEBUG_KERNEL + ---help--- + Say Y here if you want to check the overflows of kernel, IRQ + and exception stacks. This option will cause messages of the + stacks in detail when free stack space drops below a certain + limit. + If in doubt, say "N". diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile index 5707f1a62341..2f967cc6649e 100644 --- a/arch/parisc/Makefile +++ b/arch/parisc/Makefile @@ -24,19 +24,12 @@ CHECKFLAGS += -D__hppa__=1 LIBGCC = $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) MACHINE := $(shell uname -m) -ifeq ($(MACHINE),parisc*) -NATIVE := 1 -endif +NATIVE := $(if $(filter parisc%,$(MACHINE)),1,0) ifdef CONFIG_64BIT UTS_MACHINE := parisc64 CHECKFLAGS += -D__LP64__=1 -m64 WIDTH := 64 - -# FIXME: if no default set, should really try to locate dynamically -ifeq ($(CROSS_COMPILE),) -CROSS_COMPILE := hppa64-linux-gnu- -endif else # 32-bit WIDTH := endif @@ -44,6 +37,10 @@ endif # attempt to help out folks who are cross-compiling ifeq ($(NATIVE),1) CROSS_COMPILE := hppa$(WIDTH)-linux- +else + ifeq ($(CROSS_COMPILE),) + CROSS_COMPILE := hppa$(WIDTH)-linux-gnu- + endif endif OBJCOPY_FLAGS =-O binary -R .note -R .comment -S @@ -65,6 +62,12 @@ ifndef CONFIG_FUNCTION_TRACER cflags-y += -ffunction-sections endif +# Use long jumps instead of long branches (needed if your linker fails to +# link a too big vmlinux executable). Not enabled for building modules. +ifdef CONFIG_MLONGCALLS +KBUILD_CFLAGS_KERNEL += -mlong-calls +endif + # select which processor to optimise for cflags-$(CONFIG_PA7100) += -march=1.1 -mschedule=7100 cflags-$(CONFIG_PA7200) += -march=1.1 -mschedule=7200 @@ -110,12 +113,10 @@ palo: vmlinux # Shorthands for known targets not supported by parisc, use vmlinux as default Image zImage bzImage: vmlinux -kernel_install: vmlinux +install: vmlinux sh $(src)/arch/parisc/install.sh \ $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)" -install: kernel_install modules_install - CLEAN_FILES += lifimage MRPROPER_FILES += palo.conf diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index a0760b87fd4e..838b479a42c4 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -43,8 +43,7 @@ int hpux_execve(struct pt_regs *regs) error = do_execve(filename->name, (const char __user *const __user *) regs->gr[25], - (const char __user *const __user *) regs->gr[24], - regs); + (const char __user *const __user *) regs->gr[24]); putname(filename); diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index af9cf30ed474..472886ceab1d 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -115,8 +115,8 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) } -#define atomic_add(i,v) ((void)(__atomic_add_return( (i),(v)))) -#define atomic_sub(i,v) ((void)(__atomic_add_return(-(i),(v)))) +#define atomic_add(i,v) ((void)(__atomic_add_return( (i),(v)))) +#define atomic_sub(i,v) ((void)(__atomic_add_return(-((int) (i)),(v)))) #define atomic_inc(v) ((void)(__atomic_add_return( 1,(v)))) #define atomic_dec(v) ((void)(__atomic_add_return( -1,(v)))) @@ -229,6 +229,29 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) +/* + * atomic64_dec_if_positive - decrement by 1 if old value positive + * @v: pointer of type atomic_t + * + * The function returns the old value of *v minus 1, even if + * the atomic variable, v, was not decremented. + */ +static inline long atomic64_dec_if_positive(atomic64_t *v) +{ + long c, old, dec; + c = atomic64_read(v); + for (;;) { + dec = c - 1; + if (unlikely(dec < 0)) + break; + old = atomic64_cmpxchg((v), c, dec); + if (likely(old == c)) + break; + c = old; + } + return dec; +} + #endif /* !CONFIG_64BIT */ diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index 9f21ab0c02e3..f0e2784e7cca 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -115,7 +115,9 @@ flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vma { if (PageAnon(page)) { flush_tlb_page(vma, vmaddr); + preempt_disable(); flush_dcache_page_asm(page_to_phys(page), vmaddr); + preempt_enable(); } } @@ -138,7 +140,10 @@ static inline void *kmap(struct page *page) return page_address(page); } -#define kunmap(page) kunmap_parisc(page_address(page)) +static inline void kunmap(struct page *page) +{ + kunmap_parisc(page_address(page)); +} static inline void *kmap_atomic(struct page *page) { diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h index db7a662691a8..94710cfc1ce8 100644 --- a/arch/parisc/include/asm/compat.h +++ b/arch/parisc/include/asm/compat.h @@ -28,6 +28,7 @@ typedef u16 compat_nlink_t; typedef u16 compat_ipc_pid_t; typedef s32 compat_daddr_t; typedef u32 compat_caddr_t; +typedef s32 compat_key_t; typedef s32 compat_timer_t; typedef s32 compat_int_t; @@ -188,6 +189,66 @@ typedef struct compat_siginfo { #define COMPAT_OFF_T_MAX 0x7fffffff #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL +struct compat_ipc64_perm { + compat_key_t key; + __compat_uid_t uid; + __compat_gid_t gid; + __compat_uid_t cuid; + __compat_gid_t cgid; + unsigned short int __pad1; + compat_mode_t mode; + unsigned short int __pad2; + unsigned short int seq; + unsigned int __pad3; + unsigned long __unused1; /* yes they really are 64bit pads */ + unsigned long __unused2; +}; + +struct compat_semid64_ds { + struct compat_ipc64_perm sem_perm; + compat_time_t sem_otime; + unsigned int __unused1; + compat_time_t sem_ctime; + unsigned int __unused2; + compat_ulong_t sem_nsems; + compat_ulong_t __unused3; + compat_ulong_t __unused4; +}; + +struct compat_msqid64_ds { + struct compat_ipc64_perm msg_perm; + unsigned int __unused1; + compat_time_t msg_stime; + unsigned int __unused2; + compat_time_t msg_rtime; + unsigned int __unused3; + compat_time_t msg_ctime; + compat_ulong_t msg_cbytes; + compat_ulong_t msg_qnum; + compat_ulong_t msg_qbytes; + compat_pid_t msg_lspid; + compat_pid_t msg_lrpid; + compat_ulong_t __unused4; + compat_ulong_t __unused5; +}; + +struct compat_shmid64_ds { + struct compat_ipc64_perm shm_perm; + unsigned int __unused1; + compat_time_t shm_atime; + unsigned int __unused2; + compat_time_t shm_dtime; + unsigned int __unused3; + compat_time_t shm_ctime; + unsigned int __unused4; + compat_size_t shm_segsz; + compat_pid_t shm_cpid; + compat_pid_t shm_lpid; + compat_ulong_t shm_nattch; + compat_ulong_t __unused5; + compat_ulong_t __unused6; +}; + /* * A pointer passed in from user mode. This should not * be used for syscall parameters, just declare them diff --git a/arch/parisc/include/asm/compat_rt_sigframe.h b/arch/parisc/include/asm/compat_rt_sigframe.h deleted file mode 100644 index b3f95a7f18b4..000000000000 --- a/arch/parisc/include/asm/compat_rt_sigframe.h +++ /dev/null @@ -1,50 +0,0 @@ -#include <linux/compat.h> -#include <linux/compat_siginfo.h> -#include <asm/compat_ucontext.h> - -#ifndef _ASM_PARISC_COMPAT_RT_SIGFRAME_H -#define _ASM_PARISC_COMPAT_RT_SIGFRAME_H - -/* In a deft move of uber-hackery, we decide to carry the top half of all - * 64-bit registers in a non-portable, non-ABI, hidden structure. - * Userspace can read the hidden structure if it *wants* but is never - * guaranteed to be in the same place. Infact the uc_sigmask from the - * ucontext_t structure may push the hidden register file downards - */ -struct compat_regfile { - /* Upper half of all the 64-bit registers that were truncated - on a copy to a 32-bit userspace */ - compat_int_t rf_gr[32]; - compat_int_t rf_iasq[2]; - compat_int_t rf_iaoq[2]; - compat_int_t rf_sar; -}; - -#define COMPAT_SIGRETURN_TRAMP 4 -#define COMPAT_SIGRESTARTBLOCK_TRAMP 5 -#define COMPAT_TRAMP_SIZE (COMPAT_SIGRETURN_TRAMP + COMPAT_SIGRESTARTBLOCK_TRAMP) - -struct compat_rt_sigframe { - /* XXX: Must match trampoline size in arch/parisc/kernel/signal.c - Secondary to that it must protect the ERESTART_RESTARTBLOCK - trampoline we left on the stack (we were bad and didn't - change sp so we could run really fast.) */ - compat_uint_t tramp[COMPAT_TRAMP_SIZE]; - compat_siginfo_t info; - struct compat_ucontext uc; - /* Hidden location of truncated registers, *must* be last. */ - struct compat_regfile regs; -}; - -/* - * The 32-bit ABI wants at least 48 bytes for a function call frame: - * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of - * which Linux/parisc uses is sp-20 for the saved return pointer...) - * Then, the stack pointer must be rounded to a cache line (64 bytes). - */ -#define SIGFRAME32 64 -#define FUNCTIONCALLFRAME32 48 -#define PARISC_RT_SIGFRAME_SIZE32 \ - (((sizeof(struct compat_rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32) - -#endif diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h index 106b395688e1..d0eae5f2bd87 100644 --- a/arch/parisc/include/asm/dma-mapping.h +++ b/arch/parisc/include/asm/dma-mapping.h @@ -46,6 +46,9 @@ extern struct hppa_dma_ops pcx_dma_ops; extern struct hppa_dma_ops *hppa_dma_ops; +#define dma_alloc_attrs(d, s, h, f, a) dma_alloc_coherent(d, s, h, f) +#define dma_free_attrs(d, s, h, f, a) dma_free_coherent(d, s, h, f) + static inline void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h index 19f6cb1a4a1c..ad2b50397894 100644 --- a/arch/parisc/include/asm/elf.h +++ b/arch/parisc/include/asm/elf.h @@ -247,7 +247,7 @@ typedef unsigned long elf_greg_t; #define ELF_PLATFORM ("PARISC\0") #define SET_PERSONALITY(ex) \ - current->personality = PER_LINUX; \ + set_personality((current->personality & ~PER_MASK) | PER_LINUX); \ current->thread.map_base = DEFAULT_MAP_BASE; \ current->thread.task_size = DEFAULT_TASK_SIZE \ diff --git a/arch/parisc/include/asm/floppy.h b/arch/parisc/include/asm/floppy.h index 4ca69f558fae..f84ff12574b7 100644 --- a/arch/parisc/include/asm/floppy.h +++ b/arch/parisc/include/asm/floppy.h @@ -157,10 +157,10 @@ static int fd_request_irq(void) { if(can_use_virtual_dma) return request_irq(FLOPPY_IRQ, floppy_hardint, - IRQF_DISABLED, "floppy", NULL); + 0, "floppy", NULL); else return request_irq(FLOPPY_IRQ, floppy_interrupt, - IRQF_DISABLED, "floppy", NULL); + 0, "floppy", NULL); } static unsigned long dma_mem_alloc(unsigned long size) diff --git a/arch/parisc/include/asm/hardirq.h b/arch/parisc/include/asm/hardirq.h index 0d68184a76cb..12373c4dabab 100644 --- a/arch/parisc/include/asm/hardirq.h +++ b/arch/parisc/include/asm/hardirq.h @@ -1,11 +1,41 @@ /* hardirq.h: PA-RISC hard IRQ support. * * Copyright (C) 2001 Matthew Wilcox <matthew@wil.cx> + * Copyright (C) 2013 Helge Deller <deller@gmx.de> */ #ifndef _PARISC_HARDIRQ_H #define _PARISC_HARDIRQ_H -#include <asm-generic/hardirq.h> +#include <linux/cache.h> +#include <linux/threads.h> +#include <linux/irq.h> + +typedef struct { + unsigned int __softirq_pending; +#ifdef CONFIG_DEBUG_STACKOVERFLOW + unsigned int kernel_stack_usage; +#endif +#ifdef CONFIG_SMP + unsigned int irq_resched_count; + unsigned int irq_call_count; +#endif + unsigned int irq_tlb_count; +} ____cacheline_aligned irq_cpustat_t; + +DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); + +#define __ARCH_IRQ_STAT +#define __IRQ_STAT(cpu, member) (irq_stat[cpu].member) +#define inc_irq_stat(member) this_cpu_inc(irq_stat.member) +#define local_softirq_pending() this_cpu_read(irq_stat.__softirq_pending) + +#define __ARCH_SET_SOFTIRQ_PENDING + +#define set_softirq_pending(x) \ + this_cpu_write(irq_stat.__softirq_pending, (x)) +#define or_softirq_pending(x) this_cpu_or(irq_stat.__softirq_pending, (x)) + +#define ack_bad_irq(irq) WARN(1, "unexpected IRQ trap at vector %02x\n", irq) #endif /* _PARISC_HARDIRQ_H */ diff --git a/arch/parisc/include/asm/mmzone.h b/arch/parisc/include/asm/mmzone.h index e67eb9c3d1bf..0e625ab9aaec 100644 --- a/arch/parisc/include/asm/mmzone.h +++ b/arch/parisc/include/asm/mmzone.h @@ -1,9 +1,10 @@ #ifndef _PARISC_MMZONE_H #define _PARISC_MMZONE_H +#define MAX_PHYSMEM_RANGES 8 /* Fix the size for now (current known max is 3) */ + #ifdef CONFIG_DISCONTIGMEM -#define MAX_PHYSMEM_RANGES 8 /* Fix the size for now (current known max is 3) */ extern int npmem_ranges; struct node_map_data { @@ -44,7 +45,7 @@ static inline int pfn_to_nid(unsigned long pfn) return 0; i = pfn >> PFNNID_SHIFT; - BUG_ON(i >= sizeof(pfnnid_map) / sizeof(pfnnid_map[0])); + BUG_ON(i >= ARRAY_SIZE(pfnnid_map)); r = pfnnid_map[i]; BUG_ON(r == 0xff); @@ -60,7 +61,5 @@ static inline int pfn_valid(int pfn) return 0; } -#else /* !CONFIG_DISCONTIGMEM */ -#define MAX_PHYSMEM_RANGES 1 #endif #endif /* _PARISC_MMZONE_H */ diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h index 4e0e7dbf0f3f..b7adb2ac049c 100644 --- a/arch/parisc/include/asm/page.h +++ b/arch/parisc/include/asm/page.h @@ -21,15 +21,27 @@ #include <asm/types.h> #include <asm/cache.h> -#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) -#define copy_page(to,from) copy_user_page_asm((void *)(to), (void *)(from)) +#define clear_page(page) clear_page_asm((void *)(page)) +#define copy_page(to, from) copy_page_asm((void *)(to), (void *)(from)) struct page; -void copy_user_page_asm(void *to, void *from); +void clear_page_asm(void *page); +void copy_page_asm(void *to, void *from); +void clear_user_page(void *vto, unsigned long vaddr, struct page *pg); void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg); -void clear_user_page(void *page, unsigned long vaddr, struct page *pg); + +/* #define CONFIG_PARISC_TMPALIAS */ + +#ifdef CONFIG_PARISC_TMPALIAS +void clear_user_highpage(struct page *page, unsigned long vaddr); +#define clear_user_highpage clear_user_highpage +struct vm_area_struct; +void copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma); +#define __HAVE_ARCH_COPY_USER_HIGHPAGE +#endif /* * These are used to make use of C type-checking.. diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h index ee99f2339356..1e40d7f86be3 100644 --- a/arch/parisc/include/asm/pgtable.h +++ b/arch/parisc/include/asm/pgtable.h @@ -12,10 +12,11 @@ #include <linux/bitops.h> #include <linux/spinlock.h> +#include <linux/mm_types.h> #include <asm/processor.h> #include <asm/cache.h> -struct vm_area_struct; +extern spinlock_t pa_dbit_lock; /* * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel @@ -40,7 +41,17 @@ struct vm_area_struct; do{ \ *(pteptr) = (pteval); \ } while(0) -#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) + +extern void purge_tlb_entries(struct mm_struct *, unsigned long); + +#define set_pte_at(mm, addr, ptep, pteval) \ + do { \ + unsigned long flags; \ + spin_lock_irqsave(&pa_dbit_lock, flags); \ + set_pte(ptep, pteval); \ + purge_tlb_entries(mm, addr); \ + spin_unlock_irqrestore(&pa_dbit_lock, flags); \ + } while (0) #endif /* !__ASSEMBLY__ */ @@ -429,47 +440,46 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *); static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) { -#ifdef CONFIG_SMP + pte_t pte; + unsigned long flags; + if (!pte_young(*ptep)) return 0; - return test_and_clear_bit(xlate_pabit(_PAGE_ACCESSED_BIT), &pte_val(*ptep)); -#else - pte_t pte = *ptep; - if (!pte_young(pte)) + + spin_lock_irqsave(&pa_dbit_lock, flags); + pte = *ptep; + if (!pte_young(pte)) { + spin_unlock_irqrestore(&pa_dbit_lock, flags); return 0; - set_pte_at(vma->vm_mm, addr, ptep, pte_mkold(pte)); + } + set_pte(ptep, pte_mkold(pte)); + purge_tlb_entries(vma->vm_mm, addr); + spin_unlock_irqrestore(&pa_dbit_lock, flags); return 1; -#endif } -extern spinlock_t pa_dbit_lock; - struct mm_struct; static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { pte_t old_pte; + unsigned long flags; - spin_lock(&pa_dbit_lock); + spin_lock_irqsave(&pa_dbit_lock, flags); old_pte = *ptep; pte_clear(mm,addr,ptep); - spin_unlock(&pa_dbit_lock); + purge_tlb_entries(mm, addr); + spin_unlock_irqrestore(&pa_dbit_lock, flags); return old_pte; } static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { -#ifdef CONFIG_SMP - unsigned long new, old; - - do { - old = pte_val(*ptep); - new = pte_val(pte_wrprotect(__pte (old))); - } while (cmpxchg((unsigned long *) ptep, old, new) != old); -#else - pte_t old_pte = *ptep; - set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte)); -#endif + unsigned long flags; + spin_lock_irqsave(&pa_dbit_lock, flags); + set_pte(ptep, pte_wrprotect(*ptep)); + purge_tlb_entries(mm, addr); + spin_unlock_irqrestore(&pa_dbit_lock, flags); } #define pte_same(A,B) (pte_val(A) == pte_val(B)) diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h index 09b54a57a48d..064015547d1e 100644 --- a/arch/parisc/include/asm/processor.h +++ b/arch/parisc/include/asm/processor.h @@ -20,8 +20,6 @@ #endif /* __ASSEMBLY__ */ -#define KERNEL_STACK_SIZE (4*PAGE_SIZE) - /* * Default implementation of macro that returns current * instruction pointer ("program counter"). @@ -61,6 +59,23 @@ #ifndef __ASSEMBLY__ /* + * IRQ STACK - used for irq handler + */ +#ifdef __KERNEL__ + +#define IRQ_STACK_SIZE (4096 << 2) /* 16k irq stack size */ + +union irq_stack_union { + unsigned long stack[IRQ_STACK_SIZE/sizeof(unsigned long)]; +}; + +DECLARE_PER_CPU(union irq_stack_union, irq_stack_union); + +void call_on_stack(unsigned long p1, void *func, unsigned long new_stack); + +#endif /* __KERNEL__ */ + +/* * Data detected about CPUs at boot time which is the same for all CPU's. * HP boxes are SMP - ie identical processors. * @@ -97,7 +112,6 @@ struct cpuinfo_parisc { unsigned long txn_addr; /* MMIO addr of EIR or id_eid */ #ifdef CONFIG_SMP unsigned long pending_ipi; /* bitmap of type ipi_message_type */ - unsigned long ipi_count; /* number ipi Interrupts */ #endif unsigned long bh_count; /* number of times bh was invoked */ unsigned long prof_counter; /* per CPU profiling support */ diff --git a/arch/parisc/include/asm/signal.h b/arch/parisc/include/asm/signal.h index 0fdb3c835952..81a545773971 100644 --- a/arch/parisc/include/asm/signal.h +++ b/arch/parisc/include/asm/signal.h @@ -3,16 +3,12 @@ #include <uapi/asm/signal.h> - #define _NSIG 64 /* bits-per-word, where word apparently means 'long' not 'int' */ #define _NSIG_BPW BITS_PER_LONG #define _NSIG_WORDS (_NSIG / _NSIG_BPW) # ifndef __ASSEMBLY__ -#ifdef CONFIG_64BIT -#else -#endif /* Most things should be clean enough to redefine this at will, if care is taken to make libc match. */ @@ -24,15 +20,13 @@ typedef struct { unsigned long sig[_NSIG_WORDS]; } sigset_t; +#ifndef __KERNEL__ struct sigaction { __sighandler_t sa_handler; unsigned long sa_flags; sigset_t sa_mask; /* mask last for extensibility */ }; - -struct k_sigaction { - struct sigaction sa; -}; +#endif #include <asm/sigcontext.h> diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h index d1fb79a36f3d..540c88fa8f86 100644 --- a/arch/parisc/include/asm/thread_info.h +++ b/arch/parisc/include/asm/thread_info.h @@ -40,7 +40,7 @@ struct thread_info { /* thread information allocation */ -#define THREAD_SIZE_ORDER 2 +#define THREAD_SIZE_ORDER 2 /* PA-RISC requires at least 16k stack */ /* Be sure to hunt all references to this down when you change the size of * the kernel stack */ #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) @@ -77,8 +77,6 @@ struct thread_info { #define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \ _TIF_BLOCKSTEP) -#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) - #endif /* __KERNEL__ */ #endif /* _ASM_PARISC_THREAD_INFO_H */ diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h index 8f1a8100bf2d..5273da991e06 100644 --- a/arch/parisc/include/asm/tlbflush.h +++ b/arch/parisc/include/asm/tlbflush.h @@ -22,6 +22,8 @@ extern spinlock_t pa_tlb_lock; extern void flush_tlb_all(void); extern void flush_tlb_all_local(void *); +#define smp_flush_tlb_all() flush_tlb_all() + /* * flush_tlb_mm() * diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h index 4ba2c93770f1..e0a82358517e 100644 --- a/arch/parisc/include/asm/uaccess.h +++ b/arch/parisc/include/asm/uaccess.h @@ -181,30 +181,24 @@ struct exception_data { #if !defined(CONFIG_64BIT) #define __put_kernel_asm64(__val,ptr) do { \ - u64 __val64 = (u64)(__val); \ - u32 hi = (__val64) >> 32; \ - u32 lo = (__val64) & 0xffffffff; \ __asm__ __volatile__ ( \ "\n1:\tstw %2,0(%1)" \ - "\n2:\tstw %3,4(%1)\n\t" \ + "\n2:\tstw %R2,4(%1)\n\t" \ ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_put_user_skip_2)\ ASM_EXCEPTIONTABLE_ENTRY(2b,fixup_put_user_skip_1)\ : "=r"(__pu_err) \ - : "r"(ptr), "r"(hi), "r"(lo), "0"(__pu_err) \ + : "r"(ptr), "r"(__val), "0"(__pu_err) \ : "r1"); \ } while (0) #define __put_user_asm64(__val,ptr) do { \ - u64 __val64 = (u64)(__val); \ - u32 hi = (__val64) >> 32; \ - u32 lo = (__val64) & 0xffffffff; \ __asm__ __volatile__ ( \ "\n1:\tstw %2,0(%%sr3,%1)" \ - "\n2:\tstw %3,4(%%sr3,%1)\n\t" \ + "\n2:\tstw %R2,4(%%sr3,%1)\n\t" \ ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_put_user_skip_2)\ ASM_EXCEPTIONTABLE_ENTRY(2b,fixup_put_user_skip_1)\ : "=r"(__pu_err) \ - : "r"(ptr), "r"(hi), "r"(lo), "0"(__pu_err) \ + : "r"(ptr), "r"(__val), "0"(__pu_err) \ : "r1"); \ } while (0) diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index 3043194547cd..74d835820ee7 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h @@ -149,6 +149,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __ARCH_WANT_SYS_SIGNAL #define __ARCH_WANT_SYS_TIME #define __ARCH_WANT_COMPAT_SYS_TIME +#define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL #define __ARCH_WANT_SYS_UTIME #define __ARCH_WANT_SYS_WAITPID #define __ARCH_WANT_SYS_SOCKETCALL @@ -160,23 +161,13 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK -#define __ARCH_WANT_SYS_RT_SIGACTION -#define __ARCH_WANT_SYS_RT_SIGSUSPEND -#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND #define __ARCH_WANT_SYS_FORK #define __ARCH_WANT_SYS_VFORK #define __ARCH_WANT_SYS_CLONE +#define __ARCH_WANT_COMPAT_SYS_SENDFILE #endif /* __ASSEMBLY__ */ #undef STR -/* - * "Conditional" syscalls - * - * What we want is __attribute__((weak,alias("sys_ni_syscall"))), - * but it doesn't work on all toolchains, so we just do it by hand - */ -#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") - #endif /* _ASM_PARISC_UNISTD_H_ */ diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h index d9ff4731253b..70c512a386f7 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -13,7 +13,7 @@ #define SO_BROADCAST 0x0020 #define SO_LINGER 0x0080 #define SO_OOBINLINE 0x0100 -/* To add :#define SO_REUSEPORT 0x0200 */ +#define SO_REUSEPORT 0x0200 #define SO_SNDBUF 0x1001 #define SO_RCVBUF 0x1002 #define SO_SNDBUFFORCE 0x100a @@ -69,6 +69,9 @@ /* Instruct lower device to use last 4-bytes of skb data as FCS */ #define SO_NOFCS 0x4024 +#define SO_LOCK_FILTER 0x4025 + +#define SO_SELECT_ERR_QUEUE 0x4026 /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. diff --git a/arch/parisc/include/uapi/asm/unistd.h b/arch/parisc/include/uapi/asm/unistd.h index e178f30f2ccc..2c8b9bde18eb 100644 --- a/arch/parisc/include/uapi/asm/unistd.h +++ b/arch/parisc/include/uapi/asm/unistd.h @@ -822,8 +822,12 @@ #define __NR_syncfs (__NR_Linux + 327) #define __NR_setns (__NR_Linux + 328) #define __NR_sendmmsg (__NR_Linux + 329) +#define __NR_process_vm_readv (__NR_Linux + 330) +#define __NR_process_vm_writev (__NR_Linux + 331) +#define __NR_kcmp (__NR_Linux + 332) +#define __NR_finit_module (__NR_Linux + 333) -#define __NR_Linux_syscalls (__NR_sendmmsg + 1) +#define __NR_Linux_syscalls (__NR_finit_module + 1) #define __IGNORE_select /* newselect */ diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c index f61692d2b557..00dc66f9c2ba 100644 --- a/arch/parisc/kernel/binfmt_elf32.c +++ b/arch/parisc/kernel/binfmt_elf32.c @@ -85,6 +85,7 @@ struct elf_prpsinfo32 * could set a processor dependent flag in the thread_struct. */ +#undef SET_PERSONALITY #define SET_PERSONALITY(ex) \ set_thread_flag(TIF_32BIT); \ current->thread.map_base = DEFAULT_MAP_BASE32; \ diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 48e16dc20102..65fb4cbc3a0f 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -267,9 +267,11 @@ static inline void __flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long physaddr) { + preempt_disable(); flush_dcache_page_asm(physaddr, vmaddr); if (vma->vm_flags & VM_EXEC) flush_icache_page_asm(physaddr, vmaddr); + preempt_enable(); } void flush_dcache_page(struct page *page) @@ -329,17 +331,6 @@ EXPORT_SYMBOL(flush_kernel_dcache_page_asm); EXPORT_SYMBOL(flush_data_cache_local); EXPORT_SYMBOL(flush_kernel_icache_range_asm); -void clear_user_page_asm(void *page, unsigned long vaddr) -{ - unsigned long flags; - /* This function is implemented in assembly in pacache.S */ - extern void __clear_user_page_asm(void *page, unsigned long vaddr); - - purge_tlb_start(flags); - __clear_user_page_asm(page, vaddr); - purge_tlb_end(flags); -} - #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */ int parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD; @@ -373,20 +364,9 @@ void __init parisc_setup_cache_timing(void) printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); } -extern void purge_kernel_dcache_page(unsigned long); -extern void clear_user_page_asm(void *page, unsigned long vaddr); - -void clear_user_page(void *page, unsigned long vaddr, struct page *pg) -{ - unsigned long flags; - - purge_kernel_dcache_page((unsigned long)page); - purge_tlb_start(flags); - pdtlb_kernel(page); - purge_tlb_end(flags); - clear_user_page_asm(page, vaddr); -} -EXPORT_SYMBOL(clear_user_page); +extern void purge_kernel_dcache_page_asm(unsigned long); +extern void clear_user_page_asm(void *, unsigned long); +extern void copy_user_page_asm(void *, void *, unsigned long); void flush_kernel_dcache_page_addr(void *addr) { @@ -399,11 +379,26 @@ void flush_kernel_dcache_page_addr(void *addr) } EXPORT_SYMBOL(flush_kernel_dcache_page_addr); +void clear_user_page(void *vto, unsigned long vaddr, struct page *page) +{ + clear_page_asm(vto); + if (!parisc_requires_coherency()) + flush_kernel_dcache_page_asm(vto); +} +EXPORT_SYMBOL(clear_user_page); + void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, - struct page *pg) + struct page *pg) { - /* no coherency needed (all in kmap/kunmap) */ - copy_user_page_asm(vto, vfrom); + /* Copy using kernel mapping. No coherency is needed + (all in kmap/kunmap) on machines that don't support + non-equivalent aliasing. However, the `from' page + needs to be flushed before it can be accessed through + the kernel mapping. */ + preempt_disable(); + flush_dcache_page_asm(__pa(vfrom), vaddr); + preempt_enable(); + copy_page_asm(vto, vfrom); if (!parisc_requires_coherency()) flush_kernel_dcache_page_asm(vto); } @@ -419,6 +414,21 @@ void kunmap_parisc(void *addr) EXPORT_SYMBOL(kunmap_parisc); #endif +void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) +{ + unsigned long flags; + + /* Note: purge_tlb_entries can be called at startup with + no context. */ + + purge_tlb_start(flags); + mtsp(mm->context, 1); + pdtlb(addr); + pitlb(addr); + purge_tlb_end(flags); +} +EXPORT_SYMBOL(purge_tlb_entries); + void __flush_tlb_range(unsigned long sid, unsigned long start, unsigned long end) { @@ -458,8 +468,66 @@ void flush_cache_all(void) on_each_cpu(cacheflush_h_tmp_function, NULL, 1); } +static inline unsigned long mm_total_size(struct mm_struct *mm) +{ + struct vm_area_struct *vma; + unsigned long usize = 0; + + for (vma = mm->mmap; vma; vma = vma->vm_next) + usize += vma->vm_end - vma->vm_start; + return usize; +} + +static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr) +{ + pte_t *ptep = NULL; + + if (!pgd_none(*pgd)) { + pud_t *pud = pud_offset(pgd, addr); + if (!pud_none(*pud)) { + pmd_t *pmd = pmd_offset(pud, addr); + if (!pmd_none(*pmd)) + ptep = pte_offset_map(pmd, addr); + } + } + return ptep; +} + void flush_cache_mm(struct mm_struct *mm) { + /* Flushing the whole cache on each cpu takes forever on + rp3440, etc. So, avoid it if the mm isn't too big. */ + if (mm_total_size(mm) < parisc_cache_flush_threshold) { + struct vm_area_struct *vma; + + if (mm->context == mfsp(3)) { + for (vma = mm->mmap; vma; vma = vma->vm_next) { + flush_user_dcache_range_asm(vma->vm_start, + vma->vm_end); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_range_asm( + vma->vm_start, vma->vm_end); + } + } else { + pgd_t *pgd = mm->pgd; + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + unsigned long addr; + + for (addr = vma->vm_start; addr < vma->vm_end; + addr += PAGE_SIZE) { + pte_t *ptep = get_ptep(pgd, addr); + if (ptep != NULL) { + pte_t pte = *ptep; + __flush_cache_page(vma, addr, + page_to_phys(pte_page(pte))); + } + } + } + } + return; + } + #ifdef CONFIG_SMP flush_cache_all(); #else @@ -485,20 +553,36 @@ flush_user_icache_range(unsigned long start, unsigned long end) flush_instruction_cache(); } - void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - int sr3; - BUG_ON(!vma->vm_mm->context); - sr3 = mfsp(3); - if (vma->vm_mm->context == sr3) { - flush_user_dcache_range(start,end); - flush_user_icache_range(start,end); + if ((end - start) < parisc_cache_flush_threshold) { + if (vma->vm_mm->context == mfsp(3)) { + flush_user_dcache_range_asm(start, end); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_range_asm(start, end); + } else { + unsigned long addr; + pgd_t *pgd = vma->vm_mm->pgd; + + for (addr = start & PAGE_MASK; addr < end; + addr += PAGE_SIZE) { + pte_t *ptep = get_ptep(pgd, addr); + if (ptep != NULL) { + pte_t pte = *ptep; + flush_cache_page(vma, + addr, pte_pfn(pte)); + } + } + } } else { +#ifdef CONFIG_SMP flush_cache_all(); +#else + flush_cache_all_local(); +#endif } } @@ -511,3 +595,67 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn))); } + +#ifdef CONFIG_PARISC_TMPALIAS + +void clear_user_highpage(struct page *page, unsigned long vaddr) +{ + void *vto; + unsigned long flags; + + /* Clear using TMPALIAS region. The page doesn't need to + be flushed but the kernel mapping needs to be purged. */ + + vto = kmap_atomic(page); + + /* The PA-RISC 2.0 Architecture book states on page F-6: + "Before a write-capable translation is enabled, *all* + non-equivalently-aliased translations must be removed + from the page table and purged from the TLB. (Note + that the caches are not required to be flushed at this + time.) Before any non-equivalent aliased translation + is re-enabled, the virtual address range for the writeable + page (the entire page) must be flushed from the cache, + and the write-capable translation removed from the page + table and purged from the TLB." */ + + purge_kernel_dcache_page_asm((unsigned long)vto); + purge_tlb_start(flags); + pdtlb_kernel(vto); + purge_tlb_end(flags); + preempt_disable(); + clear_user_page_asm(vto, vaddr); + preempt_enable(); + + pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */ +} + +void copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma) +{ + void *vfrom, *vto; + unsigned long flags; + + /* Copy using TMPALIAS region. This has the advantage + that the `from' page doesn't need to be flushed. However, + the `to' page must be flushed in copy_user_page_asm since + it can be used to bring in executable code. */ + + vfrom = kmap_atomic(from); + vto = kmap_atomic(to); + + purge_kernel_dcache_page_asm((unsigned long)vto); + purge_tlb_start(flags); + pdtlb_kernel(vto); + pdtlb_kernel(vfrom); + purge_tlb_end(flags); + preempt_disable(); + copy_user_page_asm(vto, vfrom, vaddr); + flush_dcache_page_asm(__pa(vto), vaddr); + preempt_enable(); + + pagefault_enable(); /* kunmap_atomic(addr, KM_USER1); */ + pagefault_enable(); /* kunmap_atomic(addr, KM_USER0); */ +} + +#endif /* CONFIG_PARISC_TMPALIAS */ diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index eb7850b46c25..4bb96ad9b0b1 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -400,7 +400,15 @@ #if PT_NLEVELS == 3 extru \va,31-ASM_PMD_SHIFT,ASM_BITS_PER_PMD,\index #else +# if defined(CONFIG_64BIT) + extrd,u \va,63-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index + #else + # if PAGE_SIZE > 4096 + extru \va,31-ASM_PGDIR_SHIFT,32-ASM_PGDIR_SHIFT,\index + # else extru \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index + # endif +# endif #endif dep %r0,31,PAGE_SHIFT,\pmd /* clear offset */ copy %r0,\pte @@ -483,7 +491,7 @@ * B <-> _PAGE_DMB (memory break) * * Then incredible subtlety: The access rights are - * _PAGE_GATEWAY _PAGE_EXEC _PAGE_READ + * _PAGE_GATEWAY, _PAGE_EXEC and _PAGE_WRITE * See 3-14 of the parisc 2.0 manual * * Finally, _PAGE_READ goes in the top bit of PL1 (so we @@ -493,7 +501,7 @@ /* PAGE_USER indicates the page can be read with user privileges, * so deposit X1|11 to PL1|PL2 (remember the upper bit of PL1 - * contains _PAGE_READ */ + * contains _PAGE_READ) */ extrd,u,*= \pte,_PAGE_USER_BIT+32,1,%r0 depdi 7,11,3,\prot /* If we're a gateway page, drop PL2 back to zero for promotion @@ -615,7 +623,7 @@ .text - .align PAGE_SIZE + .align 4096 ENTRY(fault_vector_20) /* First vector is invalid (0) */ @@ -825,11 +833,6 @@ ENTRY(syscall_exit_rfi) STREG %r19,PT_SR7(%r16) intr_return: - /* NOTE: Need to enable interrupts incase we schedule. */ - ssm PSW_SM_I, %r0 - -intr_check_resched: - /* check for reschedule */ mfctl %cr30,%r1 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */ @@ -856,6 +859,11 @@ intr_check_sig: LDREG PT_IASQ1(%r16), %r20 cmpib,COND(=),n 0,%r20,intr_restore /* backward */ + /* NOTE: We need to enable interrupts if we have to deliver + * signals. We used to do this earlier but it caused kernel + * stack overflows. */ + ssm PSW_SM_I, %r0 + copy %r0, %r25 /* long in_syscall = 0 */ #ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ @@ -907,6 +915,10 @@ intr_do_resched: cmpib,COND(=) 0, %r20, intr_do_preempt nop + /* NOTE: We need to enable interrupts if we schedule. We used + * to do this earlier but it caused kernel stack overflows. */ + ssm PSW_SM_I, %r0 + #ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ #endif @@ -1694,7 +1706,8 @@ ENTRY(sys_\name\()_wrapper) ldo TASK_REGS(%r1),%r1 reg_save %r1 mfctl %cr27, %r28 - b sys_\name + ldil L%sys_\name, %r31 + be R%sys_\name(%sr4,%r31) STREG %r28, PT_CR27(%r1) ENDPROC(sys_\name\()_wrapper) .endm @@ -1748,44 +1761,6 @@ ENTRY(sys_rt_sigreturn_wrapper) LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */ ENDPROC(sys_rt_sigreturn_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 */ - LDREG TASK_PT_GR30(%r24),%r24 - STREG %r2, -RP_OFFSET(%r30) -#ifdef CONFIG_64BIT - ldo FRAME_SIZE(%r30), %r30 - BL do_sigaltstack,%r2 - ldo -16(%r30),%r29 /* Reference param save area */ -#else - BL do_sigaltstack,%r2 - ldo FRAME_SIZE(%r30), %r30 -#endif - - ldo -FRAME_SIZE(%r30), %r30 - LDREG -RP_OFFSET(%r30), %r2 - bv %r0(%r2) - nop -ENDPROC(sys_sigaltstack_wrapper) - -#ifdef CONFIG_64BIT -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 - 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 - ENTRY(syscall_exit) /* NOTE: HP-UX syscalls also come through here * after hpux_syscall_exit fixes up return @@ -2035,6 +2010,47 @@ ftrace_stub: ENDPROC(return_to_handler) #endif /* CONFIG_FUNCTION_TRACER */ +#ifdef CONFIG_IRQSTACKS +/* void call_on_stack(unsigned long param1, void *func, + unsigned long new_stack) */ +ENTRY(call_on_stack) + copy %sp, %r1 + + /* Regarding the HPPA calling conventions for function pointers, + we assume the PIC register is not changed across call. For + CONFIG_64BIT, the argument pointer is left to point at the + argument region allocated for the call to call_on_stack. */ +# ifdef CONFIG_64BIT + /* Switch to new stack. We allocate two 128 byte frames. */ + ldo 256(%arg2), %sp + /* Save previous stack pointer and return pointer in frame marker */ + STREG %rp, -144(%sp) + /* Calls always use function descriptor */ + LDREG 16(%arg1), %arg1 + bve,l (%arg1), %rp + STREG %r1, -136(%sp) + LDREG -144(%sp), %rp + bve (%rp) + LDREG -136(%sp), %sp +# else + /* Switch to new stack. We allocate two 64 byte frames. */ + ldo 128(%arg2), %sp + /* Save previous stack pointer and return pointer in frame marker */ + STREG %r1, -68(%sp) + STREG %rp, -84(%sp) + /* Calls use function descriptor if PLABEL bit is set */ + bb,>=,n %arg1, 30, 1f + depwi 0,31,2, %arg1 + LDREG 0(%arg1), %arg1 +1: + be,l 0(%sr4,%arg1), %sr0, %r31 + copy %r31, %rp + LDREG -84(%sp), %rp + bv (%rp) + LDREG -68(%sp), %sp +# endif /* CONFIG_64BIT */ +ENDPROC(call_on_stack) +#endif /* CONFIG_IRQSTACKS */ get_register: /* diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S index 5595a2f31181..e158b6fbf1b4 100644 --- a/arch/parisc/kernel/hpmc.S +++ b/arch/parisc/kernel/hpmc.S @@ -55,13 +55,13 @@ * IODC requires 7K byte stack. That leaves 1K byte for os_hpmc. */ - .align PAGE_SIZE + .align 4096 hpmc_stack: .block 16384 #define HPMC_IODC_BUF_SIZE 0x8000 - .align PAGE_SIZE + .align 4096 hpmc_iodc_buf: .block HPMC_IODC_BUF_SIZE diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c index 08324aac3544..3295ef4a185d 100644 --- a/arch/parisc/kernel/inventory.c +++ b/arch/parisc/kernel/inventory.c @@ -186,12 +186,14 @@ pat_query_module(ulong pcell_loc, ulong mod_index) if (status != PDC_OK) { /* no more cell modules or error */ + kfree(pa_pdc_cell); return status; } temp = pa_pdc_cell->cba; dev = alloc_pa_dev(PAT_GET_CBA(temp), &(pa_pdc_cell->mod_path)); if (!dev) { + kfree(pa_pdc_cell); return PDC_OK; } diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 0299d63cd112..e255db0bb761 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -152,6 +152,39 @@ static struct irq_chip cpu_interrupt_type = { .irq_retrigger = NULL, }; +DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); +#define irq_stats(x) (&per_cpu(irq_stat, x)) + +/* + * /proc/interrupts printing for arch specific interrupts + */ +int arch_show_interrupts(struct seq_file *p, int prec) +{ + int j; + +#ifdef CONFIG_DEBUG_STACKOVERFLOW + seq_printf(p, "%*s: ", prec, "STK"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", irq_stats(j)->kernel_stack_usage); + seq_printf(p, " Kernel stack usage\n"); +#endif +#ifdef CONFIG_SMP + seq_printf(p, "%*s: ", prec, "RES"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count); + seq_printf(p, " Rescheduling interrupts\n"); + seq_printf(p, "%*s: ", prec, "CAL"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", irq_stats(j)->irq_call_count); + seq_printf(p, " Function call interrupts\n"); +#endif + seq_printf(p, "%*s: ", prec, "TLB"); + for_each_online_cpu(j) + seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count); + seq_printf(p, " TLB shootdowns\n"); + return 0; +} + int show_interrupts(struct seq_file *p, void *v) { int i = *(loff_t *) v, j; @@ -219,6 +252,9 @@ int show_interrupts(struct seq_file *p, void *v) raw_spin_unlock_irqrestore(&desc->lock, flags); } + if (i == NR_IRQS) + arch_show_interrupts(p, 3); + return 0; } @@ -330,6 +366,66 @@ static inline int eirr_to_irq(unsigned long eirr) return (BITS_PER_LONG - bit) + TIMER_IRQ; } +int sysctl_panic_on_stackoverflow = 1; + +static inline void stack_overflow_check(struct pt_regs *regs) +{ +#ifdef CONFIG_DEBUG_STACKOVERFLOW + #define STACK_MARGIN (256*6) + + /* Our stack starts directly behind the thread_info struct. */ + unsigned long stack_start = (unsigned long) current_thread_info(); + unsigned long sp = regs->gr[30]; + unsigned long stack_usage; + unsigned int *last_usage; + + /* if sr7 != 0, we interrupted a userspace process which we do not want + * to check for stack overflow. We will only check the kernel stack. */ + if (regs->sr[7]) + return; + + /* calculate kernel stack usage */ + stack_usage = sp - stack_start; + last_usage = &per_cpu(irq_stat.kernel_stack_usage, smp_processor_id()); + + if (unlikely(stack_usage > *last_usage)) + *last_usage = stack_usage; + + if (likely(stack_usage < (THREAD_SIZE - STACK_MARGIN))) + return; + + pr_emerg("stackcheck: %s will most likely overflow kernel stack " + "(sp:%lx, stk bottom-top:%lx-%lx)\n", + current->comm, sp, stack_start, stack_start + THREAD_SIZE); + + if (sysctl_panic_on_stackoverflow) + panic("low stack detected by irq handler - check messages\n"); +#endif +} + +#ifdef CONFIG_IRQSTACKS +DEFINE_PER_CPU(union irq_stack_union, irq_stack_union); + +static void execute_on_irq_stack(void *func, unsigned long param1) +{ + unsigned long *irq_stack_start; + unsigned long irq_stack; + int cpu = smp_processor_id(); + + irq_stack_start = &per_cpu(irq_stack_union, cpu).stack[0]; + irq_stack = (unsigned long) irq_stack_start; + irq_stack = ALIGN(irq_stack, 16); /* align for stack frame usage */ + + BUG_ON(*irq_stack_start); /* report bug if we were called recursive. */ + *irq_stack_start = 1; + + /* This is where we switch to the IRQ stack. */ + call_on_stack(param1, func, irq_stack); + + *irq_stack_start = 0; +} +#endif /* CONFIG_IRQSTACKS */ + /* ONLY called from entry.S:intr_extint() */ void do_cpu_irq_mask(struct pt_regs *regs) { @@ -364,7 +460,13 @@ void do_cpu_irq_mask(struct pt_regs *regs) goto set_out; } #endif + stack_overflow_check(regs); + +#ifdef CONFIG_IRQSTACKS + execute_on_irq_stack(&generic_handle_irq, irq); +#else generic_handle_irq(irq); +#endif /* CONFIG_IRQSTACKS */ out: irq_exit(); @@ -379,14 +481,14 @@ void do_cpu_irq_mask(struct pt_regs *regs) static struct irqaction timer_action = { .handler = timer_interrupt, .name = "timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL, }; #ifdef CONFIG_SMP static struct irqaction ipi_action = { .handler = ipi_interrupt, .name = "IPI", - .flags = IRQF_DISABLED | IRQF_PERCPU, + .flags = IRQF_PERCPU, }; #endif @@ -420,6 +522,4 @@ void __init init_IRQ(void) cpu_eiem = EIEM_MASK(TIMER_IRQ); #endif set_eiem(cpu_eiem); /* EIEM : enable all external intr */ - } - diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 5d7218ad885c..5e1de6072be5 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -199,7 +199,6 @@ ENTRY(flush_instruction_cache_local) .callinfo NO_CALLS .entry - mtsp %r0, %sr1 load32 cache_info, %r1 /* Flush Instruction Cache */ @@ -208,7 +207,8 @@ ENTRY(flush_instruction_cache_local) LDREG ICACHE_STRIDE(%r1), %arg1 LDREG ICACHE_COUNT(%r1), %arg2 LDREG ICACHE_LOOP(%r1), %arg3 - rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/ + rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/ + mtsp %r0, %sr1 addib,COND(=) -1, %arg3, fioneloop /* Preadjust and test */ movb,<,n %arg3, %r31, fisync /* If loop < 0, do sync */ @@ -220,7 +220,33 @@ fimanyloop: /* Loop if LOOP >= 2 */ addib,COND(<=),n -1, %arg2, fisync /* Outer loop decr */ fioneloop: /* Loop if LOOP = 1 */ - addib,COND(>) -1, %arg2, fioneloop /* Outer loop count decr */ + /* Some implementations may flush with a single fice instruction */ + cmpib,COND(>>=),n 15, %arg2, fioneloop2 + +fioneloop1: + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + fice,m %arg1(%sr1, %arg0) + addib,COND(>) -16, %arg2, fioneloop1 + fice,m %arg1(%sr1, %arg0) + + /* Check if done */ + cmpb,COND(=),n %arg2, %r0, fisync /* Predict branch taken */ + +fioneloop2: + addib,COND(>) -1, %arg2, fioneloop2 /* Outer loop count decr */ fice,m %arg1(%sr1, %arg0) /* Fice for one loop */ fisync: @@ -240,8 +266,7 @@ ENTRY(flush_data_cache_local) .callinfo NO_CALLS .entry - mtsp %r0, %sr1 - load32 cache_info, %r1 + load32 cache_info, %r1 /* Flush Data Cache */ @@ -249,7 +274,8 @@ ENTRY(flush_data_cache_local) LDREG DCACHE_STRIDE(%r1), %arg1 LDREG DCACHE_COUNT(%r1), %arg2 LDREG DCACHE_LOOP(%r1), %arg3 - rsm PSW_SM_I, %r22 + rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/ + mtsp %r0, %sr1 addib,COND(=) -1, %arg3, fdoneloop /* Preadjust and test */ movb,<,n %arg3, %r31, fdsync /* If loop < 0, do sync */ @@ -261,7 +287,33 @@ fdmanyloop: /* Loop if LOOP >= 2 */ addib,COND(<=),n -1, %arg2, fdsync /* Outer loop decr */ fdoneloop: /* Loop if LOOP = 1 */ - addib,COND(>) -1, %arg2, fdoneloop /* Outer loop count decr */ + /* Some implementations may flush with a single fdce instruction */ + cmpib,COND(>>=),n 15, %arg2, fdoneloop2 + +fdoneloop1: + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + fdce,m %arg1(%sr1, %arg0) + addib,COND(>) -16, %arg2, fdoneloop1 + fdce,m %arg1(%sr1, %arg0) + + /* Check if done */ + cmpb,COND(=),n %arg2, %r0, fdsync /* Predict branch taken */ + +fdoneloop2: + addib,COND(>) -1, %arg2, fdoneloop2 /* Outer loop count decr */ fdce,m %arg1(%sr1, %arg0) /* Fdce for one loop */ fdsync: @@ -277,7 +329,104 @@ ENDPROC(flush_data_cache_local) .align 16 -ENTRY(copy_user_page_asm) +/* Macros to serialize TLB purge operations on SMP. */ + + .macro tlb_lock la,flags,tmp +#ifdef CONFIG_SMP + ldil L%pa_tlb_lock,%r1 + ldo R%pa_tlb_lock(%r1),\la + rsm PSW_SM_I,\flags +1: LDCW 0(\la),\tmp + cmpib,<>,n 0,\tmp,3f +2: ldw 0(\la),\tmp + cmpb,<> %r0,\tmp,1b + nop + b,n 2b +3: +#endif + .endm + + .macro tlb_unlock la,flags,tmp +#ifdef CONFIG_SMP + ldi 1,\tmp + stw \tmp,0(\la) + mtsm \flags +#endif + .endm + +/* Clear page using kernel mapping. */ + +ENTRY(clear_page_asm) + .proc + .callinfo NO_CALLS + .entry + +#ifdef CONFIG_64BIT + + /* Unroll the loop. */ + ldi (PAGE_SIZE / 128), %r1 + +1: + std %r0, 0(%r26) + std %r0, 8(%r26) + std %r0, 16(%r26) + std %r0, 24(%r26) + std %r0, 32(%r26) + std %r0, 40(%r26) + std %r0, 48(%r26) + std %r0, 56(%r26) + std %r0, 64(%r26) + std %r0, 72(%r26) + std %r0, 80(%r26) + std %r0, 88(%r26) + std %r0, 96(%r26) + std %r0, 104(%r26) + std %r0, 112(%r26) + std %r0, 120(%r26) + + /* Note reverse branch hint for addib is taken. */ + addib,COND(>),n -1, %r1, 1b + ldo 128(%r26), %r26 + +#else + + /* + * Note that until (if) we start saving the full 64-bit register + * values on interrupt, we can't use std on a 32 bit kernel. + */ + ldi (PAGE_SIZE / 64), %r1 + +1: + stw %r0, 0(%r26) + stw %r0, 4(%r26) + stw %r0, 8(%r26) + stw %r0, 12(%r26) + stw %r0, 16(%r26) + stw %r0, 20(%r26) + stw %r0, 24(%r26) + stw %r0, 28(%r26) + stw %r0, 32(%r26) + stw %r0, 36(%r26) + stw %r0, 40(%r26) + stw %r0, 44(%r26) + stw %r0, 48(%r26) + stw %r0, 52(%r26) + stw %r0, 56(%r26) + stw %r0, 60(%r26) + + addib,COND(>),n -1, %r1, 1b + ldo 64(%r26), %r26 +#endif + bv %r0(%r2) + nop + .exit + + .procend +ENDPROC(clear_page_asm) + +/* Copy page using kernel mapping. */ + +ENTRY(copy_page_asm) .proc .callinfo NO_CALLS .entry @@ -285,18 +434,14 @@ ENTRY(copy_user_page_asm) #ifdef CONFIG_64BIT /* PA8x00 CPUs can consume 2 loads or 1 store per cycle. * Unroll the loop by hand and arrange insn appropriately. - * GCC probably can do this just as well. + * Prefetch doesn't improve performance on rp3440. + * GCC probably can do this just as well... */ - ldd 0(%r25), %r19 ldi (PAGE_SIZE / 128), %r1 - ldw 64(%r25), %r0 /* prefetch 1 cacheline ahead */ - ldw 128(%r25), %r0 /* prefetch 2 */ - -1: ldd 8(%r25), %r20 - ldw 192(%r25), %r0 /* prefetch 3 */ - ldw 256(%r25), %r0 /* prefetch 4 */ +1: ldd 0(%r25), %r19 + ldd 8(%r25), %r20 ldd 16(%r25), %r21 ldd 24(%r25), %r22 @@ -330,20 +475,16 @@ ENTRY(copy_user_page_asm) ldd 112(%r25), %r21 ldd 120(%r25), %r22 + ldo 128(%r25), %r25 std %r19, 96(%r26) std %r20, 104(%r26) - ldo 128(%r25), %r25 std %r21, 112(%r26) std %r22, 120(%r26) - ldo 128(%r26), %r26 - /* conditional branches nullify on forward taken branch, and on - * non-taken backward branch. Note that .+4 is a backwards branch. - * The ldd should only get executed if the branch is taken. - */ - addib,COND(>),n -1, %r1, 1b /* bundle 10 */ - ldd 0(%r25), %r19 /* start next loads */ + /* Note reverse branch hint for addib is taken. */ + addib,COND(>),n -1, %r1, 1b + ldo 128(%r26), %r26 #else @@ -399,7 +540,7 @@ ENTRY(copy_user_page_asm) .exit .procend -ENDPROC(copy_user_page_asm) +ENDPROC(copy_page_asm) /* * NOTE: Code in clear_user_page has a hard coded dependency on the @@ -422,7 +563,14 @@ ENDPROC(copy_user_page_asm) * %r23 physical page (shifted for tlb insert) of "from" translation */ -#if 0 + /* Drop prot bits and convert to page addr for iitlbt and idtlbt */ + #define PAGE_ADD_SHIFT (PAGE_SHIFT-12) + .macro convert_phys_for_tlb_insert20 phys + extrd,u \phys, 56-PAGE_ADD_SHIFT, 32-PAGE_ADD_SHIFT, \phys +#if _PAGE_SIZE_ENCODING_DEFAULT + depdi _PAGE_SIZE_ENCODING_DEFAULT, 63, (63-58), \phys +#endif + .endm /* * We can't do this since copy_user_page is used to bring in @@ -435,6 +583,7 @@ ENDPROC(copy_user_page_asm) * use it if more information is passed into copy_user_page(). * Have to do some measurements to see if it is worthwhile to * lobby for such a change. + * */ ENTRY(copy_user_page_asm) @@ -442,17 +591,21 @@ ENTRY(copy_user_page_asm) .callinfo NO_CALLS .entry + /* Convert virtual `to' and `from' addresses to physical addresses. + Move `from' physical address to non shadowed register. */ ldil L%(__PAGE_OFFSET), %r1 sub %r26, %r1, %r26 - sub %r25, %r1, %r23 /* move physical addr into non shadowed reg */ + sub %r25, %r1, %r23 ldil L%(TMPALIAS_MAP_START), %r28 - /* FIXME for different page sizes != 4k */ #ifdef CONFIG_64BIT - extrd,u %r26,56,32, %r26 /* convert phys addr to tlb insert format */ - extrd,u %r23,56,32, %r23 /* convert phys addr to tlb insert format */ - depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */ - depdi 0, 63,12, %r28 /* Clear any offset bits */ +#if (TMPALIAS_MAP_START >= 0x80000000) + depdi 0, 31,32, %r28 /* clear any sign extension */ +#endif + convert_phys_for_tlb_insert20 %r26 /* convert phys addr to tlb insert format */ + convert_phys_for_tlb_insert20 %r23 /* convert phys addr to tlb insert format */ + depd %r24,63,22, %r28 /* Form aliased virtual address 'to' */ + depdi 0, 63,PAGE_SHIFT, %r28 /* Clear any offset bits */ copy %r28, %r29 depdi 1, 41,1, %r29 /* Form aliased virtual address 'from' */ #else @@ -466,10 +619,76 @@ ENTRY(copy_user_page_asm) /* Purge any old translations */ +#ifdef CONFIG_PA20 + pdtlb,l 0(%r28) + pdtlb,l 0(%r29) +#else + tlb_lock %r20,%r21,%r22 pdtlb 0(%r28) pdtlb 0(%r29) + tlb_unlock %r20,%r21,%r22 +#endif + +#ifdef CONFIG_64BIT + /* PA8x00 CPUs can consume 2 loads or 1 store per cycle. + * Unroll the loop by hand and arrange insn appropriately. + * GCC probably can do this just as well. + */ - ldi 64, %r1 + ldd 0(%r29), %r19 + ldi (PAGE_SIZE / 128), %r1 + +1: ldd 8(%r29), %r20 + + ldd 16(%r29), %r21 + ldd 24(%r29), %r22 + std %r19, 0(%r28) + std %r20, 8(%r28) + + ldd 32(%r29), %r19 + ldd 40(%r29), %r20 + std %r21, 16(%r28) + std %r22, 24(%r28) + + ldd 48(%r29), %r21 + ldd 56(%r29), %r22 + std %r19, 32(%r28) + std %r20, 40(%r28) + + ldd 64(%r29), %r19 + ldd 72(%r29), %r20 + std %r21, 48(%r28) + std %r22, 56(%r28) + + ldd 80(%r29), %r21 + ldd 88(%r29), %r22 + std %r19, 64(%r28) + std %r20, 72(%r28) + + ldd 96(%r29), %r19 + ldd 104(%r29), %r20 + std %r21, 80(%r28) + std %r22, 88(%r28) + + ldd 112(%r29), %r21 + ldd 120(%r29), %r22 + std %r19, 96(%r28) + std %r20, 104(%r28) + + ldo 128(%r29), %r29 + std %r21, 112(%r28) + std %r22, 120(%r28) + ldo 128(%r28), %r28 + + /* conditional branches nullify on forward taken branch, and on + * non-taken backward branch. Note that .+4 is a backwards branch. + * The ldd should only get executed if the branch is taken. + */ + addib,COND(>),n -1, %r1, 1b /* bundle 10 */ + ldd 0(%r29), %r19 /* start next loads */ + +#else + ldi (PAGE_SIZE / 64), %r1 /* * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw @@ -480,9 +699,7 @@ ENTRY(copy_user_page_asm) * use ldd/std on a 32 bit kernel. */ - -1: - ldw 0(%r29), %r19 +1: ldw 0(%r29), %r19 ldw 4(%r29), %r20 ldw 8(%r29), %r21 ldw 12(%r29), %r22 @@ -515,8 +732,10 @@ ENTRY(copy_user_page_asm) stw %r21, 56(%r28) stw %r22, 60(%r28) ldo 64(%r28), %r28 + addib,COND(>) -1, %r1,1b ldo 64(%r29), %r29 +#endif bv %r0(%r2) nop @@ -524,9 +743,8 @@ ENTRY(copy_user_page_asm) .procend ENDPROC(copy_user_page_asm) -#endif -ENTRY(__clear_user_page_asm) +ENTRY(clear_user_page_asm) .proc .callinfo NO_CALLS .entry @@ -537,11 +755,10 @@ ENTRY(__clear_user_page_asm) #ifdef CONFIG_64BIT #if (TMPALIAS_MAP_START >= 0x80000000) depdi 0, 31,32, %r28 /* clear any sign extension */ - /* FIXME: page size dependend */ #endif - extrd,u %r26, 56,32, %r26 /* convert phys addr to tlb insert format */ + convert_phys_for_tlb_insert20 %r26 /* convert phys addr to tlb insert format */ depd %r25, 63,22, %r28 /* Form aliased virtual address 'to' */ - depdi 0, 63,12, %r28 /* Clear any offset bits */ + depdi 0, 63,PAGE_SHIFT, %r28 /* Clear any offset bits */ #else extrw,u %r26, 24,25, %r26 /* convert phys addr to tlb insert format */ depw %r25, 31,22, %r28 /* Form aliased virtual address 'to' */ @@ -550,7 +767,13 @@ ENTRY(__clear_user_page_asm) /* Purge any old translation */ +#ifdef CONFIG_PA20 + pdtlb,l 0(%r28) +#else + tlb_lock %r20,%r21,%r22 pdtlb 0(%r28) + tlb_unlock %r20,%r21,%r22 +#endif #ifdef CONFIG_64BIT ldi (PAGE_SIZE / 128), %r1 @@ -580,8 +803,7 @@ ENTRY(__clear_user_page_asm) #else /* ! CONFIG_64BIT */ ldi (PAGE_SIZE / 64), %r1 -1: - stw %r0, 0(%r28) +1: stw %r0, 0(%r28) stw %r0, 4(%r28) stw %r0, 8(%r28) stw %r0, 12(%r28) @@ -606,7 +828,7 @@ ENTRY(__clear_user_page_asm) .exit .procend -ENDPROC(__clear_user_page_asm) +ENDPROC(clear_user_page_asm) ENTRY(flush_dcache_page_asm) .proc @@ -617,11 +839,10 @@ ENTRY(flush_dcache_page_asm) #ifdef CONFIG_64BIT #if (TMPALIAS_MAP_START >= 0x80000000) depdi 0, 31,32, %r28 /* clear any sign extension */ - /* FIXME: page size dependend */ #endif - extrd,u %r26, 56,32, %r26 /* convert phys addr to tlb insert format */ + convert_phys_for_tlb_insert20 %r26 /* convert phys addr to tlb insert format */ depd %r25, 63,22, %r28 /* Form aliased virtual address 'to' */ - depdi 0, 63,12, %r28 /* Clear any offset bits */ + depdi 0, 63,PAGE_SHIFT, %r28 /* Clear any offset bits */ #else extrw,u %r26, 24,25, %r26 /* convert phys addr to tlb insert format */ depw %r25, 31,22, %r28 /* Form aliased virtual address 'to' */ @@ -630,7 +851,13 @@ ENTRY(flush_dcache_page_asm) /* Purge any old translation */ +#ifdef CONFIG_PA20 + pdtlb,l 0(%r28) +#else + tlb_lock %r20,%r21,%r22 pdtlb 0(%r28) + tlb_unlock %r20,%r21,%r22 +#endif ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r1 @@ -663,8 +890,17 @@ ENTRY(flush_dcache_page_asm) fdc,m %r1(%r28) sync + +#ifdef CONFIG_PA20 + pdtlb,l 0(%r25) +#else + tlb_lock %r20,%r21,%r22 + pdtlb 0(%r25) + tlb_unlock %r20,%r21,%r22 +#endif + bv %r0(%r2) - pdtlb (%r25) + nop .exit .procend @@ -679,11 +915,10 @@ ENTRY(flush_icache_page_asm) #ifdef CONFIG_64BIT #if (TMPALIAS_MAP_START >= 0x80000000) depdi 0, 31,32, %r28 /* clear any sign extension */ - /* FIXME: page size dependend */ #endif - extrd,u %r26, 56,32, %r26 /* convert phys addr to tlb insert format */ + convert_phys_for_tlb_insert20 %r26 /* convert phys addr to tlb insert format */ depd %r25, 63,22, %r28 /* Form aliased virtual address 'to' */ - depdi 0, 63,12, %r28 /* Clear any offset bits */ + depdi 0, 63,PAGE_SHIFT, %r28 /* Clear any offset bits */ #else extrw,u %r26, 24,25, %r26 /* convert phys addr to tlb insert format */ depw %r25, 31,22, %r28 /* Form aliased virtual address 'to' */ @@ -692,7 +927,13 @@ ENTRY(flush_icache_page_asm) /* Purge any old translation */ - pitlb (%sr4,%r28) +#ifdef CONFIG_PA20 + pitlb,l %r0(%sr4,%r28) +#else + tlb_lock %r20,%r21,%r22 + pitlb (%sr4,%r28) + tlb_unlock %r20,%r21,%r22 +#endif ldil L%icache_stride, %r1 ldw R%icache_stride(%r1), %r1 @@ -723,12 +964,21 @@ ENTRY(flush_icache_page_asm) fic,m %r1(%sr4,%r28) fic,m %r1(%sr4,%r28) fic,m %r1(%sr4,%r28) - cmpb,COND(<<) %r28, %r25,1b + cmpb,COND(<<) %r28, %r25,1b fic,m %r1(%sr4,%r28) sync + +#ifdef CONFIG_PA20 + pitlb,l %r0(%sr4,%r25) +#else + tlb_lock %r20,%r21,%r22 + pitlb (%sr4,%r25) + tlb_unlock %r20,%r21,%r22 +#endif + bv %r0(%r2) - pitlb (%sr4,%r25) + nop .exit .procend @@ -777,7 +1027,7 @@ ENTRY(flush_kernel_dcache_page_asm) .procend ENDPROC(flush_kernel_dcache_page_asm) -ENTRY(purge_kernel_dcache_page) +ENTRY(purge_kernel_dcache_page_asm) .proc .callinfo NO_CALLS .entry @@ -817,7 +1067,7 @@ ENTRY(purge_kernel_dcache_page) .exit .procend -ENDPROC(purge_kernel_dcache_page) +ENDPROC(purge_kernel_dcache_page_asm) ENTRY(flush_user_dcache_range_asm) .proc diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index ceec85de6290..568b2c61ea02 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -120,11 +120,13 @@ extern void __ashrdi3(void); extern void __ashldi3(void); extern void __lshrdi3(void); extern void __muldi3(void); +extern void __ucmpdi2(void); EXPORT_SYMBOL(__ashrdi3); EXPORT_SYMBOL(__ashldi3); EXPORT_SYMBOL(__lshrdi3); EXPORT_SYMBOL(__muldi3); +EXPORT_SYMBOL(__ucmpdi2); asmlinkage void * __canonicalize_funcptr_for_compare(void *); EXPORT_SYMBOL(__canonicalize_funcptr_for_compare); @@ -157,5 +159,6 @@ extern void _mcount(void); EXPORT_SYMBOL(_mcount); #endif -/* from pacache.S -- needed for copy_page */ -EXPORT_SYMBOL(copy_user_page_asm); +/* from pacache.S -- needed for clear/copy_page */ +EXPORT_SYMBOL(clear_page_asm); +EXPORT_SYMBOL(copy_page_asm); diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c index d47ba1aa8253..3e04242de5a7 100644 --- a/arch/parisc/kernel/pdc_chassis.c +++ b/arch/parisc/kernel/pdc_chassis.c @@ -30,11 +30,13 @@ #endif #include <linux/init.h> +#include <linux/module.h> #include <linux/kernel.h> #include <linux/reboot.h> #include <linux/notifier.h> #include <linux/cache.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <asm/pdc_chassis.h> #include <asm/processor.h> @@ -244,38 +246,38 @@ int pdc_chassis_send_status(int message) #ifdef CONFIG_PDC_CHASSIS_WARN #ifdef CONFIG_PROC_FS -static int pdc_chassis_warn_pread(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int pdc_chassis_warn_show(struct seq_file *m, void *v) { - char *out = page; - int len, ret; unsigned long warn; u32 warnreg; - ret = pdc_chassis_warn(&warn); - if (ret != PDC_OK) + if (pdc_chassis_warn(&warn) != PDC_OK) return -EIO; warnreg = (warn & 0xFFFFFFFF); if ((warnreg >> 24) & 0xFF) - out += sprintf(out, "Chassis component failure! (eg fan or PSU): 0x%.2x\n", ((warnreg >> 24) & 0xFF)); - - out += sprintf(out, "Battery: %s\n", (warnreg & 0x04) ? "Low!" : "OK"); - out += sprintf(out, "Temp low: %s\n", (warnreg & 0x02) ? "Exceeded!" : "OK"); - out += sprintf(out, "Temp mid: %s\n", (warnreg & 0x01) ? "Exceeded!" : "OK"); - - len = out - page - off; - if (len < count) { - *eof = 1; - if (len <= 0) return 0; - } else { - len = count; - } - *start = page + off; - return len; + seq_printf(m, "Chassis component failure! (eg fan or PSU): 0x%.2x\n", + (warnreg >> 24) & 0xFF); + + seq_printf(m, "Battery: %s\n", (warnreg & 0x04) ? "Low!" : "OK"); + seq_printf(m, "Temp low: %s\n", (warnreg & 0x02) ? "Exceeded!" : "OK"); + seq_printf(m, "Temp mid: %s\n", (warnreg & 0x01) ? "Exceeded!" : "OK"); + return 0; +} + +static int pdc_chassis_warn_open(struct inode *inode, struct file *file) +{ + return single_open(file, pdc_chassis_warn_show, NULL); } +static const struct file_operations pdc_chassis_warn_fops = { + .open = pdc_chassis_warn_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int __init pdc_chassis_create_procfs(void) { unsigned long test; @@ -290,8 +292,7 @@ static int __init pdc_chassis_create_procfs(void) printk(KERN_INFO "Enabling PDC chassis warnings support v%s\n", PDC_CHASSIS_VER); - create_proc_read_entry("chassis", 0400, NULL, pdc_chassis_warn_pread, - NULL); + proc_create("chassis", 0400, NULL, &pdc_chassis_warn_fops); return 0; } diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index efc5e7d30530..d5cae55195ec 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -138,23 +138,17 @@ static const struct tty_operations pdc_console_tty_ops = { static void pdc_console_poll(unsigned long unused) { int data, count = 0; - struct tty_struct *tty = tty_port_tty_get(&tty_port); - - if (!tty) - return; while (1) { data = pdc_console_poll_key(NULL); if (data == -1) break; - tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL); + tty_insert_flip_char(&tty_port, data & 0xFF, TTY_NORMAL); count ++; } if (count) - tty_flip_buffer_push(tty); - - tty_kref_put(tty); + tty_flip_buffer_push(&tty_port); if (pdc_cons.flags & CON_ENABLED) mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index d13507246c5d..55f92b614182 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -59,28 +59,6 @@ #include <asm/unwind.h> #include <asm/sections.h> -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) -{ - set_thread_flag(TIF_POLLING_NRFLAG); - - /* endless idle loop with no priority at all */ - while (1) { - rcu_idle_enter(); - while (!need_resched()) - barrier(); - rcu_idle_exit(); - schedule_preempt_disabled(); - check_pgt_cache(); - } -} - - #define COMMAND_GLOBAL F_EXTEND(0xfffe0030) #define CMD_RESET 5 /* reset any module */ diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index a3328c2616b0..76b63e726a53 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -129,6 +129,8 @@ void __init setup_arch(char **cmdline_p) printk(KERN_INFO "The 32-bit Kernel has started...\n"); #endif + printk(KERN_INFO "Default page size is %dKB.\n", (int)(PAGE_SIZE / 1024)); + pdc_console_init(); #ifdef CONFIG_64BIT diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index fd051705a407..940188d1942c 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -143,7 +143,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) goto give_sigsegv; DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", usp, &compat_frame->uc.uc_stack); - if (do_sigaltstack32(&compat_frame->uc.uc_stack, NULL, usp) == -EFAULT) + if (compat_restore_altstack(&compat_frame->uc.uc_stack)) goto give_sigsegv; } else #endif @@ -154,7 +154,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) goto give_sigsegv; DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", usp, &frame->uc.uc_stack); - if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT) + if (restore_altstack(&frame->uc.uc_stack)) goto give_sigsegv; } @@ -242,7 +242,6 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, unsigned long haddr, sigframe_size; int err = 0; #ifdef CONFIG_64BIT - compat_int_t compat_val; struct compat_rt_sigframe __user * compat_frame; compat_sigset_t compat_set; #endif @@ -262,15 +261,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, if (is_compat_task()) { DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info); err |= copy_siginfo_to_user32(&compat_frame->info, info); - DBG(1,"SETUP_RT_FRAME: 1\n"); - compat_val = (compat_int_t)current->sas_ss_sp; - err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp); - DBG(1,"SETUP_RT_FRAME: 2\n"); - compat_val = (compat_int_t)current->sas_ss_size; - err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_size); - DBG(1,"SETUP_RT_FRAME: 3\n"); - compat_val = sas_ss_flags(regs->gr[30]); - err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_flags); + err |= __compat_save_altstack( &compat_frame->uc.uc_stack, regs->gr[30]); DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &compat_frame->uc); DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext); err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext, @@ -282,10 +273,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, { DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &frame->info); err |= copy_siginfo_to_user(&frame->info, info); - err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); - err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= __put_user(sas_ss_flags(regs->gr[30]), - &frame->uc.uc_stack.ss_flags); + err |= __save_altstack(&frame->uc.uc_stack, regs->gr[30]); DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &frame->uc); DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &frame->uc.uc_mcontext); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall); @@ -312,7 +300,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, #if DEBUG_SIG /* Assert that we're flushing in the correct space... */ { - int sid; + unsigned long sid; asm ("mfsp %%sr3,%0" : "=r" (sid)); DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n", sid, frame->tramp); diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index 5dede04f2f3e..33eca1b04926 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -60,129 +60,6 @@ sigset_64to32(compat_sigset_t *s32, sigset_t *s64) s32->sig[1] = (s64->sig[0] >> 32) & 0xffffffffUL; } -static int -put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) -{ - compat_sigset_t s; - - if (sz != sizeof *set) - return -EINVAL; - sigset_64to32(&s, set); - - return copy_to_user(up, &s, sizeof s); -} - -static int -get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz) -{ - compat_sigset_t s; - int r; - - if (sz != sizeof *set) - return -EINVAL; - - if ((r = copy_from_user(&s, up, sz)) == 0) { - sigset_32to64(set, &s); - } - - return r; -} - -int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, compat_sigset_t __user *oset, - unsigned int sigsetsize) -{ - sigset_t old_set, new_set; - int ret; - - if (set && get_sigset32(set, &new_set, sigsetsize)) - return -EFAULT; - - KERNEL_SYSCALL(ret, sys_rt_sigprocmask, how, set ? (sigset_t __user *)&new_set : NULL, - oset ? (sigset_t __user *)&old_set : NULL, sigsetsize); - - if (!ret && oset && put_sigset32(oset, &old_set, sigsetsize)) - return -EFAULT; - - return ret; -} - - -int sys32_rt_sigpending(compat_sigset_t __user *uset, unsigned int sigsetsize) -{ - int ret; - sigset_t set; - - KERNEL_SYSCALL(ret, sys_rt_sigpending, (sigset_t __user *)&set, sigsetsize); - - if (!ret && put_sigset32(uset, &set, sigsetsize)) - return -EFAULT; - - return ret; -} - -long -sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, struct sigaction32 __user *oact, - size_t sigsetsize) -{ - struct k_sigaction32 new_sa32, old_sa32; - struct k_sigaction new_sa, old_sa; - int ret = -EINVAL; - - if (act) { - if (copy_from_user(&new_sa32.sa, act, sizeof new_sa32.sa)) - return -EFAULT; - new_sa.sa.sa_handler = (__sighandler_t)(unsigned long)new_sa32.sa.sa_handler; - new_sa.sa.sa_flags = new_sa32.sa.sa_flags; - sigset_32to64(&new_sa.sa.sa_mask, &new_sa32.sa.sa_mask); - } - - ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); - - if (!ret && oact) { - sigset_64to32(&old_sa32.sa.sa_mask, &old_sa.sa.sa_mask); - old_sa32.sa.sa_flags = old_sa.sa.sa_flags; - old_sa32.sa.sa_handler = (__sighandler_t32)(unsigned long)old_sa.sa.sa_handler; - if (copy_to_user(oact, &old_sa32.sa, sizeof old_sa32.sa)) - return -EFAULT; - } - return ret; -} - -int -do_sigaltstack32 (const compat_stack_t __user *uss32, compat_stack_t __user *uoss32, unsigned long sp) -{ - compat_stack_t ss32, oss32; - stack_t ss, oss; - stack_t *ssp = NULL, *ossp = NULL; - int ret; - - if (uss32) { - if (copy_from_user(&ss32, uss32, sizeof ss32)) - return -EFAULT; - - ss.ss_sp = (void __user *)(unsigned long)ss32.ss_sp; - ss.ss_flags = ss32.ss_flags; - ss.ss_size = ss32.ss_size; - - ssp = &ss; - } - - if (uoss32) - ossp = &oss; - - KERNEL_SYSCALL(ret, do_sigaltstack, (const stack_t __user *)ssp, (stack_t __user *)ossp, sp); - - if (!ret && uoss32) { - oss32.ss_sp = (unsigned int)(unsigned long)oss.ss_sp; - oss32.ss_flags = oss.ss_flags; - oss32.ss_size = oss.ss_size; - if (copy_to_user(uoss32, &oss32, sizeof *uoss32)) - return -EFAULT; - } - - return ret; -} - long restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf, struct pt_regs *regs) @@ -499,22 +376,3 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from) } 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/signal32.h b/arch/parisc/kernel/signal32.h index 08a88b5349a2..72ab41a51f32 100644 --- a/arch/parisc/kernel/signal32.h +++ b/arch/parisc/kernel/signal32.h @@ -21,23 +21,6 @@ #include <linux/compat.h> -typedef compat_uptr_t compat_sighandler_t; - -typedef struct compat_sigaltstack { - compat_uptr_t ss_sp; - compat_int_t ss_flags; - compat_size_t ss_size; -} compat_stack_t; - -/* Most things should be clean enough to redefine this at will, if care - is taken to make libc match. */ - -struct compat_sigaction { - compat_sighandler_t sa_handler; - compat_uint_t sa_flags; - compat_sigset_t sa_mask; /* mask last for extensibility */ -}; - /* 32-bit ucontext as seen from an 64-bit kernel */ struct compat_ucontext { compat_uint_t uc_flags; @@ -51,10 +34,6 @@ struct compat_ucontext { /* ELF32 signal handling */ -struct k_sigaction32 { - struct compat_sigaction sa; -}; - int copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from); int copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from); @@ -102,8 +81,6 @@ struct compat_rt_sigframe { void sigset_32to64(sigset_t *s64, compat_sigset_t *s32); void sigset_64to32(compat_sigset_t *s32, sigset_t *s64); -int do_sigaltstack32 (const compat_stack_t __user *uss32, - compat_stack_t __user *uoss32, unsigned long sp); long restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user *rf, struct pt_regs *regs); diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 6266730efd61..e3614fb343e5 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -127,7 +127,7 @@ ipi_interrupt(int irq, void *dev_id) unsigned long flags; /* Count this now; we may make a call that never returns. */ - p->ipi_count++; + inc_irq_stat(irq_call_count); mb(); /* Order interrupt and bit testing. */ @@ -155,6 +155,7 @@ ipi_interrupt(int irq, void *dev_id) case IPI_RESCHEDULE: smp_debug(100, KERN_DEBUG "CPU%d IPI_RESCHEDULE\n", this_cpu); + inc_irq_stat(irq_resched_count); scheduler_ipi(); break; @@ -263,17 +264,6 @@ void arch_send_call_function_single_ipi(int cpu) } /* - * Flush all other CPU's tlb and then mine. Do this with on_each_cpu() - * as we want to ensure all TLB's flushed before proceeding. - */ - -void -smp_flush_tlb_all(void) -{ - on_each_cpu(flush_tlb_all_local, NULL, 1); -} - -/* * Called by secondaries to update state and initialize CPU registers. */ static void __init @@ -329,7 +319,7 @@ void __init smp_callin(void) local_irq_enable(); /* Interrupts have been off until now */ - cpu_idle(); /* Wait for timer to schedule some work */ + cpu_startup_entry(CPUHP_ONLINE); /* NOTREACHED */ panic("smp_callin() AAAAaaaaahhhh....\n"); diff --git a/arch/parisc/kernel/sys32.h b/arch/parisc/kernel/sys32.h index 06c2090cfaba..60dd470f39f8 100644 --- a/arch/parisc/kernel/sys32.h +++ b/arch/parisc/kernel/sys32.h @@ -33,16 +33,4 @@ set_fs (old_fs); \ } -#ifdef CONFIG_COMPAT - -typedef __u32 __sighandler_t32; - -struct sigaction32 { - __sighandler_t32 sa_handler; - unsigned int sa_flags; - compat_sigset_t sa_mask; /* mask last for extensibility */ -}; - -#endif - #endif diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index f76c10863c62..5dfd248e3f1a 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -35,22 +35,17 @@ static unsigned long get_unshared_area(unsigned long addr, unsigned long len) { - struct vm_area_struct *vma; + struct vm_unmapped_area_info info; - addr = PAGE_ALIGN(addr); - - for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { - /* At this point: (!vma || addr < vma->vm_end). */ - if (TASK_SIZE - len < addr) - return -ENOMEM; - if (!vma || addr + len <= vma->vm_start) - return addr; - addr = vma->vm_end; - } + info.flags = 0; + info.length = len; + info.low_limit = PAGE_ALIGN(addr); + info.high_limit = TASK_SIZE; + info.align_mask = 0; + info.align_offset = 0; + return vm_unmapped_area(&info); } -#define DCACHE_ALIGN(addr) (((addr) + (SHMLBA - 1)) &~ (SHMLBA - 1)) - /* * We need to know the offset to use. Old scheme was to look for * existing mapping and use the same offset. New scheme is to use the @@ -63,30 +58,21 @@ static unsigned long get_unshared_area(unsigned long addr, unsigned long len) */ static int get_offset(struct address_space *mapping) { - int offset = (unsigned long) mapping << (PAGE_SHIFT - 8); - return offset & 0x3FF000; + return (unsigned long) mapping >> 8; } static unsigned long get_shared_area(struct address_space *mapping, unsigned long addr, unsigned long len, unsigned long pgoff) { - struct vm_area_struct *vma; - int offset = mapping ? get_offset(mapping) : 0; - - offset = (offset + (pgoff << PAGE_SHIFT)) & 0x3FF000; - - addr = DCACHE_ALIGN(addr - offset) + offset; + struct vm_unmapped_area_info info; - for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { - /* At this point: (!vma || addr < vma->vm_end). */ - if (TASK_SIZE - len < addr) - return -ENOMEM; - if (!vma || addr + len <= vma->vm_start) - return addr; - addr = DCACHE_ALIGN(vma->vm_end - offset) + offset; - if (addr < vma->vm_end) /* handle wraparound */ - return -ENOMEM; - } + info.flags = 0; + info.length = len; + info.low_limit = PAGE_ALIGN(addr); + info.high_limit = TASK_SIZE; + info.align_mask = PAGE_MASK & (SHMLBA - 1); + info.align_offset = (get_offset(mapping) + pgoff) << PAGE_SHIFT; + return vm_unmapped_area(&info); } unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, @@ -94,11 +80,12 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, { if (len > TASK_SIZE) return -ENOMEM; - /* Might want to check for cache aliasing issues for MAP_FIXED case - * like ARM or MIPS ??? --BenH. - */ - if (flags & MAP_FIXED) + if (flags & MAP_FIXED) { + if ((flags & MAP_SHARED) && + (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)) + return -EINVAL; return addr; + } if (!addr) addr = TASK_UNMAPPED_BASE; @@ -212,6 +199,13 @@ asmlinkage long parisc_sync_file_range(int fd, (loff_t)hi_nbytes << 32 | lo_nbytes, flags); } +asmlinkage long parisc_fallocate(int fd, int mode, u32 offhi, u32 offlo, + u32 lenhi, u32 lenlo) +{ + return sys_fallocate(fd, mode, ((u64)offhi << 32) | offlo, + ((u64)lenhi << 32) | lenlo); +} + asmlinkage unsigned long sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag) { return -ENOMEM; diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index 9cfdaa19ab63..a134ff4da12e 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -21,7 +21,6 @@ #include <linux/time.h> #include <linux/smp.h> #include <linux/sem.h> -#include <linux/msg.h> #include <linux/shm.h> #include <linux/slab.h> #include <linux/uio.h> @@ -60,157 +59,3 @@ asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23, current->comm, current->pid, r20); return -ENOSYS; } - -asmlinkage long sys32_sched_rr_get_interval(pid_t pid, - struct compat_timespec __user *interval) -{ - struct timespec t; - int ret; - - KERNEL_SYSCALL(ret, sys_sched_rr_get_interval, pid, (struct timespec __user *)&t); - if (put_compat_timespec(&t, interval)) - return -EFAULT; - return ret; -} - -struct msgbuf32 { - int mtype; - char mtext[1]; -}; - -asmlinkage long sys32_msgsnd(int msqid, - struct msgbuf32 __user *umsgp32, - size_t msgsz, int msgflg) -{ - struct msgbuf *mb; - struct msgbuf32 mb32; - int err; - - if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL) - return -ENOMEM; - - err = get_user(mb32.mtype, &umsgp32->mtype); - mb->mtype = mb32.mtype; - err |= copy_from_user(mb->mtext, &umsgp32->mtext, msgsz); - - if (err) - err = -EFAULT; - else - KERNEL_SYSCALL(err, sys_msgsnd, msqid, (struct msgbuf __user *)mb, msgsz, msgflg); - - kfree(mb); - return err; -} - -asmlinkage long sys32_msgrcv(int msqid, - struct msgbuf32 __user *umsgp32, - size_t msgsz, long msgtyp, int msgflg) -{ - struct msgbuf *mb; - struct msgbuf32 mb32; - int err, len; - - if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL) - return -ENOMEM; - - KERNEL_SYSCALL(err, sys_msgrcv, msqid, (struct msgbuf __user *)mb, msgsz, msgtyp, msgflg); - - if (err >= 0) { - len = err; - mb32.mtype = mb->mtype; - err = put_user(mb32.mtype, &umsgp32->mtype); - err |= copy_to_user(&umsgp32->mtext, mb->mtext, len); - if (err) - err = -EFAULT; - else - err = len; - } - - kfree(mb); - return err; -} - -asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count) -{ - mm_segment_t old_fs = get_fs(); - int ret; - off_t of; - - if (offset && get_user(of, offset)) - return -EFAULT; - - set_fs(KERNEL_DS); - ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count); - set_fs(old_fs); - - if (offset && put_user(of, offset)) - return -EFAULT; - - return ret; -} - -asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count) -{ - mm_segment_t old_fs = get_fs(); - int ret; - loff_t lof; - - if (offset && get_user(lof, offset)) - return -EFAULT; - - set_fs(KERNEL_DS); - ret = sys_sendfile64(out_fd, in_fd, offset ? (loff_t __user *)&lof : NULL, count); - set_fs(old_fs); - - if (offset && put_user(lof, offset)) - return -EFAULT; - - return ret; -} - - -/* lseek() needs a wrapper because 'offset' can be negative, but the top - * half of the argument has been zeroed by syscall.S. - */ - -asmlinkage int sys32_lseek(unsigned int fd, int offset, unsigned int origin) -{ - return sys_lseek(fd, offset, origin); -} - -asmlinkage long sys32_semctl(int semid, int semnum, int cmd, union semun arg) -{ - union semun u; - - if (cmd == SETVAL) { - /* Ugh. arg is a union of int,ptr,ptr,ptr, so is 8 bytes. - * The int should be in the first 4, but our argument - * frobbing has left it in the last 4. - */ - u.val = *((int *)&arg + 1); - return sys_semctl (semid, semnum, cmd, u); - } - return sys_semctl (semid, semnum, cmd, arg); -} - -long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf, - size_t len) -{ - return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low, - buf, len); -} - -asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo, - u32 lenhi, u32 lenlo) -{ - return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo, - ((loff_t)lenhi << 32) | lenlo); -} - -asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi, - u32 mask_lo, int fd, - const char __user *pathname) -{ - return sys_fanotify_mark(fan_fd, flags, ((u64)mask_hi << 32) | mask_lo, - fd, pathname); -} diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 86742df0b194..e767ab733e32 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -1,12 +1,35 @@ /* * Linux/PA-RISC Project (http://www.parisc-linux.org/) * - * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai> + * System call entry code / Linux gateway page + * Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai> * Licensed under the GNU GPL. * thanks to Philipp Rumpf, Mike Shaver and various others * sorry about the wall, puffin.. */ +/* +How does the Linux gateway page on PA-RISC work? +------------------------------------------------ +The Linux gateway page on PA-RISC is "special". +It actually has PAGE_GATEWAY bits set (this is linux terminology; in parisc +terminology it's Execute, promote to PL0) in the page map. So anything +executing on this page executes with kernel level privilege (there's more to it +than that: to have this happen, you also have to use a branch with a ,gate +completer to activate the privilege promotion). The upshot is that everything +that runs on the gateway page runs at kernel privilege but with the current +user process address space (although you have access to kernel space via %sr2). +For the 0x100 syscall entry, we redo the space registers to point to the kernel +address space (preserving the user address space in %sr3), move to wide mode if +required, save the user registers and branch into the kernel syscall entry +point. For all the other functions, we execute at kernel privilege but don't +flip address spaces. The basic upshot of this is that these code snippets are +executed atomically (because the kernel can't be pre-empted) and they may +perform architecturally forbidden (to PL3) operations (like setting control +registers). +*/ + + #include <asm/asm-offsets.h> #include <asm/unistd.h> #include <asm/errno.h> @@ -15,6 +38,7 @@ #include <asm/thread_info.h> #include <asm/assembly.h> #include <asm/processor.h> +#include <asm/cache.h> #include <linux/linkage.h> @@ -309,10 +333,13 @@ tracesys_next: LDREG TASK_PT_GR25(%r1), %r25 LDREG TASK_PT_GR24(%r1), %r24 LDREG TASK_PT_GR23(%r1), %r23 -#ifdef CONFIG_64BIT LDREG TASK_PT_GR22(%r1), %r22 LDREG TASK_PT_GR21(%r1), %r21 +#ifdef CONFIG_64BIT ldo -16(%r30),%r29 /* Reference param save area */ +#else + stw %r22, -52(%r30) /* 5th argument */ + stw %r21, -56(%r30) /* 6th argument */ #endif comiclr,>>= __NR_Linux_syscalls, %r20, %r0 @@ -640,7 +667,7 @@ ENTRY(end_linux_gateway_page) .section .rodata,"a" - .align PAGE_SIZE + .align 8 /* Light-weight-syscall table */ /* Start of lws table. */ ENTRY(lws_table) @@ -649,13 +676,13 @@ ENTRY(lws_table) END(lws_table) /* End of lws table */ - .align PAGE_SIZE + .align 8 ENTRY(sys_call_table) #include "syscall_table.S" END(sys_call_table) #ifdef CONFIG_64BIT - .align PAGE_SIZE + .align 8 ENTRY(sys_call_table64) #define SYSCALL_TABLE_64BIT #include "syscall_table.S" @@ -671,7 +698,7 @@ END(sys_call_table64) with ldcw. */ .section .data - .align PAGE_SIZE + .align L1_CACHE_BYTES ENTRY(lws_lock_start) /* lws locks */ .rept 16 diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 54d950b067b7..0c9107285e66 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -76,7 +76,7 @@ ENTRY_SAME(socket) /* struct stat is MAYBE identical wide and narrow ?? */ ENTRY_COMP(newstat) - ENTRY_DIFF(lseek) + ENTRY_COMP(lseek) ENTRY_SAME(getpid) /* 20 */ /* the 'void * data' parameter may need re-packing in wide */ ENTRY_COMP(mount) @@ -165,8 +165,8 @@ ENTRY_SAME(mmap2) ENTRY_SAME(mmap) /* 90 */ ENTRY_SAME(munmap) - ENTRY_SAME(truncate) - ENTRY_SAME(ftruncate) + ENTRY_COMP(truncate) + ENTRY_COMP(ftruncate) ENTRY_SAME(fchmod) ENTRY_SAME(fchown) /* 95 */ ENTRY_SAME(getpriority) @@ -198,7 +198,7 @@ ENTRY_SAME(madvise) ENTRY_SAME(clone_wrapper) /* 120 */ ENTRY_SAME(setdomainname) - ENTRY_DIFF(sendfile) + ENTRY_COMP(sendfile) /* struct sockaddr... */ ENTRY_SAME(recvfrom) /* struct timex contains longs */ @@ -247,15 +247,12 @@ ENTRY_SAME(sched_yield) ENTRY_SAME(sched_get_priority_max) ENTRY_SAME(sched_get_priority_min) /* 160 */ - /* These 2 would've worked if someone had defined struct timespec - * carefully, like timeval for example (which is about the same). - * Unfortunately it contains a long :-( */ - ENTRY_DIFF(sched_rr_get_interval) + ENTRY_COMP(sched_rr_get_interval) ENTRY_COMP(nanosleep) ENTRY_SAME(mremap) ENTRY_SAME(setresuid) ENTRY_SAME(getresuid) /* 165 */ - ENTRY_DIFF(sigaltstack_wrapper) + ENTRY_COMP(sigaltstack) ENTRY_SAME(ni_syscall) /* query_module */ ENTRY_SAME(poll) /* structs contain pointers and an in_addr... */ @@ -265,9 +262,9 @@ ENTRY_SAME(prctl) /* signals need a careful review */ ENTRY_SAME(rt_sigreturn_wrapper) - ENTRY_DIFF(rt_sigaction) - ENTRY_DIFF(rt_sigprocmask) /* 175 */ - ENTRY_DIFF(rt_sigpending) + ENTRY_COMP(rt_sigaction) + ENTRY_COMP(rt_sigprocmask) /* 175 */ + ENTRY_COMP(rt_sigpending) ENTRY_COMP(rt_sigtimedwait) /* even though the struct siginfo_t is different, it appears like * all the paths use values which should be same wide and narrow. @@ -285,9 +282,9 @@ ENTRY_COMP(recvmsg) ENTRY_SAME(semop) /* 185 */ ENTRY_SAME(semget) - ENTRY_DIFF(semctl) - ENTRY_DIFF(msgsnd) - ENTRY_DIFF(msgrcv) + ENTRY_COMP(semctl) + ENTRY_COMP(msgsnd) + ENTRY_COMP(msgrcv) ENTRY_SAME(msgget) /* 190 */ ENTRY_SAME(msgctl) ENTRY_SAME(shmat) @@ -307,32 +304,32 @@ ENTRY_SAME(gettid) ENTRY_OURS(readahead) ENTRY_SAME(tkill) - ENTRY_SAME(sendfile64) + ENTRY_COMP(sendfile64) ENTRY_COMP(futex) /* 210 */ ENTRY_COMP(sched_setaffinity) ENTRY_COMP(sched_getaffinity) ENTRY_SAME(ni_syscall) /* set_thread_area */ ENTRY_SAME(ni_syscall) /* get_thread_area */ - ENTRY_SAME(io_setup) /* 215 */ + ENTRY_COMP(io_setup) /* 215 */ ENTRY_SAME(io_destroy) - ENTRY_SAME(io_getevents) - ENTRY_SAME(io_submit) + ENTRY_COMP(io_getevents) + ENTRY_COMP(io_submit) ENTRY_SAME(io_cancel) ENTRY_SAME(alloc_hugepages) /* 220 */ ENTRY_SAME(free_hugepages) ENTRY_SAME(exit_group) - ENTRY_DIFF(lookup_dcookie) + ENTRY_COMP(lookup_dcookie) ENTRY_SAME(epoll_create) ENTRY_SAME(epoll_ctl) /* 225 */ ENTRY_SAME(epoll_wait) ENTRY_SAME(remap_file_pages) ENTRY_SAME(semtimedop) - ENTRY_SAME(mq_open) + ENTRY_COMP(mq_open) ENTRY_SAME(mq_unlink) /* 230 */ - ENTRY_SAME(mq_timedsend) - ENTRY_SAME(mq_timedreceive) - ENTRY_SAME(mq_notify) - ENTRY_SAME(mq_getsetattr) + ENTRY_COMP(mq_timedsend) + ENTRY_COMP(mq_timedreceive) + ENTRY_COMP(mq_notify) + ENTRY_COMP(mq_getsetattr) ENTRY_COMP(waitid) /* 235 */ ENTRY_OURS(fadvise64_64) ENTRY_SAME(set_tid_address) @@ -403,7 +400,7 @@ ENTRY_COMP(signalfd) ENTRY_SAME(ni_syscall) /* was timerfd */ ENTRY_SAME(eventfd) - ENTRY_COMP(fallocate) /* 305 */ + ENTRY_OURS(fallocate) /* 305 */ ENTRY_SAME(timerfd_create) ENTRY_COMP(timerfd_settime) ENTRY_COMP(timerfd_gettime) @@ -428,6 +425,10 @@ ENTRY_SAME(syncfs) ENTRY_SAME(setns) ENTRY_COMP(sendmmsg) + ENTRY_COMP(process_vm_readv) /* 330 */ + ENTRY_COMP(process_vm_writev) + ENTRY_SAME(kcmp) + ENTRY_SAME(finit_module) /* Nothing yet */ diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 45ba99f5080b..fe41a98043bb 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -126,6 +126,8 @@ void show_regs(struct pt_regs *regs) user = user_mode(regs); level = user ? KERN_DEBUG : KERN_CRIT; + show_regs_print_info(level); + print_gr(level, regs); for (i = 0; i < 8; i += 4) @@ -158,14 +160,6 @@ void show_regs(struct pt_regs *regs) } } - -void dump_stack(void) -{ - show_stack(NULL, NULL); -} - -EXPORT_SYMBOL(dump_stack); - static void do_show_stack(struct unwind_frame_info *info) { int i = 1; @@ -282,7 +276,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) show_regs(regs); dump_stack(); - add_taint(TAINT_DIE); + add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); if (in_interrupt()) panic("Fatal exception in interrupt"); @@ -528,10 +522,10 @@ void notrace handle_interruption(int code, struct pt_regs *regs) */ if (((unsigned long)regs->iaoq[0] & 3) && ((unsigned long)regs->iasq[0] != (unsigned long)regs->sr[7])) { - /* Kill the user process later */ - regs->iaoq[0] = 0 | 3; + /* Kill the user process later */ + regs->iaoq[0] = 0 | 3; regs->iaoq[1] = regs->iaoq[0] + 4; - regs->iasq[0] = regs->iasq[1] = regs->sr[7]; + regs->iasq[0] = regs->iasq[1] = regs->sr[7]; regs->gr[0] &= ~PSW_B; return; } @@ -547,8 +541,8 @@ void notrace handle_interruption(int code, struct pt_regs *regs) /* set up a new led state on systems shipped with a LED State panel */ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_HPMC); - - parisc_terminate("High Priority Machine Check (HPMC)", + + parisc_terminate("High Priority Machine Check (HPMC)", regs, code, 0); /* NOT REACHED */ @@ -590,13 +584,13 @@ void notrace handle_interruption(int code, struct pt_regs *regs) /* Break instruction trap */ handle_break(regs); return; - + case 10: /* Privileged operation trap */ die_if_kernel("Privileged operation", regs, code); si.si_code = ILL_PRVOPC; goto give_sigill; - + case 11: /* Privileged register trap */ if ((regs->iir & 0xffdfffe0) == 0x034008a0) { @@ -640,7 +634,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs) if(user_mode(regs)){ si.si_signo = SIGFPE; /* Set to zero, and let the userspace app figure it out from - the insn pointed to by si_addr */ + the insn pointed to by si_addr */ si.si_code = 0; si.si_addr = (void __user *) regs->iaoq[0]; force_sig_info(SIGFPE, &si, current); @@ -654,7 +648,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs) die_if_kernel("Floating point exception", regs, 0); /* quiet */ handle_fpe(regs); return; - + case 15: /* Data TLB miss fault/Data page fault */ /* Fall through */ @@ -666,15 +660,15 @@ void notrace handle_interruption(int code, struct pt_regs *regs) case 17: /* Non-access data TLB miss fault/Non-access data page fault */ /* FIXME: - Still need to add slow path emulation code here! - If the insn used a non-shadow register, then the tlb + Still need to add slow path emulation code here! + If the insn used a non-shadow register, then the tlb handlers could not have their side-effect (e.g. probe writing to a target register) emulated since rfir would erase the changes to said register. Instead we have to setup everything, call this function we are in, and emulate by hand. Technically we need to emulate: fdc,fdce,pdc,"fic,4f",prober,probeir,probew, probeiw - */ + */ fault_address = regs->ior; fault_space = regs->isr; break; diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 64a999882e4f..4bb095a2f6fc 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -95,7 +95,7 @@ SECTIONS NOTES /* Data */ - RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) + RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, PAGE_SIZE) /* PA-RISC locks requires 16-byte alignment */ . = ALIGN(16); diff --git a/arch/parisc/lib/Makefile b/arch/parisc/lib/Makefile index 5f2e6904d14a..5651536ac733 100644 --- a/arch/parisc/lib/Makefile +++ b/arch/parisc/lib/Makefile @@ -2,6 +2,7 @@ # Makefile for parisc-specific library files # -lib-y := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o memcpy.o +lib-y := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o memcpy.o \ + ucmpdi2.o obj-y := iomap.o diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c index 1dbca5c31b3c..a49cc812df8a 100644 --- a/arch/parisc/lib/memcpy.c +++ b/arch/parisc/lib/memcpy.c @@ -68,7 +68,7 @@ DECLARE_PER_CPU(struct exception_data, exception_data); #define preserve_branch(label) do { \ - volatile int dummy; \ + volatile int dummy = 0; \ /* The following branch is never taken, it's just here to */ \ /* prevent gcc from optimizing away our exception code. */ \ if (unlikely(dummy != dummy)) \ diff --git a/arch/parisc/lib/ucmpdi2.c b/arch/parisc/lib/ucmpdi2.c new file mode 100644 index 000000000000..149c016f32c5 --- /dev/null +++ b/arch/parisc/lib/ucmpdi2.c @@ -0,0 +1,25 @@ +#include <linux/module.h> + +union ull_union { + unsigned long long ull; + struct { + unsigned int high; + unsigned int low; + } ui; +}; + +int __ucmpdi2(unsigned long long a, unsigned long long b) +{ + union ull_union au = {.ull = a}; + union ull_union bu = {.ull = b}; + + if (au.ui.high < bu.ui.high) + return 0; + else if (au.ui.high > bu.ui.high) + return 2; + if (au.ui.low < bu.ui.low) + return 0; + else if (au.ui.low > bu.ui.low) + return 2; + return 1; +} diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 18162ce4261e..f247a3480e8e 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -175,10 +175,12 @@ void do_page_fault(struct pt_regs *regs, unsigned long code, struct mm_struct *mm = tsk->mm; unsigned long acc_type; int fault; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; if (in_atomic() || !mm) goto no_context; +retry: down_read(&mm->mmap_sem); vma = find_vma_prev(mm, address, &prev_vma); if (!vma || address < vma->vm_start) @@ -201,7 +203,12 @@ good_area: * fault. */ - fault = handle_mm_fault(mm, vma, address, (acc_type & VM_WRITE) ? FAULT_FLAG_WRITE : 0); + fault = handle_mm_fault(mm, vma, address, + flags | ((acc_type & VM_WRITE) ? FAULT_FLAG_WRITE : 0)); + + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { /* * We hit a shared mapping outside of the file, or some @@ -214,10 +221,23 @@ good_area: goto bad_area; BUG(); } - if (fault & VM_FAULT_MAJOR) - current->maj_flt++; - else - current->min_flt++; + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) + current->maj_flt++; + else + current->min_flt++; + if (fault & VM_FAULT_RETRY) { + flags &= ~FAULT_FLAG_ALLOW_RETRY; + + /* + * No need to up_read(&mm->mmap_sem) as we would + * have already released it in __lock_page_or_retry + * in mm/filemap.c. + */ + + goto retry; + } + } up_read(&mm->mmap_sem); return; diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 3ac462de53a4..ce939ac8622b 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -505,7 +505,6 @@ static void __init map_pages(unsigned long start_vaddr, void free_initmem(void) { - unsigned long addr; unsigned long init_begin = (unsigned long)__init_begin; unsigned long init_end = (unsigned long)__init_end; @@ -533,19 +532,10 @@ void free_initmem(void) * pages are no-longer executable */ flush_icache_range(init_begin, init_end); - for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) { - ClearPageReserved(virt_to_page(addr)); - init_page_count(virt_to_page(addr)); - free_page(addr); - num_physpages++; - totalram_pages++; - } + num_physpages += free_initmem_default(0); /* set up a new led state on systems shipped LED State panel */ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE); - - printk(KERN_INFO "Freeing unused kernel memory: %luk freed\n", - (init_end - init_begin) >> 10); } @@ -697,6 +687,8 @@ void show_mem(unsigned int filter) printk(KERN_INFO "Mem-info:\n"); show_free_areas(filter); + if (filter & SHOW_MEM_FILTER_PAGE_COUNT) + return; #ifndef CONFIG_DISCONTIGMEM i = max_mapnr; while (i-- > 0) { @@ -1077,6 +1069,7 @@ void flush_tlb_all(void) { int do_recycle; + inc_irq_stat(irq_tlb_count); do_recycle = 0; spin_lock(&sid_lock); if (dirty_space_ids > RECYCLE_THRESHOLD) { @@ -1097,6 +1090,7 @@ void flush_tlb_all(void) #else void flush_tlb_all(void) { + inc_irq_stat(irq_tlb_count); spin_lock(&sid_lock); flush_tlb_all_local(NULL); recycle_sids(); @@ -1107,15 +1101,6 @@ void flush_tlb_all(void) #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - if (start >= end) - return; - printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10); - for (; start < end; start += PAGE_SIZE) { - ClearPageReserved(virt_to_page(start)); - init_page_count(virt_to_page(start)); - free_page(start); - num_physpages++; - totalram_pages++; - } + num_physpages += free_reserved_area(start, end, 0, "initrd"); } #endif |