xref: /optee_os/core/include/kernel/interrupt.h (revision 0960b6765c51598643bdb226a3bfaeab1b0e608f)
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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
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 
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 
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  */
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