xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/mali400/mali/linux/mali_osk_irq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (C) 2010-2017 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 
35 struct 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 
test_interrupt_upper_half(int port_name,void * dev_id)42 static 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 
test_interrupt(u32 irqnum,_mali_osk_irq_trigger_t trigger_func,_mali_osk_irq_ack_t ack_func,void * probe_data,const char * description)56 static _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 /* defined(CONFIG_MALI_SHARED_INTERRUPTS) */
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 /* defined(DEBUG) */
95 
_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)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 /* defined(CONFIG_MALI_SHARED_INTERRUPTS) */
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 		/* Probe for IRQ */
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; /* no probe functions, fault */
134 
135 		if (-1 != irqnum) {
136 			/* found an irq */
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 	/* Verify that the configured interrupt settings are working */
155 	if (_MALI_OSK_ERR_OK != test_interrupt(irqnum, trigger_func, ack_func, probe_data, description)) {
156 		MALI_DEBUG_PRINT(2, ("Test of IRQ(%d) handler for core '%s' failed\n", irqnum, 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 
_mali_osk_irq_term(_mali_osk_irq_t * irq)171 void _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 /** This function is called directly in interrupt context from the OS just after
180  * the CPU get the hw-irq from mali, or other devices on the same IRQ-channel.
181  * It is registered one of these function for each mali core. When an interrupt
182  * arrives this function will be called equal times as registered mali cores.
183  * That means that we only check one mali core in one function call, and the
184  * core we check for each turn is given by the \a dev_id variable.
185  * If we detect an pending interrupt on the given core, we mask the interrupt
186  * out by settging the core's IRQ_MASK register to zero.
187  * Then we schedule the mali_core_irq_handler_bottom_half to run as high priority
188  * work queue job.
189  */
irq_handler_upper_half(int port_name,void * dev_id)190 static irqreturn_t irq_handler_upper_half(int port_name, void *dev_id)   /* , struct pt_regs *regs*/
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