rpmsgblk: split multi_cmd only when it is too large to be placed into payload buffer

Signed-off-by: liaoao <liaoao@xiaomi.com>
This commit is contained in:
liaoao 2024-01-24 14:00:55 +08:00 committed by Xiang Xiao
parent 83c2a7f54e
commit e4ad92cb03
2 changed files with 258 additions and 38 deletions

View File

@ -536,25 +536,30 @@ static int rpmsgblk_mmc_cmd_ioctl(FAR struct inode *inode, unsigned long arg)
FAR struct mmc_ioc_cmd *ioc = (FAR struct mmc_ioc_cmd *)(uintptr_t)arg;
FAR struct rpmsgblk_ioctl_s *msg;
uint32_t space;
ssize_t msglen;
size_t arglen;
size_t msglen;
msglen = sizeof(*msg) + sizeof(struct mmc_ioc_cmd) +
ioc->blksz * ioc->blocks - 1;
arglen = sizeof(struct mmc_ioc_cmd);
if (ioc->write_flag)
{
arglen += ioc->blksz * ioc->blocks;
}
msglen = sizeof(*msg) + arglen - 1;
msg = rpmsgblk_get_tx_payload_buffer(priv, &space);
if (msg == NULL)
{
return -ENOMEM;
}
DEBUGASSERT(space > msglen);
DEBUGASSERT(space >= msglen);
msg->request = MMC_IOC_CMD;
msg->arg = arg;
msg->arglen = sizeof(struct mmc_ioc_cmd) + ioc->blksz * ioc->blocks;
msg->arglen = arglen;
memcpy(msg->buf, ioc, sizeof(*ioc));
if (ioc->data_ptr)
if (ioc->data_ptr && ioc->write_flag)
{
memcpy(msg->buf + sizeof(*ioc), (FAR void *)(uintptr_t)ioc->data_ptr,
ioc->blksz * ioc->blocks);
@ -578,22 +583,85 @@ static int rpmsgblk_mmc_cmd_ioctl(FAR struct inode *inode, unsigned long arg)
static int rpmsgblk_mmc_multi_cmd_ioctl(FAR struct inode *inode,
unsigned long arg)
{
FAR struct rpmsgblk_s *priv = inode->i_private;
FAR struct mmc_ioc_multi_cmd *mioc =
(FAR struct mmc_ioc_multi_cmd *)(uintptr_t)arg;
int ret = 0;
FAR struct rpmsgblk_ioctl_s *msg;
size_t arglen;
size_t msglen;
size_t rsplen;
uint64_t i;
arglen = sizeof(struct mmc_ioc_multi_cmd) +
mioc->num_of_cmds * sizeof(struct mmc_ioc_cmd);
rsplen = arglen;
for (i = 0; i < mioc->num_of_cmds; i++)
{
ret = rpmsgblk_mmc_cmd_ioctl(inode,
(unsigned long)(uintptr_t)&mioc->cmds[i]);
if (ret < 0)
if (mioc->cmds[i].data_ptr && mioc->cmds[i].write_flag)
{
return ret;
arglen += mioc->cmds[i].blksz * mioc->cmds[i].blocks;
}
else
{
rsplen += mioc->cmds[i].blksz * mioc->cmds[i].blocks;
}
}
return ret;
/* When multi cmds are read cmd, it also needs to be split if the rsp
* msg is too large.
*/
msglen = sizeof(*msg) + arglen - 1;
rsplen += sizeof(*msg) - 1;
if (MAX(msglen, rsplen) > rpmsg_virtio_get_buffer_size(priv->ept.rdev))
{
int ret = 0;
for (i = 0; i < mioc->num_of_cmds; i++)
{
ret = rpmsgblk_mmc_cmd_ioctl(inode,
(unsigned long)(uintptr_t)&mioc->cmds[i]);
if (ret < 0)
{
return ret;
}
}
return ret;
}
else
{
size_t off = sizeof(struct mmc_ioc_multi_cmd) +
mioc->num_of_cmds * sizeof(struct mmc_ioc_cmd);
uint32_t space;
msg = rpmsgblk_get_tx_payload_buffer(priv, &space);
if (msg == NULL)
{
return -ENOMEM;
}
DEBUGASSERT(space >= msglen);
msg->request = MMC_IOC_MULTI_CMD;
msg->arg = arg;
msg->arglen = arglen;
memcpy(msg->buf, mioc, off);
for (i = 0; i < mioc->num_of_cmds; i++)
{
if (mioc->cmds[i].data_ptr && mioc->cmds[i].write_flag)
{
memcpy(msg->buf + off,
(FAR void *)(uintptr_t)mioc->cmds[i].data_ptr,
mioc->cmds[i].blksz * mioc->cmds[i].blocks);
off += mioc->cmds[i].blksz * mioc->cmds[i].blocks;
}
}
return rpmsgblk_send_recv(priv, RPMSGBLK_IOCTL, false, &msg->header,
msglen, (FAR void *)arg);
}
}
/****************************************************************************
@ -625,7 +693,7 @@ static int rpmsgblk_default_ioctl(FAR struct inode *inode, int cmd,
return -ENOMEM;
}
DEBUGASSERT(space > msglen);
DEBUGASSERT(space >= msglen);
msg->request = cmd;
msg->arg = arg;
@ -925,6 +993,57 @@ static int rpmsgblk_geometry_handler(FAR struct rpmsg_endpoint *ept,
return rpmsg_post(ept, &cookie->sem);
}
/****************************************************************************
* Name: rpmsgblk_mmc_cmd_handler
****************************************************************************/
static void rpmsgblk_mmc_cmd_handler(FAR struct rpmsgblk_cookie_s *cookie,
FAR struct rpmsgblk_ioctl_s *rsp)
{
FAR struct mmc_ioc_cmd *ioc =
(FAR struct mmc_ioc_cmd *)(uintptr_t)cookie->data;
/* Copy struct mmc_ioc_cmd back to the usrspace buffer
* except data_ptr which is another buffer pointer
*/
memcpy(ioc, rsp->buf, sizeof(*ioc) - sizeof(ioc->data_ptr));
if (ioc->data_ptr && !ioc->write_flag)
{
memcpy((FAR void *)(uintptr_t)ioc->data_ptr, rsp->buf + sizeof(*ioc),
ioc->blksz * ioc->blocks);
}
}
/****************************************************************************
* Name: rpmsgblk_mmc_multi_cmd_handler
****************************************************************************/
static void
rpmsgblk_mmc_multi_cmd_handler(FAR struct rpmsgblk_cookie_s *cookie,
FAR struct rpmsgblk_ioctl_s *rsp)
{
FAR struct mmc_ioc_multi_cmd *mioc =
(FAR struct mmc_ioc_multi_cmd *)(uintptr_t)cookie->data;
FAR struct mmc_ioc_multi_cmd *mioc_rsp =
(FAR struct mmc_ioc_multi_cmd *)(uintptr_t)rsp->buf;
size_t off = sizeof(struct mmc_ioc_multi_cmd) +
mioc->num_of_cmds * sizeof(struct mmc_ioc_cmd);
uint64_t i;
for (i = 0; i < mioc->num_of_cmds; i++)
{
memcpy(&mioc->cmds[i], &mioc_rsp->cmds[i],
sizeof(struct mmc_ioc_cmd) - sizeof(mioc->cmds[i].data_ptr));
if (mioc->cmds[i].data_ptr && !mioc->cmds[i].write_flag)
{
memcpy((FAR void *)(uintptr_t)mioc->cmds[i].data_ptr,
rsp->buf + off, mioc->cmds[i].blksz * mioc->cmds[i].blocks);
off += mioc->cmds[i].blksz * mioc->cmds[i].blocks;
}
}
}
/****************************************************************************
* Name: rpmsgblk_ioctl_handler
*
@ -959,22 +1078,11 @@ static int rpmsgblk_ioctl_handler(FAR struct rpmsg_endpoint *ept,
switch (rsp->request)
{
case MMC_IOC_CMD:
{
FAR struct mmc_ioc_cmd *ioc =
(FAR struct mmc_ioc_cmd *)(uintptr_t)cookie->data;
rpmsgblk_mmc_cmd_handler(cookie, rsp);
break;
/* Copy struct mmc_ioc_cmd back to the usrspace buffer
* except data_ptr which is another buffer pointer
*/
memcpy(ioc, rsp->buf, sizeof(*ioc) - sizeof(ioc->data_ptr));
if (ioc->data_ptr)
{
memcpy((FAR void *)(uintptr_t)ioc->data_ptr,
rsp->buf + sizeof(*ioc),
ioc->blksz * ioc->blocks);
}
}
case MMC_IOC_MULTI_CMD:
rpmsgblk_mmc_multi_cmd_handler(cookie, rsp);
break;
default:

