1 /*
2  * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * @file	irq.h
9  * @brief	Interrupt handling primitives for libmetal.
10  */
11 
12 #ifndef __METAL_IRQ_CONTROLLER__H__
13 #define __METAL_IRQ_CONTROLLER__H__
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /** \defgroup irq Interrupt Handling Interfaces
20  *  @{
21  */
22 
23 #include <metal/irq.h>
24 #include <metal/list.h>
25 #include <stdlib.h>
26 
27 /** IRQ ANY ID */
28 #define METAL_IRQ_ANY         (-1)
29 
30 /** IRQ state macro which will be passed to metal irq set state function
31  *  to indicate which state the caller want the IRQ to change to.
32  */
33 #define METAL_IRQ_DISABLE    0U
34 #define METAL_IRQ_ENABLE     1U
35 
36 struct metal_irq_controller;
37 
38 /**
39  * @brief	type of interrupt controller to set irq enable
40  * @param[in]   irq_cntr pointer to interrupt controller
41  * @param[in]   irq interrupt id
42  * @param[in]   enable IRQ state
43  */
44 typedef void (*metal_irq_set_enable) (struct metal_irq_controller *irq_cntr,
45 				     int irq, unsigned int enable);
46 
47 /**
48  * @brief	type of controller specific registering interrupt function
49  * @param[in]   irq_cntr pointer to interrupt controller
50  * @param[in]   irq interrupt id
51  * @param[in]   hd interrupt handler
52  * @param[in]   arg argument which will be passed to the interrupt handler
53  * @return 0 for success, negative value for failure
54  */
55 typedef int (*metal_cntr_irq_register) (struct metal_irq_controller *irq_cntr,
56 					int irq, metal_irq_handler hd,
57 					void *arg);
58 
59 /** Libmetal interrupt structure */
60 struct metal_irq {
61 	metal_irq_handler hd; /**< Interrupt handler */
62 	void *arg; /**< Argument to pass to the interrupt handler */
63 };
64 
65 /** Libmetal interrupt controller structure */
66 struct metal_irq_controller {
67 	int irq_base; /**< Start of IRQ number of the range managed by
68 		 	* the IRQ controller
69 		 	*/
70 	int irq_num; /**< Number of IRQs managed by the IRQ controller */
71 	void *arg; /**< Argument to pass to interrupt controller function */
72 	metal_irq_set_enable irq_set_enable; /**< function to set IRQ enable */
73 	metal_cntr_irq_register irq_register; /**< function to register IRQ
74 						* handler
75 						*/
76 	struct metal_list node; /**< list node */
77 	struct metal_irq *irqs; /**< Array of IRQs managed by the controller */
78 };
79 
80 #define METAL_IRQ_CONTROLLER_DECLARE(_irq_controller, \
81 				     _irq_base, _irq_num, \
82 				     _arg, \
83 				     _irq_set_enable, \
84 				     _irq_register, \
85 				     _irqs) \
86 	struct metal_irq_controller _irq_controller = { \
87 		.irq_base = _irq_base, \
88 		.irq_num = _irq_num, \
89 		.arg = _arg, \
90 		.irq_set_enable = _irq_set_enable, \
91 		.irq_register = _irq_register, \
92 		.irqs = _irqs,\
93 	}
94 
95 /**
96  * @brief	metal_irq_register_controller
97  *
98  * Register IRQ controller
99  * This function will allocate IRQ ids if it was
100  * not predefined in the irq controller. There is no
101  * locking in the function, it is not supposed to be
102  * called by multiple threads.
103  *
104  * @param[in] cntr  Interrupt controller to register
105  * @return 0 on success, or negative value for failure.
106  */
107 int metal_irq_register_controller(struct metal_irq_controller *cntr);
108 
109 /**
110  * @brief	metal_irq_handle
111  *
112  * Call registered IRQ handler
113  *
114  * @param[in] irq_data metal IRQ structure
115  * @param[in] irq IRQ id which will be passed to handler
116  * @return IRQ handler status
117  */
118 static inline
metal_irq_handle(struct metal_irq * irq_data,int irq)119 int metal_irq_handle(struct metal_irq *irq_data, int irq)
120 {
121 	if (irq_data && irq_data->hd) {
122 		return irq_data->hd(irq, irq_data->arg);
123 	} else {
124 		return METAL_IRQ_NOT_HANDLED;
125 	}
126 }
127 
128 /** @} */
129 
130 #ifdef __cplusplus
131 }
132 #endif
133 
134 #endif /* __METAL_IRQ__H__ */
135