-
Notifications
You must be signed in to change notification settings - Fork 363
audio: pipeline: change locking strategy for user LL builds #10957
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -448,10 +448,21 @@ __cold static int ipc_pipeline_module_free(uint32_t pipeline_id) | |
| struct ipc *ipc = ipc_get(); | ||
| struct ipc_comp_dev *icd; | ||
| int ret; | ||
| #ifdef CONFIG_SOF_USERSPACE_LL | ||
| int ppl_core; | ||
| #endif | ||
|
|
||
| assert_can_be_cold(); | ||
|
|
||
| icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_COMPONENT, pipeline_id, IPC_COMP_ALL); | ||
| if (!icd) | ||
| return IPC4_SUCCESS; | ||
|
|
||
| #ifdef CONFIG_SOF_USERSPACE_LL | ||
| ppl_core = icd->core; | ||
| user_ll_lock_sched(ppl_core); | ||
| #endif | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. currently this is working with no locking at all, right? Theoretically this could race against pipeline streaming if we have a forking graph where one branch is stopped and freed while the other one is still running, correct? So I suppose we have a guard in place that would prevent the streaming loop from entering the stopped branch safely somehow?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lyakh In kernel-LL build, pipeline_disconnect() will disable local irqs to protect this. It's a good question whether that is sufficient for all cases, but at least has been in the code for a while like this. In user-LL, with higher cost taken with each mutex, taking the lock higher here, outside the loop in pipeline_module_free(). |
||
|
|
||
| while (icd) { | ||
| struct comp_buffer *buffer; | ||
| struct comp_buffer *safe; | ||
|
|
@@ -481,12 +492,20 @@ __cold static int ipc_pipeline_module_free(uint32_t pipeline_id) | |
| else | ||
| ret = ipc_comp_free(ipc, icd->id); | ||
|
|
||
| if (ret) | ||
| if (ret) { | ||
| #ifdef CONFIG_SOF_USERSPACE_LL | ||
| user_ll_unlock_sched(ppl_core); | ||
| #endif | ||
| return IPC4_INVALID_RESOURCE_STATE; | ||
| } | ||
|
|
||
| icd = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_COMPONENT, pipeline_id, IPC_COMP_ALL); | ||
| } | ||
|
|
||
| #ifdef CONFIG_SOF_USERSPACE_LL | ||
| user_ll_unlock_sched(ppl_core); | ||
| #endif | ||
|
|
||
| return IPC4_SUCCESS; | ||
| } | ||
|
|
||
|
|
@@ -560,21 +579,25 @@ __cold static struct comp_buffer *ipc4_create_buffer(struct comp_dev *src, bool | |
| * disable any interrupts. | ||
| */ | ||
|
|
||
| #define ll_block(cross_core_bind, flags) \ | ||
| #if CONFIG_SOF_USERSPACE_LL | ||
| #error "CONFIG_SOF_USERSPACE_LL not compatible with cross-core streams" | ||
| #else | ||
| #define ll_block(src_core, dst_core, flags) \ | ||
| do { \ | ||
| if (cross_core_bind) \ | ||
| if (src_core != dst_core) \ | ||
| domain_block(sof_get()->platform_timer_domain); \ | ||
| else \ | ||
| irq_local_disable(flags); \ | ||
| } while (0) | ||
|
|
||
| #define ll_unblock(cross_core_bind, flags) \ | ||
| #define ll_unblock(src_core, dst_core, flags) \ | ||
| do { \ | ||
| if (cross_core_bind) \ | ||
| if (src_core != dst_core) \ | ||
| domain_unblock(sof_get()->platform_timer_domain); \ | ||
| else \ | ||
| irq_local_enable(flags); \ | ||
| } while (0) | ||
| #endif | ||
|
|
||
| /* Calling both ll_block() and ll_wait_finished_on_core() makes sure LL will not start its | ||
| * next cycle and its current cycle on specified core has finished. | ||
|
|
@@ -606,8 +629,22 @@ static int ll_wait_finished_on_core(struct comp_dev *dev) | |
|
|
||
| #else | ||
|
|
||
| #define ll_block(cross_core_bind, flags) irq_local_disable(flags) | ||
| #define ll_unblock(cross_core_bind, flags) irq_local_enable(flags) | ||
| #if CONFIG_SOF_USERSPACE_LL | ||
| /* note: cross-core streams are disabled so src_core==dst_core */ | ||
| #define ll_block(src_core, dst_core, flags) \ | ||
| do { \ | ||
| user_ll_lock_sched(src_core); \ | ||
| ARG_UNUSED(flags); \ | ||
| } while(0) | ||
| #define ll_unblock(src_core, dst_core, flags) \ | ||
| do { \ | ||
| user_ll_unlock_sched(src_core); \ | ||
| ARG_UNUSED(flags); \ | ||
| } while(0) | ||
| #else | ||
| #define ll_block(src_core, dst_core, flags) irq_local_disable(flags) | ||
| #define ll_unblock(src_core, dst_core, flags) irq_local_enable(flags) | ||
| #endif | ||
|
|
||
| #endif | ||
|
|
||
|
|
@@ -794,7 +831,7 @@ __cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) | |
| * blocked on corresponding core(s) to prevent IPC or IDC task getting preempted which | ||
| * could result in buffers being only half connected when a pipeline task gets executed. | ||
| */ | ||
| ll_block(cross_core_bind, flags); | ||
| ll_block(source->ipc_config.core, sink->ipc_config.core, flags); | ||
|
|
||
| if (cross_core_bind) { | ||
| #if CONFIG_CROSS_CORE_STREAM | ||
|
|
@@ -851,7 +888,7 @@ __cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) | |
| source->direction_set = true; | ||
| } | ||
|
|
||
| ll_unblock(cross_core_bind, flags); | ||
| ll_unblock(source->ipc_config.core, sink->ipc_config.core, flags); | ||
|
|
||
| return IPC4_SUCCESS; | ||
|
|
||
|
|
@@ -865,7 +902,7 @@ __cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) | |
| e_sink_connect: | ||
| pipeline_disconnect(source, buffer, PPL_CONN_DIR_COMP_TO_BUFFER); | ||
| free: | ||
| ll_unblock(cross_core_bind, flags); | ||
| ll_unblock(source->ipc_config.core, sink->ipc_config.core, flags); | ||
| buffer_free(buffer); | ||
| return IPC4_INVALID_RESOURCE_STATE; | ||
| } | ||
|
|
@@ -938,24 +975,24 @@ __cold int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) | |
| * IPC or IDC task getting preempted which could result in buffers being only half connected | ||
| * when a pipeline task gets executed. | ||
| */ | ||
| ll_block(cross_core_unbind, flags); | ||
| ll_block(src->ipc_config.core, sink->ipc_config.core, flags); | ||
|
|
||
| if (cross_core_unbind) { | ||
| #if CONFIG_CROSS_CORE_STREAM | ||
| /* Make sure LL has finished on both cores */ | ||
| if (!cpu_is_me(src->ipc_config.core)) | ||
| if (ll_wait_finished_on_core(src) < 0) { | ||
| ll_unblock(cross_core_unbind, flags); | ||
| ll_unblock(src->ipc_config.core, sink->ipc_config.core, flags); | ||
| return IPC4_FAILURE; | ||
| } | ||
| if (!cpu_is_me(sink->ipc_config.core)) | ||
| if (ll_wait_finished_on_core(sink) < 0) { | ||
| ll_unblock(cross_core_unbind, flags); | ||
| ll_unblock(src->ipc_config.core, sink->ipc_config.core, flags); | ||
| return IPC4_FAILURE; | ||
| } | ||
| #else | ||
| tr_err(&ipc_tr, "Cross-core binding is disabled"); | ||
| ll_unblock(cross_core_unbind, flags); | ||
| ll_unblock(src->ipc_config.core, sink->ipc_config.core, flags); | ||
| return IPC4_FAILURE; | ||
| #endif | ||
| } | ||
|
|
@@ -972,7 +1009,7 @@ __cold int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) | |
| unbind_data.source = audio_buffer_get_source(&buffer->audio_buffer); | ||
| ret1 = comp_unbind(sink, &unbind_data); | ||
|
|
||
| ll_unblock(cross_core_unbind, flags); | ||
| ll_unblock(src->ipc_config.core, sink->ipc_config.core, flags); | ||
|
|
||
| buffer_free(buffer); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CONFIG_SOF_USERS_SPACEin commit description seems to be wrong