1 /*
2  * Copyright 2016 Advanced Micro Devices, Inc.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sub license, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portions
15  * of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
21  * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  */
27 
28 /**
29  * \file
30  *
31  * Helper library for carving out smaller allocations (called "(slab) entries")
32  * from larger buffers (called "slabs").
33  *
34  * The library supports maintaining separate heaps (e.g. VRAM vs. GTT). The
35  * meaning of each heap is treated as opaque by this library.
36  *
37  * The library allows delaying the re-use of an entry, i.e. an entry may be
38  * freed by calling \ref pb_slab_free even while the corresponding buffer
39  * region is still in use by the GPU. A callback function is called to
40  * determine when it is safe to allocate the entry again; the user of this
41  * library is expected to maintain the required fences or similar.
42  */
43 
44 #ifndef PB_SLAB_H
45 #define PB_SLAB_H
46 
47 #include "pb_buffer.h"
48 #include "util/simple_mtx.h"
49 #include "util/list.h"
50 #include "os/os_thread.h"
51 
52 struct pb_slab;
53 struct pb_slabs;
54 struct pb_slab_group;
55 
56 /* Descriptor of a slab entry.
57  *
58  * The user of this utility library is expected to embed this in a larger
59  * structure that describes a buffer object.
60  */
61 struct pb_slab_entry
62 {
63    struct list_head head;
64    struct pb_slab *slab; /* the slab that contains this buffer */
65    unsigned group_index; /* index into pb_slabs::groups */
66    unsigned entry_size;
67 };
68 
69 /* Descriptor of a slab from which many entries are carved out.
70  *
71  * The user of this utility library is expected to embed this in a larger
72  * structure that describes a buffer object.
73  */
74 struct pb_slab
75 {
76    struct list_head head;
77 
78    struct list_head free; /* list of free pb_slab_entry structures */
79    unsigned num_free; /* number of entries in free list */
80    unsigned num_entries; /* total number of entries */
81 };
82 
83 /* Callback function that is called when a new slab needs to be allocated
84  * for fulfilling allocation requests of the given size from the given heap.
85  *
86  * The callback must allocate a pb_slab structure and the desired number
87  * of entries. All entries that belong to the slab must be added to the free
88  * list. Entries' pb_slab_entry structures must be initialized with the given
89  * group_index.
90  *
91  * The callback may call pb_slab functions.
92  */
93 typedef struct pb_slab *(slab_alloc_fn)(void *priv,
94                                         unsigned heap,
95                                         unsigned entry_size,
96                                         unsigned group_index);
97 
98 /* Callback function that is called when all entries of a slab have been freed.
99  *
100  * The callback must free the slab and all its entries. It must not call any of
101  * the pb_slab functions, or a deadlock (recursive mutex lock) may occur.
102  */
103 typedef void (slab_free_fn)(void *priv, struct pb_slab *);
104 
105 /* Callback function to determine whether a given entry can already be reused.
106  */
107 typedef bool (slab_can_reclaim_fn)(void *priv, struct pb_slab_entry *);
108 
109 /* Manager of slab allocations. The user of this utility library should embed
110  * this in a structure somewhere and call pb_slab_init/deinit at init/shutdown
111  * time.
112  */
113 struct pb_slabs
114 {
115    simple_mtx_t mutex;
116 
117    unsigned min_order;
118    unsigned num_orders;
119    unsigned num_heaps;
120    bool allow_three_fourths_allocations;
121 
122    /* One group per (heap, order, three_fourth_allocations). */
123    struct pb_slab_group *groups;
124 
125    /* List of entries waiting to be reclaimed, i.e. they have been passed to
126     * pb_slab_free, but may not be safe for re-use yet. The tail points at
127     * the most-recently freed entry.
128     */
129    struct list_head reclaim;
130 
131    void *priv;
132    slab_can_reclaim_fn *can_reclaim;
133    slab_alloc_fn *slab_alloc;
134    slab_free_fn *slab_free;
135 };
136 
137 struct pb_slab_entry *
138 pb_slab_alloc_reclaimed(struct pb_slabs *slabs, unsigned size, unsigned heap, bool reclaim_all);
139 
140 struct pb_slab_entry *
141 pb_slab_alloc(struct pb_slabs *slabs, unsigned size, unsigned heap);
142 
143 void
144 pb_slab_free(struct pb_slabs* slabs, struct pb_slab_entry *entry);
145 
146 void
147 pb_slabs_reclaim(struct pb_slabs *slabs);
148 
149 bool
150 pb_slabs_init(struct pb_slabs *slabs,
151               unsigned min_order, unsigned max_order,
152               unsigned num_heaps, bool allow_three_fourth_allocations,
153               void *priv,
154               slab_can_reclaim_fn *can_reclaim,
155               slab_alloc_fn *slab_alloc,
156               slab_free_fn *slab_free);
157 
158 void
159 pb_slabs_deinit(struct pb_slabs *slabs);
160 
161 #endif
162