1235783Skib/************************************************************************** 2235783Skib * 3235783Skib * Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA. 4235783Skib * All Rights Reserved. 5235783Skib * 6235783Skib * Permission is hereby granted, free of charge, to any person obtaining a 7235783Skib * copy of this software and associated documentation files (the 8235783Skib * "Software"), to deal in the Software without restriction, including 9235783Skib * without limitation the rights to use, copy, modify, merge, publish, 10235783Skib * distribute, sub license, and/or sell copies of the Software, and to 11235783Skib * permit persons to whom the Software is furnished to do so, subject to 12235783Skib * the following conditions: 13235783Skib * 14235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 17235783Skib * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 18235783Skib * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19235783Skib * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20235783Skib * USE OR OTHER DEALINGS IN THE SOFTWARE. 21235783Skib * 22235783Skib * The above copyright notice and this permission notice (including the 23235783Skib * next paragraph) shall be included in all copies or substantial portions 24235783Skib * of the Software. 25235783Skib * 26235783Skib * 27235783Skib **************************************************************************/ 28235783Skib 29235783Skib#include <sys/cdefs.h> 30235783Skib__FBSDID("$FreeBSD$"); 31235783Skib 32235783Skib/* 33235783Skib * Simple memory manager interface that keeps track on allocate regions on a 34235783Skib * per "owner" basis. All regions associated with an "owner" can be released 35235783Skib * with a simple call. Typically if the "owner" exists. The owner is any 36235783Skib * "unsigned long" identifier. Can typically be a pointer to a file private 37235783Skib * struct or a context identifier. 38235783Skib * 39235783Skib * Authors: 40235783Skib * Thomas Hellstr��m <thomas-at-tungstengraphics-dot-com> 41235783Skib */ 42235783Skib 43235783Skib#include <dev/drm2/drmP.h> 44235783Skib#include <dev/drm2/drm_sman.h> 45235783Skib 46235783Skibstruct drm_owner_item { 47235783Skib struct drm_hash_item owner_hash; 48235783Skib struct list_head sman_list; 49235783Skib struct list_head mem_blocks; 50235783Skib}; 51235783Skib 52235783Skibvoid drm_sman_takedown(struct drm_sman * sman) 53235783Skib{ 54235783Skib drm_ht_remove(&sman->user_hash_tab); 55235783Skib drm_ht_remove(&sman->owner_hash_tab); 56235783Skib if (sman->mm) 57235783Skib drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm), 58235783Skib DRM_MEM_MM); 59235783Skib} 60235783Skib 61235783Skibint 62235783Skibdrm_sman_init(struct drm_sman * sman, unsigned int num_managers, 63235783Skib unsigned int user_order, unsigned int owner_order) 64235783Skib{ 65235783Skib int ret = 0; 66235783Skib 67235783Skib sman->mm = (struct drm_sman_mm *) drm_calloc(num_managers, 68235783Skib sizeof(*sman->mm), DRM_MEM_MM); 69235783Skib if (!sman->mm) { 70235783Skib ret = -ENOMEM; 71235783Skib goto out; 72235783Skib } 73235783Skib sman->num_managers = num_managers; 74235783Skib INIT_LIST_HEAD(&sman->owner_items); 75235783Skib ret = drm_ht_create(&sman->owner_hash_tab, owner_order); 76235783Skib if (ret) 77235783Skib goto out1; 78235783Skib ret = drm_ht_create(&sman->user_hash_tab, user_order); 79235783Skib if (!ret) 80235783Skib goto out; 81235783Skib 82235783Skib drm_ht_remove(&sman->owner_hash_tab); 83235783Skibout1: 84235783Skib drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM); 85235783Skibout: 86235783Skib return ret; 87235783Skib} 88235783Skib 89235783Skibstatic void *drm_sman_mm_allocate(void *private, unsigned long size, 90235783Skib unsigned alignment) 91235783Skib{ 92235783Skib struct drm_mm *mm = (struct drm_mm *) private; 93235783Skib struct drm_mm_node *tmp; 94235783Skib 95235783Skib tmp = drm_mm_search_free(mm, size, alignment, 1); 96235783Skib if (!tmp) { 97235783Skib return NULL; 98235783Skib } 99235783Skib /* This could be non-atomic, but we are called from a locked path */ 100235783Skib tmp = drm_mm_get_block_atomic(tmp, size, alignment); 101235783Skib return tmp; 102235783Skib} 103235783Skib 104235783Skibstatic void drm_sman_mm_free(void *private, void *ref) 105235783Skib{ 106235783Skib struct drm_mm_node *node = (struct drm_mm_node *) ref; 107235783Skib 108235783Skib drm_mm_put_block(node); 109235783Skib} 110235783Skib 111235783Skibstatic void drm_sman_mm_destroy(void *private) 112235783Skib{ 113235783Skib struct drm_mm *mm = (struct drm_mm *) private; 114235783Skib drm_mm_takedown(mm); 115235783Skib drm_free(mm, sizeof(*mm), DRM_MEM_MM); 116235783Skib} 117235783Skib 118235783Skibstatic unsigned long drm_sman_mm_offset(void *private, void *ref) 119235783Skib{ 120235783Skib struct drm_mm_node *node = (struct drm_mm_node *) ref; 121235783Skib return node->start; 122235783Skib} 123235783Skib 124235783Skibint 125235783Skibdrm_sman_set_range(struct drm_sman * sman, unsigned int manager, 126235783Skib unsigned long start, unsigned long size) 127235783Skib{ 128235783Skib struct drm_sman_mm *sman_mm; 129235783Skib struct drm_mm *mm; 130235783Skib int ret; 131235783Skib 132235783Skib KASSERT(manager < sman->num_managers, ("Invalid manager")); 133235783Skib 134235783Skib sman_mm = &sman->mm[manager]; 135235783Skib mm = malloc(sizeof(*mm), DRM_MEM_MM, M_NOWAIT | M_ZERO); 136235783Skib if (!mm) { 137235783Skib return -ENOMEM; 138235783Skib } 139235783Skib sman_mm->private = mm; 140235783Skib ret = drm_mm_init(mm, start, size); 141235783Skib 142235783Skib if (ret) { 143235783Skib drm_free(mm, sizeof(*mm), DRM_MEM_MM); 144235783Skib return ret; 145235783Skib } 146235783Skib 147235783Skib sman_mm->allocate = drm_sman_mm_allocate; 148235783Skib sman_mm->free = drm_sman_mm_free; 149235783Skib sman_mm->destroy = drm_sman_mm_destroy; 150235783Skib sman_mm->offset = drm_sman_mm_offset; 151235783Skib 152235783Skib return 0; 153235783Skib} 154235783Skib 155235783Skibint 156235783Skibdrm_sman_set_manager(struct drm_sman * sman, unsigned int manager, 157235783Skib struct drm_sman_mm * allocator) 158235783Skib{ 159235783Skib KASSERT(manager < sman->num_managers, ("Invalid manager")); 160235783Skib sman->mm[manager] = *allocator; 161235783Skib 162235783Skib return 0; 163235783Skib} 164235783Skib 165235783Skibstatic struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman, 166235783Skib unsigned long owner) 167235783Skib{ 168235783Skib int ret; 169235783Skib struct drm_hash_item *owner_hash_item; 170235783Skib struct drm_owner_item *owner_item; 171235783Skib 172235783Skib ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item); 173235783Skib if (!ret) { 174235783Skib return drm_hash_entry(owner_hash_item, struct drm_owner_item, 175235783Skib owner_hash); 176235783Skib } 177235783Skib 178235783Skib owner_item = malloc(sizeof(*owner_item), DRM_MEM_MM, M_NOWAIT | M_ZERO); 179235783Skib if (!owner_item) 180235783Skib goto out; 181235783Skib 182235783Skib INIT_LIST_HEAD(&owner_item->mem_blocks); 183235783Skib owner_item->owner_hash.key = owner; 184235783Skib DRM_DEBUG("owner_item = %p, mem_blocks = %p\n", owner_item, &owner_item->mem_blocks); 185235783Skib if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash)) 186235783Skib goto out1; 187235783Skib 188235783Skib list_add_tail(&owner_item->sman_list, &sman->owner_items); 189235783Skib return owner_item; 190235783Skib 191235783Skibout1: 192235783Skib drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); 193235783Skibout: 194235783Skib return NULL; 195235783Skib} 196235783Skib 197235783Skibstruct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int manager, 198235783Skib unsigned long size, unsigned alignment, 199235783Skib unsigned long owner) 200235783Skib{ 201235783Skib void *tmp; 202235783Skib struct drm_sman_mm *sman_mm; 203235783Skib struct drm_owner_item *owner_item; 204235783Skib struct drm_memblock_item *memblock; 205235783Skib 206235783Skib KASSERT(manager < sman->num_managers, ("Invalid manager")); 207235783Skib 208235783Skib sman_mm = &sman->mm[manager]; 209235783Skib tmp = sman_mm->allocate(sman_mm->private, size, alignment); 210235783Skib if (!tmp) { 211235783Skib return NULL; 212235783Skib } 213235783Skib 214235783Skib memblock = malloc(sizeof(*memblock), DRM_MEM_MM, M_NOWAIT | M_ZERO); 215235783Skib DRM_DEBUG("allocated mem_block %p\n", memblock); 216235783Skib if (!memblock) 217235783Skib goto out; 218235783Skib 219235783Skib memblock->mm_info = tmp; 220235783Skib memblock->mm = sman_mm; 221235783Skib memblock->sman = sman; 222235783Skib INIT_LIST_HEAD(&memblock->owner_list); 223235783Skib 224235783Skib if (drm_ht_just_insert_please 225235783Skib (&sman->user_hash_tab, &memblock->user_hash, 226235783Skib (unsigned long)memblock, 32, 0, 0)) 227235783Skib goto out1; 228235783Skib 229235783Skib owner_item = drm_sman_get_owner_item(sman, owner); 230235783Skib if (!owner_item) 231235783Skib goto out2; 232235783Skib 233235783Skib DRM_DEBUG("owner_item = %p, mem_blocks = %p\n", owner_item, &owner_item->mem_blocks); 234235783Skib DRM_DEBUG("owner_list.prev = %p, mem_blocks.prev = %p\n", memblock->owner_list.prev, owner_item->mem_blocks.prev); 235235783Skib DRM_DEBUG("owner_list.next = %p, mem_blocks.next = %p\n", memblock->owner_list.next, owner_item->mem_blocks.next); 236235783Skib list_add_tail(&memblock->owner_list, &owner_item->mem_blocks); 237235783Skib 238235783Skib DRM_DEBUG("Complete\n"); 239235783Skib return memblock; 240235783Skib 241235783Skibout2: 242235783Skib drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash); 243235783Skibout1: 244235783Skib drm_free(memblock, sizeof(*memblock), DRM_MEM_MM); 245235783Skibout: 246235783Skib sman_mm->free(sman_mm->private, tmp); 247235783Skib 248235783Skib return NULL; 249235783Skib} 250235783Skib 251235783Skibstatic void drm_sman_free(struct drm_memblock_item *item) 252235783Skib{ 253235783Skib struct drm_sman *sman = item->sman; 254235783Skib 255235783Skib list_del(&item->owner_list); 256235783Skib drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash); 257235783Skib item->mm->free(item->mm->private, item->mm_info); 258235783Skib drm_free(item, sizeof(*item), DRM_MEM_MM); 259235783Skib} 260235783Skib 261235783Skibint drm_sman_free_key(struct drm_sman *sman, unsigned int key) 262235783Skib{ 263235783Skib struct drm_hash_item *hash_item; 264235783Skib struct drm_memblock_item *memblock_item; 265235783Skib 266235783Skib if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item)) 267235783Skib return -EINVAL; 268235783Skib 269235783Skib memblock_item = drm_hash_entry(hash_item, struct drm_memblock_item, 270235783Skib user_hash); 271235783Skib drm_sman_free(memblock_item); 272235783Skib return 0; 273235783Skib} 274235783Skib 275235783Skibstatic void drm_sman_remove_owner(struct drm_sman *sman, 276235783Skib struct drm_owner_item *owner_item) 277235783Skib{ 278235783Skib list_del(&owner_item->sman_list); 279235783Skib drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash); 280235783Skib drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); 281235783Skib} 282235783Skib 283235783Skibint drm_sman_owner_clean(struct drm_sman *sman, unsigned long owner) 284235783Skib{ 285235783Skib 286235783Skib struct drm_hash_item *hash_item; 287235783Skib struct drm_owner_item *owner_item; 288235783Skib 289235783Skib if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) { 290235783Skib return -1; 291235783Skib } 292235783Skib 293235783Skib owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash); 294235783Skib DRM_DEBUG("cleaning owner_item %p\n", owner_item); 295235783Skib if (owner_item->mem_blocks.next == &owner_item->mem_blocks) { 296235783Skib drm_sman_remove_owner(sman, owner_item); 297235783Skib return -1; 298235783Skib } 299235783Skib 300235783Skib return 0; 301235783Skib} 302235783Skib 303235783Skibstatic void drm_sman_do_owner_cleanup(struct drm_sman *sman, 304235783Skib struct drm_owner_item *owner_item) 305235783Skib{ 306235783Skib struct drm_memblock_item *entry, *next; 307235783Skib 308235783Skib list_for_each_entry_safe(entry, next, &owner_item->mem_blocks, 309235783Skib owner_list) { 310235783Skib DRM_DEBUG("freeing mem_block %p\n", entry); 311235783Skib drm_sman_free(entry); 312235783Skib } 313235783Skib drm_sman_remove_owner(sman, owner_item); 314235783Skib} 315235783Skib 316235783Skibvoid drm_sman_owner_cleanup(struct drm_sman *sman, unsigned long owner) 317235783Skib{ 318235783Skib 319235783Skib struct drm_hash_item *hash_item; 320235783Skib struct drm_owner_item *owner_item; 321235783Skib 322235783Skib if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) { 323235783Skib 324235783Skib return; 325235783Skib } 326235783Skib 327235783Skib owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash); 328235783Skib drm_sman_do_owner_cleanup(sman, owner_item); 329235783Skib} 330235783Skib 331235783Skibvoid drm_sman_cleanup(struct drm_sman *sman) 332235783Skib{ 333235783Skib struct drm_owner_item *entry, *next; 334235783Skib unsigned int i; 335235783Skib struct drm_sman_mm *sman_mm; 336235783Skib 337235783Skib DRM_DEBUG("sman = %p, owner_items = %p\n", 338235783Skib sman, &sman->owner_items); 339235783Skib list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) { 340235783Skib DRM_DEBUG("cleaning owner_item = %p\n", entry); 341235783Skib drm_sman_do_owner_cleanup(sman, entry); 342235783Skib } 343235783Skib if (sman->mm) { 344235783Skib for (i = 0; i < sman->num_managers; ++i) { 345235783Skib sman_mm = &sman->mm[i]; 346235783Skib if (sman_mm->private) { 347235783Skib sman_mm->destroy(sman_mm->private); 348235783Skib sman_mm->private = NULL; 349235783Skib } 350235783Skib } 351235783Skib } 352235783Skib} 353