tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / r4p0_rel0 / linux / mali_osk_irq.c
1 /*
2  * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
3  * 
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  * 
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10
11 /**
12  * @file mali_osk_irq.c
13  * Implementation of the OS abstraction layer for the kernel device driver
14  */
15
16 #include <linux/slab.h> /* For memory allocation */
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
24 typedef 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
30 typedef irqreturn_t (*irq_handler_func_t)(int, void *, struct pt_regs *);
31 static irqreturn_t irq_handler_upper_half (int port_name, void* dev_id ); /* , struct pt_regs *regs*/
32
33 #if defined(DEBUG)
34 #if 0
35
36 struct test_interrupt_data {
37         _mali_osk_irq_ack_t ack_func;
38         void *probe_data;
39         mali_bool interrupt_received;
40         wait_queue_head_t wq;
41 };
42
43 static irqreturn_t test_interrupt_upper_half(int port_name, void *dev_id)
44 {
45         irqreturn_t ret = IRQ_NONE;
46         struct test_interrupt_data *data = (struct test_interrupt_data *)dev_id;
47
48         if (_MALI_OSK_ERR_OK == data->ack_func(data->probe_data)) {
49                 data->interrupt_received = MALI_TRUE;
50                 wake_up(&data->wq);
51                 ret = IRQ_HANDLED;
52         }
53
54         return ret;
55 }
56
57 static _mali_osk_errcode_t test_interrupt(u32 irqnum,
58         _mali_osk_irq_trigger_t trigger_func,
59         _mali_osk_irq_ack_t ack_func,
60         void *probe_data,
61         const char *description)
62 {
63         unsigned long irq_flags = 0;
64         struct test_interrupt_data data = {
65                 .ack_func = ack_func,
66                 .probe_data = probe_data,
67                 .interrupt_received = MALI_FALSE,
68         };
69
70 #if defined(CONFIG_MALI_SHARED_INTERRUPTS)
71         irq_flags |= IRQF_SHARED;
72 #endif /* defined(CONFIG_MALI_SHARED_INTERRUPTS) */
73
74         if (0 != request_irq(irqnum, test_interrupt_upper_half, irq_flags, description, &data)) {
75                 MALI_DEBUG_PRINT(2, ("Unable to install test IRQ handler for core '%s'\n", description));
76                 return _MALI_OSK_ERR_FAULT;
77         }
78
79         init_waitqueue_head(&data.wq);
80
81         trigger_func(probe_data);
82         wait_event_timeout(data.wq, data.interrupt_received, 100);
83
84         free_irq(irqnum, &data);
85
86         if (data.interrupt_received) {
87                 MALI_DEBUG_PRINT(3, ("%s: Interrupt test OK\n", description));
88                 return _MALI_OSK_ERR_OK;
89         } else {
90                 MALI_PRINT_ERROR(("%s: Failed interrupt test on %u\n", description, irqnum));
91                 return _MALI_OSK_ERR_FAULT;
92         }
93 }
94 #endif
95
96 #endif /* defined(DEBUG) */
97
98 _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 )
99 {
100         mali_osk_irq_object_t *irq_object;
101         unsigned long irq_flags = 0;
102
103 #if defined(CONFIG_MALI_SHARED_INTERRUPTS)
104         irq_flags |= IRQF_SHARED;
105 #endif /* defined(CONFIG_MALI_SHARED_INTERRUPTS) */
106
107         irq_object = kmalloc(sizeof(mali_osk_irq_object_t), GFP_KERNEL);
108         if (NULL == irq_object) {
109                 return NULL;
110         }
111
112         if (-1 == irqnum) {
113                 /* Probe for IRQ */
114                 if ( (NULL != trigger_func) && (NULL != ack_func) ) {
115                         unsigned long probe_count = 3;
116                         _mali_osk_errcode_t err;
117                         int irq;
118
119                         MALI_DEBUG_PRINT(2, ("Probing for irq\n"));
120
121                         do {
122                                 unsigned long mask;
123
124                                 mask = probe_irq_on();
125                                 trigger_func(probe_data);
126
127                                 _mali_osk_time_ubusydelay(5);
128
129                                 irq = probe_irq_off(mask);
130                                 err = ack_func(probe_data);
131                         } while (irq < 0 && (err == _MALI_OSK_ERR_OK) && probe_count--);
132
133                         if (irq < 0 || (_MALI_OSK_ERR_OK != err)) irqnum = -1;
134                         else irqnum = irq;
135                 } else irqnum = -1; /* no probe functions, fault */
136
137                 if (-1 != irqnum) {
138                         /* found an irq */
139                         MALI_DEBUG_PRINT(2, ("Found irq %d\n", irqnum));
140                 } else {
141                         MALI_DEBUG_PRINT(2, ("Probe for irq failed\n"));
142                 }
143         }
144
145         irq_object->irqnum = irqnum;
146         irq_object->uhandler = uhandler;
147         irq_object->data = int_data;
148
149         if (-1 == irqnum) {
150                 MALI_DEBUG_PRINT(2, ("No IRQ for core '%s' found during probe\n", description));
151                 kfree(irq_object);
152                 return NULL;
153         }
154
155 #if defined(DEBUG)
156 #if 0
157         /* Verify that the configured interrupt settings are working */
158         if (_MALI_OSK_ERR_OK != test_interrupt(irqnum, trigger_func, ack_func, probe_data, description)) {
159                 MALI_DEBUG_PRINT(2, ("Test of IRQ handler for core '%s' failed\n", description));
160                 kfree(irq_object);
161                 return NULL;
162         }
163 #endif
164 #endif
165
166         if (0 != request_irq(irqnum, irq_handler_upper_half, irq_flags, description, irq_object)) {
167                 MALI_DEBUG_PRINT(2, ("Unable to install IRQ handler for core '%s'\n", description));
168                 kfree(irq_object);
169                 return NULL;
170         }
171
172         return irq_object;
173 }
174
175 void _mali_osk_irq_term( _mali_osk_irq_t *irq )
176 {
177         mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq;
178         free_irq(irq_object->irqnum, irq_object);
179         kfree(irq_object);
180 }
181
182
183 /** This function is called directly in interrupt context from the OS just after
184  * the CPU get the hw-irq from mali, or other devices on the same IRQ-channel.
185  * It is registered one of these function for each mali core. When an interrupt
186  * arrives this function will be called equal times as registered mali cores.
187  * That means that we only check one mali core in one function call, and the
188  * core we check for each turn is given by the \a dev_id variable.
189  * If we detect an pending interrupt on the given core, we mask the interrupt
190  * out by settging the core's IRQ_MASK register to zero.
191  * Then we schedule the mali_core_irq_handler_bottom_half to run as high priority
192  * work queue job.
193  */
194 static irqreturn_t irq_handler_upper_half (int port_name, void* dev_id ) /* , struct pt_regs *regs*/
195 {
196         irqreturn_t ret = IRQ_NONE;
197         mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)dev_id;
198
199         if (_MALI_OSK_ERR_OK == irq_object->uhandler(irq_object->data)) {
200                 ret = IRQ_HANDLED;
201         }
202
203         return ret;
204 }