MIPS: allow GIC clockevent device config from other CPUs
authorPaul Burton <paul.burton@imgtec.com>
Wed, 5 Mar 2014 11:35:53 +0000 (11:35 +0000)
committerPaul Burton <paul.burton@imgtec.com>
Fri, 2 May 2014 15:39:11 +0000 (16:39 +0100)
This patch allows the GIC clockevent device for a CPU to be configured
by another CPU. This makes GIC clockevent devices suitable for use as
the tick broadcast device, where formerly the GIC timer local to the
configuring CPU would have been configured incorrectly.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
arch/mips/include/asm/gic.h
arch/mips/kernel/cevt-gic.c
arch/mips/kernel/irq-gic.c

index 0827166905899db5c49042d0b2fa089810d46ef4..10f6a99f92c23a5dba20a54a7b5f42c2d606133c 100644 (file)
@@ -380,6 +380,7 @@ extern unsigned int gic_compare_int (void);
 extern cycle_t gic_read_count(void);
 extern cycle_t gic_read_compare(void);
 extern void gic_write_compare(cycle_t cnt);
+extern void gic_write_cpu_compare(cycle_t cnt, int cpu);
 extern void gic_send_ipi(unsigned int intr);
 extern unsigned int plat_ipi_call_int_xlate(unsigned int);
 extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
index 925bae55906705b7957ab9c367245a0d7872af3c..6093716980b95d9903ab240ae32bdd918c393f3b 100644 (file)
@@ -26,7 +26,7 @@ static int gic_next_event(unsigned long delta, struct clock_event_device *evt)
 
        cnt = gic_read_count();
        cnt += (u64)delta;
-       gic_write_compare(cnt);
+       gic_write_cpu_compare(cnt, cpumask_first(evt->cpumask));
        res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0;
        return res;
 }
index 8520dad6d4e3c069d19926c04963c4472d4cc9e9..88e4c323382c14fadd228db1fc5c6f7476d5c55c 100644 (file)
@@ -54,6 +54,21 @@ void gic_write_compare(cycle_t cnt)
                                (int)(cnt & 0xffffffff));
 }
 
+void gic_write_cpu_compare(cycle_t cnt, int cpu)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu);
+       GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI),
+                               (int)(cnt >> 32));
+       GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO),
+                               (int)(cnt & 0xffffffff));
+
+       local_irq_restore(flags);
+}
+
 cycle_t gic_read_compare(void)
 {
        unsigned int hi, lo;