Skip to content

Commit 6dd7ba2

Browse files
committed
fast-get: enable sharing between userspace threads
If a module fast-gets memory for a specific its instance, running in userspace and then another usuerspace instance wants to share it, access has to be granted to that object by that thread too. This patch does that while also restricting object sharing to "large" objects (currently larger than half a page), and smaller objects are just copied. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
1 parent 987c80b commit 6dd7ba2

2 files changed

Lines changed: 107 additions & 3 deletions

File tree

src/audio/module_adapter/module_adapter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv,
5353
#if CONFIG_MM_DRV
5454
#define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE
5555
#else
56-
#include <platform/platform.h>
56+
#include <sof/platform.h>
5757
#define PAGE_SZ HOST_PAGE_SIZE
5858
#endif
5959

zephyr/lib/fast-get.c

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
struct 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+
93119
const 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;
138226
out:
@@ -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

Comments
 (0)