1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/slab.h>
17#include <linux/interrupt.h>
18#include <linux/wait.h>
19#include <linux/sched.h>
20
21#include "mali_osk.h"
22#include "mali_kernel_common.h"
23
24typedef struct _mali_osk_irq_t_struct {
25 u32 irqnum;
26 void *data;
27 _mali_osk_irq_uhandler_t uhandler;
28} mali_osk_irq_object_t;
29
30typedef irqreturn_t (*irq_handler_func_t)(int, void *, struct pt_regs *);
31static irqreturn_t irq_handler_upper_half(int port_name, void *dev_id);
32
33#if defined(DEBUG)
34
35struct test_interrupt_data {
36 _mali_osk_irq_ack_t ack_func;
37 void *probe_data;
38 mali_bool interrupt_received;
39 wait_queue_head_t wq;
40};
41
42static irqreturn_t test_interrupt_upper_half(int port_name, void *dev_id)
43{
44 irqreturn_t ret = IRQ_NONE;
45 struct test_interrupt_data *data = (struct test_interrupt_data *)dev_id;
46
47 if (_MALI_OSK_ERR_OK == data->ack_func(data->probe_data)) {
48 data->interrupt_received = MALI_TRUE;
49 wake_up(&data->wq);
50 ret = IRQ_HANDLED;
51 }
52
53 return ret;
54}
55
56static _mali_osk_errcode_t test_interrupt(u32 irqnum,
57 _mali_osk_irq_trigger_t trigger_func,
58 _mali_osk_irq_ack_t ack_func,
59 void *probe_data,
60 const char *description)
61{
62 unsigned long irq_flags = 0;
63 struct test_interrupt_data data = {
64 .ack_func = ack_func,
65 .probe_data = probe_data,
66 .interrupt_received = MALI_FALSE,
67 };
68
69#if defined(CONFIG_MALI_SHARED_INTERRUPTS)
70 irq_flags |= IRQF_SHARED;
71#endif
72
73 if (0 != request_irq(irqnum, test_interrupt_upper_half, irq_flags, description, &data)) {
74 MALI_DEBUG_PRINT(2, ("Unable to install test IRQ handler for core '%s'\n", description));
75 return _MALI_OSK_ERR_FAULT;
76 }
77
78 init_waitqueue_head(&data.wq);
79
80 trigger_func(probe_data);
81 wait_event_timeout(data.wq, data.interrupt_received, 100);
82
83 free_irq(irqnum, &data);
84
85 if (data.interrupt_received) {
86 MALI_DEBUG_PRINT(3, ("%s: Interrupt test OK\n", description));
87 return _MALI_OSK_ERR_OK;
88 } else {
89 MALI_PRINT_ERROR(("%s: Failed interrupt test on %u\n", description, irqnum));
90 return _MALI_OSK_ERR_FAULT;
91 }
92}
93
94#endif
95
96_mali_osk_irq_t *_mali_osk_irq_init(u32 irqnum, _mali_osk_irq_uhandler_t uhandler, void *int_data, _mali_osk_irq_trigger_t trigger_func, _mali_osk_irq_ack_t ack_func, void *probe_data, const char *description)
97{
98 mali_osk_irq_object_t *irq_object;
99 unsigned long irq_flags = 0;
100
101#if defined(CONFIG_MALI_SHARED_INTERRUPTS)
102 irq_flags |= IRQF_SHARED;
103#endif
104
105 irq_object = kmalloc(sizeof(mali_osk_irq_object_t), GFP_KERNEL);
106 if (NULL == irq_object) {
107 return NULL;
108 }
109
110 if (-1 == irqnum) {
111
112 if ((NULL != trigger_func) && (NULL != ack_func)) {
113 unsigned long probe_count = 3;
114 _mali_osk_errcode_t err;
115 int irq;
116
117 MALI_DEBUG_PRINT(2, ("Probing for irq\n"));
118
119 do {
120 unsigned long mask;
121
122 mask = probe_irq_on();
123 trigger_func(probe_data);
124
125 _mali_osk_time_ubusydelay(5);
126
127 irq = probe_irq_off(mask);
128 err = ack_func(probe_data);
129 } while (irq < 0 && (err == _MALI_OSK_ERR_OK) && probe_count--);
130
131 if (irq < 0 || (_MALI_OSK_ERR_OK != err)) irqnum = -1;
132 else irqnum = irq;
133 } else irqnum = -1;
134
135 if (-1 != irqnum) {
136
137 MALI_DEBUG_PRINT(2, ("Found irq %d\n", irqnum));
138 } else {
139 MALI_DEBUG_PRINT(2, ("Probe for irq failed\n"));
140 }
141 }
142
143 irq_object->irqnum = irqnum;
144 irq_object->uhandler = uhandler;
145 irq_object->data = int_data;
146
147 if (-1 == irqnum) {
148 MALI_DEBUG_PRINT(2, ("No IRQ for core '%s' found during probe\n", description));
149 kfree(irq_object);
150 return NULL;
151 }
152
153#if defined(DEBUG)
154
155 if (_MALI_OSK_ERR_OK != test_interrupt(irqnum, trigger_func, ack_func, probe_data, description)) {
156 MALI_DEBUG_PRINT(2, ("Test of IRQ handler for core '%s' failed\n", description));
157 kfree(irq_object);
158 return NULL;
159 }
160#endif
161
162 if (0 != request_irq(irqnum, irq_handler_upper_half, irq_flags, description, irq_object)) {
163 MALI_DEBUG_PRINT(2, ("Unable to install IRQ handler for core '%s'\n", description));
164 kfree(irq_object);
165 return NULL;
166 }
167
168 return irq_object;
169}
170
171void _mali_osk_irq_term(_mali_osk_irq_t *irq)
172{
173 mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq;
174 free_irq(irq_object->irqnum, irq_object);
175 kfree(irq_object);
176}
177
178
179
180
181
182
183
184
185
186
187
188
189
190static irqreturn_t irq_handler_upper_half(int port_name, void *dev_id)
191{
192 irqreturn_t ret = IRQ_NONE;
193 mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)dev_id;
194
195 if (_MALI_OSK_ERR_OK == irq_object->uhandler(irq_object->data)) {
196 ret = IRQ_HANDLED;
197 }
198
199 return ret;
200}
201