[PATCH 3/5] msm: timer: SMP timer support for msm
Jeff Ohlstein
johlstei at codeaurora.org
Mon Dec 6 23:49:11 EST 2010
Thomas Gleixner wrote:
> On Sun, 5 Dec 2010, Jeff Ohlstein wrote:
>> 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;
>
> Why is dev_id not pointing to the correct device in the first place?
dev_id is specified per struct irqaction, which is registered once per
irq number. However, each core has a separate clock_event_device. Since
the timer irq has the same irq number on both cores, we need to know
what core we are on to know which clock_event_device is the correct one.
>>
>> +static uint32_t msm_read_timer_count(struct msm_clock *clock,
>> + enum timer_location global)
>> +{
>> + uint32_t t1;
>> +
>> + if (global)
>> + t1 = readl(clock->regbase + TIMER_COUNT_VAL + MSM_TMR_GLOBAL);
>> + else
>> + t1 = readl(clock->regbase + TIMER_COUNT_VAL);
>> +
>> + return t1;
>
> Adding such conditionals into a fast path is brilliant. Granted, gcc
> might optimize it out, but I'm not sure given the number of call sites.
>
> What's the point of this exercise ?
The reason is I had a common function for reading a timer count, but
sometimes we want to read the cpu local timer, such as in the case of
set_next_event, but sometimes I want to read a global timer, which is at
a different address. However, you are right that it is silly to put a
conditional there, especially when which branch I want is static at the
callsite.
>> +}
>> +
>> static cycle_t msm_gpt_read(struct clocksource *cs)
>> {
>> - return readl(MSM_GPT_BASE + TIMER_COUNT_VAL);
>> + struct msm_clock *clock = &msm_clocks[MSM_CLOCK_GPT];
>> + return msm_read_timer_count(clock, GLOBAL_TIMER);
>
> Why don't you store the address of the read register including the
> shift value into the msm_clock structure ?
>
> clock->counter_reg
> clock->counter_shift
>
> And then embedd the clocksource struct there as well, so you can
> dereference msm_clock with container_of() and reduce the 3 read
> functions to a single one.
Done.
>> +static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt)
>> +{
>> +#ifdef CONFIG_SMP
>> + int i;
>> + for (i = 0; i < NR_TIMERS; i++)
>> + if (evt == &(msm_clocks[i].clockevent))
>> + return &msm_clocks[i];
>
> Why don't you use container_of here as well ?
The clockevent could be the local_clock_event, which is not embedded
into a struct msm_clock. However, its parameters will be the same as one
of the existing msm_clock entries, so use that.
>> if (late >= (-2 << clock->shift) && late < DGT_HZ*5) {
>> - printk(KERN_NOTICE "msm_timer_set_next_event(%lu) clock %s, "
>> - "alarm already expired, now %x, alarm %x, late %d\n",
>> - cycles, clock->clockevent.name, now, alarm, late);
>> + static int print_limit = 10;
>> + if (print_limit > 0) {
>> + print_limit--;
>> + printk(KERN_NOTICE "msm_timer_set_next_event(%lu) "
>> + "clock %s, alarm already expired, now %x, "
>> + "alarm %x, late %d%s\n",
>> + cycles, clock->clockevent.name, now, alarm, late,
>> + print_limit ? "" : " stop printing");
>> + }
>
> The generic clockevents layer has already a check for this. No need
> for extra printk spam.
Done.
>> @@ -107,7 +171,11 @@ static int msm_timer_set_next_event(unsigned long cycles,
>> static void msm_timer_set_mode(enum clock_event_mode mode,
>> struct clock_event_device *evt)
>> {
>> - struct msm_clock *clock = container_of(evt, struct msm_clock, clockevent);
>> + struct msm_clock *clock = clockevent_to_clock(evt);
>> + unsigned long irq_flags;
>> +
>> + local_irq_save(irq_flags);
>
> Always called with interrupts disabled.
Done.
>> + local_clock_event = evt;
>> +
>> + local_irq_save(flags);
>> + get_irq_chip(clock->irq.irq)->unmask(clock->irq.irq);
> Why are you fiddling wiht the irqchip functions directly ? Please use
> disable_irq/enable_irq if at all.
As stated by Russell, this is due to the fact that the timer interrupts
are private to each core, and share the same irq number on each core.
>> +int local_timer_ack(void)
>> +{
>> + return 1;
>
> Shouldn't that be an inline ? Why calling code which the compiler
> could optimize out.
Done.
>> +#ifdef CONFIG_HOTPLUG_CPU
>> +void __cpuexit local_timer_stop(void)
>> +{
>> + local_clock_event->set_mode(CLOCK_EVT_MODE_SHUTDOWN, local_clock_event);
>
> Aarg. No. The generic code already handles cpu hotplug.
So what needs to be done in local_timer_stop? Just stopping the timer
from ticking? Aren't I going to want to do all the same things my
set_mode function does in the shutdown case? I understand not calling
into the clockevents functions, would you be opposed to me directly
calling my set_mode function?
-Jeff
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
More information about the linux-arm-kernel
mailing list