Lines Matching +full:ipc +full:- +full:3
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
10 // Generic IPC layer that can work over MMIO and SPI/I2C. PHY layer provided
17 #include "sof-priv.h"
18 #include "sof-audio.h"
22 * sof_ipc_send_msg - generic function to prepare and send one IPC message
33 * Note: higher level sdev->ipc->tx_mutex must be held to make sure that
39 struct snd_sof_ipc *ipc = sdev->ipc; in sof_ipc_send_msg() local
43 if (ipc->disable_ipc_tx || sdev->fw_state != SOF_FW_BOOT_COMPLETE) in sof_ipc_send_msg()
44 return -ENODEV; in sof_ipc_send_msg()
47 * The spin-lock is needed to protect message objects against other in sof_ipc_send_msg()
50 spin_lock_irq(&sdev->ipc_lock); in sof_ipc_send_msg()
53 msg = &ipc->msg; in sof_ipc_send_msg()
56 msg->msg_data = msg_data; in sof_ipc_send_msg()
57 msg->msg_size = msg_bytes; in sof_ipc_send_msg()
59 msg->reply_size = reply_bytes; in sof_ipc_send_msg()
60 msg->reply_error = 0; in sof_ipc_send_msg()
62 sdev->msg = msg; in sof_ipc_send_msg()
67 msg->ipc_complete = false; in sof_ipc_send_msg()
69 spin_unlock_irq(&sdev->ipc_lock); in sof_ipc_send_msg()
74 /* send IPC message from host to DSP */
75 int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes, in sof_ipc_tx_message() argument
78 if (msg_bytes > ipc->max_payload_size || in sof_ipc_tx_message()
79 reply_bytes > ipc->max_payload_size) in sof_ipc_tx_message()
80 return -ENOBUFS; in sof_ipc_tx_message()
82 return ipc->ops->tx_msg(ipc->sdev, msg_data, msg_bytes, reply_data, in sof_ipc_tx_message()
87 /* IPC set or get data from host to DSP */
88 int sof_ipc_set_get_data(struct snd_sof_ipc *ipc, void *msg_data, in sof_ipc_set_get_data() argument
91 return ipc->ops->set_get_data(ipc->sdev, msg_data, msg_bytes, set); in sof_ipc_set_get_data()
96 * send IPC message from host to DSP without modifying the DSP state.
97 * This will be used for IPC's that can be handled by the DSP
98 * even in a low-power D0 substate.
100 int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes, in sof_ipc_tx_message_no_pm() argument
103 if (msg_bytes > ipc->max_payload_size || in sof_ipc_tx_message_no_pm()
104 reply_bytes > ipc->max_payload_size) in sof_ipc_tx_message_no_pm()
105 return -ENOBUFS; in sof_ipc_tx_message_no_pm()
107 return ipc->ops->tx_msg(ipc->sdev, msg_data, msg_bytes, reply_data, in sof_ipc_tx_message_no_pm()
116 * Sometimes, there is unexpected reply ipc arriving. The reply in snd_sof_ipc_get_reply()
117 * ipc belongs to none of the ipcs sent from driver. in snd_sof_ipc_get_reply()
118 * In this case, the driver must ignore the ipc. in snd_sof_ipc_get_reply()
120 if (!sdev->msg) { in snd_sof_ipc_get_reply()
121 dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); in snd_sof_ipc_get_reply()
125 sdev->msg->reply_error = sdev->ipc->ops->get_reply(sdev); in snd_sof_ipc_get_reply()
132 struct snd_sof_ipc_msg *msg = &sdev->ipc->msg; in snd_sof_ipc_reply()
134 if (msg->ipc_complete) { in snd_sof_ipc_reply()
135 dev_dbg(sdev->dev, in snd_sof_ipc_reply()
142 msg->ipc_complete = true; in snd_sof_ipc_reply()
143 wake_up(&msg->waitq); in snd_sof_ipc_reply()
149 struct snd_sof_ipc *ipc; in snd_sof_ipc_init() local
153 ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL); in snd_sof_ipc_init()
154 if (!ipc) in snd_sof_ipc_init()
157 mutex_init(&ipc->tx_mutex); in snd_sof_ipc_init()
158 ipc->sdev = sdev; in snd_sof_ipc_init()
159 msg = &ipc->msg; in snd_sof_ipc_init()
162 msg->ipc_complete = true; in snd_sof_ipc_init()
164 init_waitqueue_head(&msg->waitq); in snd_sof_ipc_init()
166 switch (sdev->pdata->ipc_type) { in snd_sof_ipc_init()
178 dev_err(sdev->dev, "Not supported IPC version: %d\n", in snd_sof_ipc_init()
179 sdev->pdata->ipc_type); in snd_sof_ipc_init()
184 if (!ops->tx_msg || !ops->rx_msg || !ops->set_get_data || !ops->get_reply) { in snd_sof_ipc_init()
185 dev_err(sdev->dev, "Missing IPC message handling ops\n"); in snd_sof_ipc_init()
189 if (!ops->fw_loader || !ops->fw_loader->validate || in snd_sof_ipc_init()
190 !ops->fw_loader->parse_ext_manifest) { in snd_sof_ipc_init()
191 dev_err(sdev->dev, "Missing IPC firmware loading ops\n"); in snd_sof_ipc_init()
195 if (!ops->pcm) { in snd_sof_ipc_init()
196 dev_err(sdev->dev, "Missing IPC PCM ops\n"); in snd_sof_ipc_init()
200 if (!ops->tplg || !ops->tplg->widget || !ops->tplg->control) { in snd_sof_ipc_init()
201 dev_err(sdev->dev, "Missing IPC topology ops\n"); in snd_sof_ipc_init()
205 if (ops->fw_tracing && (!ops->fw_tracing->init || !ops->fw_tracing->suspend || in snd_sof_ipc_init()
206 !ops->fw_tracing->resume)) { in snd_sof_ipc_init()
207 dev_err(sdev->dev, "Missing firmware tracing ops\n"); in snd_sof_ipc_init()
211 if (ops->init && ops->init(sdev)) in snd_sof_ipc_init()
214 ipc->ops = ops; in snd_sof_ipc_init()
216 return ipc; in snd_sof_ipc_init()
222 struct snd_sof_ipc *ipc = sdev->ipc; in snd_sof_ipc_free() local
224 if (!ipc) in snd_sof_ipc_free()
227 /* disable sending of ipc's */ in snd_sof_ipc_free()
228 mutex_lock(&ipc->tx_mutex); in snd_sof_ipc_free()
229 ipc->disable_ipc_tx = true; in snd_sof_ipc_free()
230 mutex_unlock(&ipc->tx_mutex); in snd_sof_ipc_free()
232 if (ipc->ops->exit) in snd_sof_ipc_free()
233 ipc->ops->exit(sdev); in snd_sof_ipc_free()