Skip to content

Commit ab93282

Browse files
committed
userspace: application: move to vregion
Modules, running in userspace while using the "application" DP implementation, are moved to vregion for all their private allocations. This has the advantage of not depending on build-time configured VMH buffers and of faster lifetime allocations. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
1 parent 7061f55 commit ab93282

File tree

7 files changed

+111
-56
lines changed

7 files changed

+111
-56
lines changed

src/audio/module_adapter/module/generic.c

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <sof/audio/module_adapter/module/generic.h>
1818
#include <sof/audio/data_blob.h>
1919
#include <sof/lib/fast-get.h>
20+
#include <sof/lib/vregion.h>
2021
#include <sof/schedule/dp_schedule.h>
2122
#if CONFIG_IPC_MAJOR_4
2223
#include <ipc4/header.h>
@@ -87,6 +88,7 @@ void mod_resource_init(struct processing_module *mod)
8788
/* Init memory list */
8889
list_init(&res->objpool.list);
8990
res->objpool.heap = res->alloc.heap;
91+
res->objpool.vreg = res->alloc.vreg;
9092
res->heap_usage = 0;
9193
res->heap_high_water_mark = 0;
9294
}
@@ -158,11 +160,15 @@ void mod_heap_info(struct processing_module *mod, size_t *size, uintptr_t *start
158160
{
159161
struct module_resources *res = &mod->priv.resources;
160162

161-
if (size)
162-
*size = res->alloc.heap->heap.init_bytes;
163+
if (res->alloc.vreg) {
164+
vregion_mem_info(res->alloc.vreg, size, start);
165+
} else if (res->alloc.heap) {
166+
if (size)
167+
*size = res->alloc.heap->heap.init_bytes;
163168

164-
if (start)
165-
*start = (uintptr_t)res->alloc.heap;
169+
if (start)
170+
*start = (uintptr_t)res->alloc.heap->heap.init_mem;
171+
}
166172
}
167173
#endif
168174

@@ -246,7 +252,14 @@ void *z_impl_mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t
246252
}
247253

248254
/* Allocate memory for module */
249-
void *ptr = sof_heap_alloc(res->alloc.heap, flags, size, alignment);
255+
void *ptr;
256+
257+
if (!res->alloc.vreg)
258+
ptr = sof_heap_alloc(res->alloc.heap, flags, size, alignment);
259+
else if (flags & SOF_MEM_FLAG_COHERENT)
260+
ptr = vregion_alloc_coherent_align(res->alloc.vreg, VREGION_MEM_TYPE_INTERIM, size, alignment);
261+
else
262+
ptr = vregion_alloc_align(res->alloc.vreg, VREGION_MEM_TYPE_INTERIM, size, alignment);
250263

