@@ -394,7 +394,8 @@ void ipc_schedule_process(struct ipc *ipc)
394394#define IPC_USER_EVENT_CMD BIT(0)
395395#define IPC_USER_EVENT_STOP BIT(1)
396396
397- static K_THREAD_STACK_DEFINE (ipc_user_stack , CONFIG_SOF_IPC_USER_THREAD_STACK_SIZE ) ;
397+ static K_THREAD_STACK_ARRAY_DEFINE (ipc_user_stack , CONFIG_CORE_COUNT ,
398+ CONFIG_SOF_IPC_USER_THREAD_STACK_SIZE ) ;
398399
399400/**
400401 * @brief Forward an IPC4 command to the user-space thread.
@@ -408,7 +409,7 @@ static K_THREAD_STACK_DEFINE(ipc_user_stack, CONFIG_SOF_IPC_USER_THREAD_STACK_SI
408409 * @param ipc4 Pointer to the IPC4 message request
409410 * @return Result from user thread processing
410411 */
411- int ipc_user_forward_cmd (struct ipc4_message_request * ipc4 )
412+ int ipc_user_forward_cmd (struct ipc4_message_request * ipc4 , unsigned int core )
412413{
413414 struct ipc * ipc = ipc_get ();
414415 struct ipc_user * pdata = ipc -> ipc_user_pdata ;
@@ -422,13 +423,22 @@ int ipc_user_forward_cmd(struct ipc4_message_request *ipc4)
422423 pdata -> ipc_msg_ext = ipc4 -> extension .dat ;
423424 pdata -> ipc = ipc ;
424425
426+ /*
427+ * Forwarding the first IPC to this core, wait for its userspace IPC
428+ * thread to start
429+ */
430+ if (pdata -> init_needed [core ]) {
431+ pdata -> init_needed [core ] = false;
432+ k_sem_take (pdata -> sem , K_FOREVER );
433+ }
434+
425435 /* Prevent host completion until user thread finishes */
426436 key = k_spin_lock (& ipc -> lock );
427437 ipc -> task_mask |= IPC_TASK_IN_THREAD ;
428438 k_spin_unlock (& ipc -> lock , key );
429439
430440 /* Wake the user thread */
431- k_event_set (pdata -> event , IPC_USER_EVENT_CMD );
441+ k_event_set (pdata -> event [ core ] , IPC_USER_EVENT_CMD );
432442
433443 /* Wait for user thread to complete */
434444 ret = k_sem_take (pdata -> sem , K_MSEC (100 ));
@@ -453,8 +463,8 @@ int ipc_user_forward_cmd(struct ipc4_message_request *ipc4)
453463static void ipc_user_thread_fn (void * p1 , void * p2 , void * p3 )
454464{
455465 struct ipc_user * ipc_user = p1 ;
466+ unsigned int core = POINTER_TO_UINT (p2 );
456467
457- ARG_UNUSED (p2 );
458468 ARG_UNUSED (p3 );
459469
460470 __ASSERT (k_is_user_context (), "expected user context" );
@@ -464,7 +474,7 @@ static void ipc_user_thread_fn(void *p1, void *p2, void *p3)
464474 LOG_INF ("IPC user-space thread started" );
465475
466476 for (;;) {
467- uint32_t mask = k_event_wait_safe (ipc_user -> event ,
477+ uint32_t mask = k_event_wait_safe (ipc_user -> event [ core ] ,
468478 IPC_USER_EVENT_CMD | IPC_USER_EVENT_STOP ,
469479 false, K_MSEC (5000 ));
470480
@@ -616,55 +626,92 @@ static void ipc_user_thread_fn(void *p1, void *p2, void *p3)
616626 }
617627}
618628
619- __cold static int ipc_user_init_thread (struct ipc_user * ipc_user )
629+ __cold static int ipc_user_init_thread (struct ipc_user * ipc_user , unsigned int core )
620630{
621631 char thread_name [] = "ll_user0" ;
622632 int ret ;
623633
624634 assert_can_be_cold ();
625635
626636 /* Allocate kernel objects for the user-space thread */
627- ipc_user -> event = k_object_alloc (K_OBJ_EVENT );
628- if (!ipc_user -> event ) {
637+ ipc_user -> event [ core ] = k_object_alloc (K_OBJ_EVENT );
638+ if (!ipc_user -> event [ core ] ) {
629639 LOG_ERR ("user IPC event alloc failed" );
630640 return - ENOMEM ;
631641 }
632- k_event_init (ipc_user -> event );
642+ k_event_init (ipc_user -> event [ core ] );
633643
634- ipc_user -> thread = k_object_alloc (K_OBJ_THREAD );
635- if (!ipc_user -> thread ) {
644+ ipc_user -> thread [ core ] = k_object_alloc (K_OBJ_THREAD );
645+ if (!ipc_user -> thread [ core ] ) {
636646 LOG_ERR ("user IPC thread alloc failed" );
637647 ret = - ENOMEM ;
638648 goto e_event ;
639649 }
640650
641- k_thread_create (ipc_user -> thread , ipc_user_stack ,
651+ k_thread_create (ipc_user -> thread [ core ] , ipc_user_stack [ core ] ,
642652 CONFIG_SOF_IPC_USER_THREAD_STACK_SIZE ,
643- ipc_user_thread_fn , ipc_user , NULL , NULL ,
653+ ipc_user_thread_fn , ipc_user , UINT_TO_POINTER ( core ) , NULL ,
644654 -1 , K_USER , K_FOREVER );
645655
646- k_thread_cpu_pin (ipc_user -> thread , PLATFORM_PRIMARY_CORE_ID );
647- k_thread_name_set (ipc_user -> thread , thread_name );
656+ k_thread_cpu_pin (ipc_user -> thread [core ], core );
657+ thread_name [sizeof (thread_name ) - 2 ] = '0' + core ;
658+ k_thread_name_set (ipc_user -> thread [core ], thread_name );
648659
649660 /*
650661 * Each userspace IPC thread must be able to wait on its private event
651662 * and signal completion on the primary core semaphore
652663 */
653- k_thread_access_grant (ipc_user -> thread , ipc_user -> sem , ipc_user -> event );
654- user_grant_dai_access_all (ipc_user -> thread );
655- user_grant_dma_access_all (ipc_user -> thread );
656- pipeline_posn_grant_access (ipc_user -> thread );
657- k_mem_domain_add_thread (zephyr_ll_mem_domain (), ipc_user -> thread );
658- user_ll_grant_access (ipc_user -> thread );
664+ k_thread_access_grant (ipc_user -> thread [ core ] , ipc_user -> sem , ipc_user -> event [ core ] );
665+ user_grant_dai_access_all (ipc_user -> thread [ core ] );
666+ user_grant_dma_access_all (ipc_user -> thread [ core ] );
667+ pipeline_posn_grant_access (ipc_user -> thread [ core ] );
668+ k_mem_domain_add_thread (zephyr_ll_mem_domain (), ipc_user -> thread [ core ] );
669+ user_ll_grant_access (ipc_user -> thread [ core ] );
659670
660671 return 0 ;
661672
662673e_event :
663- k_object_free (ipc_user -> event );
674+ k_object_free (ipc_user -> event [ core ] );
664675
665676 return ret ;
666677}
667678
679+ __cold int ipc_user_init_secondary (unsigned int core )
680+ {
681+ struct ipc * ipc = ipc_get ();
682+ struct ipc_user * ipc_user = ipc -> ipc_user_pdata ;
683+ int ret = ipc_user_init_thread (ipc_user , core );
684+
685+ if (ret < 0 )
686+ return ret ;
687+
688+ assert_can_be_cold ();
689+
690+ k_thread_start (ipc_user -> thread [core ]);
691+
692+ struct task * task = zephyr_ll_task_alloc ();
693+
694+ if (!task ) {
695+ LOG_ERR ("user LL task allocation failed" );
696+ k_panic ();
697+ }
698+
699+ schedule_task_init_ll (task , SOF_UUID (ipc_uuid ), SOF_SCHEDULE_LL_TIMER ,
700+ 0 , NULL , NULL , core , 0 );
701+
702+ ipc_user -> audio_thread [core ] = scheduler_init_context (task );
703+ if (!ipc_user -> audio_thread [core ]) {
704+ LOG_ERR ("user LL thread init failed" );
705+ k_panic ();
706+ }
707+
708+ k_thread_access_grant (ipc_user -> thread [core ], ipc_user -> audio_thread [core ]);
709+ ipc_user -> init_needed [core ] = true;
710+
711+ /* Wait for user thread startup — consumes the initial k_sem_give from thread */
712+ return 0 ;
713+ }
714+
668715__cold int ipc_user_init (void )
669716{
670717 struct ipc * ipc = ipc_get ();
@@ -673,6 +720,8 @@ __cold int ipc_user_init(void)
673720 sizeof (* ipc_user ), 0 );
674721 int ret ;
675722
723+ assert_can_be_cold ();
724+
676725 ipc_user -> sem = k_object_alloc (K_OBJ_SEM );
677726 if (!ipc_user -> sem ) {
678727 LOG_ERR ("user IPC sem alloc failed" );
@@ -712,40 +761,51 @@ __cold int ipc_user_init(void)
712761 ret = k_mem_domain_add_partition (zephyr_ll_mem_domain (),
713762 & cold_part );
714763 if (ret < 0 )
715- LOG_WRN ("cold rodata partition %#zx @ %#lx add failed: %d" , cold_part . size ,
716- cold_part .start , ret );
764+ LOG_WRN ("cold rodata partition %#zx @ %#lx add failed: %d" ,
765+ cold_part .size , cold_part . start , ret );
717766 }
718767 }
719768#endif
720769
721770 k_sem_init (ipc_user -> sem , 0 , 1 );
722771
723- ret = ipc_user_init_thread (ipc_user );
772+ ret = ipc_user_init_thread (ipc_user , PLATFORM_PRIMARY_CORE_ID );
724773 if (ret < 0 ) {
725774 LOG_ERR ("user IPC thread initialization failed" );
726775 k_panic ();
727776 }
728777
729- user_access_to_mailbox (zephyr_ll_mem_domain (), ipc_user -> thread );
778+ user_access_to_mailbox (zephyr_ll_mem_domain (), ipc_user -> thread [ PLATFORM_PRIMARY_CORE_ID ] );
730779
731780 /* Store references in ipc struct so kernel handler can forward commands */
732781 ipc -> ipc_user_pdata = ipc_user ;
733782
734- k_thread_start (ipc_user -> thread );
735-
736783 struct task * task = zephyr_ll_task_alloc ();
784+
785+ if (!task ) {
786+ LOG_ERR ("task allocation failed" );
787+ k_panic ();
788+ }
789+
737790 schedule_task_init_ll (task , SOF_UUID (ipc_uuid ), SOF_SCHEDULE_LL_TIMER ,
738- 0 , NULL , NULL , cpu_get_id (), 0 );
739- ipc_user -> audio_thread = scheduler_init_context (task );
791+ 0 , NULL , NULL , PLATFORM_PRIMARY_CORE_ID , 0 );
792+ ipc_user -> audio_thread [PLATFORM_PRIMARY_CORE_ID ] = scheduler_init_context (task );
793+ if (!ipc_user -> audio_thread [PLATFORM_PRIMARY_CORE_ID ]) {
794+ LOG_ERR ("user LL thread init failed" );
795+ k_panic ();
796+ }
740797
741798 /* Grant ipc_user thread permission on the audio thread object.
742799 * Needed so user-space dai_common_new() can call
743800 * k_thread_access_grant(audio_thread, dai_mutex) from user context.
744801 */
745- k_thread_access_grant (ipc_user -> thread , ipc_user -> audio_thread );
802+ k_thread_access_grant (ipc_user -> thread [PLATFORM_PRIMARY_CORE_ID ],
803+ ipc_user -> audio_thread [PLATFORM_PRIMARY_CORE_ID ]);
804+
805+ k_thread_start (ipc_user -> thread [PLATFORM_PRIMARY_CORE_ID ]);
746806
747807 /* Wait for user thread startup — consumes the initial k_sem_give from thread */
748- k_sem_take (ipc -> ipc_user_pdata -> sem , K_FOREVER );
808+ k_sem_take (ipc_user -> sem , K_FOREVER );
749809
750810 return 0 ;
751811}
0 commit comments