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