2828struct sof_fast_get_entry {
2929 const void * dram_ptr ;
3030 void * sram_ptr ;
31+ #if CONFIG_USERSPACE
32+ struct k_thread * thread ;
33+ #endif
3134 size_t size ;
3235 unsigned int refcount ;
3336};
@@ -90,16 +93,71 @@ static struct sof_fast_get_entry *fast_get_find_entry(struct sof_fast_get_data *
9093 return NULL ;
9194}
9295
96+ #if CONFIG_MM_DRV
97+ #define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE
98+ #define FAST_GET_MAX_COPY_SIZE (PAGE_SZ / 2)
99+ #else
100+ #include <sof/platform.h>
101+ #define PAGE_SZ HOST_PAGE_SIZE
102+ #define FAST_GET_MAX_COPY_SIZE 0
103+ #endif
104+
105+ #if CONFIG_USERSPACE
106+ static bool fast_get_domain_exists (struct k_thread * thread , void * start , size_t size )
107+ {
108+ struct k_mem_domain * domain = thread -> mem_domain_info .mem_domain ;
109+
110+ for (unsigned int i = 0 ; i < domain -> num_partitions ; i ++ ) {
111+ struct k_mem_partition * dpart = & domain -> partitions [i ];
112+
113+ if (dpart -> start == (uintptr_t )start && dpart -> size == size )
114+ return true;
115+ }
116+
117+ return false;
118+ }
119+
120+ static int fast_get_access_grant (k_tid_t thread , void * addr , size_t size )
121+ {
122+ struct k_mem_partition part = {
123+ .start = (uintptr_t )addr ,
124+ .size = ALIGN_UP (size , CONFIG_MM_DRV_PAGE_SIZE ),
125+ .attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB ,
126+ };
127+
128+ LOG_DBG ("add %#zx @ %p" , part .size , addr );
129+ return k_mem_domain_add_partition (thread -> mem_domain_info .mem_domain , & part );
130+ }
131+ #endif /* CONFIG_USERSPACE */
132+
93133const void * fast_get (struct k_heap * heap , const void * dram_ptr , size_t size )
94134{
95135 struct sof_fast_get_data * data = & fast_get_data ;
136+ uint32_t alloc_flags = SOF_MEM_FLAG_USER ;
96137 struct sof_fast_get_entry * entry ;
138+ size_t alloc_size , alloc_align ;
139+ const void * alloc_ptr ;
97140 k_spinlock_key_t key ;
98141 void * ret ;
99142
100143 key = k_spin_lock (& data -> lock );
144+ if (IS_ENABLED (CONFIG_USERSPACE ) && size > FAST_GET_MAX_COPY_SIZE ) {
145+ alloc_size = ALIGN_UP (size , PAGE_SZ );
146+ alloc_align = PAGE_SZ ;
147+ alloc_flags |= SOF_MEM_FLAG_LARGE_BUFFER ;
148+ } else {
149+ alloc_size = size ;
150+ alloc_align = PLATFORM_DCACHE_ALIGN ;
151+ }
152+
153+ if (size > FAST_GET_MAX_COPY_SIZE || !IS_ENABLED (CONFIG_USERSPACE ))
154+ alloc_ptr = dram_ptr ;
155+ else
156+ /* When userspace is enabled only share large buffers */
157+ alloc_ptr = NULL ;
158+
101159 do {
102- entry = fast_get_find_entry (data , dram_ptr );
160+ entry = fast_get_find_entry (data , alloc_ptr );
103161 if (!entry ) {
104162 if (fast_get_realloc (data )) {
105163 ret = NULL ;
@@ -108,6 +166,12 @@ const void *fast_get(struct k_heap *heap, const void *dram_ptr, size_t size)
108166 }
109167 } while (!entry );
110168
169+ #if CONFIG_USERSPACE
170+ LOG_DBG ("userspace %u part %#zx bytes alloc %p entry %p DRAM %p" ,
171+ k_current_get ()-> mem_domain_info .mem_domain -> num_partitions , size ,
172+ alloc_ptr , entry -> sram_ptr , dram_ptr );
173+ #endif
174+
111175 if (entry -> sram_ptr ) {
112176 if (entry -> size != size || entry -> dram_ptr != dram_ptr ) {
113177 LOG_ERR ("size %u != %u or ptr %p != %p mismatch" ,
@@ -117,22 +181,65 @@ const void *fast_get(struct k_heap *heap, const void *dram_ptr, size_t size)
117181 }
118182
119183 ret = entry -> sram_ptr ;
184+
185+ #if CONFIG_USERSPACE
186+ /* We only get there for large buffers */
187+ if (k_current_get ()-> mem_domain_info .mem_domain -> num_partitions > 1 ) {
188+ /* A userspace thread makes the request */
189+ if (k_current_get () != entry -> thread &&
190+ !fast_get_domain_exists (k_current_get (), ret ,
191+ ALIGN_UP (size , CONFIG_MM_DRV_PAGE_SIZE ))) {
192+ LOG_DBG ("grant access to thread %p first was %p" , k_current_get (),
193+ entry -> thread );
194+ int err = fast_get_access_grant (k_current_get (), ret , size );
195+
196+ if (err < 0 ) {
197+ ret = NULL ;
198+ goto out ;
199+ }
200+ /*
201+ * The data is constant, so it's safe to use cached access to
202+ * it, but initially we have to invalidate caches
203+ */
204+ dcache_invalidate_region ((__sparse_force void __sparse_cache * )ret ,
205+ size );
206+ } else {
207+ LOG_WRN ("Repeated access request by thread" );
208+ }
209+ }
210+ #endif
211+
120212 entry -> refcount ++ ;
121- /*
122- * The data is constant, so it's safe to use cached access to
123- * it, but initially we have to invalidate cached
124- */
125- dcache_invalidate_region ((__sparse_force void __sparse_cache * )ret , size );
126213 goto out ;
127214 }
128215
129- ret = sof_heap_alloc (heap , SOF_MEM_FLAG_USER , size , PLATFORM_DCACHE_ALIGN );
216+ /*
217+ * If a userspace threads is the first user to fast-get the buffer, an
218+ * SRAM copy will be allocated on its own heap, so it will have access
219+ * to it
220+ */
221+ ret = sof_heap_alloc (heap , alloc_flags , alloc_size , alloc_align );
130222 if (!ret )
131223 goto out ;
132224 entry -> size = size ;
133225 entry -> sram_ptr = ret ;
134226 memcpy_s (entry -> sram_ptr , entry -> size , dram_ptr , size );
135227 dcache_writeback_region ((__sparse_force void __sparse_cache * )entry -> sram_ptr , size );
228+
229+ #if CONFIG_USERSPACE
230+ entry -> thread = k_current_get ();
231+ if (size > FAST_GET_MAX_COPY_SIZE ) {
232+ /* Otherwise we've allocated on thread's heap, so it already has access */
233+ int err = fast_get_access_grant (entry -> thread , ret , size );
234+
235+ if (err < 0 ) {
236+ sof_heap_free (NULL , ret );
237+ ret = NULL ;
238+ goto out ;
239+ }
240+ }
241+ #endif /* CONFIG_USERSPACE */
242+
136243 entry -> dram_ptr = dram_ptr ;
137244 entry -> refcount = 1 ;
138245out :
@@ -169,6 +276,20 @@ void fast_put(struct k_heap *heap, const void *sram_ptr)
169276 goto out ;
170277 }
171278 entry -> refcount -- ;
279+
280+ #if CONFIG_USERSPACE
281+ if (entry -> size > FAST_GET_MAX_COPY_SIZE && entry -> thread ) {
282+ struct k_mem_partition part = {
283+ .start = (uintptr_t )entry -> sram_ptr ,
284+ .size = ALIGN_UP (entry -> size , CONFIG_MM_DRV_PAGE_SIZE ),
285+ .attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB ,
286+ };
287+
288+ LOG_DBG ("remove %#zx @ %p" , part .size , entry -> sram_ptr );
289+ k_mem_domain_remove_partition (entry -> thread -> mem_domain_info .mem_domain , & part );
290+ }
291+ #endif
292+
172293 if (!entry -> refcount ) {
173294 sof_heap_free (heap , entry -> sram_ptr );
174295 memset (entry , 0 , sizeof (* entry ));
0 commit comments