summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s5pv310
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s5pv310')
-rw-r--r--arch/arm/mach-s5pv310/cpu.c6
-rw-r--r--arch/arm/mach-s5pv310/hotplug.c44
-rw-r--r--arch/arm/mach-s5pv310/include/mach/smp.h7
-rw-r--r--arch/arm/mach-s5pv310/platsmp.c68
-rw-r--r--arch/arm/mach-s5pv310/time.c6
5 files changed, 43 insertions, 88 deletions
diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-s5pv310/cpu.c
index 82ce4aa6d61a..72ab289e7816 100644
--- a/arch/arm/mach-s5pv310/cpu.c
+++ b/arch/arm/mach-s5pv310/cpu.c
@@ -24,8 +24,6 @@
#include <mach/regs-irq.h>
-void __iomem *gic_cpu_base_addr;
-
extern int combiner_init(unsigned int combiner_nr, void __iomem *base,
unsigned int irq_start);
extern void combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq);
@@ -122,9 +120,7 @@ void __init s5pv310_init_irq(void)
{
int irq;
- gic_cpu_base_addr = S5P_VA_GIC_CPU;
- gic_dist_init(0, S5P_VA_GIC_DIST, IRQ_LOCALTIMER);
- gic_cpu_init(0, S5P_VA_GIC_CPU);
+ gic_init(0, IRQ_LOCALTIMER, S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-s5pv310/hotplug.c
index 03652c3605f6..afa5392d9fc0 100644
--- a/arch/arm/mach-s5pv310/hotplug.c
+++ b/arch/arm/mach-s5pv310/hotplug.c
@@ -13,14 +13,11 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/smp.h>
-#include <linux/completion.h>
#include <asm/cacheflush.h>
extern volatile int pen_release;
-static DECLARE_COMPLETION(cpu_killed);
-
static inline void cpu_enter_lowpower(void)
{
unsigned int v;
@@ -33,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");
}
@@ -49,17 +46,17 @@ 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");
}
-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
@@ -83,22 +80,19 @@ 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)++;
}
}
int platform_cpu_kill(unsigned int cpu)
{
- return wait_for_completion_timeout(&cpu_killed, 5000);
+ return 1;
}
/*
@@ -108,30 +102,22 @@ 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
-
- printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
- complete(&cpu_killed);
+ 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/include/mach/smp.h b/arch/arm/mach-s5pv310/include/mach/smp.h
index b7ec252384f4..393ccbd52c4a 100644
--- a/arch/arm/mach-s5pv310/include/mach/smp.h
+++ b/arch/arm/mach-s5pv310/include/mach/smp.h
@@ -7,16 +7,13 @@
#define ASM_ARCH_SMP_H __FILE__
#include <asm/hardware/gic.h>
-#include <asm/smp_mpidr.h>
-
-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 d357c198edee..34093b069f67 100644
--- a/arch/arm/mach-s5pv310/platsmp.c
+++ b/arch/arm/mach-s5pv310/platsmp.c
@@ -22,7 +22,6 @@
#include <linux/io.h>
#include <asm/cacheflush.h>
-#include <asm/localtimer.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>
@@ -38,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);
@@ -47,21 +59,18 @@ 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, gic_cpu_base_addr);
+ 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;
- smp_wmb();
+ write_pen_release(-1);
/*
* Synchronise with the boot thread.
@@ -88,16 +97,14 @@ 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
* 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)) {
@@ -130,13 +137,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 "
@@ -149,18 +149,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,25 +160,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-s5pv310/time.c b/arch/arm/mach-s5pv310/time.c
index 01b012ad1bfd..b262d4615331 100644
--- a/arch/arm/mach-s5pv310/time.c
+++ b/arch/arm/mach-s5pv310/time.c
@@ -211,7 +211,6 @@ struct clocksource pwm_clocksource = {
.rating = 250,
.read = s5pv310_pwm4_read,
.mask = CLOCKSOURCE_MASK(32),
- .shift = 20,
.flags = CLOCK_SOURCE_IS_CONTINUOUS ,
};
@@ -230,10 +229,7 @@ static void __init s5pv310_clocksource_init(void)
s5pv310_pwm_init(4, ~0);
s5pv310_pwm_start(4, 1);
- pwm_clocksource.mult =
- clocksource_khz2mult(clock_rate/1000, pwm_clocksource.shift);
-
- if (clocksource_register(&pwm_clocksource))
+ if (clocksource_register_hz(&pwm_clocksource, clock_rate))
panic("%s: can't register clocksource\n", pwm_clocksource.name);
}