Skip to content

Commit 783d99c

Browse files
committed
dax: sharing one instance across multiple dax adapters
DAX adapters may be created across multiple pipelines simultaneously, but only one instance can be active at any given time. This approach prevents memory exhaustion issues that would arise if multiple DAX adapters were created concurrently. Signed-off-by: Jun Lai <jun.lai@dolby.com>
1 parent 678de87 commit 783d99c

File tree

2 files changed

+180
-25
lines changed
  • src/audio/module_adapter/module/dolby
  • third_party/include

2 files changed

+180
-25
lines changed

src/audio/module_adapter/module/dolby/dax.c

Lines changed: 170 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,26 @@ SOF_DEFINE_REG_UUID(dolby_dax_audio_processing);
3838
#define DAX_ENUM_PROFILE_CONTROL_ID 0
3939
#define DAX_ENUM_DEVICE_CONTROL_ID 1
4040

41+
#define DAX_OWNER_ID_INVALID 0
42+
43+
struct dax_shared_resource {
44+
void *instance;
45+
struct dax_buffer persist_buffer;
46+
struct dax_buffer scratch_buffer;
47+
atomic_t owner_id_counter;
48+
atomic_t owner;
49+
atomic_t force_owner; /* the owner should obtain resource immediately */
50+
atomic_t ref_count;
51+
atomic_t initialized;
52+
};
53+
54+
static struct dax_shared_resource shared_resource;
55+
4156
struct dax_adapter_data {
4257
struct sof_dax dax_ctx;
4358
atomic_t proc_flags;
59+
int32_t owner_id;
60+
int32_t is_registered;
4461
};
4562

4663
enum dax_flag_opt_mode {
@@ -246,9 +263,19 @@ static void destroy_instance(struct processing_module *mod)
246263
struct dax_adapter_data *adapter_data = module_get_private_data(mod);
247264
struct sof_dax *dax_ctx = &adapter_data->dax_ctx;
248265

249-
dax_free(dax_ctx); /* free internal dax instance in dax_ctx */
250-
dax_buffer_release(mod, &dax_ctx->persist_buffer);
251-
dax_buffer_release(mod, &dax_ctx->scratch_buffer);
266+
if (dax_ctx) {
267+
dax_ctx->p_dax = shared_resource.instance;
268+
dax_free(dax_ctx); /* free internal dax instance in dax_ctx if it is valid */
269+
rfree(shared_resource.persist_buffer.addr);
270+
rfree(shared_resource.scratch_buffer.addr);
271+
memset(&shared_resource.persist_buffer, 0, sizeof(shared_resource.persist_buffer));
272+
memset(&shared_resource.scratch_buffer, 0, sizeof(shared_resource.scratch_buffer));
273+
memset(&dax_ctx->persist_buffer, 0, sizeof(dax_ctx->persist_buffer));
274+
memset(&dax_ctx->scratch_buffer, 0, sizeof(dax_ctx->scratch_buffer));
275+
shared_resource.instance = NULL;
276+
dax_ctx->p_dax = NULL;
277+
comp_info(mod->dev, "freed instance");
278+
}
252279
}
253280

254281
static int establish_instance(struct processing_module *mod)
@@ -261,25 +288,35 @@ static int establish_instance(struct processing_module *mod)
261288
uint32_t scratch_sz;
262289

