mali mess
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / gpu / mt8127 / mali / mali / linux / mali_osk_notification.c
CommitLineData
6fa3eb70
S
1/*
2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
02af6beb 4 * (C) COPYRIGHT 2008-2015 ARM Limited
6fa3eb70
S
5 * ALL RIGHTS RESERVED
6 * The entire notice above must be reproduced on all authorised
7 * copies and copies may only be made to the extent permitted
8 * by a licensing agreement from ARM Limited.
9 */
10
11/**
12 * @file mali_osk_notification.c
13 * Implementation of the OS abstraction layer for the kernel device driver
14 */
15
16#include "mali_osk.h"
17#include "mali_kernel_common.h"
18
19#include <linux/sched.h>
20#include <linux/slab.h>
21#include <linux/spinlock.h>
22
23/**
24 * Declaration of the notification queue object type
25 * Contains a linked list of notification pending delivery to user space.
26 * It also contains a wait queue of exclusive waiters blocked in the ioctl
27 * When a new notification is posted a single thread is resumed.
28 */
29struct _mali_osk_notification_queue_t_struct {
30 spinlock_t mutex; /**< Mutex protecting the list */
31 wait_queue_head_t receive_queue; /**< Threads waiting for new entries to the queue */
32 struct list_head head; /**< List of notifications waiting to be picked up */
33};
34
35typedef struct _mali_osk_notification_wrapper_t_struct {
36 struct list_head list; /**< Internal linked list variable */
37 _mali_osk_notification_t data; /**< Notification data */
38} _mali_osk_notification_wrapper_t;
39
02af6beb 40_mali_osk_notification_queue_t *_mali_osk_notification_queue_init(void)
6fa3eb70 41{
02af6beb 42 _mali_osk_notification_queue_t *result;
6fa3eb70
S
43
44 result = (_mali_osk_notification_queue_t *)kmalloc(sizeof(_mali_osk_notification_queue_t), GFP_KERNEL);
45 if (NULL == result) return NULL;
46
47 spin_lock_init(&result->mutex);
48 init_waitqueue_head(&result->receive_queue);
49 INIT_LIST_HEAD(&result->head);
50
51 return result;
52}
53
02af6beb 54_mali_osk_notification_t *_mali_osk_notification_create(u32 type, u32 size)
6fa3eb70
S
55{
56 /* OPT Recycling of notification objects */
57 _mali_osk_notification_wrapper_t *notification;
58
02af6beb
S
59 notification = (_mali_osk_notification_wrapper_t *)kmalloc(sizeof(_mali_osk_notification_wrapper_t) + size,
60 GFP_KERNEL | __GFP_HIGH | __GFP_REPEAT);
6fa3eb70
S
61 if (NULL == notification) {
62 MALI_DEBUG_PRINT(1, ("Failed to create a notification object\n"));
63 return NULL;
64 }
65
66 /* Init the list */
67 INIT_LIST_HEAD(&notification->list);
68
69 if (0 != size) {
02af6beb 70 notification->data.result_buffer = ((u8 *)notification) + sizeof(_mali_osk_notification_wrapper_t);
6fa3eb70
S
71 } else {
72 notification->data.result_buffer = NULL;
73 }
74
75 /* set up the non-allocating fields */
76 notification->data.notification_type = type;
77 notification->data.result_buffer_size = size;
78
79 /* all ok */
80 return &(notification->data);
81}
82
02af6beb 83void _mali_osk_notification_delete(_mali_osk_notification_t *object)
6fa3eb70
S
84{
85 _mali_osk_notification_wrapper_t *notification;
02af6beb 86 MALI_DEBUG_ASSERT_POINTER(object);
6fa3eb70 87
02af6beb 88 notification = container_of(object, _mali_osk_notification_wrapper_t, data);
6fa3eb70
S
89
90 /* Free the container */
91 kfree(notification);
92}
93
02af6beb 94void _mali_osk_notification_queue_term(_mali_osk_notification_queue_t *queue)
6fa3eb70
S
95{
96 _mali_osk_notification_t *result;
02af6beb 97 MALI_DEBUG_ASSERT_POINTER(queue);
6fa3eb70
S
98
99 while (_MALI_OSK_ERR_OK == _mali_osk_notification_queue_dequeue(queue, &result)) {
02af6beb 100 _mali_osk_notification_delete(result);
6fa3eb70
S
101 }
102
103 /* not much to do, just free the memory */
104 kfree(queue);
105}
02af6beb 106void _mali_osk_notification_queue_send(_mali_osk_notification_queue_t *queue, _mali_osk_notification_t *object)
6fa3eb70
S
107{
108#if defined(MALI_UPPER_HALF_SCHEDULING)
109 unsigned long irq_flags;
110#endif
111
112 _mali_osk_notification_wrapper_t *notification;
02af6beb
S
113 MALI_DEBUG_ASSERT_POINTER(queue);
114 MALI_DEBUG_ASSERT_POINTER(object);
6fa3eb70 115
02af6beb 116 notification = container_of(object, _mali_osk_notification_wrapper_t, data);
6fa3eb70
S
117
118#if defined(MALI_UPPER_HALF_SCHEDULING)
119 spin_lock_irqsave(&queue->mutex, irq_flags);
120#else
121 spin_lock(&queue->mutex);
122#endif
123
124 list_add_tail(&notification->list, &queue->head);
125
126#if defined(MALI_UPPER_HALF_SCHEDULING)
127 spin_unlock_irqrestore(&queue->mutex, irq_flags);
128#else
129 spin_unlock(&queue->mutex);
130#endif
131
132 /* and wake up one possible exclusive waiter */
133 wake_up(&queue->receive_queue);
134}
135
02af6beb 136_mali_osk_errcode_t _mali_osk_notification_queue_dequeue(_mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result)
6fa3eb70
S
137{
138#if defined(MALI_UPPER_HALF_SCHEDULING)
139 unsigned long irq_flags;
140#endif
141
142 _mali_osk_errcode_t ret = _MALI_OSK_ERR_ITEM_NOT_FOUND;
143 _mali_osk_notification_wrapper_t *wrapper_object;
144
145#if defined(MALI_UPPER_HALF_SCHEDULING)
146 spin_lock_irqsave(&queue->mutex, irq_flags);
147#else
148 spin_lock(&queue->mutex);
149#endif
150
151 if (!list_empty(&queue->head)) {
152 wrapper_object = list_entry(queue->head.next, _mali_osk_notification_wrapper_t, list);
153 *result = &(wrapper_object->data);
154 list_del_init(&wrapper_object->list);
155 ret = _MALI_OSK_ERR_OK;
156 }
157
158#if defined(MALI_UPPER_HALF_SCHEDULING)
159 spin_unlock_irqrestore(&queue->mutex, irq_flags);
160#else
161 spin_unlock(&queue->mutex);
162#endif
163
164 return ret;
165}
166
02af6beb 167_mali_osk_errcode_t _mali_osk_notification_queue_receive(_mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result)
6fa3eb70
S
168{
169 /* check input */
02af6beb
S
170 MALI_DEBUG_ASSERT_POINTER(queue);
171 MALI_DEBUG_ASSERT_POINTER(result);
6fa3eb70
S
172
173 /* default result */
174 *result = NULL;
175
176 if (wait_event_interruptible(queue->receive_queue,
02af6beb 177 _MALI_OSK_ERR_OK == _mali_osk_notification_queue_dequeue(queue, result))) {
6fa3eb70
S
178 return _MALI_OSK_ERR_RESTARTSYSCALL;
179 }
180
181 return _MALI_OSK_ERR_OK; /* all ok */
182}