ARM: gic: Consolidate PPI handling with request_percpu_irq() API

The commit 292b293 creates the MSM boot failures, so squash
the commit 28af690 with it to avoid such failures. The commit ddd847
and 0c1991 are required to keep the watchdog and Copper targets working.

commit 292b293ceef2eda1f96f0c90b96e954d7bdabd1c
Author: Marc Zyngier <marc.zyngier@arm.com>
Date:   Wed Jul 20 16:24:14 2011 +0100

    ARM: gic: consolidate PPI handling

    PPI handling is a bit of an odd beast. It uses its own low level
    handling code and is hardwired to the local timers (hence lacking
    a registration interface).

    Instead, switch the low handling to the normal SPI handling code.
    PPIs are handled by the handle_percpu_devid_irq flow.

    This also allows the removal of some duplicated code.

    Cc: Kukjin Kim <kgene.kim@samsung.com>
    Cc: David Brown <davidb@codeaurora.org>
    Cc: Bryan Huntsman <bryanh@codeaurora.org>
    Cc: Tony Lindgren <tony@atomide.com>
    Cc: Paul Mundt <lethal@linux-sh.org>
    Cc: Magnus Damm <magnus.damm@gmail.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Acked-by: David Brown <davidb@codeaurora.org>
    Tested-by: David Brown <davidb@codeaurora.org>
    Tested-by: Shawn Guo <shawn.guo@linaro.org>
    Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

commit 28af690a284dfcb627bd69d0963db1c0f412cb8c
Author: Marc Zyngier <marc.zyngier@arm.com>
Date:   Fri Jul 22 12:52:37 2011 +0100

    ARM: gic, local timers: use the request_percpu_irq() interface

    This patch remove the hardcoded link between local timers and PPIs,
    and convert the PPI users (TWD, MCT and MSM timers) to the new
    *_percpu_irq interface. Also some collateral cleanup
    (local_timer_ack() is gone, and the interrupt handler is strictly
    private to each driver).

    PPIs are now useable for more than just the local timers.

    Additional testing by David Brown (msm8250 and msm8660) and
    Shawn Guo (imx6q).

    Cc: David Brown <davidb@codeaurora.org>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Acked-by: David Brown <davidb@codeaurora.org>
    Tested-by: David Brown <davidb@codeaurora.org>
    Tested-by: Shawn Guo <shawn.guo@linaro.org>
    Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

commit ddd8478d68f8cf75ee9771667c0cbe2a9d1caeb9
Author: Trilok Soni <tsoni@codeaurora.org>
Date:   Tue Dec 6 00:56:01 2011 +0530

    msm: watchdog: Use request_percpu_irq() interface

    Change-Id: I7c319344f6a7f7a7c70682ac87f5c385e56d130c
    Signed-off-by: Trilok Soni <tsoni@codeaurora.org>
    Signed-off-by: Rohit Vaswani <rvaswani@codeaurora.org>

commit 0c19915e092214a4c17a9920c4c1f3d78610217d
Author: Sathish Ambley <sambley@codeaurora.org>
Date:   Fri Dec 9 17:07:37 2011 +0530

    arm: arch_timer: Use request_percpu_irq() API

    Change-Id: Iee9b218d538f315cd884a47d95bcc0dcc49b0fe1
    Signed-off-by: Sathish Ambley <sambley@codeaurora.org>

Change-Id: I7bbba706b1f2e55814be5891ed76063725c2bfb1
Signed-off-by: Ravi Kumar <kumarrav@codeaurora.org>
[tsoni@codeaurora.org: MSM specific fixes]
Signed-off-by: Trilok Soni <tsoni@codeaurora.org>
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 0cd27bc..5070470 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -25,7 +25,6 @@
 #include <asm/sched_clock.h>
 #include <asm/hardware/gic.h>
 
-static struct irqaction arch_irqaction[2];
 static unsigned long arch_timer_rate;
 static int arch_timer_ppi;
 static int arch_timer_ppi2;
@@ -151,9 +150,9 @@
 	clockevents_config_and_register(clk, arch_timer_rate,
 					0xf, 0x7fffffff);
 
-	gic_enable_ppi(arch_timer_ppi);
+	enable_percpu_irq(arch_timer_ppi, 0);
 	if (arch_timer_ppi2 > 0)
-		gic_enable_ppi(arch_timer_ppi2);
+		enable_percpu_irq(arch_timer_ppi2, 0);
 }
 
 /* Is the optional system timer available? */
@@ -256,11 +255,9 @@
 	struct clock_event_device *clk = data;
 	pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
 		 clk->irq, smp_processor_id());
-	if (!smp_processor_id()) {
-		remove_irq(arch_timer_ppi, &arch_irqaction[0]);
-		if (arch_timer_ppi2 > 0)
-			remove_irq(arch_timer_ppi2, &arch_irqaction[1]);
-	}
+	disable_percpu_irq(arch_timer_ppi);
+	if (arch_timer_ppi2 > 0)
+		disable_percpu_irq(arch_timer_ppi2);
 	arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
 }
 
