12
12
#include <linux/cpu.h>
13
13
#include <linux/delay.h>
14
14
#include <linux/irq.h>
15
+ #include <linux/irqdomain.h>
15
16
#include <linux/sched_clock.h>
16
17
#include <linux/io-64-nonatomic-lo-hi.h>
18
+ #include <linux/interrupt.h>
19
+ #include <linux/of_irq.h>
17
20
#include <asm/smp.h>
18
21
#include <asm/sbi.h>
19
22
@@ -39,6 +42,7 @@ static int riscv_clock_next_event(unsigned long delta,
39
42
return 0 ;
40
43
}
41
44
45
+ static unsigned int riscv_clock_event_irq ;
42
46
static DEFINE_PER_CPU (struct clock_event_device , riscv_clock_event ) = {
43
47
.name = "riscv_timer_clockevent" ,
44
48
.features = CLOCK_EVT_FEAT_ONESHOT ,
@@ -74,30 +78,36 @@ static int riscv_timer_starting_cpu(unsigned int cpu)
74
78
struct clock_event_device * ce = per_cpu_ptr (& riscv_clock_event , cpu );
75
79
76
80
ce -> cpumask = cpumask_of (cpu );
81
+ ce -> irq = riscv_clock_event_irq ;
77
82
clockevents_config_and_register (ce , riscv_timebase , 100 , 0x7fffffff );
78
83
79
- csr_set (CSR_IE , IE_TIE );
84
+ enable_percpu_irq (riscv_clock_event_irq ,
85
+ irq_get_trigger_type (riscv_clock_event_irq ));
80
86
return 0 ;
81
87
}
82
88
83
89
static int riscv_timer_dying_cpu (unsigned int cpu )
84
90
{
85
- csr_clear ( CSR_IE , IE_TIE );
91
+ disable_percpu_irq ( riscv_clock_event_irq );
86
92
return 0 ;
87
93
}
88
94
89
95
/* called directly from the low-level interrupt handler */
90
- void riscv_timer_interrupt (void )
96
+ static irqreturn_t riscv_timer_interrupt (int irq , void * dev_id )
91
97
{
92
98
struct clock_event_device * evdev = this_cpu_ptr (& riscv_clock_event );
93
99
94
100
csr_clear (CSR_IE , IE_TIE );
95
101
evdev -> event_handler (evdev );
102
+
103
+ return IRQ_HANDLED ;
96
104
}
97
105
98
106
static int __init riscv_timer_init_dt (struct device_node * n )
99
107
{
100
108
int cpuid , hartid , error ;
109
+ struct device_node * child ;
110
+ struct irq_domain * domain ;
101
111
102
112
hartid = riscv_of_processor_hartid (n );
103
113
if (hartid < 0 ) {
@@ -115,6 +125,25 @@ static int __init riscv_timer_init_dt(struct device_node *n)
115
125
if (cpuid != smp_processor_id ())
116
126
return 0 ;
117
127
128
+ domain = NULL ;
129
+ child = of_get_compatible_child (n , "riscv,cpu-intc" );
130
+ if (!child ) {
131
+ pr_err ("Failed to find INTC node [%pOF]\n" , n );
132
+ return - ENODEV ;
133
+ }
134
+ domain = irq_find_host (child );
135
+ of_node_put (child );
136
+ if (!domain ) {
137
+ pr_err ("Failed to find IRQ domain for node [%pOF]\n" , n );
138
+ return - ENODEV ;
139
+ }
140
+
141
+ riscv_clock_event_irq = irq_create_mapping (domain , RV_IRQ_TIMER );
142
+ if (!riscv_clock_event_irq ) {
143
+ pr_err ("Failed to map timer interrupt for node [%pOF]\n" , n );
144
+ return - ENODEV ;
145
+ }
146
+
118
147
pr_info ("%s: Registering clocksource cpuid [%d] hartid [%d]\n" ,
119
148
__func__ , cpuid , hartid );
120
149
error = clocksource_register_hz (& riscv_clocksource , riscv_timebase );
@@ -126,6 +155,14 @@ static int __init riscv_timer_init_dt(struct device_node *n)
126
155
127
156
sched_clock_register (riscv_sched_clock , 64 , riscv_timebase );
128
157
158
+ error = request_percpu_irq (riscv_clock_event_irq ,
159
+ riscv_timer_interrupt ,
160
+ "riscv-timer" , & riscv_clock_event );
161
+ if (error ) {
162
+ pr_err ("registering percpu irq failed [%d]\n" , error );
163
+ return error ;
164
+ }
165
+
129
166
error = cpuhp_setup_state (CPUHP_AP_RISCV_TIMER_STARTING ,
130
167
"clockevents/riscv/timer:starting" ,
131
168
riscv_timer_starting_cpu , riscv_timer_dying_cpu );
0 commit comments