251264
if (!ptr) {
252265
comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.",
@@ -347,7 +360,10 @@ static int free_contents(struct processing_module *mod, struct module_resource *
347360

348361
switch (container->type) {
349362
case MOD_RES_HEAP:
350-
sof_heap_free(res->alloc.heap, container->ptr);
363+
if (res->alloc.vreg)
364+
vregion_free(res->alloc.vreg, container->ptr);
365+
else
366+
sof_heap_free(res->alloc.heap, container->ptr);
351367
res->heap_usage -= container->size;
352368
return 0;
353369
#if CONFIG_COMP_BLOB
@@ -426,10 +442,13 @@ EXPORT_SYMBOL(z_impl_mod_free);
426442
const void *z_vrfy_mod_fast_get(struct processing_module *mod, const void * const dram_ptr,
427443
size_t size)
428444
{
429-
struct module_resources *res = &mod->priv.resources;
445+
size_t h_size = 0;
446+
uintptr_t h_start;
430447

431448
K_OOPS(K_SYSCALL_MEMORY_WRITE(mod, sizeof(*mod)));
432-
K_OOPS(K_SYSCALL_MEMORY_WRITE(res->alloc.heap, sizeof(*res->alloc.heap)));
449+
mod_heap_info(mod, &h_size, &h_start);
450+
if (h_size)
451+
K_OOPS(K_SYSCALL_MEMORY_WRITE(h_start, h_size));
433452
K_OOPS(K_SYSCALL_MEMORY_READ(dram_ptr, size));
434453

435454
return z_impl_mod_fast_get(mod, dram_ptr, size);
@@ -440,21 +459,27 @@ const void *z_vrfy_mod_fast_get(struct processing_module *mod, const void * cons
440459
void *z_vrfy_mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size,
441460
size_t alignment)
442461
{
443-
struct module_resources *res = &mod->priv.resources;
462+
size_t h_size = 0;
463+
uintptr_t h_start;
444464

445465
K_OOPS(K_SYSCALL_MEMORY_WRITE(mod, sizeof(*mod)));
446-
K_OOPS(K_SYSCALL_MEMORY_WRITE(res->alloc.heap, sizeof(*res->alloc.heap)));
466+
mod_heap_info(mod, &h_size, &h_start);
467+
if (h_size)
468+
K_OOPS(K_SYSCALL_MEMORY_WRITE(h_start, h_size));
447469

448470
return z_impl_mod_alloc_ext(mod, flags, size, alignment);
449471
}
450472
#include <zephyr/syscalls/mod_alloc_ext_mrsh.c>
451473

452474
int z_vrfy_mod_free(struct processing_module *mod, const void *ptr)
453475
{
454-
struct module_resources *res = &mod->priv.resources;
476+
size_t h_size = 0;
477+
uintptr_t h_start;
455478

456479
K_OOPS(K_SYSCALL_MEMORY_WRITE(mod, sizeof(*mod)));
457-
K_OOPS(K_SYSCALL_MEMORY_WRITE(res->alloc.heap, sizeof(*res->alloc.heap)));
480+
mod_heap_info(mod, &h_size, &h_start);
481+
if (h_size)
482+
K_OOPS(K_SYSCALL_MEMORY_WRITE(h_start, h_size));
458483

459484
return z_impl_mod_free(mod, ptr);
460485
}

src/audio/module_adapter/module_adapter.c

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <sof/audio/source_api.h>
1919
#include <sof/audio/audio_buffer.h>
2020
#include <sof/audio/pipeline.h>
21+
#include <sof/lib/vregion.h>
2122
#include <sof/schedule/dp_schedule.h>
2223
#include <sof/schedule/ll_schedule_domain.h>
2324
#include <sof/common.h>
@@ -57,38 +58,29 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv,
5758
#define PAGE_SZ HOST_PAGE_SIZE
5859
#endif
5960

60-
static struct k_heap *module_adapter_dp_heap_new(const struct comp_ipc_config *config,
61-
size_t *heap_size)
61+
static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *config,
62+
size_t *heap_size)
6263
{
6364
/* src-lite with 8 channels has been seen allocating 14k in one go */
6465
/* FIXME: the size will be derived from configuration */
6566
const size_t buf_size = 20 * 1024;
6667

67-
/* Keep uncached to match the default SOF heap! */
68-
uint8_t *mod_heap_mem = rballoc_align(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT,
69-
buf_size, PAGE_SZ);
70-
71-
if (!mod_heap_mem)
72-
return NULL;
73-
74-
struct k_heap *mod_heap = (struct k_heap *)mod_heap_mem;
75-
const size_t heap_prefix_size = ALIGN_UP(sizeof(*mod_heap), 4);
76-
void *mod_heap_buf = mod_heap_mem + heap_prefix_size;
77-
78-
*heap_size = buf_size - heap_prefix_size;
79-
k_heap_init(mod_heap, mod_heap_buf, *heap_size);
80-
#ifdef __ZEPHYR__
81-
mod_heap->heap.init_mem = mod_heap_buf;
82-
mod_heap->heap.init_bytes = *heap_size;
83-
#endif
84-
85-
return mod_heap;
68+
/*
69+
* A 1-to-1 replacement of the original heap implementation would be to
70+
* have "lifetime size" equal to 0. But (1) this is invalid for
71+
* vregion_create() and (2) we gradually move objects, that are simple
72+
* to move to the lifetime buffer. Make it 1k for the beginning.
73+
*/
74+
return vregion_create(4096, buf_size - 4096);
8675
}
8776

8877
static struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv,
8978
const struct comp_ipc_config *config)
9079
{
9180
struct k_heap *mod_heap;
81+
struct vregion *mod_vreg;
82+
struct processing_module *mod;
83+
struct comp_dev *dev;
9284
/*
9385
* For DP shared modules the struct processing_module object must be
9486
* accessible from all cores. Unfortunately at this point there's no
@@ -102,17 +94,24 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv
10294

10395
if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP && IS_ENABLED(CONFIG_USERSPACE) &&
10496
!IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) {
105-
mod_heap = module_adapter_dp_heap_new(config, &heap_size);
106-
if (!mod_heap) {
107-
comp_cl_err(drv, "Failed to allocate DP module heap");
97+
mod_vreg = module_adapter_dp_heap_new(config, &heap_size);
98+
if (!mod_vreg) {
99+
comp_cl_err(drv, "Failed to allocate DP module heap / vregion");
108100
return NULL;
109101
}
102+
mod_heap = NULL;
110103
} else {
111104
mod_heap = drv->user_heap;
112105
heap_size = 0;
106+
mod_vreg = NULL;
113107
}
114108

115-
struct processing_module *mod = sof_heap_alloc(mod_heap, flags, sizeof(*mod), 0);
109+
if (!mod_vreg)
110+
mod = sof_heap_alloc(mod_heap, flags, sizeof(*mod), 0);
111+
else if (flags & SOF_MEM_FLAG_COHERENT)
112+
mod = vregion_alloc_coherent(mod_vreg, VREGION_MEM_TYPE_LIFETIME, sizeof(*mod));
113+
else
114+
mod = vregion_alloc(mod_vreg, VREGION_MEM_TYPE_LIFETIME, sizeof(*mod));
116115

117116
if (!mod) {
118117
comp_cl_err(drv, "failed to allocate memory for module");
@@ -123,6 +122,7 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv
123122

124123
memset(mod, 0, sizeof(*mod));
125124
alloc->heap = mod_heap;
125+
alloc->vreg = mod_vreg;
126126
mod_resource_init(mod);
127127

128128
/*
@@ -131,7 +131,10 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv
131131
* then it can be cached. Effectively it can be only cached in
132132
* single-core configurations.
133133
*/
134-
struct comp_dev *dev = sof_heap_alloc(mod_heap, SOF_MEM_FLAG_COHERENT, sizeof(*dev), 0);
134+
if (mod_vreg)
135+
dev = vregion_alloc_coherent(mod_vreg, VREGION_MEM_TYPE_LIFETIME, sizeof(*dev));
136+
else
137+
dev = sof_heap_alloc(mod_heap, SOF_MEM_FLAG_COHERENT, sizeof(*dev), 0);
135138

136139
if (!dev) {
137140
comp_cl_err(drv, "failed to allocate memory for comp_dev");
@@ -144,15 +147,19 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv
144147
mod->dev = dev;
145148
dev->mod = mod;
146149

147-
if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP)
148-
alloc->client_count++;
150+
if (mod_vreg)
151+
mod->priv.resources.alloc.client_count++;
149152

150153
return mod;
151154

152155
err:
153-
sof_heap_free(mod_heap, mod);
156+
if (mod_vreg)
157+
vregion_free(mod_vreg, mod);
158+
else
159+
sof_heap_free(mod_heap, mod);
154160
emod:
155-
rfree(mod_heap);
161+
if (mod_vreg)
162+
vregion_destroy(mod_vreg);
156163

157164
return NULL;
158165
}
@@ -161,7 +168,6 @@ static void module_adapter_mem_free(struct processing_module *mod)
161168
{
162169
struct sof_alloc_api *alloc = &mod->priv.resources.alloc;
163170
struct k_heap *mod_heap = alloc->heap;
164-
unsigned int domain = mod->dev->ipc_config.proc_domain;
165171

166172
/*
167173
* In principle it shouldn't even be needed to free individual objects
@@ -170,10 +176,17 @@ static void module_adapter_mem_free(struct processing_module *mod)
170176
#if CONFIG_IPC_MAJOR_4
171177
sof_heap_free(mod_heap, mod->priv.cfg.input_pins);
172178
#endif
173-
sof_heap_free(mod_heap, mod->dev);
174-
sof_heap_free(mod_heap, mod);
175-
if (domain == COMP_PROCESSING_DOMAIN_DP && mod_heap && !--alloc->client_count)
176-
rfree(mod_heap);
179+
if (alloc->vreg) {
180+
struct vregion *mod_vreg = alloc->vreg;
181+
182+
vregion_free(mod_vreg, mod->dev);
183+
vregion_free(mod_vreg, mod);
184+
if (!--mod->priv.resources.alloc.client_count)
185+
vregion_destroy(mod_vreg);
186+
} else {
187+
sof_heap_free(mod_heap, mod->dev);
188+
sof_heap_free(mod_heap, mod);
189+
}
177190
}
178191

179192
/*
@@ -617,8 +630,7 @@ int module_adapter_prepare(struct comp_dev *dev)
617630
goto free;
618631
}
619632

620-
if (md->resources.alloc.heap &&
621-
md->resources.alloc.heap != dev->drv->user_heap)
633+
if (md->resources.alloc.vreg)
622634
md->resources.alloc.client_count++;
623635

624636
irq_local_disable(flags);

src/include/sof/objpool.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
#include <stddef.h>
1313
#include <stdint.h>
1414

15+
struct vregion;
1516
struct k_heap;
1617
struct objpool_head {
1718
struct list_item list;
19+
struct vregion *vreg;
1820
struct k_heap *heap;
1921
uint32_t flags;
2022
};

src/lib/objpool.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <sof/objpool.h>
88
#include <sof/common.h>
99
#include <sof/list.h>
10+
#include <sof/lib/vregion.h>
1011

1112
#include <errno.h>
1213
#include <limits.h>
@@ -37,8 +38,17 @@ static int objpool_add(struct objpool_head *head, unsigned int n, size_t size, u
3738
if (!head->heap)
3839
head->heap = sof_sys_heap_get();
3940

40-
struct objpool *pobjpool = sof_heap_alloc(head->heap, flags,
41-
aligned_size + sizeof(*pobjpool), 0);
41+
struct objpool *pobjpool;
42+
43+
if (!head->vreg)
44+
pobjpool = sof_heap_alloc(head->heap, flags,
45+
aligned_size + sizeof(*pobjpool), 0);
46+
else if (flags & SOF_MEM_FLAG_COHERENT)
47+
pobjpool = vregion_alloc_coherent(head->vreg, VREGION_MEM_TYPE_INTERIM,
48+
aligned_size + sizeof(*pobjpool));
49+
else
50+
pobjpool = vregion_alloc(head->vreg, VREGION_MEM_TYPE_INTERIM,
51+
aligned_size + sizeof(*pobjpool));
4252

4353
if (!pobjpool)
4454
return -ENOMEM;
@@ -150,8 +160,13 @@ void objpool_prune(struct objpool_head *head)
150160
struct list_item *next, *tmp;
151161

152162
list_for_item_safe(next, tmp, &head->list) {
163+
struct objpool *pool = container_of(next, struct objpool, list);
164+
153165
list_item_del(next);
154-
sof_heap_free(head->heap, container_of(next, struct objpool, list));
166+
if (head->vreg)
167+
vregion_free(head->vreg, pool);
168+
else
169+
sof_heap_free(head->heap, pool);
155170
}
156171
}
157172

src/schedule/zephyr_dp_schedule_application.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,12 +526,12 @@ int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid,
526526
/* Module heap partition */
527527
mod_heap_info(mod, &size, &start);
528528
pdata->mpart[SOF_DP_PART_HEAP] = (struct k_mem_partition){
529-
.start = start,
529+
.start = (uintptr_t)sys_cache_uncached_ptr_get((void *)start),
530530
.size = size,
531531
.attr = K_MEM_PARTITION_P_RW_U_RW,
532532
};
533533
pdata->mpart[SOF_DP_PART_HEAP_CACHE] = (struct k_mem_partition){
534-
.start = (uintptr_t)sys_cache_cached_ptr_get((void *)start),
534+
.start = start,
535535
.size = size,
536536
.attr = K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB,
537537
};

zephyr/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ config SOF_USERSPACE_PROXY_WORKER_STACK_SIZE
133133
config SOF_USERSPACE_APPLICATION
134134
bool
135135
default USERSPACE && !SOF_USERSPACE_PROXY
136+
depends on SOF_VREGIONS
136137
help
137138
Not manually settable. This is effectively a shortcut to replace numerous
138139
checks for (CONFIG_USERSPACE && !CONFIG_SOF_USERSPACE_PROXY)

zephyr/lib/vregion.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ void *vregion_alloc_align(struct vregion *vr, enum vregion_mem_type type,
312312
if (!vr || !size)
313313
return NULL;
314314

315-
if (!alignment)
316-
alignment = 4; /* default align 4 bytes */
315+
if (alignment < PLATFORM_DCACHE_ALIGN)
316+
alignment = PLATFORM_DCACHE_ALIGN;
317317

318318
switch (type) {
319319
case VREGION_MEM_TYPE_INTERIM:

0 commit comments

Comments
 (0)