@@ -291,8 +288,6 @@
 
 int __init arch_timer_register(struct resource *res, int res_nr)
 {
-	struct irqaction *irqa;
-	unsigned int cpu = smp_processor_id();
 	int err;
 
 	if (!res_nr || res[0].start < 0 || !(res[0].flags & IORESOURCE_IRQ))
@@ -319,34 +314,24 @@
 	set_delay_fn(read_current_timer_delay_loop);
 #endif
 
-	irqa = &arch_irqaction[0];
-	irqa->name = "arch_sys_timer";
-	irqa->flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH;
-	irqa->handler = arch_timer_handler;
-	irqa->dev_id = per_cpu_ptr(arch_timer_evt, cpu);
-	irqa->irq = arch_timer_ppi;
-	err = setup_irq(arch_timer_ppi, irqa);
+	err = request_percpu_irq(arch_timer_ppi, arch_timer_handler,
+				"arch_sys_timer", arch_timer_evt);
 	if (err) {
 		pr_err("%s: can't register interrupt %d (%d)\n",
-		       irqa->name, irqa->irq, err);
+		       "arch_sys_timer", arch_timer_ppi, err);
 		return err;
 	}
 
 	if (arch_timer_ppi2 > 0) {
-		irqa = &arch_irqaction[1];
-		irqa->name = "arch_sys_timer";
-		irqa->flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH;
-		irqa->handler = arch_timer_handler;
-		irqa->dev_id = per_cpu_ptr(arch_timer_evt, cpu);
-		irqa->irq = arch_timer_ppi2;
-		err = setup_irq(arch_timer_ppi2, irqa);
+		err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler,
+					"arch_sys_timer", arch_timer_evt);
 		if (err)
 			pr_warn("%s: can't register interrupt %d (%d)\n",
-				irqa->name, irqa->irq, err);
+				"arch_sys_timer", arch_timer_ppi2, err);
 	}
 
 	/* Immediately configure the timer on the boot CPU */
-	arch_timer_setup(per_cpu_ptr(arch_timer_evt, cpu));
+	arch_timer_setup(per_cpu_ptr(arch_timer_evt, smp_processor_id()));
 
 	register_cpu_notifier(&arch_timer_cpu_nb);
 
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 5bd484f..fe37b67 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -61,9 +61,6 @@
 #ifdef CONFIG_SMP
 	show_ipi_list(p, prec);
 #endif
-#ifdef CONFIG_LOCAL_TIMERS
-	show_local_irqs(p, prec);
-#endif
 	seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
 	return 0;
 }
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9fe0964..dc78fcb 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -449,10 +449,6 @@
 	for (i = 0; i < NR_IPI; i++)
 		sum += __get_irq_stat(cpu, ipi_irqs[i]);
 
-#ifdef CONFIG_LOCAL_TIMERS
-	sum += __get_irq_stat(cpu, local_timer_irqs);
-#endif
-
 	return sum;
 }
 
@@ -469,33 +465,6 @@
 	irq_exit();
 }
 
-#ifdef CONFIG_LOCAL_TIMERS
-asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
-{
-	struct pt_regs *old_regs = set_irq_regs(regs);
-	int cpu = smp_processor_id();
-
-	if (local_timer_ack()) {
-		__inc_irq_stat(cpu, local_timer_irqs);
-		ipi_timer();
-	}
-
-	set_irq_regs(old_regs);
-}
-
-void show_local_irqs(struct seq_file *p, int prec)
-{
-	unsigned int cpu;
-
-	seq_printf(p, "%*s: ", prec, "LOC");
-
-	for_each_present_cpu(cpu)
-		seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs));
-
-	seq_printf(p, " Local timer interrupts\n");
-}
-#endif
-
 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 static void smp_timer_broadcast(const struct cpumask *mask)
 {
@@ -546,7 +515,7 @@
 	unsigned int cpu = smp_processor_id();
 	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
 
-	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+	local_timer_stop(evt);
 }
 #endif
 
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index f62743c..d4c8c36 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 
 #include <asm/smp_twd.h>
+#include <asm/localtimer.h>
 #include <asm/hardware/gic.h>
 
 /* set up by the platform code */
@@ -26,6 +27,8 @@
 
 static unsigned long twd_timer_rate;
 
+static struct clock_event_device __percpu **twd_evt;
+
 static void twd_set_mode(enum clock_event_mode mode,
 			struct clock_event_device *clk)
 {
@@ -80,6 +83,12 @@
 	return 0;
 }
 
+void twd_timer_stop(struct clock_event_device *clk)
+{
+	twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+	disable_percpu_irq(clk->irq);
+}
+
 static void __cpuinit twd_calibrate_rate(void)
 {
 	unsigned long count;
@@ -119,11 +128,43 @@
 	}
 }
 
+static irqreturn_t twd_handler(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+
+	if (twd_timer_ack()) {
+		evt->event_handler(evt);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
 /*
  * Setup the local clock events for a CPU.
  */
 void __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
+	struct clock_event_device **this_cpu_clk;
+
+	if (!twd_evt) {
+		int err;
+
+		twd_evt = alloc_percpu(struct clock_event_device *);
+		if (!twd_evt) {
+			pr_err("twd: can't allocate memory\n");
+			return;
+		}
+
+		err = request_percpu_irq(clk->irq, twd_handler,
+					 "twd", twd_evt);
+		if (err) {
+			pr_err("twd: can't register interrupt %d (%d)\n",
+			       clk->irq, err);
+			return;
+		}
+	}
+
 	twd_calibrate_rate();
 
 	clk->name = "local_timer";
@@ -136,8 +177,10 @@
 	clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
 	clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
 
-	/* Make sure our local interrupt controller has this enabled */
-	gic_enable_ppi(clk->irq);
+	this_cpu_clk = __this_cpu_ptr(twd_evt);
+	*this_cpu_clk = clk;
 
 	clockevents_register_device(clk);
+
+	enable_percpu_irq(clk->irq, 0);
 }