Linux Audio

Check our new training course

Loading...
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) 2018 Intel Corporation. All rights reserved.
  7//
  8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
  9//
 10// Generic IPC layer that can work over MMIO and SPI/I2C. PHY layer provided
 11// by platform driver code.
 12//
 13
 14#include <linux/mutex.h>
 15#include <linux/types.h>
 16
 17#include "sof-priv.h"
 18#include "sof-audio.h"
 19#include "ops.h"
 20
 21static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id);
 22static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd);
 23
 24/*
 25 * IPC message Tx/Rx message handling.
 26 */
 27
 28/* SOF generic IPC data */
 29struct snd_sof_ipc {
 30	struct snd_sof_dev *sdev;
 31
 32	/* protects messages and the disable flag */
 33	struct mutex tx_mutex;
 34	/* disables further sending of ipc's */
 35	bool disable_ipc_tx;
 36
 37	struct snd_sof_ipc_msg msg;
 38};
 39
 40struct sof_ipc_ctrl_data_params {
 41	size_t msg_bytes;
 42	size_t hdr_bytes;
 43	size_t pl_size;
 44	size_t elems;
 45	u32 num_msg;
 46	u8 *src;
 47	u8 *dst;
 48};
 49
 50#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC)
 51static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
 52{
 53	u8 *str;
 54	u8 *str2 = NULL;
 55	u32 glb;
 56	u32 type;
 57
 58	glb = cmd & SOF_GLB_TYPE_MASK;
 59	type = cmd & SOF_CMD_TYPE_MASK;
 60
 61	switch (glb) {
 62	case SOF_IPC_GLB_REPLY:
 63		str = "GLB_REPLY"; break;
 64	case SOF_IPC_GLB_COMPOUND:
 65		str = "GLB_COMPOUND"; break;
 66	case SOF_IPC_GLB_TPLG_MSG:
 67		str = "GLB_TPLG_MSG";
 68		switch (type) {
 69		case SOF_IPC_TPLG_COMP_NEW:
 70			str2 = "COMP_NEW"; break;
 71		case SOF_IPC_TPLG_COMP_FREE:
 72			str2 = "COMP_FREE"; break;
 73		case SOF_IPC_TPLG_COMP_CONNECT:
 74			str2 = "COMP_CONNECT"; break;
 75		case SOF_IPC_TPLG_PIPE_NEW:
 76			str2 = "PIPE_NEW"; break;
 77		case SOF_IPC_TPLG_PIPE_FREE:
 78			str2 = "PIPE_FREE"; break;
 79		case SOF_IPC_TPLG_PIPE_CONNECT:
 80			str2 = "PIPE_CONNECT"; break;
 81		case SOF_IPC_TPLG_PIPE_COMPLETE:
 82			str2 = "PIPE_COMPLETE"; break;
 83		case SOF_IPC_TPLG_BUFFER_NEW:
 84			str2 = "BUFFER_NEW"; break;
 85		case SOF_IPC_TPLG_BUFFER_FREE:
 86			str2 = "BUFFER_FREE"; break;
 87		default:
 88			str2 = "unknown type"; break;
 89		}
 90		break;
 91	case SOF_IPC_GLB_PM_MSG:
 92		str = "GLB_PM_MSG";
 93		switch (type) {
 94		case SOF_IPC_PM_CTX_SAVE:
 95			str2 = "CTX_SAVE"; break;
 96		case SOF_IPC_PM_CTX_RESTORE:
 97			str2 = "CTX_RESTORE"; break;
 98		case SOF_IPC_PM_CTX_SIZE:
 99			str2 = "CTX_SIZE"; break;
100		case SOF_IPC_PM_CLK_SET:
101			str2 = "CLK_SET"; break;
102		case SOF_IPC_PM_CLK_GET:
103			str2 = "CLK_GET"; break;
104		case SOF_IPC_PM_CLK_REQ:
105			str2 = "CLK_REQ"; break;
106		case SOF_IPC_PM_CORE_ENABLE:
107			str2 = "CORE_ENABLE"; break;
108		default:
109			str2 = "unknown type"; break;
110		}
111		break;
112	case SOF_IPC_GLB_COMP_MSG:
113		str = "GLB_COMP_MSG";
114		switch (type) {
115		case SOF_IPC_COMP_SET_VALUE:
116			str2 = "SET_VALUE"; break;
117		case SOF_IPC_COMP_GET_VALUE:
118			str2 = "GET_VALUE"; break;
119		case SOF_IPC_COMP_SET_DATA:
120			str2 = "SET_DATA"; break;
121		case SOF_IPC_COMP_GET_DATA:
122			str2 = "GET_DATA"; break;
123		default:
124			str2 = "unknown type"; break;
125		}
126		break;
127	case SOF_IPC_GLB_STREAM_MSG:
128		str = "GLB_STREAM_MSG";
129		switch (type) {
130		case SOF_IPC_STREAM_PCM_PARAMS:
131			str2 = "PCM_PARAMS"; break;
132		case SOF_IPC_STREAM_PCM_PARAMS_REPLY:
133			str2 = "PCM_REPLY"; break;
134		case SOF_IPC_STREAM_PCM_FREE:
135			str2 = "PCM_FREE"; break;
136		case SOF_IPC_STREAM_TRIG_START:
137			str2 = "TRIG_START"; break;
138		case SOF_IPC_STREAM_TRIG_STOP:
139			str2 = "TRIG_STOP"; break;
140		case SOF_IPC_STREAM_TRIG_PAUSE:
141			str2 = "TRIG_PAUSE"; break;
142		case SOF_IPC_STREAM_TRIG_RELEASE:
143			str2 = "TRIG_RELEASE"; break;
144		case SOF_IPC_STREAM_TRIG_DRAIN:
145			str2 = "TRIG_DRAIN"; break;
146		case SOF_IPC_STREAM_TRIG_XRUN:
147			str2 = "TRIG_XRUN"; break;
148		case SOF_IPC_STREAM_POSITION:
149			str2 = "POSITION"; break;
150		case SOF_IPC_STREAM_VORBIS_PARAMS:
151			str2 = "VORBIS_PARAMS"; break;
152		case SOF_IPC_STREAM_VORBIS_FREE:
153			str2 = "VORBIS_FREE"; break;
154		default:
155			str2 = "unknown type"; break;
156		}
157		break;
158	case SOF_IPC_FW_READY:
159		str = "FW_READY"; break;
160	case SOF_IPC_GLB_DAI_MSG:
161		str = "GLB_DAI_MSG";
162		switch (type) {
163		case SOF_IPC_DAI_CONFIG:
164			str2 = "CONFIG"; break;
165		case SOF_IPC_DAI_LOOPBACK:
166			str2 = "LOOPBACK"; break;
167		default:
168			str2 = "unknown type"; break;
169		}
170		break;
171	case SOF_IPC_GLB_TRACE_MSG:
172		str = "GLB_TRACE_MSG"; break;
173	case SOF_IPC_GLB_TEST_MSG:
174		str = "GLB_TEST_MSG";
175		switch (type) {
176		case SOF_IPC_TEST_IPC_FLOOD:
177			str2 = "IPC_FLOOD"; break;
178		default:
179			str2 = "unknown type"; break;
180		}
181		break;
182	default:
183		str = "unknown GLB command"; break;
184	}
185
186	if (str2)
187		dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2);
188	else
189		dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str);
190}
191#else
192static inline void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
193{
194	if ((cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_TRACE_MSG)
195		dev_dbg(dev, "%s: 0x%x\n", text, cmd);
196}
197#endif
198
199/* wait for IPC message reply */
200static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg,
201			void *reply_data)
202{
203	struct snd_sof_dev *sdev = ipc->sdev;
204	struct sof_ipc_cmd_hdr *hdr = msg->msg_data;
205	int ret;
206
207	/* wait for DSP IPC completion */
208	ret = wait_event_timeout(msg->waitq, msg->ipc_complete,
209				 msecs_to_jiffies(sdev->ipc_timeout));
210
211	if (ret == 0) {
212		dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n",
213			hdr->cmd, hdr->size);
214		snd_sof_handle_fw_exception(ipc->sdev);
 
 
215		ret = -ETIMEDOUT;
216	} else {
 
217		ret = msg->reply_error;
218		if (ret < 0) {
 
 
219			dev_err(sdev->dev, "error: ipc error for 0x%x size %zu\n",
220				hdr->cmd, msg->reply_size);
221		} else {
222			ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
223			if (msg->reply_size)
224				/* copy the data returned from DSP */
225				memcpy(reply_data, msg->reply_data,
226				       msg->reply_size);
227		}
228	}
229
230	return ret;
231}
232
233/* send IPC message from host to DSP */
234static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header,
235				       void *msg_data, size_t msg_bytes,
236				       void *reply_data, size_t reply_bytes)
237{
238	struct snd_sof_dev *sdev = ipc->sdev;
239	struct snd_sof_ipc_msg *msg;
240	int ret;
241
242	if (ipc->disable_ipc_tx)
243		return -ENODEV;
244
245	/*
246	 * The spin-lock is also still needed to protect message objects against
247	 * other atomic contexts.
248	 */
249	spin_lock_irq(&sdev->ipc_lock);
250
251	/* initialise the message */
252	msg = &ipc->msg;
253
254	msg->header = header;
255	msg->msg_size = msg_bytes;
256	msg->reply_size = reply_bytes;
257	msg->reply_error = 0;
258
259	/* attach any data */
260	if (msg_bytes)
261		memcpy(msg->msg_data, msg_data, msg_bytes);
262
263	sdev->msg = msg;
264
265	ret = snd_sof_dsp_send_msg(sdev, msg);
266	/* Next reply that we receive will be related to this message */
267	if (!ret)
268		msg->ipc_complete = false;
269
270	spin_unlock_irq(&sdev->ipc_lock);
271
272	if (ret < 0) {
 
273		dev_err_ratelimited(sdev->dev,
274				    "error: ipc tx failed with error %d\n",
275				    ret);
276		return ret;
277	}
278
279	ipc_log_header(sdev->dev, "ipc tx", msg->header);
280
281	/* now wait for completion */
282	if (!ret)
283		ret = tx_wait_done(ipc, msg, reply_data);
284
285	return ret;
286}
287
288/* send IPC message from host to DSP */
289int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header,
290		       void *msg_data, size_t msg_bytes, void *reply_data,
291		       size_t reply_bytes)
292{
293	const struct sof_dsp_power_state target_state = {
294		.state = SOF_DSP_PM_D0,
295	};
296	int ret;
297
298	/* ensure the DSP is in D0 before sending a new IPC */
299	ret = snd_sof_dsp_set_power_state(ipc->sdev, &target_state);
300	if (ret < 0) {
301		dev_err(ipc->sdev->dev, "error: resuming DSP %d\n", ret);
302		return ret;
303	}
304
305	return sof_ipc_tx_message_no_pm(ipc, header, msg_data, msg_bytes,
306					reply_data, reply_bytes);
307}
308EXPORT_SYMBOL(sof_ipc_tx_message);
309
310/*
311 * send IPC message from host to DSP without modifying the DSP state.
312 * This will be used for IPC's that can be handled by the DSP
313 * even in a low-power D0 substate.
314 */
315int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, u32 header,
316			     void *msg_data, size_t msg_bytes,
317			     void *reply_data, size_t reply_bytes)
318{
319	int ret;
320
321	if (msg_bytes > SOF_IPC_MSG_MAX_SIZE ||
322	    reply_bytes > SOF_IPC_MSG_MAX_SIZE)
323		return -ENOBUFS;
324
325	/* Serialise IPC TX */
326	mutex_lock(&ipc->tx_mutex);
327
328	ret = sof_ipc_tx_message_unlocked(ipc, header, msg_data, msg_bytes,
329					  reply_data, reply_bytes);
330
331	mutex_unlock(&ipc->tx_mutex);
332
333	return ret;
334}
335EXPORT_SYMBOL(sof_ipc_tx_message_no_pm);
336
337/* handle reply message from DSP */
338void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
339{
340	struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
341
342	if (msg->ipc_complete) {
343		dev_dbg(sdev->dev,
344			"no reply expected, received 0x%x, will be ignored",
345			msg_id);
346		return;
347	}
348
349	/* wake up and return the error if we have waiters on this message ? */
350	msg->ipc_complete = true;
351	wake_up(&msg->waitq);
 
 
352}
353EXPORT_SYMBOL(snd_sof_ipc_reply);
354
355/* DSP firmware has sent host a message  */
356void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
357{
358	struct sof_ipc_cmd_hdr hdr;
359	u32 cmd, type;
360	int err = 0;
361
362	/* read back header */
363	snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr));
364	ipc_log_header(sdev->dev, "ipc rx", hdr.cmd);
365
366	cmd = hdr.cmd & SOF_GLB_TYPE_MASK;
367	type = hdr.cmd & SOF_CMD_TYPE_MASK;
368
369	/* check message type */
370	switch (cmd) {
371	case SOF_IPC_GLB_REPLY:
372		dev_err(sdev->dev, "error: ipc reply unknown\n");
373		break;
374	case SOF_IPC_FW_READY:
375		/* check for FW boot completion */
376		if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) {
377			err = sof_ops(sdev)->fw_ready(sdev, cmd);
378			if (err < 0)
379				sdev->fw_state = SOF_FW_BOOT_READY_FAILED;
380			else
381				sdev->fw_state = SOF_FW_BOOT_COMPLETE;
 
 
 
 
 
 
 
382
383			/* wake up firmware loader */
384			wake_up(&sdev->boot_wait);
385		}
386		break;
387	case SOF_IPC_GLB_COMPOUND:
388	case SOF_IPC_GLB_TPLG_MSG:
389	case SOF_IPC_GLB_PM_MSG:
390	case SOF_IPC_GLB_COMP_MSG:
391		break;
392	case SOF_IPC_GLB_STREAM_MSG:
393		/* need to pass msg id into the function */
394		ipc_stream_message(sdev, hdr.cmd);
395		break;
396	case SOF_IPC_GLB_TRACE_MSG:
397		ipc_trace_message(sdev, type);
398		break;
399	default:
400		dev_err(sdev->dev, "error: unknown DSP message 0x%x\n", cmd);
401		break;
402	}
403
404	ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd);
405}
406EXPORT_SYMBOL(snd_sof_ipc_msgs_rx);
407
408/*
409 * IPC trace mechanism.
410 */
411
412static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id)
413{
414	struct sof_ipc_dma_trace_posn posn;
415
416	switch (msg_id) {
417	case SOF_IPC_TRACE_DMA_POSITION:
418		/* read back full message */
419		snd_sof_ipc_msg_data(sdev, NULL, &posn, sizeof(posn));
420		snd_sof_trace_update_pos(sdev, &posn);
421		break;
422	default:
423		dev_err(sdev->dev, "error: unhandled trace message %x\n",
424			msg_id);
425		break;
426	}
427}
428
429/*
430 * IPC stream position.
431 */
432
433static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
434{
435	struct snd_soc_component *scomp = sdev->component;
436	struct snd_sof_pcm_stream *stream;
437	struct sof_ipc_stream_posn posn;
438	struct snd_sof_pcm *spcm;
439	int direction;
440
441	spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
442	if (!spcm) {
443		dev_err(sdev->dev,
444			"error: period elapsed for unknown stream, msg_id %d\n",
445			msg_id);
446		return;
447	}
448
449	stream = &spcm->stream[direction];
450	snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
451
452	dev_dbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n",
453		posn.host_posn, posn.dai_posn, posn.wallclock);
454
455	memcpy(&stream->posn, &posn, sizeof(posn));
456
457	/* only inform ALSA for period_wakeup mode */
458	if (!stream->substream->runtime->no_period_wakeup)
459		snd_sof_pcm_period_elapsed(stream->substream);
460}
461
462/* DSP notifies host of an XRUN within FW */
463static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id)
464{
465	struct snd_soc_component *scomp = sdev->component;
466	struct snd_sof_pcm_stream *stream;
467	struct sof_ipc_stream_posn posn;
468	struct snd_sof_pcm *spcm;
469	int direction;
470
471	spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
472	if (!spcm) {
473		dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n",
474			msg_id);
475		return;
476	}
477
478	stream = &spcm->stream[direction];
479	snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
480
481	dev_dbg(sdev->dev,  "posn XRUN: host %llx comp %d size %d\n",
482		posn.host_posn, posn.xrun_comp_id, posn.xrun_size);
483
484#if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP)
485	/* stop PCM on XRUN - used for pipeline debug */
486	memcpy(&stream->posn, &posn, sizeof(posn));
487	snd_pcm_stop_xrun(stream->substream);
488#endif
489}
490
491/* stream notifications from DSP FW */
492static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd)
493{
494	/* get msg cmd type and msd id */
495	u32 msg_type = msg_cmd & SOF_CMD_TYPE_MASK;
496	u32 msg_id = SOF_IPC_MESSAGE_ID(msg_cmd);
497
498	switch (msg_type) {
499	case SOF_IPC_STREAM_POSITION:
500		ipc_period_elapsed(sdev, msg_id);
501		break;
502	case SOF_IPC_STREAM_TRIG_XRUN:
503		ipc_xrun(sdev, msg_id);
504		break;
505	default:
506		dev_err(sdev->dev, "error: unhandled stream message %x\n",
507			msg_id);
508		break;
509	}
510}
511
512/* get stream position IPC - use faster MMIO method if available on platform */
513int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp,
514			    struct snd_sof_pcm *spcm, int direction,
515			    struct sof_ipc_stream_posn *posn)
516{
517	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
518	struct sof_ipc_stream stream;
519	int err;
520
521	/* read position via slower IPC */
522	stream.hdr.size = sizeof(stream);
523	stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_POSITION;
524	stream.comp_id = spcm->stream[direction].comp_id;
525
526	/* send IPC to the DSP */
527	err = sof_ipc_tx_message(sdev->ipc,
528				 stream.hdr.cmd, &stream, sizeof(stream), posn,
529				 sizeof(*posn));
530	if (err < 0) {
531		dev_err(sdev->dev, "error: failed to get stream %d position\n",
532			stream.comp_id);
533		return err;
534	}
535
536	return 0;
537}
538EXPORT_SYMBOL(snd_sof_ipc_stream_posn);
539
540static int sof_get_ctrl_copy_params(enum sof_ipc_ctrl_type ctrl_type,
541				    struct sof_ipc_ctrl_data *src,
542				    struct sof_ipc_ctrl_data *dst,
543				    struct sof_ipc_ctrl_data_params *sparams)
544{
545	switch (ctrl_type) {
546	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
547	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
548		sparams->src = (u8 *)src->chanv;
549		sparams->dst = (u8 *)dst->chanv;
550		break;
551	case SOF_CTRL_TYPE_VALUE_COMP_GET:
552	case SOF_CTRL_TYPE_VALUE_COMP_SET:
553		sparams->src = (u8 *)src->compv;
554		sparams->dst = (u8 *)dst->compv;
555		break;
556	case SOF_CTRL_TYPE_DATA_GET:
557	case SOF_CTRL_TYPE_DATA_SET:
558		sparams->src = (u8 *)src->data->data;
559		sparams->dst = (u8 *)dst->data->data;
560		break;
561	default:
562		return -EINVAL;
563	}
564
565	/* calculate payload size and number of messages */
566	sparams->pl_size = SOF_IPC_MSG_MAX_SIZE - sparams->hdr_bytes;
567	sparams->num_msg = DIV_ROUND_UP(sparams->msg_bytes, sparams->pl_size);
568
569	return 0;
570}
571
572static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
573				       struct sof_ipc_ctrl_data *cdata,
574				       struct sof_ipc_ctrl_data_params *sparams,
575				       bool send)
576{
577	struct sof_ipc_ctrl_data *partdata;
578	size_t send_bytes;
579	size_t offset = 0;
580	size_t msg_bytes;
581	size_t pl_size;
582	int err;
583	int i;
584
585	/* allocate max ipc size because we have at least one */
586	partdata = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
587	if (!partdata)
588		return -ENOMEM;
589
590	if (send)
591		err = sof_get_ctrl_copy_params(cdata->type, cdata, partdata,
592					       sparams);
593	else
594		err = sof_get_ctrl_copy_params(cdata->type, partdata, cdata,
595					       sparams);
596	if (err < 0) {
597		kfree(partdata);
598		return err;
599	}
600
601	msg_bytes = sparams->msg_bytes;
602	pl_size = sparams->pl_size;
603
604	/* copy the header data */
605	memcpy(partdata, cdata, sparams->hdr_bytes);
606
607	/* Serialise IPC TX */
608	mutex_lock(&sdev->ipc->tx_mutex);
609
610	/* copy the payload data in a loop */
611	for (i = 0; i < sparams->num_msg; i++) {
612		send_bytes = min(msg_bytes, pl_size);
613		partdata->num_elems = send_bytes;
614		partdata->rhdr.hdr.size = sparams->hdr_bytes + send_bytes;
615		partdata->msg_index = i;
616		msg_bytes -= send_bytes;
617		partdata->elems_remaining = msg_bytes;
618
619		if (send)
620			memcpy(sparams->dst, sparams->src + offset, send_bytes);
621
622		err = sof_ipc_tx_message_unlocked(sdev->ipc,
623						  partdata->rhdr.hdr.cmd,
624						  partdata,
625						  partdata->rhdr.hdr.size,
626						  partdata,
627						  partdata->rhdr.hdr.size);
628		if (err < 0)
629			break;
630
631		if (!send)
632			memcpy(sparams->dst + offset, sparams->src, send_bytes);
633
634		offset += pl_size;
635	}
636
637	mutex_unlock(&sdev->ipc->tx_mutex);
638
639	kfree(partdata);
640	return err;
641}
642
643/*
644 * IPC get()/set() for kcontrols.
645 */
646int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
 
