From 8838ca560032990d23d62a67cf9b38caaa02e8dc Mon Sep 17 00:00:00 2001 From: Gauri Joshi Date: Mon, 10 May 2021 23:59:29 -0700 Subject: [PATCH] msm: mhi-dev: Add support for AIO write API Diag client uses asynchronous writes for data transfer. Adding write_iter API in mhi to support the same. Change-Id: If14ebdd4aa848046abd15ea93d939691c6962fcd Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi_uci.c | 63 ++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 3a69f9359b45..2d04c2cbf5b0 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -424,6 +425,8 @@ static ssize_t mhi_uci_ctrl_client_read(struct file *file, char __user *buf, size_t count, loff_t *offp); static ssize_t mhi_uci_client_write(struct file *file, const char __user *buf, size_t count, loff_t *offp); +static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb, + struct iov_iter *buf); static int mhi_uci_client_open(struct inode *mhi_inode, struct file*); static int mhi_uci_ctrl_open(struct inode *mhi_inode, struct file*); static int mhi_uci_client_release(struct inode *mhi_inode, @@ -1480,6 +1483,65 @@ error_memcpy: } +static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb, + struct iov_iter *buf) +{ + struct uci_client *uci_handle = NULL; + void *data_loc; + unsigned long memcpy_result; + int rc; + struct file *file = iocb->ki_filp; + ssize_t count = iov_iter_count(buf); + + if (!file || !buf || !count || !file->private_data) { + uci_log(UCI_DBG_DBG, "Invalid access to write-iter\n"); + return -EINVAL; + } + + uci_handle = file->private_data; + if (!uci_handle->send || !uci_handle->out_handle) { + uci_log(UCI_DBG_DBG, "Invalid handle or send\n"); + return -EINVAL; + } + if (atomic_read(&uci_ctxt.mhi_disabled)) { + uci_log(UCI_DBG_ERROR, + "Client %d attempted to write while MHI is disabled\n", + uci_handle->out_chan); + return -EIO; + } + + if (!mhi_uci_are_channels_connected(uci_handle)) { + uci_log(UCI_DBG_ERROR, "%s:Channels are not connected\n", + __func__); + return -ENODEV; + } + + if (count > TRB_MAX_DATA_SIZE) { + uci_log(UCI_DBG_ERROR, + "Too big write size: %lu, max supported size is %d\n", + count, TRB_MAX_DATA_SIZE); + return -EFBIG; + } + + data_loc = kmalloc(count, GFP_KERNEL); + if (!data_loc) + return -ENOMEM; + + memcpy_result = copy_from_iter_full(data_loc, count, buf); + if (!memcpy_result) { + rc = -EFAULT; + goto error_memcpy; + } + + rc = mhi_uci_send_packet(uci_handle, data_loc, count); + if (rc == count) + return rc; + +error_memcpy: + kfree(data_loc); + return rc; +} + void mhi_uci_chan_state_notify_all(struct mhi_dev *mhi, enum mhi_ctrl_info ch_state) { @@ -1877,6 +1939,7 @@ static const struct file_operations mhi_uci_ctrl_client_fops = { static const struct file_operations mhi_uci_client_fops = { .read = mhi_uci_client_read, .write = mhi_uci_client_write, + .write_iter = mhi_uci_client_write_iter, .open = mhi_uci_client_open, .release = mhi_uci_client_release, .poll = mhi_uci_client_poll,