Skip to content

Commit be83c3b

Browse files
h2phongdlezcano
authored andcommitted
clocksource/drivers/sh_cmt: Fix wrong setting if don't request IRQ for clock source channel
If CMT instance has at least two channels, one channel will be used as a clock source and another one used as a clock event device. In that case, IRQ is not requested for clock source channel so sh_cmt_clock_event_program_verify() might work incorrectly. Besides, when a channel is only used for clock source, don't need to re-set the next match_value since it should be maximum timeout as it still is. On the other hand, due to no IRQ, total_cycles is not counted up when reaches compare match time (timer counter resets to zero), so sh_cmt_clocksource_read() returns unexpected value. Therefore, use 64-bit clocksoure's mask for 32-bit or 16-bit variants will also lead to wrong delta calculation. Hence, this mask should correspond to timer counter width, and above function just returns the raw value of timer counter register. Fixes: bfa76bb ("clocksource: sh_cmt: Request IRQ for clock event device only") Fixes: 37e7742 ("clocksource/drivers/sh_cmt: Fix clocksource width for 32-bit machines") Signed-off-by: Phong Hoang <[email protected]> Signed-off-by: Niklas Söderlund <[email protected]> Signed-off-by: Daniel Lezcano <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent faa186a commit be83c3b

File tree

1 file changed

+18
-12
lines changed

1 file changed

+18
-12
lines changed

drivers/clocksource/sh_cmt.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,8 @@ static int sh_cmt_start(struct sh_cmt_channel *ch, unsigned long flag)
579579
ch->flags |= flag;
580580

581581
/* setup timeout if no clockevent */
582-
if ((flag == FLAG_CLOCKSOURCE) && (!(ch->flags & FLAG_CLOCKEVENT)))
582+
if (ch->cmt->num_channels == 1 &&
583+
flag == FLAG_CLOCKSOURCE && (!(ch->flags & FLAG_CLOCKEVENT)))
583584
__sh_cmt_set_next(ch, ch->max_match_value);
584585
out:
585586
raw_spin_unlock_irqrestore(&ch->lock, flags);
@@ -621,20 +622,25 @@ static struct sh_cmt_channel *cs_to_sh_cmt(struct clocksource *cs)
621622
static u64 sh_cmt_clocksource_read(struct clocksource *cs)
622623
{
623624
struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
624-
unsigned long flags;
625625
u32 has_wrapped;
626-
u64 value;
627-
u32 raw;
628626

629-
raw_spin_lock_irqsave(&ch->lock, flags);
630-
value = ch->total_cycles;
631-
raw = sh_cmt_get_counter(ch, &has_wrapped);
627+
if (ch->cmt->num_channels == 1) {
628+
unsigned long flags;
629+
u64 value;
630+
u32 raw;
632631

633-
if (unlikely(has_wrapped))
634-
raw += ch->match_value + 1;
635-
raw_spin_unlock_irqrestore(&ch->lock, flags);
632+
raw_spin_lock_irqsave(&ch->lock, flags);
633+
value = ch->total_cycles;
634+
raw = sh_cmt_get_counter(ch, &has_wrapped);
635+
636+
if (unlikely(has_wrapped))
637+
raw += ch->match_value + 1;
638+
raw_spin_unlock_irqrestore(&ch->lock, flags);
639+
640+
return value + raw;
641+
}
636642

637-
return value + raw;
643+
return sh_cmt_get_counter(ch, &has_wrapped);
638644
}
639645

640646
static int sh_cmt_clocksource_enable(struct clocksource *cs)
@@ -697,7 +703,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_channel *ch,
697703
cs->disable = sh_cmt_clocksource_disable;
698704
cs->suspend = sh_cmt_clocksource_suspend;
699705
cs->resume = sh_cmt_clocksource_resume;
700-
cs->mask = CLOCKSOURCE_MASK(sizeof(u64) * 8);
706+
cs->mask = CLOCKSOURCE_MASK(ch->cmt->info->width);
701707
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
702708

703709
dev_info(&ch->cmt->pdev->dev, "ch%u: used as clock source\n",

0 commit comments

Comments
 (0)