xref: /rockchip-linux_mpp/osal/mpp_allocator.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3  * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4  */
5 
6 #define MODULE_TAG "mpp_allocator"
7 
8 #include "mpp_mem.h"
9 #include "mpp_debug.h"
10 #include "mpp_common.h"
11 #include "mpp_runtime.h"
12 #include "mpp_thread.h"
13 #include "mpp_allocator.h"
14 
15 #include "allocator_std.h"
16 #include "allocator_ion.h"
17 #include "allocator_drm.h"
18 #include "allocator_ext_dma.h"
19 #include "allocator_dma_heap.h"
20 
21 #include <linux/drm.h>
22 
23 #define MPP_ALLOCATOR_LOCK(p)   pthread_mutex_lock(&(p)->lock);
24 #define MPP_ALLOCATOR_UNLOCK(p) pthread_mutex_unlock(&(p)->lock);
25 
26 typedef enum OsAllocatorApiId_e {
27     ALLOC_API_ALLOC,
28     ALLOC_API_FREE,
29     ALLOC_API_IMPORT,
30     ALLOC_API_RELEASE,
31     ALLOC_API_MMAP,
32     ALLOC_API_BUTT,
33 } OsAllocatorApiId;
34 
35 typedef struct MppAllocatorImpl_t {
36     pthread_mutex_t     lock;
37     MppBufferType       type;
38     MppAllocFlagType    flags;
39     size_t              alignment;
40     os_allocator        os_api;
41     void                *ctx;
42 } MppAllocatorImpl;
43 
mpp_allocator_api_wrapper(MppAllocator allocator,MppBufferInfo * info,OsAllocatorApiId id)44 static MPP_RET mpp_allocator_api_wrapper(MppAllocator allocator,
45                                          MppBufferInfo *info,
46                                          OsAllocatorApiId id)
47 {
48     MppAllocatorImpl *p = (MppAllocatorImpl *)allocator;
49     OsAllocatorFunc func;
50     MPP_RET ret = MPP_NOK;
51 
52     if (!p || !info || id >= ALLOC_API_BUTT) {
53         mpp_err_f("invalid input: allocator %p info %p id %d\n",
54                   allocator, info, id);
55         return MPP_ERR_UNKNOW;
56     }
57 
58     MPP_ALLOCATOR_LOCK(p);
59     switch (id) {
60     case ALLOC_API_ALLOC : {
61         func = p->os_api.alloc;
62     } break;
63     case ALLOC_API_FREE : {
64         func = p->os_api.free;
65     } break;
66     case ALLOC_API_IMPORT : {
67         func = p->os_api.import;
68     } break;
69     case ALLOC_API_RELEASE : {
70         func = p->os_api.release;
71     } break;
72     case ALLOC_API_MMAP : {
73         func = p->os_api.mmap;
74     } break;
75     default : {
76         func = NULL;
77     } break;
78     }
79 
80     if (func && p->ctx)
81         ret = func(p->ctx, info);
82 
83     MPP_ALLOCATOR_UNLOCK(p);
84 
85     return ret;
86 }
87 
mpp_allocator_alloc(MppAllocator allocator,MppBufferInfo * info)88 static MPP_RET mpp_allocator_alloc(MppAllocator allocator, MppBufferInfo *info)
89 {
90     return mpp_allocator_api_wrapper(allocator, info, ALLOC_API_ALLOC);
91 }
92 
mpp_allocator_free(MppAllocator allocator,MppBufferInfo * info)93 static MPP_RET mpp_allocator_free(MppAllocator allocator, MppBufferInfo *info)
94 {
95     return mpp_allocator_api_wrapper(allocator, info, ALLOC_API_FREE);
96 }
97 
mpp_allocator_import(MppAllocator allocator,MppBufferInfo * info)98 static MPP_RET mpp_allocator_import(MppAllocator allocator, MppBufferInfo *info)
99 {
100     return mpp_allocator_api_wrapper(allocator, info, ALLOC_API_IMPORT);
101 }
102 
mpp_allocator_release(MppAllocator allocator,MppBufferInfo * info)103 static MPP_RET mpp_allocator_release(MppAllocator allocator,
104                                      MppBufferInfo *info)
105 {
106     return mpp_allocator_api_wrapper(allocator, info, ALLOC_API_RELEASE);
107 }
108 
mpp_allocator_mmap(MppAllocator allocator,MppBufferInfo * info)109 static MPP_RET mpp_allocator_mmap(MppAllocator allocator, MppBufferInfo *info)
110 {
111     return mpp_allocator_api_wrapper(allocator, info, ALLOC_API_MMAP);
112 }
113 
114 static MppAllocatorApi mpp_allocator_api = {
115     .size = sizeof(mpp_allocator_api),
116     .version = 1,
117     .alloc = mpp_allocator_alloc,
118     .free = mpp_allocator_free,
119     .import = mpp_allocator_import,
120     .release =  mpp_allocator_release,
121     .mmap  = mpp_allocator_mmap,
122 };
123 
mpp_allocator_get(MppAllocator * allocator,MppAllocatorApi ** api,MppBufferType type,MppAllocFlagType flags)124 MPP_RET mpp_allocator_get(MppAllocator *allocator, MppAllocatorApi **api,
125                           MppBufferType type, MppAllocFlagType flags)
126 {
127     MppBufferType buffer_type = (MppBufferType)(type & MPP_BUFFER_TYPE_MASK);
128     MppAllocatorImpl *p = NULL;
129 
130     do {
131         if (!allocator || !api || buffer_type >= MPP_BUFFER_TYPE_BUTT) {
132             mpp_err_f("invalid input: allocator %p api %p type %d\n",
133                       allocator, api, buffer_type);
134             break;
135         }
136 
137         p = mpp_malloc(MppAllocatorImpl, 1);
138         if (!p) {
139             mpp_err_f("failed to malloc allocator context\n");
140             break;
141         }
142 
143         p->type = buffer_type;
144         p->flags = flags;
145 
146         switch (buffer_type) {
147         case MPP_BUFFER_TYPE_NORMAL : {
148             p->os_api = allocator_std;
149         } break;
150         case MPP_BUFFER_TYPE_ION : {
151             p->os_api = (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DMA_HEAP)) ? allocator_dma_heap :
152                         (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_ION)) ? allocator_ion :
153                         (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DRM)) ? allocator_drm :
154                         allocator_std;
155         } break;
156         case MPP_BUFFER_TYPE_EXT_DMA: {
157             p->os_api = allocator_ext_dma;
158         } break;
159         case MPP_BUFFER_TYPE_DRM : {
160             p->os_api = (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DMA_HEAP)) ? allocator_dma_heap :
161                         (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DRM)) ? allocator_drm :
162                         (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_ION)) ? allocator_ion :
163                         allocator_std;
164         } break;
165         case MPP_BUFFER_TYPE_DMA_HEAP: {
166             p->os_api = (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DMA_HEAP)) ? allocator_dma_heap :
167                         (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DRM)) ? allocator_drm :
168                         (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_ION)) ? allocator_ion :
169                         allocator_std;
170         } break;
171         default : {
172         } break;
173         }
174 
175         if (p->os_api.open(&p->ctx, SZ_4K, flags))
176             break;
177 
178         /* update the real buffer type and flags */
179         p->type = p->os_api.type;
180         if (p->os_api.flags)
181             p->flags = p->os_api.flags(p->ctx);
182 
183         {
184             pthread_mutexattr_t attr;
185 
186             pthread_mutexattr_init(&attr);
187             pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
188             pthread_mutex_init(&p->lock, &attr);
189             pthread_mutexattr_destroy(&attr);
190         }
191 
192         *allocator = p;
193         *api = &mpp_allocator_api;
194 
195         return MPP_OK;
196     } while (0);
197 
198     MPP_FREE(p);
199     *allocator  = NULL;
200     *api        = NULL;
201 
202     return MPP_NOK;
203 }
204 
mpp_allocator_put(MppAllocator * allocator)205 MPP_RET mpp_allocator_put(MppAllocator *allocator)
206 {
207     MppAllocatorImpl *p = (MppAllocatorImpl *)*allocator;
208 
209     if (!p) {
210         mpp_err_f("invalid input: allocator %p\n", allocator);
211         return MPP_ERR_NULL_PTR;
212     }
213 
214     if (!p)
215         return MPP_OK;
216     *allocator = NULL;
217 
218     if (p->os_api.close && p->ctx)
219         p->os_api.close(p->ctx);
220     pthread_mutex_destroy(&p->lock);
221     mpp_free(p);
222 
223     return MPP_OK;
224 }
225 
mpp_allocator_get_flags(const MppAllocator allocator)226 MppAllocFlagType mpp_allocator_get_flags(const MppAllocator allocator)
227 {
228     MppAllocatorImpl *p = (MppAllocatorImpl *)allocator;
229 
230     return p ? p->flags : MPP_ALLOC_FLAG_NONE;
231 }
232