diff options
Diffstat (limited to 'arch/arm/mach-ux500/platsmp.c')
-rw-r--r-- | arch/arm/mach-ux500/platsmp.c | 108 |
1 files changed, 54 insertions, 54 deletions
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c index 9e4c678de785..4fff4d408417 100644 --- a/arch/arm/mach-ux500/platsmp.c +++ b/arch/arm/mach-ux500/platsmp.c @@ -18,39 +18,57 @@ #include <linux/io.h> #include <asm/cacheflush.h> -#include <asm/localtimer.h> #include <asm/smp_scu.h> #include <mach/hardware.h> +#include <mach/setup.h> /* * control for which core is the next to come out of the secondary * boot "holding pen" */ -volatile int __cpuinitdata pen_release = -1; +volatile int pen_release = -1; -static unsigned int __init get_core_count(void) +/* + * 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) { - return scu_get_core_count(__io_address(UX500_SCU_BASE)); + 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 (cpu_is_u5500()) + return __io_address(U5500_SCU_BASE); + else if (cpu_is_u8500()) + return __io_address(U8500_SCU_BASE); + else + ux500_unknown_soc(); + + return NULL; } 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 * for us: do so */ - gic_cpu_init(0, __io_address(UX500_GIC_CPU_BASE)); + gic_secondary_init(0); /* * 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. @@ -74,11 +92,9 @@ 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)); + smp_cross_call(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { @@ -97,8 +113,14 @@ 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; + void __iomem *backupram; + + if (cpu_is_u5500()) + backupram = __io_address(U5500_BACKUPRAM0_BASE); + else if (cpu_is_u8500()) + backupram = __io_address(U8500_BACKUPRAM0_BASE); + else + ux500_unknown_soc(); /* * write the address of secondary startup into the backup ram register @@ -106,15 +128,13 @@ static void __init wakeup_secondary(void) * backup ram register at offset 0x1FF0, which is what boot rom code * is waiting for. This would wake up the secondary core from WFE */ -#define U8500_CPU1_JUMPADDR_OFFSET 0x1FF4 +#define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4 __raw_writel(virt_to_phys(u8500_secondary_startup), - __io_address(UX500_BACKUPRAM0_BASE) + - U8500_CPU1_JUMPADDR_OFFSET); + backupram + UX500_CPU1_JUMPADDR_OFFSET); -#define U8500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 +#define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0 __raw_writel(0xA1FEED01, - __io_address(UX500_BACKUPRAM0_BASE) + - U8500_CPU1_WAKEMAGIC_OFFSET); + backupram + UX500_CPU1_WAKEMAGIC_OFFSET); /* make sure write buffer is drained */ mb(); @@ -126,40 +146,27 @@ static void __init wakeup_secondary(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; - 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; + ncores = scu_base ? scu_get_core_count(scu_base) : 1; /* sanity check */ - if (ncores == 0) { - printk(KERN_ERR - "U8500: strange CM count of 0? Default to 1\n"); - 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; } - smp_store_cpu_info(cpu); + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); +} - /* - * are we trying to boot more cores than exist? - */ - if (max_cpus > ncores) - max_cpus = ncores; +void __init platform_smp_prepare_cpus(unsigned int max_cpus) +{ + int i; /* * Initialise the present map, which describes the set of CPUs @@ -168,13 +175,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(scu_base_addr()); + wakeup_secondary(); } |