1
0
Fork 0

MLK-23421: fw: imx: seco_mu: Use fast IPC

Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
5.4-rM2-2.2.x-imx-squashed
Franck LENORMAND 2020-03-04 11:11:49 +01:00
parent 297f4cf6e1
commit da897c095b
1 changed files with 94 additions and 183 deletions

View File

@ -68,9 +68,9 @@
#include <linux/firmware/imx/seco_mu_ioctl.h>
#include <linux/mailbox_client.h>
#define MAX_RECV_SIZE 8
#define MAX_RECV_SIZE 31
#define MAX_RECV_SIZE_BYTES (MAX_RECV_SIZE * sizeof(u32))
#define MAX_MESSAGE_SIZE 20
#define MAX_MESSAGE_SIZE 31
#define MAX_MESSAGE_SIZE_BYTES (MAX_MESSAGE_SIZE * sizeof(u32))
#define MESSAGE_SIZE(hdr) (((struct she_mu_hdr *)(&(hdr)))->size)
#define MESSAGE_TAG(hdr) (((struct she_mu_hdr *)(&(hdr)))->tag)
@ -78,15 +78,12 @@
#define MESSAGING_TAG_COMMAND (0x17u)
#define MESSAGING_TAG_RESPONSE (0xe1u)
/* number of MU_TR registers */
#define MU_TR_COUNT (4u)
/* number of MU_RR registers */
#define MU_RR_COUNT (4u)
#define SECURE_RAM_BASE_ADDRESS (0x31800000ULL)
#define SECURE_RAM_BASE_ADDRESS_SCU (0x20800000u)
#define SECURE_RAM_SIZE (0x10000ULL)
#define SECO_MU_DEFAULT_MAX_USERS 4
#define SECO_MU_INTERRUPT_INDEX (0u)
#define SECO_DEFAULT_MU_INDEX (1u)
#define SECO_DEFAULT_TZ (0u)
@ -162,23 +159,11 @@ struct seco_mu_priv {
u32 seco_mu_id;
struct mbox_client cl;
struct com_chan {
struct mbox_client cl;
struct mbox_chan *chan;
u8 idx;
} com_chans[MU_TR_COUNT + MU_RR_COUNT];
struct mbox_chan *tx_started;
struct mbox_chan *tx_chan;
struct mbox_chan *rx_chan;
struct imx_sc_ipc *ipc_scu;
u8 seco_part_owner;
void *debug_ptr;
struct seco_mu_device_ctx *prot_ctx;
u32 prot_buf[MAX_RECV_SIZE];
u32 prot_word_received; /* bit arrray of the word received */
u32 prot_idx;
u32 prot_size;
};
/* macro to log operation of a misc device */
@ -368,8 +353,7 @@ static ssize_t seco_mu_fops_write(struct file *fp, const char __user *buf,
struct seco_mu_device_ctx *dev_ctx = container_of(fp->private_data,
struct seco_mu_device_ctx, miscdev);
struct seco_mu_priv *mu_priv = dev_ctx->mu_priv;
u32 *data, data_idx = 0, nb_words = 0, header;
struct mbox_chan *chan;
u32 nb_words = 0, header;
int err;
devctx_dbg(dev_ctx, "write from buf (%p)%ld, ppos=%lld\n", buf, size,
@ -405,6 +389,9 @@ static ssize_t seco_mu_fops_write(struct file *fp, const char __user *buf,
goto exit;
}
print_hex_dump_debug("from user ", DUMP_PREFIX_OFFSET, 4, 4,
dev_ctx->temp_cmd, size, false);
header = dev_ctx->temp_cmd[0];
/* Check the message is valid according to tags */
@ -434,48 +421,22 @@ static ssize_t seco_mu_fops_write(struct file *fp, const char __user *buf,
* carried in the message.
*/
nb_words = MESSAGE_SIZE(header);
if (nb_words * sizeof(u32) != size) {
if (nb_words * sizeof(u32) > size) {
devctx_err(dev_ctx, "User buffer too small\n");
goto exit;
}
mutex_lock(&mu_priv->mu_lock);
/* Send the first word along with the signaling */
data = &dev_ctx->temp_cmd[data_idx];
chan = mu_priv->com_chans[0].chan;
devctx_dbg(dev_ctx, "sending[%d] %.8x\n", data_idx, *data);
err = mbox_send_message(chan, data);
/* Send message */
devctx_dbg(dev_ctx, "sending message\n");
err = mbox_send_message(mu_priv->tx_chan, dev_ctx->temp_cmd);
if (err < 0) {
devctx_err(dev_ctx, "Failed to send header\n");
devctx_err(dev_ctx, "Failed to send message\n");
goto unlock;
}
devctx_dbg(dev_ctx, "%s\n", "signaling");
err = mbox_send_message(mu_priv->tx_started, data);
if (err < 0) {
devctx_err(dev_ctx, "Failed to send signal\n");
goto unlock;
}
data_idx = 1;
/* Loop over the data of the message to send */
while (data_idx < nb_words) {
data = &dev_ctx->temp_cmd[data_idx];
chan = mu_priv->com_chans[data_idx % MU_TR_COUNT].chan;
devctx_dbg(dev_ctx, "sending[%d] %.8x\n", data_idx, *data);
err = mbox_send_message(chan, data);
if (err < 0) {
devctx_err(dev_ctx, "Failed to send data %d\n",
data_idx);
goto unlock;
}
data_idx++;
}
err = data_idx * (u32)sizeof(u32);
err = nb_words * (u32)sizeof(u32);
unlock:
mutex_unlock(&mu_priv->mu_lock);
@ -618,7 +579,7 @@ seco_mu_ioctl_shared_mem_cfg_handler(struct seco_mu_device_ctx *dev_ctx,
dev_ctx->secure_mem.dma_addr = (dma_addr_t)cfg.base_offset;
dev_ctx->secure_mem.size = cfg.size;
dev_ctx->secure_mem.pos = 0;
dev_ctx->secure_mem.ptr = devm_ioremap_nocache(dev_ctx->dev,
dev_ctx->secure_mem.ptr = devm_ioremap(dev_ctx->dev,
(phys_addr_t)(SECURE_RAM_BASE_ADDRESS +
(u64)dev_ctx->secure_mem.dma_addr),
dev_ctx->secure_mem.size);
@ -883,11 +844,11 @@ static long seco_mu_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
static void seco_mu_rx_callback(struct mbox_client *c, void *msg)
{
struct device *dev = c->dev;
struct com_chan *com = container_of(c, struct com_chan, cl);
struct seco_mu_priv *priv = dev_get_drvdata(dev);
struct seco_mu_device_ctx *dev_ctx = priv->prot_ctx;
u32 idx = com->idx;
u32 val_msg;
struct seco_mu_device_ctx *dev_ctx;
bool is_response = false;
int msg_size;
u32 header;
dev_dbg(dev, "Message received on mailbox\n");
@ -897,78 +858,48 @@ static void seco_mu_rx_callback(struct mbox_client *c, void *msg)
return;
}
val_msg = *(u32 *)msg;
header = *(u32 *)msg;
/* Store the message at its postion*/
idx += (priv->prot_word_received & (1 << idx)) ? 4 : 0;
priv->prot_buf[idx] = val_msg;
priv->prot_word_received |= (1 << idx);
priv->prot_idx++;
dev_dbg(dev, "Received: %.8x from %d, idx: %d, prot_idx: %d\n", val_msg,
com->idx, idx, priv->prot_idx);
dev_dbg(dev, "Selecting device\n");
/* We check if we have received the header */
if (idx == 0) {
int msg_size;
dev_dbg(dev, "Selecting device\n");
/* Incoming command: wake up the receiver if any. */
if (MESSAGE_TAG(val_msg) == MESSAGING_TAG_COMMAND) {
dev_dbg(dev, "Selecting receiver\n");
priv->prot_ctx = priv->cmd_receiver_dev;
} else if (MESSAGE_TAG(val_msg) == MESSAGING_TAG_RESPONSE) {
dev_dbg(dev, "Selecting waiter\n");
/* This is a response. */
priv->prot_ctx = priv->waiting_rsp_dev;
} else {
dev_err(dev,
"Failed to select a device for message: %.8x\n",
val_msg);
return;
}
if (!priv->prot_ctx) {
dev_err(dev, "The device context could not be set\n");
return;
}
dev_ctx = priv->prot_ctx;
/* Init reception */
msg_size = MESSAGE_SIZE(val_msg);
if (msg_size > MAX_MESSAGE_SIZE) {
devctx_err(dev_ctx, "Message is too big (%d > %d)",
msg_size, MAX_RECV_SIZE);
return;
}
priv->prot_size = msg_size;
/* Incoming command: wake up the receiver if any. */
if (MESSAGE_TAG(header) == MESSAGING_TAG_COMMAND) {
dev_dbg(dev, "Selecting cmd receiver\n");
dev_ctx = priv->cmd_receiver_dev;
} else if (MESSAGE_TAG(header) == MESSAGING_TAG_RESPONSE) {
dev_dbg(dev, "Selecting rsp waiter\n");
dev_ctx = priv->waiting_rsp_dev;
is_response = true;
} else {
dev_err(dev, "Failed to select a device for message: %.8x\n",
header);
return;
}
/* Check end of reception */
if (priv->prot_idx == priv->prot_size) {
devctx_dbg(dev_ctx, "Transfert finished\n");
if (!dev_ctx) {
dev_err(dev, "No device context selected for message: %.8x\n",
header);
return;
}
/* Cleanup */
priv->prot_ctx = NULL;
memcpy(dev_ctx->temp_resp, priv->prot_buf, MAX_RECV_SIZE_BYTES);
dev_ctx->temp_resp_size = priv->prot_size;
/* Init reception */
msg_size = MESSAGE_SIZE(header);
if (msg_size > MAX_RECV_SIZE) {
devctx_err(dev_ctx, "Message is too big (%d > %d)", msg_size,
MAX_RECV_SIZE);
return;
}
priv->prot_idx = 0;
priv->prot_size = 0;
priv->prot_word_received = 0;
memcpy(dev_ctx->temp_resp, msg, msg_size * sizeof(u32));
dev_ctx->temp_resp_size = msg_size;
/* Allow user to read and/or write */
dev_ctx->pending_hdr = dev_ctx->temp_resp[0];
wake_up_interruptible(&dev_ctx->wq);
/* Allow user to read */
dev_ctx->pending_hdr = dev_ctx->temp_resp[0];
wake_up_interruptible(&dev_ctx->wq);
if (MESSAGE_TAG(dev_ctx->temp_resp[0]) ==
MESSAGING_TAG_RESPONSE) {
/*
* The response to the previous command is received.
* Allow following command to be sent on the MU.
*/
mutex_unlock(&priv->mu_cmd_lock);
}
if (is_response) {
/* Allow user to send new command */
mutex_unlock(&priv->mu_cmd_lock);
}
}
@ -1028,16 +959,44 @@ static void if_misc_deregister(void *miscdevice)
misc_deregister(miscdevice);
}
static int seco_mu_request_channel(struct device *dev,
struct mbox_chan **chan,
const char *name)
{
struct seco_mu_priv *priv = dev_get_drvdata(dev);
struct mbox_chan *t_chan;
int ret = 0;
t_chan = mbox_request_channel_byname(&priv->cl, name);
if (IS_ERR(t_chan)) {
ret = PTR_ERR(t_chan);
if (ret != -EPROBE_DEFER)
dev_err(dev,
"Failed to request chan %s ret %d\n", name,
ret);
goto exit;
}
ret = devm_add_action(dev, if_mbox_free_channel, t_chan);
if (ret) {
dev_err(dev, "failed to add devm removal of mbox %s\n", name);
goto exit;
}
*chan = t_chan;
exit:
return ret;
}
/* Driver probe.*/
static int seco_mu_probe(struct platform_device *pdev)
{
struct seco_mu_device_ctx *dev_ctx;
struct device *dev = &pdev->dev;
struct seco_mu_priv *priv;
struct mbox_chan *chan;
struct device_node *np;
int max_nb_users = 0;
char *chan_name;
char *devname;
int ret;
int i;
@ -1096,73 +1055,25 @@ static int seco_mu_probe(struct platform_device *pdev)
ret = of_property_read_u32(np, "fsl,seco_max_users", &max_nb_users);
if (ret) {
dev_warn(dev, "%s: Not able to read mu_max_user", __func__);
max_nb_users = 2; /* 2 users max by default. */
max_nb_users = SECO_MU_DEFAULT_MAX_USERS;
}
/* Mailbox client configuration */
priv->cl.dev = dev;
priv->cl.tx_tout = 3000;
priv->cl.knows_txdone = true;
priv->cl.rx_callback = seco_mu_rx_callback;
/* Create comm chans */
for (i = 0; i < MU_TR_COUNT + MU_RR_COUNT; i++) {
struct mbox_client *cl = &priv->com_chans[i].cl;
if (i < MU_TR_COUNT)
chan_name = devm_kasprintf(dev, GFP_KERNEL, "tx%d", i);
else
chan_name = devm_kasprintf(dev, GFP_KERNEL, "rx%d",
i - 4);
if (!chan_name) {
ret = -ENOMEM;
dev_err(dev, "Failed to build chan name %d\n", i);
goto exit;
}
memcpy(cl, &priv->cl, sizeof(priv->cl));
dev_dbg(dev, "request mbox chan %s\n", chan_name);
chan = mbox_request_channel_byname(cl, chan_name);
if (IS_ERR(chan)) {
ret = PTR_ERR(chan);
if (ret != -EPROBE_DEFER)
dev_err(dev,
"Failed to request chan %s ret %d\n",
chan_name, ret);
goto exit;
}
priv->com_chans[i].chan = chan;
priv->com_chans[i].idx = i - 4;
ret = devm_add_action(dev, if_mbox_free_channel, chan);
if (ret)
dev_warn(dev, "failed to add devm removal of mbox\n");
/* chan_name is not used anymore by mailbox framework */
devm_kfree(dev, chan_name);
}
/* Create signaling chan */
dev_dbg(dev, "request signal chan %s\n", chan_name);
priv->tx_started = mbox_request_channel_byname(&priv->cl,
"tx_started");
if (IS_ERR(priv->tx_started)) {
ret = PTR_ERR(priv->tx_started);
if (ret != -EPROBE_DEFER)
dev_err(dev,
"Failed to request chan %s ret %d\n",
chan_name, ret);
ret = seco_mu_request_channel(dev, &priv->tx_chan, "txdb");
if (ret) {
dev_err(dev, "Failed to request txdb channel\n");
goto exit;
}
ret = devm_add_action(dev, if_mbox_free_channel,
priv->tx_started);
if (ret)
dev_warn(dev,
"failed to add managed removal of mbox\n");
ret = seco_mu_request_channel(dev, &priv->rx_chan, "rxdb");
if (ret) {
dev_err(dev, "Failed to request rxdb channel\n");
goto exit;
}
/* Create users */
for (i = 0; i < max_nb_users; i++) {