ARM: local timers: Interrupt registration mechanism

Register interrupts using interrupt action mechanism instead of
gic_request_ppi() which is dependent on an another patch series
that doesn't exist yet.

Add read_current_timer() to support ARCH_HAS_READ_CURRENT_TIMER
and register the delay loop routine.

Change-Id: I2e7309b93a7bdae37103b738d547eb20f86fe9f7
Signed-off-by: Sathish Ambley <sambley@codeaurora.org>
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 5b76911..7611a04 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/timex.h>
 #include <linux/device.h>
 #include <linux/smp.h>
 #include <linux/cpu.h>
@@ -18,10 +19,13 @@
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/irq.h>
 
 #include <asm/cputype.h>
+#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;
@@ -77,13 +81,14 @@
 
 static irqreturn_t arch_timer_handler(int irq, void *dev_id)
 {
-	struct clock_event_device *evt = dev_id;
+	struct clock_event_device *evt;
 	unsigned long ctrl;
 
 	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
 	if (ctrl & 0x4) {
 		ctrl |= ARCH_TIMER_CTRL_IT_MASK;
 		arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+		evt = per_cpu_ptr(arch_timer_evt, smp_processor_id());
 		evt->event_handler(evt);
 		return IRQ_HANDLED;
 	}
@@ -131,7 +136,6 @@
 static void __cpuinit arch_timer_setup(void *data)
 {
 	struct clock_event_device *clk = data;
-	int err;
 
 	/* Be safe... */
 	arch_timer_stop();
@@ -147,20 +151,9 @@
 	clockevents_config_and_register(clk, arch_timer_rate,
 					0xf, 0x7fffffff);
 
-	err = gic_request_ppi(clk->irq, arch_timer_handler, clk);
-	if (err) {
-		pr_err("%s: can't register interrupt %d on cpu %d (%d)\n",
-		       clk->name, clk->irq, smp_processor_id(), err);
-		return;
-	}
-
-	if (arch_timer_ppi2 >= 0) {
-		err = gic_request_ppi(arch_timer_ppi2, arch_timer_handler, clk);
-		if (err) {
-			pr_warn("%s: can't register interrupt %d on cpu %d (%d)\n",
-				clk->name, arch_timer_ppi2, smp_processor_id(), err);
-		}
-	}
+	gic_enable_ppi(arch_timer_ppi);
+	if (arch_timer_ppi2 > 0)
+		gic_enable_ppi(arch_timer_ppi2);
 }
 
 /* Is the optional system timer available? */
@@ -218,6 +211,14 @@
 	return arch_counter_get_cntpct();
 }
 
+#ifdef ARCH_HAS_READ_CURRENT_TIMER
+int read_current_timer(unsigned long *timer_val)
+{
+	*timer_val = (unsigned long)arch_counter_get_cntpct();
+	return 0;
+}
+#endif
+
 static struct clocksource clocksource_counter = {
 	.name	= "arch_sys_counter",
 	.rating	= 400,
@@ -240,7 +241,7 @@
 	return (u32)(cntvct & (u32)~0);
 }
 
-DEFINE_SCHED_CLOCK_FUNC(arch_timer_sched_clock)
+unsigned long long notrace sched_clock(void)
 {
 	return cyc_to_sched_clock(&cd, arch_counter_get_cntvct32(), (u32)~0);
 }
@@ -255,9 +256,11 @@
 	struct clock_event_device *clk = data;
 	pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
 		 clk->irq, smp_processor_id());
-	gic_free_ppi(clk->irq, clk);
-	if (arch_timer_ppi2 >= 0)
-		gic_free_ppi(arch_timer_ppi2, clk);
+	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]);
+	}
 	arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
 }
 
@@ -288,6 +291,8 @@
 
 int 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))
@@ -307,11 +312,41 @@
 
 	clocksource_register_hz(&clocksource_counter, arch_timer_rate);
 
-	init_arch_sched_clock(&cd, arch_timer_update_sched_clock,
-				arch_timer_sched_clock, 32, arch_timer_rate);
+	init_sched_clock(&cd, arch_timer_update_sched_clock, 32,
+			arch_timer_rate);
+
+#ifdef ARCH_HAS_READ_CURRENT_TIMER
+	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);
+	if (err) {
+		pr_err("%s: can't register interrupt %d (%d)\n",
+		       irqa->name, irqa->irq, 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);
+		if (err)
+			pr_warn("%s: can't register interrupt %d (%d)\n",
+				irqa->name, irqa->irq, err);
+	}
 
 	/* Immediately configure the timer on the boot CPU */
-	arch_timer_setup(per_cpu_ptr(arch_timer_evt, smp_processor_id()));
+	arch_timer_setup(per_cpu_ptr(arch_timer_evt, cpu));
 
 	register_cpu_notifier(&arch_timer_cpu_nb);