Skip to content

Commit 6023125

Browse files
committed
riscv: Introduce local timer interrupt
Currently, the timer interrupt handler(riscv_timer_interrupt()) is invoked directly from the arch handler. This approach creates interwinding of driver and architecture code which is not ideal. Even if the all timer hwirq have same irq number, they are discrete interrupts connected to each core. Moreover, HLIC is modelled in a way that there are individual HLIC per hart. Thus, register timer interrupt as an individual irq under generic Linux IRQ management framework instead of per-cpu irq. Individual HLIC acts as the parent irq domain. This patch requires necessary bbl changes that adds timer node in device tree which can be found here. riscv-software-src/riscv-pk#112 Before the patch --------------------------------------------------- CPU1 CPU2 CPU3 CPU4 21: 12 8 6 5 riscv,plic0,c000000 53 eth0 37: 0 0 0 0 riscv,plic0,c000000 32 xilinx-pcie 43: 0 0 0 0 riscv,plic0,c000000 4 10010000.serial 44: 0 0 0 0 riscv,plic0,c000000 5 10011000.serial 45: 0 0 0 0 riscv,plic0,c000000 51 10040000.spi 46: 0 0 0 0 riscv,plic0,c000000 52 10041000.spi 47: 25 1 26 50 riscv,plic0,c000000 6 10050000.spi After the patch --------------------------------------------------- CPU1 CPU2 CPU3 CPU4 5: 271 0 0 0 riscv,cpu_intc,1 5 local_timer 6: 0 307 0 0 riscv,cpu_intc,2 5 local_timer 7: 0 0 303 0 riscv,cpu_intc,3 5 local_timer 8: 0 0 0 223 riscv,cpu_intc,4 5 local_timer 47: 337 489 389 35 riscv,plic0,c000000 4 10010000.serial 48: 0 0 0 0 riscv,plic0,c000000 5 10011000.serial 49: 0 0 0 0 riscv,plic0,c000000 51 10040000.spi 50: 0 0 0 0 riscv,plic0,c000000 52 10041000.spi 51: 2 14 47 39 riscv,plic0,c000000 6 10050000.spi Signed-off-by: Atish Patra <[email protected]>
1 parent 1edeb50 commit 6023125

File tree

4 files changed

+53
-30
lines changed

4 files changed

+53
-30
lines changed

arch/riscv/include/asm/irq.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
#define INTERRUPT_CAUSE_TIMER 5
2222
#define INTERRUPT_CAUSE_EXTERNAL 9
2323

24-
void riscv_timer_interrupt(void);
25-
2624
#include <asm-generic/irq.h>
2725

2826
#endif /* _ASM_RISCV_IRQ_H */

arch/riscv/kernel/time.c

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,6 @@
2424

2525
unsigned long riscv_timebase;
2626

