Skip to content

Commit b927092

Browse files
lyakhlgirdwood
authored andcommitted
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 4e1c64b commit b927092

2 files changed

Lines changed: 129 additions & 8 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: 128 additions & 7 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,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+
93133
const 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;
138245
out:
@@ -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

Comments
 (0)