Skip to content

Commit 7e77721

Browse files
h2phongsmb49
authored andcommitted
clocksource/drivers/sh_cmt: Fix wrong setting if don't request IRQ for clock source channel
BugLink: https://bugs.launchpad.net/bugs/1946788 [ Upstream commit be83c3b ] 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] Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Kamal Mostafa <[email protected]> Signed-off-by: Kelsey Skunberg <[email protected]>
1 parent f5f4242 commit 7e77721

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
@@ -576,7 +576,8 @@ static int sh_cmt_start(struct sh_cmt_channel *ch, unsigned long flag)
576576
ch->flags |= flag;
577577

578578
/* setup timeout if no clockevent */
579-
if ((flag == FLAG_CLOCKSOURCE) && (!(ch->flags & FLAG_CLOCKEVENT)))
579+
if (ch->cmt->num_channels == 1 &&
580+
flag == FLAG_CLOCKSOURCE && (!(ch->flags & FLAG_CLOCKEVENT)))
580581
__sh_cmt_set_next(ch, ch->max_match_value);
581582
out:
582583
raw_spin_unlock_irqrestore(&ch->lock, flags);
@@ -618,20 +619,25 @@ static struct sh_cmt_channel *cs_to_sh_cmt(struct clocksource *cs)
618619
static u64 sh_cmt_clocksource_read(struct clocksource *cs)
619620
{
620621
struct sh_cmt_channel *ch = cs_to_sh_cmt(cs);
621-
unsigned long flags;
622622
u32 has_wrapped;
623-
u64 value;
624-
u32 raw;
625623

626-
raw_spin_lock_irqsave(&ch->lock, flags);
627-
value = ch->total_cycles;
628-
raw = sh_cmt_get_counter(ch, &has_wrapped);
624+
if (ch->cmt->num_channels == 1) {
625+
unsigned long flags;
626+
u64 value;
627+
u32 raw;
629628

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

634-
return value + raw;
640+
return sh_cmt_get_counter(ch, &has_wrapped);
635641
}
636642

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

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

0 commit comments

Comments
 (0)