1414
1515#define AVS_IPC_TIMEOUT_MS 300
1616
17+ static void avs_dsp_recovery (struct avs_dev * adev )
18+ {
19+ struct avs_soc_component * acomp ;
20+ unsigned int core_mask ;
21+ int ret ;
22+
23+ mutex_lock (& adev -> comp_list_mutex );
24+ /* disconnect all running streams */
25+ list_for_each_entry (acomp , & adev -> comp_list , node ) {
26+ struct snd_soc_pcm_runtime * rtd ;
27+ struct snd_soc_card * card ;
28+
29+ card = acomp -> base .card ;
30+ if (!card )
31+ continue ;
32+
33+ for_each_card_rtds (card , rtd ) {
34+ struct snd_pcm * pcm ;
35+ int dir ;
36+
37+ pcm = rtd -> pcm ;
38+ if (!pcm || rtd -> dai_link -> no_pcm )
39+ continue ;
40+
41+ for_each_pcm_streams (dir ) {
42+ struct snd_pcm_substream * substream ;
43+
44+ substream = pcm -> streams [dir ].substream ;
45+ if (!substream || !substream -> runtime )
46+ continue ;
47+
48+ snd_pcm_stop (substream , SNDRV_PCM_STATE_DISCONNECTED );
49+ }
50+ }
51+ }
52+ mutex_unlock (& adev -> comp_list_mutex );
53+
54+ /* forcibly shutdown all cores */
55+ core_mask = GENMASK (adev -> hw_cfg .dsp_cores - 1 , 0 );
56+ avs_dsp_core_disable (adev , core_mask );
57+
58+ /* attempt dsp reboot */
59+ ret = avs_dsp_boot_firmware (adev , true);
60+ if (ret < 0 )
61+ dev_err (adev -> dev , "dsp reboot failed: %d\n" , ret );
62+
63+ pm_runtime_mark_last_busy (adev -> dev );
64+ pm_runtime_enable (adev -> dev );
65+ pm_request_autosuspend (adev -> dev );
66+
67+ atomic_set (& adev -> ipc -> recovering , 0 );
68+ }
69+
70+ static void avs_dsp_recovery_work (struct work_struct * work )
71+ {
72+ struct avs_ipc * ipc = container_of (work , struct avs_ipc , recovery_work );
73+
74+ avs_dsp_recovery (to_avs_dev (ipc -> dev ));
75+ }
76+
77+ static void avs_dsp_exception_caught (struct avs_dev * adev , union avs_notify_msg * msg )
78+ {
79+ struct avs_ipc * ipc = adev -> ipc ;
80+
81+ /* Account for the double-exception case. */
82+ ipc -> ready = false;
83+
84+ if (!atomic_add_unless (& ipc -> recovering , 1 , 1 )) {
85+ dev_err (adev -> dev , "dsp recovery is already in progress\n" );
86+ return ;
87+ }
88+
89+ dev_crit (adev -> dev , "communication severed, rebooting dsp..\n" );
90+
91+ /* Re-enabled on recovery completion. */
92+ pm_runtime_disable (adev -> dev );
93+
94+ /* Process received notification. */
95+ avs_dsp_op (adev , coredump , msg );
96+
97+ schedule_work (& ipc -> recovery_work );
98+ }
99+
17100static void avs_dsp_receive_rx (struct avs_dev * adev , u64 header )
18101{
19102 struct avs_ipc * ipc = adev -> ipc ;
@@ -57,6 +140,9 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
57140 data_size = sizeof (struct avs_notify_res_data );
58141 break ;
59142
143+ case AVS_NOTIFY_EXCEPTION_CAUGHT :
144+ break ;
145+
60146 case AVS_NOTIFY_MODULE_EVENT :
61147 /* To know the total payload size, header needs to be read first. */
62148 memcpy_fromio (& mod_data , avs_uplink_addr (adev ), sizeof (mod_data ));
@@ -84,6 +170,10 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
84170 complete (& adev -> fw_ready );
85171 break ;
86172
173+ case AVS_NOTIFY_EXCEPTION_CAUGHT :
174+ avs_dsp_exception_caught (adev , & msg );
175+ break ;
176+
87177 default :
88178 break ;
89179 }
@@ -278,9 +368,10 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
278368 ret = avs_ipc_wait_busy_completion (ipc , timeout );
279369 if (ret ) {
280370 if (ret == - ETIMEDOUT ) {
281- dev_crit ( adev -> dev , "communication severed: %d, rebooting dsp..\n" , ret );
371+ union avs_notify_msg msg = AVS_NOTIFICATION ( EXCEPTION_CAUGHT );
282372
283- avs_ipc_block (ipc );
373+ /* Same treatment as on exception, just stack_dump=0. */
374+ avs_dsp_exception_caught (adev , & msg );
284375 }
285376 goto exit ;
286377 }
@@ -368,6 +459,7 @@ int avs_ipc_init(struct avs_ipc *ipc, struct device *dev)
368459 ipc -> dev = dev ;
369460 ipc -> ready = false;
370461 ipc -> default_timeout_ms = AVS_IPC_TIMEOUT_MS ;
462+ INIT_WORK (& ipc -> recovery_work , avs_dsp_recovery_work );
371463 init_completion (& ipc -> done_completion );
372464 init_completion (& ipc -> busy_completion );
373465 spin_lock_init (& ipc -> rx_lock );
@@ -379,4 +471,5 @@ int avs_ipc_init(struct avs_ipc *ipc, struct device *dev)
379471void avs_ipc_block (struct avs_ipc * ipc )
380472{
381473 ipc -> ready = false;
474+ cancel_work_sync (& ipc -> recovery_work );
382475}
0 commit comments