27-
DECLARE_PER_CPU(struct clock_event_device, riscv_clock_event);
28-
29-
void riscv_timer_interrupt(void)
30-
{
31-
#ifdef CONFIG_RISCV_TIMER
32-
/*
33-
* FIXME: This needs to be cleaned up along with the rest of the IRQ
34-
* handling cleanup. See irq.c for more details.
35-
*/
36-
struct clock_event_device *evdev = this_cpu_ptr(&riscv_clock_event);
37-
38-
/*
39-
* There are no direct SBI calls to clear pending timer interrupt bit.
40-
* Disable timer interrupt to ignore pending interrupt until next
41-
* interrupt.
42-
*/
43-
csr_clear(sie, SIE_STIE);
44-
evdev->event_handler(evdev);
45-
#endif
46-
}
47-
4827
static long __init timebase_frequency(void)
4928
{
5029
struct device_node *cpu;

drivers/clocksource/riscv_timer.c

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
#include <linux/clocksource.h>
1616
#include <linux/clockchips.h>
1717
#include <linux/delay.h>
18+
#include <linux/interrupt.h>
1819
#include <linux/timer_riscv.h>
1920
#include <linux/sched_clock.h>
2021
#include <linux/cpu.h>
22+
#include <linux/of.h>
23+
#include <linux/of_irq.h>
2124
#include <asm/sbi.h>
2225

2326
#define MINDELTA 100
@@ -73,6 +76,23 @@ DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = {
7376
.read = rdtime,
7477
};
7578

79+
static irqreturn_t riscv_timer_interrupt(int irq, void *dev_id)
80+
{
81+
struct clock_event_device *evdev = dev_id;
82+
#ifdef CONFIG_RISCV_TIMER
83+
84+
/*
85+
* There are no direct SBI calls to clear pending timer interrupt bit.
86+
* Disable timer interrupt to ignore pending interrupt until next
87+
* interrupt.
88+
*/
89+
csr_clear(sie, SIE_STIE);
90+
evdev->event_handler(evdev);
91+
#endif
92+
return IRQ_HANDLED;
93+
}
94+
95+
7696
static int hart_of_timer(struct device_node *dev)
7797
{
7898
u32 hart;
@@ -94,13 +114,20 @@ static u64 notrace timer_riscv_sched_read(void)
94114

95115
static int timer_riscv_starting_cpu(unsigned int cpu)
96116
{
117+
int err;
97118
struct clock_event_device *ce = per_cpu_ptr(&riscv_clock_event, cpu);
98119

99120
ce->cpumask = cpumask_of(cpu);
100121
clockevents_config_and_register(ce, riscv_timebase, MINDELTA, MAXDELTA);
101122
/* Enable timer interrupt for this cpu */
102123
csr_set(sie, SIE_STIE);
103124

125+
err = request_irq(ce->irq, riscv_timer_interrupt,
126+
IRQF_TIMER | IRQF_NOBALANCING, "local_timer", ce);
127+
if (err)
128+
pr_err("local timer can't register for interrupt [%d] [%d]\n",
129+
ce->irq, err);
130+
104131
return 0;
105132
}
106133

@@ -115,8 +142,27 @@ static int timer_riscv_dying_cpu(unsigned int cpu)
115142
static int __init timer_riscv_init_dt(struct device_node *n)
116143
{
117144
int err = 0;
118-
int cpu_id = hart_of_timer(n);
119-
struct clocksource *cs = per_cpu_ptr(&riscv_clocksource, cpu_id);
145+
int cpu_id, timer_int;
146+
struct device_node *parent;
147+
struct clocksource *cs;
148+
struct clock_event_device *ce;
149+
150+
timer_int = irq_of_parse_and_map(n, 0);
151+
if (!timer_int) {
152+
pr_err("Unable to find local timer irq\n");
153+
return -EINVAL;
154+
}
155+
156+
parent = of_get_parent(n);
157+
if (!parent) {
158+
pr_err("Parent of timer node doesn't exist\n");
159+
return -EINVAL;
160+
}
161+
cpu_id = hart_of_timer(parent);
162+
163+
cs = per_cpu_ptr(&riscv_clocksource, cpu_id);
164+
ce = per_cpu_ptr(&riscv_clock_event, cpu_id);
165+
ce->irq = timer_int;
120166

121167
if (cpu_id == smp_processor_id()) {
122168
clocksource_register_hz(cs, riscv_timebase);
@@ -125,11 +171,14 @@ static int __init timer_riscv_init_dt(struct device_node *n)
125171
err = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING,
126172
"clockevents/riscv/timer:starting",
127173
timer_riscv_starting_cpu, timer_riscv_dying_cpu);
128-
if (err)
174+
if (err) {
129175
pr_err("RISCV timer register failed [%d] for cpu = [%d]\n",
130176
err, cpu_id);
177+
free_percpu_irq(ce->irq, ce);
178+
return err;
179+
}
131180
}
132181
return err;
133182
}
134183

135-
TIMER_OF_DECLARE(riscv_timer, "riscv", timer_riscv_init_dt);
184+
TIMER_OF_DECLARE(riscv_timer, "riscv,local-timer", timer_riscv_init_dt);

drivers/irqchip/irq-riscv-intc.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,6 @@ void riscv_intc_irq(struct pt_regs *regs)
7575
* device interrupts use the generic IRQ mechanisms.
7676
*/
7777
switch (cause) {
78-
case INTERRUPT_CAUSE_TIMER:
79-
riscv_timer_interrupt();
80-
break;
8178
case INTERRUPT_CAUSE_SOFTWARE:
8279
riscv_software_interrupt();
8380
break;

0 commit comments

Comments
 (0)