Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
   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 <trace/events/sof.h>
  13#include "sof-priv.h"
  14#include "sof-audio.h"
  15#include "ipc3-priv.h"
  16#include "ops.h"
  17
  18typedef void (*ipc3_rx_callback)(struct snd_sof_dev *sdev, void *msg_buf);
  19
  20#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC)
  21static void ipc3_log_header(struct device *dev, u8 *text, u32 cmd)
  22{
  23	u8 *str;
  24	u8 *str2 = NULL;
  25	u32 glb;
  26	u32 type;
  27	bool is_sof_ipc_stream_position = false;
  28
  29	glb = cmd & SOF_GLB_TYPE_MASK;
  30	type = cmd & SOF_CMD_TYPE_MASK;
  31
  32	switch (glb) {
  33	case SOF_IPC_GLB_REPLY:
  34		str = "GLB_REPLY"; break;
  35	case SOF_IPC_GLB_COMPOUND:
  36		str = "GLB_COMPOUND"; break;
  37	case SOF_IPC_GLB_TPLG_MSG:
  38		str = "GLB_TPLG_MSG";
  39		switch (type) {
  40		case SOF_IPC_TPLG_COMP_NEW:
  41			str2 = "COMP_NEW"; break;
  42		case SOF_IPC_TPLG_COMP_FREE:
  43			str2 = "COMP_FREE"; break;
  44		case SOF_IPC_TPLG_COMP_CONNECT:
  45			str2 = "COMP_CONNECT"; break;
  46		case SOF_IPC_TPLG_PIPE_NEW:
  47			str2 = "PIPE_NEW"; break;
  48		case SOF_IPC_TPLG_PIPE_FREE:
  49			str2 = "PIPE_FREE"; break;
  50		case SOF_IPC_TPLG_PIPE_CONNECT:
  51			str2 = "PIPE_CONNECT"; break;
  52		case SOF_IPC_TPLG_PIPE_COMPLETE:
  53			str2 = "PIPE_COMPLETE"; break;
  54		case SOF_IPC_TPLG_BUFFER_NEW:
  55			str2 = "BUFFER_NEW"; break;
  56		case SOF_IPC_TPLG_BUFFER_FREE:
  57			str2 = "BUFFER_FREE"; break;
  58		default:
  59			str2 = "unknown type"; break;
  60		}
  61		break;
  62	case SOF_IPC_GLB_PM_MSG:
  63		str = "GLB_PM_MSG";
  64		switch (type) {
  65		case SOF_IPC_PM_CTX_SAVE:
  66			str2 = "CTX_SAVE"; break;
  67		case SOF_IPC_PM_CTX_RESTORE:
  68			str2 = "CTX_RESTORE"; break;
  69		case SOF_IPC_PM_CTX_SIZE:
  70			str2 = "CTX_SIZE"; break;
  71		case SOF_IPC_PM_CLK_SET:
  72			str2 = "CLK_SET"; break;
  73		case SOF_IPC_PM_CLK_GET:
  74			str2 = "CLK_GET"; break;
  75		case SOF_IPC_PM_CLK_REQ:
  76			str2 = "CLK_REQ"; break;
  77		case SOF_IPC_PM_CORE_ENABLE:
  78			str2 = "CORE_ENABLE"; break;
  79		case SOF_IPC_PM_GATE:
  80			str2 = "GATE"; break;
  81		default:
  82			str2 = "unknown type"; break;
  83		}
  84		break;
  85	case SOF_IPC_GLB_COMP_MSG:
  86		str = "GLB_COMP_MSG";
  87		switch (type) {
  88		case SOF_IPC_COMP_SET_VALUE:
  89			str2 = "SET_VALUE"; break;
  90		case SOF_IPC_COMP_GET_VALUE:
  91			str2 = "GET_VALUE"; break;
  92		case SOF_IPC_COMP_SET_DATA:
  93			str2 = "SET_DATA"; break;
  94		case SOF_IPC_COMP_GET_DATA:
  95			str2 = "GET_DATA"; break;
  96		default:
  97			str2 = "unknown type"; break;
  98		}
  99		break;
 100	case SOF_IPC_GLB_STREAM_MSG:
 101		str = "GLB_STREAM_MSG";
 102		switch (type) {
 103		case SOF_IPC_STREAM_PCM_PARAMS:
 104			str2 = "PCM_PARAMS"; break;
 105		case SOF_IPC_STREAM_PCM_PARAMS_REPLY:
 106			str2 = "PCM_REPLY"; break;
 107		case SOF_IPC_STREAM_PCM_FREE:
 108			str2 = "PCM_FREE"; break;
 109		case SOF_IPC_STREAM_TRIG_START:
 110			str2 = "TRIG_START"; break;
 111		case SOF_IPC_STREAM_TRIG_STOP:
 112			str2 = "TRIG_STOP"; break;
 113		case SOF_IPC_STREAM_TRIG_PAUSE:
 114			str2 = "TRIG_PAUSE"; break;
 115		case SOF_IPC_STREAM_TRIG_RELEASE:
 116			str2 = "TRIG_RELEASE"; break;
 117		case SOF_IPC_STREAM_TRIG_DRAIN:
 118			str2 = "TRIG_DRAIN"; break;
 119		case SOF_IPC_STREAM_TRIG_XRUN:
 120			str2 = "TRIG_XRUN"; break;
 121		case SOF_IPC_STREAM_POSITION:
 122			is_sof_ipc_stream_position = true;
 123			str2 = "POSITION"; break;
 124		case SOF_IPC_STREAM_VORBIS_PARAMS:
 125			str2 = "VORBIS_PARAMS"; break;
 126		case SOF_IPC_STREAM_VORBIS_FREE:
 127			str2 = "VORBIS_FREE"; break;
 128		default:
 129			str2 = "unknown type"; break;
 130		}
 131		break;
 132	case SOF_IPC_FW_READY:
 133		str = "FW_READY"; break;
 134	case SOF_IPC_GLB_DAI_MSG:
 135		str = "GLB_DAI_MSG";
 136		switch (type) {
 137		case SOF_IPC_DAI_CONFIG:
 138			str2 = "CONFIG"; break;
 139		case SOF_IPC_DAI_LOOPBACK:
 140			str2 = "LOOPBACK"; break;
 141		default:
 142			str2 = "unknown type"; break;
 143		}
 144		break;
 145	case SOF_IPC_GLB_TRACE_MSG:
 146		str = "GLB_TRACE_MSG";
 147		switch (type) {
 148		case SOF_IPC_TRACE_DMA_PARAMS:
 149			str2 = "DMA_PARAMS"; break;
 150		case SOF_IPC_TRACE_DMA_POSITION:
 151			if (!sof_debug_check_flag(SOF_DBG_PRINT_DMA_POSITION_UPDATE_LOGS))
 152				return;
 153			str2 = "DMA_POSITION"; break;
 154		case SOF_IPC_TRACE_DMA_PARAMS_EXT:
 155			str2 = "DMA_PARAMS_EXT"; break;
 156		case SOF_IPC_TRACE_FILTER_UPDATE:
 157			str2 = "FILTER_UPDATE"; break;
 158		case SOF_IPC_TRACE_DMA_FREE:
 159			str2 = "DMA_FREE"; break;
 160		default:
 161			str2 = "unknown type"; break;
 162		}
 163		break;
 164	case SOF_IPC_GLB_TEST_MSG:
 165		str = "GLB_TEST_MSG";
 166		switch (type) {
 167		case SOF_IPC_TEST_IPC_FLOOD:
 168			str2 = "IPC_FLOOD"; break;
 169		default:
 170			str2 = "unknown type"; break;
 171		}
 172		break;
 173	case SOF_IPC_GLB_DEBUG:
 174		str = "GLB_DEBUG";
 175		switch (type) {
 176		case SOF_IPC_DEBUG_MEM_USAGE:
 177			str2 = "MEM_USAGE"; break;
 178		default:
 179			str2 = "unknown type"; break;
 180		}
 181		break;
 182	case SOF_IPC_GLB_PROBE:
 183		str = "GLB_PROBE";
 184		switch (type) {
 185		case SOF_IPC_PROBE_INIT:
 186			str2 = "INIT"; break;
 187		case SOF_IPC_PROBE_DEINIT:
 188			str2 = "DEINIT"; break;
 189		case SOF_IPC_PROBE_DMA_ADD:
 190			str2 = "DMA_ADD"; break;
 191		case SOF_IPC_PROBE_DMA_INFO:
 192			str2 = "DMA_INFO"; break;
 193		case SOF_IPC_PROBE_DMA_REMOVE:
 194			str2 = "DMA_REMOVE"; break;
 195		case SOF_IPC_PROBE_POINT_ADD:
 196			str2 = "POINT_ADD"; break;
 197		case SOF_IPC_PROBE_POINT_INFO:
 198			str2 = "POINT_INFO"; break;
 199		case SOF_IPC_PROBE_POINT_REMOVE:
 200			str2 = "POINT_REMOVE"; break;
 201		default:
 202			str2 = "unknown type"; break;
 203		}
 204		break;
 205	default:
 206		str = "unknown GLB command"; break;
 207	}
 208
 209	if (str2) {
 210		if (is_sof_ipc_stream_position)
 211			trace_sof_stream_position_ipc_rx(dev);
 212		else
 213			dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2);
 214	} else {
 215		dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str);
 216	}
 217}
 218#else
 219static inline void ipc3_log_header(struct device *dev, u8 *text, u32 cmd)
 220{
 221	if ((cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_TRACE_MSG)
 222		dev_dbg(dev, "%s: 0x%x\n", text, cmd);
 223}
 224#endif
 225
 226static int sof_ipc3_get_reply(struct snd_sof_dev *sdev)
 227{
 228	struct snd_sof_ipc_msg *msg = sdev->msg;
 229	struct sof_ipc_reply *reply;
 230	int ret = 0;
 231
 232	/* get the generic reply */
 233	reply = msg->reply_data;
 234	snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset, reply, sizeof(*reply));
 235
 236	if (reply->error < 0)
 237		return reply->error;
 238
 239	if (!reply->hdr.size) {
 240		/* Reply should always be >= sizeof(struct sof_ipc_reply) */
 241		if (msg->reply_size)
 242			dev_err(sdev->dev,
 243				"empty reply received, expected %zu bytes\n",
 244				msg->reply_size);
 245		else
 246			dev_err(sdev->dev, "empty reply received\n");
 247
 248		return -EINVAL;
 249	}
 250
 251	if (msg->reply_size > 0) {
 252		if (reply->hdr.size == msg->reply_size) {
 253			ret = 0;
 254		} else if (reply->hdr.size < msg->reply_size) {
 255			dev_dbg(sdev->dev,
 256				"reply size (%u) is less than expected (%zu)\n",
 257				reply->hdr.size, msg->reply_size);
 258
 259			msg->reply_size = reply->hdr.size;
 260			ret = 0;
 261		} else {
 262			dev_err(sdev->dev,
 263				"reply size (%u) exceeds the buffer size (%zu)\n",
 264				reply->hdr.size, msg->reply_size);
 265			ret = -EINVAL;
 266		}
 267
 268		/*
 269		 * get the full message if reply->hdr.size <= msg->reply_size
 270		 * and the reply->hdr.size > sizeof(struct sof_ipc_reply)
 271		 */
 272		if (!ret && msg->reply_size > sizeof(*reply))
 273			snd_sof_dsp_mailbox_read(sdev, sdev->host_box.offset,
 274						 msg->reply_data, msg->reply_size);
 275	}
 276
 277	return ret;
 278}
 279
 280/* wait for IPC message reply */
 281static int ipc3_wait_tx_done(struct snd_sof_ipc *ipc, void *reply_data)
 282{
 283	struct snd_sof_ipc_msg *msg = &ipc->msg;
 284	struct sof_ipc_cmd_hdr *hdr = msg->msg_data;
 285	struct snd_sof_dev *sdev = ipc->sdev;
 286	int ret;
 287
 288	/* wait for DSP IPC completion */
 289	ret = wait_event_timeout(msg->waitq, msg->ipc_complete,
 290				 msecs_to_jiffies(sdev->ipc_timeout));
 291
 292	if (ret == 0) {
 293		dev_err(sdev->dev,
 294			"ipc tx timed out for %#x (msg/reply size: %d/%zu)\n",
 295			hdr->cmd, hdr->size, msg->reply_size);
 296		snd_sof_handle_fw_exception(ipc->sdev, "IPC timeout");
 297		ret = -ETIMEDOUT;
 298	} else {
 299		ret = msg->reply_error;
 300		if (ret < 0) {
 301			dev_err(sdev->dev,
 302				"ipc tx error for %#x (msg/reply size: %d/%zu): %d\n",
 303				hdr->cmd, hdr->size, msg->reply_size, ret);
 304		} else {
 305			if (sof_debug_check_flag(SOF_DBG_PRINT_IPC_SUCCESS_LOGS))
 306				ipc3_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
 307			if (msg->reply_size)
 308				/* copy the data returned from DSP */
 309				memcpy(reply_data, msg->reply_data,
 310				       msg->reply_size);
 311		}
 312
 313		/* re-enable dumps after successful IPC tx */
 314		if (sdev->ipc_dump_printed) {
 315			sdev->dbg_dump_printed = false;
 316			sdev->ipc_dump_printed = false;
 317		}
 318	}
 319
 320	return ret;
 321}
 322
 323/* send IPC message from host to DSP */
 324static int ipc3_tx_msg_unlocked(struct snd_sof_ipc *ipc,
 325				void *msg_data, size_t msg_bytes,
 326				void *reply_data, size_t reply_bytes)
 327{
 328	struct sof_ipc_cmd_hdr *hdr = msg_data;
 329	struct snd_sof_dev *sdev = ipc->sdev;
 330	int ret;
 331
 332	ipc3_log_header(sdev->dev, "ipc tx", hdr->cmd);
 333
 334	ret = sof_ipc_send_msg(sdev, msg_data, msg_bytes, reply_bytes);
 335
 336	if (ret) {
 337		dev_err_ratelimited(sdev->dev,
 338				    "%s: ipc message send for %#x failed: %d\n",
 339				    __func__, hdr->cmd, ret);
 340		return ret;
 341	}
 342
 343	/* now wait for completion */
 344	return ipc3_wait_tx_done(ipc, reply_data);
 345}
 346
 347static int sof_ipc3_tx_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
 348			   void *reply_data, size_t reply_bytes, bool no_pm)
 349{
 350	struct snd_sof_ipc *ipc = sdev->ipc;
 351	int ret;
 352
 353	if (!msg_data || msg_bytes < sizeof(struct sof_ipc_cmd_hdr)) {
 354		dev_err_ratelimited(sdev->dev, "No IPC message to send\n");
 355		return -EINVAL;
 356	}
 357
 358	if (!no_pm) {
 359		const struct sof_dsp_power_state target_state = {
 360			.state = SOF_DSP_PM_D0,
 361		};
 362
 363		/* ensure the DSP is in D0 before sending a new IPC */
 364		ret = snd_sof_dsp_set_power_state(sdev, &target_state);
 365		if (ret < 0) {
 366			dev_err(sdev->dev, "%s: resuming DSP failed: %d\n",
 367				__func__, ret);
 368			return ret;
 369		}
 370	}
 371
 372	/* Serialise IPC TX */
 373	mutex_lock(&ipc->tx_mutex);
 374
 375	ret = ipc3_tx_msg_unlocked(ipc, msg_data, msg_bytes, reply_data, reply_bytes);
 376
 377	mutex_unlock(&ipc->tx_mutex);
 378
 379	return ret;
 380}
 381
 382static int sof_ipc3_set_get_data(struct snd_sof_dev *sdev, void *data, size_t data_bytes,
 383				 bool set)
 384{
 385	size_t msg_bytes, hdr_bytes, payload_size, send_bytes;
 386	struct sof_ipc_ctrl_data *cdata = data;
 387	struct sof_ipc_ctrl_data *cdata_chunk;
 388	struct snd_sof_ipc *ipc = sdev->ipc;
 389	size_t offset = 0;
 390	u8 *src, *dst;
 391	u32 num_msg;
 392	int ret = 0;
 393	int i;
 394
 395	if (!cdata || data_bytes < sizeof(*cdata))
 396		return -EINVAL;
 397
 398	if ((cdata->rhdr.hdr.cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_COMP_MSG) {
 399		dev_err(sdev->dev, "%s: Not supported message type of %#x\n",
 400			__func__, cdata->rhdr.hdr.cmd);
 401		return -EINVAL;
 402	}
 403
 404	/* send normal size ipc in one part */
 405	if (cdata->rhdr.hdr.size <= ipc->max_payload_size)
 406		return sof_ipc3_tx_msg(sdev, cdata, cdata->rhdr.hdr.size,
 407				       cdata, cdata->rhdr.hdr.size, false);
 408
 409	cdata_chunk = kzalloc(ipc->max_payload_size, GFP_KERNEL);
 410	if (!cdata_chunk)
 411		return -ENOMEM;
 412
 413	switch (cdata->type) {
 414	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
 415	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
 416		hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
 417		if (set) {
 418			src = (u8 *)cdata->chanv;
 419			dst = (u8 *)cdata_chunk->chanv;
 420		} else {
 421			src = (u8 *)cdata_chunk->chanv;
 422			dst = (u8 *)cdata->chanv;
 423		}
 424		break;
 425	case SOF_CTRL_TYPE_DATA_GET:
 426	case SOF_CTRL_TYPE_DATA_SET:
 427		hdr_bytes = sizeof(struct sof_ipc_ctrl_data) + sizeof(struct sof_abi_hdr);
 428		if (set) {
 429			src = (u8 *)cdata->data->data;
 430			dst = (u8 *)cdata_chunk->data->data;
 431		} else {
 432			src = (u8 *)cdata_chunk->data->data;
 433			dst = (u8 *)cdata->data->data;
 434		}
 435		break;
 436	default:
 437		kfree(cdata_chunk);
 438		return -EINVAL;
 439	}
 440
 441	msg_bytes = cdata->rhdr.hdr.size - hdr_bytes;
 442	payload_size = ipc->max_payload_size - hdr_bytes;
 443	num_msg = DIV_ROUND_UP(msg_bytes, payload_size);
 444
 445	/* copy the header data */
 446	memcpy(cdata_chunk, cdata, hdr_bytes);
 447
 448	/* Serialise IPC TX */
 449	mutex_lock(&sdev->ipc->tx_mutex);
 450
 451	/* copy the payload data in a loop */
 452	for (i = 0; i < num_msg; i++) {
 453		send_bytes = min(msg_bytes, payload_size);
 454		cdata_chunk->num_elems = send_bytes;
 455		cdata_chunk->rhdr.hdr.size = hdr_bytes + send_bytes;
 456		cdata_chunk->msg_index = i;
 457		msg_bytes -= send_bytes;
 458		cdata_chunk->elems_remaining = msg_bytes;
 459
 460		if (set)
 461			memcpy(dst, src + offset, send_bytes);
 462
 463		ret = ipc3_tx_msg_unlocked(sdev->ipc,
 464					   cdata_chunk, cdata_chunk->rhdr.hdr.size,
 465					   cdata_chunk, cdata_chunk->rhdr.hdr.size);
 466		if (ret < 0)
 467			break;
 468
 469		if (!set)
 470			memcpy(dst + offset, src, send_bytes);
 471
 472		offset += payload_size;
 473	}
 474
 475	mutex_unlock(&sdev->ipc->tx_mutex);
 476
 477	kfree(cdata_chunk);
 478
 479	return ret;
 480}
 481
 482int sof_ipc3_get_ext_windows(struct snd_sof_dev *sdev,
 483			     const struct sof_ipc_ext_data_hdr *ext_hdr)
 484{
 485	const struct sof_ipc_window *w =
 486		container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
 487
 488	if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
 489		return -EINVAL;
 490
 491	if (sdev->info_window) {
 492		if (memcmp(sdev->info_window, w, ext_hdr->hdr.size)) {
 493			dev_err(sdev->dev, "mismatch between window descriptor from extended manifest and mailbox");
 494			return -EINVAL;
 495		}
 496		return 0;
 497	}
 498
 499	/* keep a local copy of the data */
 500	sdev->info_window = devm_kmemdup(sdev->dev, w, ext_hdr->hdr.size, GFP_KERNEL);
 501	if (!sdev->info_window)
 502		return -ENOMEM;
 503
 504	return 0;
 505}
 506
 507int sof_ipc3_get_cc_info(struct snd_sof_dev *sdev,
 508			 const struct sof_ipc_ext_data_hdr *ext_hdr)
 509{
 510	int ret;
 511
 512	const struct sof_ipc_cc_version *cc =
 513		container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
 514
 515	if (sdev->cc_version) {
 516		if (memcmp(sdev->cc_version, cc, cc->ext_hdr.hdr.size)) {
 517			dev_err(sdev->dev,
 518				"Receive diverged cc_version descriptions");
 519			return -EINVAL;
 520		}
 521		return 0;
 522	}
 523
 524	dev_dbg(sdev->dev,
 525		"Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
 526		cc->name, cc->major, cc->minor, cc->micro, cc->desc, cc->optim);
 527
 528	/* create read-only cc_version debugfs to store compiler version info */
 529	/* use local copy of the cc_version to prevent data corruption */
 530	if (sdev->first_boot) {
 531		sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
 532						GFP_KERNEL);
 533
 534		if (!sdev->cc_version)
 535			return -ENOMEM;
 536
 537		memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
 538		ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
 539					       cc->ext_hdr.hdr.size,
 540					       "cc_version", 0444);
 541
 542		/* errors are only due to memory allocation, not debugfs */
 543		if (ret < 0) {
 544			dev_err(sdev->dev, "snd_sof_debugfs_buf_item failed\n");
 545			return ret;
 546		}
 547	}
 548
 549	return 0;
 550}
 551
 552/* parse the extended FW boot data structures from FW boot message */
 553static int ipc3_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset)
 554{
 555	struct sof_ipc_ext_data_hdr *ext_hdr;
 556	void *ext_data;
 557	int ret = 0;
 558
 559	ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
 560	if (!ext_data)
 561		return -ENOMEM;
 562
 563	/* get first header */
 564	snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
 565			       sizeof(*ext_hdr));
 566	ext_hdr = ext_data;
 567
 568	while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
 569		/* read in ext structure */
 570		snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM,
 571				       offset + sizeof(*ext_hdr),
 572				       (void *)((u8 *)ext_data + sizeof(*ext_hdr)),
 573				       ext_hdr->hdr.size - sizeof(*ext_hdr));
 574
 575		dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
 576			ext_hdr->type, ext_hdr->hdr.size);
 577
 578		/* process structure data */
 579		switch (ext_hdr->type) {
 580		case SOF_IPC_EXT_WINDOW:
 581			ret = sof_ipc3_get_ext_windows(sdev, ext_hdr);
 582			break;
 583		case SOF_IPC_EXT_CC_INFO:
 584			ret = sof_ipc3_get_cc_info(sdev, ext_hdr);
 585			break;
 586		case SOF_IPC_EXT_UNUSED:
 587		case SOF_IPC_EXT_PROBE_INFO:
 588		case SOF_IPC_EXT_USER_ABI_INFO:
 589			/* They are supported but we don't do anything here */
 590			break;
 591		default:
 592			dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n",
 593				 ext_hdr->type, ext_hdr->hdr.size);
 594			ret = 0;
 595			break;
 596		}
 597
 598		if (ret < 0) {
 599			dev_err(sdev->dev, "Failed to parse ext data type %d\n",
 600				ext_hdr->type);
 601			break;
 602		}
 603
 604		/* move to next header */
 605		offset += ext_hdr->hdr.size;
 606		snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
 607				       sizeof(*ext_hdr));
 608		ext_hdr = ext_data;
 609	}
 610
 611	kfree(ext_data);
 612	return ret;
 613}
 614
 615static void ipc3_get_windows(struct snd_sof_dev *sdev)
 616{
 617	struct sof_ipc_window_elem *elem;
 618	u32 outbox_offset = 0;
 619	u32 stream_offset = 0;
 620	u32 inbox_offset = 0;
 621	u32 outbox_size = 0;
 622	u32 stream_size = 0;
 623	u32 inbox_size = 0;
 624	u32 debug_size = 0;
 625	u32 debug_offset = 0;
 626	int window_offset;
 627	int i;
 628
 629	if (!sdev->info_window) {
 630		dev_err(sdev->dev, "%s: No window info present\n", __func__);
 631		return;
 632	}
 633
 634	for (i = 0; i < sdev->info_window->num_windows; i++) {
 635		elem = &sdev->info_window->window[i];
 636
 637		window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
 638		if (window_offset < 0) {
 639			dev_warn(sdev->dev, "No offset for window %d\n", elem->id);
 640			continue;
 641		}
 642
 643		switch (elem->type) {
 644		case SOF_IPC_REGION_UPBOX:
 645			inbox_offset = window_offset + elem->offset;
 646			inbox_size = elem->size;
 647			snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
 648							inbox_offset,
 649							elem->size, "inbox",
 650							SOF_DEBUGFS_ACCESS_D0_ONLY);
 651			break;
 652		case SOF_IPC_REGION_DOWNBOX:
 653			outbox_offset = window_offset + elem->offset;
 654			outbox_size = elem->size;
 655			snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
 656							outbox_offset,
 657							elem->size, "outbox",
 658							SOF_DEBUGFS_ACCESS_D0_ONLY);
 659			break;
 660		case SOF_IPC_REGION_TRACE:
 661			snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
 662							window_offset + elem->offset,
 663							elem->size, "etrace",
 664							SOF_DEBUGFS_ACCESS_D0_ONLY);
 665			break;
 666		case SOF_IPC_REGION_DEBUG:
 667			debug_offset = window_offset + elem->offset;
 668			debug_size = elem->size;
 669			snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
 670							window_offset + elem->offset,
 671							elem->size, "debug",
 672							SOF_DEBUGFS_ACCESS_D0_ONLY);
 673			break;
 674		case SOF_IPC_REGION_STREAM:
 675			stream_offset = window_offset + elem->offset;
 676			stream_size = elem->size;
 677			snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
 678							stream_offset,
 679							elem->size, "stream",
 680							SOF_DEBUGFS_ACCESS_D0_ONLY);
 681			break;
 682		case SOF_IPC_REGION_REGS:
 683			snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
 684							window_offset + elem->offset,
 685							elem->size, "regs",
 686							SOF_DEBUGFS_ACCESS_D0_ONLY);
 687			break;
 688		case SOF_IPC_REGION_EXCEPTION:
 689			sdev->dsp_oops_offset = window_offset + elem->offset;
 690			snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
 691							window_offset + elem->offset,
 692							elem->size, "exception",
 693							SOF_DEBUGFS_ACCESS_D0_ONLY);
 694			break;
 695		default:
 696			dev_err(sdev->dev, "%s: Illegal window info: %u\n",
 697				__func__, elem->type);
 698			return;
 699		}
 700	}
 701
 702	if (outbox_size == 0 || inbox_size == 0) {
 703		dev_err(sdev->dev, "%s: Illegal mailbox window\n", __func__);
 704		return;
 705	}
 706
 707	sdev->dsp_box.offset = inbox_offset;
 708	sdev->dsp_box.size = inbox_size;
 709
 710	sdev->host_box.offset = outbox_offset;
 711	sdev->host_box.size = outbox_size;
 712
 713	sdev->stream_box.offset = stream_offset;
 714	sdev->stream_box.size = stream_size;
 715
 716	sdev->debug_box.offset = debug_offset;
 717	sdev->debug_box.size = debug_size;
 718
 719	dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
 720		inbox_offset, inbox_size);
 721	dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
 722		outbox_offset, outbox_size);
 723	dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
 724		stream_offset, stream_size);
 725	dev_dbg(sdev->dev, " debug region 0x%x - size 0x%x\n",
 726		debug_offset, debug_size);
 727}
 728
 729static int ipc3_init_reply_data_buffer(struct snd_sof_dev *sdev)
 730{
 731	struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
 732
 733	msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
 734	if (!msg->reply_data)
 735		return -ENOMEM;
 736
 737	sdev->ipc->max_payload_size = SOF_IPC_MSG_MAX_SIZE;
 738
 739	return 0;
 740}
 741
 742int sof_ipc3_validate_fw_version(struct snd_sof_dev *sdev)
 743{
 744	struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
 745	struct sof_ipc_fw_version *v = &ready->version;
 746
 747	dev_info(sdev->dev,
 748		 "Firmware info: version %d:%d:%d-%s\n",  v->major, v->minor,
 749		 v->micro, v->tag);
 750	dev_info(sdev->dev,
 751		 "Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
 752		 SOF_ABI_VERSION_MAJOR(v->abi_version),
 753		 SOF_ABI_VERSION_MINOR(v->abi_version),
 754		 SOF_ABI_VERSION_PATCH(v->abi_version),
 755		 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
 756
 757	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) {
 758		dev_err(sdev->dev, "incompatible FW ABI version\n");
 759		return -EINVAL;
 760	}
 761
 762	if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS) &&
 763	    SOF_ABI_VERSION_MINOR(v->abi_version) > SOF_ABI_MINOR) {
 764		dev_err(sdev->dev, "FW ABI is more recent than kernel\n");
 765		return -EINVAL;
 766	}
 767
 768	if (ready->flags & SOF_IPC_INFO_BUILD) {
 769		dev_info(sdev->dev,
 770			 "Firmware debug build %d on %s-%s - options:\n"
 771			 " GDB: %s\n"
 772			 " lock debug: %s\n"
 773			 " lock vdebug: %s\n",
 774			 v->build, v->date, v->time,
 775			 (ready->flags & SOF_IPC_INFO_GDB) ?
 776				"enabled" : "disabled",
 777			 (ready->flags & SOF_IPC_INFO_LOCKS) ?
 778				"enabled" : "disabled",
 779			 (ready->flags & SOF_IPC_INFO_LOCKSV) ?
 780				"enabled" : "disabled");
 781	}
 782
 783	/* copy the fw_version into debugfs at first boot */
 784	memcpy(&sdev->fw_version, v, sizeof(*v));
 785
 786	return 0;
 787}
 788
 789static int ipc3_fw_ready(struct snd_sof_dev *sdev, u32 cmd)
 790{
 791	struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
 792	int offset;
 793	int ret;
 794
 795	/* mailbox must be on 4k boundary */
 796	offset = snd_sof_dsp_get_mailbox_offset(sdev);
 797	if (offset < 0) {
 798		dev_err(sdev->dev, "%s: no mailbox offset\n", __func__);
 799		return offset;
 800	}
 801
 802	dev_dbg(sdev->dev, "DSP is ready 0x%8.8x offset 0x%x\n", cmd, offset);
 803
 804	/* no need to re-check version/ABI for subsequent boots */
 805	if (!sdev->first_boot)
 806		return 0;
 807
 808	/*
 809	 * copy data from the DSP FW ready offset
 810	 * Subsequent error handling is not needed for BLK_TYPE_SRAM
 811	 */
 812	ret = snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, fw_ready,
 813				     sizeof(*fw_ready));
 814	if (ret) {
 815		dev_err(sdev->dev,
 816			"Unable to read fw_ready, read from TYPE_SRAM failed\n");
 817		return ret;
 818	}
 819
 820	/* make sure ABI version is compatible */
 821	ret = sof_ipc3_validate_fw_version(sdev);
 822	if (ret < 0)
 823		return ret;
 824
 825	/* now check for extended data */
 826	ipc3_fw_parse_ext_data(sdev, offset + sizeof(struct sof_ipc_fw_ready));
 827
 828	ipc3_get_windows(sdev);
 829
 830	return ipc3_init_reply_data_buffer(sdev);
 831}
 832
 833/* IPC stream position. */
 834static void ipc3_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
 835{
 836	struct snd_soc_component *scomp = sdev->component;
 837	struct snd_sof_pcm_stream *stream;
 838	struct sof_ipc_stream_posn posn;
 839	struct snd_sof_pcm *spcm;
 840	int direction, ret;
 841
 842	spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
 843	if (!spcm) {
 844		dev_err(sdev->dev, "period elapsed for unknown stream, msg_id %d\n",
 845			msg_id);
 846		return;
 847	}
 848
 849	stream = &spcm->stream[direction];
 850	ret = snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
 851	if (ret < 0) {
 852		dev_warn(sdev->dev, "failed to read stream position: %d\n", ret);
 853		return;
 854	}
 855
 856	trace_sof_ipc3_period_elapsed_position(sdev, &posn);
 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_set_core_state(struct snd_sof_dev *sdev, int core_idx, bool on)
1041{
1042	struct sof_ipc_pm_core_config core_cfg = {
1043		.hdr.size = sizeof(core_cfg),
1044		.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
1045	};
1046	struct sof_ipc_reply reply;
1047
1048	if (on)
1049		core_cfg.enable_mask = sdev->enabled_cores_mask | BIT(core_idx);
1050	else
1051		core_cfg.enable_mask = sdev->enabled_cores_mask & ~BIT(core_idx);
1052
1053	return sof_ipc3_tx_msg(sdev, &core_cfg, sizeof(core_cfg),
1054			       &reply, sizeof(reply), false);
1055}
1056
1057static int sof_ipc3_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
1058{
1059	struct sof_ipc_pm_ctx pm_ctx = {
1060		.hdr.size = sizeof(pm_ctx),
1061		.hdr.cmd = SOF_IPC_GLB_PM_MSG | cmd,
1062	};
1063	struct sof_ipc_reply reply;
1064
1065	/* send ctx save ipc to dsp */
1066	return sof_ipc3_tx_msg(sdev, &pm_ctx, sizeof(pm_ctx),
1067			       &reply, sizeof(reply), false);
1068}
1069
1070static int sof_ipc3_ctx_save(struct snd_sof_dev *sdev)
1071{
1072	return sof_ipc3_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
1073}
1074
1075static int sof_ipc3_ctx_restore(struct snd_sof_dev *sdev)
1076{
1077	return sof_ipc3_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE);
1078}
1079
1080static const struct sof_ipc_pm_ops ipc3_pm_ops = {
1081	.ctx_save = sof_ipc3_ctx_save,
1082	.ctx_restore = sof_ipc3_ctx_restore,
1083	.set_core_state = sof_ipc3_set_core_state,
1084};
1085
1086const struct sof_ipc_ops ipc3_ops = {
1087	.tplg = &ipc3_tplg_ops,
1088	.pm = &ipc3_pm_ops,
1089	.pcm = &ipc3_pcm_ops,
1090	.fw_loader = &ipc3_loader_ops,
1091	.fw_tracing = &ipc3_dtrace_ops,
1092
1093	.tx_msg = sof_ipc3_tx_msg,
1094	.rx_msg = sof_ipc3_rx_msg,
1095	.set_get_data = sof_ipc3_set_get_data,
1096	.get_reply = sof_ipc3_get_reply,
1097};