@@ -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. */
479783static 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