1848b8605Smrg 2848b8605Smrg#include <inttypes.h> 3848b8605Smrg 4848b8605Smrg#include "util/u_inlines.h" 5848b8605Smrg#include "util/u_memory.h" 6b8e80941Smrg#include "util/list.h" 7848b8605Smrg 8848b8605Smrg#include "nouveau_winsys.h" 9848b8605Smrg#include "nouveau_screen.h" 10848b8605Smrg#include "nouveau_mm.h" 11848b8605Smrg 12848b8605Smrg/* TODO: Higher orders can waste a lot of space for npot size buffers, should 13848b8605Smrg * add an extra cache for such buffer objects. 14848b8605Smrg * 15848b8605Smrg * HACK: Max order == 21 to accommodate TF2's 1.5 MiB, frequently reallocated 16848b8605Smrg * vertex buffer (VM flush (?) decreases performance dramatically). 17848b8605Smrg */ 18848b8605Smrg 19848b8605Smrg#define MM_MIN_ORDER 7 /* >= 6 to not violate ARB_map_buffer_alignment */ 20848b8605Smrg#define MM_MAX_ORDER 21 21848b8605Smrg 22848b8605Smrg#define MM_NUM_BUCKETS (MM_MAX_ORDER - MM_MIN_ORDER + 1) 23848b8605Smrg 24848b8605Smrg#define MM_MIN_SIZE (1 << MM_MIN_ORDER) 25848b8605Smrg#define MM_MAX_SIZE (1 << MM_MAX_ORDER) 26848b8605Smrg 27848b8605Smrgstruct mm_bucket { 28848b8605Smrg struct list_head free; 29848b8605Smrg struct list_head used; 30848b8605Smrg struct list_head full; 31848b8605Smrg int num_free; 32848b8605Smrg}; 33848b8605Smrg 34848b8605Smrgstruct nouveau_mman { 35848b8605Smrg struct nouveau_device *dev; 36848b8605Smrg struct mm_bucket bucket[MM_NUM_BUCKETS]; 37848b8605Smrg uint32_t domain; 38848b8605Smrg union nouveau_bo_config config; 39848b8605Smrg uint64_t allocated; 40848b8605Smrg}; 41848b8605Smrg 42848b8605Smrgstruct mm_slab { 43848b8605Smrg struct list_head head; 44848b8605Smrg struct nouveau_bo *bo; 45848b8605Smrg struct nouveau_mman *cache; 46848b8605Smrg int order; 47848b8605Smrg int count; 48848b8605Smrg int free; 49848b8605Smrg uint32_t bits[0]; 50848b8605Smrg}; 51848b8605Smrg 52848b8605Smrgstatic int 53848b8605Smrgmm_slab_alloc(struct mm_slab *slab) 54848b8605Smrg{ 55848b8605Smrg int i, n, b; 56848b8605Smrg 57848b8605Smrg if (slab->free == 0) 58848b8605Smrg return -1; 59848b8605Smrg 60848b8605Smrg for (i = 0; i < (slab->count + 31) / 32; ++i) { 61848b8605Smrg b = ffs(slab->bits[i]) - 1; 62848b8605Smrg if (b >= 0) { 63848b8605Smrg n = i * 32 + b; 64848b8605Smrg assert(n < slab->count); 65848b8605Smrg slab->free--; 66848b8605Smrg slab->bits[i] &= ~(1 << b); 67848b8605Smrg return n; 68848b8605Smrg } 69848b8605Smrg } 70848b8605Smrg return -1; 71848b8605Smrg} 72848b8605Smrg 73b8e80941Smrgstatic inline void 74848b8605Smrgmm_slab_free(struct mm_slab *slab, int i) 75848b8605Smrg{ 76848b8605Smrg assert(i < slab->count); 77848b8605Smrg slab->bits[i / 32] |= 1 << (i % 32); 78848b8605Smrg slab->free++; 79848b8605Smrg assert(slab->free <= slab->count); 80848b8605Smrg} 81848b8605Smrg 82b8e80941Smrgstatic inline int 83848b8605Smrgmm_get_order(uint32_t size) 84848b8605Smrg{ 85848b8605Smrg int s = __builtin_clz(size) ^ 31; 86848b8605Smrg 87848b8605Smrg if (size > (1 << s)) 88848b8605Smrg s += 1; 89848b8605Smrg return s; 90848b8605Smrg} 91848b8605Smrg 92848b8605Smrgstatic struct mm_bucket * 93848b8605Smrgmm_bucket_by_order(struct nouveau_mman *cache, int order) 94848b8605Smrg{ 95848b8605Smrg if (order > MM_MAX_ORDER) 96848b8605Smrg return NULL; 97848b8605Smrg return &cache->bucket[MAX2(order, MM_MIN_ORDER) - MM_MIN_ORDER]; 98848b8605Smrg} 99848b8605Smrg 100848b8605Smrgstatic struct mm_bucket * 101848b8605Smrgmm_bucket_by_size(struct nouveau_mman *cache, unsigned size) 102848b8605Smrg{ 103848b8605Smrg return mm_bucket_by_order(cache, mm_get_order(size)); 104848b8605Smrg} 105848b8605Smrg 106848b8605Smrg/* size of bo allocation for slab with chunks of (1 << chunk_order) bytes */ 107b8e80941Smrgstatic inline uint32_t 108848b8605Smrgmm_default_slab_size(unsigned chunk_order) 109848b8605Smrg{ 110848b8605Smrg static const int8_t slab_order[MM_MAX_ORDER - MM_MIN_ORDER + 1] = 111848b8605Smrg { 112848b8605Smrg 12, 12, 13, 14, 14, 17, 17, 17, 17, 19, 19, 20, 21, 22, 22 113848b8605Smrg }; 114848b8605Smrg 115848b8605Smrg assert(chunk_order <= MM_MAX_ORDER && chunk_order >= MM_MIN_ORDER); 116848b8605Smrg 117848b8605Smrg return 1 << slab_order[chunk_order - MM_MIN_ORDER]; 118848b8605Smrg} 119848b8605Smrg 120848b8605Smrgstatic int 121848b8605Smrgmm_slab_new(struct nouveau_mman *cache, int chunk_order) 122848b8605Smrg{ 123848b8605Smrg struct mm_slab *slab; 124848b8605Smrg int words, ret; 125848b8605Smrg const uint32_t size = mm_default_slab_size(chunk_order); 126848b8605Smrg 127848b8605Smrg words = ((size >> chunk_order) + 31) / 32; 128848b8605Smrg assert(words); 129848b8605Smrg 130848b8605Smrg slab = MALLOC(sizeof(struct mm_slab) + words * 4); 131848b8605Smrg if (!slab) 132848b8605Smrg return PIPE_ERROR_OUT_OF_MEMORY; 133848b8605Smrg 134848b8605Smrg memset(&slab->bits[0], ~0, words * 4); 135848b8605Smrg 136848b8605Smrg slab->bo = NULL; 137848b8605Smrg 138848b8605Smrg ret = nouveau_bo_new(cache->dev, cache->domain, 0, size, &cache->config, 139848b8605Smrg &slab->bo); 140848b8605Smrg if (ret) { 141848b8605Smrg FREE(slab); 142848b8605Smrg return PIPE_ERROR_OUT_OF_MEMORY; 143848b8605Smrg } 144848b8605Smrg 145848b8605Smrg LIST_INITHEAD(&slab->head); 146848b8605Smrg 147848b8605Smrg slab->cache = cache; 148848b8605Smrg slab->order = chunk_order; 149848b8605Smrg slab->count = slab->free = size >> chunk_order; 150848b8605Smrg 151848b8605Smrg LIST_ADD(&slab->head, &mm_bucket_by_order(cache, chunk_order)->free); 152848b8605Smrg 153848b8605Smrg cache->allocated += size; 154848b8605Smrg 155848b8605Smrg if (nouveau_mesa_debug) 156848b8605Smrg debug_printf("MM: new slab, total memory = %"PRIu64" KiB\n", 157848b8605Smrg cache->allocated / 1024); 158848b8605Smrg 159848b8605Smrg return PIPE_OK; 160848b8605Smrg} 161848b8605Smrg 162848b8605Smrg/* @return token to identify slab or NULL if we just allocated a new bo */ 163848b8605Smrgstruct nouveau_mm_allocation * 164848b8605Smrgnouveau_mm_allocate(struct nouveau_mman *cache, 165848b8605Smrg uint32_t size, struct nouveau_bo **bo, uint32_t *offset) 166848b8605Smrg{ 167848b8605Smrg struct mm_bucket *bucket; 168848b8605Smrg struct mm_slab *slab; 169848b8605Smrg struct nouveau_mm_allocation *alloc; 170848b8605Smrg int ret; 171848b8605Smrg 172848b8605Smrg bucket = mm_bucket_by_size(cache, size); 173848b8605Smrg if (!bucket) { 174848b8605Smrg ret = nouveau_bo_new(cache->dev, cache->domain, 0, size, &cache->config, 175848b8605Smrg bo); 176848b8605Smrg if (ret) 177848b8605Smrg debug_printf("bo_new(%x, %x): %i\n", 178848b8605Smrg size, cache->config.nv50.memtype, ret); 179848b8605Smrg 180848b8605Smrg *offset = 0; 181848b8605Smrg return NULL; 182848b8605Smrg } 183848b8605Smrg 184848b8605Smrg if (!LIST_IS_EMPTY(&bucket->used)) { 185848b8605Smrg slab = LIST_ENTRY(struct mm_slab, bucket->used.next, head); 186848b8605Smrg } else { 187848b8605Smrg if (LIST_IS_EMPTY(&bucket->free)) { 188848b8605Smrg mm_slab_new(cache, MAX2(mm_get_order(size), MM_MIN_ORDER)); 189848b8605Smrg } 190848b8605Smrg slab = LIST_ENTRY(struct mm_slab, bucket->free.next, head); 191848b8605Smrg 192848b8605Smrg LIST_DEL(&slab->head); 193848b8605Smrg LIST_ADD(&slab->head, &bucket->used); 194848b8605Smrg } 195848b8605Smrg 196848b8605Smrg *offset = mm_slab_alloc(slab) << slab->order; 197848b8605Smrg 198848b8605Smrg alloc = MALLOC_STRUCT(nouveau_mm_allocation); 199848b8605Smrg if (!alloc) 200848b8605Smrg return NULL; 201848b8605Smrg 202848b8605Smrg nouveau_bo_ref(slab->bo, bo); 203848b8605Smrg 204848b8605Smrg if (slab->free == 0) { 205848b8605Smrg LIST_DEL(&slab->head); 206848b8605Smrg LIST_ADD(&slab->head, &bucket->full); 207848b8605Smrg } 208848b8605Smrg 209848b8605Smrg alloc->next = NULL; 210848b8605Smrg alloc->offset = *offset; 211848b8605Smrg alloc->priv = (void *)slab; 212848b8605Smrg 213848b8605Smrg return alloc; 214848b8605Smrg} 215848b8605Smrg 216848b8605Smrgvoid 217848b8605Smrgnouveau_mm_free(struct nouveau_mm_allocation *alloc) 218848b8605Smrg{ 219848b8605Smrg struct mm_slab *slab = (struct mm_slab *)alloc->priv; 220848b8605Smrg struct mm_bucket *bucket = mm_bucket_by_order(slab->cache, slab->order); 221848b8605Smrg 222848b8605Smrg mm_slab_free(slab, alloc->offset >> slab->order); 223848b8605Smrg 224848b8605Smrg if (slab->free == slab->count) { 225848b8605Smrg LIST_DEL(&slab->head); 226848b8605Smrg LIST_ADDTAIL(&slab->head, &bucket->free); 227848b8605Smrg } else 228848b8605Smrg if (slab->free == 1) { 229848b8605Smrg LIST_DEL(&slab->head); 230848b8605Smrg LIST_ADDTAIL(&slab->head, &bucket->used); 231848b8605Smrg } 232848b8605Smrg 233848b8605Smrg FREE(alloc); 234848b8605Smrg} 235848b8605Smrg 236848b8605Smrgvoid 237848b8605Smrgnouveau_mm_free_work(void *data) 238848b8605Smrg{ 239848b8605Smrg nouveau_mm_free(data); 240848b8605Smrg} 241848b8605Smrg 242848b8605Smrgstruct nouveau_mman * 243848b8605Smrgnouveau_mm_create(struct nouveau_device *dev, uint32_t domain, 244848b8605Smrg union nouveau_bo_config *config) 245848b8605Smrg{ 246848b8605Smrg struct nouveau_mman *cache = MALLOC_STRUCT(nouveau_mman); 247848b8605Smrg int i; 248848b8605Smrg 249848b8605Smrg if (!cache) 250848b8605Smrg return NULL; 251848b8605Smrg 252848b8605Smrg cache->dev = dev; 253848b8605Smrg cache->domain = domain; 254848b8605Smrg cache->config = *config; 255848b8605Smrg cache->allocated = 0; 256848b8605Smrg 257848b8605Smrg for (i = 0; i < MM_NUM_BUCKETS; ++i) { 258848b8605Smrg LIST_INITHEAD(&cache->bucket[i].free); 259848b8605Smrg LIST_INITHEAD(&cache->bucket[i].used); 260848b8605Smrg LIST_INITHEAD(&cache->bucket[i].full); 261848b8605Smrg } 262848b8605Smrg 263848b8605Smrg return cache; 264848b8605Smrg} 265848b8605Smrg 266b8e80941Smrgstatic inline void 267848b8605Smrgnouveau_mm_free_slabs(struct list_head *head) 268848b8605Smrg{ 269848b8605Smrg struct mm_slab *slab, *next; 270848b8605Smrg 271848b8605Smrg LIST_FOR_EACH_ENTRY_SAFE(slab, next, head, head) { 272848b8605Smrg LIST_DEL(&slab->head); 273848b8605Smrg nouveau_bo_ref(NULL, &slab->bo); 274848b8605Smrg FREE(slab); 275848b8605Smrg } 276848b8605Smrg} 277848b8605Smrg 278848b8605Smrgvoid 279848b8605Smrgnouveau_mm_destroy(struct nouveau_mman *cache) 280848b8605Smrg{ 281848b8605Smrg int i; 282848b8605Smrg 283848b8605Smrg if (!cache) 284848b8605Smrg return; 285848b8605Smrg 286848b8605Smrg for (i = 0; i < MM_NUM_BUCKETS; ++i) { 287848b8605Smrg if (!LIST_IS_EMPTY(&cache->bucket[i].used) || 288848b8605Smrg !LIST_IS_EMPTY(&cache->bucket[i].full)) 289848b8605Smrg debug_printf("WARNING: destroying GPU memory cache " 290848b8605Smrg "with some buffers still in use\n"); 291848b8605Smrg 292848b8605Smrg nouveau_mm_free_slabs(&cache->bucket[i].free); 293848b8605Smrg nouveau_mm_free_slabs(&cache->bucket[i].used); 294848b8605Smrg nouveau_mm_free_slabs(&cache->bucket[i].full); 295848b8605Smrg } 296848b8605Smrg 297848b8605Smrg FREE(cache); 298848b8605Smrg} 299