sound/soc/intel/avs/ipc.c

Source file repositories/reference/linux-study-clean/sound/soc/intel/avs/ipc.c

File Facts

System
Linux kernel
Corpus path
sound/soc/intel/avs/ipc.c
Extension
.c
Size
15506 bytes
Lines
584
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

for_each_card_rtds(card, rtd) {
			struct snd_pcm *pcm;
			int dir;

			pcm = rtd->pcm;
			if (!pcm || rtd->dai_link->no_pcm)
				continue;

			for_each_pcm_streams(dir) {
				struct snd_pcm_substream *substream;

				substream = pcm->streams[dir].substream;
				if (!substream || !substream->runtime)
					continue;

				/* No need for _irq() as we are in nonatomic context. */
				snd_pcm_stream_lock(substream);
				snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
				snd_pcm_stream_unlock(substream);
			}
		}
	}
	mutex_unlock(&adev->comp_list_mutex);

	/* forcibly shutdown all cores */
	core_mask = GENMASK(adev->hw_cfg.dsp_cores - 1, 0);
	avs_dsp_core_disable(adev, core_mask);

	/* attempt dsp reboot */
	ret = avs_dsp_boot_firmware(adev, true);
	if (ret < 0)
		dev_err(adev->dev, "dsp reboot failed: %d\n", ret);

	pm_runtime_enable(adev->dev);
	pm_request_autosuspend(adev->dev);

	atomic_set(&adev->ipc->recovering, 0);
}

static void avs_dsp_recovery_work(struct work_struct *work)
{
	struct avs_ipc *ipc = container_of(work, struct avs_ipc, recovery_work);

	avs_dsp_recovery(to_avs_dev(ipc->dev));
}

static void avs_dsp_exception_caught(struct avs_dev *adev, union avs_notify_msg *msg)
{
	struct avs_ipc *ipc = adev->ipc;

	/* Account for the double-exception case. */
	ipc->ready = false;

	if (!atomic_add_unless(&ipc->recovering, 1, 1)) {
		dev_err(adev->dev, "dsp recovery is already in progress\n");
		return;
	}

	dev_crit(adev->dev, "communication severed, rebooting dsp..\n");

	/* Avoid deadlock as the exception may be the response to SET_D0IX. */
	if (current_work() != &ipc->d0ix_work.work)
		cancel_delayed_work_sync(&ipc->d0ix_work);
	ipc->in_d0ix = false;
	/* Re-enabled on recovery completion. */
	pm_runtime_disable(adev->dev);

	/* Process received notification. */
	avs_dsp_op(adev, coredump, msg);

	schedule_work(&ipc->recovery_work);
}

static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header)
{
	struct avs_ipc *ipc = adev->ipc;
	union avs_reply_msg msg = AVS_MSG(header);
	u32 sts, lec;

	sts = snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev));
	lec = snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev));
	trace_avs_ipc_reply_msg(header, sts, lec);

	ipc->rx.header = header;
	/* Abort copying payload if request processing was unsuccessful. */
	if (!msg.status) {
		/* update size in case of LARGE_CONFIG_GET */
		if (msg.msg_target == AVS_MOD_MSG &&
		    msg.global_msg_type == AVS_MOD_LARGE_CONFIG_GET)
			ipc->rx.size = min_t(u32, AVS_MAILBOX_SIZE,

Annotation

Implementation Notes