diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 3720f4830682..68401a824bc2 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2278,6 +2278,12 @@ static int mhi_dev_process_tre_ring(struct mhi_dev *mhi, ch = &mhi->ch[ring->id - mhi->ch_ring_start]; reason.ch_id = ch->ch_id; reason.reason = MHI_DEV_TRE_AVAILABLE; + /* + * Save lowest value of tre_len to split packets in UCI layer + * for write request of size more than tre_len. + */ + if (!ch->tre_size || ch->tre_size > el->tre.len) + ch->tre_size = el->tre.len; /* Invoke a callback to let the client know its data is ready. * Copy this event to the clients context so that it can be @@ -3466,7 +3472,7 @@ int mhi_dev_read_channel(struct mhi_req *mreq) uint64_t read_from_loc; ssize_t bytes_read = 0; size_t write_to_loc = 0; - uint32_t usr_buf_remaining; + uint32_t usr_buf_remaining, tre_size; int td_done = 0, rc = 0; struct mhi_dev_client *handle_client; @@ -3509,10 +3515,9 @@ int mhi_dev_read_channel(struct mhi_req *mreq) } el = &ring->ring_cache[ring->rd_offset]; - mhi_log(MHI_MSG_VERBOSE, "evtptr : 0x%llx\n", - el->tre.data_buf_ptr); - mhi_log(MHI_MSG_VERBOSE, "evntlen : 0x%x, offset:%lu\n", - el->tre.len, ring->rd_offset); + mhi_log(MHI_MSG_VERBOSE, + "TRE.PTR: 0x%llx, TRE.LEN: 0x%x, rd offset: %lu\n", + el->tre.data_buf_ptr, el->tre.len, ring->rd_offset); if (ch->tre_loc) { bytes_to_read = min(usr_buf_remaining, @@ -3531,17 +3536,15 @@ int mhi_dev_read_channel(struct mhi_req *mreq) ch->tre_loc = el->tre.data_buf_ptr; - ch->tre_size = el->tre.len; - ch->tre_bytes_left = ch->tre_size; - - mhi_log(MHI_MSG_VERBOSE, - "user_buf_remaining %d, ch->tre_size %d\n", - usr_buf_remaining, ch->tre_size); - bytes_to_read = min(usr_buf_remaining, ch->tre_size); + tre_size = el->tre.len; + ch->tre_bytes_left = el->tre.len; + mhi_log(MHI_MSG_VERBOSE, "user_buf_remaining %d, tre_size %d\n", + usr_buf_remaining, el->tre.len); + bytes_to_read = min(usr_buf_remaining, tre_size); } bytes_read += bytes_to_read; - addr_offset = ch->tre_size - ch->tre_bytes_left; + addr_offset = el->tre.len - ch->tre_bytes_left; read_from_loc = ch->tre_loc + addr_offset; write_to_loc = (size_t) mreq->buf + (mreq->len - usr_buf_remaining); diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 8aca45f6957c..5862dd0a9fde 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -391,6 +391,7 @@ struct uci_client { int (*read)(struct uci_client *h, int *bytes); unsigned int tiocm; unsigned int at_ctrl_mask; + int tre_len; }; struct mhi_uci_ctxt_t { @@ -1466,8 +1467,9 @@ static ssize_t mhi_uci_client_write(struct file *file, { struct uci_client *uci_handle = NULL; void *data_loc; + const char __user *cur_buf; unsigned long memcpy_result; - int rc; + int rc = 0, tre_len, cur_rc = 0, count_left, cur_txfr_len; if (!file || !buf || !count || !file->private_data) { uci_log(UCI_DBG_DBG, "Invalid access to write\n"); @@ -1475,6 +1477,8 @@ static ssize_t mhi_uci_client_write(struct file *file, } uci_handle = file->private_data; + tre_len = uci_handle->tre_len; + if (!uci_handle->send || !uci_handle->out_handle) { uci_log(UCI_DBG_DBG, "Invalid handle or send\n"); return -EINVAL; @@ -1497,17 +1501,47 @@ static ssize_t mhi_uci_client_write(struct file *file, count, uci_handle->out_chan_attr->max_packet_size); } - data_loc = kmalloc(count, GFP_KERNEL); - if (!data_loc) - return -ENOMEM; + cur_txfr_len = count; - memcpy_result = copy_from_user(data_loc, buf, count); - if (memcpy_result) { - rc = -EFAULT; - goto error_memcpy; + if (!tre_len) + uci_log(UCI_DBG_ERROR, "tre_len is 0, not updated yet\n"); + else if (count > tre_len) { + uci_log(UCI_DBG_DBG, "Write req size (%d) > tre_len (%d)\n", count, tre_len); + cur_txfr_len = tre_len; } - rc = mhi_uci_send_packet(uci_handle, data_loc, count); + count_left = count; + cur_buf = buf; + + do { + data_loc = kmalloc(cur_txfr_len, GFP_KERNEL); + if (!data_loc) { + uci_log(UCI_DBG_ERROR, "Memory allocation failed\n"); + return -ENOMEM; + } + + memcpy_result = copy_from_user(data_loc, cur_buf, cur_txfr_len); + if (memcpy_result) { + uci_log(UCI_DBG_ERROR, "Mem copy failed\n"); + rc = -EFAULT; + goto error_memcpy; + } + + cur_rc = mhi_uci_send_packet(uci_handle, data_loc, cur_txfr_len); + if (cur_rc != cur_txfr_len) { + uci_log(UCI_DBG_ERROR, + "Send failed with error %d, after sending %d data\n", + cur_rc, rc); + rc = cur_rc; + goto error_memcpy; + } + rc += cur_rc; + cur_buf += cur_txfr_len; + count_left -= cur_txfr_len; + + if (count_left < tre_len) + cur_txfr_len = count_left; + } while (count_left); if (rc == count) return rc; @@ -1523,7 +1557,7 @@ static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb, struct uci_client *uci_handle = NULL; void *data_loc; unsigned long memcpy_result; - int rc; + int rc = 0, tre_len, cur_rc = 0, count_left, cur_txfr_len; struct file *file = iocb->ki_filp; ssize_t count = iov_iter_count(buf); @@ -1533,6 +1567,8 @@ static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb, } uci_handle = file->private_data; + tre_len = uci_handle->tre_len; + if (!uci_handle->send || !uci_handle->out_handle) { uci_log(UCI_DBG_DBG, "Invalid handle or send\n"); return -EINVAL; @@ -1555,17 +1591,44 @@ static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb, count, uci_handle->out_chan_attr->max_packet_size); } - data_loc = kmalloc(count, GFP_KERNEL); - if (!data_loc) - return -ENOMEM; + cur_txfr_len = count; - memcpy_result = copy_from_iter_full(data_loc, count, buf); - if (!memcpy_result) { - rc = -EFAULT; - goto error_memcpy; + if (!tre_len) + uci_log(UCI_DBG_ERROR, "tre_len is 0, not updated yet\n"); + else if (count > tre_len) { + uci_log(UCI_DBG_DBG, "Write req size (%d) > tre_len (%d)\n", count, tre_len); + cur_txfr_len = tre_len; } - rc = mhi_uci_send_packet(uci_handle, data_loc, count); + count_left = count; + + do { + data_loc = kmalloc(cur_txfr_len, GFP_KERNEL); + if (!data_loc) { + uci_log(UCI_DBG_ERROR, "Memory allocation failed\n"); + return -ENOMEM; + } + + memcpy_result = copy_from_iter_full(data_loc, cur_txfr_len, buf); + if (!memcpy_result) { + uci_log(UCI_DBG_ERROR, "Mem copy failed\n"); + rc = -EFAULT; + goto error_memcpy; + } + cur_rc = mhi_uci_send_packet(uci_handle, data_loc, cur_txfr_len); + if (cur_rc != cur_txfr_len) { + uci_log(UCI_DBG_ERROR, + "Send failed with error %d, after sending %d data\n", + cur_rc, rc); + rc = cur_rc; + goto error_memcpy; + } + rc += cur_rc; + count_left -= cur_txfr_len; + if (count_left < tre_len) + cur_txfr_len = count_left; + } while (count_left); + if (rc == count) return rc; @@ -1683,6 +1746,7 @@ static void uci_event_notifier(struct mhi_dev_client_cb_reason *reason) uci_handle->in_chan); if (reason->ch_id % 2) { atomic_set(&uci_handle->write_data_ready, 1); + uci_handle->tre_len = uci_handle->out_handle->channel->tre_size; wake_up(&uci_handle->write_wq); } else { atomic_set(&uci_handle->read_data_ready, 1);