ipc.c (c16c8bfa09d5f318c1bd65698d058d3739970c24) | ipc.c (2f1f570cd730c81807ae143a83766068dd82d577) |
---|---|
1// SPDX-License-Identifier: GPL-2.0-only 2// 3// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4// 5// Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7// 8 9#include <linux/slab.h> 10#include <sound/hdaudio_ext.h> 11#include "avs.h" 12#include "messages.h" 13#include "registers.h" 14 15#define AVS_IPC_TIMEOUT_MS 300 16 | 1// SPDX-License-Identifier: GPL-2.0-only 2// 3// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4// 5// Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7// 8 9#include <linux/slab.h> 10#include <sound/hdaudio_ext.h> 11#include "avs.h" 12#include "messages.h" 13#include "registers.h" 14 15#define AVS_IPC_TIMEOUT_MS 300 16 |
17static 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 70static 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 77static 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 |
|
17static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header) 18{ 19 struct avs_ipc *ipc = adev->ipc; 20 union avs_reply_msg msg = AVS_MSG(header); 21 22 ipc->rx.header = header; 23 /* Abort copying payload if request processing was unsuccessful. */ 24 if (!msg.status) { --- 27 unchanged lines hidden (view full) --- 52 case AVS_NOTIFY_PHRASE_DETECTED: 53 data_size = sizeof(struct avs_notify_voice_data); 54 break; 55 56 case AVS_NOTIFY_RESOURCE_EVENT: 57 data_size = sizeof(struct avs_notify_res_data); 58 break; 59 | 100static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header) 101{ 102 struct avs_ipc *ipc = adev->ipc; 103 union avs_reply_msg msg = AVS_MSG(header); 104 105 ipc->rx.header = header; 106 /* Abort copying payload if request processing was unsuccessful. */ 107 if (!msg.status) { --- 27 unchanged lines hidden (view full) --- 135 case AVS_NOTIFY_PHRASE_DETECTED: 136 data_size = sizeof(struct avs_notify_voice_data); 137 break; 138 139 case AVS_NOTIFY_RESOURCE_EVENT: 140 data_size = sizeof(struct avs_notify_res_data); 141 break; 142 |
143 case AVS_NOTIFY_EXCEPTION_CAUGHT: 144 break; 145 |
|
60 case AVS_NOTIFY_MODULE_EVENT: 61 /* To know the total payload size, header needs to be read first. */ 62 memcpy_fromio(&mod_data, avs_uplink_addr(adev), sizeof(mod_data)); 63 data_size = sizeof(mod_data) + mod_data.data_size; 64 break; 65 66 default: 67 dev_info(adev->dev, "unknown notification: 0x%08x\n", msg.primary); --- 11 unchanged lines hidden (view full) --- 79 /* Perform notification-specific operations. */ 80 switch (msg.notify_msg_type) { 81 case AVS_NOTIFY_FW_READY: 82 dev_dbg(adev->dev, "FW READY 0x%08x\n", msg.primary); 83 adev->ipc->ready = true; 84 complete(&adev->fw_ready); 85 break; 86 | 146 case AVS_NOTIFY_MODULE_EVENT: 147 /* To know the total payload size, header needs to be read first. */ 148 memcpy_fromio(&mod_data, avs_uplink_addr(adev), sizeof(mod_data)); 149 data_size = sizeof(mod_data) + mod_data.data_size; 150 break; 151 152 default: 153 dev_info(adev->dev, "unknown notification: 0x%08x\n", msg.primary); --- 11 unchanged lines hidden (view full) --- 165 /* Perform notification-specific operations. */ 166 switch (msg.notify_msg_type) { 167 case AVS_NOTIFY_FW_READY: 168 dev_dbg(adev->dev, "FW READY 0x%08x\n", msg.primary); 169 adev->ipc->ready = true; 170 complete(&adev->fw_ready); 171 break; 172 |
173 case AVS_NOTIFY_EXCEPTION_CAUGHT: 174 avs_dsp_exception_caught(adev, &msg); 175 break; 176 |
|
87 default: 88 break; 89 } 90 91 kfree(data); 92} 93 94void avs_dsp_process_response(struct avs_dev *adev, u64 header) --- 178 unchanged lines hidden (view full) --- 273 spin_lock(&ipc->rx_lock); 274 avs_ipc_msg_init(ipc, reply); 275 avs_dsp_send_tx(adev, request); 276 spin_unlock(&ipc->rx_lock); 277 278 ret = avs_ipc_wait_busy_completion(ipc, timeout); 279 if (ret) { 280 if (ret == -ETIMEDOUT) { | 177 default: 178 break; 179 } 180 181 kfree(data); 182} 183 184void avs_dsp_process_response(struct avs_dev *adev, u64 header) --- 178 unchanged lines hidden (view full) --- 363 spin_lock(&ipc->rx_lock); 364 avs_ipc_msg_init(ipc, reply); 365 avs_dsp_send_tx(adev, request); 366 spin_unlock(&ipc->rx_lock); 367 368 ret = avs_ipc_wait_busy_completion(ipc, timeout); 369 if (ret) { 370 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); |
282 | 372 |
283 avs_ipc_block(ipc); | 373 /* Same treatment as on exception, just stack_dump=0. */ 374 avs_dsp_exception_caught(adev, &msg); |
284 } 285 goto exit; 286 } 287 288 ret = ipc->rx.rsp.status; 289 if (reply) { 290 reply->header = ipc->rx.header; 291 if (reply->data && ipc->rx.size) --- 71 unchanged lines hidden (view full) --- 363{ 364 ipc->rx.data = devm_kzalloc(dev, AVS_MAILBOX_SIZE, GFP_KERNEL); 365 if (!ipc->rx.data) 366 return -ENOMEM; 367 368 ipc->dev = dev; 369 ipc->ready = false; 370 ipc->default_timeout_ms = AVS_IPC_TIMEOUT_MS; | 375 } 376 goto exit; 377 } 378 379 ret = ipc->rx.rsp.status; 380 if (reply) { 381 reply->header = ipc->rx.header; 382 if (reply->data && ipc->rx.size) --- 71 unchanged lines hidden (view full) --- 454{ 455 ipc->rx.data = devm_kzalloc(dev, AVS_MAILBOX_SIZE, GFP_KERNEL); 456 if (!ipc->rx.data) 457 return -ENOMEM; 458 459 ipc->dev = dev; 460 ipc->ready = false; 461 ipc->default_timeout_ms = AVS_IPC_TIMEOUT_MS; |
462 INIT_WORK(&ipc->recovery_work, avs_dsp_recovery_work); |
|
371 init_completion(&ipc->done_completion); 372 init_completion(&ipc->busy_completion); 373 spin_lock_init(&ipc->rx_lock); 374 mutex_init(&ipc->msg_mutex); 375 376 return 0; 377} 378 379void avs_ipc_block(struct avs_ipc *ipc) 380{ 381 ipc->ready = false; | 463 init_completion(&ipc->done_completion); 464 init_completion(&ipc->busy_completion); 465 spin_lock_init(&ipc->rx_lock); 466 mutex_init(&ipc->msg_mutex); 467 468 return 0; 469} 470 471void avs_ipc_block(struct avs_ipc *ipc) 472{ 473 ipc->ready = false; |
474 cancel_work_sync(&ipc->recovery_work); |
|
382} | 475} |