-
Notifications
You must be signed in to change notification settings - Fork 133
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
Introduce i.MX93 support #4310
Introduce i.MX93 support #4310
Changes from 2 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 |
---|---|---|
|
@@ -109,6 +109,8 @@ EXPORT_SYMBOL(snd_sof_load_firmware_memcpy); | |
int snd_sof_run_firmware(struct snd_sof_dev *sdev) | ||
{ | ||
int ret; | ||
struct sof_ipc_cmd_hdr hdr; | ||
struct sof_ipc_reply reply; | ||
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 can be moved inside of the if() case 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.
FW_READY notification does get sent too early (platform driver is not even inserted yet) but I'm not sure if it gets lost since I haven't tested this case (which in hindsight seems like a poor choice on my part).
IMO Hm, using EDIT: Please see thesofproject/sof#7192. The flow is explained here. 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. @LaurentiuM1234, thanks for the pointer to the diagrams, it is clear now. In this setup you are not going to reboot Zephyr/SOF unless you do a full system suspend to turn off all A55s, right? The first and biggest issue with the current PR is that you introduce IPC3 message sending in generic, IPC neutral code (loader.c), this must be avoided. Before making any change in architecture, I would check the following:
Can you test this? If this is working then you don't need changes in core at all as the platform's peculiarities will be handled in platform code. 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. Sorry for taking so long to reply. See answers below:
This can easily be solved by moving the IPC3 code from loader.c to
Just did a small test in which the firmware sends FW_READY and
What do you mean fake an interrupt? Also, wouldn't it be more natural to just have the host initiate the FW_READY sequence (of course, all the IPC3 code would me moved from 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.
I'm even more sorry for the delay...
Kernel should never panic... How come the kernel is crashing? It should be waiting for the FW_READY and just gave up and fail the probe since it thinks that the DSP is not working/
In iMX platform code declare a delayed work and schedule it from the When the work is executed, check if the FW_READY message is in the mailbox, if it is there then call
If we are pragmatic, it is not too natural ;) |
||
|
||
init_waitqueue_head(&sdev->boot_wait); | ||
|
||
|
@@ -145,20 +147,41 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) | |
return ret; | ||
} | ||
|
||
/* | ||
* now wait for the DSP to boot. There are 3 possible outcomes: | ||
* 1. Boot wait times out indicating FW boot failure. | ||
* 2. FW boots successfully and fw_ready op succeeds. | ||
* 3. FW boots but fw_ready op fails. | ||
*/ | ||
ret = wait_event_timeout(sdev->boot_wait, | ||
sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS, | ||
msecs_to_jiffies(sdev->boot_timeout)); | ||
if (ret == 0) { | ||
snd_sof_dsp_dbg_dump(sdev, "Firmware boot failure due to timeout", | ||
SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX | | ||
SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI); | ||
return -EIO; | ||
if (!sdev->init_fw_ready) { | ||
/* | ||
* now wait for the DSP to boot. There are 3 possible outcomes: | ||
* 1. Boot wait times out indicating FW boot failure. | ||
* 2. FW boots successfully and fw_ready op succeeds. | ||
* 3. FW boots but fw_ready op fails. | ||
*/ | ||
ret = wait_event_timeout(sdev->boot_wait, | ||
sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS, | ||
msecs_to_jiffies(sdev->boot_timeout)); | ||
if (ret == 0) { | ||
snd_sof_dsp_dbg_dump(sdev, "Firmware boot failure due to timeout", | ||
SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX | | ||
SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI); | ||
return -EIO; | ||
} | ||
} else { | ||
/* initialize IPC reply buffer if need be */ | ||
if (!sdev->ipc->max_payload_size) { | ||
ret = snd_sof_ipc_init_reply_data_buffer(sdev); | ||
if (ret < 0) | ||
return ret; | ||
} | ||
|
||
/* host needs to initiate SOF_IPC_FW_READY. The | ||
* sof_ipc_fw_ready data that was previously signaled by | ||
* a FW-initiated IPC will come as a reply to host's | ||
* IPC. | ||
*/ | ||
hdr.cmd = SOF_IPC_FW_READY; | ||
hdr.size = sizeof(reply); | ||
|
||
ret = sof_ipc_tx_message(sdev->ipc, &hdr, hdr.size, &reply, sizeof(reply)); | ||
if (ret < 0) | ||
return ret; | ||
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. it's not clear where the fw_state is set in this block? Is the test line 187 even relevant for this case where the firmware is assumed to have always booted? FWIW Intel had such platforms where the firmware is loaded already in ROM/flash, so this notion of skipping the download is relevant. 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. Intel may have the issue of skipping the download, but on this new Jailhouse implementation there's more. We're also skipping the "DSP" power on itself, and the firmware starts booting outright before SOF even gets the chance to load -- quite possibly multiple seconds, and if we're doing kernel modules can be as long as 30-60 seconds before the SOF module loads. I believe this flow change is still relevant because of that. Unless Jailhouse provided a way to delay starting the secondary processor running SOF until the kernel module requested it, that is (there apparently is no such way) 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 major problem Jailhouse API has in our case is that is controlled only from userspace via ioctls. We tried proposing them opening the API to be also called in kernel, with little success. https://groups.google.com/g/jailhouse-dev/c/Vaft0VYnLzY/m/A2TYgLUyAwAJ 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 fw_state is set in 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. In this setup the firmware will never going to send the FW_READY notification or it is going to be randomly sent too early, thus the host is not going to receive it? It might be simpler to handle this use case buy using different description of the setup: This way most of the changes will happen in ipc3.c and probably better layered? |
||
} | ||
|
||
if (sdev->fw_state == SOF_FW_BOOT_READY_FAILED) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -474,6 +474,10 @@ struct sof_ipc_pcm_ops; | |
* @get_reply: Function pointer for fetching the reply to | ||
* sdev->ipc->msg.reply_data | ||
* @rx_msg: Function pointer for handling a received message | ||
* @init_reply_data_buffer: Optional pointer for IPC reply data | ||
* initialization. Used for cases where | ||
* the host needs to initialize the | ||
* SOF_IPC_FW_READY sequence. | ||
* | ||
* Note: both @tx_msg and @set_get_data considered as TX functions and they are | ||
* serialized for the duration of the instructed transfer. A large message sent | ||
|
@@ -497,6 +501,17 @@ struct sof_ipc_ops { | |
bool set); | ||
int (*get_reply)(struct snd_sof_dev *sdev); | ||
void (*rx_msg)(struct snd_sof_dev *sdev); | ||
/* this operation is required for cases where the host might | ||
* want to send the firmware a message before SOF_IPC_FW_READY | ||
* is received. | ||
* | ||
* One of these cases is on i.MX93 platform which requires the | ||
* host to send a SOF_IPC_FW_READY message to firmware in order | ||
* to receive the data expected from SOF_IPC_FW_READY. This time | ||
* said data will be received as a reply so the reply_data | ||
* buffer needs to be prepared. | ||
*/ | ||
int (*init_reply_data_buffer)(struct snd_sof_dev *sdev); | ||
}; | ||
|
||
/* SOF generic IPC data */ | ||
|
@@ -663,6 +678,10 @@ struct snd_sof_dev { | |
u16 mclk_id_quirk; /* same size as in IPC3 definitions */ | ||
|
||
void *private; /* core does not touch this */ | ||
/* set to true if the host needs to initiate | ||
* the SOF_IPC_FW_READY sequence. | ||
*/ | ||
bool init_fw_ready; | ||
}; | ||
|
||
/* | ||
|
@@ -728,6 +747,11 @@ static inline int sof_ipc_tx_message_no_pm_no_reply(struct snd_sof_ipc *ipc, voi | |
int sof_ipc_send_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes, | ||
size_t reply_bytes); | ||
|
||
static inline int snd_sof_ipc_init_reply_data_buffer(struct snd_sof_dev *sdev) | ||
{ | ||
return sdev->ipc->ops->init_reply_data_buffer(sdev); | ||
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 check for NULL of |
||
} | ||
|
||
static inline void snd_sof_ipc_process_reply(struct snd_sof_dev *sdev, u32 msg_id) | ||
{ | ||
snd_sof_ipc_get_reply(sdev); | ||
|
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.
Do you genuinely need to move an entire function? Is there no way to e.g. declare the dependency just before the function?
Such as adding before sof_ipc3_get_reply a line like:
static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd);
The definition can still be after this function, it doesn't matter to the compiler as long as it can see the declaration. That should also cause less code churn. Up to you if you think this is better than moving the function itself.
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.
Both approaches solve the same problem. If the extra commit doesn't bother anyone, might as well go with the current one.
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.
I think we should go with Paul's suggestion. Moving function around will pollute the history and make investigations harder.