From 64f495323c9a902b3e59fe0a588585102bb3b13e Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sat, 22 Apr 2006 00:48:22 -0600 Subject: [PATCH 01/23] [PARISC] Ensure all ldcw uses are ldcw,co on pa2.0 ldcw,co should always be used on pa2.0, otherwise the strict cache width alignment requirement is not relaxed. Signed-off-by: Kyle McMartin --- arch/parisc/kernel/entry.S | 6 +++--- arch/parisc/kernel/syscall.S | 2 +- include/asm-parisc/assembly.h | 2 ++ include/asm-parisc/system.h | 26 ++++++++++++++------------ 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index d9e53cf0372b..630730c32a5a 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -1638,7 +1638,7 @@ dbit_trap_20w: load32 PA(pa_dbit_lock),t0 dbit_spin_20w: - ldcw 0(t0),t1 + LDCW 0(t0),t1 cmpib,= 0,t1,dbit_spin_20w nop @@ -1674,7 +1674,7 @@ dbit_trap_11: load32 PA(pa_dbit_lock),t0 dbit_spin_11: - ldcw 0(t0),t1 + LDCW 0(t0),t1 cmpib,= 0,t1,dbit_spin_11 nop @@ -1714,7 +1714,7 @@ dbit_trap_20: load32 PA(pa_dbit_lock),t0 dbit_spin_20: - ldcw 0(t0),t1 + LDCW 0(t0),t1 cmpib,= 0,t1,dbit_spin_20 nop diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 479d9a017cd1..a028c990cbff 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -541,7 +541,7 @@ cas_nocontend: # endif /* ENABLE_LWS_DEBUG */ - ldcw 0(%sr2,%r20), %r28 /* Try to acquire the lock */ + LDCW 0(%sr2,%r20), %r28 /* Try to acquire the lock */ cmpb,<>,n %r0, %r28, cas_action /* Did we get it? */ cas_wouldblock: ldo 2(%r0), %r28 /* 2nd case */ diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h index 3ce3440d1b0c..1a7bfe699e0c 100644 --- a/include/asm-parisc/assembly.h +++ b/include/asm-parisc/assembly.h @@ -48,6 +48,7 @@ #define CALLEE_SAVE_FRAME_SIZE (CALLEE_REG_FRAME_SIZE + CALLEE_FLOAT_FRAME_SIZE) #ifdef CONFIG_PA20 +#define LDCW ldcw,co #define BL b,l # ifdef CONFIG_64BIT # define LEVEL 2.0w @@ -55,6 +56,7 @@ # define LEVEL 2.0 # endif #else +#define LDCW ldcw #define BL bl #define LEVEL 1.1 #endif diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h index 863876134b2c..5fe2d2329ab5 100644 --- a/include/asm-parisc/system.h +++ b/include/asm-parisc/system.h @@ -155,13 +155,14 @@ static inline void set_eiem(unsigned long val) type and dynamically select the 16-byte aligned int from the array for the semaphore. */ -#define __PA_LDCW_ALIGNMENT 16 -#define __ldcw_align(a) ({ \ - unsigned long __ret = (unsigned long) &(a)->lock[0]; \ - __ret = (__ret + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); \ - (volatile unsigned int *) __ret; \ +#define __PA_LDCW_ALIGNMENT 16 +#define __ldcw_align(a) ({ \ + unsigned long __ret = (unsigned long) &(a)->lock[0]; \ + __ret = (__ret + __PA_LDCW_ALIGNMENT - 1) \ + & ~(__PA_LDCW_ALIGNMENT - 1); \ + (volatile unsigned int *) __ret; \ }) -#define LDCW "ldcw" +#define __LDCW "ldcw" #else /*CONFIG_PA20*/ /* From: "Jim Hull" @@ -171,17 +172,18 @@ static inline void set_eiem(unsigned long val) they only require "natural" alignment (4-byte for ldcw, 8-byte for ldcd). */ -#define __PA_LDCW_ALIGNMENT 4 +#define __PA_LDCW_ALIGNMENT 4 #define __ldcw_align(a) ((volatile unsigned int *)a) -#define LDCW "ldcw,co" +#define __LDCW "ldcw,co" #endif /*!CONFIG_PA20*/ /* LDCW, the only atomic read-write operation PA-RISC has. *sigh*. */ -#define __ldcw(a) ({ \ - unsigned __ret; \ - __asm__ __volatile__(LDCW " 0(%1),%0" : "=r" (__ret) : "r" (a)); \ - __ret; \ +#define __ldcw(a) ({ \ + unsigned __ret; \ + __asm__ __volatile__(__LDCW " 0(%1),%0" \ + : "=r" (__ret) : "r" (a)); \ + __ret; \ }) #ifdef CONFIG_SMP From c8224e0074f1dce12e95e53ca469f6fe49cc9101 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 21 Apr 2006 02:20:37 +0000 Subject: [PATCH 02/23] [PARISC] Whitespace clean up in asm/pgtable.h Signed-off-by: Kyle McMartin --- include/asm-parisc/pgtable.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h index b6bcc672ba80..5066c54dae0a 100644 --- a/include/asm-parisc/pgtable.h +++ b/include/asm-parisc/pgtable.h @@ -506,13 +506,13 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, /* TLB page size encoding - see table 3-1 in parisc20.pdf */ #define _PAGE_SIZE_ENCODING_4K 0 -#define _PAGE_SIZE_ENCODING_16K 1 -#define _PAGE_SIZE_ENCODING_64K 2 +#define _PAGE_SIZE_ENCODING_16K 1 +#define _PAGE_SIZE_ENCODING_64K 2 #define _PAGE_SIZE_ENCODING_256K 3 #define _PAGE_SIZE_ENCODING_1M 4 #define _PAGE_SIZE_ENCODING_4M 5 -#define _PAGE_SIZE_ENCODING_16M 6 -#define _PAGE_SIZE_ENCODING_64M 7 +#define _PAGE_SIZE_ENCODING_16M 6 +#define _PAGE_SIZE_ENCODING_64M 7 #if defined(CONFIG_PARISC_PAGE_SIZE_4KB) # define _PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_4K From 3fd3a74f45c935f7d6d5c2fb48f06324b18826b7 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Sat, 22 Apr 2006 14:47:21 -0600 Subject: [PATCH 03/23] [PARISC] Use FIXUP_BRANCH_CLOBBER to asm clobber list Joel Soete noticed correctly that the fixup's clobbers must be listed as the ASM clobbers. FIXUP_BRANCH in unaligned.c has a new macro which lists all the clobbers in the fixup, we use this throughout the file to simplify the process of listing clobbers in the future. A missing "r1" clobber is added to our uaccess.h for the 64-bit __put_kernel_asm. Interestingly this is a pretty serious bug since gcc generates pretty good use of r1 as a temporary and the uses of __put_kernel_asm are varied and dangerous if r1 is scratched during an invalid write. Signed-off-by: Joel Soete Signed-off-by: Carlos O'Donell Signed-off-by: Kyle McMartin --- arch/parisc/kernel/unaligned.c | 18 ++++++++++-------- include/asm-parisc/uaccess.h | 9 +++++++-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index de0a1b21cb40..92328fbddb3e 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -43,6 +43,8 @@ "\tldil L%%" #lbl ", %%r1\n" \ "\tldo R%%" #lbl "(%%r1), %%r1\n" \ "\tbv,n %%r0(%%r1)\n" +/* If you use FIXUP_BRANCH, then you must list this clobber */ +#define FIXUP_BRANCH_CLOBBER "r1" /* 1111 1100 0000 0000 0001 0011 1100 0000 */ #define OPCODE1(a,b,c) ((a)<<26|(b)<<12|(c)<<6) @@ -157,7 +159,7 @@ static int emulate_ldh(struct pt_regs *regs, int toreg) " .previous\n" : "=r" (val), "=r" (ret) : "0" (val), "r" (saddr), "r" (regs->isr) - : "r20" ); + : "r20", FIXUP_BRANCH_CLOBBER ); DPRINTF("val = 0x" RFMT "\n", val); @@ -202,7 +204,7 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop) " .previous\n" : "=r" (val), "=r" (ret) : "0" (val), "r" (saddr), "r" (regs->isr) - : "r19", "r20" ); + : "r19", "r20", FIXUP_BRANCH_CLOBBER ); DPRINTF("val = 0x" RFMT "\n", val); @@ -253,7 +255,7 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) " .previous\n" : "=r" (val), "=r" (ret) : "0" (val), "r" (saddr), "r" (regs->isr) - : "r19", "r20" ); + : "r19", "r20", FIXUP_BRANCH_CLOBBER ); #else { unsigned long valh=0,vall=0; @@ -287,7 +289,7 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop) " .previous\n" : "=r" (valh), "=r" (vall), "=r" (ret) : "0" (valh), "1" (vall), "r" (saddr), "r" (regs->isr) - : "r19", "r20" ); + : "r19", "r20", FIXUP_BRANCH_CLOBBER ); val=((__u64)valh<<32)|(__u64)vall; } #endif @@ -335,7 +337,7 @@ static int emulate_sth(struct pt_regs *regs, int frreg) " .previous\n" : "=r" (ret) : "r" (val), "r" (regs->ior), "r" (regs->isr) - : "r19" ); + : "r19", FIXUP_BRANCH_CLOBBER ); return ret; } @@ -389,7 +391,7 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop) " .previous\n" : "=r" (ret) : "r" (val), "r" (regs->ior), "r" (regs->isr) - : "r19", "r20", "r21", "r22", "r1" ); + : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER ); return 0; } @@ -450,7 +452,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) " .previous\n" : "=r" (ret) : "r" (val), "r" (regs->ior), "r" (regs->isr) - : "r19", "r20", "r21", "r22", "r1" ); + : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER ); #else { unsigned long valh=(val>>32),vall=(val&0xffffffffl); @@ -495,7 +497,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop) " .previous\n" : "=r" (ret) : "r" (valh), "r" (vall), "r" (regs->ior), "r" (regs->isr) - : "r19", "r20", "r21", "r1" ); + : "r19", "r20", "r21", "r1", FIXUP_BRANCH_CLOBBER ); } #endif diff --git a/include/asm-parisc/uaccess.h b/include/asm-parisc/uaccess.h index f6c417c8c484..d973e8b3466c 100644 --- a/include/asm-parisc/uaccess.h +++ b/include/asm-parisc/uaccess.h @@ -172,7 +172,11 @@ struct exception_data { /* * The "__put_user/kernel_asm()" macros tell gcc they read from memory * instead of writing. This is because they do not write to any memory - * gcc knows about, so there are no aliasing issues. + * gcc knows about, so there are no aliasing issues. These macros must + * also be aware that "fixup_put_user_skip_[12]" are executed in the + * context of the fault, and any registers used there must be listed + * as clobbers. In this case only "r1" is used by the current routines. + * r8/r9 are already listed as err/val. */ #ifdef __LP64__ @@ -183,7 +187,8 @@ struct exception_data { "\t.dword\t1b,fixup_put_user_skip_1\n" \ "\t.previous" \ : "=r"(__pu_err) \ - : "r"(ptr), "r"(x), "0"(__pu_err)) + : "r"(ptr), "r"(x), "0"(__pu_err) \ + : "r1") #define __put_user_asm(stx,x,ptr) \ __asm__ __volatile__ ( \ From 40d78de1aced7e0f3ce112698d847adcc643efdf Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Thu, 11 May 2006 00:31:31 -0600 Subject: [PATCH 04/23] [PARISC] Fix gcc 4.1 warnings in sba_iommu.c Clean up gcc 4.1 warnings noted by Joel Soete. Kyle McMartin gets kudos for pointing out the issues. Matthew Wilcox noticed sba_iommu was using open coded versions of (read|write)X. Signed-off-by: Grant Grundler Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- drivers/parisc/sba_iommu.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 278f325021ee..49b617551195 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -316,10 +316,10 @@ static int reserve_sba_gart = 1; ** ** Superdome (in particular, REO) allows only 64-bit CSR accesses. */ -#define READ_REG32(addr) le32_to_cpu(__raw_readl(addr)) -#define READ_REG64(addr) le64_to_cpu(__raw_readq(addr)) -#define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr) -#define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr) +#define READ_REG32(addr) readl(addr) +#define READ_REG64(addr) readq(addr) +#define WRITE_REG32(val, addr) writel((val), (addr)) +#define WRITE_REG64(val, addr) writeq((val), (addr)) #ifdef CONFIG_64BIT #define READ_REG(addr) READ_REG64(addr) @@ -1427,7 +1427,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) iov_order = get_order(iova_space_size >> (IOVP_SHIFT - PAGE_SHIFT)); ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64); - DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits)\n", + DBG_INIT("%s() hpa 0x%p IOV %dMB (%d bits)\n", __FUNCTION__, ioc->ioc_hpa, iova_space_size >> 20, iov_order + PAGE_SHIFT); @@ -1764,7 +1764,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, sba_dev->num_ioc = num_ioc; for (i = 0; i < num_ioc; i++) { - unsigned long ioc_hpa = sba_dev->ioc[i].ioc_hpa; + void __iomem *ioc_hpa = sba_dev->ioc[i].ioc_hpa; unsigned int j; for (j=0; j < sizeof(u64) * ROPES_PER_IOC; j+=sizeof(u64)) { @@ -1776,7 +1776,8 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, * Improves netperf UDP_STREAM by ~10% for bcm5701. */ if (IS_PLUTO(sba_dev->iodc)) { - unsigned long rope_cfg, cfg_val; + void __iomem *rope_cfg; + unsigned long cfg_val; rope_cfg = ioc_hpa + IOC_ROPE0_CFG + j; cfg_val = READ_REG(rope_cfg); From 692086e0b3ca9a6cb876b901bfa87717044cb20f Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 30 May 2006 17:50:29 +0000 Subject: [PATCH 05/23] [PARISC] Test ioc_needs_fdc variable instead of open coding Some debugging code in sba_iommu.c should be testing ioc_needs_fdc, not directly testing boot_cpu_data. Signed-off-by: Kyle McMartin --- drivers/parisc/sba_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 49b617551195..d09e39e39c60 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1903,7 +1903,7 @@ sba_common_init(struct sba_device *sba_dev) * (bit #61, big endian), we have to flush and sync every time * IO-PDIR is changed in Ike/Astro. */ - if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) { + if (ioc_needs_fdc) { printk(KERN_INFO MODULE_NAME " FDC/SYNC required.\n"); } else { printk(KERN_INFO MODULE_NAME " IOC has cache coherent PDIR.\n"); From 7514b7a500411faa1c2ff1d5dc3198b855f5cdcc Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 25 May 2006 16:22:30 +0000 Subject: [PATCH 06/23] [PARISC] Remove dead function pc_in_user_space This code has been crufting up the file without any use for quite a long time, so let's kill it. Signed-off-by: Kyle McMartin --- arch/parisc/kernel/real2.S | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S index 8c2859cca77e..453d01a9f971 100644 --- a/arch/parisc/kernel/real2.S +++ b/arch/parisc/kernel/real2.S @@ -276,15 +276,6 @@ r64_ret: #endif - .export pc_in_user_space - .text - /* Doesn't belong here but I couldn't find a nicer spot. */ - /* Should never get called, only used by profile stuff in time.c */ -pc_in_user_space: - bv,n 0(%rp) - nop - - .export __canonicalize_funcptr_for_compare .text /* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html From 1b6d1b5e073ad9313ad64da49dff649f5c06e546 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 19 May 2006 20:18:17 +0000 Subject: [PATCH 07/23] [PARISC] Use MFIA in current_text_addr on pa2.0 processors Signed-off-by: Kyle McMartin --- include/asm-parisc/processor.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h index ca49dc91f4fc..b73626f040da 100644 --- a/include/asm-parisc/processor.h +++ b/include/asm-parisc/processor.h @@ -26,14 +26,12 @@ * Default implementation of macro that returns current * instruction pointer ("program counter"). */ - -/* We cannot use MFIA as it was added for PA2.0 - prumpf - - At one point there were no "0f/0b" type local symbols in gas for - PA-RISC. This is no longer true, but this still seems like the - nicest way to implement this. */ - -#define current_text_addr() ({ void *pc; __asm__("\n\tblr 0,%0\n\tnop":"=r" (pc)); pc; }) +#ifdef CONFIG_PA20 +#define current_ia(x) __asm__("mfia %0" : "=r"(x)) +#else /* mfia added in pa2.0 */ +#define current_ia(x) __asm__("blr 0,%0\n\tnop" : "=r"(x)) +#endif +#define current_text_addr() ({ void *pc; current_ia(pc); pc; }) #define TASK_SIZE (current->thread.task_size) #define TASK_UNMAPPED_BASE (current->thread.map_base) From c95f2e5f2f6f61d734a025414c9eb81872a5c831 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Wed, 21 Jun 2006 03:43:52 +0000 Subject: [PATCH 08/23] [PARISC] Remove unconditional #define PIC in syscall macros Signed-off-by: Carlos O'Donell Signed-off-by: Kyle McMartin --- include/asm-parisc/unistd.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h index 12b867238a47..27bcfad1c3e3 100644 --- a/include/asm-parisc/unistd.h +++ b/include/asm-parisc/unistd.h @@ -797,11 +797,6 @@ #define SYS_ify(syscall_name) __NR_##syscall_name -/* Assume all syscalls are done from PIC code just to be - * safe. The worst case scenario is that you lose a register - * and save/restore r19 across the syscall. */ -#define PIC - #ifndef ASM_LINE_SEP # define ASM_LINE_SEP ; #endif From 8ffaeaf42e91930888df09d696a8a6ebe056d0e0 Mon Sep 17 00:00:00 2001 From: Thibaut Varene Date: Wed, 3 May 2006 17:27:35 -0600 Subject: [PATCH 09/23] [PARISC] PDC_CHASSIS is implemented on all machines This patch removes a limitation of the original code, so that CHASSIS codes can be sent to all machines. On machines with a LCD panel, this code displays "INI" during bootup, "RUN" when the system is booted and running, "FLT" when a panic occurs, etc. This part of the code can be enabled/disabled through CONFIG_PDC_CHASSIS This patch also adds minimalistic support for Chassis warnings, through a proc entry '/proc/chassis', which will reflect the warnings status (PSU or fans failure when they happen, NVRAM battery level and temperature thresholds overflows). This part of the code can be enabled/disabled through CONFIG_PDC_CHASSIS_WARN Signed-off-by: Thibaut VARENE Signed-off-by: Kyle McMartin --- arch/parisc/kernel/firmware.c | 22 ++++++++-- arch/parisc/kernel/pdc_chassis.c | 73 +++++++++++++++++++++++++++----- drivers/parisc/Kconfig | 33 ++++++++++++--- include/asm-parisc/pdc.h | 1 + 4 files changed, 107 insertions(+), 22 deletions(-) diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 2dc06b8e1817..0596f27340cc 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -11,7 +11,7 @@ * Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy) * Copyright 2003 Grant Grundler * Copyright 2003,2004 Ryan Bradetich - * Copyright 2004 Thibaut VARENE + * Copyright 2004,2006 Thibaut VARENE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -252,10 +252,8 @@ int pdc_pat_chassis_send_log(unsigned long state, unsigned long data) #endif /** - * pdc_chassis_disp - Updates display + * pdc_chassis_disp - Updates chassis code * @retval: -1 on error, 0 on success - * - * Works on old PDC only (E class, others?) */ int pdc_chassis_disp(unsigned long disp) { @@ -268,6 +266,22 @@ int pdc_chassis_disp(unsigned long disp) return retval; } +/** + * pdc_chassis_warn - Fetches chassis warnings + * @retval: -1 on error, 0 on success + */ +int pdc_chassis_warn(unsigned long *warn) +{ + int retval = 0; + + spin_lock_irq(&pdc_lock); + retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(pdc_result)); + *warn = pdc_result[0]; + spin_unlock_irq(&pdc_lock); + + return retval; +} + /** * pdc_coproc_cfg - To identify coprocessors attached to the processor. * @pdc_coproc_info: Return buffer address. diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c index a45e2e2ffd9f..51e86c0365c1 100644 --- a/arch/parisc/kernel/pdc_chassis.c +++ b/arch/parisc/kernel/pdc_chassis.c @@ -1,8 +1,8 @@ /* - * interfaces to log Chassis Codes via PDC (firmware) + * interfaces to Chassis Codes via PDC (firmware) * * Copyright (C) 2002 Laurent Canet - * Copyright (C) 2002-2004 Thibaut VARENE + * Copyright (C) 2002-2006 Thibaut VARENE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as @@ -16,6 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: poll chassis warns, trigger (configurable) machine shutdown when + * needed. */ #undef PDC_CHASSIS_DEBUG @@ -30,6 +33,7 @@ #include #include #include +#include #include #include @@ -38,7 +42,6 @@ #ifdef CONFIG_PDC_CHASSIS -static int pdc_chassis_old __read_mostly = 0; static unsigned int pdc_chassis_enabled __read_mostly = 1; @@ -64,7 +67,7 @@ __setup("pdcchassis=", pdc_chassis_setup); * Currently, only E class and A180 are known to work with this. * Inspired by Christoph Plattner */ - +#if 0 static void __init pdc_chassis_checkold(void) { switch(CPU_HVERSION) { @@ -73,7 +76,6 @@ static void __init pdc_chassis_checkold(void) case 0x482: /* E45 */ case 0x483: /* E55 */ case 0x516: /* A180 */ - pdc_chassis_old = 1; break; default: @@ -81,7 +83,7 @@ static void __init pdc_chassis_checkold(void) } DPRINTK(KERN_DEBUG "%s: pdc_chassis_checkold(); pdc_chassis_old = %d\n", __FILE__, pdc_chassis_old); } - +#endif /** * pdc_chassis_panic_event() - Called by the panic handler. @@ -136,14 +138,13 @@ void __init parisc_pdc_chassis_init(void) DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__); /* Let see if we have something to handle... */ - /* Check for PDC_PAT or old LED Panel */ - pdc_chassis_checkold(); + /* Check for PDC_PAT */ if (is_pdc_pat()) { printk(KERN_INFO "Enabling PDC_PAT chassis codes support.\n"); handle = 1; } - else if (unlikely(pdc_chassis_old)) { - printk(KERN_INFO "Enabling old style chassis LED panel support.\n"); + else { + printk(KERN_INFO "Enabling regular chassis codes support.\n"); handle = 1; } @@ -215,9 +216,12 @@ int pdc_chassis_send_status(int message) } } else retval = -1; #else - if (unlikely(pdc_chassis_old)) { + if (1) { switch (message) { case PDC_CHASSIS_DIRECT_BSTART: + retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_INIT)); + break; + case PDC_CHASSIS_DIRECT_BCOMPLETE: retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN)); break; @@ -244,3 +248,50 @@ int pdc_chassis_send_status(int message) #endif /* CONFIG_PDC_CHASSIS */ return retval; } + +#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) +{ + char *out = page; + int len, ret; + unsigned long warn; + u32 warnreg; + + ret = pdc_chassis_warn(&warn); + if (ret != 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; +} + +static int __init pdc_chassis_create_procfs(void) +{ + printk(KERN_INFO "Enabling PDC chassis warnings support.\n"); + create_proc_read_entry("chassis", 0400, NULL, pdc_chassis_warn_pread, + NULL); + return 0; +} + +__initcall(pdc_chassis_create_procfs); + +#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_PDC_CHASSIS_WARN */ diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig index 3f5de867acd7..1d3b84b4af3f 100644 --- a/drivers/parisc/Kconfig +++ b/drivers/parisc/Kconfig @@ -140,18 +140,37 @@ config CHASSIS_LCD_LED If unsure, say Y. config PDC_CHASSIS - bool "PDC chassis State Panel support" + bool "PDC chassis state codes support" default y help - Say Y here if you want to enable support for the LED State front - panel as found on E class, and support for the GSP Virtual Front - Panel (LED State and message logging) as found on high end - servers such as A, L and N-class. - - This has nothing to do with Chassis LCD and LED support. + Say Y here if you want to enable support for Chassis codes. + That includes support for LED State front panel as found on E + class, and support for the GSP Virtual Front Panel (LED State and + message logging) as found on high end servers such as A, L and + N-class. + This driver will also display progress messages on LCD display, + such as "INI", "RUN" and "FLT", and might thus clobber messages + shown by the LED/LCD driver. + This driver updates the state panel (LED and/or LCD) upon system + state change (eg: boot, shutdown or panic). If unsure, say Y. + +config PDC_CHASSIS_WARN + bool "PDC chassis warnings support" + depends on PROC_FS + default y + help + Say Y here if you want to enable support for Chassis warnings. + This will add a proc entry '/proc/chassis' giving some information + about the overall health state of the system. + This includes NVRAM battery level, overtemp or failures such as + fans or power units. + + If unsure, say Y. + + config PDC_STABLE tristate "PDC Stable Storage support" depends on SYSFS diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h index 08364f957e7a..7d8a71a28546 100644 --- a/include/asm-parisc/pdc.h +++ b/include/asm-parisc/pdc.h @@ -719,6 +719,7 @@ void setup_pdc(void); /* in inventory.c */ int pdc_add_valid(unsigned long address); int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len); int pdc_chassis_disp(unsigned long disp); +int pdc_chassis_warn(unsigned long *warn); int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info); int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index, void *iodc_data, unsigned int iodc_data_size); From 9b0703fed7ca1af95d4454f45e2f25733f0afa76 Mon Sep 17 00:00:00 2001 From: Thibaut Varene Date: Thu, 4 May 2006 09:29:32 -0600 Subject: [PATCH 10/23] [PARISC] Work around machines which do not support chassis warnings pdc_chassis v0.05: Some machines seems not to implement Chassis warn support. Work around these. Also cleanup a bit of the code. Signed-off-by: Thibaut VARENE Signed-off-by: Kyle McMartin --- arch/parisc/kernel/pdc_chassis.c | 40 ++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c index 51e86c0365c1..d47ba1aa8253 100644 --- a/arch/parisc/kernel/pdc_chassis.c +++ b/arch/parisc/kernel/pdc_chassis.c @@ -19,6 +19,7 @@ * * TODO: poll chassis warns, trigger (configurable) machine shutdown when * needed. + * Find out how to get Chassis warnings out of PAT boxes? */ #undef PDC_CHASSIS_DEBUG @@ -40,6 +41,7 @@ #include #include +#define PDC_CHASSIS_VER "0.05" #ifdef CONFIG_PDC_CHASSIS static unsigned int pdc_chassis_enabled __read_mostly = 1; @@ -133,29 +135,20 @@ static struct notifier_block pdc_chassis_reboot_block = { void __init parisc_pdc_chassis_init(void) { #ifdef CONFIG_PDC_CHASSIS - int handle = 0; if (likely(pdc_chassis_enabled)) { DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__); /* Let see if we have something to handle... */ - /* Check for PDC_PAT */ - if (is_pdc_pat()) { - printk(KERN_INFO "Enabling PDC_PAT chassis codes support.\n"); - handle = 1; - } - else { - printk(KERN_INFO "Enabling regular chassis codes support.\n"); - handle = 1; - } + printk(KERN_INFO "Enabling %s chassis codes support v%s\n", + is_pdc_pat() ? "PDC_PAT" : "regular", + PDC_CHASSIS_VER); - if (handle) { - /* initialize panic notifier chain */ - atomic_notifier_chain_register(&panic_notifier_list, - &pdc_chassis_panic_block); + /* initialize panic notifier chain */ + atomic_notifier_chain_register(&panic_notifier_list, + &pdc_chassis_panic_block); - /* initialize reboot notifier chain */ - register_reboot_notifier(&pdc_chassis_reboot_block); - } + /* initialize reboot notifier chain */ + register_reboot_notifier(&pdc_chassis_reboot_block); } #endif /* CONFIG_PDC_CHASSIS */ } @@ -285,7 +278,18 @@ static int pdc_chassis_warn_pread(char *page, char **start, off_t off, static int __init pdc_chassis_create_procfs(void) { - printk(KERN_INFO "Enabling PDC chassis warnings support.\n"); + unsigned long test; + int ret; + + ret = pdc_chassis_warn(&test); + if ((ret == PDC_BAD_PROC) || (ret == PDC_BAD_OPTION)) { + /* seems that some boxes (eg L1000) do not implement this */ + printk(KERN_INFO "Chassis warnings not supported.\n"); + return 0; + } + + 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); return 0; From 3f9edb53f74b4e18f92783da7b6f5ad1d36e05b2 Mon Sep 17 00:00:00 2001 From: Thibaut Varene Date: Thu, 4 May 2006 18:43:34 -0600 Subject: [PATCH 11/23] [PARISC] pdc_stable version 0.30 pdc_stable v0.30: This patch introduces 3 more files to the /sys/firmware/stable tree: - diagnostic, which contains a cryptic hex string - osdep1, a 16 bytes os-dependent storage area always available - osdep2, another os-dependent storage area which existence/size depends on hversion. This patch also adds code to setup the "Linux" signature in stable storage. That is to say that starting with this patch, the kernel will now sign its OSID (0x0006, thx LaMont) in Stable Storage upon boot, whether pdc_stable is enabled or not. Signed-off-by: Thibaut VARENE Signed-off-by: Kyle McMartin --- arch/parisc/kernel/setup.c | 5 + drivers/parisc/pdc_stable.c | 219 +++++++++++++++++++++++++++++++++--- 2 files changed, 210 insertions(+), 14 deletions(-) diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index 4a36ec3f6ac1..8471486a7565 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -303,6 +303,8 @@ extern void eisa_init(void); static int __init parisc_init(void) { + u32 osid = (0x0006 << 16); + parisc_proc_mkdir(); parisc_init_resources(); do_device_inventory(); /* probe for hardware */ @@ -311,6 +313,9 @@ static int __init parisc_init(void) /* set up a new led state on systems shipped LED State panel */ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART); + + /* tell PDC we're Linux. Nevermind failure. */ + pdc_stable_write(0x40, &osid, sizeof(osid)); processor_init(); printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n", diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index bbeabe3fc4c6..4b991d50e578 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -28,8 +28,15 @@ * following code can deal with just 96 bytes of Stable Storage, and all * sizes between 96 and 192 bytes (provided they are multiple of struct * device_path size, eg: 128, 160 and 192) to provide full information. - * The code makes no use of data above 192 bytes. One last word: there's one - * path we can always count on: the primary path. + * One last word: there's one path we can always count on: the primary path. + * Anything above 224 bytes is used for 'osdep2' OS-dependent storage area. + * + * The first OS-dependent area should always be available. Obviously, this is + * not true for the other one. Also bear in mind that reading/writing from/to + * osdep2 is much more expensive than from/to osdep1. + * NOTE: We do not handle the 2 bytes OS-dep area at 0x5D, nor the first + * 2 bytes of storage available right after OSID. That's a total of 4 bytes + * sacrificed: -ETOOLAZY :P * * The current policy wrt file permissions is: * - write: root only @@ -64,15 +71,18 @@ #include #include -#define PDCS_VERSION "0.22" +#define PDCS_VERSION "0.30" #define PDCS_PREFIX "PDC Stable Storage" #define PDCS_ADDR_PPRI 0x00 #define PDCS_ADDR_OSID 0x40 +#define PDCS_ADDR_OSD1 0x48 +#define PDCS_ADDR_DIAG 0x58 #define PDCS_ADDR_FSIZ 0x5C #define PDCS_ADDR_PCON 0x60 #define PDCS_ADDR_PALT 0x80 #define PDCS_ADDR_PKBD 0xA0 +#define PDCS_ADDR_OSD2 0xE0 MODULE_AUTHOR("Thibaut VARENE "); MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data"); @@ -82,6 +92,9 @@ MODULE_VERSION(PDCS_VERSION); /* holds Stable Storage size. Initialized once and for all, no lock needed */ static unsigned long pdcs_size __read_mostly; +/* holds OS ID. Initialized once and for all, hopefully to 0x0006 */ +static u16 pdcs_osid __read_mostly; + /* This struct defines what we need to deal with a parisc pdc path entry */ struct pdcspath_entry { rwlock_t rw_lock; /* to protect path entry access */ @@ -609,27 +622,74 @@ static ssize_t pdcs_osid_read(struct subsystem *entry, char *buf) { char *out = buf; - __u32 result; char *tmpstr = NULL; if (!entry || !buf) return -EINVAL; - /* get OSID */ - if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK) - return -EIO; - - /* the actual result is 16 bits away */ - switch (result >> 16) { + switch (pdcs_osid) { case 0x0000: tmpstr = "No OS-dependent data"; break; case 0x0001: tmpstr = "HP-UX dependent data"; break; case 0x0002: tmpstr = "MPE-iX dependent data"; break; case 0x0003: tmpstr = "OSF dependent data"; break; case 0x0004: tmpstr = "HP-RT dependent data"; break; case 0x0005: tmpstr = "Novell Netware dependent data"; break; + case 0x0006: tmpstr = "Linux dependent data"; break; default: tmpstr = "Unknown"; break; } - out += sprintf(out, "%s (0x%.4x)\n", tmpstr, (result >> 16)); + out += sprintf(out, "%s (0x%.4x)\n", tmpstr, pdcs_osid); + + return out - buf; +} + +/** + * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output. + * @entry: An allocated and populated subsytem struct. We don't use it tho. + * @buf: The output buffer to write to. + * + * This can hold 16 bytes of OS-Dependent data. + */ +static ssize_t +pdcs_osdep1_read(struct subsystem *entry, char *buf) +{ + char *out = buf; + u32 result[4]; + + if (!entry || !buf) + return -EINVAL; + + if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK) + return -EIO; + + out += sprintf(out, "0x%.8x\n", result[0]); + out += sprintf(out, "0x%.8x\n", result[1]); + out += sprintf(out, "0x%.8x\n", result[2]); + out += sprintf(out, "0x%.8x\n", result[3]); + + return out - buf; +} + +/** + * pdcs_diagnostic_read - Stable Storage Diagnostic register output. + * @entry: An allocated and populated subsytem struct. We don't use it tho. + * @buf: The output buffer to write to. + * + * I have NFC how to interpret the content of that register ;-). + */ +static ssize_t +pdcs_diagnostic_read(struct subsystem *entry, char *buf) +{ + char *out = buf; + u32 result; + + if (!entry || !buf) + return -EINVAL; + + /* get diagnostic */ + if (pdc_stable_read(PDCS_ADDR_DIAG, &result, sizeof(result)) != PDC_OK) + return -EIO; + + out += sprintf(out, "0x%.4x\n", (result >> 16)); return out - buf; } @@ -645,7 +705,7 @@ static ssize_t pdcs_fastsize_read(struct subsystem *entry, char *buf) { char *out = buf; - __u32 result; + u32 result; if (!entry || !buf) return -EINVAL; @@ -663,6 +723,39 @@ pdcs_fastsize_read(struct subsystem *entry, char *buf) return out - buf; } +/** + * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output. + * @entry: An allocated and populated subsytem struct. We don't use it tho. + * @buf: The output buffer to write to. + * + * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available. + */ +static ssize_t +pdcs_osdep2_read(struct subsystem *entry, char *buf) +{ + char *out = buf; + unsigned long size; + unsigned short i; + u32 result; + + if (unlikely(pdcs_size <= 224)) + return -ENODATA; + + size = pdcs_size - 224; + + if (!entry || !buf) + return -EINVAL; + + for (i=0; i 16) + return -EMSGSIZE; + + /* We'll use a local copy of buf */ + memset(in, 0, 16); + memcpy(in, buf, count); + + if (pdc_stable_write(PDCS_ADDR_OSD1, &in, sizeof(in)) != PDC_OK) + return -EIO; + + return count; +} + +/** + * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input. + * @entry: An allocated and populated subsytem struct. We don't use it tho. + * @buf: The input buffer to read from. + * @count: The number of bytes to be read. + * + * This can store pdcs_size - 224 bytes of OS-Dependent data. We use a + * byte-by-byte write approach. It's up to userspace to deal with it when + * constructing its input buffer. + */ +static ssize_t +pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count) +{ + unsigned long size; + unsigned short i; + u8 in[4]; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (!entry || !buf || !count) + return -EINVAL; + + if (unlikely(pdcs_size <= 224)) + return -ENOSYS; + + if (unlikely(pdcs_osid != 0x0006)) + return -EPERM; + + size = pdcs_size - 224; + + if (count > size) + return -EMSGSIZE; + + /* We'll use a local copy of buf */ + + for (i=0; i> 16); + /* For now we'll register the stable subsys within this driver */ if ((rc = firmware_register(&stable_subsys))) goto fail_firmreg; @@ -887,7 +1078,7 @@ pdc_stable_init(void) /* register the paths subsys as a subsystem of stable subsys */ kset_set_kset_s(&paths_subsys, stable_subsys); - if ((rc= subsystem_register(&paths_subsys))) + if ((rc = subsystem_register(&paths_subsys))) goto fail_subsysreg; /* now we create all "files" for the paths subsys */ From b0e8bfca2f6cdef6145e377ff0797fc42473b659 Mon Sep 17 00:00:00 2001 From: Thibaut Varene Date: Thu, 4 May 2006 18:43:34 -0600 Subject: [PATCH 12/23] [PARISC] Reduce data footprint in pdc_stable.c No code change - reduce data footprint. Signed-off-by: Thibaut VARENE Signed-off-by: Kyle McMartin --- drivers/parisc/pdc_stable.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index 4b991d50e578..a1094210cd1f 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -628,16 +628,16 @@ pdcs_osid_read(struct subsystem *entry, char *buf) return -EINVAL; switch (pdcs_osid) { - case 0x0000: tmpstr = "No OS-dependent data"; break; - case 0x0001: tmpstr = "HP-UX dependent data"; break; - case 0x0002: tmpstr = "MPE-iX dependent data"; break; - case 0x0003: tmpstr = "OSF dependent data"; break; - case 0x0004: tmpstr = "HP-RT dependent data"; break; - case 0x0005: tmpstr = "Novell Netware dependent data"; break; - case 0x0006: tmpstr = "Linux dependent data"; break; + case 0x0000: tmpstr = "No OS"; break; + case 0x0001: tmpstr = "HP-UX"; break; + case 0x0002: tmpstr = "MPE-iX"; break; + case 0x0003: tmpstr = "OSF"; break; + case 0x0004: tmpstr = "HP-RT"; break; + case 0x0005: tmpstr = "Novell Netware"; break; + case 0x0006: tmpstr = "Linux"; break; default: tmpstr = "Unknown"; break; } - out += sprintf(out, "%s (0x%.4x)\n", tmpstr, pdcs_osid); + out += sprintf(out, "%s dependent data (0x%.4x)\n", tmpstr, pdcs_osid); return out - buf; } From d71624c95a231873ec3727ee9bff7b68e692de70 Mon Sep 17 00:00:00 2001 From: Thibaut Varene Date: Sun, 7 May 2006 04:54:28 -0600 Subject: [PATCH 13/23] [PARISC] Update Thibaut Varene's CREDITS entry Signed-off-by: Thibaut VARENE Signed-off-by: Kyle McMartin --- CREDITS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CREDITS b/CREDITS index 1d35f10ec3b2..70922bd656c2 100644 --- a/CREDITS +++ b/CREDITS @@ -3396,10 +3396,10 @@ S: Czech Republic N: Thibaut Varene E: T-Bone@parisc-linux.org -W: http://www.parisc-linux.org/ +W: http://www.parisc-linux.org/~varenet/ P: 1024D/B7D2F063 E67C 0D43 A75E 12A5 BB1C FA2F 1E32 C3DA B7D2 F063 D: PA-RISC port minion, PDC and GSCPS2 drivers, debuglocks and other bits -D: Some bits in an ARM port, S1D13XXX FB driver, random patches here and there +D: Some ARM at91rm9200 bits, S1D13XXX FB driver, random patches here and there D: AD1889 sound driver S: Paris, France From a3ea84fabacd9cc5bcc3fda67c35e692ca10dc8c Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 16 Jun 2006 19:10:02 +0000 Subject: [PATCH 14/23] [PARISC] Add is_compat_task() helper ... And convert signal.c and ptrace.c to use it instead of open coded equivalents. Signed-off-by: Kyle McMartin --- arch/parisc/kernel/ptrace.c | 8 ++++---- arch/parisc/kernel/signal.c | 20 ++++++++++---------- include/asm-parisc/compat.h | 11 +++++++++++ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index 413292f1a4a3..3f28de974556 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -91,7 +91,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int copied; #ifdef __LP64__ - if (personality(child->personality) == PER_LINUX32) { + if (__is_compat_task(child)) { unsigned int tmp; addr &= 0xffffffffL; @@ -123,7 +123,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_POKEDATA: ret = 0; #ifdef __LP64__ - if (personality(child->personality) == PER_LINUX32) { + if (__is_compat_task(child)) { unsigned int tmp = (unsigned int)data; DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n", request == PTRACE_POKETEXT ? "TEXT" : "DATA", @@ -146,7 +146,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_PEEKUSR: { ret = -EIO; #ifdef __LP64__ - if (personality(child->personality) == PER_LINUX32) { + if (__is_compat_task(child)) { unsigned int tmp; if (addr & (sizeof(int)-1)) @@ -205,7 +205,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) goto out_tsk; } #ifdef __LP64__ - if (personality(child->personality) == PER_LINUX32) { + if (__is_compat_task(child)) { if (addr & (sizeof(int)-1)) goto out_tsk; if ((addr = translate_usr_offset(addr)) < 0) diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index cc38edfd90c5..bb83880c5ee3 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -76,7 +76,7 @@ sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *r #ifdef __LP64__ compat_sigset_t newset32; - if(personality(current->personality) == PER_LINUX32){ + if (is_compat_task()) { /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; @@ -153,7 +153,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) compat_sigset_t compat_set; struct compat_rt_sigframe __user * compat_frame; - if(personality(current->personality) == PER_LINUX32) + if (is_compat_task()) sigframe_size = PARISC_RT_SIGFRAME_SIZE32; #endif @@ -166,7 +166,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) #ifdef __LP64__ compat_frame = (struct compat_rt_sigframe __user *)frame; - if(personality(current->personality) == PER_LINUX32){ + if (is_compat_task()) { DBG(2,"sys_rt_sigreturn: ELF32 process.\n"); if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask, sizeof(compat_set))) goto give_sigsegv; @@ -186,7 +186,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) /* Good thing we saved the old gr[30], eh? */ #ifdef __LP64__ - if(personality(current->personality) == PER_LINUX32){ + if (is_compat_task()) { DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n", &compat_frame->uc.uc_mcontext); // FIXME: Load upper half from register file @@ -315,7 +315,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, compat_frame = (struct compat_rt_sigframe __user *)frame; - if(personality(current->personality) == PER_LINUX32) { + 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"); @@ -392,7 +392,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, haddr = A(ka->sa.sa_handler); /* The sa_handler may be a pointer to a function descriptor */ #ifdef __LP64__ - if(personality(current->personality) == PER_LINUX32) { + if (is_compat_task()) { #endif if (haddr & PA_PLABEL_FDESC) { Elf32_Fdesc fdesc; @@ -427,19 +427,19 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, */ sigframe_size = PARISC_RT_SIGFRAME_SIZE; #ifdef __LP64__ - if(personality(current->personality) == PER_LINUX32) + if (is_compat_task()) sigframe_size = PARISC_RT_SIGFRAME_SIZE32; #endif if (in_syscall) { regs->gr[31] = haddr; #ifdef __LP64__ - if(personality(current->personality) == PER_LINUX) + if (personality(current->personality) == PER_LINUX) sigframe_size |= 1; #endif } else { unsigned long psw = USER_PSW; #ifdef __LP64__ - if(personality(current->personality) == PER_LINUX) + if (personality(current->personality) == PER_LINUX) psw |= PSW_W; #endif @@ -464,7 +464,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->gr[26] = sig; /* signal number */ #ifdef __LP64__ - if(personality(current->personality) == PER_LINUX32){ + if (is_compat_task()) { regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */ regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */ } else diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h index 289624d8b2d4..71b4eeea205a 100644 --- a/include/asm-parisc/compat.h +++ b/include/asm-parisc/compat.h @@ -5,6 +5,7 @@ */ #include #include +#include #define COMPAT_USER_HZ 100 @@ -149,4 +150,14 @@ static __inline__ void __user *compat_alloc_user_space(long len) return (void __user *)regs->gr[30]; } +static inline int __is_compat_task(struct task_struct *t) +{ + return personality(t->personality) == PER_LINUX32; +} + +static inline int is_compat_task(void) +{ + return __is_compat_task(current); +} + #endif /* _ASM_PARISC_COMPAT_H */ From 667baef53fcd5b839ca8e74ed65811d9df22bd7b Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sat, 17 Jun 2006 17:53:43 +0000 Subject: [PATCH 15/23] [PARISC] Remove unused macro fixup_branch in syscall.S Signed-off-by: Kyle McMartin --- arch/parisc/kernel/syscall.S | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index a028c990cbff..9670a89c77fe 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -29,18 +29,6 @@ .level 1.1 #endif -#ifndef CONFIG_64BIT - .macro fixup_branch,lbl - b \lbl - .endm -#else - .macro fixup_branch,lbl - ldil L%\lbl, %r1 - ldo R%\lbl(%r1), %r1 - bv,n %r0(%r1) - .endm -#endif - .text .import syscall_exit,code From e5a2e7fdb53028ce187c0ce0ae0d45ca7546fd5e Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Wed, 14 Jun 2006 20:26:25 +0000 Subject: [PATCH 16/23] [PARISC] Match show_cache_info with reality show_cache_info and struct pdc_cache_cf were out of sync with published documentation. Fix the reporting of cache associativity and update the pdc_cache_cf bitfields to match documentation. Signed-off-by: Kyle McMartin --- arch/parisc/kernel/cache.c | 18 ++++++++++-------- include/asm-parisc/pdc.h | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index c057ad7605ba..851519cbad6f 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -97,15 +97,17 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) void show_cache_info(struct seq_file *m) { + char buf[32]; + seq_printf(m, "I-cache\t\t: %ld KB\n", cache_info.ic_size/1024 ); - seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %d-way associative)\n", + if (cache_info.dc_loop == 1) + snprintf(buf, 32, "%lu-way associative", cache_info.dc_loop); + seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %s)\n", cache_info.dc_size/1024, (cache_info.dc_conf.cc_wt ? "WT":"WB"), (cache_info.dc_conf.cc_sh ? ", shared I/D":""), - (cache_info.dc_conf.cc_assoc) - ); - + ((cache_info.dc_loop == 1) ? "direct mapped" : buf)); seq_printf(m, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n", cache_info.it_size, cache_info.dt_size, @@ -158,11 +160,11 @@ parisc_cache_init(void) cache_info.dc_conf.cc_block, cache_info.dc_conf.cc_line, cache_info.dc_conf.cc_shift); - printk(" wt %d sh %d cst %d assoc %d\n", + printk(" wt %d sh %d cst %d hv %d\n", cache_info.dc_conf.cc_wt, cache_info.dc_conf.cc_sh, cache_info.dc_conf.cc_cst, - cache_info.dc_conf.cc_assoc); + cache_info.dc_conf.cc_hv); printk("IC base 0x%lx stride 0x%lx count 0x%lx loop 0x%lx\n", cache_info.ic_base, @@ -176,11 +178,11 @@ parisc_cache_init(void) cache_info.ic_conf.cc_block, cache_info.ic_conf.cc_line, cache_info.ic_conf.cc_shift); - printk(" wt %d sh %d cst %d assoc %d\n", + printk(" wt %d sh %d cst %d hv %d\n", cache_info.ic_conf.cc_wt, cache_info.ic_conf.cc_sh, cache_info.ic_conf.cc_cst, - cache_info.ic_conf.cc_assoc); + cache_info.ic_conf.cc_hv); printk("D-TLB conf: sh %d page %d cst %d aid %d pad1 %d \n", cache_info.dt_conf.tc_sh, diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h index 7d8a71a28546..592f13bcc987 100644 --- a/include/asm-parisc/pdc.h +++ b/include/asm-parisc/pdc.h @@ -352,8 +352,8 @@ struct pdc_cache_cf { /* for PDC_CACHE (I/D-caches) */ cc_wt : 1, /* 0 = WT-Dcache, 1 = WB-Dcache */ cc_sh : 2, /* 0 = separate I/D-cache, else shared I/D-cache */ cc_cst : 3, /* 0 = incoherent D-cache, 1=coherent D-cache */ - cc_pad1 : 5, /* reserved */ - cc_assoc: 8; /* associativity of I/D-cache */ + cc_pad1 : 10, /* reserved */ + cc_hv : 3; /* hversion dependent */ }; struct pdc_tlb_cf { /* for PDC_CACHE (I/D-TLB's) */ From a9d2d386c42b816a81eb1d02dfb7b502ba8cea82 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 16 Jun 2006 18:20:00 -0400 Subject: [PATCH 17/23] [PARISC] Ensure Space ID hashing is turned off Check PDC_CACHE to see if spaceid hashing is turned on, and fail to boot if that is the case. However, some old machines do not implement the PDC_CACHE_RET_SPID firmware call, so continue to boot if the call fails because of PDC_BAD_OPTION (but fail in all other error returns). Signed-off-by: Kyle McMartin --- arch/parisc/kernel/cache.c | 10 +++++++++- arch/parisc/kernel/firmware.c | 20 ++++++++++++++++++++ include/asm-parisc/pdc.h | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 851519cbad6f..bc7c4a4e26a1 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -236,7 +236,8 @@ parisc_cache_init(void) void disable_sr_hashing(void) { - int srhash_type; + int srhash_type, retval; + unsigned long space_bits; switch (boot_cpu_data.cpu_type) { case pcx: /* We shouldn't get this far. setup.c should prevent it. */ @@ -262,6 +263,13 @@ void disable_sr_hashing(void) } disable_sr_hashing_asm(srhash_type); + + retval = pdc_spaceid_bits(&space_bits); + /* If this procedure isn't implemented, don't panic. */ + if (retval < 0 && retval != PDC_BAD_OPTION) + panic("pdc_spaceid_bits call failed.\n"); + if (space_bits != 0) + panic("SpaceID hashing is still on!\n"); } void flush_dcache_page(struct page *page) diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 0596f27340cc..c80c277454f3 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -512,6 +512,26 @@ int pdc_cache_info(struct pdc_cache_info *cache_info) return retval; } +/** + * pdc_spaceid_bits - Return whether Space ID hashing is turned on. + * @space_bits: Should be 0, if not, bad mojo! + * + * Returns information about Space ID hashing. + */ +int pdc_spaceid_bits(unsigned long *space_bits) +{ + int retval; + + spin_lock_irq(&pdc_lock); + pdc_result[0] = 0; + retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_RET_SPID, __pa(pdc_result), 0); + convert_to_wide(pdc_result); + *space_bits = pdc_result[0]; + spin_unlock_irq(&pdc_lock); + + return retval; +} + #ifndef CONFIG_PA20 /** * pdc_btlb_info - Return block TLB information. diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h index 592f13bcc987..3d3446ec207e 100644 --- a/include/asm-parisc/pdc.h +++ b/include/asm-parisc/pdc.h @@ -733,6 +733,7 @@ int pdc_model_cpuid(unsigned long *cpu_id); int pdc_model_versions(unsigned long *versions, int id); int pdc_model_capabilities(unsigned long *capabilities); int pdc_cache_info(struct pdc_cache_info *cache); +int pdc_spaceid_bits(unsigned long *space_bits); #ifndef CONFIG_PA20 int pdc_btlb_info(struct pdc_btlb_info *btlb); int pdc_mem_map_hpa(struct pdc_memory_map *r_addr, struct pdc_module_path *mod_path); From ec1fdc24c2ae012b078ba0187ceef208e08a3aec Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Wed, 21 Jun 2006 19:27:29 +0000 Subject: [PATCH 18/23] [PARISC] OS_ID_LINUX == 0x0006 We were assigned an OS_ID of 0x0006. Consistently use OS_ID_LINUX instead of using the magic number. Also update the OS_ID_ defines in asm/pdc.h to reflect this. Signed-off-by: Kyle McMartin --- arch/parisc/kernel/firmware.c | 4 +++- arch/parisc/kernel/setup.c | 2 +- drivers/parisc/pdc_stable.c | 4 ++-- include/asm-parisc/pdc.h | 3 +-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index c80c277454f3..4398d2a95789 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -407,7 +407,9 @@ int pdc_model_info(struct pdc_model *model) * pdc_model_sysmodel - Get the system model name. * @name: A char array of at least 81 characters. * - * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L) + * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L). + * Using OS_ID_HPUX will return the equivalent of the 'modelname' command + * on HP/UX. */ int pdc_model_sysmodel(char *name) { diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index 8471486a7565..278f4b9f6a38 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -303,7 +303,7 @@ extern void eisa_init(void); static int __init parisc_init(void) { - u32 osid = (0x0006 << 16); + u32 osid = (OS_ID_LINUX << 16); parisc_proc_mkdir(); parisc_init_resources(); diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index a1094210cd1f..97b345858043 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -884,7 +884,7 @@ pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count) if (!entry || !buf || !count) return -EINVAL; - if (unlikely(pdcs_osid != 0x0006)) + if (unlikely(pdcs_osid != OS_ID_LINUX)) return -EPERM; if (count > 16) @@ -926,7 +926,7 @@ pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count) if (unlikely(pdcs_size <= 224)) return -ENOSYS; - if (unlikely(pdcs_osid != 0x0006)) + if (unlikely(pdcs_osid != OS_ID_LINUX)) return -EPERM; size = pdcs_size - 224; diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h index 3d3446ec207e..33bff615d6e1 100644 --- a/include/asm-parisc/pdc.h +++ b/include/asm-parisc/pdc.h @@ -278,12 +278,11 @@ typedef struct { /* constants for OS (NVM...) */ #define OS_ID_NONE 0 /* Undefined OS ID */ #define OS_ID_HPUX 1 /* HP-UX OS */ -#define OS_ID_LINUX OS_ID_HPUX /* just use the same value as hpux */ #define OS_ID_MPEXL 2 /* MPE XL OS */ #define OS_ID_OSF 3 /* OSF OS */ #define OS_ID_HPRT 4 /* HP-RT OS */ #define OS_ID_NOVEL 5 /* NOVELL OS */ -#define OS_ID_NT 6 /* NT OS */ +#define OS_ID_LINUX 6 /* Linux */ /* constants for PDC_CHASSIS */ From 67a061a191017f984a1ef0ff73ae988b9b15f6d3 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 25 Jun 2006 16:58:57 +0000 Subject: [PATCH 19/23] [PARISC] Add os_id_to_string helper Add a helper to asm/pdc.h to translate OS_ID values to strings and use it in the pdc_stable driver. Signed-off-by: Kyle McMartin --- drivers/parisc/pdc_stable.c | 14 ++------------ include/asm-parisc/pdc.h | 13 +++++++++++++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index 97b345858043..ea1b7a63598e 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -622,22 +622,12 @@ static ssize_t pdcs_osid_read(struct subsystem *entry, char *buf) { char *out = buf; - char *tmpstr = NULL; if (!entry || !buf) return -EINVAL; - switch (pdcs_osid) { - case 0x0000: tmpstr = "No OS"; break; - case 0x0001: tmpstr = "HP-UX"; break; - case 0x0002: tmpstr = "MPE-iX"; break; - case 0x0003: tmpstr = "OSF"; break; - case 0x0004: tmpstr = "HP-RT"; break; - case 0x0005: tmpstr = "Novell Netware"; break; - case 0x0006: tmpstr = "Linux"; break; - default: tmpstr = "Unknown"; break; - } - out += sprintf(out, "%s dependent data (0x%.4x)\n", tmpstr, pdcs_osid); + out += sprintf(out, "%s dependent data (0x%.4x)\n", + os_id_to_string(pdcs_osid), pdcs_osid); return out - buf; } diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h index 33bff615d6e1..7a21f106ade6 100644 --- a/include/asm-parisc/pdc.h +++ b/include/asm-parisc/pdc.h @@ -284,6 +284,19 @@ typedef struct { #define OS_ID_NOVEL 5 /* NOVELL OS */ #define OS_ID_LINUX 6 /* Linux */ +static inline char * os_id_to_string(u16 os_id) { + switch(os_id) { + case OS_ID_NONE: return "No OS"; + case OS_ID_HPUX: return "HP-UX"; + case OS_ID_MPEXL: return "MPE-iX"; + case OS_ID_OSF: return "OSF"; + case OS_ID_HPRT: return "HP-RT"; + case OS_ID_NOVEL: return "Novell Netware"; + case OS_ID_LINUX: return "Linux"; + default: return "Unknown"; + } +} + /* constants for PDC_CHASSIS */ #define OSTAT_OFF 0 From 1c63b4b8474700f3fb5e3442a78897766f153437 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Wed, 21 Jun 2006 16:49:38 +0000 Subject: [PATCH 20/23] [PARISC] Refactor show_regs in traps.c show_regs() was one bloaty function. Split it into a few cleaner functions and define a clean macro to print a line of registers. [And from Thibaut, only print fprs on a usermode trap.] Signed-off-by: Kyle McMartin --- arch/parisc/kernel/traps.c | 84 ++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index ff200608c851..348344a84bf7 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -66,57 +66,42 @@ int printbinary(char *buf, unsigned long x, int nbits) #else #define RFMT "%08lx" #endif +#define FFMT "%016llx" /* fpregs are 64-bit always */ -void show_regs(struct pt_regs *regs) +#define PRINTREGS(lvl,r,f,fmt,x) \ + printk("%s%s%02d-%02d " fmt " " fmt " " fmt " " fmt "\n", \ + lvl, f, (x), (x+3), (r)[(x)+0], (r)[(x)+1], \ + (r)[(x)+2], (r)[(x)+3]) + +static void print_gr(char *level, struct pt_regs *regs) { int i; - char buf[128], *p; - char *level; - unsigned long cr30; - unsigned long cr31; - /* carlos says that gcc understands better memory in a struct, - * and it makes our life easier with fpregs -- T-Bone */ - struct { u32 sw[2]; } s; - - level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT; - - printk("%s\n", level); /* don't want to have that pretty register dump messed up */ + char buf[64]; + printk("%s\n", level); printk("%s YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level); printbinary(buf, regs->gr[0], 32); printk("%sPSW: %s %s\n", level, buf, print_tainted()); - for (i = 0; i < 32; i += 4) { - int j; - p = buf; - p += sprintf(p, "%sr%02d-%02d ", level, i, i + 3); - for (j = 0; j < 4; j++) { - p += sprintf(p, " " RFMT, (i+j) == 0 ? 0 : regs->gr[i + j]); - } - printk("%s\n", buf); - } + for (i = 0; i < 32; i += 4) + PRINTREGS(level, regs->gr, "r", RFMT, i); +} - for (i = 0; i < 8; i += 4) { - int j; - p = buf; - p += sprintf(p, "%ssr%d-%d ", level, i, i + 3); - for (j = 0; j < 4; j++) { - p += sprintf(p, " " RFMT, regs->sr[i + j]); - } - printk("%s\n", buf); - } +static void print_fr(char *level, struct pt_regs *regs) +{ + int i; + char buf[64]; + struct { u32 sw[2]; } s; /* FR are 64bit everywhere. Need to use asm to get the content * of fpsr/fper1, and we assume that we won't have a FP Identify * in our way, otherwise we're screwed. * The fldd is used to restore the T-bit if there was one, as the * store clears it anyway. - * BTW, PA2.0 book says "thou shall not use fstw on FPSR/FPERs". */ - __asm__ ( - "fstd %%fr0,0(%1) \n\t" - "fldd 0(%1),%%fr0 \n\t" - : "=m" (s) : "r" (&s) : "%r0" - ); + * PA2.0 book says "thou shall not use fstw on FPSR/FPERs" - T-Bone */ + asm volatile ("fstd %%fr0,0(%1) \n\t" + "fldd 0(%1),%%fr0 \n\t" + : "=m" (s) : "r" (&s) : "r0"); printk("%s\n", level); printk("%s VZOUICununcqcqcqcqcqcrmunTDVZOUI\n", level); @@ -125,14 +110,25 @@ void show_regs(struct pt_regs *regs) printk("%sFPER1: %08x\n", level, s.sw[1]); /* here we'll print fr0 again, tho it'll be meaningless */ - for (i = 0; i < 32; i += 4) { - int j; - p = buf; - p += sprintf(p, "%sfr%02d-%02d ", level, i, i + 3); - for (j = 0; j < 4; j++) - p += sprintf(p, " %016llx", (i+j) == 0 ? 0 : regs->fr[i+j]); - printk("%s\n", buf); - } + for (i = 0; i < 32; i += 4) + PRINTREGS(level, regs->fr, "fr", FFMT, i); +} + +void show_regs(struct pt_regs *regs) +{ + int i; + char *level; + unsigned long cr30, cr31; + + level = user_mode(regs) ? KERN_DEBUG : KERN_CRIT; + + print_gr(level, regs); + + for (i = 0; i < 8; i += 4) + PRINTREGS(level, regs->sr, "sr", RFMT, i); + + if (user_mode(regs)) + print_fr(level, regs); cr30 = mfctl(30); cr31 = mfctl(31); From 6e1b9585aaae2fa4f9590f363b32c5d3b6339ba6 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 23 Jun 2006 14:15:20 -0600 Subject: [PATCH 21/23] [PARISC] Fix PCREL22F relocation problem for most modules The new problem, which has been affecting many more modules was that our new ioremap really takes chunks out of our vmalloc space. The net result being that any two kernel vmalloc's now have to slot into the chunked up space. So the vmallocs for a modules init and core sectons are no longer necessarily contiguous. Unfortunately, the module loader thinks that any internal symbol references should be satisfiable using the jump instruction, which isn't true if the symbol is referenced from init to core and vmalloc placed them a long way apart. Fix this by introducing a new stub type for intra module inter sectional jumps and using it. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin --- arch/parisc/kernel/module.c | 63 +++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index f27cfe4771b8..aee311884f3f 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c @@ -89,6 +89,12 @@ static inline int is_local(struct module *me, void *loc) return is_init(me, loc) || is_core(me, loc); } +static inline int is_local_section(struct module *me, void *loc, void *dot) +{ + return (is_init(me, loc) && is_init(me, dot)) || + (is_core(me, loc) && is_core(me, dot)); +} + #ifndef __LP64__ struct got_entry { @@ -364,8 +370,14 @@ static Elf_Addr get_fdesc(struct module *me, unsigned long value) } #endif /* __LP64__ */ +enum elf_stub_type { + ELF_STUB_GOT, + ELF_STUB_MILLI, + ELF_STUB_DIRECT, +}; + static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, - int millicode, int init_section) + enum elf_stub_type stub_type, int init_section) { unsigned long i; struct stub_entry *stub; @@ -396,7 +408,7 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, stub->insns[1] |= reassemble_17(rrsel(value, addend) / 4); #else -/* for 64-bit we have two kinds of stubs: +/* for 64-bit we have three kinds of stubs: * for normal function calls: * ldd 0(%dp),%dp * ldd 10(%dp), %r1 @@ -408,18 +420,23 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, * ldo 0(%r1), %r1 * ldd 10(%r1), %r1 * bve,n (%r1) + * + * for direct branches (jumps between different section of the + * same module): + * ldil 0, %r1 + * ldo 0(%r1), %r1 + * bve,n (%r1) */ - if (!millicode) - { + switch (stub_type) { + case ELF_STUB_GOT: stub->insns[0] = 0x537b0000; /* ldd 0(%dp),%dp */ stub->insns[1] = 0x53610020; /* ldd 10(%dp),%r1 */ stub->insns[2] = 0xe820d000; /* bve (%r1) */ stub->insns[3] = 0x537b0030; /* ldd 18(%dp),%dp */ stub->insns[0] |= reassemble_14(get_got(me, value, addend) & 0x3fff); - } - else - { + break; + case ELF_STUB_MILLI: stub->insns[0] = 0x20200000; /* ldil 0,%r1 */ stub->insns[1] = 0x34210000; /* ldo 0(%r1), %r1 */ stub->insns[2] = 0x50210020; /* ldd 10(%r1),%r1 */ @@ -427,7 +444,17 @@ static Elf_Addr get_stub(struct module *me, unsigned long value, long addend, stub->insns[0] |= reassemble_21(lrsel(value, addend)); stub->insns[1] |= reassemble_14(rrsel(value, addend)); + break; + case ELF_STUB_DIRECT: + stub->insns[0] = 0x20200000; /* ldil 0,%r1 */ + stub->insns[1] = 0x34210000; /* ldo 0(%r1), %r1 */ + stub->insns[2] = 0xe820d002; /* bve,n (%r1) */ + + stub->insns[0] |= reassemble_21(lrsel(value, addend)); + stub->insns[1] |= reassemble_14(rrsel(value, addend)); + break; } + #endif return (Elf_Addr)stub; @@ -539,14 +566,14 @@ int apply_relocate_add(Elf_Shdr *sechdrs, break; case R_PARISC_PCREL17F: /* 17-bit PC relative address */ - val = get_stub(me, val, addend, 0, is_init(me, loc)); + val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc)); val = (val - dot - 8)/4; CHECK_RELOC(val, 17) *loc = (*loc & ~0x1f1ffd) | reassemble_17(val); break; case R_PARISC_PCREL22F: /* 22-bit PC relative address; only defined for pa20 */ - val = get_stub(me, val, addend, 0, is_init(me, loc)); + val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc)); DEBUGP("STUB FOR %s loc %lx+%lx at %lx\n", strtab + sym->st_name, (unsigned long)loc, addend, val) @@ -643,13 +670,23 @@ int apply_relocate_add(Elf_Shdr *sechdrs, strtab + sym->st_name, loc, val); /* can we reach it locally? */ - if(!is_local(me, (void *)val)) { - if (strncmp(strtab + sym->st_name, "$$", 2) + if(!is_local_section(me, (void *)val, (void *)dot)) { + + if (is_local(me, (void *)val)) + /* this is the case where the + * symbol is local to the + * module, but in a different + * section, so stub the jump + * in case it's more than 22 + * bits away */ + val = get_stub(me, val, addend, ELF_STUB_DIRECT, + is_init(me, loc)); + else if (strncmp(strtab + sym->st_name, "$$", 2) == 0) - val = get_stub(me, val, addend, 1, + val = get_stub(me, val, addend, ELF_STUB_MILLI, is_init(me, loc)); else - val = get_stub(me, val, addend, 0, + val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc)); } DEBUGP("STUB FOR %s loc %lx, val %lx+%lx at %lx\n", From 61c340166d8c62086b6de00afc7670eea27eb2ab Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 24 Jun 2006 16:05:18 +0000 Subject: [PATCH 22/23] [PARISC] Fix do_gettimeofday() hang Apparently gettimeoffset can return small negative values (usually in the 100us range). If xtime.tv_nsec is accidentally less than this, though (a fortunately unlikely event) it triggers the loop forever. I've added a test and correct adjustment for this case. It has a warning printk in there which I'd like to leave for the time being just in case this problem implicates some other part of the kernel. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin --- arch/parisc/kernel/time.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 594930bc4bcf..eb35e1c0bb53 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -157,8 +157,22 @@ do_gettimeofday (struct timeval *tv) usec += (xtime.tv_nsec / 1000); } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - while (usec >= 1000000) { - usec -= 1000000; + if (unlikely(usec > LONG_MAX)) { + /* This can happen if the gettimeoffset adjustment is + * negative and xtime.tv_nsec is smaller than the + * adjustment */ + printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec); + usec += USEC_PER_SEC; + --sec; + /* This should never happen, it means the negative + * time adjustment was more than a second, so there's + * something seriously wrong */ + BUG_ON(usec > LONG_MAX); + } + + + while (usec >= USEC_PER_SEC) { + usec -= USEC_PER_SEC; ++sec; } From c1a7a755be26f68d7f21ee769584149a96185ea8 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Mon, 26 Jun 2006 11:28:09 -0400 Subject: [PATCH 23/23] [PARISC] Move os_id_to_string() inside #ifndef __ASSEMBLY__ Assembly files should be protected from os_id_to_string()... Pass me a brown paper bag, please. Signed-off-by: Kyle McMartin --- include/asm-parisc/pdc.h | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h index 7a21f106ade6..c9b2e35326ee 100644 --- a/include/asm-parisc/pdc.h +++ b/include/asm-parisc/pdc.h @@ -284,19 +284,6 @@ typedef struct { #define OS_ID_NOVEL 5 /* NOVELL OS */ #define OS_ID_LINUX 6 /* Linux */ -static inline char * os_id_to_string(u16 os_id) { - switch(os_id) { - case OS_ID_NONE: return "No OS"; - case OS_ID_HPUX: return "HP-UX"; - case OS_ID_MPEXL: return "MPE-iX"; - case OS_ID_OSF: return "OSF"; - case OS_ID_HPRT: return "HP-RT"; - case OS_ID_NOVEL: return "Novell Netware"; - case OS_ID_LINUX: return "Linux"; - default: return "Unknown"; - } -} - /* constants for PDC_CHASSIS */ #define OSTAT_OFF 0 @@ -789,6 +776,18 @@ int pdc_sti_call(unsigned long func, unsigned long flags, extern void pdc_init(void); +static inline char * os_id_to_string(u16 os_id) { + switch(os_id) { + case OS_ID_NONE: return "No OS"; + case OS_ID_HPUX: return "HP-UX"; + case OS_ID_MPEXL: return "MPE-iX"; + case OS_ID_OSF: return "OSF"; + case OS_ID_HPRT: return "HP-RT"; + case OS_ID_NOVEL: return "Novell Netware"; + case OS_ID_LINUX: return "Linux"; + default: return "Unknown"; + } +} #endif /* __ASSEMBLY__ */ #endif /* _PARISC_PDC_H */