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