|
@@ -71,12 +71,16 @@ enum timer_location {
|
|
|
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 {
|
|
@@ -87,13 +91,10 @@ 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);
|
|
@@ -171,13 +172,7 @@ static struct msm_clock msm_clocks[] = {
|
|
|
.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] = {
|
|
@@ -196,13 +191,7 @@ static struct msm_clock msm_clocks[] = {
|
|
|
.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,
|
|
|
}
|
|
@@ -261,10 +250,30 @@ static void __init msm_timer_init(void)
|
|
|
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);
|
|
|
}
|
|
@@ -273,6 +282,7 @@ static void __init msm_timer_init(void)
|
|
|
#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 */
|
|
@@ -281,12 +291,13 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt)
|
|
|
|
|
|
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;
|
|
@@ -298,17 +309,17 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt)
|
|
|
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
|