linux/drivers/staging/mali/DX910-SW-99002-r5p2-00rel0/driver/src/devicedrv/ump/linux/ump_kernel_random_mapping.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010-2011, 2013-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#include "mali_kernel_common.h"
  12#include "mali_osk.h"
  13#include "ump_osk.h"
  14#include "ump_kernel_common.h"
  15#include "ump_kernel_types.h"
  16#include "ump_kernel_random_mapping.h"
  17
  18#include <linux/random.h>
  19#include <linux/rbtree.h>
  20#include <linux/sched.h>
  21#include <linux/jiffies.h>
  22
  23
  24static ump_dd_mem *search(struct rb_root *root, int id)
  25{
  26        struct rb_node *node = root->rb_node;
  27
  28        while (node) {
  29                ump_dd_mem *e = container_of(node, ump_dd_mem, node);
  30
  31                if (id < e->secure_id) {
  32                        node = node->rb_left;
  33                } else if (id > e->secure_id) {
  34                        node = node->rb_right;
  35                } else {
  36                        return e;
  37                }
  38        }
  39
  40        return NULL;
  41}
  42
  43static mali_bool insert(struct rb_root *root, int id, ump_dd_mem *mem)
  44{
  45        struct rb_node **new = &(root->rb_node);
  46        struct rb_node *parent = NULL;
  47
  48        while (*new) {
  49                ump_dd_mem *this = container_of(*new, ump_dd_mem, node);
  50
  51                parent = *new;
  52                if (id < this->secure_id) {
  53                        new = &((*new)->rb_left);
  54                } else if (id > this->secure_id) {
  55                        new = &((*new)->rb_right);
  56                } else {
  57                        printk(KERN_ERR "UMP: ID already used %x\n", id);
  58                        return MALI_FALSE;
  59                }
  60        }
  61
  62        rb_link_node(&mem->node, parent, new);
  63        rb_insert_color(&mem->node, root);
  64
  65        return MALI_TRUE;
  66}
  67
  68
  69ump_random_mapping *ump_random_mapping_create(void)
  70{
  71        ump_random_mapping *map = _mali_osk_calloc(1, sizeof(ump_random_mapping));
  72
  73        if (NULL == map)
  74                return NULL;
  75
  76        map->lock = _mali_osk_mutex_rw_init(_MALI_OSK_LOCKFLAG_ORDERED,
  77                                            _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP);
  78        if (NULL != map->lock) {
  79                map->root = RB_ROOT;
  80#if UMP_RANDOM_MAP_DELAY
  81                map->failed.count = 0;
  82                map->failed.timestamp = jiffies;
  83#endif
  84                return map;
  85        }
  86        return NULL;
  87}
  88
  89void ump_random_mapping_destroy(ump_random_mapping *map)
  90{
  91        _mali_osk_mutex_rw_term(map->lock);
  92        _mali_osk_free(map);
  93}
  94
  95int ump_random_mapping_insert(ump_random_mapping *map, ump_dd_mem *mem)
  96{
  97        _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RW);
  98
  99        while (1) {
 100                u32 id;
 101
 102                get_random_bytes(&id, sizeof(id));
 103
 104                /* Try a new random number if id happened to be the invalid
 105                 * secure ID (-1). */
 106                if (unlikely(id == UMP_INVALID_SECURE_ID))
 107                        continue;
 108
 109                /* Insert into the tree. If the id was already in use, get a
 110                 * new random id and try again. */
 111                if (insert(&map->root, id, mem)) {
 112                        mem->secure_id = id;
 113                        break;
 114                }
 115        }
 116        _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RW);
 117
 118        return 0;
 119}
 120
 121ump_dd_mem *ump_random_mapping_get(ump_random_mapping *map, int id)
 122{
 123        ump_dd_mem *mem = NULL;
 124#if UMP_RANDOM_MAP_DELAY
 125        int do_delay = 0;
 126#endif
 127
 128        DEBUG_ASSERT(map);
 129
 130        _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RO);
 131        mem = search(&map->root, id);
 132
 133        if (unlikely(NULL == mem)) {
 134#if UMP_RANDOM_MAP_DELAY
 135                map->failed.count++;
 136
 137                if (time_is_before_jiffies(map->failed.timestamp +
 138                                           UMP_FAILED_LOOKUP_DELAY * HZ)) {
 139                        /* If it is a long time since last failure, reset
 140                         * the counter and skip the delay this time. */
 141                        map->failed.count = 0;
 142                } else if (map->failed.count > UMP_FAILED_LOOKUPS_ALLOWED) {
 143                        do_delay = 1;
 144                }
 145
 146                map->failed.timestamp = jiffies;
 147#endif /* UMP_RANDOM_MAP_DELAY */
 148        } else {
 149                ump_dd_reference_add(mem);
 150        }
 151        _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RO);
 152
 153#if UMP_RANDOM_MAP_DELAY
 154        if (do_delay) {
 155                /* Apply delay */
 156                schedule_timeout_killable(UMP_FAILED_LOOKUP_DELAY);
 157        }
 158#endif /* UMP_RANDOM_MAP_DELAY */
 159
 160        return mem;
 161}
 162
 163static ump_dd_mem *ump_random_mapping_remove_internal(ump_random_mapping *map, int id)
 164{
 165        ump_dd_mem *mem = NULL;
 166
 167        mem = search(&map->root, id);
 168
 169        if (mem) {
 170                rb_erase(&mem->node, &map->root);
 171        }
 172
 173        return mem;
 174}
 175
 176void ump_random_mapping_put(ump_dd_mem *mem)
 177{
 178        int new_ref;
 179
 180        _mali_osk_mutex_rw_wait(device.secure_id_map->lock, _MALI_OSK_LOCKMODE_RW);
 181
 182        new_ref = _ump_osk_atomic_dec_and_read(&mem->ref_count);
 183        DBG_MSG(5, ("Memory reference decremented. ID: %u, new value: %d\n",
 184                    mem->secure_id, new_ref));
 185
 186        if (0 == new_ref) {
 187                DBG_MSG(3, ("Final release of memory. ID: %u\n", mem->secure_id));
 188
 189                ump_random_mapping_remove_internal(device.secure_id_map, mem->secure_id);
 190
 191                mem->release_func(mem->ctx, mem);
 192                _mali_osk_free(mem);
 193        }
 194
 195        _mali_osk_mutex_rw_signal(device.secure_id_map->lock, _MALI_OSK_LOCKMODE_RW);
 196}
 197
 198ump_dd_mem *ump_random_mapping_remove(ump_random_mapping *map, int descriptor)
 199{
 200        ump_dd_mem *mem;
 201
 202        _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RW);
 203        mem = ump_random_mapping_remove_internal(map, descriptor);
 204        _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RW);
 205
 206        return mem;
 207}
 208