#include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/hardware/gic.h>
-#include <asm/localtimer.h>
 
 static DEFINE_SPINLOCK(irq_controller_lock);
 
        irq_set_chained_handler(irq, gic_handle_cascade_irq);
 }
 
-#ifdef CONFIG_LOCAL_TIMERS
-#define gic_ppi_handler                percpu_timer_handler
-#else
-static irqreturn_t gic_ppi_handler(int irq, void *dev_id)
-{
-       return IRQ_NONE;
-}
-#endif
-
-#define PPI_IRQACT(nr)                                         \
-       {                                                       \
-               .handler        = gic_ppi_handler,              \
-               .flags          = IRQF_PERCPU | IRQF_TIMER,     \
-               .irq            = nr,                           \
-               .name           = "PPI-" # nr,                  \
-       }
-
-static struct irqaction ppi_irqaction_template[16] __initdata = {
-       PPI_IRQACT(0),  PPI_IRQACT(1),  PPI_IRQACT(2),  PPI_IRQACT(3),
-       PPI_IRQACT(4),  PPI_IRQACT(5),  PPI_IRQACT(6),  PPI_IRQACT(7),
-       PPI_IRQACT(8),  PPI_IRQACT(9),  PPI_IRQACT(10), PPI_IRQACT(11),
-       PPI_IRQACT(12), PPI_IRQACT(13), PPI_IRQACT(14), PPI_IRQACT(15),
-};
-
-static struct irqaction *ppi_irqaction;
-
 static void __init gic_dist_init(struct gic_chip_data *gic,
        unsigned int irq_start)
 {
                        BUG();
 
                ppi_base = gic->irq_offset + 32 - nrppis;
-
-               ppi_irqaction = kmemdup(&ppi_irqaction_template[16 - nrppis],
-                                       sizeof(*ppi_irqaction) * nrppis,
-                                       GFP_KERNEL);
-
-               if (nrppis && !ppi_irqaction) {
-                       pr_err("GIC: Can't allocate PPI memory");
-                       nrppis = 0;
-                       ppi_base = 0;
-               }
        }
 
        pr_info("Configuring GIC with %d sources (%d PPIs)\n",
         */
        for (i = 0; i < nrppis; i++) {
                int ppi = i + ppi_base;
-               int err;
 
                irq_set_percpu_devid(ppi);
                irq_set_chip_and_handler(ppi, &gic_chip,
                                         handle_percpu_devid_irq);
                irq_set_chip_data(ppi, gic);
                set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN);
-
-               err = setup_percpu_irq(ppi, &ppi_irqaction[i]);
-               if (err)
-                       pr_err("GIC: can't setup PPI%d (%d)\n", ppi, err);
        }
 
        for (i = irq_start + nrppis; i < irq_limit; i++) {
        gic_cpu_init(&gic_data[gic_nr]);
 }
 
-void __cpuinit gic_enable_ppi(unsigned int irq)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       irq_set_status_flags(irq, IRQ_NOPROBE);
-       gic_unmask_irq(irq_get_irq_data(irq));
-       local_irq_restore(flags);
-}
-
 #ifdef CONFIG_SMP
 void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 
 void gic_secondary_init(unsigned int);
 void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
 void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
-void gic_enable_ppi(unsigned int);
 
 struct gic_chip_data {
        unsigned int irq_offset;
 
  */
 void percpu_timer_setup(void);
 
-/*
- * Per-cpu timer IRQ handler
- */
-irqreturn_t percpu_timer_handler(int irq, void *dev_id);
-
 #ifdef CONFIG_LOCAL_TIMERS
 
 #ifdef CONFIG_HAVE_ARM_TWD
 
 #include "smp_twd.h"
 
-#define local_timer_ack()      twd_timer_ack()
+#define local_timer_stop(c)    twd_timer_stop((c))
 
 #else
 
 /*
- * Platform provides this to acknowledge a local timer IRQ.
- * Returns true if the local timer IRQ is to be processed.
+ * Stop the local timer
  */
-int local_timer_ack(void);
+void local_timer_stop(struct clock_event_device *);
 
 #endif
 
 {
        return -ENXIO;
 }
+
+static inline void local_timer_stop(struct clock_event_device *evt)
+{
+}
 #endif
 
 #endif
 
 
 extern void __iomem *twd_base;
 
-int twd_timer_ack(void);
 void twd_timer_setup(struct clock_event_device *);
+void twd_timer_stop(struct clock_event_device *);
 
 #endif
 
        irq_exit();
 }
 
