2 * Copyright (C) 2011-2012 ARM Limited. All rights reserved.
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.
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.
12 * @file mali_osk_notification.c
13 * Implementation of the OS abstraction layer for the kernel device driver
17 #include "mali_kernel_common.h"
19 #include <linux/sched.h>
20 #include <linux/slab.h>
21 #include <linux/spinlock.h>
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.
29 struct _mali_osk_notification_queue_t_struct
31 spinlock_t mutex; /**< Mutex protecting the list */
32 wait_queue_head_t receive_queue; /**< Threads waiting for new entries to the queue */
33 struct list_head head; /**< List of notifications waiting to be picked up */
36 typedef struct _mali_osk_notification_wrapper_t_struct
38 struct list_head list; /**< Internal linked list variable */
39 _mali_osk_notification_t data; /**< Notification data */
40 } _mali_osk_notification_wrapper_t;
42 _mali_osk_notification_queue_t *_mali_osk_notification_queue_init( void )
44 _mali_osk_notification_queue_t * result;
46 result = (_mali_osk_notification_queue_t *)kmalloc(sizeof(_mali_osk_notification_queue_t), GFP_KERNEL);
47 if (NULL == result) return NULL;
49 spin_lock_init(&result->mutex);
50 init_waitqueue_head(&result->receive_queue);
51 INIT_LIST_HEAD(&result->head);
56 _mali_osk_notification_t *_mali_osk_notification_create( u32 type, u32 size )
58 /* OPT Recycling of notification objects */
59 _mali_osk_notification_wrapper_t *notification;
61 notification = (_mali_osk_notification_wrapper_t *)kmalloc( sizeof(_mali_osk_notification_wrapper_t) + size,
62 GFP_KERNEL | __GFP_HIGH | __GFP_REPEAT);
63 if (NULL == notification)
65 MALI_DEBUG_PRINT(1, ("Failed to create a notification object\n"));
70 INIT_LIST_HEAD(¬ification->list);
74 notification->data.result_buffer = ((u8*)notification) + sizeof(_mali_osk_notification_wrapper_t);
78 notification->data.result_buffer = NULL;
81 /* set up the non-allocating fields */
82 notification->data.notification_type = type;
83 notification->data.result_buffer_size = size;
86 return &(notification->data);
89 void _mali_osk_notification_delete( _mali_osk_notification_t *object )
91 _mali_osk_notification_wrapper_t *notification;
92 MALI_DEBUG_ASSERT_POINTER( object );
94 notification = container_of( object, _mali_osk_notification_wrapper_t, data );
96 /* Free the container */
100 void _mali_osk_notification_queue_term( _mali_osk_notification_queue_t *queue )
102 MALI_DEBUG_ASSERT_POINTER( queue );
104 /* not much to do, just free the memory */
108 void _mali_osk_notification_queue_send( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t *object )
110 #if defined(MALI_UPPER_HALF_SCHEDULING)
111 unsigned long irq_flags;
114 _mali_osk_notification_wrapper_t *notification;
115 MALI_DEBUG_ASSERT_POINTER( queue );
116 MALI_DEBUG_ASSERT_POINTER( object );
118 notification = container_of( object, _mali_osk_notification_wrapper_t, data );
120 #if defined(MALI_UPPER_HALF_SCHEDULING)
121 spin_lock_irqsave(&queue->mutex, irq_flags);
123 spin_lock(&queue->mutex);
126 list_add_tail(¬ification->list, &queue->head);
128 #if defined(MALI_UPPER_HALF_SCHEDULING)
129 spin_unlock_irqrestore(&queue->mutex, irq_flags);
131 spin_unlock(&queue->mutex);
134 /* and wake up one possible exclusive waiter */
135 wake_up(&queue->receive_queue);
138 _mali_osk_errcode_t _mali_osk_notification_queue_dequeue( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result )
140 #if defined(MALI_UPPER_HALF_SCHEDULING)
141 unsigned long irq_flags;
144 _mali_osk_errcode_t ret = _MALI_OSK_ERR_ITEM_NOT_FOUND;
145 _mali_osk_notification_wrapper_t *wrapper_object;
147 #if defined(MALI_UPPER_HALF_SCHEDULING)
148 spin_lock_irqsave(&queue->mutex, irq_flags);
150 spin_lock(&queue->mutex);
153 if (!list_empty(&queue->head))
155 wrapper_object = list_entry(queue->head.next, _mali_osk_notification_wrapper_t, list);
156 *result = &(wrapper_object->data);
157 list_del_init(&wrapper_object->list);
158 ret = _MALI_OSK_ERR_OK;
161 #if defined(MALI_UPPER_HALF_SCHEDULING)
162 spin_unlock_irqrestore(&queue->mutex, irq_flags);
164 spin_unlock(&queue->mutex);
170 _mali_osk_errcode_t _mali_osk_notification_queue_receive( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result )
173 MALI_DEBUG_ASSERT_POINTER( queue );
174 MALI_DEBUG_ASSERT_POINTER( result );
179 if (wait_event_interruptible(queue->receive_queue,
180 _MALI_OSK_ERR_OK == _mali_osk_notification_queue_dequeue(queue, result)))
182 return _MALI_OSK_ERR_RESTARTSYSCALL;
185 return _MALI_OSK_ERR_OK; /* all ok */