647				  u32 ipc_cmd,
648				  enum sof_ipc_ctrl_type ctrl_type,
649				  enum sof_ipc_ctrl_cmd ctrl_cmd,
650				  bool send)
651{
652	struct snd_soc_component *scomp = scontrol->scomp;
653	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
654	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
655	struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
656	struct sof_ipc_fw_version *v = &ready->version;
657	struct sof_ipc_ctrl_data_params sparams;
658	size_t send_bytes;
659	int err;
660
661	/* read or write firmware volume */
662	if (scontrol->readback_offset != 0) {
663		/* write/read value header via mmaped region */
664		send_bytes = sizeof(struct sof_ipc_ctrl_value_chan) *
665		cdata->num_elems;
666		if (send)
667			snd_sof_dsp_block_write(sdev, sdev->mmio_bar,
668						scontrol->readback_offset,
669						cdata->chanv, send_bytes);
670
671		else
672			snd_sof_dsp_block_read(sdev, sdev->mmio_bar,
673					       scontrol->readback_offset,
674					       cdata->chanv, send_bytes);
675		return 0;
676	}
677
678	cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd;
679	cdata->cmd = ctrl_cmd;
680	cdata->type = ctrl_type;
681	cdata->comp_id = scontrol->comp_id;
682	cdata->msg_index = 0;
683
684	/* calculate header and data size */
685	switch (cdata->type) {
686	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
687	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
688		sparams.msg_bytes = scontrol->num_channels *
689			sizeof(struct sof_ipc_ctrl_value_chan);
690		sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
691		sparams.elems = scontrol->num_channels;
692		break;
693	case SOF_CTRL_TYPE_VALUE_COMP_GET:
694	case SOF_CTRL_TYPE_VALUE_COMP_SET:
695		sparams.msg_bytes = scontrol->num_channels *
696			sizeof(struct sof_ipc_ctrl_value_comp);
697		sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
698		sparams.elems = scontrol->num_channels;
699		break;
700	case SOF_CTRL_TYPE_DATA_GET:
701	case SOF_CTRL_TYPE_DATA_SET:
702		sparams.msg_bytes = cdata->data->size;
703		sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data) +
704			sizeof(struct sof_abi_hdr);
705		sparams.elems = cdata->data->size;
706		break;
707	default:
708		return -EINVAL;
709	}
710
711	cdata->rhdr.hdr.size = sparams.msg_bytes + sparams.hdr_bytes;
712	cdata->num_elems = sparams.elems;
713	cdata->elems_remaining = 0;
714
715	/* send normal size ipc in one part */
716	if (cdata->rhdr.hdr.size <= SOF_IPC_MSG_MAX_SIZE) {
717		err = sof_ipc_tx_message(sdev->ipc, cdata->rhdr.hdr.cmd, cdata,
718					 cdata->rhdr.hdr.size, cdata,
719					 cdata->rhdr.hdr.size);
720
721		if (err < 0)
722			dev_err(sdev->dev, "error: set/get ctrl ipc comp %d\n",
723				cdata->comp_id);
724
725		return err;
726	}
727
728	/* data is bigger than max ipc size, chop into smaller pieces */
729	dev_dbg(sdev->dev, "large ipc size %u, control size %u\n",
730		cdata->rhdr.hdr.size, scontrol->size);
731
732	/* large messages is only supported from ABI 3.3.0 onwards */
733	if (v->abi_version < SOF_ABI_VER(3, 3, 0)) {
734		dev_err(sdev->dev, "error: incompatible FW ABI version\n");
735		return -EINVAL;
736	}
737
738	err = sof_set_get_large_ctrl_data(sdev, cdata, &sparams, send);
739
740	if (err < 0)
741		dev_err(sdev->dev, "error: set/get large ctrl ipc comp %d\n",
742			cdata->comp_id);
743
744	return err;
745}
746EXPORT_SYMBOL(snd_sof_ipc_set_get_comp_data);
747
748/*
749 * IPC layer enumeration.
750 */
751
752int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox,
753			     size_t dspbox_size, u32 hostbox,
754			     size_t hostbox_size)
755{
756	sdev->dsp_box.offset = dspbox;
757	sdev->dsp_box.size = dspbox_size;
758	sdev->host_box.offset = hostbox;
759	sdev->host_box.size = hostbox_size;
760	return 0;
761}
762EXPORT_SYMBOL(snd_sof_dsp_mailbox_init);
763
764int snd_sof_ipc_valid(struct snd_sof_dev *sdev)
765{
766	struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
767	struct sof_ipc_fw_version *v = &ready->version;
768
769	dev_info(sdev->dev,
770		 "Firmware info: version %d:%d:%d-%s\n",  v->major, v->minor,
771		 v->micro, v->tag);
772	dev_info(sdev->dev,
773		 "Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
774		 SOF_ABI_VERSION_MAJOR(v->abi_version),
775		 SOF_ABI_VERSION_MINOR(v->abi_version),
776		 SOF_ABI_VERSION_PATCH(v->abi_version),
777		 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
778
779	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) {
780		dev_err(sdev->dev, "error: incompatible FW ABI version\n");
781		return -EINVAL;
782	}
783
784	if (v->abi_version > SOF_ABI_VERSION) {
785		if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
786			dev_warn(sdev->dev, "warn: FW ABI is more recent than kernel\n");
787		} else {
788			dev_err(sdev->dev, "error: FW ABI is more recent than kernel\n");
789			return -EINVAL;
790		}
791	}
792
793	if (ready->flags & SOF_IPC_INFO_BUILD) {
794		dev_info(sdev->dev,
795			 "Firmware debug build %d on %s-%s - options:\n"
796			 " GDB: %s\n"
797			 " lock debug: %s\n"
798			 " lock vdebug: %s\n",
799			 v->build, v->date, v->time,
800			 (ready->flags & SOF_IPC_INFO_GDB) ?
801				"enabled" : "disabled",
802			 (ready->flags & SOF_IPC_INFO_LOCKS) ?
803				"enabled" : "disabled",
804			 (ready->flags & SOF_IPC_INFO_LOCKSV) ?
805				"enabled" : "disabled");
806	}
807
808	/* copy the fw_version into debugfs at first boot */
809	memcpy(&sdev->fw_version, v, sizeof(*v));
810
811	return 0;
812}
813EXPORT_SYMBOL(snd_sof_ipc_valid);
814
815struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
816{
817	struct snd_sof_ipc *ipc;
818	struct snd_sof_ipc_msg *msg;
819
 
 
 
 
 
 
820	ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL);
821	if (!ipc)
822		return NULL;
823
824	mutex_init(&ipc->tx_mutex);
825	ipc->sdev = sdev;
826	msg = &ipc->msg;
827
828	/* indicate that we aren't sending a message ATM */
829	msg->ipc_complete = true;
830
831	/* pre-allocate message data */
832	msg->msg_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE,
833				     GFP_KERNEL);
834	if (!msg->msg_data)
835		return NULL;
836
837	msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE,
838				       GFP_KERNEL);
839	if (!msg->reply_data)
840		return NULL;
841
842	init_waitqueue_head(&msg->waitq);
843
844	return ipc;
845}
846EXPORT_SYMBOL(snd_sof_ipc_init);
847
848void snd_sof_ipc_free(struct snd_sof_dev *sdev)
849{
850	struct snd_sof_ipc *ipc = sdev->ipc;
851
852	if (!ipc)
853		return;
854
855	/* disable sending of ipc's */
856	mutex_lock(&ipc->tx_mutex);
857	ipc->disable_ipc_tx = true;
858	mutex_unlock(&ipc->tx_mutex);
859}
860EXPORT_SYMBOL(snd_sof_ipc_free);
v5.4
  1// SPDX-License-Identifier: (GPL-2.0 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) 2018 Intel Corporation. All rights reserved.
  7//
  8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
  9//
 10// Generic IPC layer that can work over MMIO and SPI/I2C. PHY layer provided
 11// by platform driver code.
 12//
 13
 14#include <linux/mutex.h>
 15#include <linux/types.h>
 16
 17#include "sof-priv.h"
 
 18#include "ops.h"
 19
 20static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id);
 21static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd);
 22
 23/*
 24 * IPC message Tx/Rx message handling.
 25 */
 26
 27/* SOF generic IPC data */
 28struct snd_sof_ipc {
 29	struct snd_sof_dev *sdev;
 30
 31	/* protects messages and the disable flag */
 32	struct mutex tx_mutex;
 33	/* disables further sending of ipc's */
 34	bool disable_ipc_tx;
 35
 36	struct snd_sof_ipc_msg msg;
 37};
 38
 39struct sof_ipc_ctrl_data_params {
 40	size_t msg_bytes;
 41	size_t hdr_bytes;
 42	size_t pl_size;
 43	size_t elems;
 44	u32 num_msg;
 45	u8 *src;
 46	u8 *dst;
 47};
 48
 49#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC)
 50static void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
 51{
 52	u8 *str;
 53	u8 *str2 = NULL;
 54	u32 glb;
 55	u32 type;
 56
 57	glb = cmd & SOF_GLB_TYPE_MASK;
 58	type = cmd & SOF_CMD_TYPE_MASK;
 59
 60	switch (glb) {
 61	case SOF_IPC_GLB_REPLY:
 62		str = "GLB_REPLY"; break;
 63	case SOF_IPC_GLB_COMPOUND:
 64		str = "GLB_COMPOUND"; break;
 65	case SOF_IPC_GLB_TPLG_MSG:
 66		str = "GLB_TPLG_MSG";
 67		switch (type) {
 68		case SOF_IPC_TPLG_COMP_NEW:
 69			str2 = "COMP_NEW"; break;
 70		case SOF_IPC_TPLG_COMP_FREE:
 71			str2 = "COMP_FREE"; break;
 72		case SOF_IPC_TPLG_COMP_CONNECT:
 73			str2 = "COMP_CONNECT"; break;
 74		case SOF_IPC_TPLG_PIPE_NEW:
 75			str2 = "PIPE_NEW"; break;
 76		case SOF_IPC_TPLG_PIPE_FREE:
 77			str2 = "PIPE_FREE"; break;
 78		case SOF_IPC_TPLG_PIPE_CONNECT:
 79			str2 = "PIPE_CONNECT"; break;
 80		case SOF_IPC_TPLG_PIPE_COMPLETE:
 81			str2 = "PIPE_COMPLETE"; break;
 82		case SOF_IPC_TPLG_BUFFER_NEW:
 83			str2 = "BUFFER_NEW"; break;
 84		case SOF_IPC_TPLG_BUFFER_FREE:
 85			str2 = "BUFFER_FREE"; break;
 86		default:
 87			str2 = "unknown type"; break;
 88		}
 89		break;
 90	case SOF_IPC_GLB_PM_MSG:
 91		str = "GLB_PM_MSG";
 92		switch (type) {
 93		case SOF_IPC_PM_CTX_SAVE:
 94			str2 = "CTX_SAVE"; break;
 95		case SOF_IPC_PM_CTX_RESTORE:
 96			str2 = "CTX_RESTORE"; break;
 97		case SOF_IPC_PM_CTX_SIZE:
 98			str2 = "CTX_SIZE"; break;
 99		case SOF_IPC_PM_CLK_SET:
100			str2 = "CLK_SET"; break;
101		case SOF_IPC_PM_CLK_GET:
102			str2 = "CLK_GET"; break;
103		case SOF_IPC_PM_CLK_REQ:
104			str2 = "CLK_REQ"; break;
105		case SOF_IPC_PM_CORE_ENABLE:
106			str2 = "CORE_ENABLE"; break;
107		default:
108			str2 = "unknown type"; break;
109		}
110		break;
111	case SOF_IPC_GLB_COMP_MSG:
112		str = "GLB_COMP_MSG";
113		switch (type) {
114		case SOF_IPC_COMP_SET_VALUE:
115			str2 = "SET_VALUE"; break;
116		case SOF_IPC_COMP_GET_VALUE:
117			str2 = "GET_VALUE"; break;
118		case SOF_IPC_COMP_SET_DATA:
119			str2 = "SET_DATA"; break;
120		case SOF_IPC_COMP_GET_DATA:
121			str2 = "GET_DATA"; break;
122		default:
123			str2 = "unknown type"; break;
124		}
125		break;
126	case SOF_IPC_GLB_STREAM_MSG:
127		str = "GLB_STREAM_MSG";
128		switch (type) {
129		case SOF_IPC_STREAM_PCM_PARAMS:
130			str2 = "PCM_PARAMS"; break;
131		case SOF_IPC_STREAM_PCM_PARAMS_REPLY:
132			str2 = "PCM_REPLY"; break;
133		case SOF_IPC_STREAM_PCM_FREE:
134			str2 = "PCM_FREE"; break;
135		case SOF_IPC_STREAM_TRIG_START:
136			str2 = "TRIG_START"; break;
137		case SOF_IPC_STREAM_TRIG_STOP:
138			str2 = "TRIG_STOP"; break;
139		case SOF_IPC_STREAM_TRIG_PAUSE:
140			str2 = "TRIG_PAUSE"; break;
141		case SOF_IPC_STREAM_TRIG_RELEASE:
142			str2 = "TRIG_RELEASE"; break;
143		case SOF_IPC_STREAM_TRIG_DRAIN:
144			str2 = "TRIG_DRAIN"; break;
145		case SOF_IPC_STREAM_TRIG_XRUN:
146			str2 = "TRIG_XRUN"; break;
147		case SOF_IPC_STREAM_POSITION:
148			str2 = "POSITION"; break;
149		case SOF_IPC_STREAM_VORBIS_PARAMS:
150			str2 = "VORBIS_PARAMS"; break;
151		case SOF_IPC_STREAM_VORBIS_FREE:
152			str2 = "VORBIS_FREE"; break;
153		default:
154			str2 = "unknown type"; break;
155		}
156		break;
157	case SOF_IPC_FW_READY:
158		str = "FW_READY"; break;
159	case SOF_IPC_GLB_DAI_MSG:
160		str = "GLB_DAI_MSG";
161		switch (type) {
162		case SOF_IPC_DAI_CONFIG:
163			str2 = "CONFIG"; break;
164		case SOF_IPC_DAI_LOOPBACK:
165			str2 = "LOOPBACK"; break;
166		default:
167			str2 = "unknown type"; break;
168		}
169		break;
170	case SOF_IPC_GLB_TRACE_MSG:
171		str = "GLB_TRACE_MSG"; break;
172	case SOF_IPC_GLB_TEST_MSG:
173		str = "GLB_TEST_MSG";
174		switch (type) {
175		case SOF_IPC_TEST_IPC_FLOOD:
176			str2 = "IPC_FLOOD"; break;
177		default:
178			str2 = "unknown type"; break;
179		}
180		break;
181	default:
182		str = "unknown GLB command"; break;
183	}
184
185	if (str2)
186		dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2);
187	else
188		dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str);
189}
190#else
191static inline void ipc_log_header(struct device *dev, u8 *text, u32 cmd)
192{
193	if ((cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_TRACE_MSG)
194		dev_dbg(dev, "%s: 0x%x\n", text, cmd);
195}
196#endif
197
198/* wait for IPC message reply */
199static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg,
200			void *reply_data)
201{
202	struct snd_sof_dev *sdev = ipc->sdev;
203	struct sof_ipc_cmd_hdr *hdr = msg->msg_data;
204	int ret;
205
206	/* wait for DSP IPC completion */
207	ret = wait_event_timeout(msg->waitq, msg->ipc_complete,
208				 msecs_to_jiffies(sdev->ipc_timeout));
209
210	if (ret == 0) {
211		dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n",
212			hdr->cmd, hdr->size);
213		snd_sof_dsp_dbg_dump(ipc->sdev, SOF_DBG_REGS | SOF_DBG_MBOX);
214		snd_sof_ipc_dump(ipc->sdev);
215		snd_sof_trace_notify_for_error(ipc->sdev);
216		ret = -ETIMEDOUT;
217	} else {
218		/* copy the data returned from DSP */
219		ret = msg->reply_error;
220		if (msg->reply_size)
221			memcpy(reply_data, msg->reply_data, msg->reply_size);
222		if (ret < 0)
223			dev_err(sdev->dev, "error: ipc error for 0x%x size %zu\n",
224				hdr->cmd, msg->reply_size);
225		else
226			ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd);
 
 
 
 
 
