cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ipc3.c (28441B)


      1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
      2//
      3// This file is provided under a dual BSD/GPLv2 license.  When using or
      4// redistributing this file, you may do so under either license.
      5//
      6// Copyright(c) 2021 Intel Corporation. All rights reserved.
      7//
      8//
      9
     10#include <sound/sof/stream.h>
     11#include <sound/sof/control.h>
     12#include "sof-priv.h"
     13#include "sof-audio.h"
     14#include "ipc3-priv.h"
     15#include "ops.h"
     16
     17typedef void (*ipc3_rx_callback)(struct snd_sof_dev *sdev, void *msg_buf);
     18
     19#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC)
     20static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd)
     21{
     22	u8 *str;
     23	u8 *str2 = NULL;
     24	u32 glb;
     25	u32 type;
     26	bool vdbg = false;
     27
     28	glb = cmd & SOF_GLB_TYPE_MASK;
     29	type = cmd & SOF_CMD_TYPE_MASK;
     30
     31	switch (glb) {
     32	case SOF_IPC_GLB_REPLY:
     33		str = "GLB_REPLY"; break;
     34	case SOF_IPC_GLB_COMPOUND:
     35		str = "GLB_COMPOUND"; break;
     36	case SOF_IPC_GLB_TPLG_MSG:
     37		str = "GLB_TPLG_MSG";
     38		switch (type) {
     39		case SOF_IPC_TPLG_COMP_NEW:
     40			str2 = "COMP_NEW"; break;
     41		case SOF_IPC_TPLG_COMP_FREE:
     42			str2 = "COMP_FREE"; break;
     43		case SOF_IPC_TPLG_COMP_CONNECT:
     44			str2 = "COMP_CONNECT"; break;
     45		case SOF_IPC_TPLG_PIPE_NEW:
     46			str2 = "PIPE_NEW"; break;
     47		case SOF_IPC_TPLG_PIPE_FREE:
     48			str2 = "PIPE_FREE"; break;
     49		case SOF_IPC_TPLG_PIPE_CONNECT:
     50			str2 = "PIPE_CONNECT"; break;
     51		case SOF_IPC_TPLG_PIPE_COMPLETE:
     52			str2 = "PIPE_COMPLETE"; break;
     53		case SOF_IPC_TPLG_BUFFER_NEW:
     54			str2 = "BUFFER_NEW"; break;
     55		case SOF_IPC_TPLG_BUFFER_FREE:
     56			str2 = "BUFFER_FREE"; break;
     57		default:
     58			str2 = "unknown type"; break;
     59		}
     60		break;
     61	case SOF_IPC_GLB_PM_MSG:
     62		str = "GLB_PM_MSG";
     63		switch (type) {
     64		case SOF_IPC_PM_CTX_SAVE:
     65			str2 = "CTX_SAVE"; break;
     66		case SOF_IPC_PM_CTX_RESTORE:
     67			str2 = "CTX_RESTORE"; break;
     68		case SOF_IPC_PM_CTX_SIZE:
     69			str2 = "CTX_SIZE"; break;
     70		case SOF_IPC_PM_CLK_SET:
     71			str2 = "CLK_SET"; break;
     72		case SOF_IPC_PM_CLK_GET:
     73			str2 = "CLK_GET"; break;
     74		case SOF_IPC_PM_CLK_REQ:
     75			str2 = "CLK_REQ"; break;
     76		case SOF_IPC_PM_CORE_ENABLE:
     77			str2 = "CORE_ENABLE"; break;
     78		case SOF_IPC_PM_GATE:
     79			str2 = "GATE"; break;
     80		default:
     81			str2 = "unknown type"; break;
     82		}
     83		break;
     84	case SOF_IPC_GLB_COMP_MSG:
     85		str = "GLB_COMP_MSG";
     86		switch (type) {
     87		case SOF_IPC_COMP_SET_VALUE:
     88			str2 = "SET_VALUE"; break;
     89		case SOF_IPC_COMP_GET_VALUE:
     90			str2 = "GET_VALUE"; break;
     91		case SOF_IPC_COMP_SET_DATA:
     92			str2 = "SET_DATA"; break;
     93		case SOF_IPC_COMP_GET_DATA:
     94			str2 = "GET_DATA"; break;
     95		default:
     96			str2 = "unknown type"; break;
     97		}
     98		break;
     99	case SOF_IPC_GLB_STREAM_MSG:
    100		str = "GLB_STREAM_MSG";
    101		switch (type) {
    102		case SOF_IPC_STREAM_PCM_PARAMS:
    103			str2 = "PCM_PARAMS"; break;
    104		case SOF_IPC_STREAM_PCM_PARAMS_REPLY:
    105			str2 = "PCM_REPLY"; break;
    106		case SOF_IPC_STREAM_PCM_FREE:
    107			str2 = "PCM_FREE"; break;
    108		case SOF_IPC_STREAM_TRIG_START:
    109			str2 = "TRIG_START"; break;
    110		case SOF_IPC_STREAM_TRIG_STOP:
    111			str2 = "TRIG_STOP"; break;
    112		case SOF_IPC_STREAM_TRIG_PAUSE:
    113			str2 = "TRIG_PAUSE"; break;
    114		case SOF_IPC_STREAM_TRIG_RELEASE:
    115			str2 = "TRIG_RELEASE"; break;
    116		case SOF_IPC_STREAM_TRIG_DRAIN:
    117			str2 = "TRIG_DRAIN"; break;
    118		case SOF_IPC_STREAM_TRIG_XRUN:
    119			str2 = "TRIG_XRUN"; break;
    120		case SOF_IPC_STREAM_POSITION:
    121			vdbg = true;
    122			str2 = "POSITION"; break;
    123		case SOF_IPC_STREAM_VORBIS_PARAMS:
    124			str2 = "VORBIS_PARAMS"; break;
    125		case SOF_IPC_STREAM_VORBIS_FREE:
    126			str2 = "VORBIS_FREE"; break;
    127		default:
    128			str2 = "unknown type"; break;
    129		}
    130		break;
    131	case SOF_IPC_FW_READY:
    132		str = "FW_READY"; break;
    133	case SOF_IPC_GLB_DAI_MSG:
    134		str = "GLB_DAI_MSG";
    135		switch (type) {
    136		case SOF_IPC_DAI_CONFIG:
    137			str2 = "CONFIG"; break;
    138		case SOF_IPC_DAI_LOOPBACK:
    139			str2 = "LOOPBACK"; break;
    140		default:
    141			str2 = "unknown type"; break;
    142		}
    143		break;
    144	case SOF_IPC_GLB_TRACE_MSG:
    145		str = "GLB_TRACE_MSG";
    146		switch (type) {
    147		case SOF_IPC_TRACE_DMA_PARAMS:
    148			str2 = "DMA_PARAMS"; break;
    149		case SOF_IPC_TRACE_DMA_POSITION:
    150			str2 = "DMA_POSITION"; break;
    151		case SOF_IPC_TRACE_DMA_PARAMS_EXT:
    152			str2 = "DMA_PARAMS_EXT"; break;
    153		case SOF_IPC_TRACE_FILTER_UPDATE:
    154			str2 = "FILTER_UPDATE"; break;
    155		case SOF_IPC_TRACE_DMA_FREE:
    156			str2 = "DMA_FREE"; break;
    157		default:
    158			str2 = "unknown type"; break;
    159		}
    160		break;
    161	case SOF_IPC_GLB_TEST_MSG:
    162		str = "GLB_TEST_MSG";
    163		switch (type) {
    164		case SOF_IPC_TEST_IPC_FLOOD:
    165			str2 = "IPC_FLOOD"; break;
    166		default:
    167			str2 = "unknown type"; break;
    168		}
    169		break;
    170	case SOF_IPC_GLB_DEBUG:
    171		str = "GLB_DEBUG";
    172		switch (type) {
    173		case SOF_IPC_DEBUG_MEM_USAGE:
    174			str2 = "MEM_USAGE"; break;
    175		default:
    176			str2 = "unknown type"; break;
    177		}
    178		break;
    179	case SOF_IPC_GLB_PROBE:
    180		str = "GLB_PROBE";
    181		switch (type) {
    182		case SOF_IPC_PROBE_INIT:
    183			str2 = "INIT"; break;
    184		case SOF_IPC_PROBE_DEINIT:
    185			str2 = "DEINIT"; break;
    186		case SOF_IPC_PROBE_DMA_ADD:
    187			str2 = "DMA_ADD"; break;
    188		case SOF_IPC_PROBE_DMA_INFO:
    189			str2 = "DMA_INFO"; break;
    190		case SOF_IPC_PROBE_DMA_REMOVE:
    191			str2 = "DMA_REMOVE"; break;
    192		case SOF_IPC_PROBE_POINT_ADD:
    193			str2 = "POINT_ADD"; break;
    194		case SOF_IPC_PROBE_POINT_INFO:
    195			str2 = "POINT_INFO"; break;
    196		case SOF_IPC_PROBE_POINT_REMOVE:
    197			str2 = "POINT_REMOVE"; break;
    198		default:
    199			str2 = "unknown type"; break;
    200		}
    201		break;
    202	default:
    203		str = "unknown GLB command"; break;
    204	}
    205
    206	if (str2) {
    207		if (vdbg)
    208			dev_vdbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2);
    209		else
    210			dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2);
    211	} else {
    212		dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str);
    213	}
    214}
    215#else
    216static inline void ipc3_log_header(struct device *dev, u8 *text, u32 cmd)
    217{
    218	if ((cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_TRACE_MSG)
    219		dev_dbg(dev, "%s: 0x%x\n", text, cmd);
    220}
    221#endif
    222
    223static int sof_ipc3_get_reply(struct snd_sof_dev *sdev)
    224{
    225	struct snd_sof_ipc_msg *msg = sdev->msg;
    226	struct sof_ipc_reply *reply;
    227	int ret = 0;
    228
    229	/* get the generic reply */
    230	reply = msg->reply_data;
    231	snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, reply, sizeof(*reply));
    232
    233	if (reply->error < 0)
    234		return reply->error;
    235
    236	if (!reply->hdr.size) {
    237		/* Reply should always be >= sizeof(struct sof_ipc_reply) */
    238		if (msg->reply_size)
    239			dev_err(sdev->dev,
    240				"empty reply received, expected %zu bytes\n",
    241				msg->reply_size);
    242		else
    243			dev_err(sdev->dev, "empty reply received\n");
    244
    245		return -EINVAL;
    246	}
    247
    248	if (msg->reply_size > 0) {
    249		if (reply->hdr.size == msg->reply_size) {
    250			ret = 0;
    251		} else if (reply->hdr.size < msg->reply_size) {
    252			dev_dbg(sdev->dev,
    253				"reply size (%u) is less than expected (%zu)\n",
    254				reply->hdr.size, msg->reply_size);
    255
    256			msg->reply_size = reply->hdr.size;
    257			ret = 0;
    258		} else {
    259			dev_err(sdev->dev,
    260				"reply size (%u) exceeds the buffer size (%zu)\n",
    261				reply->hdr.size, msg->reply_size);
    262			ret = -EINVAL;
    263		}
    264
    265		/*
    266		 * get the full message if reply->hdr.size <= msg->reply_size
    267		 * and the reply->hdr.size > sizeof(struct sof_ipc_reply)
    268		 */
    269		if (!ret && msg->reply_size > sizeof(*reply))
    270			snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset,
    271						 msg->reply_data, msg->reply_size);
    272	}
    273
    274	return ret;
    275}
    276
    277/* wait for IPC message reply */
    278static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
    279{
    280	struct snd_sof_ipc_msg *msg = &ipc->msg;
    281	struct sof_ipc_cmd_hdr *hdr = msg->msg_data;
    282	struct snd_sof_dev *sdev = ipc->sdev;
    283	int ret;
    284
    285	/* wait for DSP IPC completion */
    286	ret = wait_event_timeout(msg->waitq, msg->ipc_complete,
    287				 msecs_to_jiffies(sdev->ipc_timeout));
    288
    289	if (ret == 0) {
    290		dev_err(sdev->dev,
    291			"ipc tx timed out for %#x (msg/reply size: %d/%zu)\n",
    292			hdr->cmd, hdr->size, msg->reply_size);
    293		snd_sof_handle_fw_exception(ipc->sdev);
    294		ret = -ETIMEDOUT;
    295	} else {
    296		ret = msg->reply_error;
    297		if (ret < 0) {
    298			dev_err(sdev->dev,
    299				"ipc tx error for %#x (msg/reply size: %d/%zu): %d\n",
    300				hdr->cmd, hdr->size, msg->reply_size, ret);
    301		} else {
    302			ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
    303			if (msg->reply_size)
    304				/* copy the data returned from DSP */
    305				memcpy(reply_data, msg->reply_data,
    306				       msg->reply_size);
    307		}
    308
    309		/* re-enable dumps after successful IPC tx */
    310		if (sdev->ipc_dump_printed) {
    311			sdev->dbg_dump_printed = false;
    312			sdev->ipc_dump_printed = false;
    313		}
    314	}
    315
    316	return ret;
    317}
    318
    319/* send IPC message from host to DSP */
    320static int ipc3_tx_msg_unlocked(struct snd_sof_ipc *ipc,
    321				void *msg_data, size_t msg_bytes,
    322				void *reply_data, size_t reply_bytes)
    323{
    324	struct sof_ipc_cmd_hdr *hdr = msg_data;
    325	struct snd_sof_dev *sdev = ipc->sdev;
    326	int ret;
    327
    328	ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
    329
    330	if (ret) {
    331		dev_err_ratelimited(sdev->dev,
    332				    "%s: ipc message send for %#x failed: %d\n",
    333				    __func__, hdr->cmd, ret);
    334		return ret;
    335	}
    336
    337	ipc3_log_header(sdev->dev, "ipc tx", hdr->cmd);
    338
    339	/* now wait for completion */
    340	return ipc3_wait_tx_done(ipc, reply_data);
    341}
    342
    343static int sof_ipc3_tx_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
    344			   void *reply_data, size_t reply_bytes, bool no_pm)
    345{
    346	struct snd_sof_ipc *ipc = sdev->ipc;
    347	int ret;
    348
    349	if (!msg_data || msg_bytes < sizeof(struct sof_ipc_cmd_hdr)) {
    350		dev_err_ratelimited(sdev->dev, "No IPC message to send\n");
    351		return -EINVAL;
    352	}
    353
    354	if (!no_pm) {
    355		const struct sof_dsp_power_state target_state = {
    356			.state = SOF_DSP_PM_D0,
    357		};
    358
    359		/* ensure the DSP is in D0 before sending a new IPC */
    360		ret = snd_sof_dsp_set_power_state(sdev, &target_state);
    361		if (ret < 0) {
    362			dev_err(sdev->dev, "%s: resuming DSP failed: %d\n",
    363				__func__, ret);
    364			return ret;
    365		}
    366	}
    367
    368	/* Serialise IPC TX */
    369	mutex_lock(&ipc->tx_mutex);
    370
    371	ret = ipc3_tx_msg_unlocked(ipc, msg_data, msg_bytes, reply_data, reply_bytes);
    372
    373	mutex_unlock(&ipc->tx_mutex);
    374
    375	return ret;
    376}
    377
    378static int sof_ipc3_set_get_data(struct snd_sof_dev *sdev, void *data, size_t data_bytes,
    379				 bool set)
    380{
    381	size_t msg_bytes, hdr_bytes, payload_size, send_bytes;
    382	struct sof_ipc_ctrl_data *cdata = data;
    383	struct sof_ipc_ctrl_data *cdata_chunk;
    384	struct snd_sof_ipc *ipc = sdev->ipc;
    385	size_t offset = 0;
    386	u8 *src, *dst;
    387	u32 num_msg;
    388	int ret = 0;
    389	int i;
    390
    391	if (!cdata || data_bytes < sizeof(*cdata))
    392		return -EINVAL;
    393
    394	if ((cdata->rhdr.hdr.cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_COMP_MSG) {
    395		dev_err(sdev->dev, "%s: Not supported message type of %#x\n",
    396			__func__, cdata->rhdr.hdr.cmd);
    397		return -EINVAL;
    398	}
    399
    400	/* send normal size ipc in one part */
    401	if (cdata->rhdr.hdr.size <= ipc->max_payload_size)
    402		return sof_ipc3_tx_msg(sdev, cdata, cdata->rhdr.hdr.size,
    403				       cdata, cdata->rhdr.hdr.size, false);
    404
    405	cdata_chunk = kzalloc(ipc->max_payload_size, GFP_KERNEL);
    406	if (!cdata_chunk)
    407		return -ENOMEM;
    408
    409	switch (cdata->type) {
    410	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
    411	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
    412		hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
    413		if (set) {
    414			src = (u8 *)cdata->chanv;
    415			dst = (u8 *)cdata_chunk->chanv;
    416		} else {
    417			src = (u8 *)cdata_chunk->chanv;
    418			dst = (u8 *)cdata->chanv;
    419		}
    420		break;
    421	case SOF_CTRL_TYPE_DATA_GET:
    422	case SOF_CTRL_TYPE_DATA_SET:
    423		hdr_bytes = sizeof(struct sof_ipc_ctrl_data) + sizeof(struct sof_abi_hdr);
    424		if (set) {
    425			src = (u8 *)cdata->data->data;
    426			dst = (u8 *)cdata_chunk->data->data;
    427		} else {
    428			src = (u8 *)cdata_chunk->data->data;
    429			dst = (u8 *)cdata->data->data;
    430		}
    431		break;
    432	default:
    433		kfree(cdata_chunk);
    434		return -EINVAL;
    435	}
    436
    437	msg_bytes = cdata->rhdr.hdr.size - hdr_bytes;
    438	payload_size = ipc->max_payload_size - hdr_bytes;
    439	num_msg = DIV_ROUND_UP(msg_bytes, payload_size);
    440
    441	/* copy the header data */
    442	memcpy(cdata_chunk, cdata, hdr_bytes);
    443
    444	/* Serialise IPC TX */
    445	mutex_lock(&sdev->ipc->tx_mutex);
    446
    447	/* copy the payload data in a loop */
    448	for (i = 0; i < num_msg; i++) {
    449		send_bytes = min(msg_bytes, payload_size);
    450		cdata_chunk->num_elems = send_bytes;
    451		cdata_chunk->rhdr.hdr.size = hdr_bytes + send_bytes;
    452		cdata_chunk->msg_index = i;
    453		msg_bytes -= send_bytes;
    454		cdata_chunk->elems_remaining = msg_bytes;
    455
    456		if (set)
    457			memcpy(dst, src + offset, send_bytes);
    458
    459		ret = ipc3_tx_msg_unlocked(sdev->ipc,
    460					   cdata_chunk, cdata_chunk->rhdr.hdr.size,
    461					   cdata_chunk, cdata_chunk->rhdr.hdr.size);
    462		if (ret < 0)
    463			break;
    464
    465		if (!set)
    466			memcpy(dst + offset, src, send_bytes);
    467
    468		offset += payload_size;
    469	}
    470
    471	mutex_unlock(&sdev->ipc->tx_mutex);
    472
    473	kfree(cdata_chunk);
    474
    475	return ret;
    476}
    477
    478int 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
    503int 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 */
    549static 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
    611static 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
    725static 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
    738int sof_ipc3_validate_fw_version(struct snd_sof_dev *sdev)
    739{
    740	struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
    741	struct sof_ipc_fw_version *v = &ready->version;
    742
    743	dev_info(sdev->dev,
    744		 "Firmware info: version %d:%d:%d-%s\n",  v->major, v->minor,
    745		 v->micro, v->tag);
    746	dev_info(sdev->dev,
    747		 "Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
    748		 SOF_ABI_VERSION_MAJOR(v->abi_version),
    749		 SOF_ABI_VERSION_MINOR(v->abi_version),
    750		 SOF_ABI_VERSION_PATCH(v->abi_version),
    751		 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
    752
    753	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) {
    754		dev_err(sdev->dev, "incompatible FW ABI version\n");
    755		return -EINVAL;
    756	}
    757
    758	if (SOF_ABI_VERSION_MINOR(v->abi_version) > SOF_ABI_MINOR) {
    759		if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
    760			dev_warn(sdev->dev, "FW ABI is more recent than kernel\n");
    761		} else {
    762			dev_err(sdev->dev, "FW ABI is more recent than kernel\n");
    763			return -EINVAL;
    764		}
    765	}
    766
    767	if (ready->flags & SOF_IPC_INFO_BUILD) {
    768		dev_info(sdev->dev,
    769			 "Firmware debug build %d on %s-%s - options:\n"
    770			 " GDB: %s\n"
    771			 " lock debug: %s\n"
    772			 " lock vdebug: %s\n",
    773			 v->build, v->date, v->time,
    774			 (ready->flags & SOF_IPC_INFO_GDB) ?
    775				"enabled" : "disabled",
    776			 (ready->flags & SOF_IPC_INFO_LOCKS) ?
    777				"enabled" : "disabled",
    778			 (ready->flags & SOF_IPC_INFO_LOCKSV) ?
    779				"enabled" : "disabled");
    780	}
    781
    782	/* copy the fw_version into debugfs at first boot */
    783	memcpy(&sdev->fw_version, v, sizeof(*v));
    784
    785	return 0;
    786}
    787
    788static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd)
    789{
    790	struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
    791	int offset;
    792	int ret;
    793
    794	/* mailbox must be on 4k boundary */
    795	offset = snd_sof_dsp_get_mailbox_offset(sdev);
    796	if (offset < 0) {
    797		dev_err(sdev->dev, "%s: no mailbox offset\n", __func__);
    798		return offset;
    799	}
    800
    801	dev_dbg(sdev->dev, "DSP is ready 0x%8.8x offset 0x%x\n", cmd, offset);
    802
    803	/* no need to re-check version/ABI for subsequent boots */
    804	if (!sdev->first_boot)
    805		return 0;
    806
    807	/*
    808	 * copy data from the DSP FW ready offset
    809	 * Subsequent error handling is not needed for BLK_TYPE_SRAM
    810	 */
    811	ret = snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, fw_ready,
    812				     sizeof(*fw_ready));
    813	if (ret) {
    814		dev_err(sdev->dev,
    815			"Unable to read fw_ready, read from TYPE_SRAM failed\n");
    816		return ret;
    817	}
    818
    819	/* make sure ABI version is compatible */
    820	ret = sof_ipc3_validate_fw_version(sdev);
    821	if (ret < 0)
    822		return ret;
    823
    824	/* now check for extended data */
    825	ipc3_fw_parse_ext_data(sdev, offset + sizeof(struct sof_ipc_fw_ready));
    826
    827	ipc3_get_windows(sdev);
    828
    829	return ipc3_init_reply_data_buffer(sdev);
    830}
    831
    832/* IPC stream position. */
    833static void ipc3_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
    834{
    835	struct snd_soc_component *scomp = sdev->component;
    836	struct snd_sof_pcm_stream *stream;
    837	struct sof_ipc_stream_posn posn;
    838	struct snd_sof_pcm *spcm;
    839	int direction, ret;
    840
    841	spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
    842	if (!spcm) {
    843		dev_err(sdev->dev, "period elapsed for unknown stream, msg_id %d\n",
    844			msg_id);
    845		return;
    846	}
    847
    848	stream = &spcm->stream[direction];
    849	ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
    850	if (ret < 0) {
    851		dev_warn(sdev->dev, "failed to read stream position: %d\n", ret);
    852		return;
    853	}
    854
    855	dev_vdbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n",
    856		 posn.host_posn, posn.dai_posn, posn.wallclock);
    857
    858	memcpy(&stream->posn, &posn, sizeof(posn));
    859
    860	if (spcm->pcm.compress)
    861		snd_sof_compr_fragment_elapsed(stream->cstream);
    862	else if (stream->substream->runtime &&
    863		 !stream->substream->runtime->no_period_wakeup)
    864		/* only inform ALSA for period_wakeup mode */
    865		snd_sof_pcm_period_elapsed(stream->substream);
    866}
    867
    868/* DSP notifies host of an XRUN within FW */
    869static void ipc3_xrun(struct snd_sof_dev *sdev, u32 msg_id)
    870{
    871	struct snd_soc_component *scomp = sdev->component;
    872	struct snd_sof_pcm_stream *stream;
    873	struct sof_ipc_stream_posn posn;
    874	struct snd_sof_pcm *spcm;
    875	int direction, ret;
    876
    877	spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
    878	if (!spcm) {
    879		dev_err(sdev->dev, "XRUN for unknown stream, msg_id %d\n",
    880			msg_id);
    881		return;
    882	}
    883
    884	stream = &spcm->stream[direction];
    885	ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
    886	if (ret < 0) {
    887		dev_warn(sdev->dev, "failed to read overrun position: %d\n", ret);
    888		return;
    889	}
    890
    891	dev_dbg(sdev->dev,  "posn XRUN: host %llx comp %d size %d\n",
    892		posn.host_posn, posn.xrun_comp_id, posn.xrun_size);
    893
    894#if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP)
    895	/* stop PCM on XRUN - used for pipeline debug */
    896	memcpy(&stream->posn, &posn, sizeof(posn));
    897	snd_pcm_stop_xrun(stream->substream);
    898#endif
    899}
    900
    901/* stream notifications from firmware */
    902static void ipc3_stream_message(struct snd_sof_dev *sdev, void *msg_buf)
    903{
    904	struct sof_ipc_cmd_hdr *hdr = msg_buf;
    905	u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK;
    906	u32 msg_id = SOF_IPC_MESSAGE_ID(hdr->cmd);
    907
    908	switch (msg_type) {
    909	case SOF_IPC_STREAM_POSITION:
    910		ipc3_period_elapsed(sdev, msg_id);
    911		break;
    912	case SOF_IPC_STREAM_TRIG_XRUN:
    913		ipc3_xrun(sdev, msg_id);
    914		break;
    915	default:
    916		dev_err(sdev->dev, "unhandled stream message %#x\n",
    917			msg_id);
    918		break;
    919	}
    920}
    921
    922/* component notifications from firmware */
    923static void ipc3_comp_notification(struct snd_sof_dev *sdev, void *msg_buf)
    924{
    925	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
    926	struct sof_ipc_cmd_hdr *hdr = msg_buf;
    927	u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK;
    928
    929	switch (msg_type) {
    930	case SOF_IPC_COMP_GET_VALUE:
    931	case SOF_IPC_COMP_GET_DATA:
    932		break;
    933	default:
    934		dev_err(sdev->dev, "unhandled component message %#x\n", msg_type);
    935		return;
    936	}
    937
    938	if (tplg_ops->control->update)
    939		tplg_ops->control->update(sdev, msg_buf);
    940}
    941
    942static void ipc3_trace_message(struct snd_sof_dev *sdev, void *msg_buf)
    943{
    944	struct sof_ipc_cmd_hdr *hdr = msg_buf;
    945	u32 msg_type = hdr->cmd & SOF_CMD_TYPE_MASK;
    946
    947	switch (msg_type) {
    948	case SOF_IPC_TRACE_DMA_POSITION:
    949		ipc3_dtrace_posn_update(sdev, msg_buf);
    950		break;
    951	default:
    952		dev_err(sdev->dev, "unhandled trace message %#x\n", msg_type);
    953		break;
    954	}
    955}
    956
    957/* DSP firmware has sent host a message  */
    958static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
    959{
    960	ipc3_rx_callback rx_callback = NULL;
    961	struct sof_ipc_cmd_hdr hdr;
    962	void *msg_buf;
    963	u32 cmd;
    964	int err;
    965
    966	/* read back header */
    967	err = snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr));
    968	if (err < 0) {
    969		dev_warn(sdev->dev, "failed to read IPC header: %d\n", err);
    970		return;
    971	}
    972
    973	if (hdr.size < sizeof(hdr)) {
    974		dev_err(sdev->dev, "The received message size is invalid\n");
    975		return;
    976	}
    977
    978	ipc3_log_header(sdev->dev, "ipc rx", hdr.cmd);
    979
    980	cmd = hdr.cmd & SOF_GLB_TYPE_MASK;
    981
    982	/* check message type */
    983	switch (cmd) {
    984	case SOF_IPC_GLB_REPLY:
    985		dev_err(sdev->dev, "ipc reply unknown\n");
    986		break;
    987	case SOF_IPC_FW_READY:
    988		/* check for FW boot completion */
    989		if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) {
    990			err = ipc3_fw_ready(sdev, cmd);
    991			if (err < 0)
    992				sof_set_fw_state(sdev, SOF_FW_BOOT_READY_FAILED);
    993			else
    994				sof_set_fw_state(sdev, SOF_FW_BOOT_READY_OK);
    995
    996			/* wake up firmware loader */
    997			wake_up(&sdev->boot_wait);
    998		}
    999		break;
   1000	case SOF_IPC_GLB_COMPOUND:
   1001	case SOF_IPC_GLB_TPLG_MSG:
   1002	case SOF_IPC_GLB_PM_MSG:
   1003		break;
   1004	case SOF_IPC_GLB_COMP_MSG:
   1005		rx_callback = ipc3_comp_notification;
   1006		break;
   1007	case SOF_IPC_GLB_STREAM_MSG:
   1008		rx_callback = ipc3_stream_message;
   1009		break;
   1010	case SOF_IPC_GLB_TRACE_MSG:
   1011		rx_callback = ipc3_trace_message;
   1012		break;
   1013	default:
   1014		dev_err(sdev->dev, "%s: Unknown DSP message: 0x%x\n", __func__, cmd);
   1015		break;
   1016	}
   1017
   1018	/* read the full message */
   1019	msg_buf = kmalloc(hdr.size, GFP_KERNEL);
   1020	if (!msg_buf)
   1021		return;
   1022
   1023	err = snd_sof_ipc_msg_data(sdev, NULL, msg_buf, hdr.size);
   1024	if (err < 0) {
   1025		dev_err(sdev->dev, "%s: Failed to read message: %d\n", __func__, err);
   1026	} else {
   1027		/* Call local handler for the message */
   1028		if (rx_callback)
   1029			rx_callback(sdev, msg_buf);
   1030
   1031		/* Notify registered clients */
   1032		sof_client_ipc_rx_dispatcher(sdev, msg_buf);
   1033	}
   1034
   1035	kfree(msg_buf);
   1036
   1037	ipc3_log_header(sdev->dev, "ipc rx done", hdr.cmd);
   1038}
   1039
   1040static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
   1041{
   1042	struct sof_ipc_pm_ctx pm_ctx = {
   1043		.hdr.size = sizeof(pm_ctx),
   1044		.hdr.cmd = SOF_IPC_GLB_PM_MSG | cmd,
   1045	};
   1046	struct sof_ipc_reply reply;
   1047
   1048	/* send ctx save ipc to dsp */
   1049	return sof_ipc3_tx_msg(sdev, &pm_ctx, sizeof(pm_ctx),
   1050			       &reply, sizeof(reply), false);
   1051}
   1052
   1053static int sof_ipc3_ctx_save(struct snd_sof_dev *sdev)
   1054{
   1055	return sof_ipc3_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
   1056}
   1057
   1058static int sof_ipc3_ctx_restore(struct snd_sof_dev *sdev)
   1059{
   1060	return sof_ipc3_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE);
   1061}
   1062
   1063static const struct sof_ipc_pm_ops ipc3_pm_ops = {
   1064	.ctx_save = sof_ipc3_ctx_save,
   1065	.ctx_restore = sof_ipc3_ctx_restore,
   1066};
   1067
   1068const struct sof_ipc_ops ipc3_ops = {
   1069	.tplg = &ipc3_tplg_ops,
   1070	.pm = &ipc3_pm_ops,
   1071	.pcm = &ipc3_pcm_ops,
   1072	.fw_loader = &ipc3_loader_ops,
   1073	.fw_tracing = &ipc3_dtrace_ops,
   1074
   1075	.tx_msg = sof_ipc3_tx_msg,
   1076	.rx_msg = sof_ipc3_rx_msg,
   1077	.set_get_data = sof_ipc3_set_get_data,
   1078	.get_reply = sof_ipc3_get_reply,
   1079};