linux/drivers/staging/mali/DX910-SW-99002-r5p2-00rel0/driver/src/devicedrv/mali/linux/mali_osk_notification.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010-2015 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_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
  40_mali_osk_notification_queue_t *_mali_osk_notification_queue_init(void)
  41{
  42        _mali_osk_notification_queue_t         *result;
  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
  54_mali_osk_notification_t *_mali_osk_notification_create(u32 type, u32 size)
  55{
  56        /* OPT Recycling of notification objects */
  57        _mali_osk_notification_wrapper_t *notification;
  58
  59        notification = (_mali_osk_notification_wrapper_t *)kmalloc(sizeof(_mali_osk_notification_wrapper_t) + size,
  60                        GFP_KERNEL | __GFP_HIGH | __GFP_REPEAT);
  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) {
  70                notification->data.result_buffer = ((u8 *)notification) + sizeof(_mali_osk_notification_wrapper_t);
  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
  83void _mali_osk_notification_delete(_mali_osk_notification_t *object)
  84{
  85        _mali_osk_notification_wrapper_t *notification;
  86        MALI_DEBUG_ASSERT_POINTER(object);
  87
  88        notification = container_of(object, _mali_osk_notification_wrapper_t, data);
  89
  90        /* Free the container */
  91        kfree(notification);
  92}
  93
  94void _mali_osk_notification_queue_term(_mali_osk_notification_queue_t *queue)
  95{
  96        _mali_osk_notification_t *result;
  97        MALI_DEBUG_ASSERT_POINTER(queue);
  98
  99        while (_MALI_OSK_ERR_OK == _mali_osk_notification_queue_dequeue(queue, &result)) {
 100                _mali_osk_notification_delete(result);
 101        }
 102
 103        /* not much to do, just free the memory */
 104        kfree(queue);
 105}
 106void _mali_osk_notification_queue_send(_mali_osk_notification_queue_t *queue, _mali_osk_notification_t *object)
 107{
 108#if defined(MALI_UPPER_HALF_SCHEDULING)
 109        unsigned long irq_flags;
 110#endif
 111
 112        _mali_osk_notification_wrapper_t *notification;
 113        MALI_DEBUG_ASSERT_POINTER(queue);
 114        MALI_DEBUG_ASSERT_POINTER(object);
 115
 116        notification = container_of(object, _mali_osk_notification_wrapper_t, data);
 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
 136_mali_osk_errcode_t _mali_osk_notification_queue_dequeue(_mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result)
 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
 167_mali_osk_errcode_t _mali_osk_notification_queue_receive(_mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result)
 168{
 169        /* check input */
 170        MALI_DEBUG_ASSERT_POINTER(queue);
 171        MALI_DEBUG_ASSERT_POINTER(result);
 172
 173        /* default result */
 174        *result = NULL;
 175
 176        if (wait_event_interruptible(queue->receive_queue,
 177                                     _MALI_OSK_ERR_OK == _mali_osk_notification_queue_dequeue(queue, result))) {
 178                return _MALI_OSK_ERR_RESTARTSYSCALL;
 179        }
 180
 181        return _MALI_OSK_ERR_OK; /* all ok */
 182}
 183