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,57 @@ 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 int fast_get_access_grant (k_tid_t thread , void * addr , size_t size )
107+ {
108+ struct k_mem_partition part = {
109+ .start = (uintptr_t )addr ,
110+ .size = ALIGN_UP (size , CONFIG_MM_DRV_PAGE_SIZE ),
111+ .attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB ,
112+ };
113+
114+ LOG_DBG ("add %#zx @ %p" , part .size , addr );
115+ return k_mem_domain_add_partition (thread -> mem_domain_info .mem_domain , & part );
116+ }
117+ #endif /* CONFIG_USERSPACE */
118+
93119const void * fast_get (struct k_heap * heap , const void * dram_ptr , size_t size )
94120{
95121 struct sof_fast_get_data * data = & fast_get_data ;
122+ uint32_t alloc_flags = SOF_MEM_FLAG_USER ;
96123 struct sof_fast_get_entry * entry ;
124+ size_t alloc_size , alloc_align ;
125+ const void * alloc_ptr ;
97126 k_spinlock_key_t key ;
98127 void * ret ;
99128
100129 key = k_spin_lock (& data -> lock );
130+ if (IS_ENABLED (CONFIG_USERSPACE ) && size > FAST_GET_MAX_COPY_SIZE ) {
131+ alloc_size = ALIGN_UP (size , PAGE_SZ );
132+ alloc_align = PAGE_SZ ;
133+ alloc_flags |= SOF_MEM_FLAG_LARGE_BUFFER ;
134+ } else {
135+ alloc_size = size ;
136+ alloc_align = PLATFORM_DCACHE_ALIGN ;
137+ }
138+
139+ if (size > FAST_GET_MAX_COPY_SIZE || !IS_ENABLED (CONFIG_USERSPACE ))
140+ alloc_ptr = dram_ptr ;
141+ else
142+ /* When userspace is enabled only share large buffers */
143+ alloc_ptr = NULL ;
144+
101145 do {
102- entry = fast_get_find_entry (data , dram_ptr );
146+ entry = fast_get_find_entry (data , alloc_ptr );
103147 if (!entry ) {
104148 if (fast_get_realloc (data )) {
105149 ret = NULL ;
@@ -108,6 +152,12 @@ const void *fast_get(struct k_heap *heap, const void *dram_ptr, size_t size)
108152 }
109153 } while (!entry );
110154
155+ #if CONFIG_USERSPACE
156+ LOG_DBG ("userspace %u part %#zx bytes alloc %p entry %p DRAM %p" ,
157+ k_current_get ()-> mem_domain_info .mem_domain -> num_partitions , size ,
158+ alloc_ptr , entry -> sram_ptr , dram_ptr );
159+ #endif
160+
111161 if (entry -> sram_ptr ) {
112162 if (entry -> size != size || entry -> dram_ptr != dram_ptr ) {
113163 LOG_ERR ("size %u != %u or ptr %p != %p mismatch" ,
@@ -116,6 +166,24 @@ const void *fast_get(struct k_heap *heap, const void *dram_ptr, size_t size)
116166 goto out ;
117167 }
118168
169+ #if CONFIG_USERSPACE
170+ /* We only get there for large buffers */
171+ if (k_current_get ()-> mem_domain_info .mem_domain -> num_partitions > 1 ) {
172+ /* A userspace thread makes the request */
173+ if (k_current_get () != entry -> thread ) {
174+ int err = fast_get_access_grant (k_current_get (),
175+ entry -> sram_ptr , size );
176+
177+ if (err < 0 ) {
178+ ret = NULL ;
179+ goto out ;
180+ }
181+ } else {
182+ LOG_WRN ("Repeated access request by thread" );
183+ }
184+ }
185+ #endif
186+
119187 ret = entry -> sram_ptr ;
120188 entry -> refcount ++ ;
121189 /*
@@ -126,13 +194,33 @@ const void *fast_get(struct k_heap *heap, const void *dram_ptr, size_t size)
126194 goto out ;
127195 }
128196
129- ret = sof_heap_alloc (heap , SOF_MEM_FLAG_USER , size , PLATFORM_DCACHE_ALIGN );
197+ /*
198+ * If a userspace threads is the first user to fast-get the buffer, an
199+ * SRAM copy will be allocated on its own heap, so it will have access
200+ * to it
201+ */
202+ ret = sof_heap_alloc (heap , alloc_flags , alloc_size , alloc_align );
130203 if (!ret )
131204 goto out ;
132205 entry -> size = size ;
133206 entry -> sram_ptr = ret ;
134207 memcpy_s (entry -> sram_ptr , entry -> size , dram_ptr , size );
135208 dcache_writeback_region ((__sparse_force void __sparse_cache * )entry -> sram_ptr , size );
209+
210+ #if CONFIG_USERSPACE
211+ entry -> thread = k_current_get ();
212+ if (size > FAST_GET_MAX_COPY_SIZE ) {
213+ /* Otherwise we've allocated on thread's heap, so it already has access */
214+ int err = fast_get_access_grant (entry -> thread , ret , size );
215+
216+ if (err < 0 ) {
217+ sof_heap_free (NULL , ret );
218+ ret = NULL ;
219+ goto out ;
220+ }
221+ }
222+ #endif /* CONFIG_USERSPACE */
223+
136224 entry -> dram_ptr = dram_ptr ;
137225 entry -> refcount = 1 ;
138226out :
@@ -169,6 +257,22 @@ void fast_put(struct k_heap *heap, const void *sram_ptr)
169257 goto out ;
170258 }
171259 entry -> refcount -- ;
260+
261+ #if CONFIG_USERSPACE
262+ if (entry -> size > FAST_GET_MAX_COPY_SIZE &&
263+ k_current_get ()-> mem_domain_info .mem_domain -> num_partitions > 1 ) {
264+ struct k_mem_partition part = {
265+ .start = (uintptr_t )entry -> sram_ptr ,
266+ .size = ALIGN_UP (entry -> size , CONFIG_MM_DRV_PAGE_SIZE ),
267+ .attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB ,
268+ };
269+
270+ LOG_DBG ("remove %#zx @ %p" , part .size , entry -> sram_ptr );
271+ k_mem_domain_remove_partition (k_current_get ()-> mem_domain_info .mem_domain ,
272+ & part );
273+ }
274+ #endif
275+
172276 if (!entry -> refcount ) {
173277 sof_heap_free (heap , entry -> sram_ptr );
174278 memset (entry , 0 , sizeof (* entry ));
0 commit comments