|
15 | 15 | #include <linux/clocksource.h> |
16 | 16 | #include <linux/clockchips.h> |
17 | 17 | #include <linux/delay.h> |
| 18 | +#include <linux/interrupt.h> |
18 | 19 | #include <linux/timer_riscv.h> |
19 | 20 | #include <linux/sched_clock.h> |
20 | 21 | #include <linux/cpu.h> |
| 22 | +#include <linux/of.h> |
| 23 | +#include <linux/of_irq.h> |
21 | 24 | #include <asm/sbi.h> |
22 | 25 |
|
23 | 26 | #define MINDELTA 100 |
@@ -73,6 +76,23 @@ DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = { |
73 | 76 | .read = rdtime, |
74 | 77 | }; |
75 | 78 |
|
| 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 | + |
76 | 96 | static int hart_of_timer(struct device_node *dev) |
77 | 97 | { |
78 | 98 | u32 hart; |
@@ -100,36 +120,69 @@ static int timer_riscv_starting_cpu(unsigned int cpu) |
100 | 120 | clockevents_config_and_register(ce, riscv_timebase, MINDELTA, MAXDELTA); |
101 | 121 | /* Enable timer interrupt for this cpu */ |
102 | 122 | csr_set(sie, SIE_STIE); |
| 123 | + enable_percpu_irq(ce->irq, IRQ_TYPE_NONE); |
103 | 124 |
|
104 | 125 | return 0; |
105 | 126 | } |
106 | 127 |
|
107 | 128 | static int timer_riscv_dying_cpu(unsigned int cpu) |
108 | 129 | { |
| 130 | + struct clock_event_device *ce = per_cpu_ptr(&riscv_clock_event, cpu); |
109 | 131 | /* Disable timer interrupt for this cpu */ |
110 | 132 | csr_clear(sie, SIE_STIE); |
| 133 | + disable_percpu_irq(ce->irq); |
111 | 134 |
|
112 | 135 | return 0; |
113 | 136 | } |
114 | 137 |
|
115 | 138 | static int __init timer_riscv_init_dt(struct device_node *n) |
116 | 139 | { |
117 | 140 | int err = 0; |
118 | | - int cpu_id = hart_of_timer(n); |
119 | | - struct clocksource *cs = per_cpu_ptr(&riscv_clocksource, cpu_id); |
| 141 | + int cpu_id, timer_int; |
| 142 | + struct device_node *parent; |
| 143 | + struct clocksource *cs; |
| 144 | + struct clock_event_device *ce; |
| 145 | + |
| 146 | + timer_int = irq_of_parse_and_map(n, 0); |
| 147 | + if (!timer_int) { |
| 148 | + pr_err("Unable to find local timer irq\n"); |
| 149 | + return -EINVAL; |
| 150 | + } |
120 | 151 |
|
| 152 | + parent = of_get_parent(n); |
| 153 | + if (!parent) { |
| 154 | + pr_err("Parent of timer node doesn't exist\n"); |
| 155 | + return -EINVAL; |
| 156 | + } |
| 157 | + cpu_id = hart_of_timer(parent); |
| 158 | + |
| 159 | + cs = per_cpu_ptr(&riscv_clocksource, cpu_id); |
| 160 | + ce = per_cpu_ptr(&riscv_clock_event, cpu_id); |
| 161 | + ce->irq = timer_int; |
| 162 | + |
| 163 | + err = request_percpu_irq(ce->irq, riscv_timer_interrupt, |
| 164 | + "local_timer", &riscv_clock_event); |
| 165 | + if (err) { |
| 166 | + pr_err("local timer can't register for interrupt [%d] [%d]\n", |
| 167 | + timer_int, err); |
| 168 | + free_percpu_irq(ce->irq, ce); |
| 169 | + return err; |
| 170 | + } |
121 | 171 | if (cpu_id == smp_processor_id()) { |
122 | 172 | clocksource_register_hz(cs, riscv_timebase); |
123 | 173 | sched_clock_register(timer_riscv_sched_read, 64, riscv_timebase); |
124 | 174 |
|
125 | 175 | err = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING, |
126 | 176 | "clockevents/riscv/timer:starting", |
127 | 177 | timer_riscv_starting_cpu, timer_riscv_dying_cpu); |
128 | | - if (err) |
| 178 | + if (err) { |
129 | 179 | pr_err("RISCV timer register failed [%d] for cpu = [%d]\n", |
130 | 180 | err, cpu_id); |
| 181 | + free_percpu_irq(ce->irq, ce); |
| 182 | + return err; |
| 183 | + } |
131 | 184 | } |
132 | 185 | return err; |
133 | 186 | } |
134 | 187 |
|
135 | | -TIMER_OF_DECLARE(riscv_timer, "riscv", timer_riscv_init_dt); |
| 188 | +TIMER_OF_DECLARE(riscv_timer, "riscv,local-timer", timer_riscv_init_dt); |
0 commit comments