227	}
228
229	return ret;
230}
231
232/* send IPC message from host to DSP */
233static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header,
234				       void *msg_data, size_t msg_bytes,
235				       void *reply_data, size_t reply_bytes)
236{
237	struct snd_sof_dev *sdev = ipc->sdev;
238	struct snd_sof_ipc_msg *msg;
239	int ret;
240
241	if (ipc->disable_ipc_tx)
242		return -ENODEV;
243
244	/*
245	 * The spin-lock is also still needed to protect message objects against
246	 * other atomic contexts.
247	 */
248	spin_lock_irq(&sdev->ipc_lock);
249
250	/* initialise the message */
251	msg = &ipc->msg;
252
253	msg->header = header;
254	msg->msg_size = msg_bytes;
255	msg->reply_size = reply_bytes;
256	msg->reply_error = 0;
257
258	/* attach any data */
259	if (msg_bytes)
260		memcpy(msg->msg_data, msg_data, msg_bytes);
261
262	sdev->msg = msg;
263
264	ret = snd_sof_dsp_send_msg(sdev, msg);
265	/* Next reply that we receive will be related to this message */
266	if (!ret)
267		msg->ipc_complete = false;
268
269	spin_unlock_irq(&sdev->ipc_lock);
270
271	if (ret < 0) {
272		/* So far IPC TX never fails, consider making the above void */
273		dev_err_ratelimited(sdev->dev,
274				    "error: ipc tx failed with error %d\n",
275				    ret);
276		return ret;
277	}
278
279	ipc_log_header(sdev->dev, "ipc tx", msg->header);
280
281	/* now wait for completion */
282	if (!ret)
283		ret = tx_wait_done(ipc, msg, reply_data);
284
285	return ret;
286}
287
288/* send IPC message from host to DSP */
289int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header,
290		       void *msg_data, size_t msg_bytes, void *reply_data,
291		       size_t reply_bytes)
292{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293	int ret;
294
295	if (msg_bytes > SOF_IPC_MSG_MAX_SIZE ||
296	    reply_bytes > SOF_IPC_MSG_MAX_SIZE)
297		return -ENOBUFS;
298
299	/* Serialise IPC TX */
300	mutex_lock(&ipc->tx_mutex);
301
302	ret = sof_ipc_tx_message_unlocked(ipc, header, msg_data, msg_bytes,
303					  reply_data, reply_bytes);
304
305	mutex_unlock(&ipc->tx_mutex);
306
307	return ret;
308}
309EXPORT_SYMBOL(sof_ipc_tx_message);
310
311/* handle reply message from DSP */
312int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
313{
314	struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
315
316	if (msg->ipc_complete) {
317		dev_err(sdev->dev, "error: no reply expected, received 0x%x",
 
318			msg_id);
319		return -EINVAL;
320	}
321
322	/* wake up and return the error if we have waiters on this message ? */
323	msg->ipc_complete = true;
324	wake_up(&msg->waitq);
325
326	return 0;
327}
328EXPORT_SYMBOL(snd_sof_ipc_reply);
329
330/* DSP firmware has sent host a message  */
331void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev)
332{
333	struct sof_ipc_cmd_hdr hdr;
334	u32 cmd, type;
335	int err = 0;
336
337	/* read back header */
338	snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr));
339	ipc_log_header(sdev->dev, "ipc rx", hdr.cmd);
340
341	cmd = hdr.cmd & SOF_GLB_TYPE_MASK;
342	type = hdr.cmd & SOF_CMD_TYPE_MASK;
343
344	/* check message type */
345	switch (cmd) {
346	case SOF_IPC_GLB_REPLY:
347		dev_err(sdev->dev, "error: ipc reply unknown\n");
348		break;
349	case SOF_IPC_FW_READY:
350		/* check for FW boot completion */
351		if (!sdev->boot_complete) {
352			err = sof_ops(sdev)->fw_ready(sdev, cmd);
353			if (err < 0) {
354				/*
355				 * this indicates a mismatch in ABI
356				 * between the driver and fw
357				 */
358				dev_err(sdev->dev, "error: ABI mismatch %d\n",
359					err);
360			} else {
361				/* firmware boot completed OK */
362				sdev->boot_complete = true;
363			}
364
365			/* wake up firmware loader */
366			wake_up(&sdev->boot_wait);
367		}
368		break;
369	case SOF_IPC_GLB_COMPOUND:
370	case SOF_IPC_GLB_TPLG_MSG:
371	case SOF_IPC_GLB_PM_MSG:
372	case SOF_IPC_GLB_COMP_MSG:
373		break;
374	case SOF_IPC_GLB_STREAM_MSG:
375		/* need to pass msg id into the function */
376		ipc_stream_message(sdev, hdr.cmd);
377		break;
378	case SOF_IPC_GLB_TRACE_MSG:
379		ipc_trace_message(sdev, type);
380		break;
381	default:
382		dev_err(sdev->dev, "error: unknown DSP message 0x%x\n", cmd);
383		break;
384	}
385
386	ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd);
387}
388EXPORT_SYMBOL(snd_sof_ipc_msgs_rx);
389
390/*
391 * IPC trace mechanism.
392 */
393
394static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id)
395{
396	struct sof_ipc_dma_trace_posn posn;
397
398	switch (msg_id) {
399	case SOF_IPC_TRACE_DMA_POSITION:
400		/* read back full message */
401		snd_sof_ipc_msg_data(sdev, NULL, &posn, sizeof(posn));
402		snd_sof_trace_update_pos(sdev, &posn);
403		break;
404	default:
405		dev_err(sdev->dev, "error: unhandled trace message %x\n",
406			msg_id);
407		break;
408	}
409}
410
411/*
412 * IPC stream position.
413 */
414
415static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
416{
 
417	struct snd_sof_pcm_stream *stream;
418	struct sof_ipc_stream_posn posn;
419	struct snd_sof_pcm *spcm;
420	int direction;
421
422	spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction);
423	if (!spcm) {
424		dev_err(sdev->dev,
425			"error: period elapsed for unknown stream, msg_id %d\n",
426			msg_id);
427		return;
428	}
429
430	stream = &spcm->stream[direction];
431	snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
432
433	dev_dbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n",
434		posn.host_posn, posn.dai_posn, posn.wallclock);
435
436	memcpy(&stream->posn, &posn, sizeof(posn));
437
438	/* only inform ALSA for period_wakeup mode */
439	if (!stream->substream->runtime->no_period_wakeup)
440		snd_sof_pcm_period_elapsed(stream->substream);
441}
442
443/* DSP notifies host of an XRUN within FW */
444static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id)
445{
 
446	struct snd_sof_pcm_stream *stream;
447	struct sof_ipc_stream_posn posn;
448	struct snd_sof_pcm *spcm;
449	int direction;
450
451	spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction);
452	if (!spcm) {
453		dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n",
454			msg_id);
455		return;
456	}
457
458	stream = &spcm->stream[direction];
459	snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn));
460
461	dev_dbg(sdev->dev,  "posn XRUN: host %llx comp %d size %d\n",
462		posn.host_posn, posn.xrun_comp_id, posn.xrun_size);
463
464#if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP)
465	/* stop PCM on XRUN - used for pipeline debug */
466	memcpy(&stream->posn, &posn, sizeof(posn));
467	snd_pcm_stop_xrun(stream->substream);
468#endif
469}
470
471/* stream notifications from DSP FW */
472static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd)
473{
474	/* get msg cmd type and msd id */
475	u32 msg_type = msg_cmd & SOF_CMD_TYPE_MASK;
476	u32 msg_id = SOF_IPC_MESSAGE_ID(msg_cmd);
477
478	switch (msg_type) {
479	case SOF_IPC_STREAM_POSITION:
480		ipc_period_elapsed(sdev, msg_id);
481		break;
482	case SOF_IPC_STREAM_TRIG_XRUN:
483		ipc_xrun(sdev, msg_id);
484		break;
485	default:
486		dev_err(sdev->dev, "error: unhandled stream message %x\n",
487			msg_id);
488		break;
489	}
490}
491
492/* get stream position IPC - use faster MMIO method if available on platform */
493int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev,
494			    struct snd_sof_pcm *spcm, int direction,
495			    struct sof_ipc_stream_posn *posn)
496{
 
497	struct sof_ipc_stream stream;
498	int err;
499
500	/* read position via slower IPC */
501	stream.hdr.size = sizeof(stream);
502	stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_POSITION;
503	stream.comp_id = spcm->stream[direction].comp_id;
504
505	/* send IPC to the DSP */
506	err = sof_ipc_tx_message(sdev->ipc,
507				 stream.hdr.cmd, &stream, sizeof(stream), &posn,
508				 sizeof(*posn));
509	if (err < 0) {
510		dev_err(sdev->dev, "error: failed to get stream %d position\n",
511			stream.comp_id);
512		return err;
513	}
514
515	return 0;
516}
517EXPORT_SYMBOL(snd_sof_ipc_stream_posn);
518
519static int sof_get_ctrl_copy_params(enum sof_ipc_ctrl_type ctrl_type,
520				    struct sof_ipc_ctrl_data *src,
521				    struct sof_ipc_ctrl_data *dst,
522				    struct sof_ipc_ctrl_data_params *sparams)
523{
524	switch (ctrl_type) {
525	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
526	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
527		sparams->src = (u8 *)src->chanv;
528		sparams->dst = (u8 *)dst->chanv;
529		break;
530	case SOF_CTRL_TYPE_VALUE_COMP_GET:
531	case SOF_CTRL_TYPE_VALUE_COMP_SET:
532		sparams->src = (u8 *)src->compv;
533		sparams->dst = (u8 *)dst->compv;
534		break;
535	case SOF_CTRL_TYPE_DATA_GET:
536	case SOF_CTRL_TYPE_DATA_SET:
537		sparams->src = (u8 *)src->data->data;
538		sparams->dst = (u8 *)dst->data->data;
539		break;
540	default:
541		return -EINVAL;
542	}
543
544	/* calculate payload size and number of messages */
545	sparams->pl_size = SOF_IPC_MSG_MAX_SIZE - sparams->hdr_bytes;
546	sparams->num_msg = DIV_ROUND_UP(sparams->msg_bytes, sparams->pl_size);
547
548	return 0;
549}
550
551static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
552				       struct sof_ipc_ctrl_data *cdata,
553				       struct sof_ipc_ctrl_data_params *sparams,
554				       bool send)
555{
556	struct sof_ipc_ctrl_data *partdata;
557	size_t send_bytes;
558	size_t offset = 0;
559	size_t msg_bytes;
560	size_t pl_size;
561	int err;
562	int i;
563
564	/* allocate max ipc size because we have at least one */
565	partdata = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL);
566	if (!partdata)
567		return -ENOMEM;
568
569	if (send)
570		err = sof_get_ctrl_copy_params(cdata->type, cdata, partdata,
571					       sparams);
572	else
573		err = sof_get_ctrl_copy_params(cdata->type, partdata, cdata,
574					       sparams);
575	if (err < 0) {
576		kfree(partdata);
577		return err;
578	}
579
580	msg_bytes = sparams->msg_bytes;
581	pl_size = sparams->pl_size;
582
583	/* copy the header data */
584	memcpy(partdata, cdata, sparams->hdr_bytes);
585
586	/* Serialise IPC TX */
587	mutex_lock(&sdev->ipc->tx_mutex);
588
589	/* copy the payload data in a loop */
590	for (i = 0; i < sparams->num_msg; i++) {
591		send_bytes = min(msg_bytes, pl_size);
592		partdata->num_elems = send_bytes;
593		partdata->rhdr.hdr.size = sparams->hdr_bytes + send_bytes;
594		partdata->msg_index = i;
595		msg_bytes -= send_bytes;
596		partdata->elems_remaining = msg_bytes;
597
598		if (send)
599			memcpy(sparams->dst, sparams->src + offset, send_bytes);
600
601		err = sof_ipc_tx_message_unlocked(sdev->ipc,
602						  partdata->rhdr.hdr.cmd,
603						  partdata,
604						  partdata->rhdr.hdr.size,
605						  partdata,
606						  partdata->rhdr.hdr.size);
607		if (err < 0)
608			break;
609
610		if (!send)
611			memcpy(sparams->dst + offset, sparams->src, send_bytes);
612
613		offset += pl_size;
614	}
615
616	mutex_unlock(&sdev->ipc->tx_mutex);
617
618	kfree(partdata);
619	return err;
620}
621
622/*
623 * IPC get()/set() for kcontrols.
624 */
625int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc,
626				  struct snd_sof_control *scontrol,
627				  u32 ipc_cmd,
628				  enum sof_ipc_ctrl_type ctrl_type,
629				  enum sof_ipc_ctrl_cmd ctrl_cmd,
630				  bool send)
631{
 
632	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
633	struct snd_sof_dev *sdev = ipc->sdev;
634	struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
635	struct sof_ipc_fw_version *v = &ready->version;
636	struct sof_ipc_ctrl_data_params sparams;
637	size_t send_bytes;
638	int err;
639
640	/* read or write firmware volume */
641	if (scontrol->readback_offset != 0) {
642		/* write/read value header via mmaped region */
643		send_bytes = sizeof(struct sof_ipc_ctrl_value_chan) *
644		cdata->num_elems;
645		if (send)
646			snd_sof_dsp_block_write(sdev, sdev->mmio_bar,
647						scontrol->readback_offset,
648						cdata->chanv, send_bytes);
649
650		else
651			snd_sof_dsp_block_read(sdev, sdev->mmio_bar,
652					       scontrol->readback_offset,
653					       cdata->chanv, send_bytes);
654		return 0;
655	}
656
657	cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd;
658	cdata->cmd = ctrl_cmd;
659	cdata->type = ctrl_type;
660	cdata->comp_id = scontrol->comp_id;
661	cdata->msg_index = 0;
662
663	/* calculate header and data size */
664	switch (cdata->type) {
665	case SOF_CTRL_TYPE_VALUE_CHAN_GET:
666	case SOF_CTRL_TYPE_VALUE_CHAN_SET:
667		sparams.msg_bytes = scontrol->num_channels *
668			sizeof(struct sof_ipc_ctrl_value_chan);
669		sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
670		sparams.elems = scontrol->num_channels;
671		break;
672	case SOF_CTRL_TYPE_VALUE_COMP_GET:
673	case SOF_CTRL_TYPE_VALUE_COMP_SET:
674		sparams.msg_bytes = scontrol->num_channels *
675			sizeof(struct sof_ipc_ctrl_value_comp);
676		sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data);
677		sparams.elems = scontrol->num_channels;
678		break;
679	case SOF_CTRL_TYPE_DATA_GET:
680	case SOF_CTRL_TYPE_DATA_SET:
681		sparams.msg_bytes = cdata->data->size;
682		sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data) +
683			sizeof(struct sof_abi_hdr);
684		sparams.elems = cdata->data->size;
685		break;
686	default:
687		return -EINVAL;
688	}
689
690	cdata->rhdr.hdr.size = sparams.msg_bytes + sparams.hdr_bytes;
691	cdata->num_elems = sparams.elems;
692	cdata->elems_remaining = 0;
693
694	/* send normal size ipc in one part */
695	if (cdata->rhdr.hdr.size <= SOF_IPC_MSG_MAX_SIZE) {
696		err = sof_ipc_tx_message(sdev->ipc, cdata->rhdr.hdr.cmd, cdata,
697					 cdata->rhdr.hdr.size, cdata,
698					 cdata->rhdr.hdr.size);
699
700		if (err < 0)
701			dev_err(sdev->dev, "error: set/get ctrl ipc comp %d\n",
702				cdata->comp_id);
703
704		return err;
705	}
706
707	/* data is bigger than max ipc size, chop into smaller pieces */
708	dev_dbg(sdev->dev, "large ipc size %u, control size %u\n",
709		cdata->rhdr.hdr.size, scontrol->size);
710
711	/* large messages is only supported from ABI 3.3.0 onwards */
712	if (v->abi_version < SOF_ABI_VER(3, 3, 0)) {
713		dev_err(sdev->dev, "error: incompatible FW ABI version\n");
714		return -EINVAL;
715	}
716
717	err = sof_set_get_large_ctrl_data(sdev, cdata, &sparams, send);
718
719	if (err < 0)
720		dev_err(sdev->dev, "error: set/get large ctrl ipc comp %d\n",
721			cdata->comp_id);
722
723	return err;
724}
725EXPORT_SYMBOL(snd_sof_ipc_set_get_comp_data);
726
727/*
728 * IPC layer enumeration.
729 */
730
731int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox,
732			     size_t dspbox_size, u32 hostbox,
733			     size_t hostbox_size)
734{
735	sdev->dsp_box.offset = dspbox;
736	sdev->dsp_box.size = dspbox_size;
737	sdev->host_box.offset = hostbox;
738	sdev->host_box.size = hostbox_size;
739	return 0;
740}
741EXPORT_SYMBOL(snd_sof_dsp_mailbox_init);
742
743int snd_sof_ipc_valid(struct snd_sof_dev *sdev)
744{
745	struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
746	struct sof_ipc_fw_version *v = &ready->version;
747
748	dev_info(sdev->dev,
749		 "Firmware info: version %d:%d:%d-%s\n",  v->major, v->minor,
750		 v->micro, v->tag);
751	dev_info(sdev->dev,
752		 "Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
753		 SOF_ABI_VERSION_MAJOR(v->abi_version),
754		 SOF_ABI_VERSION_MINOR(v->abi_version),
755		 SOF_ABI_VERSION_PATCH(v->abi_version),
756		 SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
757
758	if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) {
759		dev_err(sdev->dev, "error: incompatible FW ABI version\n");
760		return -EINVAL;
761	}
762
763	if (v->abi_version > SOF_ABI_VERSION) {
764		if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) {
765			dev_warn(sdev->dev, "warn: FW ABI is more recent than kernel\n");
766		} else {
767			dev_err(sdev->dev, "error: FW ABI is more recent than kernel\n");
768			return -EINVAL;
769		}
770	}
771
772	if (ready->flags & SOF_IPC_INFO_BUILD) {
773		dev_info(sdev->dev,
774			 "Firmware debug build %d on %s-%s - options:\n"
775			 " GDB: %s\n"
776			 " lock debug: %s\n"
777			 " lock vdebug: %s\n",
778			 v->build, v->date, v->time,
779			 (ready->flags & SOF_IPC_INFO_GDB) ?
780				"enabled" : "disabled",
781			 (ready->flags & SOF_IPC_INFO_LOCKS) ?
782				"enabled" : "disabled",
783			 (ready->flags & SOF_IPC_INFO_LOCKSV) ?
784				"enabled" : "disabled");
785	}
786
787	/* copy the fw_version into debugfs at first boot */
788	memcpy(&sdev->fw_version, v, sizeof(*v));
789
790	return 0;
791}
792EXPORT_SYMBOL(snd_sof_ipc_valid);
793
794struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
795{
796	struct snd_sof_ipc *ipc;
797	struct snd_sof_ipc_msg *msg;
798
799	/* check if mandatory ops required for ipc are defined */
800	if (!sof_ops(sdev)->fw_ready) {
801		dev_err(sdev->dev, "error: ipc mandatory ops not defined\n");
802		return NULL;
803	}
804
805	ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL);
806	if (!ipc)
807		return NULL;
808
809	mutex_init(&ipc->tx_mutex);
810	ipc->sdev = sdev;
811	msg = &ipc->msg;
812
813	/* indicate that we aren't sending a message ATM */
814	msg->ipc_complete = true;
815
816	/* pre-allocate message data */
817	msg->msg_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE,
818				     GFP_KERNEL);
819	if (!msg->msg_data)
820		return NULL;
821
822	msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE,
823				       GFP_KERNEL);
824	if (!msg->reply_data)
825		return NULL;
826
827	init_waitqueue_head(&msg->waitq);
828
829	return ipc;
830}
831EXPORT_SYMBOL(snd_sof_ipc_init);
832
833void snd_sof_ipc_free(struct snd_sof_dev *sdev)
834{
835	struct snd_sof_ipc *ipc = sdev->ipc;
 
 
 
836
837	/* disable sending of ipc's */
838	mutex_lock(&ipc->tx_mutex);
839	ipc->disable_ipc_tx = true;
840	mutex_unlock(&ipc->tx_mutex);
841}
842EXPORT_SYMBOL(snd_sof_ipc_free);