From 2a98beb6390aef8fad85103ea25b3b1ace8015b5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 9 Nov 2005 10:50:29 +0000 Subject: [ARM SMP] Add local timer support for Realview MPcore Add platform specific parts for local timer support for the Realview board. Signed-off-by: Russell King --- arch/arm/Kconfig | 2 +- arch/arm/mach-realview/Makefile | 1 + arch/arm/mach-realview/core.c | 2 +- arch/arm/mach-realview/localtimer.c | 130 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-realview/platsmp.c | 5 ++ 5 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-realview/localtimer.c (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3bfef0934c9d..ec77721507cb 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -358,7 +358,7 @@ config HOTPLUG_CPU config LOCAL_TIMERS bool "Use local timer interrupts" - depends on SMP && n + depends on SMP && REALVIEW_MPCORE default y help Enable support for local timers on SMP platforms, rather then the diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile index 011a85c10627..a6a40dac26a9 100644 --- a/arch/arm/mach-realview/Makefile +++ b/arch/arm/mach-realview/Makefile @@ -5,3 +5,4 @@ obj-y := core.o clock.o obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 4ea60d8b6e36..e2c6fa23d3cd 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -550,7 +550,7 @@ static irqreturn_t realview_timer_interrupt(int irq, void *dev_id, struct pt_reg timer_tick(regs); -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) smp_send_timer(); update_process_times(user_mode(regs)); #endif diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c new file mode 100644 index 000000000000..5e917e37d095 --- /dev/null +++ b/arch/arm/mach-realview/localtimer.c @@ -0,0 +1,130 @@ +/* + * linux/arch/arm/mach-realview/localtimer.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 +#include + +#include +#include +#include +#include +#include +#include + +#include "core.h" + +#define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \ + ((cpu) * REALVIEW_TWD_SIZE)) + +static unsigned long mpcore_timer_rate; + +/* + * local_timer_ack: checks for a local timer interrupt. + * + * If a local timer interrupt has occured, acknowledge and return 1. + * Otherwise, return 0. + */ +int local_timer_ack(void) +{ + void __iomem *base = TWD_BASE(smp_processor_id()); + + if (__raw_readl(base + TWD_TIMER_INTSTAT)) { + __raw_writel(1, base + TWD_TIMER_INTSTAT); + return 1; + } + + return 0; +} + +void __cpuinit local_timer_setup(unsigned int cpu) +{ + void __iomem *base = TWD_BASE(cpu); + unsigned int load, offset; + u64 waitjiffies; + unsigned int count; + + /* + * If this is the first time round, we need to work out how fast + * the timer ticks + */ + if (mpcore_timer_rate == 0) { + printk("Calibrating local timer... "); + + /* Wait for a tick to start */ + waitjiffies = get_jiffies_64() + 1; + + while (get_jiffies_64() < waitjiffies) + udelay(10); + + /* OK, now the tick has started, let's get the timer going */ + waitjiffies += 5; + + /* enable, no interrupt or reload */ + __raw_writel(0x1, base + TWD_TIMER_CONTROL); + + /* maximum value */ + __raw_writel(0xFFFFFFFFU, base + TWD_TIMER_COUNTER); + + while (get_jiffies_64() < waitjiffies) + udelay(10); + + count = __raw_readl(base + TWD_TIMER_COUNTER); + + mpcore_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); + + printk("%lu.%02luMHz.\n", mpcore_timer_rate / 1000000, + (mpcore_timer_rate / 100000) % 100); + } + + load = mpcore_timer_rate / HZ; + + __raw_writel(load, base + TWD_TIMER_LOAD); + __raw_writel(0x7, base + TWD_TIMER_CONTROL); + + /* + * Now maneuver our local tick into the right part of the jiffy. + * Start by working out where within the tick our local timer + * interrupt should go. + */ + offset = ((mpcore_timer_rate / HZ) / (NR_CPUS + 1)) * (cpu + 1); + + /* + * gettimeoffset() will return a number of us since the last tick. + * Convert this number of us to a local timer tick count. + * Be careful of integer overflow whilst keeping maximum precision. + * + * with HZ=100 and 1MHz (fpga) ~ 1GHz processor: + * load = 1 ~ 10,000 + * mpcore_timer_rate/10000 = 100 ~ 100,000 + * + * so the multiply value will be less than 10^9 always. + */ + load = (system_timer->offset() * (mpcore_timer_rate / 10000)) / 100; + + /* Add on our offset to get the load value */ + load = (load + offset) % (mpcore_timer_rate / HZ); + + __raw_writel(load, base + TWD_TIMER_COUNTER); + + /* Make sure our local interrupt controller has this enabled */ + __raw_writel(1 << IRQ_LOCALTIMER, + __io_address(REALVIEW_GIC_DIST_BASE) + GIC_DIST_ENABLE_SET); +} + +/* + * take a local timer down + */ +void __cpuexit local_timer_stop(unsigned int cpu) +{ + __raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL); +} diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index 09b35f62247a..0c7d4ac9a7b3 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -174,6 +174,11 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (max_cpus > ncores) max_cpus = ncores; + /* + * Enable the local timer for primary CPU + */ + local_timer_setup(cpu); + /* * Initialise the possible/present maps. * cpu_possible_map describes the set of CPUs which may be present -- cgit v1.2.3-70-g09d2 From 97a63ecff4bd06da5d8feb8c0394a4d020f2d34d Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 9 Nov 2005 13:50:57 +0000 Subject: [ARM SMP] Add CPU hotplug support for Realview MPcore Add platform specific parts for hotplug CPU support for the Realview board. Signed-off-by: Russell King --- arch/arm/mach-realview/Makefile | 1 + arch/arm/mach-realview/hotplug.c | 138 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 arch/arm/mach-realview/hotplug.c (limited to 'arch') diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile index a6a40dac26a9..36e76ba937fc 100644 --- a/arch/arm/mach-realview/Makefile +++ b/arch/arm/mach-realview/Makefile @@ -5,4 +5,5 @@ obj-y := core.o clock.o obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.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-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c new file mode 100644 index 000000000000..09748cbcd10e --- /dev/null +++ b/arch/arm/mach-realview/hotplug.c @@ -0,0 +1,138 @@ +/* + * 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 DECLARE_COMPLETION(cpu_killed); + +static inline void cpu_enter_lowpower(void) +{ + unsigned int v; + + asm volatile( "mcr p15, 0, %1, c7, c14, 0\n" + " 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, #0x20\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) + : "cc"); +} + +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" + " 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) + : + : "cc"); +} + +static inline void platform_do_lowpower(unsigned int cpu) +{ + /* + * 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 + * + * 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 + */ +#ifdef DEBUG + printk("CPU%u: spurious wakeup call\n", cpu); +#endif + } +} + +int platform_cpu_kill(unsigned int cpu) +{ + return wait_for_completion_timeout(&cpu_killed, 5000); +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +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 + + printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); + complete(&cpu_killed); + + /* + * we're ready for shutdown now, so do it + */ + cpu_enter_lowpower(); + platform_do_lowpower(cpu); + + /* + * bring this CPU back into the world of cache + * coherency, and then restore interrupts + */ + cpu_leave_lowpower(); +} + +int mach_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; +} -- cgit v1.2.3-70-g09d2 From 8dd523118bfbcaca5b67923ff6ee546e04a4db64 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 9 Nov 2005 14:05:30 +0000 Subject: [ARM] 3136/1: Anubis - fix map_desc initialisers Patch from Ben Dooks Fix the map_desc initialisers for the Simtec Anubis board to match the new initialiser scheme. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/mach-anubis.c | 51 ++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c index 8390b685c2b6..0f81fc0c2f7f 100644 --- a/arch/arm/mach-s3c2410/mach-anubis.c +++ b/arch/arm/mach-s3c2410/mach-anubis.c @@ -56,8 +56,16 @@ static struct map_desc anubis_iodesc[] __initdata = { /* ISA IO areas */ - { (u32)S3C24XX_VA_ISA_BYTE, 0x0, SZ_16M, MT_DEVICE }, - { (u32)S3C24XX_VA_ISA_WORD, 0x0, SZ_16M, MT_DEVICE }, + { + .virtual = (u32)S3C24XX_VA_ISA_BYTE, + .pfn = __phys_to_pfn(0x0), + .length = SZ_4M, + .type = MT_DEVICE + }, { + .virtual = (u32)S3C24XX_VA_ISA_WORD, + .pfn = __phys_to_pfn(0x0), + .length = SZ_4M, MT_DEVICE + }, /* we could possibly compress the next set down into a set of smaller tables * pagetables, but that would mean using an L2 section, and it still means @@ -66,16 +74,41 @@ static struct map_desc anubis_iodesc[] __initdata = { /* CPLD control registers */ - { (u32)ANUBIS_VA_CTRL1, ANUBIS_PA_CTRL1, SZ_4K, MT_DEVICE }, - { (u32)ANUBIS_VA_CTRL2, ANUBIS_PA_CTRL2, SZ_4K, MT_DEVICE }, + { + .virtual = (u32)ANUBIS_VA_CTRL1, + .pfn = __phys_to_pfn(ANUBIS_PA_CTRL1), + .length = SZ_4K, + .type = MT_DEVICE + }, { + .virtual = (u32)ANUBIS_VA_CTRL2, + .pfn = __phys_to_pfn(ANUBIS_PA_CTRL2), + .length = SZ_4K, + .type =MT_DEVICE + }, /* IDE drives */ - { (u32)ANUBIS_IDEPRI, S3C2410_CS3, SZ_1M, MT_DEVICE }, - { (u32)ANUBIS_IDEPRIAUX, S3C2410_CS3+(1<<26), SZ_1M, MT_DEVICE }, - - { (u32)ANUBIS_IDESEC, S3C2410_CS4, SZ_1M, MT_DEVICE }, - { (u32)ANUBIS_IDESECAUX, S3C2410_CS4+(1<<26), SZ_1M, MT_DEVICE }, + { + .virtual = (u32)ANUBIS_IDEPRI, + .pfn = __phys_to_pfn(S3C2410_CS3), + .length = SZ_1M, + .type = MT_DEVICE + }, { + .virtual = (u32)ANUBIS_IDEPRIAUX, + .pfn = __phys_to_pfn(S3C2410_CS3+(1<<26)), + .length = SZ_1M, + .type = MT_DEVICE + }, { + .virtual = (u32)ANUBIS_IDESEC, + .pfn = __phys_to_pfn(S3C2410_CS4), + .length = SZ_1M, + .type = MT_DEVICE + }, { + .virtual = (u32)ANUBIS_IDESECAUX, + .pfn = __phys_to_pfn(S3C2410_CS4+(1<<26)), + .length = SZ_1M, + .type = MT_DEVICE + }, }; #define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK -- cgit v1.2.3-70-g09d2 From ff6ffa82fe122ecda457bb10dbab7b0c08ee3803 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 9 Nov 2005 14:05:31 +0000 Subject: [ARM] 3137/1: RX3715 - fix map_desc initialiser Patch from Ben Dooks Change the initialiser for the map_desc for the iPAQ RX3715 to use the new pfn initialiser, and also reduce the amount of ISA space mapped (we only need to stop any ISA IO writes OOPsing the system, so do not need >1Mbyte of space) Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/mach-rx3715.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c index 24d69019a843..f8d86d1e16b6 100644 --- a/arch/arm/mach-s3c2410/mach-rx3715.c +++ b/arch/arm/mach-s3c2410/mach-rx3715.c @@ -56,8 +56,17 @@ static struct map_desc rx3715_iodesc[] __initdata = { /* dump ISA space somewhere unused */ - { (u32)S3C24XX_VA_ISA_WORD, S3C2410_CS3, SZ_16M, MT_DEVICE }, - { (u32)S3C24XX_VA_ISA_BYTE, S3C2410_CS3, SZ_16M, MT_DEVICE }, + { + .virtual = (u32)S3C24XX_VA_ISA_WORD, + .pfn = __phys_to_pfn(S3C2410_CS3), + .length = SZ_1M, + .type = MT_DEVICE, + }, { + .virtual = (u32)S3C24XX_VA_ISA_BYTE, + .pfn = __phys_to_pfn(S3C2410_CS3), + .length = SZ_1M, + .type = MT_DEVICE, + }, }; -- cgit v1.2.3-70-g09d2 From cbe69f95fa7ffc4604622cd4f7efd56ed10999fe Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 9 Nov 2005 14:05:31 +0000 Subject: [ARM] 3138/1: SMDK2440 - fix map_desc initialisation (and ISA memory space) Patch from Ben Dooks Fix the map_desc initialisers for the SMDK2440 machine to use the new .pfn method, and at the same time making the differntiation between ISA IO and Memory space accesses Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/mach-smdk2440.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c index d666c621ad06..4e31118533e6 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2440.c +++ b/arch/arm/mach-s3c2410/mach-smdk2440.c @@ -58,8 +58,27 @@ static struct map_desc smdk2440_iodesc[] __initdata = { /* ISA IO Space map (memory space selected by A24) */ - { (u32)S3C24XX_VA_ISA_WORD, S3C2410_CS2, SZ_16M, MT_DEVICE }, - { (u32)S3C24XX_VA_ISA_BYTE, S3C2410_CS2, SZ_16M, MT_DEVICE }, + { + .virtual = (u32)S3C24XX_VA_ISA_WORD, + .pfn = __phys_to_pfn(S3C2410_CS2), + .length = 0x10000, + .type = MT_DEVICE, + }, { + .virtual = (u32)S3C24XX_VA_ISA_WORD + 0x10000, + .pfn = __phys_to_pfn(S3C2410_CS2 + (1<<24)), + .length = SZ_4M, + .type = MT_DEVICE, + }, { + .virtual = (u32)S3C24XX_VA_ISA_BYTE, + .pfn = __phys_to_pfn(S3C2410_CS2), + .length = 0x10000, + .type = MT_DEVICE, + }, { + .virtual = (u32)S3C24XX_VA_ISA_BYTE + 0x10000, + .pfn = __phys_to_pfn(S3C2410_CS2 + (1<<24)), + .length = SZ_4M, + .type = MT_DEVICE, + } }; #define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK -- cgit v1.2.3-70-g09d2 From c906107bb72b7bd5ecfc98cc807bdb8f34d17501 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 9 Nov 2005 14:09:31 +0000 Subject: [ARM] 3100/1: simplify a pointer computation Patch from Nicolas Pitre Looks clearer this way. Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/kernel/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index ba298277becd..07fb744f8a68 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -355,7 +355,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long stack_start, struct thread_info *thread = p->thread_info; struct pt_regs *childregs; - childregs = ((struct pt_regs *)((unsigned long)thread + THREAD_START_SP)) - 1; + childregs = (void *)thread + THREAD_START_SP - sizeof(*regs); *childregs = *regs; childregs->ARM_r0 = 0; childregs->ARM_sp = stack_start; -- cgit v1.2.3-70-g09d2 From 59d1ff3bfb56d9b8cf3ec864857e6a4dfd9d2dba Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 9 Nov 2005 15:04:22 +0000 Subject: [ARM] Clean up save_and_disable_irqs macro and allow use of ARMv6 CPSID save_and_disable_irqs does not need to use mov + msr (which was introduced to work around a documentation bug which was propagated into binutils.) Use msr with an immediate constant, and if we're building for ARMv6 or later, use the new CPSID instruction. Signed-off-by: Russell King --- arch/arm/lib/bitops.h | 4 ++-- include/asm-arm/assembler.h | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/lib/bitops.h b/arch/arm/lib/bitops.h index f35d91fbe117..b8c14e936697 100644 --- a/arch/arm/lib/bitops.h +++ b/arch/arm/lib/bitops.h @@ -34,7 +34,7 @@ and r2, r0, #7 mov r3, #1 mov r3, r3, lsl r2 - save_and_disable_irqs ip, r2 + save_and_disable_irqs ip ldrb r2, [r1, r0, lsr #3] \instr r2, r2, r3 strb r2, [r1, r0, lsr #3] @@ -54,7 +54,7 @@ add r1, r1, r0, lsr #3 and r3, r0, #7 mov r0, #1 - save_and_disable_irqs ip, r2 + save_and_disable_irqs ip ldrb r2, [r1] tst r2, r0, lsl r3 \instr r2, r2, r0, lsl r3 diff --git a/include/asm-arm/assembler.h b/include/asm-arm/assembler.h index 69a28f96bee2..f31ac92b6c7f 100644 --- a/include/asm-arm/assembler.h +++ b/include/asm-arm/assembler.h @@ -83,10 +83,13 @@ * Save the current IRQ state and disable IRQs. Note that this macro * assumes FIQs are enabled, and that the processor is in SVC mode. */ - .macro save_and_disable_irqs, oldcpsr, temp + .macro save_and_disable_irqs, oldcpsr mrs \oldcpsr, cpsr - mov \temp, #PSR_I_BIT | MODE_SVC - msr cpsr_c, \temp +#if __LINUX_ARM_ARCH__ >= 6 + cpsid i +#else + msr cpsr_c, #PSR_I_BIT | MODE_SVC +#endif .endm /* -- cgit v1.2.3-70-g09d2