Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 150
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
88f33a70d166a249b52be775cb469ff992b4bbbe9a9d62fff8348e34b0aae2bfc391aaFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -185,6 +185,10 @@ enum sof_ipc4_pipeline_state { | ||
| #define SOF_IPC4_GLB_PIPE_STATE_MASK GENMASK(15, 0) | ||
| #define SOF_IPC4_GLB_PIPE_STATE(x) ((x) << SOF_IPC4_GLB_PIPE_STATE_SHIFT) | ||
| /* load library ipc msg */ | ||
| #define SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID_SHIFT 16 | ||
| #define SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(x) ((x) << SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID_SHIFT) | ||
ranj063 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| enum sof_ipc4_channel_config { | ||
| /* one channel only. */ | ||
| SOF_IPC4_CHANNEL_CONFIG_MONO, | ||
| 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? CollaboratorAuthor 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.
Uh oh!There was an error while loading. Please reload this page. | ||
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? CollaboratorAuthor 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? CollaboratorAuthor 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? CollaboratorAuthor 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 */ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -136,10 +136,9 @@ static ssize_t ipc3_fw_ext_man_size(struct snd_sof_dev *sdev, const struct firmw | ||
| return 0; | ||
| } | ||
| static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev) | ||
ranj063 marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev, const struct firmware *fw, | ||
| u32 lib_index, u32 flags) | ||
| { | ||
| struct snd_sof_pdata *plat_data = sdev->pdata; | ||
| const struct firmware *fw = plat_data->fw; | ||
| const struct sof_ext_man_elem_header *elem_hdr; | ||
| const struct sof_ext_man_header *head; | ||
| ssize_t ext_man_size; | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.