diff options
Diffstat (limited to 'arch/arm/kernel')
27 files changed, 492 insertions, 219 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5140df5f23aa..a30fc9be9e9e 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -17,7 +17,8 @@ CFLAGS_REMOVE_return_address.o = -pg  obj-y		:= elf.o entry-common.o irq.o opcodes.o \  		   process.o ptrace.o return_address.o \ -		   setup.o signal.o stacktrace.o sys_arm.o time.o traps.o +		   setup.o signal.o sigreturn_codes.o \ +		   stacktrace.o sys_arm.o time.o traps.o  obj-$(CONFIG_ATAGS)		+= atags_parse.o  obj-$(CONFIG_ATAGS_PROC)	+= atags_proc.o @@ -78,6 +79,7 @@ obj-$(CONFIG_CPU_XSC3)		+= xscale-cp0.o  obj-$(CONFIG_CPU_MOHAWK)	+= xscale-cp0.o  obj-$(CONFIG_CPU_PJ4)		+= pj4-cp0.o  obj-$(CONFIG_IWMMXT)		+= iwmmxt.o +obj-$(CONFIG_PERF_EVENTS)	+= perf_regs.o  obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o perf_event_cpu.o  AFLAGS_iwmmxt.o			:= -Wa,-mcpu=iwmmxt  obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c index 221f07b11ccb..1791f12c180b 100644 --- a/arch/arm/kernel/arch_timer.c +++ b/arch/arm/kernel/arch_timer.c @@ -11,7 +11,6 @@  #include <linux/init.h>  #include <linux/types.h>  #include <linux/errno.h> -#include <linux/sched_clock.h>  #include <asm/delay.h> @@ -22,13 +21,6 @@ static unsigned long arch_timer_read_counter_long(void)  	return arch_timer_read_counter();  } -static u32 sched_clock_mult __read_mostly; - -static unsigned long long notrace arch_timer_sched_clock(void) -{ -	return arch_timer_read_counter() * sched_clock_mult; -} -  static struct delay_timer arch_delay_timer;  static void __init arch_timer_delay_timer_register(void) @@ -48,11 +40,5 @@ int __init arch_timer_arch_init(void)  	arch_timer_delay_timer_register(); -	/* Cache the sched_clock multiplier to save a divide in the hot path. */ -	sched_clock_mult = NSEC_PER_SEC / arch_timer_rate; -	sched_clock_func = arch_timer_sched_clock; -	pr_info("sched_clock: ARM arch timer >56 bits at %ukHz, resolution %uns\n", -		arch_timer_rate / 1000, sched_clock_mult); -  	return 0;  } diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 60d3b738d420..1f031ddd0667 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -155,4 +155,5 @@ EXPORT_SYMBOL(__gnu_mcount_nc);  #ifdef CONFIG_ARM_PATCH_PHYS_VIRT  EXPORT_SYMBOL(__pv_phys_offset); +EXPORT_SYMBOL(__pv_offset);  #endif diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index f35906b3d8c9..739c3dfc1da2 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -174,6 +174,19 @@ bool arch_match_cpu_phys_id(int cpu, u64 phys_id)  	return (phys_id & MPIDR_HWID_BITMASK) == cpu_logical_map(cpu);  } +static const void * __init arch_get_next_mach(const char *const **match) +{ +	static const struct machine_desc *mdesc = __arch_info_begin; +	const struct machine_desc *m = mdesc; + +	if (m >= __arch_info_end) +		return NULL; + +	mdesc++; +	*match = m->dt_compat; +	return m; +} +  /**   * setup_machine_fdt - Machine setup when an dtb was passed to the kernel   * @dt_phys: physical address of dt blob @@ -183,11 +196,7 @@ bool arch_match_cpu_phys_id(int cpu, u64 phys_id)   */  const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)  { -	struct boot_param_header *devtree;  	const struct machine_desc *mdesc, *mdesc_best = NULL; -	unsigned int score, mdesc_score = ~1; -	unsigned long dt_root; -	const char *model;  #ifdef CONFIG_ARCH_MULTIPLATFORM  	DT_MACHINE_START(GENERIC_DT, "Generic DT based system") @@ -196,32 +205,20 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)  	mdesc_best = &__mach_desc_GENERIC_DT;  #endif -	if (!dt_phys) +	if (!dt_phys || !early_init_dt_scan(phys_to_virt(dt_phys)))  		return NULL; -	devtree = phys_to_virt(dt_phys); +	mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach); -	/* check device tree validity */ -	if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) -		return NULL; - -	/* Search the mdescs for the 'best' compatible value match */ -	initial_boot_params = devtree; -	dt_root = of_get_flat_dt_root(); -	for_each_machine_desc(mdesc) { -		score = of_flat_dt_match(dt_root, mdesc->dt_compat); -		if (score > 0 && score < mdesc_score) { -			mdesc_best = mdesc; -			mdesc_score = score; -		} -	} -	if (!mdesc_best) { +	if (!mdesc) {  		const char *prop;  		long size; +		unsigned long dt_root;  		early_print("\nError: unrecognized/unsupported "  			    "device tree compatible list:\n[ "); +		dt_root = of_get_flat_dt_root();  		prop = of_get_flat_dt_prop(dt_root, "compatible", &size);  		while (size > 0) {  			early_print("'%s' ", prop); @@ -233,22 +230,8 @@ const struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)  		dump_machine_table(); /* does not return */  	} -	model = of_get_flat_dt_prop(dt_root, "model", NULL); -	if (!model) -		model = of_get_flat_dt_prop(dt_root, "compatible", NULL); -	if (!model) -		model = "<unknown>"; -	pr_info("Machine: %s, model: %s\n", mdesc_best->name, model); - -	/* Retrieve various information from the /chosen node */ -	of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); -	/* Initialize {size,address}-cells info */ -	of_scan_flat_dt(early_init_dt_scan_root, NULL); -	/* Setup memory, calling early_init_dt_add_memory_arch */ -	of_scan_flat_dt(early_init_dt_scan_memory, NULL); -  	/* Change machine number to match the mdesc we're using */ -	__machine_arch_type = mdesc_best->nr; +	__machine_arch_type = mdesc->nr; -	return mdesc_best; +	return mdesc;  } diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 9cbe70c8b0ef..b3fb8c9e1ff2 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -192,6 +192,7 @@ __dabt_svc:  	svc_entry  	mov	r2, sp  	dabt_helper + THUMB(	ldr	r5, [sp, #S_PSR]	)	@ potentially updated CPSR  	svc_exit r5				@ return from exception   UNWIND(.fnend		)  ENDPROC(__dabt_svc) @@ -416,9 +417,8 @@ __und_usr:  	bne	__und_usr_thumb  	sub	r4, r2, #4			@ ARM instr at LR - 4  1:	ldrt	r0, [r4] -#ifdef CONFIG_CPU_ENDIAN_BE8 -	rev	r0, r0				@ little endian instruction -#endif + ARM_BE8(rev	r0, r0)				@ little endian instruction +  	@ r0 = 32-bit ARM instruction which caused the exception  	@ r2 = PC value for the following instruction (:= regs->ARM_pc)  	@ r4 = PC value for the faulting instruction diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index bc6bd9683ba4..a2dcafdf1bc8 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -393,9 +393,7 @@ ENTRY(vector_swi)  #else   USER(	ldr	r10, [lr, #-4]		)	@ get SWI instruction  #endif -#ifdef CONFIG_CPU_ENDIAN_BE8 -	rev	r10, r10			@ little endian instruction -#endif + ARM_BE8(rev	r10, r10)			@ little endian instruction  #elif defined(CONFIG_AEABI) diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 2c7cc1e03473..11d59b32fb8d 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -77,6 +77,7 @@  	__HEAD  ENTRY(stext) + ARM_BE8(setend	be )			@ ensure we are in BE8 mode   THUMB(	adr	r9, BSYM(1f)	)	@ Kernel is always entered in ARM.   THUMB(	bx	r9		)	@ If this is a Thumb-2 kernel, @@ -352,6 +353,9 @@ ENTRY(secondary_startup)  	 * the processor type - there is no need to check the machine type  	 * as it has already been validated by the primary processor.  	 */ + + ARM_BE8(setend	be)				@ ensure we are in BE8 mode +  #ifdef CONFIG_ARM_VIRT_EXT  	bl	__hyp_stub_install_secondary  #endif @@ -487,7 +491,27 @@ __fixup_smp:  	mrc	p15, 0, r0, c0, c0, 5	@ read MPIDR  	and	r0, r0, #0xc0000000	@ multiprocessing extensions and  	teq	r0, #0x80000000		@ not part of a uniprocessor system? -	moveq	pc, lr			@ yes, assume SMP +	bne    __fixup_smp_on_up	@ no, assume UP + +	@ Core indicates it is SMP. Check for Aegis SOC where a single +	@ Cortex-A9 CPU is present but SMP operations fault. +	mov	r4, #0x41000000 +	orr	r4, r4, #0x0000c000 +	orr	r4, r4, #0x00000090 +	teq	r3, r4			@ Check for ARM Cortex-A9 +	movne	pc, lr			@ Not ARM Cortex-A9, + +	@ If a future SoC *does* use 0x0 as the PERIPH_BASE, then the +	@ below address check will need to be #ifdef'd or equivalent +	@ for the Aegis platform. +	mrc	p15, 4, r0, c15, c0	@ get SCU base address +	teq	r0, #0x0		@ '0' on actual UP A9 hardware +	beq	__fixup_smp_on_up	@ So its an A9 UP +	ldr	r0, [r0, #4]		@ read SCU Config +ARM_BE8(rev	r0, r0)			@ byteswap if big endian +	and	r0, r0, #0x3		@ number of CPUs +	teq	r0, #0x0		@ is 1? +	movne	pc, lr  __fixup_smp_on_up:  	adr	r0, 1f @@ -536,6 +560,14 @@ ENTRY(fixup_smp)  	ldmfd	sp!, {r4 - r6, pc}  ENDPROC(fixup_smp) +#ifdef __ARMEB__ +#define LOW_OFFSET	0x4 +#define HIGH_OFFSET	0x0 +#else +#define LOW_OFFSET	0x0 +#define HIGH_OFFSET	0x4 +#endif +  #ifdef CONFIG_ARM_PATCH_PHYS_VIRT  /* __fixup_pv_table - patch the stub instructions with the delta between @@ -546,17 +578,20 @@ ENDPROC(fixup_smp)  	__HEAD  __fixup_pv_table:  	adr	r0, 1f -	ldmia	r0, {r3-r5, r7} -	sub	r3, r0, r3	@ PHYS_OFFSET - PAGE_OFFSET +	ldmia	r0, {r3-r7} +	mvn	ip, #0 +	subs	r3, r0, r3	@ PHYS_OFFSET - PAGE_OFFSET  	add	r4, r4, r3	@ adjust table start address  	add	r5, r5, r3	@ adjust table end address -	add	r7, r7, r3	@ adjust __pv_phys_offset address -	str	r8, [r7]	@ save computed PHYS_OFFSET to __pv_phys_offset +	add	r6, r6, r3	@ adjust __pv_phys_offset address +	add	r7, r7, r3	@ adjust __pv_offset address +	str	r8, [r6, #LOW_OFFSET]	@ save computed PHYS_OFFSET to __pv_phys_offset +	strcc	ip, [r7, #HIGH_OFFSET]	@ save to __pv_offset high bits  	mov	r6, r3, lsr #24	@ constant for add/sub instructions  	teq	r3, r6, lsl #24 @ must be 16MiB aligned  THUMB(	it	ne		@ cross section branch )  	bne	__error -	str	r6, [r7, #4]	@ save to __pv_offset +	str	r3, [r7, #LOW_OFFSET]	@ save to __pv_offset low bits  	b	__fixup_a_pv_table  ENDPROC(__fixup_pv_table) @@ -565,10 +600,19 @@ ENDPROC(__fixup_pv_table)  	.long	__pv_table_begin  	.long	__pv_table_end  2:	.long	__pv_phys_offset +	.long	__pv_offset  	.text  __fixup_a_pv_table: +	adr	r0, 3f +	ldr	r6, [r0] +	add	r6, r6, r3 +	ldr	r0, [r6, #HIGH_OFFSET]	@ pv_offset high word +	ldr	r6, [r6, #LOW_OFFSET]	@ pv_offset low word +	mov	r6, r6, lsr #24 +	cmn	r0, #1  #ifdef CONFIG_THUMB2_KERNEL +	moveq	r0, #0x200000	@ set bit 21, mov to mvn instruction  	lsls	r6, #24  	beq	2f  	clz	r7, r6 @@ -582,18 +626,46 @@ __fixup_a_pv_table:  	b	2f  1:	add     r7, r3  	ldrh	ip, [r7, #2] -	and	ip, 0x8f00 -	orr	ip, r6	@ mask in offset bits 31-24 +ARM_BE8(rev16	ip, ip) +	tst	ip, #0x4000 +	and	ip, #0x8f00 +	orrne	ip, r6	@ mask in offset bits 31-24 +	orreq	ip, r0	@ mask in offset bits 7-0 +ARM_BE8(rev16	ip, ip)  	strh	ip, [r7, #2] +	bne	2f +	ldrh	ip, [r7] +ARM_BE8(rev16	ip, ip) +	bic	ip, #0x20 +	orr	ip, ip, r0, lsr #16 +ARM_BE8(rev16	ip, ip) +	strh	ip, [r7]  2:	cmp	r4, r5  	ldrcc	r7, [r4], #4	@ use branch for delay slot  	bcc	1b  	bx	lr  #else +#ifdef CONFIG_CPU_ENDIAN_BE8 +	moveq	r0, #0x00004000	@ set bit 22, mov to mvn instruction +#else +	moveq	r0, #0x400000	@ set bit 22, mov to mvn instruction +#endif  	b	2f  1:	ldr	ip, [r7, r3] +#ifdef CONFIG_CPU_ENDIAN_BE8 +	@ in BE8, we load data in BE, but instructions still in LE +	bic	ip, ip, #0xff000000 +	tst	ip, #0x000f0000	@ check the rotation field +	orrne	ip, ip, r6, lsl #24 @ mask in offset bits 31-24 +	biceq	ip, ip, #0x00004000 @ clear bit 22 +	orreq	ip, ip, r0      @ mask in offset bits 7-0 +#else  	bic	ip, ip, #0x000000ff -	orr	ip, ip, r6	@ mask in offset bits 31-24 +	tst	ip, #0xf00	@ check the rotation field +	orrne	ip, ip, r6	@ mask in offset bits 31-24 +	biceq	ip, ip, #0x400000	@ clear bit 22 +	orreq	ip, ip, r0	@ mask in offset bits 7-0 +#endif  	str	ip, [r7, r3]  2:	cmp	r4, r5  	ldrcc	r7, [r4], #4	@ use branch for delay slot @@ -602,28 +674,30 @@ __fixup_a_pv_table:  #endif  ENDPROC(__fixup_a_pv_table) +	.align +3:	.long __pv_offset +  ENTRY(fixup_pv_table)  	stmfd	sp!, {r4 - r7, lr} -	ldr	r2, 2f			@ get address of __pv_phys_offset  	mov	r3, #0			@ no offset  	mov	r4, r0			@ r0 = table start  	add	r5, r0, r1		@ r1 = table size -	ldr	r6, [r2, #4]		@ get __pv_offset  	bl	__fixup_a_pv_table  	ldmfd	sp!, {r4 - r7, pc}  ENDPROC(fixup_pv_table) -	.align -2:	.long	__pv_phys_offset -  	.data  	.globl	__pv_phys_offset  	.type	__pv_phys_offset, %object  __pv_phys_offset: -	.long	0 -	.size	__pv_phys_offset, . - __pv_phys_offset +	.quad	0 +	.size	__pv_phys_offset, . -__pv_phys_offset + +	.globl	__pv_offset +	.type	__pv_offset, %object  __pv_offset: -	.long	0 +	.quad	0 +	.size	__pv_offset, . -__pv_offset  #endif  #include "head-common.S" diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 7b95de601357..3d446605cbf8 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -344,13 +344,13 @@ int arch_install_hw_breakpoint(struct perf_event *bp)  		/* Breakpoint */  		ctrl_base = ARM_BASE_BCR;  		val_base = ARM_BASE_BVR; -		slots = (struct perf_event **)__get_cpu_var(bp_on_reg); +		slots = this_cpu_ptr(bp_on_reg);  		max_slots = core_num_brps;  	} else {  		/* Watchpoint */  		ctrl_base = ARM_BASE_WCR;  		val_base = ARM_BASE_WVR; -		slots = (struct perf_event **)__get_cpu_var(wp_on_reg); +		slots = this_cpu_ptr(wp_on_reg);  		max_slots = core_num_wrps;  	} @@ -396,12 +396,12 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)  	if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {  		/* Breakpoint */  		base = ARM_BASE_BCR; -		slots = (struct perf_event **)__get_cpu_var(bp_on_reg); +		slots = this_cpu_ptr(bp_on_reg);  		max_slots = core_num_brps;  	} else {  		/* Watchpoint */  		base = ARM_BASE_WCR; -		slots = (struct perf_event **)__get_cpu_var(wp_on_reg); +		slots = this_cpu_ptr(wp_on_reg);  		max_slots = core_num_wrps;  	} @@ -697,7 +697,7 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,  	struct arch_hw_breakpoint *info;  	struct arch_hw_breakpoint_ctrl ctrl; -	slots = (struct perf_event **)__get_cpu_var(wp_on_reg); +	slots = this_cpu_ptr(wp_on_reg);  	for (i = 0; i < core_num_wrps; ++i) {  		rcu_read_lock(); @@ -768,7 +768,7 @@ static void watchpoint_single_step_handler(unsigned long pc)  	struct perf_event *wp, **slots;  	struct arch_hw_breakpoint *info; -	slots = (struct perf_event **)__get_cpu_var(wp_on_reg); +	slots = this_cpu_ptr(wp_on_reg);  	for (i = 0; i < core_num_wrps; ++i) {  		rcu_read_lock(); @@ -802,7 +802,7 @@ static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)  	struct arch_hw_breakpoint *info;  	struct arch_hw_breakpoint_ctrl ctrl; -	slots = (struct perf_event **)__get_cpu_var(bp_on_reg); +	slots = this_cpu_ptr(bp_on_reg);  	/* The exception entry code places the amended lr in the PC. */  	addr = regs->ARM_pc; diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 170e9f34003f..a7b621ece23d 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -171,13 +171,13 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)  static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)  { -	__get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; +	__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);  	kcb->kprobe_status = kcb->prev_kprobe.status;  }  static void __kprobes set_current_kprobe(struct kprobe *p)  { -	__get_cpu_var(current_kprobe) = p; +	__this_cpu_write(current_kprobe, p);  }  static void __kprobes @@ -421,10 +421,10 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs)  			continue;  		if (ri->rp && ri->rp->handler) { -			__get_cpu_var(current_kprobe) = &ri->rp->kp; +			__this_cpu_write(current_kprobe, &ri->rp->kp);  			get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;  			ri->rp->handler(ri, regs); -			__get_cpu_var(current_kprobe) = NULL; +			__this_cpu_write(current_kprobe, NULL);  		}  		orig_ret_address = (unsigned long)ri->ret_addr; diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 57221e349a7c..f0d180d8b29f 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -14,11 +14,12 @@  #include <asm/pgalloc.h>  #include <asm/mmu_context.h>  #include <asm/cacheflush.h> +#include <asm/fncpy.h>  #include <asm/mach-types.h>  #include <asm/smp_plat.h>  #include <asm/system_misc.h> -extern const unsigned char relocate_new_kernel[]; +extern void relocate_new_kernel(void);  extern const unsigned int relocate_new_kernel_size;  extern unsigned long kexec_start_address; @@ -142,6 +143,8 @@ void machine_kexec(struct kimage *image)  {  	unsigned long page_list;  	unsigned long reboot_code_buffer_phys; +	unsigned long reboot_entry = (unsigned long)relocate_new_kernel; +	unsigned long reboot_entry_phys;  	void *reboot_code_buffer;  	/* @@ -168,16 +171,16 @@ void machine_kexec(struct kimage *image)  	/* copy our kernel relocation code to the control code page */ -	memcpy(reboot_code_buffer, -	       relocate_new_kernel, relocate_new_kernel_size); +	reboot_entry = fncpy(reboot_code_buffer, +			     reboot_entry, +			     relocate_new_kernel_size); +	reboot_entry_phys = (unsigned long)reboot_entry + +		(reboot_code_buffer_phys - (unsigned long)reboot_code_buffer); - -	flush_icache_range((unsigned long) reboot_code_buffer, -			   (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);  	printk(KERN_INFO "Bye!\n");  	if (kexec_reinit)  		kexec_reinit(); -	soft_restart(reboot_code_buffer_phys); +	soft_restart(reboot_entry_phys);  } diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 084dc8896986..45e478157278 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -24,6 +24,7 @@  #include <asm/sections.h>  #include <asm/smp_plat.h>  #include <asm/unwind.h> +#include <asm/opcodes.h>  #ifdef CONFIG_XIP_KERNEL  /* @@ -40,7 +41,7 @@  void *module_alloc(unsigned long size)  {  	return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, -				GFP_KERNEL, PAGE_KERNEL_EXEC, -1, +				GFP_KERNEL, PAGE_KERNEL_EXEC, NUMA_NO_NODE,  				__builtin_return_address(0));  }  #endif @@ -60,6 +61,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,  		Elf32_Sym *sym;  		const char *symname;  		s32 offset; +		u32 tmp;  #ifdef CONFIG_THUMB2_KERNEL  		u32 upper, lower, sign, j1, j2;  #endif @@ -95,7 +97,8 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,  		case R_ARM_PC24:  		case R_ARM_CALL:  		case R_ARM_JUMP24: -			offset = (*(u32 *)loc & 0x00ffffff) << 2; +			offset = __mem_to_opcode_arm(*(u32 *)loc); +			offset = (offset & 0x00ffffff) << 2;  			if (offset & 0x02000000)  				offset -= 0x04000000; @@ -111,9 +114,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,  			}  			offset >>= 2; +			offset &= 0x00ffffff; -			*(u32 *)loc &= 0xff000000; -			*(u32 *)loc |= offset & 0x00ffffff; +			*(u32 *)loc &= __opcode_to_mem_arm(0xff000000); +			*(u32 *)loc |= __opcode_to_mem_arm(offset);  			break;  	       case R_ARM_V4BX: @@ -121,8 +125,8 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,  			* other bits to re-code instruction as  			* MOV PC,Rm.  			*/ -		       *(u32 *)loc &= 0xf000000f; -		       *(u32 *)loc |= 0x01a0f000; +		       *(u32 *)loc &= __opcode_to_mem_arm(0xf000000f); +		       *(u32 *)loc |= __opcode_to_mem_arm(0x01a0f000);  		       break;  		case R_ARM_PREL31: @@ -132,7 +136,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,  		case R_ARM_MOVW_ABS_NC:  		case R_ARM_MOVT_ABS: -			offset = *(u32 *)loc; +			offset = tmp = __mem_to_opcode_arm(*(u32 *)loc);  			offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);  			offset = (offset ^ 0x8000) - 0x8000; @@ -140,16 +144,18 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,  			if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS)  				offset >>= 16; -			*(u32 *)loc &= 0xfff0f000; -			*(u32 *)loc |= ((offset & 0xf000) << 4) | -					(offset & 0x0fff); +			tmp &= 0xfff0f000; +			tmp |= ((offset & 0xf000) << 4) | +				(offset & 0x0fff); + +			*(u32 *)loc = __opcode_to_mem_arm(tmp);  			break;  #ifdef CONFIG_THUMB2_KERNEL  		case R_ARM_THM_CALL:  		case R_ARM_THM_JUMP24: -			upper = *(u16 *)loc; -			lower = *(u16 *)(loc + 2); +			upper = __mem_to_opcode_thumb16(*(u16 *)loc); +			lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2));  			/*  			 * 25 bit signed address range (Thumb-2 BL and B.W @@ -198,17 +204,20 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,  			sign = (offset >> 24) & 1;  			j1 = sign ^ (~(offset >> 23) & 1);  			j2 = sign ^ (~(offset >> 22) & 1); -			*(u16 *)loc = (u16)((upper & 0xf800) | (sign << 10) | +			upper = (u16)((upper & 0xf800) | (sign << 10) |  					    ((offset >> 12) & 0x03ff)); -			*(u16 *)(loc + 2) = (u16)((lower & 0xd000) | -						  (j1 << 13) | (j2 << 11) | -						  ((offset >> 1) & 0x07ff)); +			lower = (u16)((lower & 0xd000) | +				      (j1 << 13) | (j2 << 11) | +				      ((offset >> 1) & 0x07ff)); + +			*(u16 *)loc = __opcode_to_mem_thumb16(upper); +			*(u16 *)(loc + 2) = __opcode_to_mem_thumb16(lower);  			break;  		case R_ARM_THM_MOVW_ABS_NC:  		case R_ARM_THM_MOVT_ABS: -			upper = *(u16 *)loc; -			lower = *(u16 *)(loc + 2); +			upper = __mem_to_opcode_thumb16(*(u16 *)loc); +			lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2));  			/*  			 * MOVT/MOVW instructions encoding in Thumb-2: @@ -229,12 +238,14 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,  			if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS)  				offset >>= 16; -			*(u16 *)loc = (u16)((upper & 0xfbf0) | -					    ((offset & 0xf000) >> 12) | -					    ((offset & 0x0800) >> 1)); -			*(u16 *)(loc + 2) = (u16)((lower & 0x8f00) | -						  ((offset & 0x0700) << 4) | -						  (offset & 0x00ff)); +			upper = (u16)((upper & 0xfbf0) | +				      ((offset & 0xf000) >> 12) | +				      ((offset & 0x0800) >> 1)); +			lower = (u16)((lower & 0x8f00) | +				      ((offset & 0x0700) << 4) | +				      (offset & 0x00ff)); +			*(u16 *)loc = __opcode_to_mem_thumb16(upper); +			*(u16 *)(loc + 2) = __opcode_to_mem_thumb16(lower);  			break;  #endif diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index e186ee1e63f6..bc3f2efa0d86 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -256,12 +256,11 @@ validate_event(struct pmu_hw_events *hw_events,  	       struct perf_event *event)  {  	struct arm_pmu *armpmu = to_arm_pmu(event->pmu); -	struct pmu *leader_pmu = event->group_leader->pmu;  	if (is_software_event(event))  		return 1; -	if (event->pmu != leader_pmu || event->state < PERF_EVENT_STATE_OFF) +	if (event->state < PERF_EVENT_STATE_OFF)  		return 1;  	if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec) diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 8d6147b2001f..d85055cd24ba 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(perf_num_counters);  static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)  { -	return &__get_cpu_var(cpu_hw_events); +	return this_cpu_ptr(&cpu_hw_events);  }  static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu) diff --git a/arch/arm/kernel/perf_regs.c b/arch/arm/kernel/perf_regs.c new file mode 100644 index 000000000000..6e4379c67cbc --- /dev/null +++ b/arch/arm/kernel/perf_regs.c @@ -0,0 +1,30 @@ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/perf_event.h> +#include <linux/bug.h> +#include <asm/perf_regs.h> +#include <asm/ptrace.h> + +u64 perf_reg_value(struct pt_regs *regs, int idx) +{ +	if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM_MAX)) +		return 0; + +	return regs->uregs[idx]; +} + +#define REG_RESERVED (~((1ULL << PERF_REG_ARM_MAX) - 1)) + +int perf_reg_validate(u64 mask) +{ +	if (!mask || mask & REG_RESERVED) +		return -EINVAL; + +	return 0; +} + +u64 perf_reg_abi(struct task_struct *task) +{ +	return PERF_SAMPLE_REGS_ABI_32; +} diff --git a/arch/arm/kernel/psci_smp.c b/arch/arm/kernel/psci_smp.c index 70ded3fb42d9..570a48cc3d64 100644 --- a/arch/arm/kernel/psci_smp.c +++ b/arch/arm/kernel/psci_smp.c @@ -14,7 +14,6 @@   */  #include <linux/init.h> -#include <linux/irqchip/arm-gic.h>  #include <linux/smp.h>  #include <linux/of.h> diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S index d0cdedf4864d..95858966d84e 100644 --- a/arch/arm/kernel/relocate_kernel.S +++ b/arch/arm/kernel/relocate_kernel.S @@ -2,10 +2,12 @@   * relocate_kernel.S - put the kernel image in place to boot   */ +#include <linux/linkage.h>  #include <asm/kexec.h> -	.globl relocate_new_kernel -relocate_new_kernel: +	.align	3	/* not needed for this code, but keeps fncpy() happy */ + +ENTRY(relocate_new_kernel)  	ldr	r0,kexec_indirection_page  	ldr	r1,kexec_start_address @@ -79,6 +81,8 @@ kexec_mach_type:  kexec_boot_atags:  	.long	0x0 +ENDPROC(relocate_new_kernel) +  relocate_new_kernel_end:  	.globl relocate_new_kernel_size diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 0e1e2b3afa45..6a1b8a81b1ae 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -73,6 +73,8 @@ __setup("fpe=", fpe_setup);  #endif  extern void paging_init(const struct machine_desc *desc); +extern void early_paging_init(const struct machine_desc *, +			      struct proc_info_list *);  extern void sanity_check_meminfo(void);  extern enum reboot_mode reboot_mode;  extern void setup_dma_zone(const struct machine_desc *desc); @@ -599,6 +601,8 @@ static void __init setup_processor(void)  	elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT);  #endif +	erratum_a15_798181_init(); +  	feat_v6_fixup();  	cacheid_init(); @@ -619,9 +623,10 @@ void __init dump_machine_table(void)  		/* can't use cpu_relax() here as it may require MMU setup */;  } -int __init arm_add_memory(phys_addr_t start, phys_addr_t size) +int __init arm_add_memory(u64 start, u64 size)  {  	struct membank *bank = &meminfo.bank[meminfo.nr_banks]; +	u64 aligned_start;  	if (meminfo.nr_banks >= NR_BANKS) {  		printk(KERN_CRIT "NR_BANKS too low, " @@ -634,10 +639,16 @@ int __init arm_add_memory(phys_addr_t start, phys_addr_t size)  	 * Size is appropriately rounded down, start is rounded up.  	 */  	size -= start & ~PAGE_MASK; -	bank->start = PAGE_ALIGN(start); +	aligned_start = PAGE_ALIGN(start); -#ifndef CONFIG_ARM_LPAE -	if (bank->start + size < bank->start) { +#ifndef CONFIG_ARCH_PHYS_ADDR_T_64BIT +	if (aligned_start > ULONG_MAX) { +		printk(KERN_CRIT "Ignoring memory at 0x%08llx outside " +		       "32-bit physical address space\n", (long long)start); +		return -EINVAL; +	} + +	if (aligned_start + size > ULONG_MAX) {  		printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "  			"32-bit physical address space\n", (long long)start);  		/* @@ -645,10 +656,11 @@ int __init arm_add_memory(phys_addr_t start, phys_addr_t size)  		 * 32 bits, we use ULONG_MAX as the upper limit rather than 4GB.  		 * This means we lose a page after masking.  		 */ -		size = ULONG_MAX - bank->start; +		size = ULONG_MAX - aligned_start;  	}  #endif +	bank->start = aligned_start;  	bank->size = size & ~(phys_addr_t)(PAGE_SIZE - 1);  	/* @@ -669,8 +681,8 @@ int __init arm_add_memory(phys_addr_t start, phys_addr_t size)  static int __init early_mem(char *p)  {  	static int usermem __initdata = 0; -	phys_addr_t size; -	phys_addr_t start; +	u64 size; +	u64 start;  	char *endp;  	/* @@ -878,6 +890,8 @@ void __init setup_arch(char **cmdline_p)  	parse_early_param();  	sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL); + +	early_paging_init(mdesc, lookup_processor_type(read_cpuid_id()));  	sanity_check_meminfo();  	arm_memblock_init(&meminfo, mdesc); @@ -975,6 +989,7 @@ static const char *hwcap_str[] = {  	"idivt",  	"vfpd32",  	"lpae", +	"evtstrm",  	NULL  }; diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index ab3304225272..04d63880037f 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -21,29 +21,7 @@  #include <asm/unistd.h>  #include <asm/vfp.h> -/* - * For ARM syscalls, we encode the syscall number into the instruction. - */ -#define SWI_SYS_SIGRETURN	(0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE)) -#define SWI_SYS_RT_SIGRETURN	(0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)) - -/* - * With EABI, the syscall number has to be loaded into r7. - */ -#define MOV_R7_NR_SIGRETURN	(0xe3a07000 | (__NR_sigreturn - __NR_SYSCALL_BASE)) -#define MOV_R7_NR_RT_SIGRETURN	(0xe3a07000 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) - -/* - * For Thumb syscalls, we pass the syscall number via r7.  We therefore - * need two 16-bit instructions. - */ -#define SWI_THUMB_SIGRETURN	(0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE)) -#define SWI_THUMB_RT_SIGRETURN	(0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) - -static const unsigned long sigreturn_codes[7] = { -	MOV_R7_NR_SIGRETURN,    SWI_SYS_SIGRETURN,    SWI_THUMB_SIGRETURN, -	MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, -}; +extern const unsigned long sigreturn_codes[7];  static unsigned long signal_return_offset; @@ -375,12 +353,18 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,  		 */  		thumb = handler & 1; -		if (thumb) { -			cpsr |= PSR_T_BIT;  #if __LINUX_ARM_ARCH__ >= 7 -			/* clear the If-Then Thumb-2 execution state */ -			cpsr &= ~PSR_IT_MASK; +		/* +		 * Clear the If-Then Thumb-2 execution state +		 * ARM spec requires this to be all 000s in ARM mode +		 * Snapdragon S4/Krait misbehaves on a Thumb=>ARM +		 * signal transition without this. +		 */ +		cpsr &= ~PSR_IT_MASK;  #endif + +		if (thumb) { +			cpsr |= PSR_T_BIT;  		} else  			cpsr &= ~PSR_T_BIT;  	} diff --git a/arch/arm/kernel/sigreturn_codes.S b/arch/arm/kernel/sigreturn_codes.S new file mode 100644 index 000000000000..b84d0cb13682 --- /dev/null +++ b/arch/arm/kernel/sigreturn_codes.S @@ -0,0 +1,102 @@ +/* + * sigreturn_codes.S - code sinpets for sigreturn syscalls + * + * Created by:	Victor Kamensky, 2013-08-13 + * Copyright:	(C) 2013  Linaro Limited + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <asm/unistd.h> + +/* + * For ARM syscalls, we encode the syscall number into the instruction. + * With EABI, the syscall number has to be loaded into r7. As result + * ARM syscall sequence snippet will have move and svc in .arm encoding + * + * For Thumb syscalls, we pass the syscall number via r7.  We therefore + * need two 16-bit instructions in .thumb encoding + * + * Please note sigreturn_codes code are not executed in place. Instead + * they just copied by kernel into appropriate places. Code inside of + * arch/arm/kernel/signal.c is very sensitive to layout of these code + * snippets. + */ + +/* + * In CPU_THUMBONLY case kernel arm opcodes are not allowed. + * Note in this case codes skips those instructions but it uses .org + * directive to keep correct layout of sigreturn_codes array. + */ +#ifndef CONFIG_CPU_THUMBONLY +#define ARM_OK(code...)	code +#else +#define ARM_OK(code...) +#endif + +	.macro arm_slot n +	.org	sigreturn_codes + 12 * (\n) +ARM_OK(	.arm	) +	.endm + +	.macro thumb_slot n +	.org	sigreturn_codes + 12 * (\n) + 8 +	.thumb +	.endm + +#if __LINUX_ARM_ARCH__ <= 4 +	/* +	 * Note we manually set minimally required arch that supports +	 * required thumb opcodes for early arch versions. It is OK +	 * for this file to be used in combination with other +	 * lower arch variants, since these code snippets are only +	 * used as input data. +	 */ +	.arch armv4t +#endif + +	.section .rodata +	.global sigreturn_codes +	.type	sigreturn_codes, #object + +	.align + +sigreturn_codes: + +	/* ARM sigreturn syscall code snippet */ +	arm_slot 0 +ARM_OK(	mov	r7, #(__NR_sigreturn - __NR_SYSCALL_BASE)	) +ARM_OK(	swi	#(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE)	) + +	/* Thumb sigreturn syscall code snippet */ +	thumb_slot 0 +	movs	r7, #(__NR_sigreturn - __NR_SYSCALL_BASE) +	swi	#0 + +	/* ARM sigreturn_rt syscall code snippet */ +	arm_slot 1 +ARM_OK(	mov	r7, #(__NR_rt_sigreturn - __NR_SYSCALL_BASE)	) +ARM_OK(	swi	#(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)	) + +	/* Thumb sigreturn_rt syscall code snippet */ +	thumb_slot 1 +	movs	r7, #(__NR_rt_sigreturn - __NR_SYSCALL_BASE) +	swi	#0 + +	/* +	 * Note on addtional space: setup_return in signal.c +	 * algorithm uses two words copy regardless whether +	 * it is thumb case or not, so we need additional +	 * word after real last entry. +	 */ +	arm_slot 2 +	.space	4 + +	.size	sigreturn_codes, . - sigreturn_codes diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index db1536b8b30b..b907d9b790ab 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -55,6 +55,7 @@   * specific registers and some other data for resume.   *  r0 = suspend function arg0   *  r1 = suspend function + *  r2 = MPIDR value the resuming CPU will use   */  ENTRY(__cpu_suspend)  	stmfd	sp!, {r4 - r11, lr} @@ -67,23 +68,18 @@ ENTRY(__cpu_suspend)  	mov	r5, sp			@ current virtual SP  	add	r4, r4, #12		@ Space for pgd, virt sp, phys resume fn  	sub	sp, sp, r4		@ allocate CPU state on stack -	stmfd	sp!, {r0, r1}		@ save suspend func arg and pointer -	add	r0, sp, #8		@ save pointer to save block -	mov	r1, r4			@ size of save block -	mov	r2, r5			@ virtual SP  	ldr	r3, =sleep_save_sp +	stmfd	sp!, {r0, r1}		@ save suspend func arg and pointer  	ldr	r3, [r3, #SLEEP_SAVE_SP_VIRT] -	ALT_SMP(mrc p15, 0, r9, c0, c0, 5) -        ALT_UP_B(1f) -	ldr	r8, =mpidr_hash -	/* -	 * This ldmia relies on the memory layout of the mpidr_hash -	 * struct mpidr_hash. -	 */ -	ldmia	r8, {r4-r7}	@ r4 = mpidr mask (r5,r6,r7) = l[0,1,2] shifts -	compute_mpidr_hash	lr, r5, r6, r7, r9, r4 -	add	r3, r3, lr, lsl #2 -1: +	ALT_SMP(ldr r0, =mpidr_hash) +	ALT_UP_B(1f) +	/* This ldmia relies on the memory layout of the mpidr_hash struct */ +	ldmia	r0, {r1, r6-r8}	@ r1 = mpidr mask (r6,r7,r8) = l[0,1,2] shifts +	compute_mpidr_hash	r0, r6, r7, r8, r2, r1 +	add	r3, r3, r0, lsl #2 +1:	mov	r2, r5			@ virtual SP +	mov	r1, r4			@ size of save block +	add	r0, sp, #8		@ pointer to save block  	bl	__cpu_suspend_save  	adr	lr, BSYM(cpu_suspend_abort)  	ldmfd	sp!, {r0, pc}		@ call suspend fn @@ -130,6 +126,7 @@ ENDPROC(cpu_resume_after_mmu)  	.data  	.align  ENTRY(cpu_resume) +ARM_BE8(setend be)			@ ensure we are in BE mode  	mov	r1, #0  	ALT_SMP(mrc p15, 0, r0, c0, c0, 5)  	ALT_UP_B(1f) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 72024ea8a3a6..dc894ab3622b 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -25,6 +25,7 @@  #include <linux/clockchips.h>  #include <linux/completion.h>  #include <linux/cpufreq.h> +#include <linux/irq_work.h>  #include <linux/atomic.h>  #include <asm/smp.h> @@ -66,6 +67,8 @@ enum ipi_msg_type {  	IPI_CALL_FUNC,  	IPI_CALL_FUNC_SINGLE,  	IPI_CPU_STOP, +	IPI_IRQ_WORK, +	IPI_COMPLETION,  };  static DECLARE_COMPLETION(cpu_running); @@ -80,7 +83,7 @@ void __init smp_set_ops(struct smp_operations *ops)  static unsigned long get_arch_pgd(pgd_t *pgd)  { -	phys_addr_t pgdir = virt_to_phys(pgd); +	phys_addr_t pgdir = virt_to_idmap(pgd);  	BUG_ON(pgdir & ARCH_PGD_MASK);  	return pgdir >> ARCH_PGD_SHIFT;  } @@ -448,6 +451,14 @@ void arch_send_call_function_single_ipi(int cpu)  	smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);  } +#ifdef CONFIG_IRQ_WORK +void arch_irq_work_raise(void) +{ +	if (is_smp()) +		smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); +} +#endif +  static const char *ipi_types[NR_IPI] = {  #define S(x,s)	[x] = s  	S(IPI_WAKEUP, "CPU wakeup interrupts"), @@ -456,6 +467,8 @@ static const char *ipi_types[NR_IPI] = {  	S(IPI_CALL_FUNC, "Function call interrupts"),  	S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),  	S(IPI_CPU_STOP, "CPU stop interrupts"), +	S(IPI_IRQ_WORK, "IRQ work interrupts"), +	S(IPI_COMPLETION, "completion interrupts"),  };  void show_ipi_list(struct seq_file *p, int prec) @@ -515,6 +528,19 @@ static void ipi_cpu_stop(unsigned int cpu)  		cpu_relax();  } +static DEFINE_PER_CPU(struct completion *, cpu_completion); + +int register_ipi_completion(struct completion *completion, int cpu) +{ +	per_cpu(cpu_completion, cpu) = completion; +	return IPI_COMPLETION; +} + +static void ipi_complete(unsigned int cpu) +{ +	complete(per_cpu(cpu_completion, cpu)); +} +  /*   * Main handler for inter-processor interrupts   */ @@ -565,6 +591,20 @@ void handle_IPI(int ipinr, struct pt_regs *regs)  		irq_exit();  		break; +#ifdef CONFIG_IRQ_WORK +	case IPI_IRQ_WORK: +		irq_enter(); +		irq_work_run(); +		irq_exit(); +		break; +#endif + +	case IPI_COMPLETION: +		irq_enter(); +		ipi_complete(cpu); +		irq_exit(); +		break; +  	default:  		printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",  		       cpu, ipinr); diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c index 5bc1a63284e3..1aafa0d785eb 100644 --- a/arch/arm/kernel/smp_scu.c +++ b/arch/arm/kernel/smp_scu.c @@ -28,7 +28,7 @@   */  unsigned int __init scu_get_core_count(void __iomem *scu_base)  { -	unsigned int ncores = __raw_readl(scu_base + SCU_CONFIG); +	unsigned int ncores = readl_relaxed(scu_base + SCU_CONFIG);  	return (ncores & 0x03) + 1;  } @@ -42,19 +42,19 @@ void scu_enable(void __iomem *scu_base)  #ifdef CONFIG_ARM_ERRATA_764369  	/* Cortex-A9 only */  	if ((read_cpuid_id() & 0xff0ffff0) == 0x410fc090) { -		scu_ctrl = __raw_readl(scu_base + 0x30); +		scu_ctrl = readl_relaxed(scu_base + 0x30);  		if (!(scu_ctrl & 1)) -			__raw_writel(scu_ctrl | 0x1, scu_base + 0x30); +			writel_relaxed(scu_ctrl | 0x1, scu_base + 0x30);  	}  #endif -	scu_ctrl = __raw_readl(scu_base + SCU_CTRL); +	scu_ctrl = readl_relaxed(scu_base + SCU_CTRL);  	/* already enabled? */  	if (scu_ctrl & 1)  		return;  	scu_ctrl |= 1; -	__raw_writel(scu_ctrl, scu_base + SCU_CTRL); +	writel_relaxed(scu_ctrl, scu_base + SCU_CTRL);  	/*  	 * Ensure that the data accessed by CPU0 before the SCU was @@ -80,9 +80,9 @@ int scu_power_mode(void __iomem *scu_base, unsigned int mode)  	if (mode > 3 || mode == 1 || cpu > 3)  		return -EINVAL; -	val = __raw_readb(scu_base + SCU_CPU_STATUS + cpu) & ~0x03; +	val = readb_relaxed(scu_base + SCU_CPU_STATUS + cpu) & ~0x03;  	val |= mode; -	__raw_writeb(val, scu_base + SCU_CPU_STATUS + cpu); +	writeb_relaxed(val, scu_base + SCU_CPU_STATUS + cpu);  	return 0;  } diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c index 83ccca303df8..95d063620b76 100644 --- a/arch/arm/kernel/smp_tlb.c +++ b/arch/arm/kernel/smp_tlb.c @@ -70,6 +70,40 @@ static inline void ipi_flush_bp_all(void *ignored)  	local_flush_bp_all();  } +#ifdef CONFIG_ARM_ERRATA_798181 +bool (*erratum_a15_798181_handler)(void); + +static bool erratum_a15_798181_partial(void) +{ +	asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0)); +	dsb(ish); +	return false; +} + +static bool erratum_a15_798181_broadcast(void) +{ +	asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0)); +	dsb(ish); +	return true; +} + +void erratum_a15_798181_init(void) +{ +	unsigned int midr = read_cpuid_id(); +	unsigned int revidr = read_cpuid(CPUID_REVIDR); + +	/* Cortex-A15 r0p0..r3p2 w/o ECO fix affected */ +	if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2 || +	    (revidr & 0x210) == 0x210) { +		return; +	} +	if (revidr & 0x10) +		erratum_a15_798181_handler = erratum_a15_798181_partial; +	else +		erratum_a15_798181_handler = erratum_a15_798181_broadcast; +} +#endif +  static void ipi_flush_tlb_a15_erratum(void *arg)  {  	dmb(); @@ -80,7 +114,6 @@ static void broadcast_tlb_a15_erratum(void)  	if (!erratum_a15_798181())  		return; -	dummy_flush_tlb_a15_erratum();  	smp_call_function(ipi_flush_tlb_a15_erratum, NULL, 1);  } @@ -92,7 +125,6 @@ static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)  	if (!erratum_a15_798181())  		return; -	dummy_flush_tlb_a15_erratum();  	this_cpu = get_cpu();  	a15_erratum_get_cpumask(this_cpu, mm, &mask);  	smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1); diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 2985c9f0905d..6591e26fc13f 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -45,7 +45,7 @@ static void twd_set_mode(enum clock_event_mode mode,  	case CLOCK_EVT_MODE_PERIODIC:  		ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE  			| TWD_TIMER_CONTROL_PERIODIC; -		__raw_writel(DIV_ROUND_CLOSEST(twd_timer_rate, HZ), +		writel_relaxed(DIV_ROUND_CLOSEST(twd_timer_rate, HZ),  			twd_base + TWD_TIMER_LOAD);  		break;  	case CLOCK_EVT_MODE_ONESHOT: @@ -58,18 +58,18 @@ static void twd_set_mode(enum clock_event_mode mode,  		ctrl = 0;  	} -	__raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL); +	writel_relaxed(ctrl, twd_base + TWD_TIMER_CONTROL);  }  static int twd_set_next_event(unsigned long evt,  			struct clock_event_device *unused)  { -	unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL); +	unsigned long ctrl = readl_relaxed(twd_base + TWD_TIMER_CONTROL);  	ctrl |= TWD_TIMER_CONTROL_ENABLE; -	__raw_writel(evt, twd_base + TWD_TIMER_COUNTER); -	__raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL); +	writel_relaxed(evt, twd_base + TWD_TIMER_COUNTER); +	writel_relaxed(ctrl, twd_base + TWD_TIMER_CONTROL);  	return 0;  } @@ -82,8 +82,8 @@ static int twd_set_next_event(unsigned long evt,   */  static int twd_timer_ack(void)  { -	if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) { -		__raw_writel(1, twd_base + TWD_TIMER_INTSTAT); +	if (readl_relaxed(twd_base + TWD_TIMER_INTSTAT)) { +		writel_relaxed(1, twd_base + TWD_TIMER_INTSTAT);  		return 1;  	} @@ -211,15 +211,15 @@ static void twd_calibrate_rate(void)  		waitjiffies += 5;  				 /* enable, no interrupt or reload */ -		__raw_writel(0x1, twd_base + TWD_TIMER_CONTROL); +		writel_relaxed(0x1, twd_base + TWD_TIMER_CONTROL);  				 /* maximum value */ -		__raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER); +		writel_relaxed(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);  		while (get_jiffies_64() < waitjiffies)  			udelay(10); -		count = __raw_readl(twd_base + TWD_TIMER_COUNTER); +		count = readl_relaxed(twd_base + TWD_TIMER_COUNTER);  		twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); @@ -277,7 +277,7 @@ static void twd_timer_setup(void)  	 * bother with the below.  	 */  	if (per_cpu(percpu_setup_called, cpu)) { -		__raw_writel(0, twd_base + TWD_TIMER_CONTROL); +		writel_relaxed(0, twd_base + TWD_TIMER_CONTROL);  		clockevents_register_device(clk);  		enable_percpu_irq(clk->irq, 0);  		return; @@ -290,7 +290,7 @@ static void twd_timer_setup(void)  	 * The following is done once per CPU the first time .setup() is  	 * called.  	 */ -	__raw_writel(0, twd_base + TWD_TIMER_CONTROL); +	writel_relaxed(0, twd_base + TWD_TIMER_CONTROL);  	clk->name = "local_timer";  	clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index 41cf3cbf756d..2835d35234ca 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c @@ -10,7 +10,7 @@  #include <asm/suspend.h>  #include <asm/tlbflush.h> -extern int __cpu_suspend(unsigned long, int (*)(unsigned long)); +extern int __cpu_suspend(unsigned long, int (*)(unsigned long), u32 cpuid);  extern void cpu_resume_mmu(void);  #ifdef CONFIG_MMU @@ -21,6 +21,7 @@ extern void cpu_resume_mmu(void);  int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))  {  	struct mm_struct *mm = current->active_mm; +	u32 __mpidr = cpu_logical_map(smp_processor_id());  	int ret;  	if (!idmap_pgd) @@ -32,7 +33,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))  	 * resume (indicated by a zero return code), we need to switch  	 * back to the correct page tables.  	 */ -	ret = __cpu_suspend(arg, fn); +	ret = __cpu_suspend(arg, fn, __mpidr);  	if (ret == 0) {  		cpu_switch_mm(mm->pgd, mm);  		local_flush_bp_all(); @@ -44,7 +45,8 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))  #else  int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))  { -	return __cpu_suspend(arg, fn); +	u32 __mpidr = cpu_logical_map(smp_processor_id()); +	return __cpu_suspend(arg, fn, __mpidr);  }  #define	idmap_pgd	NULL  #endif diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 98aee3258398..829a96d4a179 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -11,25 +11,26 @@   *  This file contains the ARM-specific time handling details:   *  reading the RTC at bootup, etc...   */ +#include <linux/clk-provider.h> +#include <linux/clocksource.h> +#include <linux/errno.h>  #include <linux/export.h> -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/time.h>  #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/profile.h>  #include <linux/sched.h> +#include <linux/sched_clock.h>  #include <linux/smp.h> +#include <linux/time.h>  #include <linux/timex.h> -#include <linux/errno.h> -#include <linux/profile.h>  #include <linux/timer.h> -#include <linux/clocksource.h> -#include <linux/irq.h> -#include <linux/sched_clock.h> -#include <asm/thread_info.h> -#include <asm/stacktrace.h>  #include <asm/mach/arch.h>  #include <asm/mach/time.h> +#include <asm/stacktrace.h> +#include <asm/thread_info.h>  #if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || \      defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE) @@ -116,8 +117,12 @@ int __init register_persistent_clock(clock_access_fn read_boot,  void __init time_init(void)  { -	if (machine_desc->init_time) +	if (machine_desc->init_time) {  		machine_desc->init_time(); -	else +	} else { +#ifdef CONFIG_COMMON_CLK +		of_clk_init(NULL); +#endif  		clocksource_of_init(); +	}  } diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 8fcda140358d..dbf0923e8d76 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -34,6 +34,7 @@  #include <asm/unwind.h>  #include <asm/tls.h>  #include <asm/system_misc.h> +#include <asm/opcodes.h>  static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; @@ -341,15 +342,17 @@ void arm_notify_die(const char *str, struct pt_regs *regs,  int is_valid_bugaddr(unsigned long pc)  {  #ifdef CONFIG_THUMB2_KERNEL -	unsigned short bkpt; +	u16 bkpt; +	u16 insn = __opcode_to_mem_thumb16(BUG_INSTR_VALUE);  #else -	unsigned long bkpt; +	u32 bkpt; +	u32 insn = __opcode_to_mem_arm(BUG_INSTR_VALUE);  #endif  	if (probe_kernel_address((unsigned *)pc, bkpt))  		return 0; -	return bkpt == BUG_INSTR_VALUE; +	return bkpt == insn;  }  #endif @@ -402,25 +405,28 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)  	if (processor_mode(regs) == SVC_MODE) {  #ifdef CONFIG_THUMB2_KERNEL  		if (thumb_mode(regs)) { -			instr = ((u16 *)pc)[0]; +			instr = __mem_to_opcode_thumb16(((u16 *)pc)[0]);  			if (is_wide_instruction(instr)) { -				instr <<= 16; -				instr |= ((u16 *)pc)[1]; +				u16 inst2; +				inst2 = __mem_to_opcode_thumb16(((u16 *)pc)[1]); +				instr = __opcode_thumb32_compose(instr, inst2);  			}  		} else  #endif -			instr = *(u32 *) pc; +			instr = __mem_to_opcode_arm(*(u32 *) pc);  	} else if (thumb_mode(regs)) {  		if (get_user(instr, (u16 __user *)pc))  			goto die_sig; +		instr = __mem_to_opcode_thumb16(instr);  		if (is_wide_instruction(instr)) {  			unsigned int instr2;  			if (get_user(instr2, (u16 __user *)pc+1))  				goto die_sig; -			instr <<= 16; -			instr |= instr2; +			instr2 = __mem_to_opcode_thumb16(instr2); +			instr = __opcode_thumb32_compose(instr, instr2);  		}  	} else if (get_user(instr, (u32 __user *)pc)) { +		instr = __mem_to_opcode_arm(instr);  		goto die_sig;  	} @@ -850,7 +856,7 @@ static void __init kuser_init(void *vectors)  		memcpy(vectors + 0xfe0, vectors + 0xfe8, 4);  }  #else -static void __init kuser_init(void *vectors) +static inline void __init kuser_init(void *vectors)  {  }  #endif  | 