263290
persist_sz = dax_query_persist_memory(dax_ctx);
264-
if (dax_buffer_alloc(mod, &dax_ctx->persist_buffer, persist_sz) != 0) {
291+
shared_resource.persist_buffer.addr = rballoc(SOF_MEM_FLAG_LARGE_BUFFER, persist_sz);
292+
if (!shared_resource.persist_buffer.addr) {
265293
comp_err(dev, "allocate %u bytes failed for persist", persist_sz);
266294
ret = -ENOMEM;
267295
goto err;
268296
}
269297
scratch_sz = dax_query_scratch_memory(dax_ctx);
270-
if (dax_buffer_alloc(mod, &dax_ctx->scratch_buffer, scratch_sz) != 0) {
298+
shared_resource.scratch_buffer.addr = rballoc(SOF_MEM_FLAG_LARGE_BUFFER, scratch_sz);
299+
if (!shared_resource.scratch_buffer.addr) {
271300
comp_err(dev, "allocate %u bytes failed for scratch", scratch_sz);
272301
ret = -ENOMEM;
273302
goto err;
274303
}
304+
305+
shared_resource.persist_buffer.size = persist_sz;
306+
shared_resource.scratch_buffer.size = scratch_sz;
307+
dax_ctx->persist_buffer = shared_resource.persist_buffer;
308+
dax_ctx->scratch_buffer = shared_resource.scratch_buffer;
275309
ret = dax_init(dax_ctx);
276310
if (ret != 0) {
277311
comp_err(dev, "dax instance initialization failed, ret %d", ret);
278312
goto err;
279313
}
314+
shared_resource.instance = dax_ctx->p_dax;
280315

281-
/* set DAX_ENABLE_MASK bit to trigger the fully update of kcontrol values */
282-
flag_process(adapter_data, DAX_ENABLE_MASK, DAX_FLAG_SET);
316+
/* reset dax_ctx here because acquire_ownership is only the way to get shared instance */
317+
dax_ctx->p_dax = NULL;
318+
memset(&dax_ctx->persist_buffer, 0, sizeof(dax_ctx->persist_buffer));
319+
memset(&dax_ctx->scratch_buffer, 0, sizeof(dax_ctx->scratch_buffer));
283320

284321
comp_info(dev, "allocated: persist %u, scratch %u. version: %s",
285322
persist_sz, scratch_sz, dax_get_version());
@@ -290,6 +327,82 @@ static int establish_instance(struct processing_module *mod)
290327
return ret;
291328
}
292329

330+
static bool is_instance_owned(struct processing_module *mod)
331+
{
332+
struct dax_adapter_data *adapter_data = module_get_private_data(mod);
333+
334+
return atomic_read(&shared_resource.owner) == adapter_data->owner_id;
335+
}
336+
337+
static void release_ownership(struct processing_module *mod)
338+
{
339+
struct dax_adapter_data *adapter_data = module_get_private_data(mod);
340+
struct sof_dax *dax_ctx = &adapter_data->dax_ctx;
341+
342+
atomic_set(&shared_resource.owner, DAX_OWNER_ID_INVALID);
343+
dax_ctx->p_dax = NULL;
344+
memset(&dax_ctx->persist_buffer, 0, sizeof(dax_ctx->persist_buffer));
345+
memset(&dax_ctx->scratch_buffer, 0, sizeof(dax_ctx->scratch_buffer));
346+
comp_info(mod->dev, "unbinded DAX instance from owner %d", adapter_data->owner_id);
347+
}
348+
349+
static void set_ownership(struct processing_module *mod, int32_t owner_id)
350+
{
351+
struct dax_adapter_data *adapter_data = module_get_private_data(mod);
352+
struct sof_dax *dax_ctx = &adapter_data->dax_ctx;
353+
354+
atomic_set(&shared_resource.owner, owner_id);
355+
dax_ctx->p_dax = shared_resource.instance;
356+
dax_ctx->persist_buffer = shared_resource.persist_buffer;
357+
dax_ctx->scratch_buffer = shared_resource.scratch_buffer;
358+
359+
/* reset instance buffer data */
360+
dax_set_enable(0, dax_ctx);
361+
362+
/* set DAX_ENABLE_MASK bit to trigger the fully update of kcontrol values */
363+
flag_process(adapter_data, DAX_ENABLE_MASK, DAX_FLAG_SET);
364+
365+
comp_info(mod->dev, "binded DAX instance to owner %d", adapter_data->owner_id);
366+
}
367+
368+
/* can only be called within sof_dax_process */
369+
static int acquire_ownership(struct processing_module *mod)
370+
{
371+
struct dax_adapter_data *adapter_data = module_get_private_data(mod);
372+
struct sof_dax *dax_ctx = &adapter_data->dax_ctx;
373+
int32_t force_owner;
374+
375+
if (atomic_read(&shared_resource.initialized) == 0)
376+
return -EINVAL;
377+
378+
force_owner = atomic_read(&shared_resource.force_owner);
379+
if (force_owner != DAX_OWNER_ID_INVALID && force_owner != adapter_data->owner_id) {
380+
/* release current ownership cause force_owner has more priority */
381+
if (is_instance_owned(mod))
382+
release_ownership(mod);
383+
return 0;
384+
}
385+
386+
/* transfer owner safely */
387+
if (atomic_read(&shared_resource.owner) == DAX_OWNER_ID_INVALID) {
388+
set_ownership(mod, adapter_data->owner_id);
389+
if (force_owner == adapter_data->owner_id)
390+
atomic_set(&shared_resource.force_owner, DAX_OWNER_ID_INVALID);
391+
return 0;
392+
}
393+
394+
/* highest priority for speaker */
395+
if (dax_ctx->out_device == DAX_AUDIO_DEVICE_OUT_SPEAKER) {
396+
atomic_set(&shared_resource.force_owner, adapter_data->owner_id);
397+
return 0;
398+
}
399+
400+
dax_ctx->p_dax = NULL;
401+
memset(&dax_ctx->persist_buffer, 0, sizeof(dax_ctx->persist_buffer));
402+
memset(&dax_ctx->scratch_buffer, 0, sizeof(dax_ctx->scratch_buffer));
403+
return -EBUSY;
404+
}
405+
293406
static int set_tuning_file(struct processing_module *mod, void *value, uint32_t size)
294407
{
295408
int ret = 0;
@@ -313,17 +426,14 @@ static int set_tuning_file(struct processing_module *mod, void *value, uint32_t
313426

314427
static int set_enable(struct processing_module *mod, int32_t enable)
315428
{
316-
int ret = 0;
429+
int ret;
317430
struct dax_adapter_data *adapter_data = module_get_private_data(mod);
318431
struct sof_dax *dax_ctx = &adapter_data->dax_ctx;
319432

320-
if (enable) {
321-
ret = dax_set_enable(1, dax_ctx);
322-
dax_ctx->enable = (ret == 0 ? 1 : 0);
323-
} else {
324-
dax_ctx->enable = 0;
325-
dax_set_enable(0, dax_ctx);
326-
}
433+
if (!is_instance_owned(mod))
434+
return 0;
435+
436+
ret = dax_set_enable(enable, dax_ctx);
327437

328438
comp_info(mod->dev, "set dax enable %d, ret %d", enable, ret);
329439
return ret;
@@ -336,7 +446,7 @@ static int set_volume(struct processing_module *mod, int32_t abs_volume)
336446
struct sof_dax *dax_ctx = &adapter_data->dax_ctx;
337447

338448
dax_ctx->volume = abs_volume;
339-
if (!dax_ctx->enable)
449+
if (!dax_ctx->enable || !is_instance_owned(mod))
340450
return 0;
341451

342452
ret = dax_set_volume(abs_volume, dax_ctx);
@@ -351,6 +461,9 @@ static int set_device(struct processing_module *mod, int32_t out_device)
351461
struct sof_dax *dax_ctx = &adapter_data->dax_ctx;
352462

353463
dax_ctx->out_device = out_device;
464+
if (!dax_ctx->enable || !is_instance_owned(mod))
465+
return 0;
466+
354467
ret = dax_set_device(out_device, dax_ctx);
355468

356469
comp_info(mod->dev, "set device %d, ret %d", out_device, ret);
@@ -364,6 +477,9 @@ static int set_crosstalk_cancellation_enable(struct processing_module *mod, int3
364477
struct sof_dax *dax_ctx = &adapter_data->dax_ctx;
365478

366479
dax_ctx->ctc_enable = enable;
480+
if (!dax_ctx->enable || !is_instance_owned(mod))
481+
return 0;
482+
367483
ret = dax_set_ctc_enable(enable, dax_ctx);
368484

369485
comp_info(mod->dev, "set ctc enable %d, ret %d", enable, ret);
@@ -382,7 +498,7 @@ static int set_profile(struct processing_module *mod, int32_t profile_id)
382498
void *params;
383499

384500
dax_ctx->profile = profile_id;
385-
if (!dax_ctx->enable)
501+
if (!dax_ctx->enable || !is_instance_owned(mod))
386502
return 0;
387503

388504
params = dax_find_params(DAX_PARAM_ID_PROFILE, profile_id, &params_sz, dax_ctx);
@@ -403,7 +519,7 @@ static int set_tuning_device(struct processing_module *mod, int32_t tuning_devic
403519
void *params;
404520

405521
dax_ctx->tuning_device = tuning_device;
406-
if (!dax_ctx->enable)
522+
if (!dax_ctx->enable || !is_instance_owned(mod))
407523
return 0;
408524

409525
params = dax_find_params(DAX_PARAM_ID_TUNING_DEVICE, tuning_device, &params_sz, dax_ctx);
@@ -424,7 +540,7 @@ static int set_content_processing_enable(struct processing_module *mod, int32_t
424540
void *params;
425541

426542
dax_ctx->content_processing_enable = enable;
427-
if (!dax_ctx->enable)
543+
if (!dax_ctx->enable || !is_instance_owned(mod))
428544
return 0;
429545

430546
params = dax_find_params(DAX_PARAM_ID_CP_ENABLE, enable, &params_sz, dax_ctx);
@@ -542,6 +658,9 @@ static void check_and_update_settings(struct processing_module *mod)
542658
struct dax_adapter_data *adapter_data = module_get_private_data(mod);
543659
struct sof_dax *dax_ctx = &adapter_data->dax_ctx;
544660

661+
if (!is_instance_owned(mod))
662+
return;
663+
545664
if (flag_process(adapter_data, DAX_ENABLE_MASK, DAX_FLAG_READ_AND_CLEAR)) {
546665
set_enable(mod, dax_ctx->enable);
547666
if (dax_ctx->enable) {
@@ -580,13 +699,16 @@ static int sof_dax_reset(struct processing_module *mod)
580699
struct dax_adapter_data *adapter_data = module_get_private_data(mod);
581700
struct sof_dax *dax_ctx;
582701

583-
/* dax instance will be established on prepare(), and destroyed on reset() */
584702
if (adapter_data) {
585703
dax_ctx = &adapter_data->dax_ctx;
586704
if (flag_process(adapter_data, DAX_PROCESSING_MASK, DAX_FLAG_READ)) {
587705
flag_process(adapter_data, DAX_RESET_MASK, DAX_FLAG_SET);
588706
} else {
589-
destroy_instance(mod);
707+
if (adapter_data->is_registered == 1) {
708+
atomic_sub(&shared_resource.ref_count, 1);
709+
release_ownership(mod);
710+
adapter_data->is_registered = 0;
711+
}
590712
dax_buffer_release(mod, &dax_ctx->input_buffer);
591713
dax_buffer_release(mod, &dax_ctx->output_buffer);
592714
}
@@ -606,6 +728,12 @@ static int sof_dax_free(struct processing_module *mod)
606728
flag_process(adapter_data, DAX_FREE_MASK, DAX_FLAG_SET);
607729
} else {
608730
sof_dax_reset(mod);
731+
732+
if (atomic_read(&shared_resource.ref_count) == 0) {
733+
destroy_instance(mod);
734+
atomic_set(&shared_resource.initialized, 0);
735+
}
736+
609737
dax_buffer_release(mod, &dax_ctx->tuning_file_buffer);
610738
mod_data_blob_handler_free(mod, dax_ctx->blob_handler);
611739
dax_ctx->blob_handler = NULL;
@@ -661,6 +789,12 @@ static int sof_dax_init(struct processing_module *mod)
661789
return -ENOMEM;
662790
}
663791

792+
if (atomic_read(&shared_resource.owner_id_counter) == INT32_MAX)
793+
atomic_set(&shared_resource.owner_id_counter, 0);
794+
atomic_add(&shared_resource.owner_id_counter, 1);
795+
adapter_data->owner_id = atomic_read(&shared_resource.owner_id_counter);
796+
comp_info(dev, "initialized, owner id %d", adapter_data->owner_id);
797+
664798
return 0;
665799
}
666800

@@ -757,10 +891,20 @@ static int sof_dax_prepare(struct processing_module *mod, struct sof_source **so
757891
if (ret != 0)
758892
return ret;
759893

760-
/* dax instance will be established on prepare(), and destroyed on reset() */
761-
ret = establish_instance(mod);
762-
if (ret != 0)
763-
return ret;
894+
if (adapter_data->is_registered == 0) {
895+
adapter_data->is_registered = 1;
896+
atomic_add(&shared_resource.ref_count, 1);
897+
}
898+
899+
if (atomic_read(&shared_resource.initialized) == 0) {
900+
atomic_set(&shared_resource.initialized, 1);
901+
ret = establish_instance(mod);
902+
if (ret) {
903+
/* rollback initialization state */
904+
atomic_set(&shared_resource.initialized, 0);
905+
return ret;
906+
}
907+
}
764908

765909
dax_ctx->sof_period_bytes = dev->frames *
766910
dax_ctx->output_media_format.num_channels *
@@ -832,6 +976,7 @@ static int sof_dax_process(struct processing_module *mod, struct sof_source **so
832976
dax_buffer_produce(dax_input_buffer, consumed_bytes);
833977
source_release_data(source, consumed_bytes);
834978

979+
acquire_ownership(mod);
835980
check_and_update_settings(mod);
836981

837982
/* internal input buffer -> internal output buffer */

third_party/include/dax_inf.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
#include <stdint.h>
1515
#include <string.h>
1616

17+
enum dax_out_device {
18+
DAX_AUDIO_DEVICE_UNSUPPORTED = -1,
19+
DAX_AUDIO_DEVICE_OUT_SPEAKER = 0,
20+
DAX_AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 1,
21+
};
22+
1723
enum dax_frame_fmt {
1824
DAX_FMT_UNSUPPORTED = -1,
1925
DAX_FMT_SHORT_16 = 4,
@@ -144,6 +150,10 @@ int dax_init(struct sof_dax *dax_ctx);
144150
/**
145151
* @brief Process audio data through the DAX module
146152
*
153+
* If DAX is disabled or the DAX instance is invalid (dax_ctx->p_dax is NULL),
154+
* the dax_process will by default perform only copy operations, without any
155+
* audio processing.
156+
*
147157
* @param[in] dax_ctx Pointer to the DAX context structure
148158
*
149159
* @return Bytes of processed. negative error code on failure

0 commit comments

Comments
 (0)