-
Notifications
You must be signed in to change notification settings - Fork 142
Add support for dynamic loading of module libraries for IPC4 #3720
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
Changes from all commits
88f33a7
0d166a2
49b52be
775cb46
9ff992b
4bbbe9a
9d62fff
8348e34
b0aae2b
fc391aa
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 |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ | |
| #include <sound/hdaudio_ext.h> | ||
| #include <sound/hda_register.h> | ||
| #include <sound/sof.h> | ||
| #include <sound/sof/ipc4/header.h> | ||
| #include "ext_manifest.h" | ||
| #include "../ops.h" | ||
| #include "../sof-priv.h" | ||
|
|
@@ -382,6 +383,64 @@ static int hda_dsp_boot_imr(struct snd_sof_dev *sdev) | |
| return ret; | ||
| } | ||
|
|
||
| int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, | ||
| struct snd_sof_module_library_info *lib_info) | ||
| { | ||
| struct hdac_ext_stream *hext_stream; | ||
| struct firmware stripped_firmware; | ||
| struct snd_dma_buffer dmab; | ||
| struct sof_ipc4_msg msg = {}; | ||
| int ret, ret1; | ||
|
|
||
| stripped_firmware.data = lib_info->fw->data + lib_info->fw_offset; | ||
| stripped_firmware.size = lib_info->fw->size - lib_info->fw_offset; | ||
|
Member
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. maybe check that the offset is smaller than a size?
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. the parse_ext_manifest op already takes of it isnt it?
Member
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. no idea, a comment wouldn't hurt :-) |
||
|
|
||
| /* prepare DMA for code loader stream */ | ||
| hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, | ||
| stripped_firmware.size, | ||
| &dmab, SNDRV_PCM_STREAM_PLAYBACK); | ||
| if (IS_ERR(hext_stream)) { | ||
| dev_err(sdev->dev, "DMA prepare failed\n"); | ||
| return PTR_ERR(hext_stream); | ||
| } | ||
|
|
||
| memcpy(dmab.area, stripped_firmware.data, stripped_firmware.size); | ||
|
|
||
| msg.primary = hext_stream->hstream.stream_tag - 1; | ||
| msg.primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_LOAD_LIBRARY); | ||
| msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); | ||
| msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); | ||
| msg.primary |= SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(lib_info->id); | ||
plbossart marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
|
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. Should we move those IPC4 stuff to a new helper function in ipc4.c?
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. do you mean the entire load_library function? and this is HDA specific no? how can I move to the common code outside the intel directory?
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. This is highly HDA specific message and sequence, let's add a comment and think about the abstraction if the need ever arise |
||
| ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START); | ||
| if (ret < 0) { | ||
| dev_err(sdev->dev, "DMA trigger start failed\n"); | ||
| goto cleanup; | ||
| } | ||
|
|
||
| ret = sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); | ||
|
|
||
| ret1 = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP); | ||
|
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. the reply is only going to be received when the module is loaded by the DMA or they go in parallel? Is there a race here? If the module is 'big' we might have a timeout or we stop the channel before the whole module is sent down?
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. @ujfalusi I'd assume the reply would be recieved after the module library is loaded. And if the module is big and takes too long and we don't receive the reply, the time will timeout. |
||
| if (ret1 < 0) { | ||
| dev_err(sdev->dev, "DMA trigger stop failed\n"); | ||
| if (!ret) | ||
| ret = ret1; | ||
| } | ||
|
|
||
| cleanup: | ||
| /* clean up even in case of error and return the first error */ | ||
| ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream); | ||
| if (ret1 < 0) { | ||
| dev_err(sdev->dev, "Code loader DSP cleanup failed\n"); | ||
|
|
||
| /* set return value to indicate cleanup failure */ | ||
| if (!ret) | ||
| ret = ret1; | ||
| } | ||
|
|
||
| return ret; | ||
| } | ||
|
|
||
| int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) | ||
| { | ||
| struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; | ||
|
|
@@ -479,7 +538,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) | |
| ret = hda_cl_copy_fw(sdev, hext_stream); | ||
| if (!ret) { | ||
| dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); | ||
| hda->skip_imr_boot = false; | ||
| } else { | ||
| snd_sof_dsp_dbg_dump(sdev, "Firmware download failed", | ||
| SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX); | ||
|
|
@@ -525,6 +583,7 @@ int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) | |
| /* post fw run operations */ | ||
| int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) | ||
| { | ||
| struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; | ||
| int ret; | ||
|
|
||
| if (sdev->first_boot) { | ||
|
|
@@ -542,8 +601,17 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) | |
| (sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT || | ||
| sdev->pdata->ipc_type == SOF_INTEL_IPC4)) | ||
| hdev->imrboot_supported = true; | ||
| } else { | ||
| /* reload all 3rd party module libraries during cold boot */ | ||
| if (!hda->imrboot_supported || hda->skip_imr_boot) { | ||
| ret = sdev->ipc->ops->fw_loader->reload_libraries(sdev); | ||
|
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. Can this be done in higher level?
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. load_library happens during topology parsing and it will be not done during resume. So we need an explicit way to do this either during resume or here inpost_fw_run
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. The callback should be validated, this will Oops with IPC3 after a firmware crash or when waking up from hibernation, no? |
||
| if (ret < 0) | ||
| return ret; | ||
| } | ||
| } | ||
|
|
||
| hda->skip_imr_boot = false; | ||
|
|
||
| hda_sdw_int_enable(sdev, true); | ||
|
|
||
| /* re-enable clock gating and power gating */ | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.