From 247055aa21ffef1c49dd64710d5e94c2aee19b58 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 13 Sep 2010 16:03:21 +0100 Subject: [PATCH 01/52] ARM: 6384/1: Remove the domain switching on ARMv6k/v7 CPUs This patch removes the domain switching functionality via the set_fs and __switch_to functions on cores that have a TLS register. Currently, the ioremap and vmalloc areas share the same level 1 page tables and therefore have the same domain (DOMAIN_KERNEL). When the kernel domain is modified from Client to Manager (via the __set_fs or in the __switch_to function), the XN (eXecute Never) bit is overridden and newer CPUs can speculatively prefetch the ioremap'ed memory. Linux performs the kernel domain switching to allow user-specific functions (copy_to/from_user, get/put_user etc.) to access kernel memory. In order for these functions to work with the kernel domain set to Client, the patch modifies the LDRT/STRT and related instructions to the LDR/STR ones. The user pages access rights are also modified for kernel read-only access rather than read/write so that the copy-on-write mechanism still works. CPU_USE_DOMAINS gets disabled only if the hardware has a TLS register (CPU_32v6K is defined) since writing the TLS value to the high vectors page isn't possible. The user addresses passed to the kernel are checked by the access_ok() function so that they do not point to the kernel space. Tested-by: Anton Vorontsov Cc: Tony Lindgren Signed-off-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/assembler.h | 13 ++--- arch/arm/include/asm/domain.h | 31 +++++++++++- arch/arm/include/asm/futex.h | 9 ++-- arch/arm/include/asm/traps.h | 2 + arch/arm/include/asm/uaccess.h | 16 +++--- arch/arm/kernel/entry-armv.S | 4 +- arch/arm/kernel/fiq.c | 5 ++ arch/arm/kernel/traps.c | 14 ++++-- arch/arm/lib/getuser.S | 13 ++--- arch/arm/lib/putuser.S | 29 +++++------ arch/arm/lib/uaccess.S | 83 ++++++++++++++++---------------- arch/arm/mm/Kconfig | 8 +++ arch/arm/mm/mmu.c | 6 +-- arch/arm/mm/proc-macros.S | 7 +++ arch/arm/mm/proc-v7.S | 5 +- 15 files changed, 153 insertions(+), 92 deletions(-) diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 062b58c029ab9..4e84d09c9c1b6 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -18,6 +18,7 @@ #endif #include +#include /* * Endian independent macros for shifting bytes within registers. @@ -206,12 +207,12 @@ */ #ifdef CONFIG_THUMB2_KERNEL - .macro usraccoff, instr, reg, ptr, inc, off, cond, abort + .macro usraccoff, instr, reg, ptr, inc, off, cond, abort, t=T() 9999: .if \inc == 1 - \instr\cond\()bt \reg, [\ptr, #\off] + \instr\cond\()b\()\t\().w \reg, [\ptr, #\off] .elseif \inc == 4 - \instr\cond\()t \reg, [\ptr, #\off] + \instr\cond\()\t\().w \reg, [\ptr, #\off] .else .error "Unsupported inc macro argument" .endif @@ -246,13 +247,13 @@ #else /* !CONFIG_THUMB2_KERNEL */ - .macro usracc, instr, reg, ptr, inc, cond, rept, abort + .macro usracc, instr, reg, ptr, inc, cond, rept, abort, t=T() .rept \rept 9999: .if \inc == 1 - \instr\cond\()bt \reg, [\ptr], #\inc + \instr\cond\()b\()\t \reg, [\ptr], #\inc .elseif \inc == 4 - \instr\cond\()t \reg, [\ptr], #\inc + \instr\cond\()\t \reg, [\ptr], #\inc .else .error "Unsupported inc macro argument" .endif diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h index cc7ef4080711f..af18ceaacf5d2 100644 --- a/arch/arm/include/asm/domain.h +++ b/arch/arm/include/asm/domain.h @@ -45,13 +45,17 @@ */ #define DOMAIN_NOACCESS 0 #define DOMAIN_CLIENT 1 +#ifdef CONFIG_CPU_USE_DOMAINS #define DOMAIN_MANAGER 3 +#else +#define DOMAIN_MANAGER 1 +#endif #define domain_val(dom,type) ((type) << (2*(dom))) #ifndef __ASSEMBLY__ -#ifdef CONFIG_MMU +#ifdef CONFIG_CPU_USE_DOMAINS #define set_domain(x) \ do { \ __asm__ __volatile__( \ @@ -74,5 +78,28 @@ #define modify_domain(dom,type) do { } while (0) #endif +/* + * Generate the T (user) versions of the LDR/STR and related + * instructions (inline assembly) + */ +#ifdef CONFIG_CPU_USE_DOMAINS +#define T(instr) #instr "t" +#else +#define T(instr) #instr #endif -#endif /* !__ASSEMBLY__ */ + +#else /* __ASSEMBLY__ */ + +/* + * Generate the T (user) versions of the LDR/STR and related + * instructions + */ +#ifdef CONFIG_CPU_USE_DOMAINS +#define T(instr) instr ## t +#else +#define T(instr) instr +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* !__ASM_PROC_DOMAIN_H */ diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h index 540a044153a54..b33fe7065b386 100644 --- a/arch/arm/include/asm/futex.h +++ b/arch/arm/include/asm/futex.h @@ -13,12 +13,13 @@ #include #include #include +#include #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ __asm__ __volatile__( \ - "1: ldrt %1, [%2]\n" \ + "1: " T(ldr) " %1, [%2]\n" \ " " insn "\n" \ - "2: strt %0, [%2]\n" \ + "2: " T(str) " %0, [%2]\n" \ " mov %0, #0\n" \ "3:\n" \ " .pushsection __ex_table,\"a\"\n" \ @@ -97,10 +98,10 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) pagefault_disable(); /* implies preempt_disable() */ __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" - "1: ldrt %0, [%3]\n" + "1: " T(ldr) " %0, [%3]\n" " teq %0, %1\n" " it eq @ explicit IT needed for the 2b label\n" - "2: streqt %2, [%3]\n" + "2: " T(streq) " %2, [%3]\n" "3:\n" " .pushsection __ex_table,\"a\"\n" " .align 3\n" diff --git a/arch/arm/include/asm/traps.h b/arch/arm/include/asm/traps.h index 491960bf42602..af5d5d1388c6b 100644 --- a/arch/arm/include/asm/traps.h +++ b/arch/arm/include/asm/traps.h @@ -27,4 +27,6 @@ static inline int in_exception_text(unsigned long ptr) extern void __init early_trap_init(void); extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame); +extern void *vectors_page; + #endif diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 33e4a48fe1037..b293616a1a1a8 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -227,7 +227,7 @@ do { \ #define __get_user_asm_byte(x,addr,err) \ __asm__ __volatile__( \ - "1: ldrbt %1,[%2]\n" \ + "1: " T(ldrb) " %1,[%2],#0\n" \ "2:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -263,7 +263,7 @@ do { \ #define __get_user_asm_word(x,addr,err) \ __asm__ __volatile__( \ - "1: ldrt %1,[%2]\n" \ + "1: " T(ldr) " %1,[%2],#0\n" \ "2:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -308,7 +308,7 @@ do { \ #define __put_user_asm_byte(x,__pu_addr,err) \ __asm__ __volatile__( \ - "1: strbt %1,[%2]\n" \ + "1: " T(strb) " %1,[%2],#0\n" \ "2:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -341,7 +341,7 @@ do { \ #define __put_user_asm_word(x,__pu_addr,err) \ __asm__ __volatile__( \ - "1: strt %1,[%2]\n" \ + "1: " T(str) " %1,[%2],#0\n" \ "2:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ @@ -366,10 +366,10 @@ do { \ #define __put_user_asm_dword(x,__pu_addr,err) \ __asm__ __volatile__( \ - ARM( "1: strt " __reg_oper1 ", [%1], #4\n" ) \ - ARM( "2: strt " __reg_oper0 ", [%1]\n" ) \ - THUMB( "1: strt " __reg_oper1 ", [%1]\n" ) \ - THUMB( "2: strt " __reg_oper0 ", [%1, #4]\n" ) \ + ARM( "1: " T(str) " " __reg_oper1 ", [%1], #4\n" ) \ + ARM( "2: " T(str) " " __reg_oper0 ", [%1]\n" ) \ + THUMB( "1: " T(str) " " __reg_oper1 ", [%1]\n" ) \ + THUMB( "2: " T(str) " " __reg_oper0 ", [%1, #4]\n" ) \ "3:\n" \ " .pushsection .fixup,\"ax\"\n" \ " .align 2\n" \ diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index c09e3573c5deb..35f3f20d67318 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -735,7 +735,7 @@ ENTRY(__switch_to) THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack THUMB( str sp, [ip], #4 ) THUMB( str lr, [ip], #4 ) -#ifdef CONFIG_MMU +#ifdef CONFIG_CPU_USE_DOMAINS ldr r6, [r2, #TI_CPU_DOMAIN] #endif set_tls r3, r4, r5 @@ -744,7 +744,7 @@ ENTRY(__switch_to) ldr r8, =__stack_chk_guard ldr r7, [r7, #TSK_STACK_CANARY] #endif -#ifdef CONFIG_MMU +#ifdef CONFIG_CPU_USE_DOMAINS mcr p15, 0, r6, c3, c0, 0 @ Set domain register #endif mov r5, r0 diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index 6ff7919613d7d..d601ef297eb62 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -45,6 +45,7 @@ #include #include #include +#include static unsigned long no_fiq_insn; @@ -77,7 +78,11 @@ int show_fiq_list(struct seq_file *p, void *v) void set_fiq_handler(void *start, unsigned int length) { +#if defined(CONFIG_CPU_USE_DOMAINS) memcpy((void *)0xffff001c, start, length); +#else + memcpy(vectors_page + 0x1c, start, length); +#endif flush_icache_range(0xffff001c, 0xffff001c + length); if (!vectors_high()) flush_icache_range(0x1c, 0x1c + length); diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index cda78d59aa31b..87abca018054c 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -37,6 +37,8 @@ static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; +void *vectors_page; + #ifdef CONFIG_DEBUG_USER unsigned int user_debug; @@ -759,7 +761,11 @@ static void __init kuser_get_tls_init(unsigned long vectors) void __init early_trap_init(void) { +#if defined(CONFIG_CPU_USE_DOMAINS) unsigned long vectors = CONFIG_VECTORS_BASE; +#else + unsigned long vectors = (unsigned long)vectors_page; +#endif extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; extern char __kuser_helper_start[], __kuser_helper_end[]; @@ -783,10 +789,10 @@ void __init early_trap_init(void) * Copy signal return handlers into the vector page, and * set sigreturn to be a pointer to these. */ - memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes, - sizeof(sigreturn_codes)); - memcpy((void *)KERN_RESTART_CODE, syscall_restart_code, - sizeof(syscall_restart_code)); + memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), + sigreturn_codes, sizeof(sigreturn_codes)); + memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE), + syscall_restart_code, sizeof(syscall_restart_code)); flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index b1631a7dbe750..1b049cd7a49a8 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -28,20 +28,21 @@ */ #include #include +#include ENTRY(__get_user_1) -1: ldrbt r2, [r0] +1: T(ldrb) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__get_user_1) ENTRY(__get_user_2) #ifdef CONFIG_THUMB2_KERNEL -2: ldrbt r2, [r0] -3: ldrbt r3, [r0, #1] +2: T(ldrb) r2, [r0] +3: T(ldrb) r3, [r0, #1] #else -2: ldrbt r2, [r0], #1 -3: ldrbt r3, [r0] +2: T(ldrb) r2, [r0], #1 +3: T(ldrb) r3, [r0] #endif #ifndef __ARMEB__ orr r2, r2, r3, lsl #8 @@ -53,7 +54,7 @@ ENTRY(__get_user_2) ENDPROC(__get_user_2) ENTRY(__get_user_4) -4: ldrt r2, [r0] +4: T(ldr) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__get_user_4) diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S index 5a01a23c6c06f..c023fc11e86c7 100644 --- a/arch/arm/lib/putuser.S +++ b/arch/arm/lib/putuser.S @@ -28,9 +28,10 @@ */ #include #include +#include ENTRY(__put_user_1) -1: strbt r2, [r0] +1: T(strb) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__put_user_1) @@ -39,19 +40,19 @@ ENTRY(__put_user_2) mov ip, r2, lsr #8 #ifdef CONFIG_THUMB2_KERNEL #ifndef __ARMEB__ -2: strbt r2, [r0] -3: strbt ip, [r0, #1] +2: T(strb) r2, [r0] +3: T(strb) ip, [r0, #1] #else -2: strbt ip, [r0] -3: strbt r2, [r0, #1] +2: T(strb) ip, [r0] +3: T(strb) r2, [r0, #1] #endif #else /* !CONFIG_THUMB2_KERNEL */ #ifndef __ARMEB__ -2: strbt r2, [r0], #1 -3: strbt ip, [r0] +2: T(strb) r2, [r0], #1 +3: T(strb) ip, [r0] #else -2: strbt ip, [r0], #1 -3: strbt r2, [r0] +2: T(strb) ip, [r0], #1 +3: T(strb) r2, [r0] #endif #endif /* CONFIG_THUMB2_KERNEL */ mov r0, #0 @@ -59,18 +60,18 @@ ENTRY(__put_user_2) ENDPROC(__put_user_2) ENTRY(__put_user_4) -4: strt r2, [r0] +4: T(str) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__put_user_4) ENTRY(__put_user_8) #ifdef CONFIG_THUMB2_KERNEL -5: strt r2, [r0] -6: strt r3, [r0, #4] +5: T(str) r2, [r0] +6: T(str) r3, [r0, #4] #else -5: strt r2, [r0], #4 -6: strt r3, [r0] +5: T(str) r2, [r0], #4 +6: T(str) r3, [r0] #endif mov r0, #0 mov pc, lr diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S index fee9f6f88adb5..d0ece2aeb70df 100644 --- a/arch/arm/lib/uaccess.S +++ b/arch/arm/lib/uaccess.S @@ -14,6 +14,7 @@ #include #include #include +#include .text @@ -31,11 +32,11 @@ rsb ip, ip, #4 cmp ip, #2 ldrb r3, [r1], #1 -USER( strbt r3, [r0], #1) @ May fault +USER( T(strb) r3, [r0], #1) @ May fault ldrgeb r3, [r1], #1 -USER( strgebt r3, [r0], #1) @ May fault +USER( T(strgeb) r3, [r0], #1) @ May fault ldrgtb r3, [r1], #1 -USER( strgtbt r3, [r0], #1) @ May fault +USER( T(strgtb) r3, [r0], #1) @ May fault sub r2, r2, ip b .Lc2u_dest_aligned @@ -58,7 +59,7 @@ ENTRY(__copy_to_user) addmi ip, r2, #4 bmi .Lc2u_0nowords ldr r3, [r1], #4 -USER( strt r3, [r0], #4) @ May fault +USER( T(str) r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -87,18 +88,18 @@ USER( strt r3, [r0], #4) @ May fault stmneia r0!, {r3 - r4} @ Shouldnt fault tst ip, #4 ldrne r3, [r1], #4 - strnet r3, [r0], #4 @ Shouldnt fault + T(strne) r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .Lc2u_0fupi .Lc2u_0nowords: teq ip, #0 beq .Lc2u_finished .Lc2u_nowords: cmp ip, #2 ldrb r3, [r1], #1 -USER( strbt r3, [r0], #1) @ May fault +USER( T(strb) r3, [r0], #1) @ May fault ldrgeb r3, [r1], #1 -USER( strgebt r3, [r0], #1) @ May fault +USER( T(strgeb) r3, [r0], #1) @ May fault ldrgtb r3, [r1], #1 -USER( strgtbt r3, [r0], #1) @ May fault +USER( T(strgtb) r3, [r0], #1) @ May fault b .Lc2u_finished .Lc2u_not_enough: @@ -119,7 +120,7 @@ USER( strgtbt r3, [r0], #1) @ May fault mov r3, r7, pull #8 ldr r7, [r1], #4 orr r3, r3, r7, push #24 -USER( strt r3, [r0], #4) @ May fault +USER( T(str) r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -154,18 +155,18 @@ USER( strt r3, [r0], #4) @ May fault movne r3, r7, pull #8 ldrne r7, [r1], #4 orrne r3, r3, r7, push #24 - strnet r3, [r0], #4 @ Shouldnt fault + T(strne) r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .Lc2u_1fupi .Lc2u_1nowords: mov r3, r7, get_byte_1 teq ip, #0 beq .Lc2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) @ May fault +USER( T(strb) r3, [r0], #1) @ May fault movge r3, r7, get_byte_2 -USER( strgebt r3, [r0], #1) @ May fault +USER( T(strgeb) r3, [r0], #1) @ May fault movgt r3, r7, get_byte_3 -USER( strgtbt r3, [r0], #1) @ May fault +USER( T(strgtb) r3, [r0], #1) @ May fault b .Lc2u_finished .Lc2u_2fupi: subs r2, r2, #4 @@ -174,7 +175,7 @@ USER( strgtbt r3, [r0], #1) @ May fault mov r3, r7, pull #16 ldr r7, [r1], #4 orr r3, r3, r7, push #16 -USER( strt r3, [r0], #4) @ May fault +USER( T(str) r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -209,18 +210,18 @@ USER( strt r3, [r0], #4) @ May fault movne r3, r7, pull #16 ldrne r7, [r1], #4 orrne r3, r3, r7, push #16 - strnet r3, [r0], #4 @ Shouldnt fault + T(strne) r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .Lc2u_2fupi .Lc2u_2nowords: mov r3, r7, get_byte_2 teq ip, #0 beq .Lc2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) @ May fault +USER( T(strb) r3, [r0], #1) @ May fault movge r3, r7, get_byte_3 -USER( strgebt r3, [r0], #1) @ May fault +USER( T(strgeb) r3, [r0], #1) @ May fault ldrgtb r3, [r1], #0 -USER( strgtbt r3, [r0], #1) @ May fault +USER( T(strgtb) r3, [r0], #1) @ May fault b .Lc2u_finished .Lc2u_3fupi: subs r2, r2, #4 @@ -229,7 +230,7 @@ USER( strgtbt r3, [r0], #1) @ May fault mov r3, r7, pull #24 ldr r7, [r1], #4 orr r3, r3, r7, push #8 -USER( strt r3, [r0], #4) @ May fault +USER( T(str) r3, [r0], #4) @ May fault mov ip, r0, lsl #32 - PAGE_SHIFT rsb ip, ip, #0 movs ip, ip, lsr #32 - PAGE_SHIFT @@ -264,18 +265,18 @@ USER( strt r3, [r0], #4) @ May fault movne r3, r7, pull #24 ldrne r7, [r1], #4 orrne r3, r3, r7, push #8 - strnet r3, [r0], #4 @ Shouldnt fault + T(strne) r3, [r0], #4 @ Shouldnt fault ands ip, ip, #3 beq .Lc2u_3fupi .Lc2u_3nowords: mov r3, r7, get_byte_3 teq ip, #0 beq .Lc2u_finished cmp ip, #2 -USER( strbt r3, [r0], #1) @ May fault +USER( T(strb) r3, [r0], #1) @ May fault ldrgeb r3, [r1], #1 -USER( strgebt r3, [r0], #1) @ May fault +USER( T(strgeb) r3, [r0], #1) @ May fault ldrgtb r3, [r1], #0 -USER( strgtbt r3, [r0], #1) @ May fault +USER( T(strgtb) r3, [r0], #1) @ May fault b .Lc2u_finished ENDPROC(__copy_to_user) @@ -294,11 +295,11 @@ ENDPROC(__copy_to_user) .Lcfu_dest_not_aligned: rsb ip, ip, #4 cmp ip, #2 -USER( ldrbt r3, [r1], #1) @ May fault +USER( T(ldrb) r3, [r1], #1) @ May fault strb r3, [r0], #1 -USER( ldrgebt r3, [r1], #1) @ May fault +USER( T(ldrgeb) r3, [r1], #1) @ May fault strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #1) @ May fault +USER( T(ldrgtb) r3, [r1], #1) @ May fault strgtb r3, [r0], #1 sub r2, r2, ip b .Lcfu_dest_aligned @@ -321,7 +322,7 @@ ENTRY(__copy_from_user) .Lcfu_0fupi: subs r2, r2, #4 addmi ip, r2, #4 bmi .Lcfu_0nowords -USER( ldrt r3, [r1], #4) +USER( T(ldr) r3, [r1], #4) str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction rsb ip, ip, #0 @@ -350,18 +351,18 @@ USER( ldrt r3, [r1], #4) ldmneia r1!, {r3 - r4} @ Shouldnt fault stmneia r0!, {r3 - r4} tst ip, #4 - ldrnet r3, [r1], #4 @ Shouldnt fault + T(ldrne) r3, [r1], #4 @ Shouldnt fault strne r3, [r0], #4 ands ip, ip, #3 beq .Lcfu_0fupi .Lcfu_0nowords: teq ip, #0 beq .Lcfu_finished .Lcfu_nowords: cmp ip, #2 -USER( ldrbt r3, [r1], #1) @ May fault +USER( T(ldrb) r3, [r1], #1) @ May fault strb r3, [r0], #1 -USER( ldrgebt r3, [r1], #1) @ May fault +USER( T(ldrgeb) r3, [r1], #1) @ May fault strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #1) @ May fault +USER( T(ldrgtb) r3, [r1], #1) @ May fault strgtb r3, [r0], #1 b .Lcfu_finished @@ -374,7 +375,7 @@ USER( ldrgtbt r3, [r1], #1) @ May fault .Lcfu_src_not_aligned: bic r1, r1, #3 -USER( ldrt r7, [r1], #4) @ May fault +USER( T(ldr) r7, [r1], #4) @ May fault cmp ip, #2 bgt .Lcfu_3fupi beq .Lcfu_2fupi @@ -382,7 +383,7 @@ USER( ldrt r7, [r1], #4) @ May fault addmi ip, r2, #4 bmi .Lcfu_1nowords mov r3, r7, pull #8 -USER( ldrt r7, [r1], #4) @ May fault +USER( T(ldr) r7, [r1], #4) @ May fault orr r3, r3, r7, push #24 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -417,7 +418,7 @@ USER( ldrt r7, [r1], #4) @ May fault stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, pull #8 -USER( ldrnet r7, [r1], #4) @ May fault +USER( T(ldrne) r7, [r1], #4) @ May fault orrne r3, r3, r7, push #24 strne r3, [r0], #4 ands ip, ip, #3 @@ -437,7 +438,7 @@ USER( ldrnet r7, [r1], #4) @ May fault addmi ip, r2, #4 bmi .Lcfu_2nowords mov r3, r7, pull #16 -USER( ldrt r7, [r1], #4) @ May fault +USER( T(ldr) r7, [r1], #4) @ May fault orr r3, r3, r7, push #16 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -473,7 +474,7 @@ USER( ldrt r7, [r1], #4) @ May fault stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, pull #16 -USER( ldrnet r7, [r1], #4) @ May fault +USER( T(ldrne) r7, [r1], #4) @ May fault orrne r3, r3, r7, push #16 strne r3, [r0], #4 ands ip, ip, #3 @@ -485,7 +486,7 @@ USER( ldrnet r7, [r1], #4) @ May fault strb r3, [r0], #1 movge r3, r7, get_byte_3 strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #0) @ May fault +USER( T(ldrgtb) r3, [r1], #0) @ May fault strgtb r3, [r0], #1 b .Lcfu_finished @@ -493,7 +494,7 @@ USER( ldrgtbt r3, [r1], #0) @ May fault addmi ip, r2, #4 bmi .Lcfu_3nowords mov r3, r7, pull #24 -USER( ldrt r7, [r1], #4) @ May fault +USER( T(ldr) r7, [r1], #4) @ May fault orr r3, r3, r7, push #8 str r3, [r0], #4 mov ip, r1, lsl #32 - PAGE_SHIFT @@ -528,7 +529,7 @@ USER( ldrt r7, [r1], #4) @ May fault stmneia r0!, {r3 - r4} tst ip, #4 movne r3, r7, pull #24 -USER( ldrnet r7, [r1], #4) @ May fault +USER( T(ldrne) r7, [r1], #4) @ May fault orrne r3, r3, r7, push #8 strne r3, [r0], #4 ands ip, ip, #3 @@ -538,9 +539,9 @@ USER( ldrnet r7, [r1], #4) @ May fault beq .Lcfu_finished cmp ip, #2 strb r3, [r0], #1 -USER( ldrgebt r3, [r1], #1) @ May fault +USER( T(ldrgeb) r3, [r1], #1) @ May fault strgeb r3, [r0], #1 -USER( ldrgtbt r3, [r1], #1) @ May fault +USER( T(ldrgtb) r3, [r1], #1) @ May fault strgtb r3, [r0], #1 b .Lcfu_finished ENDPROC(__copy_from_user) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 4414a01e1e8a3..6d05f79a8cd25 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -599,6 +599,14 @@ config CPU_CP15_MPU help Processor has the CP15 register, which has MPU related registers. +config CPU_USE_DOMAINS + bool + depends on MMU + default y if !CPU_32v6K + help + This option enables or disables the use of domain switching + via the set_fs() function. + # # CPU supports 36-bit I/O # diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 72ad3e1f56cfb..79c01f540cbe3 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -914,12 +915,11 @@ static void __init devicemaps_init(struct machine_desc *mdesc) { struct map_desc map; unsigned long addr; - void *vectors; /* * Allocate the vector page early. */ - vectors = early_alloc(PAGE_SIZE); + vectors_page = early_alloc(PAGE_SIZE); for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE) pmd_clear(pmd_off_k(addr)); @@ -959,7 +959,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc) * location (0xffff0000). If we aren't using high-vectors, also * create a mapping at the low-vectors virtual address. */ - map.pfn = __phys_to_pfn(virt_to_phys(vectors)); + map.pfn = __phys_to_pfn(virt_to_phys(vectors_page)); map.virtual = 0xffff0000; map.length = PAGE_SIZE; map.type = MT_HIGH_VECTORS; diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index 7d63beaf97456..337f10256cd68 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -99,6 +99,10 @@ * 110x 0 1 0 r/w r/o * 11x0 0 1 0 r/w r/o * 1111 0 1 1 r/w r/w + * + * If !CONFIG_CPU_USE_DOMAINS, the following permissions are changed: + * 110x 1 1 1 r/o r/o + * 11x0 1 1 1 r/o r/o */ .macro armv6_mt_table pfx \pfx\()_mt_table: @@ -138,8 +142,11 @@ tst r1, #L_PTE_USER orrne r3, r3, #PTE_EXT_AP1 +#ifdef CONFIG_CPU_USE_DOMAINS + @ allow kernel read/write access to read-only user pages tstne r3, #PTE_EXT_APX bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0 +#endif tst r1, #L_PTE_EXEC orreq r3, r3, #PTE_EXT_XN diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 53cbe2225153d..cfc11afab1fb1 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -148,8 +148,11 @@ ENTRY(cpu_v7_set_pte_ext) tst r1, #L_PTE_USER orrne r3, r3, #PTE_EXT_AP1 +#ifdef CONFIG_CPU_USE_DOMAINS + @ allow kernel read/write access to read-only user pages tstne r3, #PTE_EXT_APX bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0 +#endif tst r1, #L_PTE_EXEC orreq r3, r3, #PTE_EXT_XN @@ -273,8 +276,6 @@ __v7_setup: ALT_SMP(orr r4, r4, #TTB_FLAGS_SMP) ALT_UP(orr r4, r4, #TTB_FLAGS_UP) mcr p15, 0, r4, c2, c0, 1 @ load TTB1 - mov r10, #0x1f @ domains 0, 1 = manager - mcr p15, 0, r10, c3, c0, 0 @ load domain access register /* * Memory region attributes with SCTLR.TRE=1 * From 64d2dc384e41e2b7acead6804593ddaaf8aad8e1 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Thu, 16 Sep 2010 18:00:47 +0100 Subject: [PATCH 02/52] ARM: 6396/1: Add SWP/SWPB emulation for ARMv7 processors The SWP instruction was deprecated in the ARMv6 architecture, superseded by the LDREX/STREX family of instructions for load-linked/store-conditional operations. The ARMv7 multiprocessing extensions mandate that SWP/SWPB instructions are treated as undefined from reset, with the ability to enable them through the System Control Register SW bit. This patch adds the alternative solution to emulate the SWP and SWPB instructions using LDREX/STREX sequences, and log statistics to /proc/cpu/swp_emulation. To correctly deal with copy-on-write, it also modifies cpu_v7_set_pte_ext to change the mappings to priviliged RO when user RO. Signed-off-by: Leif Lindholm Acked-by: Catalin Marinas Acked-by: Kirill A. Shutemov Signed-off-by: Russell King --- Documentation/arm/00-INDEX | 2 + Documentation/arm/swp_emulation | 27 ++++ arch/arm/kernel/Makefile | 1 + arch/arm/kernel/swp_emulate.c | 267 ++++++++++++++++++++++++++++++++ arch/arm/mm/Kconfig | 27 ++++ arch/arm/mm/proc-v7.S | 4 + 6 files changed, 328 insertions(+) create mode 100644 Documentation/arm/swp_emulation create mode 100644 arch/arm/kernel/swp_emulate.c diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX index ecf7d04bca260..91c24a1e8a9ef 100644 --- a/Documentation/arm/00-INDEX +++ b/Documentation/arm/00-INDEX @@ -34,3 +34,5 @@ memory.txt - description of the virtual memory layout nwfpe/ - NWFPE floating point emulator documentation +swp_emulation + - SWP/SWPB emulation handler/logging description diff --git a/Documentation/arm/swp_emulation b/Documentation/arm/swp_emulation new file mode 100644 index 0000000000000..af903d22fd934 --- /dev/null +++ b/Documentation/arm/swp_emulation @@ -0,0 +1,27 @@ +Software emulation of deprecated SWP instruction (CONFIG_SWP_EMULATE) +--------------------------------------------------------------------- + +ARMv6 architecture deprecates use of the SWP/SWPB instructions, and recommeds +moving to the load-locked/store-conditional instructions LDREX and STREX. + +ARMv7 multiprocessing extensions introduce the ability to disable these +instructions, triggering an undefined instruction exception when executed. +Trapped instructions are emulated using an LDREX/STREX or LDREXB/STREXB +sequence. If a memory access fault (an abort) occurs, a segmentation fault is +signalled to the triggering process. + +/proc/cpu/swp_emulation holds some statistics/information, including the PID of +the last process to trigger the emulation to be invocated. For example: +--- +Emulated SWP: 12 +Emulated SWPB: 0 +Aborted SWP{B}: 1 +Last process: 314 +--- + +NOTE: when accessing uncached shared regions, LDREX/STREX rely on an external +transaction monitoring block called a global monitor to maintain update +atomicity. If your system does not implement a global monitor, this option can +cause programs that perform SWP operations to uncached memory to deadlock, as +the STREX operation will always fail. + diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5b9b268f4fbb3..119a6bb59bde2 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_ARM_UNWIND) += unwind.o obj-$(CONFIG_HAVE_TCM) += tcm.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o +obj-$(CONFIG_SWP_EMULATE) += swp_emulate.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c new file mode 100644 index 0000000000000..7a57609229141 --- /dev/null +++ b/arch/arm/kernel/swp_emulate.c @@ -0,0 +1,267 @@ +/* + * linux/arch/arm/kernel/swp_emulate.c + * + * Copyright (C) 2009 ARM Limited + * __user_* functions adapted from include/asm/uaccess.h + * + * 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 + * published by the Free Software Foundation. + * + * Implements emulation of the SWP/SWPB instructions using load-exclusive and + * store-exclusive for processors that have them disabled (or future ones that + * might not implement them). + * + * Syntax of SWP{B} instruction: SWP{B} , , [] + * Where: Rt = destination + * Rt2 = source + * Rn = address + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Error-checking SWP macros implemented using ldrex{b}/strex{b} + */ +#define __user_swpX_asm(data, addr, res, temp, B) \ + __asm__ __volatile__( \ + " mov %2, %1\n" \ + "0: ldrex"B" %1, [%3]\n" \ + "1: strex"B" %0, %2, [%3]\n" \ + " cmp %0, #0\n" \ + " movne %0, %4\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + " .align 2\n" \ + "3: mov %0, %5\n" \ + " b 2b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .long 0b, 3b\n" \ + " .long 1b, 3b\n" \ + " .previous" \ + : "=&r" (res), "+r" (data), "=&r" (temp) \ + : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ + : "cc", "memory") + +#define __user_swp_asm(data, addr, res, temp) \ + __user_swpX_asm(data, addr, res, temp, "") +#define __user_swpb_asm(data, addr, res, temp) \ + __user_swpX_asm(data, addr, res, temp, "b") + +/* + * Macros/defines for extracting register numbers from instruction. + */ +#define EXTRACT_REG_NUM(instruction, offset) \ + (((instruction) & (0xf << (offset))) >> (offset)) +#define RN_OFFSET 16 +#define RT_OFFSET 12 +#define RT2_OFFSET 0 +/* + * Bit 22 of the instruction encoding distinguishes between + * the SWP and SWPB variants (bit set means SWPB). + */ +#define TYPE_SWPB (1 << 22) + +static unsigned long swpcounter; +static unsigned long swpbcounter; +static unsigned long abtcounter; +static pid_t previous_pid; + +#ifdef CONFIG_PROC_FS +static int proc_read_status(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + char *p = page; + int len; + + p += sprintf(p, "Emulated SWP:\t\t%lu\n", swpcounter); + p += sprintf(p, "Emulated SWPB:\t\t%lu\n", swpbcounter); + p += sprintf(p, "Aborted SWP{B}:\t\t%lu\n", abtcounter); + if (previous_pid != 0) + p += sprintf(p, "Last process:\t\t%d\n", previous_pid); + + len = (p - page) - off; + if (len < 0) + len = 0; + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + return len; +} +#endif + +/* + * Set up process info to signal segmentation fault - called on access error. + */ +static void set_segfault(struct pt_regs *regs, unsigned long addr) +{ + siginfo_t info; + + if (find_vma(current->mm, addr) == NULL) + info.si_code = SEGV_MAPERR; + else + info.si_code = SEGV_ACCERR; + + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_addr = (void *) instruction_pointer(regs); + + pr_debug("SWP{B} emulation: access caused memory abort!\n"); + arm_notify_die("Illegal memory access", regs, &info, 0, 0); + + abtcounter++; +} + +static int emulate_swpX(unsigned int address, unsigned int *data, + unsigned int type) +{ + unsigned int res = 0; + + if ((type != TYPE_SWPB) && (address & 0x3)) { + /* SWP to unaligned address not permitted */ + pr_debug("SWP instruction on unaligned pointer!\n"); + return -EFAULT; + } + + while (1) { + unsigned long temp; + + /* + * Barrier required between accessing protected resource and + * releasing a lock for it. Legacy code might not have done + * this, and we cannot determine that this is not the case + * being emulated, so insert always. + */ + smp_mb(); + + if (type == TYPE_SWPB) + __user_swpb_asm(*data, address, res, temp); + else + __user_swp_asm(*data, address, res, temp); + + if (likely(res != -EAGAIN) || signal_pending(current)) + break; + + cond_resched(); + } + + if (res == 0) { + /* + * Barrier also required between aquiring a lock for a + * protected resource and accessing the resource. Inserted for + * same reason as above. + */ + smp_mb(); + + if (type == TYPE_SWPB) + swpbcounter++; + else + swpcounter++; + } + + return res; +} + +/* + * swp_handler logs the id of calling process, dissects the instruction, sanity + * checks the memory location, calls emulate_swpX for the actual operation and + * deals with fixup/error handling before returning + */ +static int swp_handler(struct pt_regs *regs, unsigned int instr) +{ + unsigned int address, destreg, data, type; + unsigned int res = 0; + + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, regs->ARM_pc); + + if (current->pid != previous_pid) { + pr_debug("\"%s\" (%ld) uses deprecated SWP{B} instruction\n", + current->comm, (unsigned long)current->pid); + previous_pid = current->pid; + } + + address = regs->uregs[EXTRACT_REG_NUM(instr, RN_OFFSET)]; + data = regs->uregs[EXTRACT_REG_NUM(instr, RT2_OFFSET)]; + destreg = EXTRACT_REG_NUM(instr, RT_OFFSET); + + type = instr & TYPE_SWPB; + + pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n", + EXTRACT_REG_NUM(instr, RN_OFFSET), address, + destreg, EXTRACT_REG_NUM(instr, RT2_OFFSET), data); + + /* Check access in reasonable access range for both SWP and SWPB */ + if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) { + pr_debug("SWP{B} emulation: access to %p not allowed!\n", + (void *)address); + res = -EFAULT; + } else { + res = emulate_swpX(address, &data, type); + } + + if (res == 0) { + /* + * On successful emulation, revert the adjustment to the PC + * made in kernel/traps.c in order to resume execution at the + * instruction following the SWP{B}. + */ + regs->ARM_pc += 4; + regs->uregs[destreg] = data; + } else if (res == -EFAULT) { + /* + * Memory errors do not mean emulation failed. + * Set up signal info to return SEGV, then return OK + */ + set_segfault(regs, address); + } + + return 0; +} + +/* + * Only emulate SWP/SWPB executed in ARM state/User mode. + * The kernel must be SWP free and SWP{B} does not exist in Thumb/ThumbEE. + */ +static struct undef_hook swp_hook = { + .instr_mask = 0x0fb00ff0, + .instr_val = 0x01000090, + .cpsr_mask = MODE_MASK | PSR_T_BIT | PSR_J_BIT, + .cpsr_val = USR_MODE, + .fn = swp_handler +}; + +/* + * Register handler and create status file in /proc/cpu + * Invoked as late_initcall, since not needed before init spawned. + */ +static int __init swp_emulation_init(void) +{ +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *res; + + res = create_proc_entry("cpu/swp_emulation", S_IRUGO, NULL); + + if (!res) + return -ENOMEM; + + res->read_proc = proc_read_status; +#endif /* CONFIG_PROC_FS */ + + printk(KERN_NOTICE "Registering SWP/SWPB emulation handler\n"); + register_undef_hook(&swp_hook); + + return 0; +} + +late_initcall(swp_emulation_init); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 6d05f79a8cd25..8493ed04797a6 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -636,6 +636,33 @@ config ARM_THUMBEE Say Y here if you have a CPU with the ThumbEE extension and code to make use of it. Say N for code that can run on CPUs without ThumbEE. +config SWP_EMULATE + bool "Emulate SWP/SWPB instructions" + depends on CPU_V7 + select HAVE_PROC_CPU if PROC_FS + default y if SMP + help + ARMv6 architecture deprecates use of the SWP/SWPB instructions. + ARMv7 multiprocessing extensions introduce the ability to disable + these instructions, triggering an undefined instruction exception + when executed. Say Y here to enable software emulation of these + instructions for userspace (not kernel) using LDREX/STREX. + Also creates /proc/cpu/swp_emulation for statistics. + + In some older versions of glibc [<=2.8] SWP is used during futex + trylock() operations with the assumption that the code will not + be preempted. This invalid assumption may be more likely to fail + with SWP emulation enabled, leading to deadlock of the user + application. + + NOTE: when accessing uncached shared regions, LDREX/STREX rely + on an external transaction monitoring block called a global + monitor to maintain update atomicity. If your system does not + implement a global monitor, this option can cause programs that + perform SWP operations to uncached memory to deadlock. + + If unsure, say Y. + config CPU_BIG_ENDIAN bool "Build big-endian kernel" depends on ARCH_SUPPORTS_BIG_ENDIAN diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index cfc11afab1fb1..2b5b20baf80d2 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -313,6 +313,10 @@ __v7_setup: ldmia r5, {r5, r6} #ifdef CONFIG_CPU_ENDIAN_BE8 orr r6, r6, #1 << 25 @ big-endian page tables +#endif +#ifdef CONFIG_SWP_EMULATE + orr r5, r5, #(1 << 10) @ set SW bit in "clear" + bic r6, r6, #(1 << 10) @ clear it in "mmuset" #endif mrc p15, 0, r0, c1, c0, 0 @ read control register bic r0, r0, r5 @ clear bits them From 6d803ba736abb5e122dede70a4720e4843dd6df4 Mon Sep 17 00:00:00 2001 From: Jean-Christop PLAGNIOL-VILLARD Date: Wed, 17 Nov 2010 10:04:33 +0100 Subject: [PATCH 03/52] ARM: 6483/1: arm & sh: factorised duplicated clkdev.c factorise some generic infrastructure to assist looking up struct clks for the ARM & SH architecture. as the code is identical at 99% put the arch specific code for allocation as example in asm/clkdev.h Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Paul Mundt Signed-off-by: Russell King --- arch/arm/Kconfig | 42 ++--- arch/arm/common/Kconfig | 4 - arch/arm/common/Makefile | 1 - arch/arm/include/asm/clkdev.h | 22 +-- arch/arm/mach-bcmring/clock.c | 3 +- arch/arm/mach-bcmring/core.c | 2 +- arch/arm/mach-davinci/clock.h | 2 +- arch/arm/mach-ep93xx/clock.c | 2 +- arch/arm/mach-imx/clock-imx1.c | 3 +- arch/arm/mach-imx/clock-imx21.c | 2 +- arch/arm/mach-imx/clock-imx27.c | 2 +- arch/arm/mach-integrator/core.c | 3 +- arch/arm/mach-integrator/impd1.c | 3 +- arch/arm/mach-integrator/integrator_cp.c | 3 +- arch/arm/mach-lpc32xx/clock.c | 3 +- arch/arm/mach-mmp/clock.h | 2 +- arch/arm/mach-mx25/clock.c | 3 +- arch/arm/mach-mx3/clock-imx31.c | 2 +- arch/arm/mach-mx3/clock-imx35.c | 3 +- arch/arm/mach-mx5/clock-mx51.c | 2 +- arch/arm/mach-mxc91231/clock.c | 2 +- arch/arm/mach-nomadik/clock.c | 2 +- arch/arm/mach-nuc93x/clock.h | 2 +- arch/arm/mach-omap1/clock.c | 2 +- arch/arm/mach-omap2/dpll3xxx.c | 2 +- arch/arm/mach-pnx4008/clock.c | 3 +- arch/arm/mach-pxa/clock.c | 2 +- arch/arm/mach-pxa/clock.h | 2 +- arch/arm/mach-realview/core.c | 3 +- arch/arm/mach-shmobile/Kconfig | 6 +- arch/arm/mach-shmobile/clock-sh7367.c | 2 +- arch/arm/mach-shmobile/clock-sh7372.c | 2 +- arch/arm/mach-shmobile/clock-sh7377.c | 2 +- arch/arm/mach-tcc8k/clock.c | 3 +- arch/arm/mach-tegra/clock.c | 2 +- arch/arm/mach-tegra/clock.h | 2 +- arch/arm/mach-tegra/tegra2_clocks.c | 3 +- arch/arm/mach-u300/clock.c | 2 +- arch/arm/mach-ux500/clock.c | 3 +- arch/arm/mach-versatile/core.c | 3 +- arch/arm/mach-vexpress/ct-ca9x4.c | 3 +- arch/arm/mach-vexpress/v2m.c | 3 +- arch/arm/mach-w90x900/clock.h | 2 +- arch/arm/plat-omap/Kconfig | 4 +- arch/arm/plat-omap/include/plat/clkdev_omap.h | 2 +- arch/arm/plat-spear/include/plat/clock.h | 2 +- arch/arm/plat-stmp3xxx/clock.c | 2 +- arch/sh/Kconfig | 2 +- arch/sh/boards/mach-highlander/setup.c | 2 +- arch/sh/include/asm/clkdev.h | 38 ++-- arch/sh/kernel/Makefile | 2 +- arch/sh/kernel/clkdev.c | 171 ------------------ arch/sh/kernel/cpu/clock-cpg.c | 2 +- arch/sh/kernel/cpu/clock.c | 16 -- arch/sh/kernel/cpu/sh4/clock-sh4-202.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-sh7343.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-sh7366.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-sh7722.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-sh7723.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-sh7724.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-sh7757.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-sh7763.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-sh7780.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-sh7785.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-sh7786.c | 2 +- arch/sh/kernel/cpu/sh4a/clock-shx3.c | 2 +- drivers/Kconfig | 2 + drivers/Makefile | 2 + drivers/clk/Kconfig | 4 + drivers/clk/Makefile | 2 + {arch/arm/common => drivers/clk}/clkdev.c | 13 +- include/linux/clkdev.h | 36 ++++ 72 files changed, 157 insertions(+), 336 deletions(-) delete mode 100644 arch/sh/kernel/clkdev.c create mode 100644 drivers/clk/Kconfig create mode 100644 drivers/clk/Makefile rename {arch/arm/common => drivers/clk}/clkdev.c (93%) create mode 100644 include/linux/clkdev.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a19a5266d5fc9..0e51342b3c024 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -221,7 +221,7 @@ config ARCH_INTEGRATOR bool "ARM Ltd. Integrator family" select ARM_AMBA select ARCH_HAS_CPUFREQ - select COMMON_CLKDEV + select CLKDEV_LOOKUP select ICST select GENERIC_CLOCKEVENTS select PLAT_VERSATILE @@ -231,7 +231,7 @@ config ARCH_INTEGRATOR config ARCH_REALVIEW bool "ARM Ltd. RealView family" select ARM_AMBA - select COMMON_CLKDEV + select CLKDEV_LOOKUP select ICST select GENERIC_CLOCKEVENTS select ARCH_WANT_OPTIONAL_GPIOLIB @@ -245,7 +245,7 @@ config ARCH_VERSATILE bool "ARM Ltd. Versatile family" select ARM_AMBA select ARM_VIC - select COMMON_CLKDEV + select CLKDEV_LOOKUP select ICST select GENERIC_CLOCKEVENTS select ARCH_WANT_OPTIONAL_GPIOLIB @@ -259,7 +259,7 @@ config ARCH_VEXPRESS select ARCH_WANT_OPTIONAL_GPIOLIB select ARM_AMBA select ARM_TIMER_SP804 - select COMMON_CLKDEV + select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS select HAVE_CLK select ICST @@ -280,7 +280,7 @@ config ARCH_BCMRING depends on MMU select CPU_V6 select ARM_AMBA - select COMMON_CLKDEV + select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS select ARCH_WANT_OPTIONAL_GPIOLIB help @@ -327,7 +327,7 @@ config ARCH_EP93XX select CPU_ARM920T select ARM_AMBA select ARM_VIC - select COMMON_CLKDEV + select CLKDEV_LOOKUP select ARCH_REQUIRE_GPIOLIB select ARCH_HAS_HOLES_MEMORYMODEL select ARCH_USES_GETTIMEOFFSET @@ -347,14 +347,14 @@ config ARCH_MXC bool "Freescale MXC/iMX-based" select GENERIC_CLOCKEVENTS select ARCH_REQUIRE_GPIOLIB - select COMMON_CLKDEV + select CLKDEV_LOOKUP help Support for Freescale MXC/iMX-based family of processors config ARCH_STMP3XXX bool "Freescale STMP3xxx" select CPU_ARM926T - select COMMON_CLKDEV + select CLKDEV_LOOKUP select ARCH_REQUIRE_GPIOLIB select GENERIC_CLOCKEVENTS select USB_ARCH_HAS_EHCI @@ -472,7 +472,7 @@ config ARCH_LPC32XX select HAVE_IDE select ARM_AMBA select USB_ARCH_HAS_OHCI - select COMMON_CLKDEV + select CLKDEV_LOOKUP select GENERIC_TIME select GENERIC_CLOCKEVENTS help @@ -506,7 +506,7 @@ config ARCH_MMP bool "Marvell PXA168/910/MMP2" depends on MMU select ARCH_REQUIRE_GPIOLIB - select COMMON_CLKDEV + select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS select TICK_ONESHOT select PLAT_PXA @@ -539,7 +539,7 @@ config ARCH_W90X900 bool "Nuvoton W90X900 CPU" select CPU_ARM926T select ARCH_REQUIRE_GPIOLIB - select COMMON_CLKDEV + select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS help Support for Nuvoton (Winbond logic dept.) ARM9 processor, @@ -553,7 +553,7 @@ config ARCH_W90X900 config ARCH_NUC93X bool "Nuvoton NUC93X CPU" select CPU_ARM926T - select COMMON_CLKDEV + select CLKDEV_LOOKUP help Support for Nuvoton (Winbond logic dept.) NUC93X MCU,The NUC93X is a low-power and high performance MPEG-4/JPEG multimedia controller chip. @@ -564,7 +564,7 @@ config ARCH_TEGRA select GENERIC_CLOCKEVENTS select GENERIC_GPIO select HAVE_CLK - select COMMON_CLKDEV + select CLKDEV_LOOKUP select ARCH_HAS_BARRIERS if CACHE_L2X0 select ARCH_HAS_CPUFREQ help @@ -574,7 +574,7 @@ config ARCH_TEGRA config ARCH_PNX4008 bool "Philips Nexperia PNX4008 Mobile" select CPU_ARM926T - select COMMON_CLKDEV + select CLKDEV_LOOKUP select ARCH_USES_GETTIMEOFFSET help This enables support for Philips PNX4008 mobile platform. @@ -584,7 +584,7 @@ config ARCH_PXA depends on MMU select ARCH_MTD_XIP select ARCH_HAS_CPUFREQ - select COMMON_CLKDEV + select CLKDEV_LOOKUP select ARCH_REQUIRE_GPIOLIB select GENERIC_CLOCKEVENTS select TICK_ONESHOT @@ -761,7 +761,7 @@ config ARCH_TCC_926 bool "Telechips TCC ARM926-based systems" select CPU_ARM926T select HAVE_CLK - select COMMON_CLKDEV + select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS help Support for Telechips TCC ARM926-based systems. @@ -785,7 +785,7 @@ config ARCH_U300 select ARM_AMBA select ARM_VIC select GENERIC_CLOCKEVENTS - select COMMON_CLKDEV + select CLKDEV_LOOKUP select GENERIC_GPIO help Support for ST-Ericsson U300 series mobile platforms. @@ -795,7 +795,7 @@ config ARCH_U8500 select CPU_V7 select ARM_AMBA select GENERIC_CLOCKEVENTS - select COMMON_CLKDEV + select CLKDEV_LOOKUP select ARCH_REQUIRE_GPIOLIB help Support for ST-Ericsson's Ux500 architecture @@ -805,7 +805,7 @@ config ARCH_NOMADIK select ARM_AMBA select ARM_VIC select CPU_ARM926T - select COMMON_CLKDEV + select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS select ARCH_REQUIRE_GPIOLIB help @@ -817,7 +817,7 @@ config ARCH_DAVINCI select ARCH_REQUIRE_GPIOLIB select ZONE_DMA select HAVE_IDE - select COMMON_CLKDEV + select CLKDEV_LOOKUP select GENERIC_ALLOCATOR select ARCH_HAS_HOLES_MEMORYMODEL help @@ -837,7 +837,7 @@ config PLAT_SPEAR bool "ST SPEAr" select ARM_AMBA select ARCH_REQUIRE_GPIOLIB - select COMMON_CLKDEV + select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS select HAVE_CLK help diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 0a34c81869244..778655f0257a9 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -37,7 +37,3 @@ config SHARP_PARAM config SHARP_SCOOP bool - -config COMMON_CLKDEV - bool - select HAVE_CLK diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index e6e8664a94139..799e140274f15 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -16,4 +16,3 @@ obj-$(CONFIG_SHARP_SCOOP) += scoop.o obj-$(CONFIG_ARCH_IXP2000) += uengine.o obj-$(CONFIG_ARCH_IXP23XX) += uengine.o obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o -obj-$(CONFIG_COMMON_CLKDEV) += clkdev.o diff --git a/arch/arm/include/asm/clkdev.h b/arch/arm/include/asm/clkdev.h index b56c1389b6fa4..765d332223694 100644 --- a/arch/arm/include/asm/clkdev.h +++ b/arch/arm/include/asm/clkdev.h @@ -12,23 +12,13 @@ #ifndef __ASM_CLKDEV_H #define __ASM_CLKDEV_H -struct clk; -struct device; +#include -struct clk_lookup { - struct list_head node; - const char *dev_id; - const char *con_id; - struct clk *clk; -}; +#include -struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id, - const char *dev_fmt, ...); - -void clkdev_add(struct clk_lookup *cl); -void clkdev_drop(struct clk_lookup *cl); - -void clkdev_add_table(struct clk_lookup *, size_t); -int clk_add_alias(const char *, const char *, char *, struct device *); +static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) +{ + return kzalloc(size, GFP_KERNEL); +} #endif diff --git a/arch/arm/mach-bcmring/clock.c b/arch/arm/mach-bcmring/clock.c index 14bafc38f2dcc..ad237a42d265e 100644 --- a/arch/arm/mach-bcmring/clock.c +++ b/arch/arm/mach-bcmring/clock.c @@ -21,13 +21,12 @@ #include #include #include +#include #include #include #include #include -#include - #include "clock.h" #define clk_is_primary(x) ((x)->type & CLK_TYPE_PRIMARY) diff --git a/arch/arm/mach-bcmring/core.c b/arch/arm/mach-bcmring/core.c index d3f959e92b2dd..ed96ef400474b 100644 --- a/arch/arm/mach-bcmring/core.c +++ b/arch/arm/mach-bcmring/core.c @@ -30,10 +30,10 @@ #include #include #include +#include #include #include -#include #include #include #include diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h index 11099980b58bd..0dd22031ec622 100644 --- a/arch/arm/mach-davinci/clock.h +++ b/arch/arm/mach-davinci/clock.h @@ -68,7 +68,7 @@ #ifndef __ASSEMBLER__ #include -#include +#include #define PLLSTAT_GOSTAT BIT(0) #define PLLCMD_GOSET BIT(0) diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index ef06c66a6f163..ca4de71050973 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -19,10 +19,10 @@ #include #include #include +#include #include -#include #include diff --git a/arch/arm/mach-imx/clock-imx1.c b/arch/arm/mach-imx/clock-imx1.c index daca30b2d5b1a..3938a563b2807 100644 --- a/arch/arm/mach-imx/clock-imx1.c +++ b/arch/arm/mach-imx/clock-imx1.c @@ -22,8 +22,7 @@ #include #include #include - -#include +#include #include #include diff --git a/arch/arm/mach-imx/clock-imx21.c b/arch/arm/mach-imx/clock-imx21.c index cf15ea516a72c..d7056559715a0 100644 --- a/arch/arm/mach-imx/clock-imx21.c +++ b/arch/arm/mach-imx/clock-imx21.c @@ -21,11 +21,11 @@ #include #include #include +#include #include #include #include -#include #include #define IO_ADDR_CCM(off) (MX21_IO_ADDRESS(MX21_CCM_BASE_ADDR + (off))) diff --git a/arch/arm/mach-imx/clock-imx27.c b/arch/arm/mach-imx/clock-imx27.c index 98a25bada783f..ca1017b9028d0 100644 --- a/arch/arm/mach-imx/clock-imx27.c +++ b/arch/arm/mach-imx/clock-imx27.c @@ -21,8 +21,8 @@ #include #include #include +#include -#include #include #include diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index 8f4fb6d638f7e..b8e884b450da7 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -21,9 +21,8 @@ #include #include #include +#include -#include -#include #include #include #include diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index fd684bf205e5d..5db574f8ae3fd 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -22,9 +22,8 @@ #include #include #include +#include -#include -#include #include #include #include diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 6258c90d020c3..9403d2fa13a39 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -21,9 +21,8 @@ #include #include #include +#include -#include -#include #include #include #include diff --git a/arch/arm/mach-lpc32xx/clock.c b/arch/arm/mach-lpc32xx/clock.c index 32d63796430aa..da0e6498110a4 100644 --- a/arch/arm/mach-lpc32xx/clock.c +++ b/arch/arm/mach-lpc32xx/clock.c @@ -90,10 +90,9 @@ #include #include #include +#include #include -#include -#include #include #include "clock.h" #include "common.h" diff --git a/arch/arm/mach-mmp/clock.h b/arch/arm/mach-mmp/clock.h index 016ae94691c04..9b027d7491f5e 100644 --- a/arch/arm/mach-mmp/clock.h +++ b/arch/arm/mach-mmp/clock.h @@ -6,7 +6,7 @@ * published by the Free Software Foundation. */ -#include +#include struct clkops { void (*enable)(struct clk *); diff --git a/arch/arm/mach-mx25/clock.c b/arch/arm/mach-mx25/clock.c index 9e4a5578c2fb9..00dcb08019e96 100644 --- a/arch/arm/mach-mx25/clock.c +++ b/arch/arm/mach-mx25/clock.c @@ -21,8 +21,7 @@ #include #include #include - -#include +#include #include #include diff --git a/arch/arm/mach-mx3/clock-imx31.c b/arch/arm/mach-mx3/clock-imx31.c index 109e98f323e05..1cd8b40b7676c 100644 --- a/arch/arm/mach-mx3/clock-imx31.c +++ b/arch/arm/mach-mx3/clock-imx31.c @@ -23,8 +23,8 @@ #include #include #include +#include -#include #include #include diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c index 61e4a318980a2..819dd809615a4 100644 --- a/arch/arm/mach-mx3/clock-imx35.c +++ b/arch/arm/mach-mx3/clock-imx35.c @@ -21,8 +21,7 @@ #include #include #include - -#include +#include #include #include diff --git a/arch/arm/mach-mx5/clock-mx51.c b/arch/arm/mach-mx5/clock-mx51.c index 8ac36d8829276..5975edb47de82 100644 --- a/arch/arm/mach-mx5/clock-mx51.c +++ b/arch/arm/mach-mx5/clock-mx51.c @@ -14,8 +14,8 @@ #include #include #include +#include -#include #include #include diff --git a/arch/arm/mach-mxc91231/clock.c b/arch/arm/mach-mxc91231/clock.c index 5c85075d8a56b..9fab505f1eb1a 100644 --- a/arch/arm/mach-mxc91231/clock.c +++ b/arch/arm/mach-mxc91231/clock.c @@ -2,12 +2,12 @@ #include #include #include +#include #include #include #include -#include #include #include diff --git a/arch/arm/mach-nomadik/clock.c b/arch/arm/mach-nomadik/clock.c index 89f793adf7764..48a59f24e10c1 100644 --- a/arch/arm/mach-nomadik/clock.c +++ b/arch/arm/mach-nomadik/clock.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "clock.h" /* diff --git a/arch/arm/mach-nuc93x/clock.h b/arch/arm/mach-nuc93x/clock.h index 18e51be4816f7..4de1f1da9dc52 100644 --- a/arch/arm/mach-nuc93x/clock.h +++ b/arch/arm/mach-nuc93x/clock.h @@ -10,7 +10,7 @@ * the Free Software Foundation; either version 2 of the License. */ -#include +#include void nuc93x_clk_enable(struct clk *clk, int enable); void clks_register(struct clk_lookup *clks, size_t num); diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index b8c7fb9d79210..84ef70476b511 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -17,9 +17,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index ed8d330522f18..ebb888f59365c 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -26,10 +26,10 @@ #include #include #include +#include #include #include -#include #include "clock.h" #include "prm.h" diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c index 9d1975fa4d9f2..a4a3819c96cbf 100644 --- a/arch/arm/mach-pnx4008/clock.c +++ b/arch/arm/mach-pnx4008/clock.c @@ -21,8 +21,7 @@ #include #include #include - -#include +#include #include #include diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c index abba0089a2ae0..4e4a84be96bac 100644 --- a/arch/arm/mach-pxa/clock.c +++ b/arch/arm/mach-pxa/clock.c @@ -11,8 +11,8 @@ #include #include #include +#include -#include #include #include diff --git a/arch/arm/mach-pxa/clock.h b/arch/arm/mach-pxa/clock.h index d8488742b8075..12cc0e87e6c43 100644 --- a/arch/arm/mach-pxa/clock.h +++ b/arch/arm/mach-pxa/clock.h @@ -1,4 +1,4 @@ -#include +#include struct clkops { void (*enable)(struct clk *); diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 07c08151dfe64..3d915b1ccdb51 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -30,8 +30,8 @@ #include #include #include +#include -#include #include #include #include @@ -47,7 +47,6 @@ #include -#include #include #include #include diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 54b479c35ee01..f8f06e9fec35d 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -6,7 +6,7 @@ config ARCH_SH7367 bool "SH-Mobile G3 (SH7367)" select CPU_V6 select HAVE_CLK - select COMMON_CLKDEV + select CLKDEV_LOOKUP select SH_CLK_CPG select GENERIC_CLOCKEVENTS @@ -14,7 +14,7 @@ config ARCH_SH7377 bool "SH-Mobile G4 (SH7377)" select CPU_V7 select HAVE_CLK - select COMMON_CLKDEV + select CLKDEV_LOOKUP select SH_CLK_CPG select GENERIC_CLOCKEVENTS @@ -22,7 +22,7 @@ config ARCH_SH7372 bool "SH-Mobile AP4 (SH7372)" select CPU_V7 select HAVE_CLK - select COMMON_CLKDEV + select CLKDEV_LOOKUP select SH_CLK_CPG select GENERIC_CLOCKEVENTS diff --git a/arch/arm/mach-shmobile/clock-sh7367.c b/arch/arm/mach-shmobile/clock-sh7367.c index 9f78729098f27..6b186aefcbd63 100644 --- a/arch/arm/mach-shmobile/clock-sh7367.c +++ b/arch/arm/mach-shmobile/clock-sh7367.c @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include /* SH7367 registers */ #define RTFRQCR 0xe6150000 diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 8565aefa21fd3..445112adba460 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include /* SH7372 registers */ #define FRQCRA 0xe6150000 diff --git a/arch/arm/mach-shmobile/clock-sh7377.c b/arch/arm/mach-shmobile/clock-sh7377.c index f91395aeb9aba..95942466e63f2 100644 --- a/arch/arm/mach-shmobile/clock-sh7377.c +++ b/arch/arm/mach-shmobile/clock-sh7377.c @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include /* SH7377 registers */ #define RTFRQCR 0xe6150000 diff --git a/arch/arm/mach-tcc8k/clock.c b/arch/arm/mach-tcc8k/clock.c index ba32a15127ab7..3970a9cdce26e 100644 --- a/arch/arm/mach-tcc8k/clock.c +++ b/arch/arm/mach-tcc8k/clock.c @@ -12,8 +12,7 @@ #include #include #include - -#include +#include #include #include diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index ae19f95585be1..77948e0f49098 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "clock.h" #include "board.h" diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h index 94fd859770f1a..083a4cfc6cf0d 100644 --- a/arch/arm/mach-tegra/clock.h +++ b/arch/arm/mach-tegra/clock.h @@ -21,7 +21,7 @@ #define __MACH_TEGRA_CLOCK_H #include -#include +#include #define DIV_BUS (1 << 0) #define DIV_U71 (1 << 1) diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index ae3b308e22a4d..f0dae6d8ba520 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -24,8 +24,7 @@ #include #include #include - -#include +#include #include diff --git a/arch/arm/mach-u300/clock.c b/arch/arm/mach-u300/clock.c index 7458fc6df5c67..fabcc49abe80c 100644 --- a/arch/arm/mach-u300/clock.c +++ b/arch/arm/mach-u300/clock.c @@ -25,8 +25,8 @@ #include #include #include +#include -#include #include #include diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 1675047daf20f..531de5c636415 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c @@ -13,8 +13,7 @@ #include #include #include - -#include +#include #include #include diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index e38acb0f89c88..8c1ca1d63538f 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -31,8 +31,8 @@ #include #include #include +#include -#include #include #include #include @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c index c2e405a9e0256..26a02eb575716 100644 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -8,8 +8,8 @@ #include #include #include +#include -#include #include #include #include @@ -18,7 +18,6 @@ #include #include -#include #include #include diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 7eaa232180a5a..d374a78986e8b 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -11,15 +11,14 @@ #include #include #include +#include -#include #include #include #include #include #include -#include #include #include diff --git a/arch/arm/mach-w90x900/clock.h b/arch/arm/mach-w90x900/clock.h index c56ddab3d9128..b88a1b16b2e96 100644 --- a/arch/arm/mach-w90x900/clock.h +++ b/arch/arm/mach-w90x900/clock.h @@ -10,7 +10,7 @@ * the Free Software Foundation; either version 2 of the License. */ -#include +#include void nuc900_clk_enable(struct clk *clk, int enable); void nuc900_subclk_enable(struct clk *clk, int enable); diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 92c5bb7909f56..c9408434a855e 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -11,13 +11,13 @@ choice config ARCH_OMAP1 bool "TI OMAP1" - select COMMON_CLKDEV + select CLKDEV_LOOKUP help "Systems based on omap7xx, omap15xx or omap16xx" config ARCH_OMAP2PLUS bool "TI OMAP2/3/4" - select COMMON_CLKDEV + select CLKDEV_LOOKUP help "Systems based on OMAP2, OMAP3 or OMAP4" diff --git a/arch/arm/plat-omap/include/plat/clkdev_omap.h b/arch/arm/plat-omap/include/plat/clkdev_omap.h index bb937f3fabed3..4b2028ab4d2b5 100644 --- a/arch/arm/plat-omap/include/plat/clkdev_omap.h +++ b/arch/arm/plat-omap/include/plat/clkdev_omap.h @@ -8,7 +8,7 @@ #ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_PLAT_CLKDEV_OMAP_H #define __ARCH_ARM_PLAT_OMAP_INCLUDE_PLAT_CLKDEV_OMAP_H -#include +#include struct omap_clk { u16 cpu; diff --git a/arch/arm/plat-spear/include/plat/clock.h b/arch/arm/plat-spear/include/plat/clock.h index 298bafc0a52f7..2572260f990f1 100644 --- a/arch/arm/plat-spear/include/plat/clock.h +++ b/arch/arm/plat-spear/include/plat/clock.h @@ -15,7 +15,7 @@ #define __PLAT_CLOCK_H #include -#include +#include #include /* clk structure flags */ diff --git a/arch/arm/plat-stmp3xxx/clock.c b/arch/arm/plat-stmp3xxx/clock.c index e593a2a801c63..2e712e17ce725 100644 --- a/arch/arm/plat-stmp3xxx/clock.c +++ b/arch/arm/plat-stmp3xxx/clock.c @@ -25,9 +25,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 5c075f562ebae..cfc510608039b 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -1,7 +1,7 @@ config SUPERH def_bool y select EMBEDDED - select HAVE_CLK + select CLKDEV_LOOKUP select HAVE_IDE if HAS_IOPORT select HAVE_MEMBLOCK select HAVE_OPROFILE diff --git a/arch/sh/boards/mach-highlander/setup.c b/arch/sh/boards/mach-highlander/setup.c index a5ecfbacaf36b..87618c91d1781 100644 --- a/arch/sh/boards/mach-highlander/setup.c +++ b/arch/sh/boards/mach-highlander/setup.c @@ -24,10 +24,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include diff --git a/arch/sh/include/asm/clkdev.h b/arch/sh/include/asm/clkdev.h index 5645f358128b6..6ba91868201ce 100644 --- a/arch/sh/include/asm/clkdev.h +++ b/arch/sh/include/asm/clkdev.h @@ -1,9 +1,5 @@ /* - * arch/sh/include/asm/clkdev.h - * - * Cloned from arch/arm/include/asm/clkdev.h: - * - * Copyright (C) 2008 Russell King. + * Copyright (C) 2010 Paul Mundt * * 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 @@ -11,25 +7,25 @@ * * Helper for the clk API to assist looking up a struct clk. */ -#ifndef __ASM_CLKDEV_H -#define __ASM_CLKDEV_H -struct clk; +#ifndef __CLKDEV__H_ +#define __CLKDEV__H_ -struct clk_lookup { - struct list_head node; - const char *dev_id; - const char *con_id; - struct clk *clk; -}; +#include +#include +#include -struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id, - const char *dev_fmt, ...); +#include -void clkdev_add(struct clk_lookup *cl); -void clkdev_drop(struct clk_lookup *cl); +static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) +{ + if (!slab_is_available()) + return alloc_bootmem_low_pages(size); + else + return kzalloc(size, GFP_KERNEL); +} -void clkdev_add_table(struct clk_lookup *, size_t); -int clk_add_alias(const char *, const char *, char *, struct device *); +#define __clk_put(clk) +#define __clk_get(clk) ({ 1; }) -#endif +#endif /* __CLKDEV_H__ */ diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 8eed6a4854463..cf65221795238 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -11,7 +11,7 @@ endif CFLAGS_REMOVE_return_address.o = -pg -obj-y := clkdev.o debugtraps.o dma-nommu.o dumpstack.o \ +obj-y := debugtraps.o dma-nommu.o dumpstack.o \ idle.o io.o irq.o irq_$(BITS).o kdebugfs.o \ machvec.o nmi_debug.o process.o \ process_$(BITS).o ptrace.o ptrace_$(BITS).o \ diff --git a/arch/sh/kernel/clkdev.c b/arch/sh/kernel/clkdev.c deleted file mode 100644 index 1f800ef4a7356..0000000000000 --- a/arch/sh/kernel/clkdev.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * arch/sh/kernel/clkdev.c - * - * Cloned from arch/arm/common/clkdev.c: - * - * Copyright (C) 2008 Russell King. - * - * 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 - * published by the Free Software Foundation. - * - * Helper for the clk API to assist looking up a struct clk. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static LIST_HEAD(clocks); -static DEFINE_MUTEX(clocks_mutex); - -/* - * Find the correct struct clk for the device and connection ID. - * We do slightly fuzzy matching here: - * An entry with a NULL ID is assumed to be a wildcard. - * If an entry has a device ID, it must match - * If an entry has a connection ID, it must match - * Then we take the most specific entry - with the following - * order of precedence: dev+con > dev only > con only. - */ -static struct clk *clk_find(const char *dev_id, const char *con_id) -{ - struct clk_lookup *p; - struct clk *clk = NULL; - int match, best = 0; - - list_for_each_entry(p, &clocks, node) { - match = 0; - if (p->dev_id) { - if (!dev_id || strcmp(p->dev_id, dev_id)) - continue; - match += 2; - } - if (p->con_id) { - if (!con_id || strcmp(p->con_id, con_id)) - continue; - match += 1; - } - if (match == 0) - continue; - - if (match > best) { - clk = p->clk; - best = match; - } - } - return clk; -} - -struct clk *clk_get_sys(const char *dev_id, const char *con_id) -{ - struct clk *clk; - - mutex_lock(&clocks_mutex); - clk = clk_find(dev_id, con_id); - mutex_unlock(&clocks_mutex); - - return clk ? clk : ERR_PTR(-ENOENT); -} -EXPORT_SYMBOL(clk_get_sys); - -void clkdev_add(struct clk_lookup *cl) -{ - mutex_lock(&clocks_mutex); - list_add_tail(&cl->node, &clocks); - mutex_unlock(&clocks_mutex); -} -EXPORT_SYMBOL(clkdev_add); - -void __init clkdev_add_table(struct clk_lookup *cl, size_t num) -{ - mutex_lock(&clocks_mutex); - while (num--) { - list_add_tail(&cl->node, &clocks); - cl++; - } - mutex_unlock(&clocks_mutex); -} - -#define MAX_DEV_ID 20 -#define MAX_CON_ID 16 - -struct clk_lookup_alloc { - struct clk_lookup cl; - char dev_id[MAX_DEV_ID]; - char con_id[MAX_CON_ID]; -}; - -struct clk_lookup * __init_refok -clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) -{ - struct clk_lookup_alloc *cla; - - if (!slab_is_available()) - cla = alloc_bootmem_low_pages(sizeof(*cla)); - else - cla = kzalloc(sizeof(*cla), GFP_KERNEL); - - if (!cla) - return NULL; - - cla->cl.clk = clk; - if (con_id) { - strlcpy(cla->con_id, con_id, sizeof(cla->con_id)); - cla->cl.con_id = cla->con_id; - } - - if (dev_fmt) { - va_list ap; - - va_start(ap, dev_fmt); - vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); - cla->cl.dev_id = cla->dev_id; - va_end(ap); - } - - return &cla->cl; -} -EXPORT_SYMBOL(clkdev_alloc); - -int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, - struct device *dev) -{ - struct clk *r = clk_get(dev, id); - struct clk_lookup *l; - - if (IS_ERR(r)) - return PTR_ERR(r); - - l = clkdev_alloc(r, alias, alias_dev_name); - clk_put(r); - if (!l) - return -ENODEV; - clkdev_add(l); - return 0; -} -EXPORT_SYMBOL(clk_add_alias); - -/* - * clkdev_drop - remove a clock dynamically allocated - */ -void clkdev_drop(struct clk_lookup *cl) -{ - struct clk_lookup_alloc *cla = container_of(cl, struct clk_lookup_alloc, cl); - - mutex_lock(&clocks_mutex); - list_del(&cl->node); - mutex_unlock(&clocks_mutex); - kfree(cla); -} -EXPORT_SYMBOL(clkdev_drop); diff --git a/arch/sh/kernel/cpu/clock-cpg.c b/arch/sh/kernel/cpu/clock-cpg.c index e2f63d68da515..dd0e0f2113598 100644 --- a/arch/sh/kernel/cpu/clock-cpg.c +++ b/arch/sh/kernel/cpu/clock-cpg.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include static struct clk master_clk = { diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 50f887dda5655..4187cf4fe1858 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -48,20 +48,4 @@ int __init clk_init(void) return ret; } -/* - * Returns a clock. Note that we first try to use device id on the bus - * and clock name. If this fails, we try to use clock name only. - */ -struct clk *clk_get(struct device *dev, const char *con_id) -{ - const char *dev_id = dev ? dev_name(dev) : NULL; - - return clk_get_sys(dev_id, con_id); -} -EXPORT_SYMBOL_GPL(clk_get); - -void clk_put(struct clk *clk) -{ -} -EXPORT_SYMBOL_GPL(clk_put); diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c index 4eabc68cd7532..6c1492b8431a2 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c +++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c index 71291ae201b9f..93c646072c1b9 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include /* SH7343 registers */ diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7366.c b/arch/sh/kernel/cpu/sh4a/clock-sh7366.c index 7ce5bbcd4084d..049dc0628ccc1 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7366.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7366.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include /* SH7366 registers */ diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c index 2030f3d9fac7e..9d23a36f0647b 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c index d3938f0d37029..55493cd5bd8f3 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c index 2d9700c6b53a0..527936bb3ce0f 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c index ce39a2ae8c6cd..e073e3eb4c3de 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7757.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7757.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7763.c b/arch/sh/kernel/cpu/sh4a/clock-sh7763.c index 1f1df48008cdf..599630fc4d3bd 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7763.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7763.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7780.c b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c index 62d7063500600..8894926479a61 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c index c3e458aaa2b7e..2d960247f3ebf 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c index 597c9fbe49c6d..42e403be9076d 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c index 4f70df6b6169c..1afdb93b8ccb2 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/Kconfig b/drivers/Kconfig index a2b902f4d4370..3d93b3a3d630c 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -111,4 +111,6 @@ source "drivers/xen/Kconfig" source "drivers/staging/Kconfig" source "drivers/platform/Kconfig" + +source "drivers/clk/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 14cf9077bb2bc..4af7d5b124ce2 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -114,3 +114,5 @@ obj-$(CONFIG_VLYNQ) += vlynq/ obj-$(CONFIG_STAGING) += staging/ obj-y += platform/ obj-y += ieee802154/ +#common clk code +obj-y += clk/ diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig new file mode 100644 index 0000000000000..4168c8896e16b --- /dev/null +++ b/drivers/clk/Kconfig @@ -0,0 +1,4 @@ + +config CLKDEV_LOOKUP + bool + select HAVE_CLK diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile new file mode 100644 index 0000000000000..07613fa172c99 --- /dev/null +++ b/drivers/clk/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o diff --git a/arch/arm/common/clkdev.c b/drivers/clk/clkdev.c similarity index 93% rename from arch/arm/common/clkdev.c rename to drivers/clk/clkdev.c index e2b2bb66e0949..0fc0a79852de0 100644 --- a/arch/arm/common/clkdev.c +++ b/drivers/clk/clkdev.c @@ -1,5 +1,5 @@ /* - * arch/arm/common/clkdev.c + * drivers/clk/clkdev.c * * Copyright (C) 2008 Russell King. * @@ -18,10 +18,7 @@ #include #include #include -#include - -#include -#include +#include static LIST_HEAD(clocks); static DEFINE_MUTEX(clocks_mutex); @@ -120,12 +117,12 @@ struct clk_lookup_alloc { char con_id[MAX_CON_ID]; }; -struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id, - const char *dev_fmt, ...) +struct clk_lookup * __init_refok +clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) { struct clk_lookup_alloc *cla; - cla = kzalloc(sizeof(*cla), GFP_KERNEL); + cla = __clkdev_alloc(sizeof(*cla)); if (!cla) return NULL; diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h new file mode 100644 index 0000000000000..457bcb0a310a4 --- /dev/null +++ b/include/linux/clkdev.h @@ -0,0 +1,36 @@ +/* + * include/linux/clkdev.h + * + * Copyright (C) 2008 Russell King. + * + * 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 + * published by the Free Software Foundation. + * + * Helper for the clk API to assist looking up a struct clk. + */ +#ifndef __CLKDEV_H +#define __CLKDEV_H + +#include + +struct clk; +struct device; + +struct clk_lookup { + struct list_head node; + const char *dev_id; + const char *con_id; + struct clk *clk; +}; + +struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id, + const char *dev_fmt, ...); + +void clkdev_add(struct clk_lookup *cl); +void clkdev_drop(struct clk_lookup *cl); + +void clkdev_add_table(struct clk_lookup *, size_t); +int clk_add_alias(const char *, const char *, char *, struct device *); + +#endif From 283a1b92e25fe3a62c766a042f96dad2eefa7d17 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 8 Nov 2010 10:11:19 +0000 Subject: [PATCH 04/52] ARM: always build swp_emulate as ARMv7 swp_emulate is only used on ARMv7+, and includes ARMv7+ assembly instructions. Allow the assembler to accept ARMv7 instructions, but leave the compiler's code generation options alone. Signed-off-by: Russell King --- arch/arm/kernel/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 119a6bb59bde2..4036a59264651 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_ARM_UNWIND) += unwind.o obj-$(CONFIG_HAVE_TCM) += tcm.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_SWP_EMULATE) += swp_emulate.o +CFLAGS_swp_emulate.o := -Wa,-march=armv7-a obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o From 65500fa94aaeb3475e39c0c5180f188014164ca4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 4 Nov 2010 13:06:59 +0100 Subject: [PATCH 05/52] ARM: 6467/1: amba: optional PrimeCell core voltage switch On some contemporary sub-micron SoCs, peripherals on the chip have power domain switches, i.e. the voltage to the core may be turned off to conserve power. In the Ux500 we have this for out PrimeCell derivates. This patch makes it possible to specify an (optional) regulator to handle the voltage domain switch on AMBA PrimeCells, modeled very similar to how block clocks are handled. Additional amba_vcore_[enable|disable] calls are supplied to make it possible introduce optional powering off of the core voltage. Using this will require code to spool/unspool any core HW state. Cc: Rabin Vincent Cc: Bengt Jonsson Cc: Jonas Aaberg Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/amba/bus.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/amba/bus.h | 8 ++++++++ 2 files changed, 47 insertions(+) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 2737b97522052..e7df019d29d44 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -147,6 +147,39 @@ static void amba_put_disable_pclk(struct amba_device *pcdev) clk_put(pclk); } +static int amba_get_enable_vcore(struct amba_device *pcdev) +{ + struct regulator *vcore = regulator_get(&pcdev->dev, "vcore"); + int ret; + + pcdev->vcore = vcore; + + if (IS_ERR(vcore)) { + /* It is OK not to supply a vcore regulator */ + if (PTR_ERR(vcore) == -ENODEV) + return 0; + return PTR_ERR(vcore); + } + + ret = regulator_enable(vcore); + if (ret) { + regulator_put(vcore); + pcdev->vcore = ERR_PTR(-ENODEV); + } + + return ret; +} + +static void amba_put_disable_vcore(struct amba_device *pcdev) +{ + struct regulator *vcore = pcdev->vcore; + + if (!IS_ERR(vcore)) { + regulator_disable(vcore); + regulator_put(vcore); + } +} + /* * These are the device model conversion veneers; they convert the * device model structures to our more specific structures. @@ -159,6 +192,10 @@ static int amba_probe(struct device *dev) int ret; do { + ret = amba_get_enable_vcore(pcdev); + if (ret) + break; + ret = amba_get_enable_pclk(pcdev); if (ret) break; @@ -168,6 +205,7 @@ static int amba_probe(struct device *dev) break; amba_put_disable_pclk(pcdev); + amba_put_disable_vcore(pcdev); } while (0); return ret; @@ -180,6 +218,7 @@ static int amba_remove(struct device *dev) int ret = drv->remove(pcdev); amba_put_disable_pclk(pcdev); + amba_put_disable_vcore(pcdev); return ret; } diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h index c6454cca04478..9e7f259346e1e 100644 --- a/include/linux/amba/bus.h +++ b/include/linux/amba/bus.h @@ -18,6 +18,7 @@ #include #include #include +#include #define AMBA_NR_IRQS 2 #define AMBA_CID 0xb105f00d @@ -28,6 +29,7 @@ struct amba_device { struct device dev; struct resource res; struct clk *pclk; + struct regulator *vcore; u64 dma_mask; unsigned int periphid; unsigned int irq[AMBA_NR_IRQS]; @@ -71,6 +73,12 @@ void amba_release_regions(struct amba_device *); #define amba_pclk_disable(d) \ do { if (!IS_ERR((d)->pclk)) clk_disable((d)->pclk); } while (0) +#define amba_vcore_enable(d) \ + (IS_ERR((d)->vcore) ? 0 : regulator_enable((d)->vcore)) + +#define amba_vcore_disable(d) \ + do { if (!IS_ERR((d)->vcore)) regulator_disable((d)->vcore); } while (0) + /* Some drivers don't use the struct amba_device */ #define AMBA_CONFIG_BITS(a) (((a) >> 24) & 0xff) #define AMBA_REV_BITS(a) (((a) >> 20) & 0x0f) From d92e04713c6323e09a0d0fdfa0d7cbcedb175e49 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 09:36:18 +0000 Subject: [PATCH 06/52] ARM: remove obsolete smp_cross_call_done() smp_cross_call_done() was removed long ago (see 78d236c - remove useless smp_cross_call_done()). Remove those which have been subsequently merged. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/mach-tegra/include/mach/smp.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/arm/mach-tegra/include/mach/smp.h b/arch/arm/mach-tegra/include/mach/smp.h index e4a34a35a5446..d3cd265cb058c 100644 --- a/arch/arm/mach-tegra/include/mach/smp.h +++ b/arch/arm/mach-tegra/include/mach/smp.h @@ -12,11 +12,4 @@ static inline void smp_cross_call(const struct cpumask *mask) gic_raise_softirq(mask, 1); } -/* - * Do nothing on MPcore. - */ -static inline void smp_cross_call_done(cpumask_t callmap) -{ -} - #endif From ad3b6993b9c5482e8a2ec5aed181538c921fdcbd Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 09:42:08 +0000 Subject: [PATCH 07/52] ARM: SMP: pass an ipi number to smp_cross_call() This allows us to use smp_cross_call() to trigger a number of different software generated interrupts, rather than combining them all on one SGI. Recover the SGI number via do_IPI. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/smp.h | 4 ++-- arch/arm/kernel/entry-armv.S | 2 +- arch/arm/kernel/smp.c | 10 ++-------- arch/arm/mach-msm/include/mach/smp.h | 4 ++-- arch/arm/mach-omap2/omap-smp.c | 2 +- arch/arm/mach-realview/include/mach/smp.h | 4 ++-- arch/arm/mach-realview/platsmp.c | 2 +- arch/arm/mach-s5pv310/include/mach/smp.h | 4 ++-- arch/arm/mach-s5pv310/platsmp.c | 2 +- arch/arm/mach-tegra/include/mach/smp.h | 4 ++-- arch/arm/mach-ux500/include/mach/smp.h | 4 ++-- arch/arm/mach-ux500/platsmp.c | 2 +- arch/arm/mach-vexpress/include/mach/smp.h | 4 ++-- arch/arm/mach-vexpress/platsmp.c | 2 +- arch/arm/plat-omap/include/plat/smp.h | 4 ++-- 15 files changed, 24 insertions(+), 30 deletions(-) diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index 3d05190797cbf..da7e7ca53cc1d 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -38,7 +38,7 @@ extern void show_ipi_list(struct seq_file *p); /* * Called from assembly code, this handles an IPI. */ -asmlinkage void do_IPI(struct pt_regs *regs); +asmlinkage void do_IPI(int ipinr, struct pt_regs *regs); /* * Setup the set of possible CPUs (via set_cpu_possible) @@ -53,7 +53,7 @@ extern void smp_store_cpu_info(unsigned int cpuid); /* * Raise an IPI cross call on CPUs in callmap. */ -extern void smp_cross_call(const struct cpumask *mask); +extern void smp_cross_call(const struct cpumask *mask, int ipi); /* * Boot a secondary CPU, and assign it the specified idle task. diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index c09e3573c5deb..955cf5f539ed9 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -48,7 +48,7 @@ */ ALT_SMP(test_for_ipi r0, r6, r5, lr) ALT_UP_B(9997f) - movne r0, sp + movne r1, sp adrne lr, BSYM(1b) bne do_IPI diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 8c1959590252e..7a236db03fb55 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -404,7 +404,7 @@ static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg) /* * Call the platform specific cross-CPU call function. */ - smp_cross_call(mask); + smp_cross_call(mask, 1); local_irq_restore(flags); } @@ -537,14 +537,8 @@ static void ipi_cpu_stop(unsigned int cpu) /* * Main handler for inter-processor interrupts - * - * For ARM, the ipimask now only identifies a single - * category of IPI (Bit 1 IPIs have been replaced by a - * different mechanism): - * - * Bit 0 - Inter-processor function call */ -asmlinkage void __exception do_IPI(struct pt_regs *regs) +asmlinkage void __exception do_IPI(int ipinr, struct pt_regs *regs) { unsigned int cpu = smp_processor_id(); struct ipi_data *ipi = &per_cpu(ipi_data, cpu); diff --git a/arch/arm/mach-msm/include/mach/smp.h b/arch/arm/mach-msm/include/mach/smp.h index 3ff7bf5e679ec..a95f7b9efe31b 100644 --- a/arch/arm/mach-msm/include/mach/smp.h +++ b/arch/arm/mach-msm/include/mach/smp.h @@ -31,9 +31,9 @@ #include -static inline void smp_cross_call(const struct cpumask *mask) +static inline void smp_cross_call(const struct cpumask *mask, int ipi) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 9e9f70e18e3c9..56a8bce247c89 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -76,7 +76,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) omap_modify_auxcoreboot0(0x200, 0xfffffdff); flush_cache_all(); smp_wmb(); - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); /* * Now the secondary core is starting up let it run its diff --git a/arch/arm/mach-realview/include/mach/smp.h b/arch/arm/mach-realview/include/mach/smp.h index d3cd265cb058c..d1aa70415a4e1 100644 --- a/arch/arm/mach-realview/include/mach/smp.h +++ b/arch/arm/mach-realview/include/mach/smp.h @@ -7,9 +7,9 @@ /* * We use IRQ1 as the IPI */ -static inline void smp_cross_call(const struct cpumask *mask) +static inline void smp_cross_call(const struct cpumask *mask, int ipi) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 009265818d557..af3d9093390b6 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -116,7 +116,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * Use smp_cross_call() for this, since there's little * point duplicating the code here */ - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { diff --git a/arch/arm/mach-s5pv310/include/mach/smp.h b/arch/arm/mach-s5pv310/include/mach/smp.h index b7ec252384f47..2897747bcb07b 100644 --- a/arch/arm/mach-s5pv310/include/mach/smp.h +++ b/arch/arm/mach-s5pv310/include/mach/smp.h @@ -14,9 +14,9 @@ extern void __iomem *gic_cpu_base_addr; /* * We use IRQ1 as the IPI */ -static inline void smp_cross_call(const struct cpumask *mask) +static inline void smp_cross_call(const struct cpumask *mask, int ipi) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c index d357c198edee3..d474426f37b75 100644 --- a/arch/arm/mach-s5pv310/platsmp.c +++ b/arch/arm/mach-s5pv310/platsmp.c @@ -97,7 +97,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * the boot monitor to read the system wide flags register, * and branch to the address found there. */ - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { diff --git a/arch/arm/mach-tegra/include/mach/smp.h b/arch/arm/mach-tegra/include/mach/smp.h index d3cd265cb058c..d1aa70415a4e1 100644 --- a/arch/arm/mach-tegra/include/mach/smp.h +++ b/arch/arm/mach-tegra/include/mach/smp.h @@ -7,9 +7,9 @@ /* * We use IRQ1 as the IPI */ -static inline void smp_cross_call(const struct cpumask *mask) +static inline void smp_cross_call(const struct cpumask *mask, int ipi) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-ux500/include/mach/smp.h b/arch/arm/mach-ux500/include/mach/smp.h index 197e8417375e1..bd57c50a5b860 100644 --- a/arch/arm/mach-ux500/include/mach/smp.h +++ b/arch/arm/mach-ux500/include/mach/smp.h @@ -18,8 +18,8 @@ extern void u8500_secondary_startup(void); /* * We use IRQ1 as the IPI */ -static inline void smp_cross_call(const struct cpumask *mask) +static inline void smp_cross_call(const struct cpumask *mask, int ipi) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 9e4c678de7859..b8987bd212497 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -78,7 +78,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1); - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { diff --git a/arch/arm/mach-vexpress/include/mach/smp.h b/arch/arm/mach-vexpress/include/mach/smp.h index 5a6da4fd247e8..721be0f0311da 100644 --- a/arch/arm/mach-vexpress/include/mach/smp.h +++ b/arch/arm/mach-vexpress/include/mach/smp.h @@ -7,8 +7,8 @@ /* * We use IRQ1 as the IPI */ -static inline void smp_cross_call(const struct cpumask *mask) +static inline void smp_cross_call(const struct cpumask *mask, int ipi) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index 670970699ba93..276f916014c1c 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -92,7 +92,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * the boot monitor to read the system wide flags register, * and branch to the address found there. */ - smp_cross_call(cpumask_of(cpu)); + smp_cross_call(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { diff --git a/arch/arm/plat-omap/include/plat/smp.h b/arch/arm/plat-omap/include/plat/smp.h index ecd6a488c497c..e5541e5388be6 100644 --- a/arch/arm/plat-omap/include/plat/smp.h +++ b/arch/arm/plat-omap/include/plat/smp.h @@ -29,9 +29,9 @@ extern u32 omap_read_auxcoreboot0(void); /* * We use Soft IRQ1 as the IPI */ -static inline void smp_cross_call(const struct cpumask *mask) +static inline void smp_cross_call(const struct cpumask *mask, int ipi) { - gic_raise_softirq(mask, 1); + gic_raise_softirq(mask, ipi); } #endif From 24480d980e9063b3ebd0dfdf2f396c305956c356 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 09:54:18 +0000 Subject: [PATCH 08/52] ARM: SMP: avoid using bitmasks and locks for IPIs, use hardware instead Avoid using bitmasks and locks in the percpu area for IPIs, and instead use individual software generated interrupts to identify the reason for the IPI. This avoids the problems of having spinlocks in the percpu area. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 87 +++++++++++++------------------------------ 1 file changed, 26 insertions(+), 61 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 7a236db03fb55..78d55c681a4fe 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -48,20 +48,15 @@ struct secondary_data secondary_data; /* * structures for inter-processor calls - * - A collection of single bit ipi messages. */ struct ipi_data { - spinlock_t lock; unsigned long ipi_count; - unsigned long bits; }; -static DEFINE_PER_CPU(struct ipi_data, ipi_data) = { - .lock = SPIN_LOCK_UNLOCKED, -}; +static DEFINE_PER_CPU(struct ipi_data, ipi_data); enum ipi_msg_type { - IPI_TIMER, + IPI_TIMER = 2, IPI_RESCHEDULE, IPI_CALL_FUNC, IPI_CALL_FUNC_SINGLE, @@ -389,22 +384,13 @@ void __init smp_prepare_boot_cpu(void) static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg) { unsigned long flags; - unsigned int cpu; local_irq_save(flags); - for_each_cpu(cpu, mask) { - struct ipi_data *ipi = &per_cpu(ipi_data, cpu); - - spin_lock(&ipi->lock); - ipi->bits |= 1 << msg; - spin_unlock(&ipi->lock); - } - /* * Call the platform specific cross-CPU call function. */ - smp_cross_call(mask, 1); + smp_cross_call(mask, msg); local_irq_restore(flags); } @@ -546,56 +532,35 @@ asmlinkage void __exception do_IPI(int ipinr, struct pt_regs *regs) ipi->ipi_count++; - for (;;) { - unsigned long msgs; - - spin_lock(&ipi->lock); - msgs = ipi->bits; - ipi->bits = 0; - spin_unlock(&ipi->lock); - - if (!msgs) - break; - - do { - unsigned nextmsg; - - nextmsg = msgs & -msgs; - msgs &= ~nextmsg; - nextmsg = ffz(~nextmsg); - - switch (nextmsg) { - case IPI_TIMER: - ipi_timer(); - break; + switch (ipinr) { + case IPI_TIMER: + ipi_timer(); + break; - case IPI_RESCHEDULE: - /* - * nothing more to do - eveything is - * done on the interrupt return path - */ - break; + case IPI_RESCHEDULE: + /* + * nothing more to do - eveything is + * done on the interrupt return path + */ + break; - case IPI_CALL_FUNC: - generic_smp_call_function_interrupt(); - break; + case IPI_CALL_FUNC: + generic_smp_call_function_interrupt(); + break; - case IPI_CALL_FUNC_SINGLE: - generic_smp_call_function_single_interrupt(); - break; + case IPI_CALL_FUNC_SINGLE: + generic_smp_call_function_single_interrupt(); + break; - case IPI_CPU_STOP: - ipi_cpu_stop(cpu); - break; + case IPI_CPU_STOP: + ipi_cpu_stop(cpu); + break; - default: - printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", - cpu, nextmsg); - break; - } - } while (msgs); + default: + printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", + cpu, ipinr); + break; } - set_irq_regs(old_regs); } From 0df7095205cbf6ea1cdfe6254e0d6a3b823caa3b Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 2 Dec 2010 19:16:56 +0000 Subject: [PATCH 09/52] ARM: SMP: remove IRQ-disabling for smp_cross_call() As we've now removed the spinlock and bitmask, we have nothing left which requires interrupts to be disabled when sending an IPI. All current IPI-sending implementations use the GIC, which also does not require interrupts disabled when calling gic_raise_softirq(). Remove the now unnecessary IRQ disable. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 78d55c681a4fe..4878e51561f94 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -383,16 +383,10 @@ void __init smp_prepare_boot_cpu(void) static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg) { - unsigned long flags; - - local_irq_save(flags); - /* * Call the platform specific cross-CPU call function. */ smp_cross_call(mask, msg); - - local_irq_restore(flags); } void arch_send_call_function_ipi_mask(const struct cpumask *mask) From 0b05da7200dd56a5364c4d9cf5441715c1d706ed Mon Sep 17 00:00:00 2001 From: Hans Ulli Kroll Date: Thu, 2 Dec 2010 12:32:15 +0100 Subject: [PATCH 10/52] ARM: 6520/1: Kconfig: add new symbol MIGHT_HAVE_PCI Today more boards with arm cpu have selectable pci bus. This patch makes this more scalable and remove line continuations in Kconfig Acked-by: Arnd Bergmann Signed-off-by: Hans Ulli Kroll Signed-off-by: Russell King --- arch/arm/Kconfig | 7 ++++++- arch/arm/mach-cns3xxx/Kconfig | 1 + arch/arm/mach-integrator/Kconfig | 1 + arch/arm/mach-ks8695/Kconfig | 1 + arch/arm/mach-pxa/Kconfig | 1 + arch/arm/mach-versatile/Kconfig | 1 + 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 0e51342b3c024..7e94f8609c879 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -34,6 +34,9 @@ config ARM config HAVE_PWM bool +config MIGHT_HAVE_PCI + bool + config SYS_SUPPORTS_APM_EMULATION bool @@ -298,6 +301,7 @@ config ARCH_CNS3XXX select CPU_V6 select GENERIC_CLOCKEVENTS select ARM_GIC + select MIGHT_HAVE_PCI select PCI_DOMAINS if PCI help Support for Cavium Networks CNS3XXX platform. @@ -433,6 +437,7 @@ config ARCH_IXP4XX select CPU_XSCALE select GENERIC_GPIO select GENERIC_CLOCKEVENTS + select MIGHT_HAVE_PCI select DMABOUNCE if PCI help Support for Intel's IXP4XX (XScale) family of processors. @@ -1164,7 +1169,7 @@ config ISA_DMA_API bool config PCI - bool "PCI support" if ARCH_INTEGRATOR_AP || ARCH_VERSATILE_PB || ARCH_IXP4XX || ARCH_KS8695 || MACH_ARMCORE || ARCH_CNS3XXX + bool "PCI support" if MIGHT_HAVE_PCI help Find out whether you have a PCI motherboard. PCI is the name of a bus system, i.e. the way the CPU talks to the other stuff inside diff --git a/arch/arm/mach-cns3xxx/Kconfig b/arch/arm/mach-cns3xxx/Kconfig index 9ebfcc46feb1a..29b13f249aa9b 100644 --- a/arch/arm/mach-cns3xxx/Kconfig +++ b/arch/arm/mach-cns3xxx/Kconfig @@ -3,6 +3,7 @@ menu "CNS3XXX platform type" config MACH_CNS3420VB bool "Support for CNS3420 Validation Board" + select MIGHT_HAVE_PCI help Include support for the Cavium Networks CNS3420 MPCore Platform Baseboard. diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index 27db275b367cf..769b0f10c8349 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -4,6 +4,7 @@ menu "Integrator Options" config ARCH_INTEGRATOR_AP bool "Support Integrator/AP and Integrator/PP2 platforms" + select MIGHT_HAVE_PCI help Include support for the ARM(R) Integrator/AP and Integrator/PP2 platforms. diff --git a/arch/arm/mach-ks8695/Kconfig b/arch/arm/mach-ks8695/Kconfig index fe0c82e30b2db..f5c39a8c2b00f 100644 --- a/arch/arm/mach-ks8695/Kconfig +++ b/arch/arm/mach-ks8695/Kconfig @@ -4,6 +4,7 @@ menu "Kendin/Micrel KS8695 Implementations" config MACH_KS8695 bool "KS8695 development board" + select MIGHT_HAVE_PCI help Say 'Y' here if you want your kernel to run on the original Kendin-Micrel KS8695 development board. diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index dd235ecc9d6c5..716a2e159c2c3 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -94,6 +94,7 @@ config MACH_ARMCORE select PXA27x select IWMMXT select PXA25x + select MIGHT_HAVE_PCI config MACH_EM_X270 bool "CompuLab EM-x270 platform" diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig index c781f30c8368a..3f7b5e9d83c51 100644 --- a/arch/arm/mach-versatile/Kconfig +++ b/arch/arm/mach-versatile/Kconfig @@ -4,6 +4,7 @@ menu "Versatile platform type" config ARCH_VERSATILE_PB bool "Support Versatile/PB platform" select CPU_ARM926T + select MIGHT_HAVE_PCI default y help Include support for the ARM(R) Versatile/PB platform. From daf8741675562197d4fb4c4e9d773f53494203a5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 4 Dec 2010 17:08:32 +0000 Subject: [PATCH 11/52] ARM: implement support for read-mostly sections As our SMP implementation uses MESI protocols. Grouping together data which is mostly only read together means that we avoid unnecessary cache line bouncing when this code shares a cache line with other data. In other words, cache lines associated with read-mostly data are expected to spend most of their time in shared state. Signed-off-by: Russell King --- arch/arm/include/asm/cache.h | 2 ++ arch/arm/kernel/vmlinux.lds.S | 1 + 2 files changed, 3 insertions(+) diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h index 9d6122096fbec..75fe66bc02b42 100644 --- a/arch/arm/include/asm/cache.h +++ b/arch/arm/include/asm/cache.h @@ -23,4 +23,6 @@ #define ARCH_SLAB_MINALIGN 8 #endif +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) + #endif diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index cead8893b46bc..1581f6d18ccad 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -167,6 +167,7 @@ SECTIONS NOSAVE_DATA CACHELINE_ALIGNED_DATA(32) + READ_MOSTLY_DATA(32) /* * The exception fixup table (might need resorting at runtime) From 0385ebc0c9b16fc2d8262c082843165313f7b1e4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 4 Dec 2010 17:45:55 +0000 Subject: [PATCH 12/52] ARM: move high-usage mostly read variables in setup.c to __read_mostly Signed-off-by: Russell King --- arch/arm/kernel/setup.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 336f14e0e5c21..8075e592f902f 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -75,9 +75,9 @@ extern void reboot_setup(char *str); unsigned int processor_id; EXPORT_SYMBOL(processor_id); -unsigned int __machine_arch_type; +unsigned int __machine_arch_type __read_mostly; EXPORT_SYMBOL(__machine_arch_type); -unsigned int cacheid; +unsigned int cacheid __read_mostly; EXPORT_SYMBOL(cacheid); unsigned int __atags_pointer __initdata; @@ -91,24 +91,24 @@ EXPORT_SYMBOL(system_serial_low); unsigned int system_serial_high; EXPORT_SYMBOL(system_serial_high); -unsigned int elf_hwcap; +unsigned int elf_hwcap __read_mostly; EXPORT_SYMBOL(elf_hwcap); #ifdef MULTI_CPU -struct processor processor; +struct processor processor __read_mostly; #endif #ifdef MULTI_TLB -struct cpu_tlb_fns cpu_tlb; +struct cpu_tlb_fns cpu_tlb __read_mostly; #endif #ifdef MULTI_USER -struct cpu_user_fns cpu_user; +struct cpu_user_fns cpu_user __read_mostly; #endif #ifdef MULTI_CACHE -struct cpu_cache_fns cpu_cache; +struct cpu_cache_fns cpu_cache __read_mostly; #endif #ifdef CONFIG_OUTER_CACHE -struct outer_cache_fns outer_cache; +struct outer_cache_fns outer_cache __read_mostly; EXPORT_SYMBOL(outer_cache); #endif From 4a50bfe365a977f634311504484342fbfffe855c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 5 Dec 2010 23:06:22 +0000 Subject: [PATCH 13/52] ARM: Ensure experimental options are so marked It is kernel-wide policy that options depending on EXPERIMENTAL should also have '(EXPERIMENTAL)' in their option text, and options with '(EXPERIMENTAL)' depend on EXPERIMENTAL. Ensure that all ARM options comply with this. Signed-off-by: Russell King --- arch/arm/Kconfig | 7 ++++--- arch/arm/Kconfig.debug | 2 +- arch/arm/mach-s3c2412/Kconfig | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7e94f8609c879..fd0e21be5e440 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1315,7 +1315,7 @@ config HZ default 100 config THUMB2_KERNEL - bool "Compile the kernel in Thumb-2 mode" + bool "Compile the kernel in Thumb-2 mode (EXPERIMENTAL)" depends on CPU_V7 && EXPERIMENTAL select AEABI select ARM_ASM_UNIFIED @@ -1529,6 +1529,7 @@ config SECCOMP config CC_STACKPROTECTOR bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" + depends on EXPERIMENTAL help This option turns on the -fstack-protector GCC feature. This feature puts, at the beginning of functions, a canary value on @@ -1712,7 +1713,7 @@ config CPU_FREQ_S3C Internal configuration node for common cpufreq on Samsung SoC config CPU_FREQ_S3C24XX - bool "CPUfreq driver for Samsung S3C24XX series CPUs" + bool "CPUfreq driver for Samsung S3C24XX series CPUs (EXPERIMENTAL)" depends on ARCH_S3C2410 && CPU_FREQ && EXPERIMENTAL select CPU_FREQ_S3C help @@ -1724,7 +1725,7 @@ config CPU_FREQ_S3C24XX If in doubt, say N. config CPU_FREQ_S3C24XX_PLL - bool "Support CPUfreq changing of PLL frequency" + bool "Support CPUfreq changing of PLL frequency (EXPERIMENTAL)" depends on CPU_FREQ_S3C24XX && EXPERIMENTAL help Compile in support for changing the PLL frequency from the diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 2fd0b99afc4bc..a5775a56f0b2b 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -31,7 +31,7 @@ config FRAME_POINTER reported is severely limited. config ARM_UNWIND - bool "Enable stack unwinding support" + bool "Enable stack unwinding support (EXPERIMENTAL)" depends on AEABI && EXPERIMENTAL default y help diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig index cef6a65637bd9..e824a85c89a83 100644 --- a/arch/arm/mach-s3c2412/Kconfig +++ b/arch/arm/mach-s3c2412/Kconfig @@ -52,7 +52,7 @@ config MACH_JIVE Say Y here if you are using the Logitech Jive. config MACH_JIVE_SHOW_BOOTLOADER - bool "Allow access to bootloader partitions in MTD" + bool "Allow access to bootloader partitions in MTD (EXPERIMENTAL)" depends on MACH_JIVE && EXPERIMENTAL config MACH_SMDK2413 From e3fbb087650df130788d8e3ac29875ee56819249 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Dec 2010 14:47:19 +0000 Subject: [PATCH 14/52] ARM: SMP: remove send_ipi_message() send_ipi_message() does nothing except call smp_cross_call(). As this is a static function, nothing external to this file calls it, so we can easily clean up this now unnecessary indirection. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 4878e51561f94..3772cfc6953a0 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -381,22 +381,14 @@ void __init smp_prepare_boot_cpu(void) per_cpu(cpu_data, cpu).idle = current; } -static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg) -{ - /* - * Call the platform specific cross-CPU call function. - */ - smp_cross_call(mask, msg); -} - void arch_send_call_function_ipi_mask(const struct cpumask *mask) { - send_ipi_message(mask, IPI_CALL_FUNC); + smp_cross_call(mask, IPI_CALL_FUNC); } void arch_send_call_function_single_ipi(int cpu) { - send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); + smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); } void show_ipi_list(struct seq_file *p) @@ -454,7 +446,7 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST static void smp_timer_broadcast(const struct cpumask *mask) { - send_ipi_message(mask, IPI_TIMER); + smp_cross_call(mask, IPI_TIMER); } #else #define smp_timer_broadcast NULL @@ -560,7 +552,7 @@ asmlinkage void __exception do_IPI(int ipinr, struct pt_regs *regs) void smp_send_reschedule(int cpu) { - send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); + smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); } void smp_send_stop(void) @@ -568,7 +560,7 @@ void smp_send_stop(void) cpumask_t mask = cpu_online_map; cpu_clear(smp_processor_id(), mask); if (!cpus_empty(mask)) - send_ipi_message(&mask, IPI_CPU_STOP); + smp_cross_call(&mask, IPI_CPU_STOP); } /* From ec405ea9fe5fdeb40824edba7082803b3e98f176 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 13:38:06 +0000 Subject: [PATCH 15/52] ARM: include local timer irq stats only when local timers configured Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/hardirq.h | 2 ++ arch/arm/kernel/irq.c | 2 ++ arch/arm/kernel/smp.c | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index 6d7485aff9558..522fb23241acc 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -7,7 +7,9 @@ typedef struct { unsigned int __softirq_pending; +#ifdef CONFIG_LOCAL_TIMERS unsigned int local_timer_irqs; +#endif } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 36ad3be4692a2..ea29721ba3483 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -93,6 +93,8 @@ int show_interrupts(struct seq_file *p, void *v) #endif #ifdef CONFIG_SMP show_ipi_list(p); +#endif +#ifdef CONFIG_LOCAL_TIMERS show_local_irqs(p); #endif seq_printf(p, "Err: %10lu\n", irq_err_count); diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 3772cfc6953a0..36d4b9140dcf1 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -403,18 +403,6 @@ void show_ipi_list(struct seq_file *p) seq_putc(p, '\n'); } -void show_local_irqs(struct seq_file *p) -{ - unsigned int cpu; - - seq_printf(p, "LOC: "); - - for_each_present_cpu(cpu) - seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); - - seq_putc(p, '\n'); -} - /* * Timer (local or broadcast) support */ @@ -441,6 +429,18 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) set_irq_regs(old_regs); } + +void show_local_irqs(struct seq_file *p) +{ + unsigned int cpu; + + seq_printf(p, "LOC: "); + + for_each_present_cpu(cpu) + seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); + + seq_putc(p, '\n'); +} #endif #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST From 46c48f222f568decb881a552caa1c8f9c96c521e Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 14:15:03 +0000 Subject: [PATCH 16/52] ARM: SMP: provide accessors for irq_stat data Provide __inc_irq_stat() and __get_irq_stat() to increment and read the irq stat counters. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/hardirq.h | 3 +++ arch/arm/kernel/smp.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index 522fb23241acc..923eaa1ba83b7 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -14,6 +14,9 @@ typedef struct { #include /* Standard mappings for irq_cpustat_t above */ +#define __inc_irq_stat(cpu, member) __IRQ_STAT(cpu, member)++ +#define __get_irq_stat(cpu, member) __IRQ_STAT(cpu, member) + #if NR_IRQS > 512 #define HARDIRQ_BITS 10 #elif NR_IRQS > 256 diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 36d4b9140dcf1..24131264ec2c6 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -423,7 +423,7 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) int cpu = smp_processor_id(); if (local_timer_ack()) { - irq_stat[cpu].local_timer_irqs++; + __inc_irq_stat(cpu, local_timer_irqs); ipi_timer(); } @@ -437,7 +437,7 @@ void show_local_irqs(struct seq_file *p) seq_printf(p, "LOC: "); for_each_present_cpu(cpu) - seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); + seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs)); seq_putc(p, '\n'); } From cab8c6f3053c1b147bba825844c8e208f8b3b9f4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 14:20:41 +0000 Subject: [PATCH 17/52] ARM: SMP: move ipi_count into irq_stat structure Move the ipi_count into irq_stat, which allows the ipi_data structure to be entirely removed. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/hardirq.h | 3 +++ arch/arm/kernel/smp.c | 14 ++------------ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index 923eaa1ba83b7..824b08aa3f7a3 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -10,6 +10,9 @@ typedef struct { #ifdef CONFIG_LOCAL_TIMERS unsigned int local_timer_irqs; #endif +#ifdef CONFIG_SMP + unsigned int ipi_irqs; +#endif } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 24131264ec2c6..65b5ba8678058 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -46,15 +46,6 @@ */ struct secondary_data secondary_data; -/* - * structures for inter-processor calls - */ -struct ipi_data { - unsigned long ipi_count; -}; - -static DEFINE_PER_CPU(struct ipi_data, ipi_data); - enum ipi_msg_type { IPI_TIMER = 2, IPI_RESCHEDULE, @@ -398,7 +389,7 @@ void show_ipi_list(struct seq_file *p) seq_puts(p, "IPI:"); for_each_present_cpu(cpu) - seq_printf(p, " %10lu", per_cpu(ipi_data, cpu).ipi_count); + seq_printf(p, " %10u", __get_irq_stat(cpu, ipi_irqs)); seq_putc(p, '\n'); } @@ -513,10 +504,9 @@ static void ipi_cpu_stop(unsigned int cpu) asmlinkage void __exception do_IPI(int ipinr, struct pt_regs *regs) { unsigned int cpu = smp_processor_id(); - struct ipi_data *ipi = &per_cpu(ipi_data, cpu); struct pt_regs *old_regs = set_irq_regs(regs); - ipi->ipi_count++; + __inc_irq_stat(cpu, ipi_irqs); switch (ipinr) { case IPI_TIMER: From f13cd4170ee789f63b3c9585c1ae34e028bd549d Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 14:33:51 +0000 Subject: [PATCH 18/52] ARM: fix /proc/interrupts formatting As per x86, align the initial column according to how many IRQs we have. Also, provide an english explaination for the 'LOC:' and 'IPI:' lines. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/mach/irq.h | 2 +- arch/arm/include/asm/smp.h | 4 ++-- arch/arm/kernel/fiq.c | 5 +++-- arch/arm/kernel/irq.c | 16 ++++++++++------ arch/arm/kernel/smp.c | 14 +++++++------- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/arch/arm/include/asm/mach/irq.h b/arch/arm/include/asm/mach/irq.h index ce3eee9fe26cb..2bc47fb94d519 100644 --- a/arch/arm/include/asm/mach/irq.h +++ b/arch/arm/include/asm/mach/irq.h @@ -20,7 +20,7 @@ struct seq_file; extern unsigned int arch_nr_irqs; extern void (*init_arch_irq)(void); extern void init_FIQ(void); -extern int show_fiq_list(struct seq_file *, void *); +extern int show_fiq_list(struct seq_file *, int); /* * This is for easy migration, but should be changed in the source diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index da7e7ca53cc1d..f93d0a6370166 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -33,7 +33,7 @@ struct seq_file; /* * generate IPI list text */ -extern void show_ipi_list(struct seq_file *p); +extern void show_ipi_list(struct seq_file *, int); /* * Called from assembly code, this handles an IPI. @@ -97,6 +97,6 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); /* * show local interrupt info */ -extern void show_local_irqs(struct seq_file *); +extern void show_local_irqs(struct seq_file *, int); #endif /* ifndef __ASM_ARM_SMP_H */ diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index 6ff7919613d7d..47837b85c07cb 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -67,10 +67,11 @@ static struct fiq_handler default_owner = { static struct fiq_handler *current_fiq = &default_owner; -int show_fiq_list(struct seq_file *p, void *v) +int show_fiq_list(struct seq_file *p, int prec) { if (current_fiq != &default_owner) - seq_printf(p, "FIQ: %s\n", current_fiq->name); + seq_printf(p, "%*s: %s\n", prec, "FIQ", + current_fiq->name); return 0; } diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index ea29721ba3483..4e7a7d2722125 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -57,11 +57,15 @@ int show_interrupts(struct seq_file *p, void *v) struct irq_desc *desc; struct irqaction * action; unsigned long flags; + int prec, n; + + for (prec = 3, n = 1000; prec < 10 && n <= nr_irqs; prec++) + n *= 10; if (i == 0) { char cpuname[12]; - seq_printf(p, " "); + seq_printf(p, "%*s ", prec, ""); for_each_present_cpu(cpu) { sprintf(cpuname, "CPU%d", cpu); seq_printf(p, " %10s", cpuname); @@ -76,7 +80,7 @@ int show_interrupts(struct seq_file *p, void *v) if (!action) goto unlock; - seq_printf(p, "%3d: ", i); + seq_printf(p, "%*d: ", prec, i); for_each_present_cpu(cpu) seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu)); seq_printf(p, " %10s", desc->chip->name ? : "-"); @@ -89,15 +93,15 @@ int show_interrupts(struct seq_file *p, void *v) raw_spin_unlock_irqrestore(&desc->lock, flags); } else if (i == nr_irqs) { #ifdef CONFIG_FIQ - show_fiq_list(p, v); + show_fiq_list(p, prec); #endif #ifdef CONFIG_SMP - show_ipi_list(p); + show_ipi_list(p, prec); #endif #ifdef CONFIG_LOCAL_TIMERS - show_local_irqs(p); + show_local_irqs(p, prec); #endif - seq_printf(p, "Err: %10lu\n", irq_err_count); + seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); } return 0; } diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 65b5ba8678058..269237ed76a01 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -382,16 +382,16 @@ void arch_send_call_function_single_ipi(int cpu) smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); } -void show_ipi_list(struct seq_file *p) +void show_ipi_list(struct seq_file *p, int prec) { unsigned int cpu; - seq_puts(p, "IPI:"); + seq_printf(p, "%*s: ", prec, "IPI"); for_each_present_cpu(cpu) - seq_printf(p, " %10u", __get_irq_stat(cpu, ipi_irqs)); + seq_printf(p, "%10u ", __get_irq_stat(cpu, ipi_irqs)); - seq_putc(p, '\n'); + seq_printf(p, " Inter-processor interrupts\n"); } /* @@ -421,16 +421,16 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) set_irq_regs(old_regs); } -void show_local_irqs(struct seq_file *p) +void show_local_irqs(struct seq_file *p, int prec) { unsigned int cpu; - seq_printf(p, "LOC: "); + seq_printf(p, "%*s: ", prec, "LOC"); for_each_present_cpu(cpu) seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs)); - seq_putc(p, '\n'); + seq_printf(p, " Local timer interrupts\n"); } #endif From 4a88abd7b48e8ec8084b1252d0f5ebdab43c2508 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 14:40:29 +0000 Subject: [PATCH 19/52] ARM: SMP: provide individual IPI interrupt statistics This separates out the individual IPI interrupt counts from the total IPI count, which allows better visibility of what IPIs are being used for. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/hardirq.h | 4 +++- arch/arm/kernel/irq.c | 5 +++++ arch/arm/kernel/smp.c | 25 +++++++++++++++++++------ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index 824b08aa3f7a3..c52e2507c9e02 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -5,13 +5,15 @@ #include #include +#define NR_IPI 5 + typedef struct { unsigned int __softirq_pending; #ifdef CONFIG_LOCAL_TIMERS unsigned int local_timer_irqs; #endif #ifdef CONFIG_SMP - unsigned int ipi_irqs; + unsigned int ipi_irqs[NR_IPI]; #endif } ____cacheline_aligned irq_cpustat_t; diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 4e7a7d2722125..6276f01df9e4e 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -62,6 +62,11 @@ int show_interrupts(struct seq_file *p, void *v) for (prec = 3, n = 1000; prec < 10 && n <= nr_irqs; prec++) n *= 10; +#ifdef CONFIG_SMP + if (prec < 4) + prec = 4; +#endif + if (i == 0) { char cpuname[12]; diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 269237ed76a01..fa0c5f6e15873 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -382,16 +382,28 @@ void arch_send_call_function_single_ipi(int cpu) smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); } +static const char *ipi_types[NR_IPI] = { +#define S(x,s) [x - IPI_TIMER] = s + S(IPI_TIMER, "Timer broadcast interrupts"), + S(IPI_RESCHEDULE, "Rescheduling interrupts"), + S(IPI_CALL_FUNC, "Function call interrupts"), + S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), + S(IPI_CPU_STOP, "CPU stop interrupts"), +}; + void show_ipi_list(struct seq_file *p, int prec) { - unsigned int cpu; + unsigned int cpu, i; - seq_printf(p, "%*s: ", prec, "IPI"); + for (i = 0; i < NR_IPI; i++) { + seq_printf(p, "%*s%u: ", prec - 1, "IPI", i); - for_each_present_cpu(cpu) - seq_printf(p, "%10u ", __get_irq_stat(cpu, ipi_irqs)); + for_each_present_cpu(cpu) + seq_printf(p, "%10u ", + __get_irq_stat(cpu, ipi_irqs[i])); - seq_printf(p, " Inter-processor interrupts\n"); + seq_printf(p, " %s\n", ipi_types[i]); + } } /* @@ -506,7 +518,8 @@ asmlinkage void __exception do_IPI(int ipinr, struct pt_regs *regs) unsigned int cpu = smp_processor_id(); struct pt_regs *old_regs = set_irq_regs(regs); - __inc_irq_stat(cpu, ipi_irqs); + if (ipinr >= IPI_TIMER && ipinr < IPI_TIMER + NR_IPI) + __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_TIMER]); switch (ipinr) { case IPI_TIMER: From b54992fe1b4bad7b7488d58b8696e4e8974fdab0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 15 Nov 2010 14:46:46 +0000 Subject: [PATCH 20/52] ARM: SMP: collect IPI and local timer IRQs for /proc/stat The IPI and local timer interrupts weren't being properly accounted for in /proc/stat. Collect them from the irq_stat structure, and return their sum. Reviewed-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/hardirq.h | 8 ++++++++ arch/arm/kernel/smp.c | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h index c52e2507c9e02..89ad1805e5797 100644 --- a/arch/arm/include/asm/hardirq.h +++ b/arch/arm/include/asm/hardirq.h @@ -22,6 +22,14 @@ typedef struct { #define __inc_irq_stat(cpu, member) __IRQ_STAT(cpu, member)++ #define __get_irq_stat(cpu, member) __IRQ_STAT(cpu, member) +#ifdef CONFIG_SMP +u64 smp_irq_stat_cpu(unsigned int cpu); +#else +#define smp_irq_stat_cpu(cpu) 0 +#endif + +#define arch_irq_stat_cpu smp_irq_stat_cpu + #if NR_IRQS > 512 #define HARDIRQ_BITS 10 #elif NR_IRQS > 256 diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index fa0c5f6e15873..1de3e13a42a11 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -406,6 +406,21 @@ void show_ipi_list(struct seq_file *p, int prec) } } +u64 smp_irq_stat_cpu(unsigned int cpu) +{ + u64 sum = 0; + int i; + + for (i = 0; i < NR_IPI; i++) + sum += __get_irq_stat(cpu, ipi_irqs[i]); + +#ifdef CONFIG_LOCAL_TIMERS + sum += __get_irq_stat(cpu, local_timer_irqs); +#endif + + return sum; +} + /* * Timer (local or broadcast) support */ From 0eb0511d176534674600a1986c3c766756288908 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 22 Nov 2010 12:06:28 +0000 Subject: [PATCH 21/52] ARM: SMP: use more sane register allocation for __fixup_smp_on_up Use r0,r3-r6 rather than r0,r3,r4,r6,r7, which makes it easier to understand which registers can be modified. Also document which registers hold values which must be preserved. Signed-off-by: Russell King --- arch/arm/kernel/head.S | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index dd6b369ac69ca..fd94e4e82fc92 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -89,6 +89,11 @@ ENTRY(stext) bl __lookup_machine_type @ r5=machinfo movs r8, r5 @ invalid machine (r5=0)? beq __error_a @ yes, error 'a' + + /* + * r1 = machine no, r2 = atags, + * r8 = machinfo, r9 = cpuid, r10 = procinfo + */ bl __vet_atags #ifdef CONFIG_SMP_ON_UP bl __fixup_smp @@ -381,19 +386,19 @@ ENDPROC(__turn_mmu_on) #ifdef CONFIG_SMP_ON_UP __fixup_smp: - mov r7, #0x00070000 - orr r6, r7, #0xff000000 @ mask 0xff070000 - orr r7, r7, #0x41000000 @ val 0x41070000 - and r0, r9, r6 - teq r0, r7 @ ARM CPU and ARMv6/v7? + mov r4, #0x00070000 + orr r3, r4, #0xff000000 @ mask 0xff070000 + orr r4, r4, #0x41000000 @ val 0x41070000 + and r0, r9, r3 + teq r0, r4 @ ARM CPU and ARMv6/v7? bne __fixup_smp_on_up @ no, assume UP - orr r6, r6, #0x0000ff00 - orr r6, r6, #0x000000f0 @ mask 0xff07fff0 - orr r7, r7, #0x0000b000 - orr r7, r7, #0x00000020 @ val 0x4107b020 - and r0, r9, r6 - teq r0, r7 @ ARM 11MPCore? + orr r3, r3, #0x0000ff00 + orr r3, r3, #0x000000f0 @ mask 0xff07fff0 + orr r4, r4, #0x0000b000 + orr r4, r4, #0x00000020 @ val 0x4107b020 + and r0, r9, r3 + teq r0, r4 @ ARM 11MPCore? moveq pc, lr @ yes, assume SMP mrc p15, 0, r0, c0, c0, 5 @ read MPIDR @@ -402,13 +407,13 @@ __fixup_smp: __fixup_smp_on_up: adr r0, 1f - ldmia r0, {r3, r6, r7} + ldmia r0, {r3 - r5} sub r3, r0, r3 - add r6, r6, r3 - add r7, r7, r3 -2: cmp r6, r7 - ldmia r6!, {r0, r4} - strlo r4, [r0, r3] + add r4, r4, r3 + add r5, r5, r3 +2: cmp r4, r5 + ldmia r4!, {r0, r6} + strlo r6, [r0, r3] blo 2b mov pc, lr ENDPROC(__fixup_smp) From 28e18293cf0f8d23a0950d7b1d2212d11af494dc Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 2 Dec 2010 09:53:54 +0000 Subject: [PATCH 22/52] ARM: SMP: ensure smp_send_stop() waits for CPUs to stop Wait for CPUs to indicate that they've stopped, after sending the stop IPI, rather than blindly continuing on and hoping that they've stopped in time. Print a warning if we fail to stop the other CPUs. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 1de3e13a42a11..64f2d198c7647 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -575,10 +575,22 @@ void smp_send_reschedule(int cpu) void smp_send_stop(void) { - cpumask_t mask = cpu_online_map; - cpu_clear(smp_processor_id(), mask); - if (!cpus_empty(mask)) + unsigned long timeout; + + if (num_online_cpus() > 1) { + cpumask_t mask = cpu_online_map; + cpu_clear(smp_processor_id(), mask); + smp_cross_call(&mask, IPI_CPU_STOP); + } + + /* Wait up to one second for other CPUs to stop */ + timeout = USEC_PER_SEC; + while (num_online_cpus() > 1 && timeout--) + udelay(1); + + if (num_online_cpus() > 1) + pr_warning("SMP: failed to stop secondary CPUs\n"); } /* From bbc3d14e9aca023bb98e580aa1c9350af8effdb1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 3 Dec 2010 10:42:58 +0000 Subject: [PATCH 23/52] ARM: SMP: move CPU number sanity checks to smp_init_cpus() Ensure that the number of CPUs is sanity checked before setting the number of possible CPUs. This avoids any chance of overflowing the cpu_possible bitmap. Signed-off-by: Russell King --- arch/arm/mach-omap2/omap-smp.c | 21 +++++++++++---------- arch/arm/mach-realview/platsmp.c | 20 ++++++++++---------- arch/arm/mach-ux500/platsmp.c | 26 +++++++++++++------------- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 56a8bce247c89..3c87468ce9cbb 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -120,16 +120,6 @@ void __init smp_init_cpus(void) ncores = get_core_count(); - for (i = 0; i < ncores; i++) - set_cpu_possible(i, true); -} - -void __init smp_prepare_cpus(unsigned int max_cpus) -{ - unsigned int ncores = get_core_count(); - unsigned int cpu = smp_processor_id(); - int i; - /* sanity check */ if (ncores == 0) { printk(KERN_ERR @@ -144,6 +134,17 @@ void __init smp_prepare_cpus(unsigned int max_cpus) ncores, NR_CPUS); ncores = NR_CPUS; } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} + +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + unsigned int ncores = num_possible_cpus(); + unsigned int cpu = smp_processor_id(); + int i; + smp_store_cpu_info(cpu); /* diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index af3d9093390b6..108e92f9746b0 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -160,16 +160,6 @@ void __init smp_init_cpus(void) { unsigned int i, ncores = get_core_count(); - for (i = 0; i < ncores; i++) - set_cpu_possible(i, true); -} - -void __init smp_prepare_cpus(unsigned int max_cpus) -{ - unsigned int ncores = get_core_count(); - unsigned int cpu = smp_processor_id(); - int i; - /* sanity check */ if (ncores == 0) { printk(KERN_ERR @@ -186,6 +176,16 @@ void __init smp_prepare_cpus(unsigned int max_cpus) ncores = NR_CPUS; } + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} + +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + unsigned int ncores = num_possible_cpus(); + unsigned int cpu = smp_processor_id(); + int i; + smp_store_cpu_info(cpu); /* diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index b8987bd212497..a51962b7579ba 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -128,16 +128,6 @@ void __init smp_init_cpus(void) { unsigned int i, ncores = get_core_count(); - for (i = 0; i < ncores; i++) - set_cpu_possible(i, true); -} - -void __init smp_prepare_cpus(unsigned int max_cpus) -{ - unsigned int ncores = get_core_count(); - unsigned int cpu = smp_processor_id(); - int i; - /* sanity check */ if (ncores == 0) { printk(KERN_ERR @@ -145,14 +135,24 @@ void __init smp_prepare_cpus(unsigned int max_cpus) ncores = 1; } - if (ncores > num_possible_cpus()) { + if (ncores > NR_CPUS) { printk(KERN_WARNING "U8500: no. of cores (%d) greater than configured " "maximum of %d - clipping\n", - ncores, num_possible_cpus()); - ncores = num_possible_cpus(); + ncores, NR_CPUS); + ncores = NR_CPUS; } + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} + +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + unsigned int ncores = num_possible_cpus(); + unsigned int cpu = smp_processor_id(); + int i; + smp_store_cpu_info(cpu); /* From 8975b6c0fdd57e061f4d1040163778ceaf340ad8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 3 Dec 2010 19:29:53 +0000 Subject: [PATCH 24/52] ARM: SMP: Clean up ncores sanity checks scu_get_core_count() never returns zero cores, so we don't need to check and correct if ncores is zero. Tegra was missing the check against NR_CPUS, leading to a potential bitfield overflow if this becomes the case. Signed-off-by: Russell King --- arch/arm/mach-omap2/omap-smp.c | 6 ------ arch/arm/mach-realview/platsmp.c | 7 ------- arch/arm/mach-s5pv310/platsmp.c | 7 ------- arch/arm/mach-tegra/platsmp.c | 6 ++++++ arch/arm/mach-ux500/platsmp.c | 6 ------ arch/arm/mach-vexpress/platsmp.c | 7 ------- 6 files changed, 6 insertions(+), 33 deletions(-) diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 3c87468ce9cbb..5f10f38354aea 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -121,12 +121,6 @@ void __init smp_init_cpus(void) ncores = get_core_count(); /* sanity check */ - if (ncores == 0) { - printk(KERN_ERR - "OMAP4: strange core count of 0? Default to 1\n"); - ncores = 1; - } - if (ncores > NR_CPUS) { printk(KERN_WARNING "OMAP4: no. of cores (%d) greater than configured " diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 108e92f9746b0..13116cd37639a 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -161,13 +161,6 @@ void __init smp_init_cpus(void) unsigned int i, ncores = get_core_count(); /* sanity check */ - if (ncores == 0) { - printk(KERN_ERR - "Realview: strange CM count of 0? Default to 1\n"); - - ncores = 1; - } - if (ncores > NR_CPUS) { printk(KERN_WARNING "Realview: no. of cores (%d) greater than configured " diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c index d474426f37b75..560ada83b0b14 100644 --- a/arch/arm/mach-s5pv310/platsmp.c +++ b/arch/arm/mach-s5pv310/platsmp.c @@ -130,13 +130,6 @@ void __init smp_init_cpus(void) ncores = scu_base ? scu_get_core_count(scu_base) : 1; /* sanity check */ - if (ncores == 0) { - printk(KERN_ERR - "S5PV310: strange CM count of 0? Default to 1\n"); - - ncores = 1; - } - if (ncores > NR_CPUS) { printk(KERN_WARNING "S5PV310: no. of cores (%d) greater than configured " diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 1c0fd92cab39e..5b194dd815a8a 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -117,6 +117,12 @@ void __init smp_init_cpus(void) { unsigned int i, ncores = scu_get_core_count(scu_base); + if (ncores > NR_CPUS) { + printk(KERN_ERR "Tegra: no. of cores (%u) greater than configured (%u), clipping\n", + ncores, NR_CPUS); + ncores = NR_CPUS; + } + for (i = 0; i < ncores; i++) cpu_set(i, cpu_possible_map); } diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index a51962b7579ba..e31024e3a7ccc 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -129,12 +129,6 @@ void __init smp_init_cpus(void) unsigned int i, ncores = get_core_count(); /* sanity check */ - if (ncores == 0) { - printk(KERN_ERR - "U8500: strange CM count of 0? Default to 1\n"); - ncores = 1; - } - if (ncores > NR_CPUS) { printk(KERN_WARNING "U8500: no. of cores (%d) greater than configured " diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index 276f916014c1c..b5a7586836683 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -124,13 +124,6 @@ void __init smp_init_cpus(void) ncores = scu_base ? scu_get_core_count(scu_base) : 1; /* sanity check */ - if (ncores == 0) { - printk(KERN_ERR - "vexpress: strange CM count of 0? Default to 1\n"); - - ncores = 1; - } - if (ncores > NR_CPUS) { printk(KERN_WARNING "vexpress: no. of cores (%d) greater than configured " From fd778f0ad7dda1108281410ddca0d07936256d3c Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 2 Dec 2010 18:09:37 +0000 Subject: [PATCH 25/52] ARM: SMP: get rid of get_core_count() We don't need this small function as well as scu_get_core_count() Signed-off-by: Russell King --- arch/arm/mach-omap2/omap-smp.c | 12 +----------- arch/arm/mach-realview/platsmp.c | 13 ++++--------- arch/arm/mach-ux500/platsmp.c | 9 +++------ 3 files changed, 8 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 5f10f38354aea..405a8fc533088 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -29,16 +29,6 @@ /* SCU base address */ static void __iomem *scu_base; -/* - * Use SCU config register to count number of cores - */ -static inline unsigned int get_core_count(void) -{ - if (scu_base) - return scu_get_core_count(scu_base); - return 1; -} - static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) @@ -118,7 +108,7 @@ void __init smp_init_cpus(void) scu_base = ioremap(OMAP44XX_SCU_BASE, SZ_256); BUG_ON(!scu_base); - ncores = get_core_count(); + ncores = scu_get_core_count(scu_base); /* sanity check */ if (ncores > NR_CPUS) { diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 13116cd37639a..6595e875fb2f9 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -50,14 +50,6 @@ static void __iomem *scu_base_addr(void) return (void __iomem *)0; } -static inline unsigned int get_core_count(void) -{ - void __iomem *scu_base = scu_base_addr(); - if (scu_base) - return scu_get_core_count(scu_base); - return 1; -} - static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) @@ -158,7 +150,10 @@ static void __init poke_milo(void) */ void __init smp_init_cpus(void) { - unsigned int i, ncores = get_core_count(); + void __iomem *scu_base = scu_base_addr(); + unsigned int i, ncores; + + ncores = scu_base ? scu_get_core_count(scu_base) : 1; /* sanity check */ if (ncores > NR_CPUS) { diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index e31024e3a7ccc..fd40fa175913c 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -28,11 +28,6 @@ */ volatile int __cpuinitdata pen_release = -1; -static unsigned int __init get_core_count(void) -{ - return scu_get_core_count(__io_address(UX500_SCU_BASE)); -} - static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) @@ -126,7 +121,9 @@ static void __init wakeup_secondary(void) */ void __init smp_init_cpus(void) { - unsigned int i, ncores = get_core_count(); + unsigned int i, ncores; + + ncores = scu_get_core_count(__io_address(UX500_SCU_BASE)); /* sanity check */ if (ncores > NR_CPUS) { From aec66ba1f75c2030cf66f5a21d1c81aa83aa5d95 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 2 Dec 2010 19:10:01 +0000 Subject: [PATCH 26/52] ARM: SMP: get rid of references to poke_milo and Milo Milo is an old boot loader, which is no longer relevant for these platforms. References to it are misleading. Move the code out of poke_milo(), and remove references to milo in comments. Signed-off-by: Russell King --- arch/arm/mach-realview/platsmp.c | 44 +++++++++----------------------- arch/arm/mach-tegra/platsmp.c | 7 ----- 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 6595e875fb2f9..ef3cc86f51408 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -99,14 +99,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) flush_cache_all(); /* - * XXX - * - * This is a later addition to the booting protocol: the - * bootMonitor now puts secondary cores into WFI, so - * poke_milo() no longer gets the cores moving; we need - * to send a soft interrupt to wake the secondary core. - * Use smp_cross_call() for this, since there's little - * point duplicating the code here + * Send the secondary CPU a soft interrupt, thereby causing + * the boot monitor to read the system wide flags register, + * and branch to the address found there. */ smp_cross_call(cpumask_of(cpu), 1); @@ -128,22 +123,6 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) return pen_release != -1 ? -ENOSYS : 0; } -static void __init poke_milo(void) -{ - /* nobody is to be released from the pen yet */ - pen_release = -1; - - /* - * Write the address of secondary startup into the system-wide flags - * register. The BootMonitor waits for this register to become - * non-zero. - */ - __raw_writel(BSYM(virt_to_phys(realview_secondary_startup)), - __io_address(REALVIEW_SYS_FLAGSSET)); - - mb(); -} - /* * Initialise the CPU possible map early - this describes the CPUs * which may be present or become present in the system. @@ -189,13 +168,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - /* - * Initialise the SCU if there are more than one CPU and let - * them know where to start. Note that, on modern versions of - * MILO, the "poke" doesn't actually do anything until each - * individual core is sent a soft interrupt to get it out of - * WFI - */ if (max_cpus > 1) { /* * Enable the local timer or broadcast device for the @@ -204,6 +176,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus) percpu_timer_setup(); scu_enable(scu_base_addr()); - poke_milo(); + + /* + * Write the address of secondary startup into the + * system-wide flags register. The BootMonitor waits + * until it receives a soft interrupt, and then the + * secondary CPU branches to this address. + */ + __raw_writel(BSYM(virt_to_phys(realview_secondary_startup)), + __io_address(REALVIEW_SYS_FLAGSSET)); } } diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 5b194dd815a8a..66d0634e7a962 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -148,13 +148,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - /* - * Initialise the SCU if there are more than one CPU and let - * them know where to start. Note that, on modern versions of - * MILO, the "poke" doesn't actually do anything until each - * individual core is sent a soft interrupt to get it out of - * WFI - */ if (max_cpus > 1) { percpu_timer_setup(); scu_enable(scu_base); From 05c74a6cbcfb416286a947668ba32f63d99fe74a Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 3 Dec 2010 11:09:48 +0000 Subject: [PATCH 27/52] ARM: SMP: consolidate the common parts of smp_prepare_cpus() There is a certain amount of smp_prepare_cpus() which doesn't belong in the platform support code - that is, code which is invariant to the SMP implementation. Move this code into arch/arm/kernel/smp.c, and add a platform_ prefix to the original function. Signed-off-by: Russell King --- arch/arm/include/asm/smp.h | 9 +++--- arch/arm/kernel/smp.c | 49 +++++++++++++++++++++++++------- arch/arm/mach-omap2/omap-smp.c | 33 +++++---------------- arch/arm/mach-realview/platsmp.c | 41 +++++++------------------- arch/arm/mach-s5pv310/platsmp.c | 35 +++++------------------ arch/arm/mach-tegra/platsmp.c | 18 ++---------- arch/arm/mach-ux500/platsmp.c | 24 ++-------------- arch/arm/mach-vexpress/platsmp.c | 43 +++++++--------------------- 8 files changed, 83 insertions(+), 169 deletions(-) diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index f93d0a6370166..96ed521f24087 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -45,10 +45,6 @@ asmlinkage void do_IPI(int ipinr, struct pt_regs *regs); */ extern void smp_init_cpus(void); -/* - * Move global data into per-processor storage. - */ -extern void smp_store_cpu_info(unsigned int cpuid); /* * Raise an IPI cross call on CPUs in callmap. @@ -72,6 +68,11 @@ asmlinkage void secondary_start_kernel(void); */ extern void platform_secondary_init(unsigned int cpu); +/* + * Initialize cpu_possible map, and enable coherency + */ +extern void platform_smp_prepare_cpus(unsigned int); + /* * Initial data for bringing up a secondary CPU. */ diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 64f2d198c7647..c66f2d3f65d3e 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -281,6 +281,17 @@ void __ref cpu_die(void) } #endif /* CONFIG_HOTPLUG_CPU */ +/* + * Called by both boot and secondaries to move global data into + * per-processor storage. + */ +static void __cpuinit smp_store_cpu_info(unsigned int cpuid) +{ + struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); + + cpu_info->loops_per_jiffy = loops_per_jiffy; +} + /* * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. @@ -339,17 +350,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void) cpu_idle(); } -/* - * Called by both boot and secondaries to move global data into - * per-processor storage. - */ -void __cpuinit smp_store_cpu_info(unsigned int cpuid) -{ - struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid); - - cpu_info->loops_per_jiffy = loops_per_jiffy; -} - void __init smp_cpus_done(unsigned int max_cpus) { int cpu; @@ -372,6 +372,33 @@ void __init smp_prepare_boot_cpu(void) per_cpu(cpu_data, cpu).idle = current; } +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + unsigned int ncores = num_possible_cpus(); + + smp_store_cpu_info(smp_processor_id()); + + /* + * are we trying to boot more cores than exist? + */ + if (max_cpus > ncores) + max_cpus = ncores; + + if (max_cpus > 1) { + /* + * Enable the local timer or broadcast device for the + * boot CPU, but only if we have more than one CPU. + */ + percpu_timer_setup(); + + /* + * Initialise the SCU if there are more than one CPU + * and let them know where to start. + */ + platform_smp_prepare_cpus(max_cpus); + } +} + void arch_send_call_function_ipi_mask(const struct cpumask *mask) { smp_cross_call(mask, IPI_CALL_FUNC); diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 405a8fc533088..3c3d6796c97c2 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -123,20 +122,10 @@ void __init smp_init_cpus(void) set_cpu_possible(i, true); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = num_possible_cpus(); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -144,18 +133,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - - /* - * Initialise the SCU and wake up the secondary core using - * wakeup_secondary(). - */ - scu_enable(scu_base); - wakeup_secondary(); - } + /* + * Initialise the SCU and wake up the secondary core using + * wakeup_secondary(). + */ + scu_enable(scu_base); + wakeup_secondary(); } diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index ef3cc86f51408..380562cd6580d 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -147,20 +146,10 @@ void __init smp_init_cpus(void) set_cpu_possible(i, true); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = num_possible_cpus(); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -168,22 +157,14 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - - scu_enable(scu_base_addr()); - - /* - * Write the address of secondary startup into the - * system-wide flags register. The BootMonitor waits - * until it receives a soft interrupt, and then the - * secondary CPU branches to this address. - */ - __raw_writel(BSYM(virt_to_phys(realview_secondary_startup)), - __io_address(REALVIEW_SYS_FLAGSSET)); - } + scu_enable(scu_base_addr()); + + /* + * Write the address of secondary startup into the + * system-wide flags register. The BootMonitor waits + * until it receives a soft interrupt, and then the + * secondary CPU branches to this address. + */ + __raw_writel(BSYM(virt_to_phys(realview_secondary_startup)), + __io_address(REALVIEW_SYS_FLAGSSET)); } diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c index 560ada83b0b14..51c44d4c98902 100644 --- a/arch/arm/mach-s5pv310/platsmp.c +++ b/arch/arm/mach-s5pv310/platsmp.c @@ -22,7 +22,6 @@ #include #include -#include #include #include @@ -142,18 +141,10 @@ void __init smp_init_cpus(void) set_cpu_possible(i, true); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = num_possible_cpus(); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* are we trying to boot more cores than exist? */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -161,25 +152,13 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); + scu_enable(scu_base_addr()); + /* - * Initialise the SCU if there are more than one CPU and let - * them know where to start. + * Write the address of secondary startup into the + * system-wide flags register. The boot monitor waits + * until it receives a soft interrupt, and then the + * secondary CPU branches to this address. */ - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - - scu_enable(scu_base_addr()); - - /* - * Write the address of secondary startup into the - * system-wide flags register. The boot monitor waits - * until it receives a soft interrupt, and then the - * secondary CPU branches to this address. - */ __raw_writel(BSYM(virt_to_phys(s5pv310_secondary_startup)), S5P_VA_SYSRAM); - } } diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 66d0634e7a962..b66a0c2d990d2 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -127,20 +126,10 @@ void __init smp_init_cpus(void) cpu_set(i, cpu_possible_map); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = scu_get_core_count(scu_base); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -148,8 +137,5 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - if (max_cpus > 1) { - percpu_timer_setup(); - scu_enable(scu_base); - } + scu_enable(scu_base); } diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index fd40fa175913c..458a288981cb5 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -138,20 +137,10 @@ void __init smp_init_cpus(void) set_cpu_possible(i, true); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = num_possible_cpus(); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -159,13 +148,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - scu_enable(__io_address(UX500_SCU_BASE)); - wakeup_secondary(); - } + scu_enable(__io_address(UX500_SCU_BASE)); + wakeup_secondary(); } diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index b5a7586836683..a0341d14ff2aa 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -17,7 +17,6 @@ #include #include -#include #include #include @@ -136,20 +135,10 @@ void __init smp_init_cpus(void) set_cpu_possible(i, true); } -void __init smp_prepare_cpus(unsigned int max_cpus) +void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - unsigned int ncores = num_possible_cpus(); - unsigned int cpu = smp_processor_id(); int i; - smp_store_cpu_info(cpu); - - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; - /* * Initialise the present map, which describes the set of CPUs * actually populated at the present time. @@ -157,27 +146,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < max_cpus; i++) set_cpu_present(i, true); + scu_enable(scu_base_addr()); + /* - * Initialise the SCU if there are more than one CPU and let - * them know where to start. + * Write the address of secondary startup into the + * system-wide flags register. The boot monitor waits + * until it receives a soft interrupt, and then the + * secondary CPU branches to this address. */ - if (max_cpus > 1) { - /* - * Enable the local timer or broadcast device for the - * boot CPU, but only if we have more than one CPU. - */ - percpu_timer_setup(); - - scu_enable(scu_base_addr()); - - /* - * Write the address of secondary startup into the - * system-wide flags register. The boot monitor waits - * until it receives a soft interrupt, and then the - * secondary CPU branches to this address. - */ - writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR)); - writel(BSYM(virt_to_phys(vexpress_secondary_startup)), - MMIO_P2V(V2M_SYS_FLAGSSET)); - } + writel(~0, MMIO_P2V(V2M_SYS_FLAGSCLR)); + writel(BSYM(virt_to_phys(vexpress_secondary_startup)), + MMIO_P2V(V2M_SYS_FLAGSSET)); } From 2c0136dba4e43b0916ccc9ecc7f11e6d6b73f046 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 3 Dec 2010 15:00:49 +0000 Subject: [PATCH 28/52] ARM: SMP: consolidate trace_hardirqs_off() into common SMP code All platforms call trace_hardirqs_off() in their secondary startup code, so move this into the core SMP code - it doesn't need to be in the per-platform code. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 1 + arch/arm/mach-omap2/omap-smp.c | 2 -- arch/arm/mach-realview/platsmp.c | 2 -- arch/arm/mach-s5pv310/platsmp.c | 2 -- arch/arm/mach-tegra/platsmp.c | 2 -- arch/arm/mach-ux500/platsmp.c | 2 -- arch/arm/mach-vexpress/platsmp.c | 2 -- 7 files changed, 1 insertion(+), 12 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index c66f2d3f65d3e..a30c4094db3a2 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -317,6 +317,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void) cpu_init(); preempt_disable(); + trace_hardirqs_off(); /* * Give the platform a chance to do its own initialisation. diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 3c3d6796c97c2..9fed631ba0467 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -32,8 +32,6 @@ static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * If any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 380562cd6580d..226c63102a004 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -53,8 +53,6 @@ static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c index 51c44d4c98902..18aaf5f540332 100644 --- a/arch/arm/mach-s5pv310/platsmp.c +++ b/arch/arm/mach-s5pv310/platsmp.c @@ -46,8 +46,6 @@ static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index b66a0c2d990d2..c729cd72cc3b7 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -40,8 +40,6 @@ static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 458a288981cb5..ddedbc80c41ff 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -31,8 +31,6 @@ static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index a0341d14ff2aa..d7e0cb994e9df 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -43,8 +43,6 @@ static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) { - trace_hardirqs_off(); - /* * if any interrupts are already enabled for the primary * core (e.g. timer irq), then they will not have been enabled From 3c030beabf937b1d3b4ecaedfd1fb2f1e2aa0c70 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 30 Nov 2010 11:07:35 +0000 Subject: [PATCH 29/52] ARM: CPU hotplug: move cpu_killed completion to core code We always need to wait for the dying CPU to reach a safe state before taking it down, irrespective of the requirements of the platform. Move the completion code into the ARM SMP hotplug code rather than having each platform re-implement this. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 14 +++++++++++++- arch/arm/mach-omap2/omap-hotplug.c | 8 ++------ arch/arm/mach-realview/hotplug.c | 8 +------- arch/arm/mach-s5pv310/hotplug.c | 8 +------- arch/arm/mach-tegra/hotplug.c | 8 +------- arch/arm/mach-ux500/hotplug.c | 8 +------- 6 files changed, 19 insertions(+), 35 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index a30c4094db3a2..8c81ff9b3732d 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -238,12 +239,20 @@ int __cpu_disable(void) return 0; } +static DECLARE_COMPLETION(cpu_died); + /* * called on the thread which is asking for a CPU to be shutdown - * waits until shutdown has completed, or it is timed out. */ void __cpu_die(unsigned int cpu) { + if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) { + pr_err("CPU%u: cpu didn't die\n", cpu); + return; + } + printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); + if (!platform_cpu_kill(cpu)) printk("CPU%u: unable to kill\n", cpu); } @@ -263,9 +272,12 @@ void __ref cpu_die(void) local_irq_disable(); idle_task_exit(); + /* Tell __cpu_die() that this CPU is now safe to dispose of */ + complete(&cpu_died); + /* * actual CPU shutdown procedure is at least platform (if not - * CPU) specific + * CPU) specific. */ platform_cpu_die(cpu); diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c index 6cee456ca542e..ace979d74bfcc 100644 --- a/arch/arm/mach-omap2/omap-hotplug.c +++ b/arch/arm/mach-omap2/omap-hotplug.c @@ -17,16 +17,13 @@ #include #include #include -#include #include #include -static DECLARE_COMPLETION(cpu_killed); - int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -42,8 +39,7 @@ void platform_cpu_die(unsigned int cpu) this_cpu, cpu); BUG(); } - pr_notice("CPU%u: shutdown\n", cpu); - complete(&cpu_killed); + flush_cache_all(); dsb(); diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c index f95521a5e5ce6..7d58c16c83a76 100644 --- a/arch/arm/mach-realview/hotplug.c +++ b/arch/arm/mach-realview/hotplug.c @@ -11,14 +11,11 @@ #include #include #include -#include #include extern volatile int pen_release; -static DECLARE_COMPLETION(cpu_killed); - static inline void cpu_enter_lowpower(void) { unsigned int v; @@ -95,7 +92,7 @@ static inline void platform_do_lowpower(unsigned int cpu) int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -115,9 +112,6 @@ void platform_cpu_die(unsigned int cpu) } #endif - printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); - complete(&cpu_killed); - /* * we're ready for shutdown now, so do it */ diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-s5pv310/hotplug.c index 03652c3605f60..d7be70ac75360 100644 --- a/arch/arm/mach-s5pv310/hotplug.c +++ b/arch/arm/mach-s5pv310/hotplug.c @@ -13,14 +13,11 @@ #include #include #include -#include #include extern volatile int pen_release; -static DECLARE_COMPLETION(cpu_killed); - static inline void cpu_enter_lowpower(void) { unsigned int v; @@ -98,7 +95,7 @@ static inline void platform_do_lowpower(unsigned int cpu) int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -118,9 +115,6 @@ void platform_cpu_die(unsigned int cpu) } #endif - printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); - complete(&cpu_killed); - /* * we're ready for shutdown now, so do it */ diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index 8e7f115aa21e8..ecaa41ce49767 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -11,12 +11,9 @@ #include #include #include -#include #include -static DECLARE_COMPLETION(cpu_killed); - static inline void cpu_enter_lowpower(void) { unsigned int v; @@ -94,7 +91,7 @@ static inline void platform_do_lowpower(unsigned int cpu) int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -114,9 +111,6 @@ void platform_cpu_die(unsigned int cpu) } #endif - printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); - complete(&cpu_killed); - /* * we're ready for shutdown now, so do it */ diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c index b782a03024be1..7a4890b96e5ce 100644 --- a/arch/arm/mach-ux500/hotplug.c +++ b/arch/arm/mach-ux500/hotplug.c @@ -11,14 +11,11 @@ #include #include #include -#include #include extern volatile int pen_release; -static DECLARE_COMPLETION(cpu_killed); - static inline void platform_do_lowpower(unsigned int cpu) { flush_cache_all(); @@ -38,7 +35,7 @@ static inline void platform_do_lowpower(unsigned int cpu) int platform_cpu_kill(unsigned int cpu) { - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -58,9 +55,6 @@ void platform_cpu_die(unsigned int cpu) } #endif - printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); - complete(&cpu_killed); - /* directly enter low power state, skipping secure registers */ platform_do_lowpower(cpu); } From bbc81fd4327f9ed4480b05981e38acd48b1d184a Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 30 Nov 2010 11:12:30 +0000 Subject: [PATCH 30/52] ARM: CPU hotplug: remove bug checks in platform_cpu_die() platform_cpu_die() is entered from the CPU's own idle thread, which can not be migrated to other CPUs. Moreover, the 'cpu' argument comes from the thread info, which will always be the 'current' CPU. So remove this useless bug check. Signed-off-by: Russell King --- arch/arm/mach-omap2/omap-hotplug.c | 8 -------- arch/arm/mach-realview/hotplug.c | 10 ---------- arch/arm/mach-s5pv310/hotplug.c | 10 ---------- arch/arm/mach-tegra/hotplug.c | 10 ---------- arch/arm/mach-ux500/hotplug.c | 10 ---------- 5 files changed, 48 deletions(-) diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c index ace979d74bfcc..4976b9393e491 100644 --- a/arch/arm/mach-omap2/omap-hotplug.c +++ b/arch/arm/mach-omap2/omap-hotplug.c @@ -32,14 +32,6 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { - unsigned int this_cpu = hard_smp_processor_id(); - - if (cpu != this_cpu) { - pr_crit("platform_cpu_die running on %u, should be %u\n", - this_cpu, cpu); - BUG(); - } - flush_cache_all(); dsb(); diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c index 7d58c16c83a76..e06572e6c4904 100644 --- a/arch/arm/mach-realview/hotplug.c +++ b/arch/arm/mach-realview/hotplug.c @@ -102,16 +102,6 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { -#ifdef DEBUG - unsigned int this_cpu = hard_smp_processor_id(); - - if (cpu != this_cpu) { - printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n", - this_cpu, cpu); - BUG(); - } -#endif - /* * we're ready for shutdown now, so do it */ diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-s5pv310/hotplug.c index d7be70ac75360..ea951ef6ea544 100644 --- a/arch/arm/mach-s5pv310/hotplug.c +++ b/arch/arm/mach-s5pv310/hotplug.c @@ -105,16 +105,6 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { -#ifdef DEBUG - unsigned int this_cpu = hard_smp_processor_id(); - - if (cpu != this_cpu) { - printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n", - this_cpu, cpu); - BUG(); - } -#endif - /* * we're ready for shutdown now, so do it */ diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index ecaa41ce49767..a5eeb9126645d 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -101,16 +101,6 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { -#ifdef DEBUG - unsigned int this_cpu = hard_smp_processor_id(); - - if (cpu != this_cpu) { - printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n", - this_cpu, cpu); - BUG(); - } -#endif - /* * we're ready for shutdown now, so do it */ diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c index 7a4890b96e5ce..dd8037ebccf8b 100644 --- a/arch/arm/mach-ux500/hotplug.c +++ b/arch/arm/mach-ux500/hotplug.c @@ -45,16 +45,6 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { -#ifdef DEBUG - unsigned int this_cpu = hard_smp_processor_id(); - - if (cpu != this_cpu) { - printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n", - this_cpu, cpu); - BUG(); - } -#endif - /* directly enter low power state, skipping secure registers */ platform_do_lowpower(cpu); } From f36d340122ae8744e64af0a92a6f77b97542c0a4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 30 Nov 2010 12:21:30 +0000 Subject: [PATCH 31/52] ARM: CPU hotplug: ensure correct ordering of unplug Don't call idle_task_exit() with interrupts disabled, and ensure that we have a memory barrier after interrupts are disabled but before signalling that this CPU has shut down. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 8c81ff9b3732d..1a1c5e2b3ef93 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -269,9 +269,11 @@ void __ref cpu_die(void) { unsigned int cpu = smp_processor_id(); - local_irq_disable(); idle_task_exit(); + local_irq_disable(); + mb(); + /* Tell __cpu_die() that this CPU is now safe to dispose of */ complete(&cpu_died); From 86e62b93368cffca9111996e3ed9e5b7bf6f0af3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 30 Nov 2010 18:24:57 +0000 Subject: [PATCH 32/52] ARM: SMP: remove smp_mpidr.h With "ARM: CPU hotplug: remove bug checks in platform_cpu_die()", we now do not use hard_smp_processor_id(), we no longer need to read the hardware processor ID. Remove the include providing this function. Signed-off-by: Russell King --- arch/arm/include/asm/smp_mpidr.h | 17 ----------------- arch/arm/mach-realview/include/mach/smp.h | 1 - arch/arm/mach-s5pv310/include/mach/smp.h | 1 - arch/arm/mach-tegra/include/mach/smp.h | 1 - arch/arm/mach-ux500/include/mach/smp.h | 1 - arch/arm/mach-vexpress/include/mach/smp.h | 1 - arch/arm/plat-omap/include/plat/smp.h | 1 - 7 files changed, 23 deletions(-) delete mode 100644 arch/arm/include/asm/smp_mpidr.h diff --git a/arch/arm/include/asm/smp_mpidr.h b/arch/arm/include/asm/smp_mpidr.h deleted file mode 100644 index 6a9307d649003..0000000000000 --- a/arch/arm/include/asm/smp_mpidr.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ASMARM_SMP_MIDR_H -#define ASMARM_SMP_MIDR_H - -#define hard_smp_processor_id() \ - ({ \ - unsigned int cpunum; \ - __asm__("\n" \ - "1: mrc p15, 0, %0, c0, c0, 5\n" \ - " .pushsection \".alt.smp.init\", \"a\"\n"\ - " .long 1b\n" \ - " mov %0, #0\n" \ - " .popsection" \ - : "=r" (cpunum)); \ - cpunum &= 0x0F; \ - }) - -#endif diff --git a/arch/arm/mach-realview/include/mach/smp.h b/arch/arm/mach-realview/include/mach/smp.h index d1aa70415a4e1..c8221b38ee7c3 100644 --- a/arch/arm/mach-realview/include/mach/smp.h +++ b/arch/arm/mach-realview/include/mach/smp.h @@ -2,7 +2,6 @@ #define ASMARM_ARCH_SMP_H #include -#include /* * We use IRQ1 as the IPI diff --git a/arch/arm/mach-s5pv310/include/mach/smp.h b/arch/arm/mach-s5pv310/include/mach/smp.h index 2897747bcb07b..77e5a841f7414 100644 --- a/arch/arm/mach-s5pv310/include/mach/smp.h +++ b/arch/arm/mach-s5pv310/include/mach/smp.h @@ -7,7 +7,6 @@ #define ASM_ARCH_SMP_H __FILE__ #include -#include extern void __iomem *gic_cpu_base_addr; diff --git a/arch/arm/mach-tegra/include/mach/smp.h b/arch/arm/mach-tegra/include/mach/smp.h index d1aa70415a4e1..c8221b38ee7c3 100644 --- a/arch/arm/mach-tegra/include/mach/smp.h +++ b/arch/arm/mach-tegra/include/mach/smp.h @@ -2,7 +2,6 @@ #define ASMARM_ARCH_SMP_H #include -#include /* * We use IRQ1 as the IPI diff --git a/arch/arm/mach-ux500/include/mach/smp.h b/arch/arm/mach-ux500/include/mach/smp.h index bd57c50a5b860..ca2b15b1b3b18 100644 --- a/arch/arm/mach-ux500/include/mach/smp.h +++ b/arch/arm/mach-ux500/include/mach/smp.h @@ -10,7 +10,6 @@ #define ASMARM_ARCH_SMP_H #include -#include /* This is required to wakeup the secondary core */ extern void u8500_secondary_startup(void); diff --git a/arch/arm/mach-vexpress/include/mach/smp.h b/arch/arm/mach-vexpress/include/mach/smp.h index 721be0f0311da..4c05e4a9713a3 100644 --- a/arch/arm/mach-vexpress/include/mach/smp.h +++ b/arch/arm/mach-vexpress/include/mach/smp.h @@ -2,7 +2,6 @@ #define __MACH_SMP_H #include -#include /* * We use IRQ1 as the IPI diff --git a/arch/arm/plat-omap/include/plat/smp.h b/arch/arm/plat-omap/include/plat/smp.h index e5541e5388be6..7a10257909efa 100644 --- a/arch/arm/plat-omap/include/plat/smp.h +++ b/arch/arm/plat-omap/include/plat/smp.h @@ -18,7 +18,6 @@ #define OMAP_ARCH_SMP_H #include -#include /* Needed for secondary core boot */ extern void omap_secondary_startup(void); From ed3768a8d9dc2d345d4f27eb44ee1e4825056c08 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Wed, 1 Dec 2010 15:39:23 +0100 Subject: [PATCH 33/52] ARM: 6516/1: Allow SMP_ON_UP to work with Thumb-2 kernels. * __fixup_smp_on_up has been modified with support for the THUMB2_KERNEL case. For THUMB2_KERNEL only, fixups are split into halfwords in case of misalignment, since we can't rely on unaligned accesses working before turning the MMU on. No attempt is made to optimise the aligned case, since the number of fixups is typically small, and it seems best to keep the code as simple as possible. * Add a rotate in the fixup_smp code in order to support CPU_BIG_ENDIAN, as suggested by Nicolas Pitre. * Add an assembly-time sanity-check to ALT_UP() to ensure that the content really is the right size (4 bytes). (No check is done for ALT_SMP(). Possibly, this could be fixed by splitting the two uses ot ALT_SMP() (ALT_SMP...SMP_UP versus ALT_SMP...SMP_UP_B) into two macros. In the first case, ALT_SMP needs to expand to >= 4 bytes, not == 4.) * smp_mpidr.h (which implements ALT_SMP()/ALT_UP() manually due to macro limitations) has not been modified: the affected instruction (mov) has no 16-bit encoding, so the correct instruction size is satisfied in this case. * A "mode" parameter has been added to smp_dmb: smp_dmb arm @ assumes 4-byte instructions (for ARM code, e.g. kuser) smp_dmb @ uses W() to ensure 4-byte instructions for ALT_SMP() This avoids assembly failures due to use of W() inside smp_dmb, when assembling pure-ARM code in the vectors page. There might be a better way to achieve this. * Kconfig: make SMP_ON_UP depend on (!THUMB2_KERNEL || !BIG_ENDIAN) i.e., THUMB2_KERNEL is now supported, but only if !BIG_ENDIAN (The fixup code for Thumb-2 currently assumes little-endian order.) Tested using a single generic realview kernel on: ARM RealView PB-A8 (CONFIG_THUMB2_KERNEL={n,y}) ARM RealView PBX-A9 (SMP) Signed-off-by: Dave Martin Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/Kconfig | 2 +- arch/arm/include/asm/assembler.h | 22 +++++++++++++++++++--- arch/arm/kernel/entry-armv.S | 4 ++-- arch/arm/kernel/head.S | 13 ++++++++++--- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index db524e75c4a21..290a4b57617f7 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1229,7 +1229,7 @@ config SMP config SMP_ON_UP bool "Allow booting SMP kernel on uniprocessor systems (EXPERIMENTAL)" depends on EXPERIMENTAL - depends on SMP && !XIP && !THUMB2_KERNEL + depends on SMP && !XIP default y help SMP kernels contain instructions which fail on non-SMP processors. diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 749bb6622404b..72d3389e9c12e 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -157,16 +157,24 @@ #ifdef CONFIG_SMP #define ALT_SMP(instr...) \ 9998: instr +/* + * Note: if you get assembler errors from ALT_UP() when building with + * CONFIG_THUMB2_KERNEL, you almost certainly need to use + * ALT_SMP( W(instr) ... ) + */ #define ALT_UP(instr...) \ .pushsection ".alt.smp.init", "a" ;\ .long 9998b ;\ - instr ;\ +9997: instr ;\ + .if . - 9997b != 4 ;\ + .error "ALT_UP() content must assemble to exactly 4 bytes";\ + .endif ;\ .popsection #define ALT_UP_B(label) \ .equ up_b_offset, label - 9998b ;\ .pushsection ".alt.smp.init", "a" ;\ .long 9998b ;\ - b . + up_b_offset ;\ + W(b) . + up_b_offset ;\ .popsection #else #define ALT_SMP(instr...) @@ -177,16 +185,24 @@ /* * SMP data memory barrier */ - .macro smp_dmb + .macro smp_dmb mode #ifdef CONFIG_SMP #if __LINUX_ARM_ARCH__ >= 7 + .ifeqs "\mode","arm" ALT_SMP(dmb) + .else + ALT_SMP(W(dmb)) + .endif #elif __LINUX_ARM_ARCH__ == 6 ALT_SMP(mcr p15, 0, r0, c7, c10, 5) @ dmb #else #error Incompatible SMP platform #endif + .ifeqs "\mode","arm" ALT_UP(nop) + .else + ALT_UP(W(nop)) + .endif #endif .endm diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 955cf5f539ed9..7f22a11a51050 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -842,7 +842,7 @@ __kuser_helper_start: */ __kuser_memory_barrier: @ 0xffff0fa0 - smp_dmb + smp_dmb arm usr_ret lr .align 5 @@ -959,7 +959,7 @@ kuser_cmpxchg_fixup: #else - smp_dmb + smp_dmb arm 1: ldrex r3, [r2] subs r3, r3, r0 strexeq r3, r1, [r2] diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index fd94e4e82fc92..359e54e83bd5c 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -412,10 +412,17 @@ __fixup_smp_on_up: add r4, r4, r3 add r5, r5, r3 2: cmp r4, r5 + movhs pc, lr ldmia r4!, {r0, r6} - strlo r6, [r0, r3] - blo 2b - mov pc, lr + ARM( str r6, [r0, r3] ) + THUMB( add r0, r0, r3 ) +#ifdef __ARMEB__ + THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian. +#endif + THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords + THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r3. + THUMB( strh r6, [r0] ) + b 2b ENDPROC(__fixup_smp) 1: .word . From 3705ff6da538aff6dba535e2e9cbcbb9456d0d53 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 18 Dec 2010 10:53:12 +0000 Subject: [PATCH 34/52] ARM: Fix subtle race in CPU pen_release hotplug code There is a subtle race in the CPU hotplug code, where a CPU which has been offlined can online itself before being requested, which results in things going astray on the next online/offline cycle. What happens in the normal online/offline/online cycle is: CPU0 CPU3 requests boot of CPU3 pen_release = 3 flush cache line checks pen_release, reads 3 starts boot pen_release = -1 ... requests CPU3 offline ... ... dies ... checks pen_release, reads -1 requests boot of CPU3 pen_release = 3 flush cache line checks pen_release, reads 3 starts boot pen_release = -1 However, as the write of -1 of pen_release is not fully flushed back to memory, and the checking of pen_release is done with caches disabled, this allows CPU3 the opportunity to read the old value of pen_release: CPU0 CPU3 requests boot of CPU3 pen_release = 3 flush cache line checks pen_release, reads 3 starts boot pen_release = -1 ... requests CPU3 offline ... ... dies ... checks pen_release, reads 3 starts boot pen_release = -1 requests boot of CPU3 pen_release = 3 flush cache line Fix this by grouping the write of pen_release along with its cache line flushing code to ensure that any update to pen_release is always pushed out to physical memory. Signed-off-by: Russell King --- arch/arm/mach-realview/platsmp.c | 19 +++++++++++++++---- arch/arm/mach-s5pv310/platsmp.c | 20 +++++++++++++++----- arch/arm/mach-ux500/platsmp.c | 22 +++++++++++++++------- arch/arm/mach-vexpress/platsmp.c | 20 +++++++++++++++----- 4 files changed, 60 insertions(+), 21 deletions(-) diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 226c63102a004..bb8d6c4e4315f 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -36,6 +36,19 @@ extern void realview_secondary_startup(void); */ volatile int __cpuinitdata pen_release = -1; +/* + * Write pen_release in a way that is guaranteed to be visible to all + * observers, irrespective of whether they're taking part in coherency + * or not. This is necessary for the hotplug code to work reliably. + */ +static void write_pen_release(int val) +{ + pen_release = val; + smp_wmb(); + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); +} + static void __iomem *scu_base_addr(void) { if (machine_is_realview_eb_mp()) @@ -64,8 +77,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * let the primary processor know we're out of the * pen, then head off into the C entry point */ - pen_release = -1; - smp_wmb(); + write_pen_release(-1); /* * Synchronise with the boot thread. @@ -92,8 +104,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * Note that "pen_release" is the hardware CPU ID, whereas * "cpu" is Linux's internal ID. */ - pen_release = cpu; - flush_cache_all(); + write_pen_release(cpu); /* * Send the secondary CPU a soft interrupt, thereby causing diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c index 18aaf5f540332..98c04748ed843 100644 --- a/arch/arm/mach-s5pv310/platsmp.c +++ b/arch/arm/mach-s5pv310/platsmp.c @@ -37,6 +37,19 @@ extern void s5pv310_secondary_startup(void); volatile int __cpuinitdata pen_release = -1; +/* + * Write pen_release in a way that is guaranteed to be visible to all + * observers, irrespective of whether they're taking part in coherency + * or not. This is necessary for the hotplug code to work reliably. + */ +static void write_pen_release(int val) +{ + pen_release = val; + smp_wmb(); + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); +} + static void __iomem *scu_base_addr(void) { return (void __iomem *)(S5P_VA_SCU); @@ -57,8 +70,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * let the primary processor know we're out of the * pen, then head off into the C entry point */ - pen_release = -1; - smp_wmb(); + write_pen_release(-1); /* * Synchronise with the boot thread. @@ -85,9 +97,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * Note that "pen_release" is the hardware CPU ID, whereas * "cpu" is Linux's internal ID. */ - pen_release = cpu; - __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); - outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + write_pen_release(cpu); /* * Send the secondary CPU a soft interrupt, thereby causing diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index ddedbc80c41ff..f71175a766d7b 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -27,6 +27,19 @@ */ volatile int __cpuinitdata pen_release = -1; +/* + * Write pen_release in a way that is guaranteed to be visible to all + * observers, irrespective of whether they're taking part in coherency + * or not. This is necessary for the hotplug code to work reliably. + */ +static void write_pen_release(int val) +{ + pen_release = val; + smp_wmb(); + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); +} + static DEFINE_SPINLOCK(boot_lock); void __cpuinit platform_secondary_init(unsigned int cpu) @@ -42,7 +55,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * let the primary processor know we're out of the * pen, then head off into the C entry point */ - pen_release = -1; + write_pen_release(-1); /* * Synchronise with the boot thread. @@ -66,9 +79,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * the holding pen - release it, then wait for it to flag * that it has been released by resetting pen_release. */ - pen_release = cpu; - __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); - outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1); + write_pen_release(cpu); smp_cross_call(cpumask_of(cpu), 1); @@ -89,9 +100,6 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) static void __init wakeup_secondary(void) { - /* nobody is to be released from the pen yet */ - pen_release = -1; - /* * write the address of secondary startup into the backup ram register * at offset 0x1FF4, then write the magic number 0xA1FEED01 to the diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index d7e0cb994e9df..8ce9fef29555b 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -34,6 +34,19 @@ extern void vexpress_secondary_startup(void); */ volatile int __cpuinitdata pen_release = -1; +/* + * Write pen_release in a way that is guaranteed to be visible to all + * observers, irrespective of whether they're taking part in coherency + * or not. This is necessary for the hotplug code to work reliably. + */ +static void write_pen_release(int val) +{ + pen_release = val; + smp_wmb(); + __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); + outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); +} + static void __iomem *scu_base_addr(void) { return MMIO_P2V(A9_MPCORE_SCU); @@ -54,8 +67,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * let the primary processor know we're out of the * pen, then head off into the C entry point */ - pen_release = -1; - smp_wmb(); + write_pen_release(-1); /* * Synchronise with the boot thread. @@ -80,9 +92,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) * since we haven't sent them a soft interrupt, they shouldn't * be there. */ - pen_release = cpu; - __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release)); - outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1)); + write_pen_release(cpu); /* * Send the secondary CPU a soft interrupt, thereby causing From 90b44199e83ec780d6def11a602d825dc68438e3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 18 Dec 2010 10:59:49 +0000 Subject: [PATCH 35/52] ARM: VFP: re-initialize VFP coprocessor access enables on CPU hotplug We can not guarantee that VFP will be enabled when CPU hotplug brings a CPU back online from a reset state. Add a hotplug CPU notifier to ensure that the VFP coprocessor access is enabled whenever a CPU comes back online. Signed-off-by: Russell King --- arch/arm/vfp/vfpmodule.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 8063a322c790d..0797cb528b463 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -10,9 +10,12 @@ */ #include #include +#include #include +#include #include #include +#include #include #include @@ -484,7 +487,24 @@ void vfp_flush_hwstate(struct thread_info *thread) put_cpu(); } -#include +/* + * VFP hardware can lose all context when a CPU goes offline. + * Safely clear our held state when a CPU has been killed, and + * re-enable access to VFP when the CPU comes back online. + * + * Both CPU_DYING and CPU_STARTING are called on the CPU which + * is being offlined/onlined. + */ +static int vfp_hotplug(struct notifier_block *b, unsigned long action, + void *hcpu) +{ + if (action == CPU_DYING || action == CPU_DYING_FROZEN) { + unsigned int cpu = (long)hcpu; + last_VFP_context[cpu] = NULL; + } else if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) + vfp_enable(NULL); + return NOTIFY_OK; +} /* * VFP support code initialisation. @@ -514,6 +534,8 @@ static int __init vfp_init(void) else if (vfpsid & FPSID_NODOUBLE) { printk("no double precision support\n"); } else { + hotcpu_notifier(vfp_hotplug, 0); + smp_call_function(vfp_enable, NULL, 1); VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */ From 58613cd1d4f8c2d5f25b6c57ad7fbed80e75a67b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 18 Dec 2010 12:34:39 +0000 Subject: [PATCH 36/52] ARM: smp: improve CPU bringup failure diagnostics We used to print a bland error message which gave no clue as to the failure when we failed to bring up a secondary CPU. Resolve this by separating the two failure cases. If boot_secondary() fails, we print a message indicating the returned error code from boot_secondary(): "CPU%u: failed to boot: %d\n", cpu, ret. However, if boot_secondary() succeeded, but the CPU did not appear to mark itself online within the timeout, indicate that it failed to come online: "CPU%u: failed to come online\n", cpu Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 1a1c5e2b3ef93..6afaf6f730690 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -164,8 +164,12 @@ int __cpuinit __cpu_up(unsigned int cpu) barrier(); } - if (!cpu_online(cpu)) + if (!cpu_online(cpu)) { + pr_crit("CPU%u: failed to come online\n", cpu); ret = -EIO; + } + } else { + pr_err("CPU%u: failed to boot: %d\n", cpu, ret); } secondary_data.stack = NULL; @@ -181,14 +185,6 @@ int __cpuinit __cpu_up(unsigned int cpu) pgd_free(&init_mm, pgd); - if (ret) { - printk(KERN_CRIT "CPU%u: processor failed to boot\n", cpu); - - /* - * FIXME: We need to clean up the new idle thread. --rmk - */ - } - return ret; } From d4450261e546953c4a1ce8b48e29164a57c6ed33 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 19 Dec 2010 11:30:43 +0000 Subject: [PATCH 37/52] ARM: CPU hotplug: fix reporting of spurious wakeups The original scheme for reporting spurious wakeups was broken - it tried to use printk() from a context which wasn't coherent with the other CPUs, which risks corrupting the printk() data. Fix this by noting the number spurious wakeups, and only report them when we are properly woken - when we will be coherent with the rest of the system. Signed-off-by: Russell King --- arch/arm/mach-realview/hotplug.c | 20 +++++++++++--------- arch/arm/mach-s5pv310/hotplug.c | 20 +++++++++++--------- arch/arm/mach-tegra/hotplug.c | 20 +++++++++++--------- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c index e06572e6c4904..b6387cfe70443 100644 --- a/arch/arm/mach-realview/hotplug.c +++ b/arch/arm/mach-realview/hotplug.c @@ -53,7 +53,7 @@ static inline void cpu_leave_lowpower(void) : "cc"); } -static inline void platform_do_lowpower(unsigned int cpu) +static inline void platform_do_lowpower(unsigned int cpu, int *spurious) { /* * there is no power-control hardware on this platform, so all @@ -77,16 +77,13 @@ static inline void platform_do_lowpower(unsigned int cpu) } /* - * getting here, means that we have come out of WFI without + * Getting here, means that we have come out of WFI without * having been woken up - this shouldn't happen * - * The trouble is, letting people know about this is not really - * possible, since we are currently running incoherently, and - * therefore cannot safely call printk() or anything else + * Just note it happening - when we're woken, we can report + * its occurrence. */ -#ifdef DEBUG - printk("CPU%u: spurious wakeup call\n", cpu); -#endif + (*spurious)++; } } @@ -102,17 +99,22 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { + int spurious = 0; + /* * we're ready for shutdown now, so do it */ cpu_enter_lowpower(); - platform_do_lowpower(cpu); + platform_do_lowpower(cpu, &spurious); /* * bring this CPU back into the world of cache * coherency, and then restore interrupts */ cpu_leave_lowpower(); + + if (spurious) + pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); } int platform_cpu_disable(unsigned int cpu) diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-s5pv310/hotplug.c index ea951ef6ea544..951ba6d63d215 100644 --- a/arch/arm/mach-s5pv310/hotplug.c +++ b/arch/arm/mach-s5pv310/hotplug.c @@ -56,7 +56,7 @@ static inline void cpu_leave_lowpower(void) : "cc"); } -static inline void platform_do_lowpower(unsigned int cpu) +static inline void platform_do_lowpower(unsigned int cpu, int *spurious) { /* * there is no power-control hardware on this platform, so all @@ -80,16 +80,13 @@ static inline void platform_do_lowpower(unsigned int cpu) } /* - * getting here, means that we have come out of WFI without + * Getting here, means that we have come out of WFI without * having been woken up - this shouldn't happen * - * The trouble is, letting people know about this is not really - * possible, since we are currently running incoherently, and - * therefore cannot safely call printk() or anything else + * Just note it happening - when we're woken, we can report + * its occurrence. */ -#ifdef DEBUG - printk(KERN_WARN "CPU%u: spurious wakeup call\n", cpu); -#endif + (*spurious)++; } } @@ -105,17 +102,22 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { + int spurious = 0; + /* * we're ready for shutdown now, so do it */ cpu_enter_lowpower(); - platform_do_lowpower(cpu); + platform_do_lowpower(cpu, &spurious); /* * bring this CPU back into the world of cache * coherency, and then restore interrupts */ cpu_leave_lowpower(); + + if (spurious) + pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); } int platform_cpu_disable(unsigned int cpu) diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index a5eeb9126645d..17faf777af23a 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -52,7 +52,7 @@ static inline void cpu_leave_lowpower(void) : "cc"); } -static inline void platform_do_lowpower(unsigned int cpu) +static inline void platform_do_lowpower(unsigned int cpu, int *spurious) { /* * there is no power-control hardware on this platform, so all @@ -76,16 +76,13 @@ static inline void platform_do_lowpower(unsigned int cpu) /*}*/ /* - * getting here, means that we have come out of WFI without + * Getting here, means that we have come out of WFI without * having been woken up - this shouldn't happen * - * The trouble is, letting people know about this is not really - * possible, since we are currently running incoherently, and - * therefore cannot safely call printk() or anything else + * Just note it happening - when we're woken, we can report + * its occurrence. */ -#ifdef DEBUG - printk(KERN_WARN "CPU%u: spurious wakeup call\n", cpu); -#endif + (*spurious)++; } } @@ -101,17 +98,22 @@ int platform_cpu_kill(unsigned int cpu) */ void platform_cpu_die(unsigned int cpu) { + int spurious = 0; + /* * we're ready for shutdown now, so do it */ cpu_enter_lowpower(); - platform_do_lowpower(cpu); + platform_do_lowpower(cpu, &spurious); /* * bring this CPU back into the world of cache * coherency, and then restore interrupts */ cpu_leave_lowpower(); + + if (spurious) + pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); } int platform_cpu_disable(unsigned int cpu) From e9882777d992b76e0b80deadd66ad886c25f5d1f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 19 Dec 2010 11:33:12 +0000 Subject: [PATCH 38/52] ARM: CPU hotplug: add Versatile Express hotplug CPU support Signed-off-by: Russell King --- arch/arm/mach-vexpress/Makefile | 1 + arch/arm/mach-vexpress/hotplug.c | 128 +++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 arch/arm/mach-vexpress/hotplug.c diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile index 1b71b77ade229..2c0ac7de28142 100644 --- a/arch/arm/mach-vexpress/Makefile +++ b/arch/arm/mach-vexpress/Makefile @@ -5,4 +5,5 @@ obj-y := v2m.o obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o diff --git a/arch/arm/mach-vexpress/hotplug.c b/arch/arm/mach-vexpress/hotplug.c new file mode 100644 index 0000000000000..ea4cbfb90a667 --- /dev/null +++ b/arch/arm/mach-vexpress/hotplug.c @@ -0,0 +1,128 @@ +/* + * linux/arch/arm/mach-realview/hotplug.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * 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 + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include + +extern volatile int pen_release; + +static inline void cpu_enter_lowpower(void) +{ + unsigned int v; + + flush_cache_all(); + asm volatile( + "mcr p15, 0, %1, c7, c5, 0\n" + " mcr p15, 0, %1, c7, c10, 4\n" + /* + * Turn off coherency + */ + " mrc p15, 0, %0, c1, c0, 1\n" + " bic %0, %0, %3\n" + " mcr p15, 0, %0, c1, c0, 1\n" + " mrc p15, 0, %0, c1, c0, 0\n" + " bic %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 0\n" + : "=&r" (v) + : "r" (0), "Ir" (CR_C), "Ir" (0x40) + : "cc"); +} + +static inline void cpu_leave_lowpower(void) +{ + unsigned int v; + + asm volatile( + "mrc p15, 0, %0, c1, c0, 0\n" + " orr %0, %0, %1\n" + " mcr p15, 0, %0, c1, c0, 0\n" + " mrc p15, 0, %0, c1, c0, 1\n" + " orr %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 1\n" + : "=&r" (v) + : "Ir" (CR_C), "Ir" (0x40) + : "cc"); +} + +static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +{ + /* + * there is no power-control hardware on this platform, so all + * we can do is put the core into WFI; this is safe as the calling + * code will have already disabled interrupts + */ + for (;;) { + /* + * here's the WFI + */ + asm(".word 0xe320f003\n" + : + : + : "memory", "cc"); + + if (pen_release == cpu) { + /* + * OK, proper wakeup, we're done + */ + break; + } + + /* + * Getting here, means that we have come out of WFI without + * having been woken up - this shouldn't happen + * + * Just note it happening - when we're woken, we can report + * its occurrence. + */ + (*spurious)++; + } +} + +int platform_cpu_kill(unsigned int cpu) +{ + return 1; +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void platform_cpu_die(unsigned int cpu) +{ + int spurious = 0; + + /* + * we're ready for shutdown now, so do it + */ + cpu_enter_lowpower(); + platform_do_lowpower(cpu, &spurious); + + /* + * bring this CPU back into the world of cache + * coherency, and then restore interrupts + */ + cpu_leave_lowpower(); + + if (spurious) + pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); +} + +int platform_cpu_disable(unsigned int cpu) +{ + /* + * we don't allow CPU 0 to be shutdown (it is still too special + * e.g. clock tick interrupts) + */ + return cpu == 0 ? -EPERM : 0; +} From e3d9c625f5e4158014e041f492b46e38ad10987e Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 19 Dec 2010 11:36:33 +0000 Subject: [PATCH 39/52] ARM: CPU hotplug: fix hard-coded control register constants Use the definition we've provided in asm/system.h rather than numeric constants. Signed-off-by: Russell King --- arch/arm/mach-realview/hotplug.c | 8 ++++---- arch/arm/mach-s5pv310/hotplug.c | 8 ++++---- arch/arm/mach-tegra/hotplug.c | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c index b6387cfe70443..a87523d095e63 100644 --- a/arch/arm/mach-realview/hotplug.c +++ b/arch/arm/mach-realview/hotplug.c @@ -31,10 +31,10 @@ static inline void cpu_enter_lowpower(void) " bic %0, %0, #0x20\n" " mcr p15, 0, %0, c1, c0, 1\n" " mrc p15, 0, %0, c1, c0, 0\n" - " bic %0, %0, #0x04\n" + " bic %0, %0, %2\n" " mcr p15, 0, %0, c1, c0, 0\n" : "=&r" (v) - : "r" (0) + : "r" (0), "Ir" (CR_C) : "cc"); } @@ -43,13 +43,13 @@ static inline void cpu_leave_lowpower(void) unsigned int v; asm volatile( "mrc p15, 0, %0, c1, c0, 0\n" - " orr %0, %0, #0x04\n" + " orr %0, %0, %1\n" " mcr p15, 0, %0, c1, c0, 0\n" " mrc p15, 0, %0, c1, c0, 1\n" " orr %0, %0, #0x20\n" " mcr p15, 0, %0, c1, c0, 1\n" : "=&r" (v) - : + : "Ir" (CR_C) : "cc"); } diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-s5pv310/hotplug.c index 951ba6d63d215..afa5392d9fc0e 100644 --- a/arch/arm/mach-s5pv310/hotplug.c +++ b/arch/arm/mach-s5pv310/hotplug.c @@ -30,13 +30,13 @@ static inline void cpu_enter_lowpower(void) * Turn off coherency */ " mrc p15, 0, %0, c1, c0, 1\n" - " bic %0, %0, #0x20\n" + " bic %0, %0, %2\n" " mcr p15, 0, %0, c1, c0, 1\n" " mrc p15, 0, %0, c1, c0, 0\n" " bic %0, %0, #0x04\n" " mcr p15, 0, %0, c1, c0, 0\n" : "=&r" (v) - : "r" (0) + : "r" (0), "Ir" (CR_C) : "cc"); } @@ -46,13 +46,13 @@ static inline void cpu_leave_lowpower(void) asm volatile( "mrc p15, 0, %0, c1, c0, 0\n" - " orr %0, %0, #0x04\n" + " orr %0, %0, %1\n" " mcr p15, 0, %0, c1, c0, 0\n" " mrc p15, 0, %0, c1, c0, 1\n" " orr %0, %0, #0x20\n" " mcr p15, 0, %0, c1, c0, 1\n" : "=&r" (v) - : + : "Ir" (CR_C) : "cc"); } diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index 17faf777af23a..a5cb1ce76ff2a 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -26,13 +26,13 @@ static inline void cpu_enter_lowpower(void) * Turn off coherency */ " mrc p15, 0, %0, c1, c0, 1\n" - " bic %0, %0, #0x20\n" + " bic %0, %0, %2\n" " mcr p15, 0, %0, c1, c0, 1\n" " mrc p15, 0, %0, c1, c0, 0\n" " bic %0, %0, #0x04\n" " mcr p15, 0, %0, c1, c0, 0\n" : "=&r" (v) - : "r" (0) + : "r" (0), "Ir" (CR_C) : "cc"); } @@ -42,13 +42,13 @@ static inline void cpu_leave_lowpower(void) asm volatile( "mrc p15, 0, %0, c1, c0, 0\n" - " orr %0, %0, #0x04\n" + " orr %0, %0, %1\n" " mcr p15, 0, %0, c1, c0, 0\n" " mrc p15, 0, %0, c1, c0, 1\n" " orr %0, %0, #0x20\n" " mcr p15, 0, %0, c1, c0, 1\n" : "=&r" (v) - : + : "Ir" (CR_C) : "cc"); } From 10034aabca9032246762daaca3152f3e79380ea0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Dec 2010 14:28:02 +0000 Subject: [PATCH 40/52] ARM: localtimer: clean up local timer on hot unplug When a CPU is hot unplugged, the generic tick code cleans up the clock event device, but fails to call down to the device's set_mode function to actually shut the device down. To work around this, we've historically had a local_timer_stop() callback out of the hotplug code. However, this adds needless complexity when we have the clock event device itself available. Explicitly call the clock event device's set_mode function with CLOCK_EVT_MODE_UNUSED, so that the hardware can be cleanly shutdown without any special external callbacks. When/if the generic code is fixed, percpu_timer_stop() can be killed off. Signed-off-by: Russell King --- arch/arm/include/asm/localtimer.h | 12 ------------ arch/arm/include/asm/smp_twd.h | 1 - arch/arm/kernel/smp.c | 19 ++++++++++++++++++- arch/arm/kernel/smp_twd.c | 10 ---------- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h index 50c7e7cfd6707..6bc63ab498ce4 100644 --- a/arch/arm/include/asm/localtimer.h +++ b/arch/arm/include/asm/localtimer.h @@ -30,7 +30,6 @@ asmlinkage void do_local_timer(struct pt_regs *); #include "smp_twd.h" #define local_timer_ack() twd_timer_ack() -#define local_timer_stop() twd_timer_stop() #else @@ -40,11 +39,6 @@ asmlinkage void do_local_timer(struct pt_regs *); */ int local_timer_ack(void); -/* - * Stop a local timer interrupt. - */ -void local_timer_stop(void); - #endif /* @@ -52,12 +46,6 @@ void local_timer_stop(void); */ void local_timer_setup(struct clock_event_device *); -#else - -static inline void local_timer_stop(void) -{ -} - #endif #endif diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h index 634f357be6bb7..fed9981fba08f 100644 --- a/arch/arm/include/asm/smp_twd.h +++ b/arch/arm/include/asm/smp_twd.h @@ -22,7 +22,6 @@ struct clock_event_device; extern void __iomem *twd_base; -void twd_timer_stop(void); int twd_timer_ack(void); void twd_timer_setup(struct clock_event_device *); diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 6afaf6f730690..4dc864ef9cdf8 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -189,6 +189,8 @@ int __cpuinit __cpu_up(unsigned int cpu) } #ifdef CONFIG_HOTPLUG_CPU +static void percpu_timer_stop(void); + /* * __cpu_disable runs on the processor to be shutdown. */ @@ -216,7 +218,7 @@ int __cpu_disable(void) /* * Stop the local timer for this CPU. */ - local_timer_stop(); + percpu_timer_stop(); /* * Flush user cache and TLB mappings, and then remove this CPU @@ -539,6 +541,21 @@ void __cpuinit percpu_timer_setup(void) local_timer_setup(evt); } +#ifdef CONFIG_HOTPLUG_CPU +/* + * The generic clock events code purposely does not stop the local timer + * on CPU_DEAD/CPU_DEAD_FROZEN hotplug events, so we have to do it + * manually here. + */ +static void percpu_timer_stop(void) +{ + unsigned int cpu = smp_processor_id(); + struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); + + evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); +} +#endif + static DEFINE_SPINLOCK(stop_lock); /* diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 35882fbf37f90..24585d97c1048 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -150,13 +150,3 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk) clockevents_register_device(clk); } - -#ifdef CONFIG_HOTPLUG_CPU -/* - * take a local timer down - */ -void twd_timer_stop(void) -{ - __raw_writel(0, twd_base + TWD_TIMER_CONTROL); -} -#endif From 03b505eae6a276b8c38b6222694afb6cea10b1cc Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Dec 2010 14:44:32 +0000 Subject: [PATCH 41/52] ARM: SMP: split out software TLB maintainence broadcasting smp.c is becoming too large, so split out the TLB maintainence broadcasting into a separate smp_tlb.c file. Signed-off-by: Russell King --- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/smp.c | 126 ---------------------------------- arch/arm/kernel/smp_tlb.c | 139 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 127 deletions(-) create mode 100644 arch/arm/kernel/smp_tlb.c diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5b9b268f4fbb3..659937b0a8964 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -29,7 +29,7 @@ obj-$(CONFIG_MODULES) += armksyms.o module.o obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o -obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_SMP) += smp.o smp_tlb.o obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 4dc864ef9cdf8..6d0c66bc434d4 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -38,7 +38,6 @@ #include #include #include -#include /* * as from 2.5, kernels no longer have an init_tasks structure @@ -655,128 +654,3 @@ int setup_profiling_timer(unsigned int multiplier) { return -EINVAL; } - -static void -on_each_cpu_mask(void (*func)(void *), void *info, int wait, - const struct cpumask *mask) -{ - preempt_disable(); - - smp_call_function_many(mask, func, info, wait); - if (cpumask_test_cpu(smp_processor_id(), mask)) - func(info); - - preempt_enable(); -} - -/**********************************************************************/ - -/* - * TLB operations - */ -struct tlb_args { - struct vm_area_struct *ta_vma; - unsigned long ta_start; - unsigned long ta_end; -}; - -static inline void ipi_flush_tlb_all(void *ignored) -{ - local_flush_tlb_all(); -} - -static inline void ipi_flush_tlb_mm(void *arg) -{ - struct mm_struct *mm = (struct mm_struct *)arg; - - local_flush_tlb_mm(mm); -} - -static inline void ipi_flush_tlb_page(void *arg) -{ - struct tlb_args *ta = (struct tlb_args *)arg; - - local_flush_tlb_page(ta->ta_vma, ta->ta_start); -} - -static inline void ipi_flush_tlb_kernel_page(void *arg) -{ - struct tlb_args *ta = (struct tlb_args *)arg; - - local_flush_tlb_kernel_page(ta->ta_start); -} - -static inline void ipi_flush_tlb_range(void *arg) -{ - struct tlb_args *ta = (struct tlb_args *)arg; - - local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); -} - -static inline void ipi_flush_tlb_kernel_range(void *arg) -{ - struct tlb_args *ta = (struct tlb_args *)arg; - - local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end); -} - -void flush_tlb_all(void) -{ - if (tlb_ops_need_broadcast()) - on_each_cpu(ipi_flush_tlb_all, NULL, 1); - else - local_flush_tlb_all(); -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - if (tlb_ops_need_broadcast()) - on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm)); - else - local_flush_tlb_mm(mm); -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) -{ - if (tlb_ops_need_broadcast()) { - struct tlb_args ta; - ta.ta_vma = vma; - ta.ta_start = uaddr; - on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm)); - } else - local_flush_tlb_page(vma, uaddr); -} - -void flush_tlb_kernel_page(unsigned long kaddr) -{ - if (tlb_ops_need_broadcast()) { - struct tlb_args ta; - ta.ta_start = kaddr; - on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); - } else - local_flush_tlb_kernel_page(kaddr); -} - -void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - if (tlb_ops_need_broadcast()) { - struct tlb_args ta; - ta.ta_vma = vma; - ta.ta_start = start; - ta.ta_end = end; - on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm)); - } else - local_flush_tlb_range(vma, start, end); -} - -void flush_tlb_kernel_range(unsigned long start, unsigned long end) -{ - if (tlb_ops_need_broadcast()) { - struct tlb_args ta; - ta.ta_start = start; - ta.ta_end = end; - on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); - } else - local_flush_tlb_kernel_range(start, end); -} diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c new file mode 100644 index 0000000000000..7dcb35285be7b --- /dev/null +++ b/arch/arm/kernel/smp_tlb.c @@ -0,0 +1,139 @@ +/* + * linux/arch/arm/kernel/smp_tlb.c + * + * Copyright (C) 2002 ARM Limited, All Rights Reserved. + * + * 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 + * published by the Free Software Foundation. + */ +#include +#include + +#include +#include + +static void on_each_cpu_mask(void (*func)(void *), void *info, int wait, + const struct cpumask *mask) +{ + preempt_disable(); + + smp_call_function_many(mask, func, info, wait); + if (cpumask_test_cpu(smp_processor_id(), mask)) + func(info); + + preempt_enable(); +} + +/**********************************************************************/ + +/* + * TLB operations + */ +struct tlb_args { + struct vm_area_struct *ta_vma; + unsigned long ta_start; + unsigned long ta_end; +}; + +static inline void ipi_flush_tlb_all(void *ignored) +{ + local_flush_tlb_all(); +} + +static inline void ipi_flush_tlb_mm(void *arg) +{ + struct mm_struct *mm = (struct mm_struct *)arg; + + local_flush_tlb_mm(mm); +} + +static inline void ipi_flush_tlb_page(void *arg) +{ + struct tlb_args *ta = (struct tlb_args *)arg; + + local_flush_tlb_page(ta->ta_vma, ta->ta_start); +} + +static inline void ipi_flush_tlb_kernel_page(void *arg) +{ + struct tlb_args *ta = (struct tlb_args *)arg; + + local_flush_tlb_kernel_page(ta->ta_start); +} + +static inline void ipi_flush_tlb_range(void *arg) +{ + struct tlb_args *ta = (struct tlb_args *)arg; + + local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end); +} + +static inline void ipi_flush_tlb_kernel_range(void *arg) +{ + struct tlb_args *ta = (struct tlb_args *)arg; + + local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end); +} + +void flush_tlb_all(void) +{ + if (tlb_ops_need_broadcast()) + on_each_cpu(ipi_flush_tlb_all, NULL, 1); + else + local_flush_tlb_all(); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + if (tlb_ops_need_broadcast()) + on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm)); + else + local_flush_tlb_mm(mm); +} + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) +{ + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_vma = vma; + ta.ta_start = uaddr; + on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm)); + } else + local_flush_tlb_page(vma, uaddr); +} + +void flush_tlb_kernel_page(unsigned long kaddr) +{ + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_start = kaddr; + on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); + } else + local_flush_tlb_kernel_page(kaddr); +} + +void flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_vma = vma; + ta.ta_start = start; + ta.ta_end = end; + on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm)); + } else + local_flush_tlb_range(vma, start, end); +} + +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + if (tlb_ops_need_broadcast()) { + struct tlb_args ta; + ta.ta_start = start; + ta.ta_end = end; + on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); + } else + local_flush_tlb_kernel_range(start, end); +} + From faabfa0816916b0a7cfc93f6a9be382830658c80 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Dec 2010 16:58:19 +0000 Subject: [PATCH 42/52] ARM: SMP: ensure frame pointer is reinitialized for soft-CPU hotplug When we soft-CPU hotplug a CPU, we reset the stack pointer and jump back to start_secondary(). This allows us to restart as if the CPU was actually reset. However, we weren't resetting the frame pointer, which could cause problems with backtracing. Reset the frame pointer to zero (which means no parent frame) just like the early assembly code also does. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 6d0c66bc434d4..5341b0b197014 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -286,6 +286,7 @@ void __ref cpu_die(void) * to be repeated to undo the effects of taking the CPU offline. */ __asm__("mov sp, %0\n" + " mov fp, #0\n" " b secondary_start_kernel" : : "r" (task_stack_page(current) + THREAD_SIZE - 8)); From 521086412ee423fbdfc7da81f257239c43f707b4 Mon Sep 17 00:00:00 2001 From: eric miao Date: Mon, 13 Dec 2010 09:42:34 +0100 Subject: [PATCH 43/52] ARM: 6532/1: Allow machine to specify it's own IRQ handlers at run-time Normally different ARM platform has different way to decode the IRQ hardware status and demultiplex to the corresponding IRQ handler. This is highly optimized by macro irq_handler in entry-armv.S, and each machine defines their own macro to decode the IRQ number. However, this prevents multiple machine classes to be built into a single kernel. By allowing each machine to specify thier own handler, and making function pointer 'handle_arch_irq' to point to it at run time, this can be solved. And introduce CONFIG_MULTI_IRQ_HANDLER to allow both solutions to work. Comparing with the highly optimized macro of irq_handler, the new function must be written with care not to lose too much performance. And the IPI stuff on SMP is expected to move to the provided arch IRQ handler as well. The assembly code to invoke handle_arch_irq is optimized by Russell King. Signed-off-by: Eric Miao Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/Kconfig | 5 +++++ arch/arm/include/asm/mach/arch.h | 3 +++ arch/arm/include/asm/mach/irq.h | 4 ++++ arch/arm/kernel/entry-armv.S | 17 +++++++++++++++-- arch/arm/kernel/setup.c | 3 +++ 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index fd0e21be5e440..47694865018c4 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1022,6 +1022,11 @@ config CPU_HAS_PMU default y bool +config MULTI_IRQ_HANDLER + bool + help + Allow each machine to specify it's own IRQ handler at run time. + if !MMU source "arch/arm/Kconfig-nommu" endif diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index d97a964207fa1..7d55356110d48 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -40,6 +40,9 @@ struct machine_desc { void (*init_irq)(void); struct sys_timer *timer; /* system tick timer */ void (*init_machine)(void); +#ifdef CONFIG_MULTI_IRQ_HANDLER + void (*handle_irq)(struct pt_regs *); +#endif }; /* diff --git a/arch/arm/include/asm/mach/irq.h b/arch/arm/include/asm/mach/irq.h index ce3eee9fe26cb..6ecdad9a5c42a 100644 --- a/arch/arm/include/asm/mach/irq.h +++ b/arch/arm/include/asm/mach/irq.h @@ -22,6 +22,10 @@ extern void (*init_arch_irq)(void); extern void init_FIQ(void); extern int show_fiq_list(struct seq_file *, void *); +#ifdef CONFIG_MULTI_IRQ_HANDLER +extern void (*handle_arch_irq)(struct pt_regs *); +#endif + /* * This is for easy migration, but should be changed in the source */ diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 35f3f20d67318..caa6c396ec784 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -30,6 +30,14 @@ * Interrupt handling. Preserves r7, r8, r9 */ .macro irq_handler +#ifdef CONFIG_MULTI_IRQ_HANDLER + ldr r5, =handle_arch_irq + mov r0, sp + ldr r5, [r5] + adr lr, BSYM(9997f) + teq r5, #0 + movne pc, r5 +#endif get_irqnr_preamble r5, lr 1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp @@ -58,9 +66,8 @@ adrne lr, BSYM(1b) bne do_local_timer #endif -9997: #endif - +9997: .endm #ifdef CONFIG_KPROBES @@ -1245,3 +1252,9 @@ cr_alignment: .space 4 cr_no_alignment: .space 4 + +#ifdef CONFIG_MULTI_IRQ_HANDLER + .globl handle_arch_irq +handle_arch_irq: + .space 4 +#endif diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 8075e592f902f..0826f36330c46 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -875,6 +875,9 @@ void __init setup_arch(char **cmdline_p) init_arch_irq = mdesc->init_irq; system_timer = mdesc->timer; init_machine = mdesc->init_machine; +#ifdef CONFIG_MULTI_IRQ_HANDLER + handle_arch_irq = mdesc->handle_irq; +#endif #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) From cd544ce754ac2432ffcc0626ea802d2b30876b50 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Wed, 22 Dec 2010 13:20:08 +0100 Subject: [PATCH 44/52] ARM: 6538/1: Subarch IRQ handler macros V3 Per subarch interrupt handler macros V3. This patch breaks out code from the irq_handler macro into arch_irq_handler and arch_irq_handler_default. The macros are put in the header file "entry-macro-multi.S" The arch_irq_handler_default macro is designed to be used by irq_handler in entry-armv.S while arch_irq_handler is suitable for per-subarch use. Signed-off-by: Magnus Damm Signed-off-by: Russell King --- arch/arm/include/asm/entry-macro-multi.S | 44 ++++++++++++++++++++++++ arch/arm/kernel/entry-armv.S | 31 ++--------------- 2 files changed, 46 insertions(+), 29 deletions(-) create mode 100644 arch/arm/include/asm/entry-macro-multi.S diff --git a/arch/arm/include/asm/entry-macro-multi.S b/arch/arm/include/asm/entry-macro-multi.S new file mode 100644 index 0000000000000..44f21d4584e88 --- /dev/null +++ b/arch/arm/include/asm/entry-macro-multi.S @@ -0,0 +1,44 @@ +/* + * Interrupt handling. Preserves r7, r8, r9 + */ + .macro arch_irq_handler_default + get_irqnr_preamble r5, lr +1: get_irqnr_and_base r0, r6, r5, lr + movne r1, sp + @ + @ routine called with r0 = irq number, r1 = struct pt_regs * + @ + adrne lr, BSYM(1b) + bne asm_do_IRQ + +#ifdef CONFIG_SMP + /* + * XXX + * + * this macro assumes that irqstat (r6) and base (r5) are + * preserved from get_irqnr_and_base above + */ + ALT_SMP(test_for_ipi r0, r6, r5, lr) + ALT_UP_B(9997f) + movne r0, sp + adrne lr, BSYM(1b) + bne do_IPI + +#ifdef CONFIG_LOCAL_TIMERS + test_for_ltirq r0, r6, r5, lr + movne r0, sp + adrne lr, BSYM(1b) + bne do_local_timer +#endif +#endif +9997: + .endm + + .macro arch_irq_handler, symbol_name + .align 5 + .global \symbol_name +\symbol_name: + mov r4, lr + arch_irq_handler_default + mov pc, r4 + .endm diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index caa6c396ec784..a866dce611d0c 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -25,6 +25,7 @@ #include #include "entry-header.S" +#include /* * Interrupt handling. Preserves r7, r8, r9 @@ -38,35 +39,7 @@ teq r5, #0 movne pc, r5 #endif - get_irqnr_preamble r5, lr -1: get_irqnr_and_base r0, r6, r5, lr - movne r1, sp - @ - @ routine called with r0 = irq number, r1 = struct pt_regs * - @ - adrne lr, BSYM(1b) - bne asm_do_IRQ - -#ifdef CONFIG_SMP - /* - * XXX - * - * this macro assumes that irqstat (r6) and base (r5) are - * preserved from get_irqnr_and_base above - */ - ALT_SMP(test_for_ipi r0, r6, r5, lr) - ALT_UP_B(9997f) - movne r0, sp - adrne lr, BSYM(1b) - bne do_IPI - -#ifdef CONFIG_LOCAL_TIMERS - test_for_ltirq r0, r6, r5, lr - movne r0, sp - adrne lr, BSYM(1b) - bne do_local_timer -#endif -#endif + arch_irq_handler_default 9997: .endm From 8ff1443c5439ecee7472b80cf12ecfc337e6ee98 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 20 Dec 2010 10:18:36 +0000 Subject: [PATCH 45/52] ARM: simplify early machine init hooks Rather than storing each machine init hook separately, store a pointer to the machine description record and dereference this instead. This pointer is only available while the init sections are present, which is not a problem as we only use it from init code. Signed-off-by: Russell King --- arch/arm/include/asm/mach/arch.h | 5 +++++ arch/arm/include/asm/mach/irq.h | 2 -- arch/arm/include/asm/mach/time.h | 1 - arch/arm/kernel/irq.c | 7 +++---- arch/arm/kernel/setup.c | 15 ++++----------- arch/arm/kernel/time.c | 4 +++- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 7d55356110d48..69908ddbaf183 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -45,6 +45,11 @@ struct machine_desc { #endif }; +/* + * Current machine - only accessible during boot. + */ +extern struct machine_desc *machine_desc; + /* * Set of macros to define architecture features. This is built into * a table by the linker. diff --git a/arch/arm/include/asm/mach/irq.h b/arch/arm/include/asm/mach/irq.h index 6ecdad9a5c42a..831e81453f81d 100644 --- a/arch/arm/include/asm/mach/irq.h +++ b/arch/arm/include/asm/mach/irq.h @@ -17,8 +17,6 @@ struct seq_file; /* * This is internal. Do not use it. */ -extern unsigned int arch_nr_irqs; -extern void (*init_arch_irq)(void); extern void init_FIQ(void); extern int show_fiq_list(struct seq_file *, void *); diff --git a/arch/arm/include/asm/mach/time.h b/arch/arm/include/asm/mach/time.h index 35d408f6dccfb..883f6be5117a7 100644 --- a/arch/arm/include/asm/mach/time.h +++ b/arch/arm/include/asm/mach/time.h @@ -43,7 +43,6 @@ struct sys_timer { #endif }; -extern struct sys_timer *system_timer; extern void timer_tick(void); #endif diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 36ad3be4692a2..a591971dbf7b7 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -47,8 +48,6 @@ #define irq_finish(irq) do { } while (0) #endif -unsigned int arch_nr_irqs; -void (*init_arch_irq)(void) __initdata = NULL; unsigned long irq_err_count; int show_interrupts(struct seq_file *p, void *v) @@ -154,13 +153,13 @@ void set_irq_flags(unsigned int irq, unsigned int iflags) void __init init_IRQ(void) { - init_arch_irq(); + machine_desc->init_irq(); } #ifdef CONFIG_SPARSE_IRQ int __init arch_probe_nr_irqs(void) { - nr_irqs = arch_nr_irqs ? arch_nr_irqs : NR_IRQS; + nr_irqs = machine_desc->nr_irqs ? machine_desc->nr_irqs : NR_IRQS; return nr_irqs; } #endif diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 0826f36330c46..e53132eee27aa 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -126,6 +126,7 @@ EXPORT_SYMBOL(elf_platform); static const char *cpu_name; static const char *machine_name; static char __initdata cmd_line[COMMAND_LINE_SIZE]; +struct machine_desc *machine_desc __initdata; static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; @@ -708,13 +709,11 @@ static struct init_tags { { 0, ATAG_NONE } }; -static void (*init_machine)(void) __initdata; - static int __init customize_machine(void) { /* customizes platform devices, or adds new ones */ - if (init_machine) - init_machine(); + if (machine_desc->init_machine) + machine_desc->init_machine(); return 0; } arch_initcall(customize_machine); @@ -809,6 +808,7 @@ void __init setup_arch(char **cmdline_p) setup_processor(); mdesc = setup_machine(machine_arch_type); + machine_desc = mdesc; machine_name = mdesc->name; if (mdesc->soft_reboot) @@ -868,13 +868,6 @@ void __init setup_arch(char **cmdline_p) cpu_init(); tcm_init(); - /* - * Set up various architecture-specific pointers - */ - arch_nr_irqs = mdesc->nr_irqs; - init_arch_irq = mdesc->init_irq; - system_timer = mdesc->timer; - init_machine = mdesc->init_machine; #ifdef CONFIG_MULTI_IRQ_HANDLER handle_arch_irq = mdesc->handle_irq; #endif diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 38c261f9951c8..f1e2eb19a67d4 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -30,12 +30,13 @@ #include #include #include +#include #include /* * Our system timer. */ -struct sys_timer *system_timer; +static struct sys_timer *system_timer; #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) /* this needs a better home */ @@ -160,6 +161,7 @@ device_initcall(timer_init_sysfs); void __init time_init(void) { + system_timer = machine_desc->timer; system_timer->init(); } From dec12e62c03d26bbc7a142f067215a3a43cce7d0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 16 Dec 2010 13:49:34 +0000 Subject: [PATCH 46/52] ARM: provide an early platform initialization hook This allows platforms to hook into the initialization early to setup things like scheduler clocks, etc. Signed-off-by: Russell King --- arch/arm/include/asm/mach/arch.h | 1 + arch/arm/kernel/setup.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 69908ddbaf183..3a0893a76a3b2 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -37,6 +37,7 @@ struct machine_desc { struct meminfo *); void (*reserve)(void);/* reserve mem blocks */ void (*map_io)(void);/* IO mapping function */ + void (*init_early)(void); void (*init_irq)(void); struct sys_timer *timer; /* system tick timer */ void (*init_machine)(void); diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index e53132eee27aa..3455ad33de4c4 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -880,6 +880,9 @@ void __init setup_arch(char **cmdline_p) #endif #endif early_trap_init(); + + if (mdesc->init_early) + mdesc->init_early(); } From 67cfa23ac9df810d1fbf3a06b7f408243350ecfe Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 21 Dec 2010 10:42:20 +0000 Subject: [PATCH 47/52] Revert "ARM: relax ioremap prohibition (309caa9) for -final and -stable" This reverts commit 06c1088, as promised in the warning message. --- arch/arm/mm/ioremap.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 17e7b0b57e49f..ab506272b2d3e 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -204,12 +204,8 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, /* * Don't allow RAM to be mapped - this causes problems with ARMv6+ */ - if (pfn_valid(pfn)) { - printk(KERN_WARNING "BUG: Your driver calls ioremap() on system memory. This leads\n" - KERN_WARNING "to architecturally unpredictable behaviour on ARMv6+, and ioremap()\n" - KERN_WARNING "will fail in the next kernel release. Please fix your driver.\n"); - WARN_ON(1); - } + if (WARN_ON(pfn_valid(pfn))) + return NULL; type = get_mem_type(mtype); if (!type) From 78368c79944b12f91bcacb0b0b030c36016264e8 Mon Sep 17 00:00:00 2001 From: Srinidhi Kasagar Date: Wed, 22 Dec 2010 13:18:58 +0100 Subject: [PATCH 48/52] ARM: 6539/1: ux500: remove unnecessary barrier from the secondary startup Signed-off-by: srinidhi kasagar Acked-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-ux500/headsmp.S | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-ux500/headsmp.S b/arch/arm/mach-ux500/headsmp.S index a6be2cdf2b2f4..64fa451edcfd4 100644 --- a/arch/arm/mach-ux500/headsmp.S +++ b/arch/arm/mach-ux500/headsmp.S @@ -23,7 +23,6 @@ ENTRY(u8500_secondary_startup) ldmia r4, {r5, r6} sub r4, r4, r5 add r6, r6, r4 - dsb pen: ldr r7, [r6] cmp r7, r0 bne pen From 3d29005ab8d828e36108ecc2338612ce3acdd86f Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Thu, 23 Dec 2010 11:32:41 +0100 Subject: [PATCH 49/52] ARM: 6541/1: move sev definition to common system.h include file sev is used to send wakeup event to other cores in ARMv6K and above. This has been moved from platform specific part to standard common ARM header file (asm/system.h). Also introduced wfi() and wfe(). Signed-off-by: Shiraz Hashim Signed-off-by: Russell King --- arch/arm/include/asm/system.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 1120f18a6b176..9ab8d7e647376 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -119,6 +119,13 @@ extern unsigned int user_debug; #define vectors_high() (0) #endif +#if __LINUX_ARM_ARCH__ >= 7 || \ + (__LINUX_ARM_ARCH__ == 6 && defined(CONFIG_CPU_32v6K)) +#define sev() __asm__ __volatile__ ("sev" : : : "memory") +#define wfe() __asm__ __volatile__ ("wfe" : : : "memory") +#define wfi() __asm__ __volatile__ ("wfi" : : : "memory") +#endif + #if __LINUX_ARM_ARCH__ >= 7 #define isb() __asm__ __volatile__ ("isb" : : : "memory") #define dsb() __asm__ __volatile__ ("dsb" : : : "memory") From 15095bb0fe779c0403091bda7adce5fb3bb9ca35 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 2 Jan 2011 15:05:21 +0000 Subject: [PATCH 50/52] ARM: TWD: enable one-shot mode Allow one shot timer mode to be used with the TWD. This allows NOHZ mode to be used on SMP systems using the TWD localtimer. Tested on Versatile Express and U8500. Tested-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 290a4b57617f7..15a177573b74b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1248,6 +1248,7 @@ config HAVE_ARM_SCU config HAVE_ARM_TWD bool depends on SMP + select TICK_ONESHOT help This options enables support for the ARM timer and watchdog unit From 9eedd96301cad8ab58ee8c1e579677d0a75c2ba1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 3 Jan 2011 00:00:17 +0000 Subject: [PATCH 51/52] ARM: DMA: Replace page_to_dma()/dma_to_page() with pfn_to_dma()/dma_to_pfn() Replace the page_to_dma() and dma_to_page() macros with their PFN equivalents. This allows us to map parts of memory which do not have a struct page allocated to them to bus addresses. This will be used internally by dma_alloc_coherent()/dma_alloc_writecombine(). Build tested on Versatile, OMAP1, IOP13xx and KS8695. Tested-by: Janusz Krzysztofik Signed-off-by: Russell King --- arch/arm/include/asm/dma-mapping.h | 34 ++++++++++++--------- arch/arm/mach-iop13xx/include/mach/memory.h | 6 ++-- arch/arm/mach-ks8695/include/mach/memory.h | 8 ++--- arch/arm/mm/dma-mapping.c | 4 +-- arch/arm/plat-omap/include/plat/memory.h | 8 ++--- 5 files changed, 32 insertions(+), 28 deletions(-) diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index c568da7dcae45..8f69b98f68fc7 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -9,20 +9,24 @@ #include #include +#ifdef __arch_page_to_dma +#error Please update to __arch_pfn_to_dma +#endif + /* - * page_to_dma/dma_to_virt/virt_to_dma are architecture private functions - * used internally by the DMA-mapping API to provide DMA addresses. They - * must not be used by drivers. + * dma_to_pfn/pfn_to_dma/dma_to_virt/virt_to_dma are architecture private + * functions used internally by the DMA-mapping API to provide DMA + * addresses. They must not be used by drivers. */ -#ifndef __arch_page_to_dma -static inline dma_addr_t page_to_dma(struct device *dev, struct page *page) +#ifndef __arch_pfn_to_dma +static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn) { - return (dma_addr_t)__pfn_to_bus(page_to_pfn(page)); + return (dma_addr_t)__pfn_to_bus(pfn); } -static inline struct page *dma_to_page(struct device *dev, dma_addr_t addr) +static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr) { - return pfn_to_page(__bus_to_pfn(addr)); + return __bus_to_pfn(addr); } static inline void *dma_to_virt(struct device *dev, dma_addr_t addr) @@ -35,14 +39,14 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) return (dma_addr_t)__virt_to_bus((unsigned long)(addr)); } #else -static inline dma_addr_t page_to_dma(struct device *dev, struct page *page) +static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn) { - return __arch_page_to_dma(dev, page); + return __arch_pfn_to_dma(dev, pfn); } -static inline struct page *dma_to_page(struct device *dev, dma_addr_t addr) +static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr) { - return __arch_dma_to_page(dev, addr); + return __arch_dma_to_pfn(dev, addr); } static inline void *dma_to_virt(struct device *dev, dma_addr_t addr) @@ -368,7 +372,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, __dma_page_cpu_to_dev(page, offset, size, dir); - return page_to_dma(dev, page) + offset; + return pfn_to_dma(dev, page_to_pfn(page)) + offset; } /** @@ -408,8 +412,8 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, static inline void dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { - __dma_page_dev_to_cpu(dma_to_page(dev, handle), handle & ~PAGE_MASK, - size, dir); + __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)), + handle & ~PAGE_MASK, size, dir); } #endif /* CONFIG_DMABOUNCE */ diff --git a/arch/arm/mach-iop13xx/include/mach/memory.h b/arch/arm/mach-iop13xx/include/mach/memory.h index 7415e4338651e..3ad455318868d 100644 --- a/arch/arm/mach-iop13xx/include/mach/memory.h +++ b/arch/arm/mach-iop13xx/include/mach/memory.h @@ -58,13 +58,13 @@ static inline unsigned long __lbus_to_virt(dma_addr_t x) __dma; \ }) -#define __arch_page_to_dma(dev, page) \ +#define __arch_pfn_to_dma(dev, pfn) \ ({ \ /* __is_lbus_virt() can never be true for RAM pages */ \ - (dma_addr_t)page_to_phys(page); \ + (dma_addr_t)__pfn_to_phys(pfn); \ }) -#define __arch_dma_to_page(dev, addr) phys_to_page(addr) +#define __arch_dma_to_pfn(dev, addr) __phys_to_pfn(addr) #endif /* CONFIG_ARCH_IOP13XX */ #endif /* !ASSEMBLY */ diff --git a/arch/arm/mach-ks8695/include/mach/memory.h b/arch/arm/mach-ks8695/include/mach/memory.h index ffa19aae6e054..bace9a681adcb 100644 --- a/arch/arm/mach-ks8695/include/mach/memory.h +++ b/arch/arm/mach-ks8695/include/mach/memory.h @@ -35,17 +35,17 @@ extern struct bus_type platform_bus_type; __phys_to_virt(x) : __bus_to_virt(x)); }) #define __arch_virt_to_dma(dev, x) ({ is_lbus_device(dev) ? \ (dma_addr_t)__virt_to_phys(x) : (dma_addr_t)__virt_to_bus(x); }) -#define __arch_page_to_dma(dev, x) \ - ({ dma_addr_t __dma = page_to_phys(page); \ +#define __arch_pfn_to_dma(dev, pfn) \ + ({ dma_addr_t __dma = __pfn_to_phys(pfn); \ if (!is_lbus_device(dev)) \ __dma = __dma - PHYS_OFFSET + KS8695_PCIMEM_PA; \ __dma; }) -#define __arch_dma_to_page(dev, x) \ +#define __arch_dma_to_pfn(dev, x) \ ({ dma_addr_t __dma = x; \ if (!is_lbus_device(dev)) \ __dma += PHYS_OFFSET - KS8695_PCIMEM_PA; \ - phys_to_page(__dma); \ + __phys_to_pfn(__dma); \ }) #endif diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index e4dd0646e8597..44e72108d7a77 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -311,7 +311,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, addr = page_address(page); if (addr) - *handle = page_to_dma(dev, page); + *handle = pfn_to_dma(dev, page_to_pfn(page)); return addr; } @@ -406,7 +406,7 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr if (!arch_is_coherent()) __dma_free_remap(cpu_addr, size); - __dma_free_buffer(dma_to_page(dev, handle), size); + __dma_free_buffer(pfn_to_page(dma_to_pfn(dev, handle)), size); } EXPORT_SYMBOL(dma_free_coherent); diff --git a/arch/arm/plat-omap/include/plat/memory.h b/arch/arm/plat-omap/include/plat/memory.h index d5306bee44b2f..f8d922fb5584e 100644 --- a/arch/arm/plat-omap/include/plat/memory.h +++ b/arch/arm/plat-omap/include/plat/memory.h @@ -61,17 +61,17 @@ #define lbus_to_virt(x) ((x) - OMAP1510_LB_OFFSET + PAGE_OFFSET) #define is_lbus_device(dev) (cpu_is_omap15xx() && dev && (strncmp(dev_name(dev), "ohci", 4) == 0)) -#define __arch_page_to_dma(dev, page) \ - ({ dma_addr_t __dma = page_to_phys(page); \ +#define __arch_pfn_to_dma(dev, pfn) \ + ({ dma_addr_t __dma = __pfn_to_phys(pfn); \ if (is_lbus_device(dev)) \ __dma = __dma - PHYS_OFFSET + OMAP1510_LB_OFFSET; \ __dma; }) -#define __arch_dma_to_page(dev, addr) \ +#define __arch_dma_to_pfn(dev, addr) \ ({ dma_addr_t __dma = addr; \ if (is_lbus_device(dev)) \ __dma += PHYS_OFFSET - OMAP1510_LB_OFFSET; \ - phys_to_page(__dma); \ + __phys_to_pfn(__dma); \ }) #define __arch_dma_to_virt(dev, addr) ({ (void *) (is_lbus_device(dev) ? \ From 24056f525051a9e186af28904b396320e18bf9a0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 3 Jan 2011 11:29:28 +0000 Subject: [PATCH 52/52] ARM: DMA: add support for DMA debugging Add ARM support for the DMA debug infrastructure, which allows the DMA API usage to be debugged. Signed-off-by: Russell King --- arch/arm/Kconfig | 1 + arch/arm/common/dmabounce.c | 16 ++++---- arch/arm/include/asm/dma-mapping.h | 65 ++++++++++++++++++++++++------ arch/arm/mm/dma-mapping.c | 24 +++++++++-- 4 files changed, 83 insertions(+), 23 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 47694865018c4..ca2ab3d286390 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2,6 +2,7 @@ config ARM bool default y select HAVE_AOUT + select HAVE_DMA_API_DEBUG select HAVE_IDE select HAVE_MEMBLOCK select RTC_LIB diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index cc0a932bbea90..e5681636626f5 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -328,7 +328,7 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, * substitute the safe buffer for the unsafe one. * (basically move the buffer from an unsafe area to a safe one) */ -dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, +dma_addr_t __dma_map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir) { dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", @@ -338,7 +338,7 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, return map_single(dev, ptr, size, dir); } -EXPORT_SYMBOL(dma_map_single); +EXPORT_SYMBOL(__dma_map_single); /* * see if a mapped address was really a "safe" buffer and if so, copy @@ -346,7 +346,7 @@ EXPORT_SYMBOL(dma_map_single); * the safe buffer. (basically return things back to the way they * should be) */ -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, +void __dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", @@ -354,9 +354,9 @@ void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, unmap_single(dev, dma_addr, size, dir); } -EXPORT_SYMBOL(dma_unmap_single); +EXPORT_SYMBOL(__dma_unmap_single); -dma_addr_t dma_map_page(struct device *dev, struct page *page, +dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", @@ -372,7 +372,7 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page, return map_single(dev, page_address(page) + offset, size, dir); } -EXPORT_SYMBOL(dma_map_page); +EXPORT_SYMBOL(__dma_map_page); /* * see if a mapped address was really a "safe" buffer and if so, copy @@ -380,7 +380,7 @@ EXPORT_SYMBOL(dma_map_page); * the safe buffer. (basically return things back to the way they * should be) */ -void dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, +void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", @@ -388,7 +388,7 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, unmap_single(dev, dma_addr, size, dir); } -EXPORT_SYMBOL(dma_unmap_page); +EXPORT_SYMBOL(__dma_unmap_page); int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr, unsigned long off, size_t sz, enum dma_data_direction dir) diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 8f69b98f68fc7..4fff837363edd 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -297,13 +298,13 @@ extern int dma_needs_bounce(struct device*, dma_addr_t, size_t); /* * The DMA API, implemented by dmabounce.c. See below for descriptions. */ -extern dma_addr_t dma_map_single(struct device *, void *, size_t, +extern dma_addr_t __dma_map_single(struct device *, void *, size_t, enum dma_data_direction); -extern void dma_unmap_single(struct device *, dma_addr_t, size_t, +extern void __dma_unmap_single(struct device *, dma_addr_t, size_t, enum dma_data_direction); -extern dma_addr_t dma_map_page(struct device *, struct page *, +extern dma_addr_t __dma_map_page(struct device *, struct page *, unsigned long, size_t, enum dma_data_direction); -extern void dma_unmap_page(struct device *, dma_addr_t, size_t, +extern void __dma_unmap_page(struct device *, dma_addr_t, size_t, enum dma_data_direction); /* @@ -327,6 +328,34 @@ static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr, } +static inline dma_addr_t __dma_map_single(struct device *dev, void *cpu_addr, + size_t size, enum dma_data_direction dir) +{ + __dma_single_cpu_to_dev(cpu_addr, size, dir); + return virt_to_dma(dev, cpu_addr); +} + +static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction dir) +{ + __dma_page_cpu_to_dev(page, offset, size, dir); + return pfn_to_dma(dev, page_to_pfn(page)) + offset; +} + +static inline void __dma_unmap_single(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir) +{ + __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir); +} + +static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir) +{ + __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)), + handle & ~PAGE_MASK, size, dir); +} +#endif /* CONFIG_DMABOUNCE */ + /** * dma_map_single - map a single buffer for streaming DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices @@ -344,11 +373,16 @@ static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr, static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir) { + dma_addr_t addr; + BUG_ON(!valid_dma_direction(dir)); - __dma_single_cpu_to_dev(cpu_addr, size, dir); + addr = __dma_map_single(dev, cpu_addr, size, dir); + debug_dma_map_page(dev, virt_to_page(cpu_addr), + (unsigned long)cpu_addr & ~PAGE_MASK, size, + dir, addr, true); - return virt_to_dma(dev, cpu_addr); + return addr; } /** @@ -368,11 +402,14 @@ static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { + dma_addr_t addr; + BUG_ON(!valid_dma_direction(dir)); - __dma_page_cpu_to_dev(page, offset, size, dir); + addr = __dma_map_page(dev, page, offset, size, dir); + debug_dma_map_page(dev, page, offset, size, dir, addr, false); - return pfn_to_dma(dev, page_to_pfn(page)) + offset; + return addr; } /** @@ -392,7 +429,8 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { - __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir); + debug_dma_unmap_page(dev, handle, size, dir, true); + __dma_unmap_single(dev, handle, size, dir); } /** @@ -412,10 +450,9 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, static inline void dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { - __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)), - handle & ~PAGE_MASK, size, dir); + debug_dma_unmap_page(dev, handle, size, dir, false); + __dma_unmap_page(dev, handle, size, dir); } -#endif /* CONFIG_DMABOUNCE */ /** * dma_sync_single_range_for_cpu @@ -441,6 +478,8 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev, { BUG_ON(!valid_dma_direction(dir)); + debug_dma_sync_single_for_cpu(dev, handle + offset, size, dir); + if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir)) return; @@ -453,6 +492,8 @@ static inline void dma_sync_single_range_for_device(struct device *dev, { BUG_ON(!valid_dma_direction(dir)); + debug_dma_sync_single_for_device(dev, handle + offset, size, dir); + if (!dmabounce_sync_for_device(dev, handle, offset, size, dir)) return; diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 44e72108d7a77..85f9361f3e023 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -554,17 +554,20 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, struct scatterlist *s; int i, j; + BUG_ON(!valid_dma_direction(dir)); + for_each_sg(sg, s, nents, i) { - s->dma_address = dma_map_page(dev, sg_page(s), s->offset, + s->dma_address = __dma_map_page(dev, sg_page(s), s->offset, s->length, dir); if (dma_mapping_error(dev, s->dma_address)) goto bad_mapping; } + debug_dma_map_sg(dev, sg, nents, nents, dir); return nents; bad_mapping: for_each_sg(sg, s, i, j) - dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir); + __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir); return 0; } EXPORT_SYMBOL(dma_map_sg); @@ -585,8 +588,10 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, struct scatterlist *s; int i; + debug_dma_unmap_sg(dev, sg, nents, dir); + for_each_sg(sg, s, nents, i) - dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir); + __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir); } EXPORT_SYMBOL(dma_unmap_sg); @@ -611,6 +616,8 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, __dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir); } + + debug_dma_sync_sg_for_cpu(dev, sg, nents, dir); } EXPORT_SYMBOL(dma_sync_sg_for_cpu); @@ -635,5 +642,16 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir); } + + debug_dma_sync_sg_for_device(dev, sg, nents, dir); } EXPORT_SYMBOL(dma_sync_sg_for_device); + +#define PREALLOC_DMA_DEBUG_ENTRIES 4096 + +static int __init dma_debug_do_init(void) +{ + dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); + return 0; +} +fs_initcall(dma_debug_do_init);