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/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 370d8ab..29fd0da 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -383,7 +383,6 @@
 
 static void __init apq8064_init_irq(void)
 {
-	unsigned int i;
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
 						(void *)MSM_QGIC_CPU_BASE);
 
@@ -392,16 +391,6 @@
 
 	writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
 	mb();
-
-	/*
-	 * FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 }
 
 static struct platform_device msm8064_device_saw_regulator_core0 = {
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index c8a2737..abcfd39 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -832,8 +832,6 @@
 
 static void __init msm8960_init_irq(void)
 {
-	unsigned int i;
-
 	msm_mpm_irq_extn_init();
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
 						(void *)MSM_QGIC_CPU_BASE);
@@ -843,15 +841,6 @@
 
 	writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
 	mb();
-
-	/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 }
 
 static void __init msm8960_init_buses(void)
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 13d63d3..f4fcb75 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -50,8 +50,6 @@
 
 void __init msm_copper_init_irq(void)
 {
-	unsigned int i;
-
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
 			(void *)MSM_QGIC_CPU_BASE);
 
@@ -61,14 +59,6 @@
 	writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
 	mb();
 
-	/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 	irq_domain_generate_simple(msm_copper_gic_match,
 		COPPER_QGIC_DIST_PHYS, GIC_SPI_START);
 }
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index ebe884de..a37f38f 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -54,9 +54,9 @@
 	return 0;
 }
 
-int local_timer_ack(void)
+void local_timer_stop(void)
 {
-	return 1;
+	return;
 }
 
 static void __init msm_dt_init_irq(void)
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 3627e0a..2e85d87 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -885,8 +885,6 @@
 
 void __init msm9615_init_irq(void)
 {
-	unsigned int i;
-
 	msm_mpm_irq_extn_init();
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
 						(void *)MSM_QGIC_CPU_BASE);
@@ -896,16 +894,6 @@
 
 	writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
 	mb();
-
-	/*
-	 * FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 }
 
 struct platform_device msm_bus_9615_sys_fabric = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index aa9e380..eea7bc4 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -170,22 +170,11 @@
 
 void __init msm8x60_init_irq(void)
 {
-	unsigned int i;
-
 	msm_mpm_irq_extn_init();
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, (void *)MSM_QGIC_CPU_BASE);
 
 	/* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
 	writel(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
-
-	/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 }
 
 #define MSM_LPASS_QDSP6SS_PHYS 0x28800000
diff --git a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
index 092e48e..245f3bd 100644
--- a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
+++ b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
@@ -8,89 +8,11 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <mach/hardware.h>
-#include <asm/hardware/gic.h>
+#include <asm/hardware/entry-macro-gic.S>
 
 	.macro	disable_fiq
 	.endm
 
-	.macro  get_irqnr_preamble, base, tmp
-	ldr	\base, =gic_cpu_base_addr
-	ldr	\base, [\base]
-	.endm
-
 	.macro  arch_ret_to_user, tmp1, tmp2
 	.endm
 
-	/*
-	 * The interrupt numbering scheme is defined in the
-	 * interrupt controller spec.  To wit:
-	 *
-	 * Migrated the code from ARM MP port to be more consistant
-	 * with interrupt processing , the following still holds true
-	 * however, all interrupts are treated the same regardless of
-	 * if they are local IPI or PPI
-	 *
-	 * Interrupts 0-15 are IPI
-	 * 16-31 are PPI
-	 *   (16-18 are the timers)
-	 * 32-1020 are global
-	 * 1021-1022 are reserved
-	 * 1023 is "spurious" (no interrupt)
-	 *
-	 * A simple read from the controller will tell us the number of the
-	 * highest priority enabled interrupt.  We then just need to check
-	 * whether it is in the valid range for an IRQ (0-1020 inclusive).
-	 *
-	 * Base ARM code assumes that the local (private) peripheral interrupts
-	 * are not valid, we treat them differently, in that the privates are
-	 * handled like normal shared interrupts with the exception that only
-	 * one processor can register the interrupt and the handler must be
-	 * the same for all processors.
-	 */
-
-	.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-
-	ldr  \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 =srcCPU,
-						   9-0 =int # */
-
-	bic     \irqnr, \irqstat, #0x1c00	@mask src
-#ifdef CONFIG_REQUEST_IPI
-	cmp     \irqnr, #0
-#else
-	cmp     \irqnr, #15
-#endif
-	ldr		\tmp, =1021
-	cmpcc	\irqnr, \irqnr
-	cmpne	\irqnr, \tmp
-	cmpcs	\irqnr, \irqnr
-
-	.endm
-
-	/* We assume that irqstat (the raw value of the IRQ acknowledge
-	 * register) is preserved from the macro above.
-	 * If there is an IPI, we immediately signal end of interrupt on the
-	 * controller, since this requires the original irqstat value which
-	 * we won't easily be able to recreate later.
-	 */
-	.macro test_for_ipi, irqnr, irqstat, base, tmp
-#ifndef CONFIG_REQUEST_IPI
-    bic \irqnr, \irqstat, #0x1c00
-    cmp \irqnr, #16
-    strcc   \irqstat, [\base, #GIC_CPU_EOI]
-    cmpcs   \irqnr, \irqnr
-#endif
-	.endm
-
-	/* As above, this assumes that irqstat and base are preserved.. */
-
-	.macro test_for_ltirq, irqnr, irqstat, base, tmp
-#ifndef CONFIG_REQUEST_IPI
-    bic \irqnr, \irqstat, #0x1c00
-    mov     \tmp, #0
-    cmp \irqnr, #16
-    moveq   \tmp, #1
-    streq   \irqstat, [\base, #GIC_CPU_EOI]
-    cmp \tmp, #0
-#endif
-	.endm
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index f04148a..5877fbf 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -21,6 +21,7 @@
 #include <linux/mfd/pmic8058.h>
 #include <linux/jiffies.h>
 #include <linux/suspend.h>
+#include <linux/percpu.h>
 #include <linux/interrupt.h>
 #include <mach/msm_iomap.h>
 #include <asm/mach-types.h>
@@ -87,6 +88,8 @@
 /* Area for context dump in secure mode */
 static void *scm_regsave;
 
+static struct msm_watchdog_pdata __percpu **percpu_pdata;
+
 static void pet_watchdog_work(struct work_struct *work);
 static void init_watchdog_work(struct work_struct *work);
 static DECLARE_DELAYED_WORK(dogwork_struct, pet_watchdog_work);
@@ -158,7 +161,9 @@
 		if (!old_val) {
 			__raw_writel(0, msm_tmr0_base + WDT0_EN);
 			mb();
-			free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+			disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+			free_percpu_irq(WDT0_ACCSCSSNBARK_INT, percpu_pdata);
+			free_percpu(percpu_pdata);
 			enable = 0;
 			atomic_notifier_chain_unregister(&panic_notifier_list,
 			       &panic_blk);
@@ -216,7 +221,9 @@
 	if (enable) {
 		__raw_writel(0, msm_tmr0_base + WDT0_EN);
 		mb();
-		free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+		disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+		free_percpu_irq(WDT0_ACCSCSSNBARK_INT, percpu_pdata);
+		free_percpu(percpu_pdata);
 		enable = 0;
 		/* In case we got suspended mid-exit */
 		__raw_writel(0, msm_tmr0_base + WDT0_EN);
@@ -331,11 +338,23 @@
 
 	msm_tmr0_base = msm_timer_get_timer0_base();
 
+	percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
+	if (!percpu_pdata) {
+		pr_err("%s: memory allocation failed for percpu data\n",
+				__func__);
+		return -ENOMEM;
+	}
+
+	*__this_cpu_ptr(percpu_pdata) = pdata;
 	/* Must request irq before sending scm command */
-	ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
-			  "apps_wdog_bark", NULL);
-	if (ret)
-		return -EINVAL;
+	ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler,
+			  "apps_wdog_bark", percpu_pdata);
+	if (ret) {
+		free_percpu(percpu_pdata);
+		return ret;
+	}
+
+	enable_percpu_irq(WDT0_ACCSCSSNBARK_INT, 0);
 
 	/*
 	 * This is only temporary till SBLs turn on the XPUs
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 7e61e8b..6f04470 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -102,7 +102,7 @@
 struct msm_clock {
 	struct clock_event_device   clockevent;
 	struct clocksource          clocksource;
-	struct irqaction            irq;
+	unsigned int		    irq;
 	void __iomem                *regbase;
 	uint32_t                    freq;
 	uint32_t                    shift;
@@ -110,6 +110,12 @@
 	uint32_t                    write_delay;
 	uint32_t                    rollover_offset;
 	uint32_t                    index;
+	void __iomem                *global_counter;
+	void __iomem                *local_counter;
+	union {
+		struct clock_event_device		*evt;
+		struct clock_event_device __percpu	**percpu_evt;
+	};
 };
 
 enum {
@@ -117,7 +123,6 @@
 	MSM_CLOCK_DGT,
 };
 
-
 struct msm_clock_percpu_data {
 	uint32_t                  last_set;
 	uint32_t                  sleep_offset;
@@ -155,14 +160,7 @@
 			.shift          = 17,
 			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 		},
-		.irq = {
-			.name    = "gp_timer",
-			.flags   = IRQF_DISABLED | IRQF_TIMER |
-				   IRQF_TRIGGER_RISING,
-			.handler = msm_timer_interrupt,
-			.dev_id  = &msm_clocks[0].clockevent,
-			.irq     = INT_GP_TIMER_EXP
-		},
+		.irq = INT_GP_TIMER_EXP,
 		.regbase = MSM_TMR_BASE + 0x4,
 		.freq = 32768,
 		.index = MSM_CLOCK_GPT,
@@ -185,22 +183,13 @@
 			.shift          = 24,
 			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 		},
-		.irq = {
-			.name    = "dg_timer",
-			.flags   = IRQF_DISABLED | IRQF_TIMER |
-				   IRQF_TRIGGER_RISING,
-			.handler = msm_timer_interrupt,
-			.dev_id  = &msm_clocks[1].clockevent,
-			.irq     = INT_DEBUG_TIMER_EXP
-		},
+		.irq = INT_DEBUG_TIMER_EXP,
 		.regbase = MSM_TMR_BASE + 0x24,
 		.index = MSM_CLOCK_DGT,
 		.write_delay = 9,
 	}
 };
 
-static DEFINE_PER_CPU(struct clock_event_device*, local_clock_event);
-
 static DEFINE_PER_CPU(struct msm_clock_percpu_data[NR_TIMERS],
     msm_clocks_percpu);
 
@@ -208,9 +197,7 @@
 
 static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
 {
-	struct clock_event_device *evt = dev_id;
-	if (smp_processor_id() != 0)
-		evt = __get_cpu_var(local_clock_event);
+	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
 	if (evt->event_handler == NULL)
 		return IRQ_HANDLED;
 	evt->event_handler(evt);
@@ -356,9 +343,9 @@
 		get_cpu_var(msm_active_clock) = clock;
 		put_cpu_var(msm_active_clock);
 		__raw_writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
-		chip = irq_get_chip(clock->irq.irq);
+		chip = irq_get_chip(clock->irq);
 		if (chip && chip->irq_unmask)
-			chip->irq_unmask(irq_get_irq_data(clock->irq.irq));
+			chip->irq_unmask(irq_get_irq_data(clock->irq));
 		if (clock != &msm_clocks[MSM_CLOCK_GPT])
 			__raw_writel(TIMER_ENABLE_EN,
 				msm_clocks[MSM_CLOCK_GPT].regbase +
@@ -374,9 +361,9 @@
 			msm_read_timer_count(clock, LOCAL_TIMER) +
 			clock_state->sleep_offset;
 		__raw_writel(0, clock->regbase + TIMER_MATCH_VAL);
-		chip = irq_get_chip(clock->irq.irq);
+		chip = irq_get_chip(clock->irq);
 		if (chip && chip->irq_mask)
-			chip->irq_mask(irq_get_irq_data(clock->irq.irq));
+			chip->irq_mask(irq_get_irq_data(clock->irq));
 
 		if (!is_smp() || clock != &msm_clocks[MSM_CLOCK_DGT]
 				|| smp_processor_id())
@@ -1073,14 +1060,35 @@
 			printk(KERN_ERR "msm_timer_init: clocksource_register "
 			       "failed for %s\n", cs->name);
 
-		res = setup_irq(clock->irq.irq, &clock->irq);
-		if (res)
-			printk(KERN_ERR "msm_timer_init: setup_irq "
-			       "failed for %s\n", cs->name);
+		ce->irq = clock->irq;
+		if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
+				cpu_is_msm8930() || cpu_is_msm9615()) {
+			clock->percpu_evt = alloc_percpu(struct clock_event_device *);
+			if (!clock->percpu_evt) {
+				pr_err("msm_timer_init: memory allocation "
+				       "failed for %s\n", ce->name);
+				continue;
+			}
 
-		chip = irq_get_chip(clock->irq.irq);
+			*__this_cpu_ptr(clock->percpu_evt) = ce;
+			res = request_percpu_irq(ce->irq, msm_timer_interrupt,
+						 ce->name, clock->percpu_evt);
+			if (!res)
+				enable_percpu_irq(ce->irq, 0);
+		} else {
+			clock->evt = ce;
+			res = request_irq(ce->irq, msm_timer_interrupt,
+					  IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
+					  ce->name, &clock->evt);
+		}
+
+		if (res)
+			pr_err("msm_timer_init: request_irq failed for %s\n",
+			       ce->name);
+
+		chip = irq_get_chip(clock->irq);
 		if (chip && chip->irq_mask)
-			chip->irq_mask(irq_get_irq_data(clock->irq.irq));
+			chip->irq_mask(irq_get_irq_data(clock->irq));
 
 		clockevents_register_device(ce);
 	}
@@ -1097,7 +1105,6 @@
 
 int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
-	unsigned long flags;
 	static DEFINE_PER_CPU(bool, first_boot) = true;
 	struct msm_clock *clock = &msm_clocks[msm_global_timer];
 
@@ -1115,7 +1122,7 @@
 		__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
 		__get_cpu_var(first_boot) = false;
 	}
-	evt->irq = clock->irq.irq;
+	evt->irq = clock->irq;
 	evt->name = "local_timer";
 	evt->features = CLOCK_EVT_FEAT_ONESHOT;
 	evt->rating = clock->clockevent.rating;
@@ -1127,21 +1134,18 @@
 		clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
 	evt->min_delta_ns = clockevent_delta2ns(4, evt);
 
-	__get_cpu_var(local_clock_event) = evt;
-
-	local_irq_save(flags);
-	gic_clear_spi_pending(clock->irq.irq);
-	local_irq_restore(flags);
-	gic_enable_ppi(clock->irq.irq);
+	*__this_cpu_ptr(clock->percpu_evt) = evt;
 
 	clockevents_register_device(evt);
+	enable_percpu_irq(evt->irq, 0);
 
 	return 0;
 }
 
-int local_timer_ack(void)
+void local_timer_stop(struct clock_event_device *evt)
 {
-	return 1;
+	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+	disable_percpu_irq(evt->irq);
 }
 #endif