View File

@ -312,6 +312,125 @@ static int rpmsgblk_geometry_handler(FAR struct rpmsg_endpoint *ept,
return rpmsg_send(ept, msg, len);
}
/****************************************************************************
* Name: rpmsgblk_mmc_cmd_handler
****************************************************************************/
static int rpmsgblk_mmc_cmd_handler(FAR struct rpmsg_endpoint *ept,
FAR struct rpmsgblk_ioctl_s *msg)
{
FAR struct rpmsgblk_server_s *server = ept->priv;
FAR struct mmc_ioc_cmd *ioc =
(FAR struct mmc_ioc_cmd *)(uintptr_t)msg->buf;
FAR struct rpmsgblk_ioctl_s *rsp;
FAR struct mmc_ioc_cmd *ioc_rsp;
size_t rsplen;
size_t arglen;
uint32_t space;
arglen = sizeof(struct mmc_ioc_cmd);
if (!ioc->write_flag)
{
arglen += ioc->blksz * ioc->blocks;
}
rsplen = sizeof(*rsp) + arglen - 1;
rsp = rpmsg_get_tx_payload_buffer(ept, &space, true);
if (msg == NULL)
{
return -ENOMEM;
}
DEBUGASSERT(space >= rsplen);
memcpy(rsp, msg, sizeof(*rsp) + sizeof(struct mmc_ioc_cmd) - 1);
rsp->arglen = arglen;
ioc_rsp = (FAR struct mmc_ioc_cmd *)(uintptr_t)rsp->buf;
if (ioc_rsp->write_flag)
{
ioc_rsp->data_ptr = (uint64_t)(uintptr_t)(msg->buf + sizeof(*ioc_rsp));
}
else
{
ioc_rsp->data_ptr = (uint64_t)(uintptr_t)(rsp->buf + sizeof(*ioc_rsp));
}
rsp->header.result = server->bops->ioctl(server->blknode, rsp->request,
(unsigned long)rsp->buf);
return rpmsg_send_nocopy(ept, rsp, rsplen);
}
/****************************************************************************
* Name: rpmsgblk_mmc_cmd_handler
****************************************************************************/
static int rpmsgblk_mmc_multi_cmd_handler(FAR struct rpmsg_endpoint *ept,
FAR struct rpmsgblk_ioctl_s *msg)
{
FAR struct rpmsgblk_server_s *server = ept->priv;
FAR struct mmc_ioc_multi_cmd *mioc =
(FAR struct mmc_ioc_multi_cmd *)(uintptr_t)msg->buf;
FAR struct rpmsgblk_ioctl_s *rsp;
FAR struct mmc_ioc_multi_cmd *mioc_rsp;
size_t rsplen;
size_t arglen;
size_t off;
size_t rsp_off;
uint32_t space;
uint64_t i;
arglen = sizeof(struct mmc_ioc_multi_cmd) +
mioc->num_of_cmds * sizeof(struct mmc_ioc_cmd);
for (i = 0; i < mioc->num_of_cmds; i++)
{
if (!mioc->cmds[i].write_flag)
{
arglen += mioc->cmds[i].blksz * mioc->cmds[i].blocks;
}
}
rsplen = sizeof(*rsp) + arglen - 1;
rsp = rpmsg_get_tx_payload_buffer(ept, &space, true);
if (msg == NULL)
{
return -ENOMEM;
}
DEBUGASSERT(space >= rsplen);
off = sizeof(struct mmc_ioc_multi_cmd) +
mioc->num_of_cmds * sizeof(struct mmc_ioc_cmd);
/* Consist of the rsp msg */
memcpy(rsp, msg, sizeof(*rsp) + off - 1);
rsp->arglen = arglen;
mioc_rsp = (FAR struct mmc_ioc_multi_cmd *)(uintptr_t)rsp->buf;
rsp_off = off;
for (i = 0; i < mioc_rsp->num_of_cmds; i++)
{
if (mioc_rsp->cmds[i].write_flag)
{
mioc_rsp->cmds[i].data_ptr = (uint64_t)(uintptr_t)
(msg->buf + off);
off += mioc_rsp->cmds[i].blksz * mioc_rsp->cmds[i].blocks;
}
else
{
mioc_rsp->cmds[i].data_ptr = (uint64_t)(uintptr_t)
(rsp->buf + rsp_off);
rsp_off += mioc_rsp->cmds[i].blksz * mioc_rsp->cmds[i].blocks;
}
}
rsp->header.result = server->bops->ioctl(server->blknode, rsp->request,
(unsigned long)rsp->buf);
return rpmsg_send_nocopy(ept, rsp, rsplen);
}
/****************************************************************************
* Name: rpmsgblk_ioctl_handler
****************************************************************************/
@ -334,17 +453,10 @@ static int rpmsgblk_ioctl_handler(FAR struct rpmsg_endpoint *ept,
switch (msg->request)
{
case MMC_IOC_CMD:
{
FAR struct mmc_ioc_cmd *ioc =
(FAR struct mmc_ioc_cmd *)(uintptr_t)msg->buf;
return rpmsgblk_mmc_cmd_handler(ept, data);
if (ioc->data_ptr)
{
ioc->data_ptr = (uint64_t)(uintptr_t)
((FAR uint8_t *)ioc + sizeof(*ioc));
}
}
break;
case MMC_IOC_MULTI_CMD:
return rpmsgblk_mmc_multi_cmd_handler(ept, data);
default:
break;