1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2006-2008 VMware, Inc., USA
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, FREE of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17bf215546Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
21bf215546Sopenharmony_ci *
22bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
23bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
24bf215546Sopenharmony_ci * of the Software.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci *
27bf215546Sopenharmony_ci **************************************************************************/
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci/**
30bf215546Sopenharmony_ci * @file
31bf215546Sopenharmony_ci * S-lab pool implementation.
32bf215546Sopenharmony_ci *
33bf215546Sopenharmony_ci * @sa http://en.wikipedia.org/wiki/Slab_allocation
34bf215546Sopenharmony_ci *
35bf215546Sopenharmony_ci * @author Thomas Hellstrom <thellstrom-at-vmware-dot-com>
36bf215546Sopenharmony_ci * @author Jose Fonseca <jfonseca@vmware.com>
37bf215546Sopenharmony_ci */
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci#include "pipe/p_compiler.h"
40bf215546Sopenharmony_ci#include "util/u_debug.h"
41bf215546Sopenharmony_ci#include "os/os_thread.h"
42bf215546Sopenharmony_ci#include "pipe/p_defines.h"
43bf215546Sopenharmony_ci#include "util/u_memory.h"
44bf215546Sopenharmony_ci#include "util/list.h"
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci#include "pb_buffer.h"
47bf215546Sopenharmony_ci#include "pb_bufmgr.h"
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_cistruct pb_slab;
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci/**
54bf215546Sopenharmony_ci * Buffer in a slab.
55bf215546Sopenharmony_ci *
56bf215546Sopenharmony_ci * Sub-allocation of a contiguous buffer.
57bf215546Sopenharmony_ci */
58bf215546Sopenharmony_cistruct pb_slab_buffer
59bf215546Sopenharmony_ci{
60bf215546Sopenharmony_ci   struct pb_buffer base;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   struct pb_slab *slab;
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci   struct list_head head;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   unsigned mapCount;
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci   /** Offset relative to the start of the slab buffer. */
69bf215546Sopenharmony_ci   pb_size start;
70bf215546Sopenharmony_ci};
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci/**
74bf215546Sopenharmony_ci * Slab -- a contiguous piece of memory.
75bf215546Sopenharmony_ci */
76bf215546Sopenharmony_cistruct pb_slab
77bf215546Sopenharmony_ci{
78bf215546Sopenharmony_ci   struct list_head head;
79bf215546Sopenharmony_ci   struct list_head freeBuffers;
80bf215546Sopenharmony_ci   pb_size numBuffers;
81bf215546Sopenharmony_ci   pb_size numFree;
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci   struct pb_slab_buffer *buffers;
84bf215546Sopenharmony_ci   struct pb_slab_manager *mgr;
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci   /** Buffer from the provider */
87bf215546Sopenharmony_ci   struct pb_buffer *bo;
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   void *virtual;
90bf215546Sopenharmony_ci};
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci/**
94bf215546Sopenharmony_ci * It adds/removes slabs as needed in order to meet the allocation/destruction
95bf215546Sopenharmony_ci * of individual buffers.
96bf215546Sopenharmony_ci */
97bf215546Sopenharmony_cistruct pb_slab_manager
98bf215546Sopenharmony_ci{
99bf215546Sopenharmony_ci   struct pb_manager base;
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci   /** From where we get our buffers */
102bf215546Sopenharmony_ci   struct pb_manager *provider;
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   /** Size of the buffers we hand on downstream */
105bf215546Sopenharmony_ci   pb_size bufSize;
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   /** Size of the buffers we request upstream */
108bf215546Sopenharmony_ci   pb_size slabSize;
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci   /**
111bf215546Sopenharmony_ci    * Alignment, usage to be used to allocate the slab buffers.
112bf215546Sopenharmony_ci    *
113bf215546Sopenharmony_ci    * We can only provide buffers which are consistent (in alignment, usage)
114bf215546Sopenharmony_ci    * with this description.
115bf215546Sopenharmony_ci    */
116bf215546Sopenharmony_ci   struct pb_desc desc;
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   /**
119bf215546Sopenharmony_ci    * Partial slabs
120bf215546Sopenharmony_ci    *
121bf215546Sopenharmony_ci    * Full slabs are not stored in any list. Empty slabs are destroyed
122bf215546Sopenharmony_ci    * immediatly.
123bf215546Sopenharmony_ci    */
124bf215546Sopenharmony_ci   struct list_head slabs;
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_ci   mtx_t mutex;
127bf215546Sopenharmony_ci};
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci/**
131bf215546Sopenharmony_ci * Wrapper around several slabs, therefore capable of handling buffers of
132bf215546Sopenharmony_ci * multiple sizes.
133bf215546Sopenharmony_ci *
134bf215546Sopenharmony_ci * This buffer manager just dispatches buffer allocations to the appropriate slab
135bf215546Sopenharmony_ci * manager, according to the requested buffer size, or by passes the slab
136bf215546Sopenharmony_ci * managers altogether for even greater sizes.
137bf215546Sopenharmony_ci *
138bf215546Sopenharmony_ci * The data of this structure remains constant after
139bf215546Sopenharmony_ci * initialization and thus needs no mutex protection.
140bf215546Sopenharmony_ci */
141bf215546Sopenharmony_cistruct pb_slab_range_manager
142bf215546Sopenharmony_ci{
143bf215546Sopenharmony_ci   struct pb_manager base;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   struct pb_manager *provider;
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   pb_size minBufSize;
148bf215546Sopenharmony_ci   pb_size maxBufSize;
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci   /** @sa pb_slab_manager::desc */
151bf215546Sopenharmony_ci   struct pb_desc desc;
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci   unsigned numBuckets;
154bf215546Sopenharmony_ci   pb_size *bucketSizes;
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   /** Array of pb_slab_manager, one for each bucket size */
157bf215546Sopenharmony_ci   struct pb_manager **buckets;
158bf215546Sopenharmony_ci};
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_cistatic inline struct pb_slab_buffer *
162bf215546Sopenharmony_cipb_slab_buffer(struct pb_buffer *buf)
163bf215546Sopenharmony_ci{
164bf215546Sopenharmony_ci   assert(buf);
165bf215546Sopenharmony_ci   return (struct pb_slab_buffer *)buf;
166bf215546Sopenharmony_ci}
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_cistatic inline struct pb_slab_manager *
170bf215546Sopenharmony_cipb_slab_manager(struct pb_manager *mgr)
171bf215546Sopenharmony_ci{
172bf215546Sopenharmony_ci   assert(mgr);
173bf215546Sopenharmony_ci   return (struct pb_slab_manager *)mgr;
174bf215546Sopenharmony_ci}
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_cistatic inline struct pb_slab_range_manager *
178bf215546Sopenharmony_cipb_slab_range_manager(struct pb_manager *mgr)
179bf215546Sopenharmony_ci{
180bf215546Sopenharmony_ci   assert(mgr);
181bf215546Sopenharmony_ci   return (struct pb_slab_range_manager *)mgr;
182bf215546Sopenharmony_ci}
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci/**
186bf215546Sopenharmony_ci * Delete a buffer from the slab delayed list and put
187bf215546Sopenharmony_ci * it on the slab FREE list.
188bf215546Sopenharmony_ci */
189bf215546Sopenharmony_cistatic void
190bf215546Sopenharmony_cipb_slab_buffer_destroy(void *winsys, struct pb_buffer *_buf)
191bf215546Sopenharmony_ci{
192bf215546Sopenharmony_ci   struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
193bf215546Sopenharmony_ci   struct pb_slab *slab = buf->slab;
194bf215546Sopenharmony_ci   struct pb_slab_manager *mgr = slab->mgr;
195bf215546Sopenharmony_ci   struct list_head *list = &buf->head;
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci   mtx_lock(&mgr->mutex);
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci   assert(!pipe_is_referenced(&buf->base.reference));
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   buf->mapCount = 0;
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci   list_del(list);
204bf215546Sopenharmony_ci   list_addtail(list, &slab->freeBuffers);
205bf215546Sopenharmony_ci   slab->numFree++;
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   if (slab->head.next == &slab->head)
208bf215546Sopenharmony_ci      list_addtail(&slab->head, &mgr->slabs);
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   /* If the slab becomes totally empty, free it */
211bf215546Sopenharmony_ci   if (slab->numFree == slab->numBuffers) {
212bf215546Sopenharmony_ci      list = &slab->head;
213bf215546Sopenharmony_ci      list_delinit(list);
214bf215546Sopenharmony_ci      pb_unmap(slab->bo);
215bf215546Sopenharmony_ci      pb_reference(&slab->bo, NULL);
216bf215546Sopenharmony_ci      FREE(slab->buffers);
217bf215546Sopenharmony_ci      FREE(slab);
218bf215546Sopenharmony_ci   }
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci   mtx_unlock(&mgr->mutex);
221bf215546Sopenharmony_ci}
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_cistatic void *
225bf215546Sopenharmony_cipb_slab_buffer_map(struct pb_buffer *_buf,
226bf215546Sopenharmony_ci                   enum pb_usage_flags flags,
227bf215546Sopenharmony_ci                   void *flush_ctx)
228bf215546Sopenharmony_ci{
229bf215546Sopenharmony_ci   struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   /* XXX: it will be necessary to remap here to propagate flush_ctx */
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci   ++buf->mapCount;
234bf215546Sopenharmony_ci   return (void *) ((uint8_t *) buf->slab->virtual + buf->start);
235bf215546Sopenharmony_ci}
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_cistatic void
239bf215546Sopenharmony_cipb_slab_buffer_unmap(struct pb_buffer *_buf)
240bf215546Sopenharmony_ci{
241bf215546Sopenharmony_ci   struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   --buf->mapCount;
244bf215546Sopenharmony_ci}
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_cistatic enum pipe_error
248bf215546Sopenharmony_cipb_slab_buffer_validate(struct pb_buffer *_buf,
249bf215546Sopenharmony_ci                         struct pb_validate *vl,
250bf215546Sopenharmony_ci                         enum pb_usage_flags flags)
251bf215546Sopenharmony_ci{
252bf215546Sopenharmony_ci   struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
253bf215546Sopenharmony_ci   return pb_validate(buf->slab->bo, vl, flags);
254bf215546Sopenharmony_ci}
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_cistatic void
258bf215546Sopenharmony_cipb_slab_buffer_fence(struct pb_buffer *_buf,
259bf215546Sopenharmony_ci                      struct pipe_fence_handle *fence)
260bf215546Sopenharmony_ci{
261bf215546Sopenharmony_ci   struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
262bf215546Sopenharmony_ci   pb_fence(buf->slab->bo, fence);
263bf215546Sopenharmony_ci}
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_cistatic void
267bf215546Sopenharmony_cipb_slab_buffer_get_base_buffer(struct pb_buffer *_buf,
268bf215546Sopenharmony_ci                               struct pb_buffer **base_buf,
269bf215546Sopenharmony_ci                               pb_size *offset)
270bf215546Sopenharmony_ci{
271bf215546Sopenharmony_ci   struct pb_slab_buffer *buf = pb_slab_buffer(_buf);
272bf215546Sopenharmony_ci   pb_get_base_buffer(buf->slab->bo, base_buf, offset);
273bf215546Sopenharmony_ci   *offset += buf->start;
274bf215546Sopenharmony_ci}
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_cistatic const struct pb_vtbl
278bf215546Sopenharmony_cipb_slab_buffer_vtbl = {
279bf215546Sopenharmony_ci      pb_slab_buffer_destroy,
280bf215546Sopenharmony_ci      pb_slab_buffer_map,
281bf215546Sopenharmony_ci      pb_slab_buffer_unmap,
282bf215546Sopenharmony_ci      pb_slab_buffer_validate,
283bf215546Sopenharmony_ci      pb_slab_buffer_fence,
284bf215546Sopenharmony_ci      pb_slab_buffer_get_base_buffer
285bf215546Sopenharmony_ci};
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_ci/**
289bf215546Sopenharmony_ci * Create a new slab.
290bf215546Sopenharmony_ci *
291bf215546Sopenharmony_ci * Called when we ran out of free slabs.
292bf215546Sopenharmony_ci */
293bf215546Sopenharmony_cistatic enum pipe_error
294bf215546Sopenharmony_cipb_slab_create(struct pb_slab_manager *mgr)
295bf215546Sopenharmony_ci{
296bf215546Sopenharmony_ci   struct pb_slab *slab;
297bf215546Sopenharmony_ci   struct pb_slab_buffer *buf;
298bf215546Sopenharmony_ci   unsigned numBuffers;
299bf215546Sopenharmony_ci   unsigned i;
300bf215546Sopenharmony_ci   enum pipe_error ret;
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_ci   slab = CALLOC_STRUCT(pb_slab);
303bf215546Sopenharmony_ci   if (!slab)
304bf215546Sopenharmony_ci      return PIPE_ERROR_OUT_OF_MEMORY;
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_ci   slab->bo = mgr->provider->create_buffer(mgr->provider, mgr->slabSize, &mgr->desc);
307bf215546Sopenharmony_ci   if(!slab->bo) {
308bf215546Sopenharmony_ci      ret = PIPE_ERROR_OUT_OF_MEMORY;
309bf215546Sopenharmony_ci      goto out_err0;
310bf215546Sopenharmony_ci   }
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci   /* Note down the slab virtual address. All mappings are accessed directly
313bf215546Sopenharmony_ci    * through this address so it is required that the buffer is mapped
314bf215546Sopenharmony_ci    * persistent */
315bf215546Sopenharmony_ci   slab->virtual = pb_map(slab->bo,
316bf215546Sopenharmony_ci                          PB_USAGE_CPU_READ |
317bf215546Sopenharmony_ci                          PB_USAGE_CPU_WRITE |
318bf215546Sopenharmony_ci                          PB_USAGE_PERSISTENT, NULL);
319bf215546Sopenharmony_ci   if(!slab->virtual) {
320bf215546Sopenharmony_ci      ret = PIPE_ERROR_OUT_OF_MEMORY;
321bf215546Sopenharmony_ci      goto out_err1;
322bf215546Sopenharmony_ci   }
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci   numBuffers = slab->bo->size / mgr->bufSize;
325bf215546Sopenharmony_ci
326bf215546Sopenharmony_ci   slab->buffers = CALLOC(numBuffers, sizeof(*slab->buffers));
327bf215546Sopenharmony_ci   if (!slab->buffers) {
328bf215546Sopenharmony_ci      ret = PIPE_ERROR_OUT_OF_MEMORY;
329bf215546Sopenharmony_ci      goto out_err1;
330bf215546Sopenharmony_ci   }
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   list_inithead(&slab->head);
333bf215546Sopenharmony_ci   list_inithead(&slab->freeBuffers);
334bf215546Sopenharmony_ci   slab->numBuffers = numBuffers;
335bf215546Sopenharmony_ci   slab->numFree = 0;
336bf215546Sopenharmony_ci   slab->mgr = mgr;
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci   buf = slab->buffers;
339bf215546Sopenharmony_ci   for (i=0; i < numBuffers; ++i) {
340bf215546Sopenharmony_ci      pipe_reference_init(&buf->base.reference, 0);
341bf215546Sopenharmony_ci      buf->base.size = mgr->bufSize;
342bf215546Sopenharmony_ci      buf->base.alignment_log2 = 0;
343bf215546Sopenharmony_ci      buf->base.usage = 0;
344bf215546Sopenharmony_ci      buf->base.vtbl = &pb_slab_buffer_vtbl;
345bf215546Sopenharmony_ci      buf->slab = slab;
346bf215546Sopenharmony_ci      buf->start = i* mgr->bufSize;
347bf215546Sopenharmony_ci      buf->mapCount = 0;
348bf215546Sopenharmony_ci      list_addtail(&buf->head, &slab->freeBuffers);
349bf215546Sopenharmony_ci      slab->numFree++;
350bf215546Sopenharmony_ci      buf++;
351bf215546Sopenharmony_ci   }
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci   /* Add this slab to the list of partial slabs */
354bf215546Sopenharmony_ci   list_addtail(&slab->head, &mgr->slabs);
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci   return PIPE_OK;
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ciout_err1:
359bf215546Sopenharmony_ci   pb_reference(&slab->bo, NULL);
360bf215546Sopenharmony_ciout_err0:
361bf215546Sopenharmony_ci   FREE(slab);
362bf215546Sopenharmony_ci   return ret;
363bf215546Sopenharmony_ci}
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_ci
366bf215546Sopenharmony_cistatic struct pb_buffer *
367bf215546Sopenharmony_cipb_slab_manager_create_buffer(struct pb_manager *_mgr,
368bf215546Sopenharmony_ci                              pb_size size,
369bf215546Sopenharmony_ci                              const struct pb_desc *desc)
370bf215546Sopenharmony_ci{
371bf215546Sopenharmony_ci   struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
372bf215546Sopenharmony_ci   static struct pb_slab_buffer *buf;
373bf215546Sopenharmony_ci   struct pb_slab *slab;
374bf215546Sopenharmony_ci   struct list_head *list;
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci   /* check size */
377bf215546Sopenharmony_ci   assert(size <= mgr->bufSize);
378bf215546Sopenharmony_ci   if(size > mgr->bufSize)
379bf215546Sopenharmony_ci      return NULL;
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci   /* check if we can provide the requested alignment */
382bf215546Sopenharmony_ci   assert(pb_check_alignment(desc->alignment, mgr->desc.alignment));
383bf215546Sopenharmony_ci   if(!pb_check_alignment(desc->alignment, mgr->desc.alignment))
384bf215546Sopenharmony_ci      return NULL;
385bf215546Sopenharmony_ci   assert(pb_check_alignment(desc->alignment, mgr->bufSize));
386bf215546Sopenharmony_ci   if(!pb_check_alignment(desc->alignment, mgr->bufSize))
387bf215546Sopenharmony_ci      return NULL;
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_ci   assert(pb_check_usage(desc->usage, mgr->desc.usage));
390bf215546Sopenharmony_ci   if(!pb_check_usage(desc->usage, mgr->desc.usage))
391bf215546Sopenharmony_ci      return NULL;
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci   mtx_lock(&mgr->mutex);
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_ci   /* Create a new slab, if we run out of partial slabs */
396bf215546Sopenharmony_ci   if (mgr->slabs.next == &mgr->slabs) {
397bf215546Sopenharmony_ci      (void) pb_slab_create(mgr);
398bf215546Sopenharmony_ci      if (mgr->slabs.next == &mgr->slabs) {
399bf215546Sopenharmony_ci	 mtx_unlock(&mgr->mutex);
400bf215546Sopenharmony_ci	 return NULL;
401bf215546Sopenharmony_ci      }
402bf215546Sopenharmony_ci   }
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci   /* Allocate the buffer from a partial (or just created) slab */
405bf215546Sopenharmony_ci   list = mgr->slabs.next;
406bf215546Sopenharmony_ci   slab = list_entry(list, struct pb_slab, head);
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_ci   /* If totally full remove from the partial slab list */
409bf215546Sopenharmony_ci   if (--slab->numFree == 0)
410bf215546Sopenharmony_ci      list_delinit(list);
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_ci   list = slab->freeBuffers.next;
413bf215546Sopenharmony_ci   list_delinit(list);
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci   mtx_unlock(&mgr->mutex);
416bf215546Sopenharmony_ci   buf = list_entry(list, struct pb_slab_buffer, head);
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci   pipe_reference_init(&buf->base.reference, 1);
419bf215546Sopenharmony_ci   buf->base.alignment_log2 = util_logbase2(desc->alignment);
420bf215546Sopenharmony_ci   buf->base.usage = desc->usage;
421bf215546Sopenharmony_ci
422bf215546Sopenharmony_ci   return &buf->base;
423bf215546Sopenharmony_ci}
424bf215546Sopenharmony_ci
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_cistatic void
427bf215546Sopenharmony_cipb_slab_manager_flush(struct pb_manager *_mgr)
428bf215546Sopenharmony_ci{
429bf215546Sopenharmony_ci   struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
430bf215546Sopenharmony_ci
431bf215546Sopenharmony_ci   assert(mgr->provider->flush);
432bf215546Sopenharmony_ci   if(mgr->provider->flush)
433bf215546Sopenharmony_ci      mgr->provider->flush(mgr->provider);
434bf215546Sopenharmony_ci}
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci
437bf215546Sopenharmony_cistatic void
438bf215546Sopenharmony_cipb_slab_manager_destroy(struct pb_manager *_mgr)
439bf215546Sopenharmony_ci{
440bf215546Sopenharmony_ci   struct pb_slab_manager *mgr = pb_slab_manager(_mgr);
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci   /* TODO: cleanup all allocated buffers */
443bf215546Sopenharmony_ci   FREE(mgr);
444bf215546Sopenharmony_ci}
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_cistruct pb_manager *
448bf215546Sopenharmony_cipb_slab_manager_create(struct pb_manager *provider,
449bf215546Sopenharmony_ci                       pb_size bufSize,
450bf215546Sopenharmony_ci                       pb_size slabSize,
451bf215546Sopenharmony_ci                       const struct pb_desc *desc)
452bf215546Sopenharmony_ci{
453bf215546Sopenharmony_ci   struct pb_slab_manager *mgr;
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_ci   mgr = CALLOC_STRUCT(pb_slab_manager);
456bf215546Sopenharmony_ci   if (!mgr)
457bf215546Sopenharmony_ci      return NULL;
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_ci   mgr->base.destroy = pb_slab_manager_destroy;
460bf215546Sopenharmony_ci   mgr->base.create_buffer = pb_slab_manager_create_buffer;
461bf215546Sopenharmony_ci   mgr->base.flush = pb_slab_manager_flush;
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_ci   mgr->provider = provider;
464bf215546Sopenharmony_ci   mgr->bufSize = bufSize;
465bf215546Sopenharmony_ci   mgr->slabSize = slabSize;
466bf215546Sopenharmony_ci   mgr->desc = *desc;
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   list_inithead(&mgr->slabs);
469bf215546Sopenharmony_ci
470bf215546Sopenharmony_ci   (void) mtx_init(&mgr->mutex, mtx_plain);
471bf215546Sopenharmony_ci
472bf215546Sopenharmony_ci   return &mgr->base;
473bf215546Sopenharmony_ci}
474bf215546Sopenharmony_ci
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_cistatic struct pb_buffer *
477bf215546Sopenharmony_cipb_slab_range_manager_create_buffer(struct pb_manager *_mgr,
478bf215546Sopenharmony_ci                                    pb_size size,
479bf215546Sopenharmony_ci                                    const struct pb_desc *desc)
480bf215546Sopenharmony_ci{
481bf215546Sopenharmony_ci   struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
482bf215546Sopenharmony_ci   pb_size bufSize;
483bf215546Sopenharmony_ci   pb_size reqSize = size;
484bf215546Sopenharmony_ci   enum pb_usage_flags i;
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_ci   if(desc->alignment > reqSize)
487bf215546Sopenharmony_ci	   reqSize = desc->alignment;
488bf215546Sopenharmony_ci
489bf215546Sopenharmony_ci   bufSize = mgr->minBufSize;
490bf215546Sopenharmony_ci   for (i = 0; i < mgr->numBuckets; ++i) {
491bf215546Sopenharmony_ci      if(bufSize >= reqSize)
492bf215546Sopenharmony_ci	 return mgr->buckets[i]->create_buffer(mgr->buckets[i], size, desc);
493bf215546Sopenharmony_ci      bufSize *= 2;
494bf215546Sopenharmony_ci   }
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci   /* Fall back to allocate a buffer object directly from the provider. */
497bf215546Sopenharmony_ci   return mgr->provider->create_buffer(mgr->provider, size, desc);
498bf215546Sopenharmony_ci}
499bf215546Sopenharmony_ci
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_cistatic void
502bf215546Sopenharmony_cipb_slab_range_manager_flush(struct pb_manager *_mgr)
503bf215546Sopenharmony_ci{
504bf215546Sopenharmony_ci   struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci   /* Individual slabs don't hold any temporary buffers so no need to call them */
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci   assert(mgr->provider->flush);
509bf215546Sopenharmony_ci   if(mgr->provider->flush)
510bf215546Sopenharmony_ci      mgr->provider->flush(mgr->provider);
511bf215546Sopenharmony_ci}
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci
514bf215546Sopenharmony_cistatic void
515bf215546Sopenharmony_cipb_slab_range_manager_destroy(struct pb_manager *_mgr)
516bf215546Sopenharmony_ci{
517bf215546Sopenharmony_ci   struct pb_slab_range_manager *mgr = pb_slab_range_manager(_mgr);
518bf215546Sopenharmony_ci   unsigned i;
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci   for (i = 0; i < mgr->numBuckets; ++i)
521bf215546Sopenharmony_ci      mgr->buckets[i]->destroy(mgr->buckets[i]);
522bf215546Sopenharmony_ci   FREE(mgr->buckets);
523bf215546Sopenharmony_ci   FREE(mgr->bucketSizes);
524bf215546Sopenharmony_ci   FREE(mgr);
525bf215546Sopenharmony_ci}
526bf215546Sopenharmony_ci
527bf215546Sopenharmony_ci
528bf215546Sopenharmony_cistruct pb_manager *
529bf215546Sopenharmony_cipb_slab_range_manager_create(struct pb_manager *provider,
530bf215546Sopenharmony_ci                             pb_size minBufSize,
531bf215546Sopenharmony_ci                             pb_size maxBufSize,
532bf215546Sopenharmony_ci                             pb_size slabSize,
533bf215546Sopenharmony_ci                             const struct pb_desc *desc)
534bf215546Sopenharmony_ci{
535bf215546Sopenharmony_ci   struct pb_slab_range_manager *mgr;
536bf215546Sopenharmony_ci   pb_size bufSize;
537bf215546Sopenharmony_ci   unsigned i;
538bf215546Sopenharmony_ci
539bf215546Sopenharmony_ci   if (!provider)
540bf215546Sopenharmony_ci      return NULL;
541bf215546Sopenharmony_ci
542bf215546Sopenharmony_ci   mgr = CALLOC_STRUCT(pb_slab_range_manager);
543bf215546Sopenharmony_ci   if (!mgr)
544bf215546Sopenharmony_ci      goto out_err0;
545bf215546Sopenharmony_ci
546bf215546Sopenharmony_ci   mgr->base.destroy = pb_slab_range_manager_destroy;
547bf215546Sopenharmony_ci   mgr->base.create_buffer = pb_slab_range_manager_create_buffer;
548bf215546Sopenharmony_ci   mgr->base.flush = pb_slab_range_manager_flush;
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci   mgr->provider = provider;
551bf215546Sopenharmony_ci   mgr->minBufSize = minBufSize;
552bf215546Sopenharmony_ci   mgr->maxBufSize = maxBufSize;
553bf215546Sopenharmony_ci
554bf215546Sopenharmony_ci   mgr->numBuckets = 1;
555bf215546Sopenharmony_ci   bufSize = minBufSize;
556bf215546Sopenharmony_ci   while(bufSize < maxBufSize) {
557bf215546Sopenharmony_ci      bufSize *= 2;
558bf215546Sopenharmony_ci      ++mgr->numBuckets;
559bf215546Sopenharmony_ci   }
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci   mgr->buckets = CALLOC(mgr->numBuckets, sizeof(*mgr->buckets));
562bf215546Sopenharmony_ci   if (!mgr->buckets)
563bf215546Sopenharmony_ci      goto out_err1;
564bf215546Sopenharmony_ci
565bf215546Sopenharmony_ci   bufSize = minBufSize;
566bf215546Sopenharmony_ci   for (i = 0; i < mgr->numBuckets; ++i) {
567bf215546Sopenharmony_ci      mgr->buckets[i] = pb_slab_manager_create(provider, bufSize, slabSize, desc);
568bf215546Sopenharmony_ci      if(!mgr->buckets[i])
569bf215546Sopenharmony_ci	 goto out_err2;
570bf215546Sopenharmony_ci      bufSize *= 2;
571bf215546Sopenharmony_ci   }
572bf215546Sopenharmony_ci
573bf215546Sopenharmony_ci   return &mgr->base;
574bf215546Sopenharmony_ci
575bf215546Sopenharmony_ciout_err2:
576bf215546Sopenharmony_ci   for (i = 0; i < mgr->numBuckets; ++i)
577bf215546Sopenharmony_ci      if(mgr->buckets[i])
578bf215546Sopenharmony_ci	    mgr->buckets[i]->destroy(mgr->buckets[i]);
579bf215546Sopenharmony_ci   FREE(mgr->buckets);
580bf215546Sopenharmony_ciout_err1:
581bf215546Sopenharmony_ci   FREE(mgr);
582bf215546Sopenharmony_ciout_err0:
583bf215546Sopenharmony_ci   return NULL;
584bf215546Sopenharmony_ci}
585