tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / mali / linux / mali_osk_irq.c
1 /*
2  * Copyright (C) 2011-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
18 #include "mali_osk.h"
19 #include "mali_kernel_common.h"
20 #include "linux/interrupt.h"
21
22 typedef struct _mali_osk_irq_t_struct
23 {
24         u32 irqnum;
25         void *data;
26         _mali_osk_irq_uhandler_t uhandler;
27 } mali_osk_irq_object_t;
28
29 typedef irqreturn_t (*irq_handler_func_t)(int, void *, struct pt_regs *);
30 static irqreturn_t irq_handler_upper_half (int port_name, void* dev_id ); /* , struct pt_regs *regs*/
31
32 _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 )
33 {
34         mali_osk_irq_object_t *irq_object;
35
36         irq_object = kmalloc(sizeof(mali_osk_irq_object_t), GFP_KERNEL);
37         if (NULL == irq_object)
38         {
39                 return NULL;
40         }
41
42         if (-1 == irqnum)
43         {
44                 /* Probe for IRQ */
45                 if ( (NULL != trigger_func) && (NULL != ack_func) )
46                 {
47                         unsigned long probe_count = 3;
48                         _mali_osk_errcode_t err;
49                         int irq;
50
51                         MALI_DEBUG_PRINT(2, ("Probing for irq\n"));
52
53                         do
54                         {
55                                 unsigned long mask;
56
57                                 mask = probe_irq_on();
58                                 trigger_func(probe_data);
59
60                                 _mali_osk_time_ubusydelay(5);
61
62                                 irq = probe_irq_off(mask);
63                                 err = ack_func(probe_data);
64                         }
65                         while (irq < 0 && (err == _MALI_OSK_ERR_OK) && probe_count--);
66
67                         if (irq < 0 || (_MALI_OSK_ERR_OK != err)) irqnum = -1;
68                         else irqnum = irq;
69                 }
70                 else irqnum = -1; /* no probe functions, fault */
71
72                 if (-1 != irqnum)
73                 {
74                         /* found an irq */
75                         MALI_DEBUG_PRINT(2, ("Found irq %d\n", irqnum));
76                 }
77                 else
78                 {
79                         MALI_DEBUG_PRINT(2, ("Probe for irq failed\n"));
80                 }
81         }
82
83         irq_object->irqnum = irqnum;
84         irq_object->uhandler = uhandler;
85         irq_object->data = int_data;
86
87         if (-1 == irqnum)
88         {
89                 MALI_DEBUG_PRINT(2, ("No IRQ for core '%s' found during probe\n", description));
90                 kfree(irq_object);
91                 return NULL;
92         }
93
94         if (0 != request_irq(irqnum, irq_handler_upper_half, IRQF_SHARED, description, irq_object))
95         {
96                 MALI_DEBUG_PRINT(2, ("Unable to install IRQ handler for core '%s'\n", description));
97                 kfree(irq_object);
98                 return NULL;
99         }
100
101         return irq_object;
102 }
103
104 void _mali_osk_irq_term( _mali_osk_irq_t *irq )
105 {
106         mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq;
107         free_irq(irq_object->irqnum, irq_object);
108         kfree(irq_object);
109 }
110
111
112 /** This function is called directly in interrupt context from the OS just after
113  * the CPU get the hw-irq from mali, or other devices on the same IRQ-channel.
114  * It is registered one of these function for each mali core. When an interrupt
115  * arrives this function will be called equal times as registered mali cores.
116  * That means that we only check one mali core in one function call, and the
117  * core we check for each turn is given by the \a dev_id variable.
118  * If we detect an pending interrupt on the given core, we mask the interrupt
119  * out by settging the core's IRQ_MASK register to zero.
120  * Then we schedule the mali_core_irq_handler_bottom_half to run as high priority
121  * work queue job.
122  */
123 static irqreturn_t irq_handler_upper_half (int port_name, void* dev_id ) /* , struct pt_regs *regs*/
124 {
125         mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)dev_id;
126
127         if (irq_object->uhandler(irq_object->data) == _MALI_OSK_ERR_OK)
128         {
129                 return IRQ_HANDLED;
130         }
131         return IRQ_NONE;
132 }
133