0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/mutex.h>
0015 #include <linux/types.h>
0016
0017 #include "sof-priv.h"
0018 #include "sof-audio.h"
0019 #include "ops.h"
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 int sof_ipc_send_msg(struct snd_sof_dev *sdev, void *msg_data, size_t msg_bytes,
0037 size_t reply_bytes)
0038 {
0039 struct snd_sof_ipc *ipc = sdev->ipc;
0040 struct snd_sof_ipc_msg *msg;
0041 int ret;
0042
0043 if (ipc->disable_ipc_tx || sdev->fw_state != SOF_FW_BOOT_COMPLETE)
0044 return -ENODEV;
0045
0046
0047
0048
0049
0050 spin_lock_irq(&sdev->ipc_lock);
0051
0052
0053 msg = &ipc->msg;
0054
0055
0056 msg->msg_data = msg_data;
0057 msg->msg_size = msg_bytes;
0058
0059 msg->reply_size = reply_bytes;
0060 msg->reply_error = 0;
0061
0062 sdev->msg = msg;
0063
0064 ret = snd_sof_dsp_send_msg(sdev, msg);
0065
0066 if (!ret)
0067 msg->ipc_complete = false;
0068
0069 spin_unlock_irq(&sdev->ipc_lock);
0070
0071 return ret;
0072 }
0073
0074
0075 int sof_ipc_tx_message(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes,
0076 void *reply_data, size_t reply_bytes)
0077 {
0078 if (msg_bytes > ipc->max_payload_size ||
0079 reply_bytes > ipc->max_payload_size)
0080 return -ENOBUFS;
0081
0082 return ipc->ops->tx_msg(ipc->sdev, msg_data, msg_bytes, reply_data,
0083 reply_bytes, false);
0084 }
0085 EXPORT_SYMBOL(sof_ipc_tx_message);
0086
0087
0088
0089
0090
0091
0092 int sof_ipc_tx_message_no_pm(struct snd_sof_ipc *ipc, void *msg_data, size_t msg_bytes,
0093 void *reply_data, size_t reply_bytes)
0094 {
0095 if (msg_bytes > ipc->max_payload_size ||
0096 reply_bytes > ipc->max_payload_size)
0097 return -ENOBUFS;
0098
0099 return ipc->ops->tx_msg(ipc->sdev, msg_data, msg_bytes, reply_data,
0100 reply_bytes, true);
0101 }
0102 EXPORT_SYMBOL(sof_ipc_tx_message_no_pm);
0103
0104
0105 void snd_sof_ipc_get_reply(struct snd_sof_dev *sdev)
0106 {
0107
0108
0109
0110
0111
0112 if (!sdev->msg) {
0113 dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n");
0114 return;
0115 }
0116
0117 sdev->msg->reply_error = sdev->ipc->ops->get_reply(sdev);
0118 }
0119 EXPORT_SYMBOL(snd_sof_ipc_get_reply);
0120
0121
0122 void snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id)
0123 {
0124 struct snd_sof_ipc_msg *msg = &sdev->ipc->msg;
0125
0126 if (msg->ipc_complete) {
0127 dev_dbg(sdev->dev,
0128 "no reply expected, received 0x%x, will be ignored",
0129 msg_id);
0130 return;
0131 }
0132
0133
0134 msg->ipc_complete = true;
0135 wake_up(&msg->waitq);
0136 }
0137 EXPORT_SYMBOL(snd_sof_ipc_reply);
0138
0139 struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev)
0140 {
0141 struct snd_sof_ipc *ipc;
0142 struct snd_sof_ipc_msg *msg;
0143 const struct sof_ipc_ops *ops;
0144
0145 ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL);
0146 if (!ipc)
0147 return NULL;
0148
0149 mutex_init(&ipc->tx_mutex);
0150 ipc->sdev = sdev;
0151 msg = &ipc->msg;
0152
0153
0154 msg->ipc_complete = true;
0155
0156 init_waitqueue_head(&msg->waitq);
0157
0158 switch (sdev->pdata->ipc_type) {
0159 #if defined(CONFIG_SND_SOC_SOF_IPC3)
0160 case SOF_IPC:
0161 ops = &ipc3_ops;
0162 break;
0163 #endif
0164 #if defined(CONFIG_SND_SOC_SOF_INTEL_IPC4)
0165 case SOF_INTEL_IPC4:
0166 ops = &ipc4_ops;
0167 break;
0168 #endif
0169 default:
0170 dev_err(sdev->dev, "Not supported IPC version: %d\n",
0171 sdev->pdata->ipc_type);
0172 return NULL;
0173 }
0174
0175
0176 if (!ops->tx_msg || !ops->rx_msg || !ops->set_get_data || !ops->get_reply) {
0177 dev_err(sdev->dev, "Missing IPC message handling ops\n");
0178 return NULL;
0179 }
0180
0181 if (!ops->fw_loader || !ops->fw_loader->validate ||
0182 !ops->fw_loader->parse_ext_manifest) {
0183 dev_err(sdev->dev, "Missing IPC firmware loading ops\n");
0184 return NULL;
0185 }
0186
0187 if (!ops->pcm) {
0188 dev_err(sdev->dev, "Missing IPC PCM ops\n");
0189 return NULL;
0190 }
0191
0192 if (!ops->tplg || !ops->tplg->widget || !ops->tplg->control) {
0193 dev_err(sdev->dev, "Missing IPC topology ops\n");
0194 return NULL;
0195 }
0196
0197 if (ops->fw_tracing && (!ops->fw_tracing->init || !ops->fw_tracing->suspend ||
0198 !ops->fw_tracing->resume)) {
0199 dev_err(sdev->dev, "Missing firmware tracing ops\n");
0200 return NULL;
0201 }
0202
0203 ipc->ops = ops;
0204
0205 return ipc;
0206 }
0207 EXPORT_SYMBOL(snd_sof_ipc_init);
0208
0209 void snd_sof_ipc_free(struct snd_sof_dev *sdev)
0210 {
0211 struct snd_sof_ipc *ipc = sdev->ipc;
0212
0213 if (!ipc)
0214 return;
0215
0216
0217 mutex_lock(&ipc->tx_mutex);
0218 ipc->disable_ipc_tx = true;
0219 mutex_unlock(&ipc->tx_mutex);
0220 }
0221 EXPORT_SYMBOL(snd_sof_ipc_free);