-#ifdef CONFIG_LOCAL_TIMERS
-irqreturn_t percpu_timer_handler(int irq, void *dev_id)
-{
-       struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
-
-       if (local_timer_ack()) {
-               evt->event_handler(evt);
-               return IRQ_HANDLED;
-       }
-
-       return IRQ_NONE;
-}
-#endif
-
 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 static void smp_timer_broadcast(const struct cpumask *mask)
 {
        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
 
 
 #include <linux/io.h>
 
 #include <asm/smp_twd.h>
+#include <asm/localtimer.h>
 #include <asm/hardware/gic.h>
 
 /* set up by the platform code */
 
 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)
 {
        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;
        }
 }
 
+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";
        clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
        clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
 
+       this_cpu_clk = __this_cpu_ptr(twd_evt);
+       *this_cpu_clk = clk;
+
        clockevents_register_device(clk);
 
-       /* Make sure our local interrupt controller has this enabled */
-       gic_enable_ppi(clk->irq);
+       enable_percpu_irq(clk->irq, 0);
 }
 
 
        if (cpu == 0) {
                mct_tick0_event_irq.dev_id = &mct_tick[cpu];
+               evt->irq = IRQ_MCT_L0;
                setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq);
        } else {
                mct_tick1_event_irq.dev_id = &mct_tick[cpu];
+               evt->irq = IRQ_MCT_L1;
                setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq);
                irq_set_affinity(IRQ_MCT_L1, cpumask_of(1));
        }
        exynos4_mct_tick_init(evt);
 }
 
-int local_timer_ack(void)
+void local_timer_stop(struct clock_event_device *evt)
 {
-       return 0;
+       evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+       disable_irq(evt->irq);
 }
 
 #endif /* CONFIG_LOCAL_TIMERS */
 
 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;
        void __iomem                *global_counter;
        void __iomem                *local_counter;
+       union {
+               struct clock_event_device               *evt;
+               struct clock_event_device __percpu      **percpu_evt;
+       };              
 };
 
 enum {
 
 
 static struct msm_clock msm_clocks[];
-static struct clock_event_device *local_clock_event;
 
 static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
 {
-       struct clock_event_device *evt = dev_id;
-       if (smp_processor_id() != 0)
-               evt = 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);
                        .mask           = CLOCKSOURCE_MASK(32),
                        .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,
                .freq = GPT_HZ,
        },
        [MSM_CLOCK_DGT] = {
                        .mask           = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
                        .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,
                .freq = DGT_HZ >> MSM_DGT_SHIFT,
                .shift = MSM_DGT_SHIFT,
        }
                        printk(KERN_ERR "msm_timer_init: clocksource_register "
                               "failed for %s\n", cs->name);
 
-               res = setup_irq(clock->irq.irq, &clock->irq);
+               ce->irq = clock->irq;
+               if (cpu_is_msm8x60() || cpu_is_msm8960()) {
+                       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;
+                       }
+
+                       *__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)
-                       printk(KERN_ERR "msm_timer_init: setup_irq "
-                              "failed for %s\n", cs->name);
+                       pr_err("msm_timer_init: request_irq failed for %s\n",
+                              ce->name);
 
                clockevents_register_device(ce);
        }
 #ifdef CONFIG_SMP
 int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
+       static bool local_timer_inited;
        struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER];
 
        /* Use existing clock_event for cpu 0 */
 
        writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
 
-       if (!local_clock_event) {
+       if (!local_timer_inited) {
                writel(0, clock->regbase  + TIMER_ENABLE);
                writel(0, clock->regbase + TIMER_CLEAR);
                writel(~0, clock->regbase + TIMER_MATCH_VAL);
+               local_timer_inited = true;
        }
-       evt->irq = clock->irq.irq;
+       evt->irq = clock->irq;
        evt->name = "local_timer";
        evt->features = CLOCK_EVT_FEAT_ONESHOT;
        evt->rating = clock->clockevent.rating;
                clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
        evt->min_delta_ns = clockevent_delta2ns(4, evt);
 
-       local_clock_event = evt;
-
-       gic_enable_ppi(clock->irq.irq);
+       *__this_cpu_ptr(clock->percpu_evt) = evt;
+       enable_percpu_irq(evt->irq, 0);
 
        clockevents_register_device(evt);
        return 0;
 }
 
-inline 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