linux/drivers/char/drm/drm_sman.c
<<
>>
Prefs
   1/**************************************************************************
   2 *
   3 * Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA.
   4 * All Rights Reserved.
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a
   7 * copy of this software and associated documentation files (the
   8 * "Software"), to deal in the Software without restriction, including
   9 * without limitation the rights to use, copy, modify, merge, publish,
  10 * distribute, sub license, and/or sell copies of the Software, and to
  11 * permit persons to whom the Software is furnished to do so, subject to
  12 * the following conditions:
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * The above copyright notice and this permission notice (including the
  23 * next paragraph) shall be included in all copies or substantial portions
  24 * of the Software.
  25 *
  26 *
  27 **************************************************************************/
  28/*
  29 * Simple memory manager interface that keeps track on allocate regions on a
  30 * per "owner" basis. All regions associated with an "owner" can be released
  31 * with a simple call. Typically if the "owner" exists. The owner is any
  32 * "unsigned long" identifier. Can typically be a pointer to a file private
  33 * struct or a context identifier.
  34 *
  35 * Authors:
  36 * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
  37 */
  38
  39#include "drm_sman.h"
  40
  41struct drm_owner_item {
  42        struct drm_hash_item owner_hash;
  43        struct list_head sman_list;
  44        struct list_head mem_blocks;
  45};
  46
  47void drm_sman_takedown(struct drm_sman * sman)
  48{
  49        drm_ht_remove(&sman->user_hash_tab);
  50        drm_ht_remove(&sman->owner_hash_tab);
  51        if (sman->mm)
  52                drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm),
  53                         DRM_MEM_MM);
  54}
  55
  56EXPORT_SYMBOL(drm_sman_takedown);
  57
  58int
  59drm_sman_init(struct drm_sman * sman, unsigned int num_managers,
  60              unsigned int user_order, unsigned int owner_order)
  61{
  62        int ret = 0;
  63
  64        sman->mm = (struct drm_sman_mm *) drm_calloc(num_managers, sizeof(*sman->mm),
  65                                                DRM_MEM_MM);
  66        if (!sman->mm) {
  67                ret = -ENOMEM;
  68                goto out;
  69        }
  70        sman->num_managers = num_managers;
  71        INIT_LIST_HEAD(&sman->owner_items);
  72        ret = drm_ht_create(&sman->owner_hash_tab, owner_order);
  73        if (ret)
  74                goto out1;
  75        ret = drm_ht_create(&sman->user_hash_tab, user_order);
  76        if (!ret)
  77                goto out;
  78
  79        drm_ht_remove(&sman->owner_hash_tab);
  80out1:
  81        drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM);
  82out:
  83        return ret;
  84}
  85
  86EXPORT_SYMBOL(drm_sman_init);
  87
  88static void *drm_sman_mm_allocate(void *private, unsigned long size,
  89                                  unsigned alignment)
  90{
  91        struct drm_mm *mm = (struct drm_mm *) private;
  92        struct drm_mm_node *tmp;
  93
  94        tmp = drm_mm_search_free(mm, size, alignment, 1);
  95        if (!tmp) {
  96                return NULL;
  97        }
  98        tmp = drm_mm_get_block(tmp, size, alignment);
  99        return tmp;
 100}
 101
 102static void drm_sman_mm_free(void *private, void *ref)
 103{
 104        struct drm_mm_node *node = (struct drm_mm_node *) ref;
 105
 106        drm_mm_put_block(node);
 107}
 108
 109static void drm_sman_mm_destroy(void *private)
 110{
 111        struct drm_mm *mm = (struct drm_mm *) private;
 112        drm_mm_takedown(mm);
 113        drm_free(mm, sizeof(*mm), DRM_MEM_MM);
 114}
 115
 116static unsigned long drm_sman_mm_offset(void *private, void *ref)
 117{
 118        struct drm_mm_node *node = (struct drm_mm_node *) ref;
 119        return node->start;
 120}
 121
 122int
 123drm_sman_set_range(struct drm_sman * sman, unsigned int manager,
 124                   unsigned long start, unsigned long size)
 125{
 126        struct drm_sman_mm *sman_mm;
 127        struct drm_mm *mm;
 128        int ret;
 129
 130        BUG_ON(manager >= sman->num_managers);
 131
 132        sman_mm = &sman->mm[manager];
 133        mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM);
 134        if (!mm) {
 135                return -ENOMEM;
 136        }
 137        sman_mm->private = mm;
 138        ret = drm_mm_init(mm, start, size);
 139
 140        if (ret) {
 141                drm_free(mm, sizeof(*mm), DRM_MEM_MM);
 142                return ret;
 143        }
 144
 145        sman_mm->allocate = drm_sman_mm_allocate;
 146        sman_mm->free = drm_sman_mm_free;
 147        sman_mm->destroy = drm_sman_mm_destroy;
 148        sman_mm->offset = drm_sman_mm_offset;
 149
 150        return 0;
 151}
 152
 153EXPORT_SYMBOL(drm_sman_set_range);
 154
 155int
 156drm_sman_set_manager(struct drm_sman * sman, unsigned int manager,
 157                     struct drm_sman_mm * allocator)
 158{
 159        BUG_ON(manager >= sman->num_managers);
 160        sman->mm[manager] = *allocator;
 161
 162        return 0;
 163}
 164EXPORT_SYMBOL(drm_sman_set_manager);
 165
 166static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman,
 167                                                 unsigned long owner)
 168{
 169        int ret;
 170        struct drm_hash_item *owner_hash_item;
 171        struct drm_owner_item *owner_item;
 172
 173        ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item);
 174        if (!ret) {
 175                return drm_hash_entry(owner_hash_item, struct drm_owner_item,
 176                                      owner_hash);
 177        }
 178
 179        owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM);
 180        if (!owner_item)
 181                goto out;
 182
 183        INIT_LIST_HEAD(&owner_item->mem_blocks);
 184        owner_item->owner_hash.key = owner;
 185        if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash))
 186                goto out1;
 187
 188        list_add_tail(&owner_item->sman_list, &sman->owner_items);
 189        return owner_item;
 190
 191out1:
 192        drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
 193out:
 194        return NULL;
 195}
 196
 197struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int manager,
 198                                    unsigned long size, unsigned alignment,
 199                                    unsigned long owner)
 200{
 201        void *tmp;
 202        struct drm_sman_mm *sman_mm;
 203        struct drm_owner_item *owner_item;
 204        struct drm_memblock_item *memblock;
 205
 206        BUG_ON(manager >= sman->num_managers);
 207
 208        sman_mm = &sman->mm[manager];
 209        tmp = sman_mm->allocate(sman_mm->private, size, alignment);
 210
 211        if (!tmp) {
 212                return NULL;
 213        }
 214
 215        memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM);
 216
 217        if (!memblock)
 218                goto out;
 219
 220        memblock->mm_info = tmp;
 221        memblock->mm = sman_mm;
 222        memblock->sman = sman;
 223
 224        if (drm_ht_just_insert_please
 225            (&sman->user_hash_tab, &memblock->user_hash,
 226             (unsigned long)memblock, 32, 0, 0))
 227                goto out1;
 228
 229        owner_item = drm_sman_get_owner_item(sman, owner);
 230        if (!owner_item)
 231                goto out2;
 232
 233        list_add_tail(&memblock->owner_list, &owner_item->mem_blocks);
 234
 235        return memblock;
 236
 237out2:
 238        drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash);
 239out1:
 240        drm_free(memblock, sizeof(*memblock), DRM_MEM_MM);
 241out:
 242        sman_mm->free(sman_mm->private, tmp);
 243
 244        return NULL;
 245}
 246
 247EXPORT_SYMBOL(drm_sman_alloc);
 248
 249static void drm_sman_free(struct drm_memblock_item *item)
 250{
 251        struct drm_sman *sman = item->sman;
 252
 253        list_del(&item->owner_list);
 254        drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash);
 255        item->mm->free(item->mm->private, item->mm_info);
 256        drm_free(item, sizeof(*item), DRM_MEM_MM);
 257}
 258
 259int drm_sman_free_key(struct drm_sman *sman, unsigned int key)
 260{
 261        struct drm_hash_item *hash_item;
 262        struct drm_memblock_item *memblock_item;
 263
 264        if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item))
 265                return -EINVAL;
 266
 267        memblock_item = drm_hash_entry(hash_item, struct drm_memblock_item,
 268                                       user_hash);
 269        drm_sman_free(memblock_item);
 270        return 0;
 271}
 272
 273EXPORT_SYMBOL(drm_sman_free_key);
 274
 275static void drm_sman_remove_owner(struct drm_sman *sman,
 276                                  struct drm_owner_item *owner_item)
 277{
 278        list_del(&owner_item->sman_list);
 279        drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash);
 280        drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
 281}
 282
 283int drm_sman_owner_clean(struct drm_sman *sman, unsigned long owner)
 284{
 285
 286        struct drm_hash_item *hash_item;
 287        struct drm_owner_item *owner_item;
 288
 289        if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
 290                return -1;
 291        }
 292
 293        owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash);
 294        if (owner_item->mem_blocks.next == &owner_item->mem_blocks) {
 295                drm_sman_remove_owner(sman, owner_item);
 296                return -1;
 297        }
 298
 299        return 0;
 300}
 301
 302EXPORT_SYMBOL(drm_sman_owner_clean);
 303
 304static void drm_sman_do_owner_cleanup(struct drm_sman *sman,
 305                                      struct drm_owner_item *owner_item)
 306{
 307        struct drm_memblock_item *entry, *next;
 308
 309        list_for_each_entry_safe(entry, next, &owner_item->mem_blocks,
 310                                 owner_list) {
 311                drm_sman_free(entry);
 312        }
 313        drm_sman_remove_owner(sman, owner_item);
 314}
 315
 316void drm_sman_owner_cleanup(struct drm_sman *sman, unsigned long owner)
 317{
 318
 319        struct drm_hash_item *hash_item;
 320        struct drm_owner_item *owner_item;
 321
 322        if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
 323
 324                return;
 325        }
 326
 327        owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash);
 328        drm_sman_do_owner_cleanup(sman, owner_item);
 329}
 330
 331EXPORT_SYMBOL(drm_sman_owner_cleanup);
 332
 333void drm_sman_cleanup(struct drm_sman *sman)
 334{
 335        struct drm_owner_item *entry, *next;
 336        unsigned int i;
 337        struct drm_sman_mm *sman_mm;
 338
 339        list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) {
 340                drm_sman_do_owner_cleanup(sman, entry);
 341        }
 342        if (sman->mm) {
 343                for (i = 0; i < sman->num_managers; ++i) {
 344                        sman_mm = &sman->mm[i];
 345                        if (sman_mm->private) {
 346                                sman_mm->destroy(sman_mm->private);
 347                                sman_mm->private = NULL;
 348                        }
 349                }
 350        }
 351}
 352
 353EXPORT_SYMBOL(drm_sman_cleanup);
 354
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.