diff --git a/MAINTAINERS b/MAINTAINERS index ac425b5b4a40..7c8392e1797d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -439,7 +439,7 @@ S: Maintained ARM/ATMEL AT91RM9200 ARM ARCHITECTURE P: Andrew Victor -M: andrew@sanpeople.com +M: linux@maxim.org.za L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) W: http://maxim.org.za/at91_26.html S: Maintained diff --git a/arch/arm/common/uengine.c b/arch/arm/common/uengine.c index 95c8508c29b7..117cab30bd36 100644 --- a/arch/arm/common/uengine.c +++ b/arch/arm/common/uengine.c @@ -374,8 +374,8 @@ static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c) u8 *ucode; int i; - gpr_a = kmalloc(128 * sizeof(u32), GFP_KERNEL); - gpr_b = kmalloc(128 * sizeof(u32), GFP_KERNEL); + gpr_a = kzalloc(128 * sizeof(u32), GFP_KERNEL); + gpr_b = kzalloc(128 * sizeof(u32), GFP_KERNEL); ucode = kmalloc(513 * 5, GFP_KERNEL); if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) { kfree(ucode); @@ -388,8 +388,6 @@ static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c) if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS) per_ctx_regs = 32; - memset(gpr_a, 0, sizeof(gpr_a)); - memset(gpr_b, 0, sizeof(gpr_b)); for (i = 0; i < 256; i++) { struct ixp2000_reg_value *r = c->initial_reg_values + i; u32 *bank; diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index d645897652c2..29dec080a604 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -339,16 +339,6 @@ __pabt_svc: str r1, [sp] @ save the "real" r0 copied @ from the exception stack -#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) -#ifndef CONFIG_MMU -#warning "NPTL on non MMU needs fixing" -#else - @ make sure our user space atomic helper is aborted - cmp r2, #TASK_SIZE - bichs r3, r3, #PSR_Z_BIT -#endif -#endif - @ @ We are now ready to fill in the remaining blanks on the stack: @ @@ -372,9 +362,25 @@ __pabt_svc: zero_fp .endm + .macro kuser_cmpxchg_check +#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) +#ifndef CONFIG_MMU +#warning "NPTL on non MMU needs fixing" +#else + @ Make sure our user space atomic helper is restarted + @ if it was interrupted in a critical region. Here we + @ perform a quick test inline since it should be false + @ 99.9999% of the time. The rest is done out of line. + cmp r2, #TASK_SIZE + blhs kuser_cmpxchg_fixup +#endif +#endif + .endm + .align 5 __dabt_usr: usr_entry + kuser_cmpxchg_check @ @ Call the processor-specific abort handler: @@ -404,6 +410,7 @@ __dabt_usr: .align 5 __irq_usr: usr_entry + kuser_cmpxchg_check #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off @@ -446,9 +453,9 @@ __und_usr: @ @ r0 - instruction @ -1: ldrt r0, [r4] adr r9, ret_from_exception adr lr, __und_usr_unknown +1: ldrt r0, [r4] @ @ fallthrough to call_fpe @ @@ -669,7 +676,7 @@ __kuser_helper_start: * * Clobbered: * - * the Z flag might be lost + * none * * Definition and user space usage example: * @@ -730,9 +737,6 @@ __kuser_memory_barrier: @ 0xffff0fa0 * * - This routine already includes memory barriers as needed. * - * - A failure might be transient, i.e. it is possible, although unlikely, - * that "failure" be returned even if *ptr == oldval. - * * For example, a user space atomic_add implementation could look like this: * * #define atomic_add(ptr, val) \ @@ -769,46 +773,62 @@ __kuser_cmpxchg: @ 0xffff0fc0 #elif __LINUX_ARM_ARCH__ < 6 - /* - * Theory of operation: - * - * We set the Z flag before loading oldval. If ever an exception - * occurs we can not be sure the loaded value will still be the same - * when the exception returns, therefore the user exception handler - * will clear the Z flag whenever the interrupted user code was - * actually from the kernel address space (see the usr_entry macro). - * - * The post-increment on the str is used to prevent a race with an - * exception happening just after the str instruction which would - * clear the Z flag although the exchange was done. - */ #ifdef CONFIG_MMU - teq ip, ip @ set Z flag - ldr ip, [r2] @ load current val - add r3, r2, #1 @ prepare store ptr - teqeq ip, r0 @ compare with oldval if still allowed - streq r1, [r3, #-1]! @ store newval if still allowed - subs r0, r2, r3 @ if r2 == r3 the str occured + + /* + * The only thing that can break atomicity in this cmpxchg + * implementation is either an IRQ or a data abort exception + * causing another process/thread to be scheduled in the middle + * of the critical sequence. To prevent this, code is added to + * the IRQ and data abort exception handlers to set the pc back + * to the beginning of the critical section if it is found to be + * within that critical section (see kuser_cmpxchg_fixup). + */ +1: ldr r3, [r2] @ load current val + subs r3, r3, r0 @ compare with oldval +2: streq r1, [r2] @ store newval if eq + rsbs r0, r3, #0 @ set return val and C flag + usr_ret lr + + .text +kuser_cmpxchg_fixup: + @ Called from kuser_cmpxchg_check macro. + @ r2 = address of interrupted insn (must be preserved). + @ sp = saved regs. r7 and r8 are clobbered. + @ 1b = first critical insn, 2b = last critical insn. + @ If r2 >= 1b and r2 <= 2b then saved pc_usr is set to 1b. + mov r7, #0xffff0fff + sub r7, r7, #(0xffff0fff - (0xffff0fc0 + (1b - __kuser_cmpxchg))) + subs r8, r2, r7 + rsbcss r8, r8, #(2b - 1b) + strcs r7, [sp, #S_PC] + mov pc, lr + .previous + #else #warning "NPTL on non MMU needs fixing" mov r0, #-1 adds r0, r0, #0 -#endif usr_ret lr +#endif #else #ifdef CONFIG_SMP mcr p15, 0, r0, c7, c10, 5 @ dmb #endif - ldrex r3, [r2] +1: ldrex r3, [r2] subs r3, r3, r0 strexeq r3, r1, [r2] + teqeq r3, #1 + beq 1b rsbs r0, r3, #0 + /* beware -- each __kuser slot must be 8 instructions max */ #ifdef CONFIG_SMP - mcr p15, 0, r0, c7, c10, 5 @ dmb -#endif + b __kuser_memory_barrier +#else usr_ret lr +#endif #endif @@ -829,7 +849,7 @@ __kuser_cmpxchg: @ 0xffff0fc0 * * Clobbered: * - * the Z flag might be lost + * none * * Definition and user space usage example: * diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 4764bd9ccee8..c34db4e868fa 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -327,7 +327,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) if ((instr & hook->instr_mask) == hook->instr_val && (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) { if (hook->fn(regs, instr) == 0) { - spin_unlock_irq(&undef_lock); + spin_unlock_irqrestore(&undef_lock, flags); return; } } @@ -509,7 +509,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) * existence. Don't ever use this from user code. */ case 0xfff0: - { + for (;;) { extern void do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs); unsigned long val; @@ -545,7 +545,6 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) up_read(&mm->mmap_sem); /* simulate a write access fault */ do_DataAbort(addr, 15 + (1 << 11), regs); - return -1; } #endif diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 0417c165d50d..9296833f91cc 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -435,7 +436,40 @@ void __init at91_add_device_nand(struct at91_nand_data *data) {} * TWI (i2c) * -------------------------------------------------------------------- */ -#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE) +/* + * Prefer the GPIO code since the TWI controller isn't robust + * (gets overruns and underruns under load) and can only issue + * repeated STARTs in one scenario (the driver doesn't yet handle them). + */ +#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE) + +static struct i2c_gpio_platform_data pdata = { + .sda_pin = AT91_PIN_PA25, + .sda_is_open_drain = 1, + .scl_pin = AT91_PIN_PA26, + .scl_is_open_drain = 1, + .udelay = 2, /* ~100 kHz */ +}; + +static struct platform_device at91rm9200_twi_device = { + .name = "i2c-gpio", + .id = -1, + .dev.platform_data = &pdata, +}; + +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) +{ + at91_set_GPIO_periph(AT91_PIN_PA25, 1); /* TWD (SDA) */ + at91_set_multi_drive(AT91_PIN_PA25, 1); + + at91_set_GPIO_periph(AT91_PIN_PA26, 1); /* TWCK (SCL) */ + at91_set_multi_drive(AT91_PIN_PA26, 1); + + i2c_register_board_info(0, devices, nr_devices); + platform_device_register(&at91rm9200_twi_device); +} + +#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE) static struct resource twi_resources[] = { [0] = { @@ -457,7 +491,7 @@ static struct platform_device at91rm9200_twi_device = { .num_resources = ARRAY_SIZE(twi_resources), }; -void __init at91_add_device_i2c(void) +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) { /* pins used for TWI interface */ at91_set_A_periph(AT91_PIN_PA25, 0); /* TWD */ @@ -466,10 +500,11 @@ void __init at91_add_device_i2c(void) at91_set_A_periph(AT91_PIN_PA26, 0); /* TWCK */ at91_set_multi_drive(AT91_PIN_PA26, 1); + i2c_register_board_info(0, devices, nr_devices); platform_device_register(&at91rm9200_twi_device); } #else -void __init at91_add_device_i2c(void) {} +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {} #endif diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index ffd3154c1e54..3091bf47d8c9 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -352,7 +353,41 @@ void __init at91_add_device_nand(struct at91_nand_data *data) {} * TWI (i2c) * -------------------------------------------------------------------- */ -#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE) +/* + * Prefer the GPIO code since the TWI controller isn't robust + * (gets overruns and underruns under load) and can only issue + * repeated STARTs in one scenario (the driver doesn't yet handle them). + */ + +#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE) + +static struct i2c_gpio_platform_data pdata = { + .sda_pin = AT91_PIN_PA23, + .sda_is_open_drain = 1, + .scl_pin = AT91_PIN_PA24, + .scl_is_open_drain = 1, + .udelay = 2, /* ~100 kHz */ +}; + +static struct platform_device at91sam9260_twi_device = { + .name = "i2c-gpio", + .id = -1, + .dev.platform_data = &pdata, +}; + +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) +{ + at91_set_GPIO_periph(AT91_PIN_PA23, 1); /* TWD (SDA) */ + at91_set_multi_drive(AT91_PIN_PA23, 1); + + at91_set_GPIO_periph(AT91_PIN_PA24, 1); /* TWCK (SCL) */ + at91_set_multi_drive(AT91_PIN_PA24, 1); + + i2c_register_board_info(0, devices, nr_devices); + platform_device_register(&at91sam9260_twi_device); +} + +#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE) static struct resource twi_resources[] = { [0] = { @@ -374,7 +409,7 @@ static struct platform_device at91sam9260_twi_device = { .num_resources = ARRAY_SIZE(twi_resources), }; -void __init at91_add_device_i2c(void) +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) { /* pins used for TWI interface */ at91_set_A_periph(AT91_PIN_PA23, 0); /* TWD */ @@ -383,10 +418,11 @@ void __init at91_add_device_i2c(void) at91_set_A_periph(AT91_PIN_PA24, 0); /* TWCK */ at91_set_multi_drive(AT91_PIN_PA24, 1); + i2c_register_board_info(0, devices, nr_devices); platform_device_register(&at91sam9260_twi_device); } #else -void __init at91_add_device_i2c(void) {} +void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {} #endif diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 3576595b4941..64979a9023c2 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -14,7 +14,9 @@ #include #include +#include +#include #include