1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * Copyright (c) 2016-2019, Linaro Limited
4 */
5 #ifndef __KERNEL_INTERRUPT_H
6 #define __KERNEL_INTERRUPT_H
7
8 #include <dt-bindings/interrupt-controller/irq.h>
9 #include <kernel/dt_driver.h>
10 #include <mm/core_memprot.h>
11 #include <sys/queue.h>
12 #include <tee_api_types.h>
13 #include <types_ext.h>
14 #include <util.h>
15
16 #define ITRF_TRIGGER_LEVEL BIT(0)
17 #define ITRF_SHARED BIT(1)
18
19 /* Forward the interrupt only to the current CPU */
20 #define ITR_CPU_MASK_TO_THIS_CPU BIT(31)
21 /* Forward the interrupt to all CPUs except the current CPU */
22 #define ITR_CPU_MASK_TO_OTHER_CPUS BIT(30)
23
24 struct itr_handler;
25
26 /*
27 * struct itr_chip - Interrupt controller
28 *
29 * @ops Operation callback functions
30 * @name Controller name, for debug purpose
31 * @handlers Registered handlers list head
32 * @dt_get_irq Device tree node parsing function
33 */
34 struct itr_chip {
35 const struct itr_ops *ops;
36 const char *name;
37 SLIST_HEAD(, itr_handler) handlers;
38 /*
39 * dt_get_irq - parse a device tree interrupt property
40 *
41 * @properties Big-endian interrupt property array from device tree
42 * @count number of elements in @properties
43 * @type If not NULL, output interrupt type (IRQ_TYPE_* defines)
44 * or IRQ_TYPE_NONE if unknown
45 * @prio If not NULL, output interrupt priority value or 0 if unknown
46 *
47 * This handler is required to support dt_get_irq_type_prio() and
48 * dt_get_irq() API function for interrupt consumers manually
49 * retrieving trigger type and/or priority from the device tree.
50 */
51 int (*dt_get_irq)(const uint32_t *properties, int count, uint32_t *type,
52 uint32_t *prio);
53 };
54
55 /*
56 * struct itr_ops - Interrupt controller operations
57 * @configure Configure an interrupt
58 * @enable Enable an interrupt
59 * @disable Disable an interrupt
60 * @mask Mask an interrupt, may be called from an interrupt context
61 * @unmask Unmask an interrupt, may be called from an interrupt context
62 * @raise_pi Raise per-cpu interrupt or NULL if not applicable
63 * @raise_sgi Raise a SGI or NULL if not applicable to that controller
64 * @set_affinity Set interrupt/cpu affinity or NULL if not applicable
65 * @set_wake Enable/disable power-management wake-on of an interrupt or NULL
66 * if not applicable
67 *
68 * Handlers @enable, @disable, @mask and @unmask are mandated. Handlers
69 * @mask and @unmask have unpaged memory constraints. These requirements are
70 * verified by itr_chip_init() and itr_chip_dt_only_init().
71 *
72 * Handler @configure is needed for interrupt providers which do not rely on
73 * DT for consumers interrupt configuration, that is interrupt consumers using
74 * interrupt_configure() or friends (interrupt_add_handler(),
75 * interrupt_add_configure_handler(), interrupt_add_handler_with_chip(),
76 * etc...).
77 */
78 struct itr_ops {
79 void (*configure)(struct itr_chip *chip, size_t it, uint32_t type,
80 uint32_t prio);
81 void (*enable)(struct itr_chip *chip, size_t it);
82 void (*disable)(struct itr_chip *chip, size_t it);
83 void (*mask)(struct itr_chip *chip, size_t it);
84 void (*unmask)(struct itr_chip *chip, size_t it);
85 void (*raise_pi)(struct itr_chip *chip, size_t it);
86 void (*raise_sgi)(struct itr_chip *chip, size_t it,
87 uint32_t cpu_mask);
88 void (*set_affinity)(struct itr_chip *chip, size_t it,
89 uint8_t cpu_mask);
90 void (*set_wake)(struct itr_chip *chip, size_t it, bool on);
91 };
92
93 /*
94 * struct itr_desc - Interrupt description
95 * @chip Interrupt controller reference
96 * @itr_num Interrupt number
97 *
98 * This struct is used for binding interrupt device data between
99 * drivers when using DT_DRIVERS means. See itr_dt_get_func type
100 * definition.
101 */
102 struct itr_desc {
103 struct itr_chip *chip;
104 size_t itr_num;
105 };
106
107 /* Interrupt handler return value */
108 enum itr_return {
109 ITRR_NONE,
110 ITRR_HANDLED,
111 };
112
113 /* Interrupt handler signature */
114 typedef enum itr_return (*itr_handler_t)(struct itr_handler *h);
115
116 /*
117 * struct itr_handler - Interrupt handler reference
118 * @it Interrupt number
119 * @flags Property bit flags (ITRF_*) or 0
120 * @data Private data for that interrupt handler
121 * @chip Interrupt controller chip device
122 * @link Reference in controller handler list
123 */
124 struct itr_handler {
125 size_t it;
126 uint32_t flags;
127 itr_handler_t handler;
128 void *data;
129 struct itr_chip *chip;
130 SLIST_ENTRY(itr_handler) link;
131 };
132
133 #define ITR_HANDLER(_chip, _itr_num, _flags, _fn, _priv) \
134 ((struct itr_handler){ \
135 .chip = (_chip), .it = (_itr_num), .flags = (_flags), \
136 .handler = (_fn), .data = (_priv), \
137 })
138
139 /*
140 * Initialise an interrupt controller handle to be used only with the DT
141 * @chip Interrupt controller
142 */
143 TEE_Result itr_chip_dt_only_init(struct itr_chip *chip);
144
145 /*
146 * Initialise an interrupt controller handle
147 * @chip Interrupt controller
148 */
149 TEE_Result itr_chip_init(struct itr_chip *chip);
150
151 /*
152 * Initialise main interrupt controller driver
153 * @data Main controller main data reference to register
154 */
155 void interrupt_main_init(struct itr_chip *data);
156
157 /* Retrieve main interrupt controller reference */
158 struct itr_chip *interrupt_get_main_chip(void);
159 /* Retrieve main interrupt controller reference, or NULL on failure */
160 struct itr_chip *interrupt_get_main_chip_may_fail(void);
161
162 #ifdef CFG_DT
163 /*
164 * Get the DT interrupt property at @node. In the DT an interrupt property can
165 * specify additional information which can be retrieved with @type and @prio.
166 *
167 * @fdt reference to the Device Tree
168 * @node is the node offset to read the interrupt property from
169 * @type interrupt type (IRQ_TYPE_* defines) if specified by interrupt property
170 * or IRQ_TYPE_NONE if not. Can be NULL if not needed
171 * @prio interrupt priority if specified by interrupt property or 0 if not. Can
172 * be NULL if not needed
173 *
174 * Returns the interrupt number if value >= 0
175 * otherwise DT_INFO_INVALID_INTERRUPT
176 */
177 int dt_get_irq_type_prio(const void *fdt, int node, uint32_t *type,
178 uint32_t *prio);
179
180 /*
181 * Get the DT interrupt property at @node
182 */
dt_get_irq(const void * fdt,int node)183 static inline int dt_get_irq(const void *fdt, int node)
184 {
185 return dt_get_irq_type_prio(fdt, node, NULL, NULL);
186 }
187 #endif
188
189 /*
190 * __weak overridable function which is called when a secure interrupt is
191 * received. The default function calls panic() immediately, platforms which
192 * expects to receive secure interrupts should override this function.
193 */
194 void interrupt_main_handler(void);
195
196 /*
197 * Interrupt controller chip API functions
198 */
199
200 /*
201 * interrupt_call_handlers() - Call registered handlers for an interrupt
202 * @chip Interrupt controller
203 * @itr_num Interrupt number
204 *
205 * This function is called from an interrupt context by a primary interrupt
206 * handler. This function calls the handlers registered for that interrupt.
207 * If interrupt is not handled, it is masked.
208 */
209 void interrupt_call_handlers(struct itr_chip *chip, size_t itr_num);
210
211 /*
212 * interrupt_mask() - Mask an interrupt
213 * @chip Interrupt controller
214 * @itr_num Interrupt number
215 *
216 * This function may be called in interrupt context
217 */
interrupt_mask(struct itr_chip * chip,size_t itr_num)218 static inline void interrupt_mask(struct itr_chip *chip, size_t itr_num)
219 {
220 chip->ops->mask(chip, itr_num);
221 }
222
223 /*
224 * interrupt_unmask() - Unmask an interrupt
225 * @chip Interrupt controller
226 * @itr_num Interrupt number
227 *
228 * This function may be called in interrupt context
229 */
interrupt_unmask(struct itr_chip * chip,size_t itr_num)230 static inline void interrupt_unmask(struct itr_chip *chip, size_t itr_num)
231 {
232 chip->ops->unmask(chip, itr_num);
233 }
234
235 /*
236 * interrupt_enable() - Enable an interrupt
237 * @chip Interrupt controller
238 * @itr_num Interrupt number
239 */
interrupt_enable(struct itr_chip * chip,size_t itr_num)240 static inline void interrupt_enable(struct itr_chip *chip, size_t itr_num)
241 {
242 chip->ops->enable(chip, itr_num);
243 }
244
245 /*
246 * interrupt_disable() - Disable an interrupt
247 * @chip Interrupt controller
248 * @itr_num Interrupt number
249 */
interrupt_disable(struct itr_chip * chip,size_t itr_num)250 static inline void interrupt_disable(struct itr_chip *chip, size_t itr_num)
251 {
252 chip->ops->disable(chip, itr_num);
253 }
254
255 /*
256 * interrupt_can_raise_pi() - Return whether controller embeds raise_pi
257 * @chip Interrupt controller
258 */
interrupt_can_raise_pi(struct itr_chip * chip)259 static inline bool interrupt_can_raise_pi(struct itr_chip *chip)
260 {
261 return chip->ops->raise_pi;
262 }
263
264 /*
265 * interrupt_can_raise_sgi() - Return whether controller embeds raise_sgi
266 * @chip Interrupt controller
267 */
interrupt_can_raise_sgi(struct itr_chip * chip)268 static inline bool interrupt_can_raise_sgi(struct itr_chip *chip)
269 {
270 return chip->ops->raise_sgi;
271 }
272
273 /*
274 * interrupt_can_set_affinity() - Return whether controller embeds set_affinity
275 * @chip Interrupt controller
276 */
interrupt_can_set_affinity(struct itr_chip * chip)277 static inline bool interrupt_can_set_affinity(struct itr_chip *chip)
278 {
279 return chip->ops->set_affinity;
280 }
281
282 /*
283 * interrupt_can_set_wake() - Return whether controller embeds set_wake
284 * @chip Interrupt controller
285 */
interrupt_can_set_wake(struct itr_chip * chip)286 static inline bool interrupt_can_set_wake(struct itr_chip *chip)
287 {
288 return chip->ops->set_wake;
289 }
290
291 /*
292 * interrupt_raise_pi() - Raise a peripheral interrupt of a controller
293 * @chip Interrupt controller
294 * @itr_num Interrupt number to raise
295 */
interrupt_raise_pi(struct itr_chip * chip,size_t itr_num)296 static inline void interrupt_raise_pi(struct itr_chip *chip, size_t itr_num)
297 {
298 assert(interrupt_can_raise_pi(chip));
299 chip->ops->raise_pi(chip, itr_num);
300 }
301
302 /*
303 * interrupt_raise_sgi() - Raise a software generiated interrupt of a controller
304 * @chip Interrupt controller
305 * @itr_num Interrupt number to raise
306 * @cpu_mask: A bitfield of CPUs to forward the interrupt to, unless
307 * ITR_CPU_MASK_TO_THIS_CPU or ITR_CPU_MASK_TO_OTHER_CPUS
308 * (mutually exclusive) are set.
309 */
interrupt_raise_sgi(struct itr_chip * chip,size_t itr_num,uint32_t cpu_mask)310 static inline void interrupt_raise_sgi(struct itr_chip *chip, size_t itr_num,
311 uint32_t cpu_mask)
312 {
313 assert(interrupt_can_raise_sgi(chip));
314 chip->ops->raise_sgi(chip, itr_num, cpu_mask);
315 }
316
317 /*
318 * interrupt_set_affinity() - Set CPU affinity for a controller interrupt
319 * @chip Interrupt controller
320 * @itr_num Interrupt number
321 * @cpu_mask Mask of the CPUs targeted by the interrupt
322 */
interrupt_set_affinity(struct itr_chip * chip,size_t itr_num,uint8_t cpu_mask)323 static inline void interrupt_set_affinity(struct itr_chip *chip, size_t itr_num,
324 uint8_t cpu_mask)
325 {
326 assert(interrupt_can_set_affinity(chip));
327 chip->ops->set_affinity(chip, itr_num, cpu_mask);
328 }
329
330 /*
331 * interrupt_set_wake() - Enable/disable power-management wake-on of interrupt
332 * @chip Interrupt controller
333 * @itr_num Interrupt number
334 * @on A boolean for enable/disable
335 */
interrupt_set_wake(struct itr_chip * chip,size_t itr_num,bool on)336 static inline void interrupt_set_wake(struct itr_chip *chip, size_t itr_num,
337 bool on)
338 {
339 assert(interrupt_can_set_wake(chip));
340 chip->ops->set_wake(chip, itr_num, on);
341 }
342
343 /*
344 * interrupt_configure() - Configure an interrupt in an interrupt controller
345 * @chip Interrupt controller
346 * @itr_num Interrupt number
347 * @type Interrupt trigger type (IRQ_TYPE_* defines) or IRQ_TYPE_NONE
348 * @prio Interrupt priority or 0
349 *
350 * Interrupt consumers that get their interrupt from the DT do not need to
351 * call interrupt_configure() since the interrupt configuration has already
352 * been done by interrupt controller based on the DT bidings.
353 */
354 TEE_Result interrupt_configure(struct itr_chip *chip, size_t itr_num,
355 uint32_t type, uint32_t prio);
356
357 /*
358 * interrupt_add_and_configure_handler() - Register and configure a handler
359 * @hdl Interrupt handler to register
360 * @type Interrupt trigger type (IRQ_TYPE_* defines) or IRQ_TYPE_NONE
361 * @prio Interrupt priority or 0
362 */
363 TEE_Result interrupt_add_configure_handler(struct itr_handler *hdl,
364 uint32_t type, uint32_t prio);
365
366 /*
367 * interrupt_add_handler() - Register an interrupt handler
368 * @hdl Interrupt handler to register
369 *
370 * This helper function assumes interrupt type is set to IRQ_TYPE_NONE
371 * and interrupt priority to 0.
372 */
interrupt_add_handler(struct itr_handler * hdl)373 static inline TEE_Result interrupt_add_handler(struct itr_handler *hdl)
374 {
375 return interrupt_add_configure_handler(hdl, IRQ_TYPE_NONE, 0);
376 }
377
378 /*
379 * interrupt_create_handler() - Allocate/register an interrupt callback handler
380 * @itr_chip Interrupt chip obtained from interrupt_dt_get_by_*() or like
381 * @itr_num Interrupt number obtained from interrupt_dt_get_by_*() or like
382 * @callback Callback handler function
383 * @priv Private dat to pssa to @callback
384 * @flags INTERRUPT_FLAGS_* or 0
385 * @out_hdl Output allocated and registered handler or NULL
386 *
387 * This function differs from interrupt_add_handler() in that the
388 * interrupt is not reconfigured. interrupt_create_handler() expects
389 * @itr_chip and @itr_num were obtained from a call
390 * to interrupt_dt_get_by_index() or interrupt_dt_get_by_name() that
391 * are in charge of configuring the interrupt according to its DT property.
392 */
393 TEE_Result interrupt_create_handler(struct itr_chip *itr_chip, size_t itr_num,
394 itr_handler_t callback, void *priv,
395 uint32_t flags,
396 struct itr_handler **out_hdl);
397
398 /*
399 * interrupt_add_handler_with_chip() - Register an interrupt handler providing
400 * the interrupt chip reference in specific argument @chip.
401 * @chip Interrupt controller
402 * @h Interrupt handler to register
403 */
interrupt_add_handler_with_chip(struct itr_chip * chip,struct itr_handler * h)404 static inline TEE_Result interrupt_add_handler_with_chip(struct itr_chip *chip,
405 struct itr_handler *h)
406 {
407 h->chip = chip;
408 return interrupt_add_handler(h);
409 }
410
411 /*
412 * interrupt_remove_handler() - Remove a registered interrupt handler
413 * @hdl Interrupt handler to remove
414 *
415 * This function is the counterpart of interrupt_add_handler().
416 * This function may panic on non-NULL invalid @hdl reference.
417 */
418 void interrupt_remove_handler(struct itr_handler *hdl);
419
420 /*
421 * interrupt_alloc_add_conf_handler() - Allocate, configure, register a handler
422 * @chip Interrupt controller
423 * @itr_num Interrupt number
424 * @handler Interrupt handler to register
425 * @flags Bitmask flag ITRF_*
426 * @data Private data reference passed to @handler
427 * @type Interrupt trigger type (IRQ_TYPE_* defines) or IRQ_TYPE_NONE
428 * @prio Interrupt priority or 0
429 * @out_hdl NULL or output pointer to allocated struct itr_handler
430 */
431 TEE_Result interrupt_alloc_add_conf_handler(struct itr_chip *chip,
432 size_t it_num,
433 itr_handler_t handler,
434 uint32_t flags, void *data,
435 uint32_t type, uint32_t prio,
436 struct itr_handler **out_hdl);
437
438 /*
439 * interrupt_alloc_add_handler() - Allocate and register an interrupt handler
440 * @chip Interrupt controller
441 * @itr_num Interrupt number
442 * @handler Interrupt handler to register
443 * @flags Bitmask flag ITRF_*
444 * @data Private data reference passed to @handler
445 * @out_hdl NULL or output pointer to allocated struct itr_handler
446 */
interrupt_alloc_add_handler(struct itr_chip * chip,size_t it_num,itr_handler_t handler,uint32_t flags,void * data,struct itr_handler ** hdl)447 static inline TEE_Result interrupt_alloc_add_handler(struct itr_chip *chip,
448 size_t it_num,
449 itr_handler_t handler,
450 uint32_t flags,
451 void *data,
452 struct itr_handler **hdl)
453 {
454 return interrupt_alloc_add_conf_handler(chip, it_num, handler, flags,
455 data, IRQ_TYPE_NONE, 0, hdl);
456 }
457
458 /*
459 * interrupt_remove_free_handler() - Remove/free a registered interrupt handler
460 * @hdl Interrupt handler to remove and free
461 *
462 * This function is the counterpart of interrupt_alloc_add_handler()
463 * and interrupt_alloc_add_conf_handler().
464 * This function may panic on non-NULL invalid @hdl reference.
465 */
466 void interrupt_remove_free_handler(struct itr_handler *hdl);
467
468 /*
469 * itr_dt_get_func - Typedef of function to get an interrupt in DT node
470 *
471 * @args Reference to phandle arguments
472 * @data Pointer to data given at interrupt_register_provider() call
473 * @itr_desc_p Pointer to the struct itr_desc to fill
474 * Return TEE_SUCCESS in case of success.
475 * Return TEE_ERROR_DEFER_DRIVER_INIT if controller is not initialized.
476 * Return another TEE_Result code otherwise.
477 *
478 * Upon success, the interrupt is configured and consumer can add a handler
479 * function to the interrupt. Yet, the interrupt is not enabled until consumer
480 * calls interrupt_enable().
481 */
482 typedef TEE_Result (*itr_dt_get_func)(struct dt_pargs *args, void *data,
483 struct itr_desc *itr_desc_p);
484
485 #ifdef CFG_DT
486 /**
487 * interrupt_register_provider() - Register an interrupt provider
488 *
489 * @fdt Device tree to work on
490 * @node Node offset of the interrupt controller in the DT
491 * @dt_get_itr Callback to match the devicetree interrupt reference with
492 * @data Data which will be passed to the get_dt_its callback
493 */
494 TEE_Result interrupt_register_provider(const void *fdt, int node,
495 itr_dt_get_func dt_get_itr, void *data);
496
497 /**
498 * interrupt_dt_get_by_index() - Get an interrupt from DT by interrupt index
499 *
500 * Interrupt index (@index) refers to the index of the target interrupt to be
501 * retrieved as DT binding property "interrupts" may define several
502 * interrupts.
503 *
504 * @fdt Device tree to work on
505 * @node Node offset of the subnode containing interrupt(s) references
506 * @index Index in "interrupts" or "interrupts-extended" property list
507 * @chip Output interrupt controller reference upon success
508 * @itr_num Output interrupt number upon success
509 *
510 * Return TEE_SUCCESS in case of success
511 * Return TEE_ERROR_DEFER_DRIVER_INIT if interrupt driver is not yet initialized
512 * Return TEE_ERROR_ITEM_NOT_FOUND if the DT does not reference target interrupt
513 * Return any other TEE_Result compliant code in case of error
514 */
515 TEE_Result interrupt_dt_get_by_index(const void *fdt, int node,
516 unsigned int index, struct itr_chip **chip,
517 size_t *itr_num);
518
519 /**
520 * interrupt_dt_get_by_name() - Get an interrupt from DT by interrupt name
521 *
522 * @fdt Device tree to work on
523 * @node Node offset of the subnode containing interrupt(s) references
524 * @name Name identifier used in "interrupt-names" property
525 * @chip Output interrupt controller reference upon success
526 * @itr_num Output interrupt number upon success
527 *
528 * Return TEE_SUCCESS in case of success
529 * Return TEE_ERROR_DEFER_DRIVER_INIT if interrupt driver is not yet initialized
530 * Return TEE_ERROR_ITEM_NOT_FOUND if the DT does not reference target interrupt
531 * Return any other TEE_Result compliant code in case of error
532 */
533 TEE_Result interrupt_dt_get_by_name(const void *fdt, int node, const char *name,
534 struct itr_chip **chip, size_t *itr_num);
535 #else
interrupt_register_provider(const void * dt __unused,int node __unused,itr_dt_get_func f __unused,void * data __unused)536 static inline TEE_Result interrupt_register_provider(const void *dt __unused,
537 int node __unused,
538 itr_dt_get_func f __unused,
539 void *data __unused)
540 {
541 return TEE_ERROR_NOT_IMPLEMENTED;
542 }
543
interrupt_dt_get_by_index(const void * fdt __unused,int node __unused,unsigned int index __unused,struct itr_chip ** c __unused,size_t * itr_num __unused)544 static inline TEE_Result interrupt_dt_get_by_index(const void *fdt __unused,
545 int node __unused,
546 unsigned int index __unused,
547 struct itr_chip **c __unused,
548 size_t *itr_num __unused)
549 {
550 return TEE_ERROR_NOT_IMPLEMENTED;
551 }
552
interrupt_dt_get_by_name(const void * fdt __unused,int node __unused,const char * name __unused,struct itr_chip ** ch __unused,size_t * itr_num __unused)553 static inline TEE_Result interrupt_dt_get_by_name(const void *fdt __unused,
554 int node __unused,
555 const char *name __unused,
556 struct itr_chip **ch __unused,
557 size_t *itr_num __unused)
558 {
559 return TEE_ERROR_NOT_IMPLEMENTED;
560 }
561 #endif /*CFG_DT*/
562
563 /*
564 * Helper function for when caller retrieves the first interrupt defined
565 * in "interrupts" or "interrupts-extended" DT binding property list.
566 */
interrupt_dt_get(const void * fdt,int node,struct itr_chip ** chip,size_t * itr_num)567 static inline TEE_Result interrupt_dt_get(const void *fdt, int node,
568 struct itr_chip **chip,
569 size_t *itr_num)
570 {
571 return interrupt_dt_get_by_index(fdt, node, 0, chip, itr_num);
572 }
573 #endif /*__KERNEL_INTERRUPT_H*/
574