Commit abf31fee authored by Cezary Rojewski's avatar Cezary Rojewski Committed by Mark Brown

ASoC: Intel: Update request-reply IPC model

struct ipc_message contains fields: header, tx_data and tx_size which
represent TX i.e. request while RX is represented by rx_data and rx_size
with reply's header equivalent missing.

Reply header may contain some vital information including, but not
limited to, received payload size. Some IPCs have entire payload found
within RX header instead. Content and value of said header is context
dependent and may vary between firmware versions and target platform.
Current model does not allow such IPCs to function at all.

Rather than appending yet another parameter to an already long list of
such for sst_ipc_tx_message_XXXs, declare message container in form of
struct sst_ipc_message and add them to parent's ipc_message declaration.

Align haswell, baytrail and skylake with updated request-reply model and
modify their reply processing functions to save RX header within message
container. Despite the range of changes, status quo is achieved.
Signed-off-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20190723144341.21339-2-cezary.rojewski@intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent b8ba3b57
......@@ -211,7 +211,7 @@ static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt,
static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg)
{
struct sst_byt_stream *stream;
u64 header = msg->header;
u64 header = msg->tx.header;
u8 stream_id = sst_byt_header_str_id(header);
u8 stream_msg = sst_byt_header_msg_id(header);
......@@ -240,9 +240,10 @@ static int sst_byt_process_reply(struct sst_byt *byt, u64 header)
if (msg == NULL)
return 1;
msg->rx.header = header;
if (header & IPC_HEADER_LARGE(true)) {
msg->rx_size = sst_byt_header_data(header);
sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size);
msg->rx.size = sst_byt_header_data(header);
sst_dsp_inbox_read(byt->dsp, msg->rx.data, msg->rx.size);
}
/* update any stream states */
......@@ -407,17 +408,18 @@ int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream)
{
struct sst_byt_alloc_params *str_req = &stream->request;
struct sst_byt_alloc_response *reply = &stream->reply;
u64 header;
struct sst_ipc_message request, reply = {0};
int ret;
header = sst_byt_header(IPC_IA_ALLOC_STREAM,
sizeof(*str_req) + sizeof(u32),
request.header = sst_byt_header(IPC_IA_ALLOC_STREAM,
sizeof(stream->request) + sizeof(u32),
true, stream->str_id);
ret = sst_ipc_tx_message_wait(&byt->ipc, header, str_req,
sizeof(*str_req),
reply, sizeof(*reply));
request.data = &stream->request;
request.size = sizeof(stream->request);
reply.data = &stream->reply;
reply.size = sizeof(stream->reply);
ret = sst_ipc_tx_message_wait(&byt->ipc, request, &reply);
if (ret < 0) {
dev_err(byt->dev, "ipc: error stream commit failed\n");
return ret;
......@@ -430,7 +432,7 @@ int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream)
int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
{
u64 header;
struct sst_ipc_message request = {0};
int ret = 0;
struct sst_dsp *sst = byt->dsp;
unsigned long flags;
......@@ -438,8 +440,9 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
if (!stream->commited)
goto out;
header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id);
ret = sst_ipc_tx_message_wait(&byt->ipc, header, NULL, 0, NULL, 0);
request.header = sst_byt_header(IPC_IA_FREE_STREAM,
0, false, stream->str_id);
ret = sst_ipc_tx_message_wait(&byt->ipc, request, NULL);
if (ret < 0) {
dev_err(byt->dev, "ipc: free stream %d failed\n",
stream->str_id);
......@@ -459,15 +462,13 @@ int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
static int sst_byt_stream_operations(struct sst_byt *byt, int type,
int stream_id, int wait)
{
u64 header;
struct sst_ipc_message request = {0};
header = sst_byt_header(type, 0, false, stream_id);
request.header = sst_byt_header(type, 0, false, stream_id);
if (wait)
return sst_ipc_tx_message_wait(&byt->ipc, header, NULL,
0, NULL, 0);
return sst_ipc_tx_message_wait(&byt->ipc, request, NULL);
else
return sst_ipc_tx_message_nowait(&byt->ipc, header,
NULL, 0);
return sst_ipc_tx_message_nowait(&byt->ipc, request);
}
/* stream ALSA trigger operations */
......@@ -475,19 +476,17 @@ int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream,
u32 start_offset)
{
struct sst_byt_start_stream_params start_stream;
void *tx_msg;
size_t size;
u64 header;
struct sst_ipc_message request;
int ret;
start_stream.byte_offset = start_offset;
header = sst_byt_header(IPC_IA_START_STREAM,
request.header = sst_byt_header(IPC_IA_START_STREAM,
sizeof(start_stream) + sizeof(u32),
true, stream->str_id);
tx_msg = &start_stream;
size = sizeof(start_stream);
request.data = &start_stream;
request.size = sizeof(start_stream);
ret = sst_ipc_tx_message_nowait(&byt->ipc, header, tx_msg, size);
ret = sst_ipc_tx_message_nowait(&byt->ipc, request);
if (ret < 0)
dev_err(byt->dev, "ipc: error failed to start stream %d\n",
stream->str_id);
......@@ -623,10 +622,10 @@ EXPORT_SYMBOL_GPL(sst_byt_dsp_wait_for_ready);
static void byt_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
{
if (msg->header & IPC_HEADER_LARGE(true))
sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size);
if (msg->tx.header & IPC_HEADER_LARGE(true))
sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size);
sst_dsp_shim_write64_unlocked(ipc->dsp, SST_IPCX, msg->header);
sst_dsp_shim_write64_unlocked(ipc->dsp, SST_IPCX, msg->tx.header);
}
static void byt_shim_dbg(struct sst_generic_ipc *ipc, const char *text)
......@@ -648,9 +647,9 @@ static void byt_tx_data_copy(struct ipc_message *msg, char *tx_data,
size_t tx_size)
{
/* msg content = lower 32-bit of the header + data */
*(u32 *)msg->tx_data = (u32)(msg->header & (u32)-1);
memcpy(msg->tx_data + sizeof(u32), tx_data, tx_size);
msg->tx_size += sizeof(u32);
*(u32 *)msg->tx.data = (u32)(msg->tx.header & (u32)-1);
memcpy(msg->tx.data + sizeof(u32), tx_data, tx_size);
msg->tx.size += sizeof(u32);
}
static u64 byt_reply_msg_match(u64 header, u64 *mask)
......
......@@ -43,7 +43,7 @@ static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc)
}
static int tx_wait_done(struct sst_generic_ipc *ipc,
struct ipc_message *msg, void *rx_data)
struct ipc_message *msg, struct sst_ipc_message *reply)
{
unsigned long flags;
int ret;
......@@ -62,8 +62,11 @@ static int tx_wait_done(struct sst_generic_ipc *ipc,
} else {
/* copy the data returned from DSP */
if (rx_data)
memcpy(rx_data, msg->rx_data, msg->rx_size);
if (reply) {
reply->header = msg->rx.header;
if (reply->data)
memcpy(reply->data, msg->rx.data, msg->rx.size);
}
ret = msg->errno;
}
......@@ -72,9 +75,9 @@ static int tx_wait_done(struct sst_generic_ipc *ipc,
return ret;
}
static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header,
void *tx_data, size_t tx_bytes, void *rx_data,
size_t rx_bytes, int wait)
static int ipc_tx_message(struct sst_generic_ipc *ipc,
struct sst_ipc_message request,
struct sst_ipc_message *reply, int wait)
{
struct ipc_message *msg;
unsigned long flags;
......@@ -87,23 +90,24 @@ static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header,
return -EBUSY;
}
msg->header = header;
msg->tx_size = tx_bytes;
msg->rx_size = rx_bytes;
msg->tx.header = request.header;
msg->tx.size = request.size;
msg->rx.header = 0;
msg->rx.size = reply ? reply->size : 0;
msg->wait = wait;
msg->errno = 0;
msg->pending = false;
msg->complete = false;
if ((tx_bytes) && (ipc->ops.tx_data_copy != NULL))
ipc->ops.tx_data_copy(msg, tx_data, tx_bytes);
if ((request.size) && (ipc->ops.tx_data_copy != NULL))
ipc->ops.tx_data_copy(msg, request.data, request.size);
list_add_tail(&msg->list, &ipc->tx_list);
schedule_work(&ipc->kwork);
spin_unlock_irqrestore(&ipc->dsp->spinlock, flags);
if (wait)
return tx_wait_done(ipc, msg, rx_data);
return tx_wait_done(ipc, msg, reply);
else
return 0;
}
......@@ -118,13 +122,13 @@ static int msg_empty_list_init(struct sst_generic_ipc *ipc)
return -ENOMEM;
for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
ipc->msg[i].tx_data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL);
if (ipc->msg[i].tx_data == NULL)
ipc->msg[i].tx.data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL);
if (ipc->msg[i].tx.data == NULL)
goto free_mem;
ipc->msg[i].rx_data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL);
if (ipc->msg[i].rx_data == NULL) {
kfree(ipc->msg[i].tx_data);
ipc->msg[i].rx.data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL);
if (ipc->msg[i].rx.data == NULL) {
kfree(ipc->msg[i].tx.data);
goto free_mem;
}
......@@ -136,8 +140,8 @@ static int msg_empty_list_init(struct sst_generic_ipc *ipc)
free_mem:
while (i > 0) {
kfree(ipc->msg[i-1].tx_data);
kfree(ipc->msg[i-1].rx_data);
kfree(ipc->msg[i-1].tx.data);
kfree(ipc->msg[i-1].rx.data);
--i;
}
kfree(ipc->msg);
......@@ -173,8 +177,8 @@ static void ipc_tx_msgs(struct work_struct *work)
spin_unlock_irq(&ipc->dsp->spinlock);
}
int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc,
struct sst_ipc_message request, struct sst_ipc_message *reply)
{
int ret;
......@@ -187,8 +191,7 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
if (ipc->ops.check_dsp_lp_on(ipc->dsp, true))
return -EIO;
ret = ipc_tx_message(ipc, header, tx_data, tx_bytes,
rx_data, rx_bytes, 1);
ret = ipc_tx_message(ipc, request, reply, 1);
if (ipc->ops.check_dsp_lp_on)
if (ipc->ops.check_dsp_lp_on(ipc->dsp, false))
......@@ -198,19 +201,17 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
}
EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait);
int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header,
void *tx_data, size_t tx_bytes)
int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc,
struct sst_ipc_message request)
{
return ipc_tx_message(ipc, header, tx_data, tx_bytes,
NULL, 0, 0);
return ipc_tx_message(ipc, request, NULL, 0);
}
EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait);
int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header,
void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc,
struct sst_ipc_message request, struct sst_ipc_message *reply)
{
return ipc_tx_message(ipc, header, tx_data, tx_bytes,
rx_data, rx_bytes, 1);
return ipc_tx_message(ipc, request, reply, 1);
}
EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm);
......@@ -230,7 +231,7 @@ struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
}
list_for_each_entry(msg, &ipc->rx_list, list) {
if ((msg->header & mask) == header)
if ((msg->tx.header & mask) == header)
return msg;
}
......@@ -304,8 +305,8 @@ void sst_ipc_fini(struct sst_generic_ipc *ipc)
if (ipc->msg) {
for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
kfree(ipc->msg[i].tx_data);
kfree(ipc->msg[i].rx_data);
kfree(ipc->msg[i].tx.data);
kfree(ipc->msg[i].rx.data);
}
kfree(ipc->msg);
}
......
......@@ -17,15 +17,16 @@
#define IPC_MAX_MAILBOX_BYTES 256
struct ipc_message {
struct list_head list;
struct sst_ipc_message {
u64 header;
void *data;
size_t size;
};
/* direction wrt host CPU */
char *tx_data;
size_t tx_size;
char *rx_data;
size_t rx_size;
struct ipc_message {
struct list_head list;
struct sst_ipc_message tx;
struct sst_ipc_message rx;
wait_queue_head_t waitq;
bool pending;
......@@ -66,14 +67,14 @@ struct sst_generic_ipc {
struct sst_plat_ipc_ops ops;
};
int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header,
void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes);
int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc,
struct sst_ipc_message request, struct sst_ipc_message *reply);
int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header,
void *tx_data, size_t tx_bytes);
int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc,
struct sst_ipc_message request);
int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header,
void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes);
int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc,
struct sst_ipc_message request, struct sst_ipc_message *reply);
struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc,
u64 header);
......
This diff is collapsed.
......@@ -366,10 +366,10 @@ static struct sst_dsp_device cnl_dev = {
static void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
{
struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header);
struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header);
if (msg->tx_size)
sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size);
if (msg->tx.size)
sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size);
sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD,
header->extension);
sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR,
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment