1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <inttypes.h>
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_inlines.h"
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_memory.h"
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "util/u_double_list.h"
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "nouveau_winsys.h"
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "nouveau_screen.h"
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "nouveau_mm.h"
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define MM_MIN_ORDER 7
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define MM_MAX_ORDER 20
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define MM_NUM_BUCKETS (MM_MAX_ORDER - MM_MIN_ORDER + 1)
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define MM_MIN_SIZE (1 << MM_MIN_ORDER)
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#define MM_MAX_SIZE (1 << MM_MAX_ORDER)
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct mm_bucket {
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct list_head free;
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct list_head used;
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct list_head full;
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int num_free;
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct nouveau_mman {
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nouveau_device *dev;
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct mm_bucket bucket[MM_NUM_BUCKETS];
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   uint32_t domain;
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   union nouveau_bo_config config;
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   uint64_t allocated;
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct mm_slab {
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct list_head head;
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nouveau_bo *bo;
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nouveau_mman *cache;
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int order;
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int count;
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int free;
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   uint32_t bits[0];
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic int
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgmm_slab_alloc(struct mm_slab *slab)
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int i, n, b;
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (slab->free == 0)
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return -1;
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   for (i = 0; i < (slab->count + 31) / 32; ++i) {
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      b = ffs(slab->bits[i]) - 1;
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (b >= 0) {
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         n = i * 32 + b;
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         assert(n < slab->count);
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         slab->free--;
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         slab->bits[i] &= ~(1 << b);
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         return n;
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return -1;
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE void
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgmm_slab_free(struct mm_slab *slab, int i)
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   assert(i < slab->count);
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   slab->bits[i / 32] |= 1 << (i % 32);
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   slab->free++;
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   assert(slab->free <= slab->count);
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE int
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgmm_get_order(uint32_t size)
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int s = __builtin_clz(size) ^ 31;
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (size > (1 << s))
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      s += 1;
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return s;
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct mm_bucket *
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgmm_bucket_by_order(struct nouveau_mman *cache, int order)
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (order > MM_MAX_ORDER)
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return NULL;
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return &cache->bucket[MAX2(order, MM_MIN_ORDER) - MM_MIN_ORDER];
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic struct mm_bucket *
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgmm_bucket_by_size(struct nouveau_mman *cache, unsigned size)
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return mm_bucket_by_order(cache, mm_get_order(size));
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* size of bo allocation for slab with chunks of (1 << chunk_order) bytes */
100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE uint32_t
101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgmm_default_slab_size(unsigned chunk_order)
102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   static const int8_t slab_order[MM_MAX_ORDER - MM_MIN_ORDER + 1] =
104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   {
105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      12, 12, 13, 14, 14, 17, 17, 17, 17, 19, 19, 20, 21, 22
106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   };
107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   assert(chunk_order <= MM_MAX_ORDER && chunk_order >= MM_MIN_ORDER);
109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return 1 << slab_order[chunk_order - MM_MIN_ORDER];
111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic int
114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgmm_slab_new(struct nouveau_mman *cache, int chunk_order)
115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct mm_slab *slab;
117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int words, ret;
118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   const uint32_t size = mm_default_slab_size(chunk_order);
119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   words = ((size >> chunk_order) + 31) / 32;
121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   assert(words);
122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   slab = MALLOC(sizeof(struct mm_slab) + words * 4);
124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!slab)
125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return PIPE_ERROR_OUT_OF_MEMORY;
126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   memset(&slab->bits[0], ~0, words * 4);
128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   slab->bo = NULL;
130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   ret = nouveau_bo_new(cache->dev, cache->domain, 0, size, &cache->config,
132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                        &slab->bo);
133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (ret) {
134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      FREE(slab);
135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return PIPE_ERROR_OUT_OF_MEMORY;
136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   LIST_INITHEAD(&slab->head);
139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   slab->cache = cache;
141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   slab->order = chunk_order;
142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   slab->count = slab->free = size >> chunk_order;
143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   LIST_ADD(&slab->head, &mm_bucket_by_order(cache, chunk_order)->free);
145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cache->allocated += size;
147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (nouveau_mesa_debug)
149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      debug_printf("MM: new slab, total memory = %"PRIu64" KiB\n",
150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                   cache->allocated / 1024);
151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return PIPE_OK;
153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* @return token to identify slab or NULL if we just allocated a new bo */
156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct nouveau_mm_allocation *
157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnouveau_mm_allocate(struct nouveau_mman *cache,
158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                    uint32_t size, struct nouveau_bo **bo, uint32_t *offset)
159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct mm_bucket *bucket;
161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct mm_slab *slab;
162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nouveau_mm_allocation *alloc;
163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int ret;
164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   bucket = mm_bucket_by_size(cache, size);
166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!bucket) {
167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      ret = nouveau_bo_new(cache->dev, cache->domain, 0, size, &cache->config,
168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                           bo);
169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (ret)
170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         debug_printf("bo_new(%x, %x): %i\n",
171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                      size, cache->config.nv50.memtype, ret);
172f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
173f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      *offset = 0;
174f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return NULL;
175f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
176f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
177f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!LIST_IS_EMPTY(&bucket->used)) {
178f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      slab = LIST_ENTRY(struct mm_slab, bucket->used.next, head);
179f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } else {
180f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (LIST_IS_EMPTY(&bucket->free)) {
181f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         mm_slab_new(cache, MAX2(mm_get_order(size), MM_MIN_ORDER));
182f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      }
183f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      slab = LIST_ENTRY(struct mm_slab, bucket->free.next, head);
184f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
185f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_DEL(&slab->head);
186f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_ADD(&slab->head, &bucket->used);
187f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
188f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
189f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   *offset = mm_slab_alloc(slab) << slab->order;
190f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
191f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   alloc = MALLOC_STRUCT(nouveau_mm_allocation);
192f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!alloc)
193f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return NULL;
194f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
195f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   nouveau_bo_ref(slab->bo, bo);
196f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
197f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (slab->free == 0) {
198f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_DEL(&slab->head);
199f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_ADD(&slab->head, &bucket->full);
200f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
201f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
202f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   alloc->next = NULL;
203f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   alloc->offset = *offset;
204f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   alloc->priv = (void *)slab;
205f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
206f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return alloc;
207f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
208f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
209f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid
210f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnouveau_mm_free(struct nouveau_mm_allocation *alloc)
211f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
212f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct mm_slab *slab = (struct mm_slab *)alloc->priv;
213f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct mm_bucket *bucket = mm_bucket_by_order(slab->cache, slab->order);
214f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
215f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   mm_slab_free(slab, alloc->offset >> slab->order);
216f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
217f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (slab->free == slab->count) {
218f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_DEL(&slab->head);
219f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_ADDTAIL(&slab->head, &bucket->free);
220f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   } else
221f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (slab->free == 1) {
222f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_DEL(&slab->head);
223f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_ADDTAIL(&slab->head, &bucket->used);
224f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
225f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
226f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   FREE(alloc);
227f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
228f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
229f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid
230f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnouveau_mm_free_work(void *data)
231f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
232f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   nouveau_mm_free(data);
233f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
234f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
235f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstruct nouveau_mman *
236f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnouveau_mm_create(struct nouveau_device *dev, uint32_t domain,
237f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                  union nouveau_bo_config *config)
238f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
239f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct nouveau_mman *cache = MALLOC_STRUCT(nouveau_mman);
240f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int i;
241f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
242f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!cache)
243f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return NULL;
244f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
245f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cache->dev = dev;
246f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cache->domain = domain;
247f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cache->config = *config;
248f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   cache->allocated = 0;
249f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
250f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   for (i = 0; i < MM_NUM_BUCKETS; ++i) {
251f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_INITHEAD(&cache->bucket[i].free);
252f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_INITHEAD(&cache->bucket[i].used);
253f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_INITHEAD(&cache->bucket[i].full);
254f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
255f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
256f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   return cache;
257f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
258f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
259f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic INLINE void
260f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnouveau_mm_free_slabs(struct list_head *head)
261f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
262f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   struct mm_slab *slab, *next;
263f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
264f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   LIST_FOR_EACH_ENTRY_SAFE(slab, next, head, head) {
265f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      LIST_DEL(&slab->head);
266f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      nouveau_bo_ref(NULL, &slab->bo);
267f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      FREE(slab);
268f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
269f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
270f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
271f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid
272f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnouveau_mm_destroy(struct nouveau_mman *cache)
273f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{
274f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   int i;
275f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
276f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   if (!cache)
277f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      return;
278f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
279f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   for (i = 0; i < MM_NUM_BUCKETS; ++i) {
280f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      if (!LIST_IS_EMPTY(&cache->bucket[i].used) ||
281f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org          !LIST_IS_EMPTY(&cache->bucket[i].full))
282f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org         debug_printf("WARNING: destroying GPU memory cache "
283f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                      "with some buffers still in use\n");
284f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
285f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      nouveau_mm_free_slabs(&cache->bucket[i].free);
286f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      nouveau_mm_free_slabs(&cache->bucket[i].used);
287f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      nouveau_mm_free_slabs(&cache->bucket[i].full);
288f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   }
289f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
290f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org   FREE(cache);
291f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
292f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
293