Skip to content

Commit b641fb7

Browse files
ujfalusibroonie
authored andcommitted
ASoC: SOF: ipc3: Add local implementation for handling fw_ready message
The handling of fw_ready is IPC3 specific, move the needed code from the loader.c to ipc3.c and stop using the sof_ops(sdev)->fw_ready() callback. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Ajit Pandey <ajitkumar.pandey@amd.com> Reviewed-by: Daniel Baluta <daniel.baluta@nxp.com> Link: https://lore.kernel.org/r/20220421080735.31698-2-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 57ebd5d commit b641fb7

1 file changed

Lines changed: 305 additions & 1 deletion

File tree

sound/soc/sof/ipc3.c

Lines changed: 305 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,310 @@ static int sof_ipc3_set_get_data(struct snd_sof_dev *sdev, void *data, size_t da
475475
return ret;
476476
}
477477

478+
static int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev,
479+
const struct sof_ipc_ext_data_hdr *ext_hdr)
480+
{
481+
const struct sof_ipc_window *w =
482+
container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
483+
484+
if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
485+
return -EINVAL;
486+
487+
if (sdev->info_window) {
488+
if (memcmp(sdev->info_window, w, ext_hdr->hdr.size)) {
489+
dev_err(sdev->dev, "mismatch between window descriptor from extended manifest and mailbox");
490+
return -EINVAL;
491+
}
492+
return 0;
493+
}
494+
495+
/* keep a local copy of the data */
496+
sdev->info_window = devm_kmemdup(sdev->dev, w, ext_hdr->hdr.size, GFP_KERNEL);
497+
if (!sdev->info_window)
498+
return -ENOMEM;
499+
500+
return 0;
501+
}
502+
503+
static int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev,
504+
const struct sof_ipc_ext_data_hdr *ext_hdr)
505+
{
506+
int ret;
507+
508+
const struct sof_ipc_cc_version *cc =
509+
container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
510+
511+
if (sdev->cc_version) {
512+
if (memcmp(sdev->cc_version, cc, cc->ext_hdr.hdr.size)) {
513+
dev_err(sdev->dev,
514+
"Receive diverged cc_version descriptions");
515+
return -EINVAL;
516+
}
517+
return 0;
518+
}
519+
520+
dev_dbg(sdev->dev,
521+
"Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
522+
cc->name, cc->major, cc->minor, cc->micro, cc->desc, cc->optim);
523+
524+
/* create read-only cc_version debugfs to store compiler version info */
525+
/* use local copy of the cc_version to prevent data corruption */
526+
if (sdev->first_boot) {
527+
sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
528+
GFP_KERNEL);
529+
530+
if (!sdev->cc_version)
531+
return -ENOMEM;
532+
533+
memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
534+
ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
535+
cc->ext_hdr.hdr.size,
536+
"cc_version", 0444);
537+
538+
/* errors are only due to memory allocation, not debugfs */
539+
if (ret < 0) {
540+
dev_err(sdev->dev, "snd_sof_debugfs_buf_item failed\n");
541+
return ret;
542+
}
543+
}
544+
545+
return 0;
546+
}
547+
548+
/* parse the extended FW boot data structures from FW boot message */
549+
static int ipc3_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset)
550+
{
551+
struct sof_ipc_ext_data_hdr *ext_hdr;
552+
void *ext_data;
553+
int ret = 0;
554+
555+
ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
556+
if (!ext_data)
557+
return -ENOMEM;
558+
559+
/* get first header */
560+
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
561+
sizeof(*ext_hdr));
562+
ext_hdr = ext_data;
563+
564+
while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
565+
/* read in ext structure */
566+
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM,
567+
offset + sizeof(*ext_hdr),
568+
(void *)((u8 *)ext_data + sizeof(*ext_hdr)),
569+
ext_hdr->hdr.size - sizeof(*ext_hdr));
570+
571+
dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
572+
ext_hdr->type, ext_hdr->hdr.size);
573+
574+
/* process structure data */
575+
switch (ext_hdr->type) {
576+
case SOF_IPC_EXT_WINDOW:
577+
ret = sof_ipc3_get_ext_windows(sdev, ext_hdr);
578+
break;
579+
case SOF_IPC_EXT_CC_INFO:
580+
ret = sof_ipc3_get_cc_info(sdev, ext_hdr);
581+
break;
582+
case SOF_IPC_EXT_UNUSED:
583+
case SOF_IPC_EXT_PROBE_INFO:
584+
case SOF_IPC_EXT_USER_ABI_INFO:
585+
/* They are supported but we don't do anything here */
586+
break;
587+
default:
588+
dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n",
589+
ext_hdr->type, ext_hdr->hdr.size);
590+
ret = 0;
591+
break;
592+
}
593+
594+
if (ret < 0) {
595+
dev_err(sdev->dev, "Failed to parse ext data type %d\n",
596+
ext_hdr->type);
597+
break;
598+
}
599+
600+
/* move to next header */
601+
offset += ext_hdr->hdr.size;
602+
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
603+
sizeof(*ext_hdr));
604+
ext_hdr = ext_data;
605+
}
606+
607+
kfree(ext_data);
608+
return ret;
609+
}
610+
611+
static void ipc3_get_windows(struct snd_sof_dev *sdev)
612+
{
613+
struct sof_ipc_window_elem *elem;
614+
u32 outbox_offset = 0;
615+
u32 stream_offset = 0;
616+
u32 inbox_offset = 0;
617+
u32 outbox_size = 0;
618+
u32 stream_size = 0;
619+
u32 inbox_size = 0;
620+
u32 debug_size = 0;
621+
u32 debug_offset = 0;
622+
int window_offset;
623+
int i;
624+
625+
if (!sdev->info_window) {
626+
dev_err(sdev->dev, "%s: No window info present\n", __func__);
627+
return;
628+
}
629+
630+
for (i = 0; i < sdev->info_window->num_windows; i++) {
631+
elem = &sdev->info_window->window[i];
632+
633+
window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
634+
if (window_offset < 0) {
635+
dev_warn(sdev->dev, "No offset for window %d\n", elem->id);
636+
continue;
637+
}
638+
639+
switch (elem->type) {
640+
case SOF_IPC_REGION_UPBOX:
641+
inbox_offset = window_offset + elem->offset;
642+
inbox_size = elem->size;
643+
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
644+
inbox_offset,
645+
elem->size, "inbox",
646+
SOF_DEBUGFS_ACCESS_D0_ONLY);
647+
break;
648+
case SOF_IPC_REGION_DOWNBOX:
649+
outbox_offset = window_offset + elem->offset;
650+
outbox_size = elem->size;
651+
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
652+
outbox_offset,
653+
elem->size, "outbox",
654+
SOF_DEBUGFS_ACCESS_D0_ONLY);
655+
break;
656+
case SOF_IPC_REGION_TRACE:
657+
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
658+
window_offset + elem->offset,
659+
elem->size, "etrace",
660+
SOF_DEBUGFS_ACCESS_D0_ONLY);
661+
break;
662+
case SOF_IPC_REGION_DEBUG:
663+
debug_offset = window_offset + elem->offset;
664+
debug_size = elem->size;
665+
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
666+
window_offset + elem->offset,
667+
elem->size, "debug",
668+
SOF_DEBUGFS_ACCESS_D0_ONLY);
669+
break;
670+
case SOF_IPC_REGION_STREAM:
671+
stream_offset = window_offset + elem->offset;
672+
stream_size = elem->size;
673+
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
674+
stream_offset,
675+
elem->size, "stream",
676+
SOF_DEBUGFS_ACCESS_D0_ONLY);
677+
break;
678+
case SOF_IPC_REGION_REGS:
679+
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
680+
window_offset + elem->offset,
681+
elem->size, "regs",
682+
SOF_DEBUGFS_ACCESS_D0_ONLY);
683+
break;
684+
case SOF_IPC_REGION_EXCEPTION:
685+
sdev->dsp_oops_offset = window_offset + elem->offset;
686+
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
687+
window_offset + elem->offset,
688+
elem->size, "exception",
689+
SOF_DEBUGFS_ACCESS_D0_ONLY);
690+
break;
691+
default:
692+
dev_err(sdev->dev, "%s: Illegal window info: %u\n",
693+
__func__, elem->type);
694+
return;
695+
}
696+
}
697+
698+
if (outbox_size == 0 || inbox_size == 0) {
699+
dev_err(sdev->dev, "%s: Illegal mailbox window\n", __func__);
700+
return;
701+
}
702+
703+
sdev->dsp_box.offset = inbox_offset;
704+
sdev->dsp_box.size = inbox_size;
705+
706+
sdev->host_box.offset = outbox_offset;
707+
sdev->host_box.size = outbox_size;
708+
709+
sdev->stream_box.offset = stream_offset;
710+
sdev->stream_box.size = stream_size;
711+
712+
sdev->debug_box.offset = debug_offset;
713+
sdev->debug_box.size = debug_size;
714+
715+
dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
716+
inbox_offset, inbox_size);
717+
dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
718+
outbox_offset, outbox_size);
719+
dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
720+
stream_offset, stream_size);
721+
dev_dbg(sdev->dev, " debug region 0x%x - size 0x%x\n",
722+
debug_offset, debug_size);
723+
}
724+
725+
static int ipc3_init_reply_data_buffer(struct snd_sof_dev *sdev)
726+
{
727+
struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
728+
729+
msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
730+
if (!msg->reply_data)
731+
return -ENOMEM;
732+
733+
sdev->ipc->max_payload_size = SOF_IPC_MSG_MAX_SIZE;
734+
735+
return 0;
736+
}
737+
738+
static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd)
739+
{
740+
struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
741+
int offset;
742+
int ret;
743+
744+
/* mailbox must be on 4k boundary */
745+
offset = snd_sof_dsp_get_mailbox_offset(sdev);
746+
if (offset < 0) {
747+
dev_err(sdev->dev, "%s: no mailbox offset\n", __func__);
748+
return offset;
749+
}
750+
751+
dev_dbg(sdev->dev, "DSP is ready 0x%8.8x offset 0x%x\n", cmd, offset);
752+
753+
/* no need to re-check version/ABI for subsequent boots */
754+
if (!sdev->first_boot)
755+
return 0;
756+
757+
/*
758+
* copy data from the DSP FW ready offset
759+
* Subsequent error handling is not needed for BLK_TYPE_SRAM
760+
*/
761+
ret = snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, fw_ready,
762+
sizeof(*fw_ready));
763+
if (ret) {
764+
dev_err(sdev->dev,
765+
"Unable to read fw_ready, read from TYPE_SRAM failed\n");
766+
return ret;
767+
}
768+
769+
/* make sure ABI version is compatible */
770+
ret = snd_sof_ipc_valid(sdev);
771+
if (ret < 0)
772+
return ret;
773+
774+
/* now check for extended data */
775+
ipc3_fw_parse_ext_data(sdev, offset + sizeof(struct sof_ipc_fw_ready));
776+
777+
ipc3_get_windows(sdev);
778+
779+
return ipc3_init_reply_data_buffer(sdev);
780+
}
781+
478782
/* IPC stream position. */
479783
static void ipc3_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
480784
{
@@ -633,7 +937,7 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
633937
case SOF_IPC_FW_READY:
634938
/* check for FW boot completion */
635939
if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) {
636-
err = sof_ops(sdev)->fw_ready(sdev, cmd);
940+
err = ipc3_fw_ready(sdev, cmd);
637941
if (err < 0)
638942
sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED);
639943
else

0 commit comments

Comments
 (0)