Merge "mhi: uci: Fix a bug related to split transfer packets"

This commit is contained in:
Linux Build Service Account 2017-07-28 00:21:22 -07:00 committed by Gerrit - the friendly Code Review server
commit f687374863

View file

@ -326,73 +326,6 @@ static int mhi_init_inbound(struct uci_client *client_handle)
return ret_val; return ret_val;
} }
static int mhi_uci_send_packet(struct mhi_client_handle **client_handle,
void *buf,
u32 size)
{
u32 nr_avail_trbs = 0;
u32 i = 0;
void *data_loc = NULL;
unsigned long memcpy_result = 0;
int data_left_to_insert = 0;
size_t data_to_insert_now = 0;
u32 data_inserted_so_far = 0;
int ret_val = 0;
struct uci_client *uci_handle;
struct uci_buf *uci_buf;
uci_handle = container_of(client_handle, struct uci_client,
out_attr.mhi_handle);
nr_avail_trbs = atomic_read(&uci_handle->out_attr.avail_pkts);
data_left_to_insert = size;
for (i = 0; i < nr_avail_trbs; ++i) {
data_to_insert_now = min_t(size_t, data_left_to_insert,
uci_handle->out_attr.max_packet_size);
data_loc = kmalloc(data_to_insert_now + sizeof(*uci_buf),
GFP_KERNEL);
if (!data_loc) {
uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Failed to allocate memory 0x%zx\n",
data_to_insert_now);
return -ENOMEM;
}
uci_buf = data_loc + data_to_insert_now;
uci_buf->data = data_loc;
uci_buf->pkt_id = uci_handle->out_attr.pkt_count++;
memcpy_result = copy_from_user(uci_buf->data,
buf + data_inserted_so_far,
data_to_insert_now);
if (memcpy_result)
goto error_xfer;
uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"At trb i = %d/%d, size = %lu, id %llu chan %d\n",
i, nr_avail_trbs, data_to_insert_now, uci_buf->pkt_id,
uci_handle->out_attr.chan_id);
ret_val = mhi_queue_xfer(*client_handle, uci_buf->data,
data_to_insert_now, MHI_EOT);
if (ret_val) {
goto error_xfer;
} else {
data_left_to_insert -= data_to_insert_now;
data_inserted_so_far += data_to_insert_now;
atomic_inc(&uci_handle->out_pkt_pend_ack);
atomic_dec(&uci_handle->out_attr.avail_pkts);
list_add_tail(&uci_buf->node,
&uci_handle->out_attr.buf_head);
}
if (!data_left_to_insert)
break;
}
return data_inserted_so_far;
error_xfer:
kfree(uci_buf->data);
return data_inserted_so_far;
}
static int mhi_uci_send_status_cmd(struct uci_client *client) static int mhi_uci_send_status_cmd(struct uci_client *client)
{ {
void *buf = NULL; void *buf = NULL;
@ -963,18 +896,11 @@ static ssize_t mhi_uci_client_write(struct file *file,
goto sys_interrupt; goto sys_interrupt;
} }
while (bytes_transferrd != count) { while (count) {
ret_val = mhi_uci_send_packet(&chan_attr->mhi_handle, size_t xfer_size;
(void *)buf, count); void *data_loc = NULL;
if (ret_val < 0) struct uci_buf *uci_buf;
goto sys_interrupt;
bytes_transferrd += ret_val;
if (bytes_transferrd == count)
break;
uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"No descriptors available, did we poll, chan %d?\n",
chan);
mutex_unlock(&chan_attr->chan_lock); mutex_unlock(&chan_attr->chan_lock);
ret_val = wait_event_interruptible(chan_attr->wq, ret_val = wait_event_interruptible(chan_attr->wq,
(atomic_read(&chan_attr->avail_pkts) || (atomic_read(&chan_attr->avail_pkts) ||
@ -991,6 +917,37 @@ static ssize_t mhi_uci_client_write(struct file *file,
ret_val = -ERESTARTSYS; ret_val = -ERESTARTSYS;
goto sys_interrupt; goto sys_interrupt;
} }
xfer_size = min_t(size_t, count, chan_attr->max_packet_size);
data_loc = kmalloc(xfer_size + sizeof(*uci_buf), GFP_KERNEL);
if (!data_loc) {
uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Failed to allocate memory %lu\n", xfer_size);
ret_val = -ENOMEM;
goto sys_interrupt;
}
uci_buf = data_loc + xfer_size;
uci_buf->data = data_loc;
uci_buf->pkt_id = uci_handle->out_attr.pkt_count++;
ret_val = copy_from_user(uci_buf->data, buf, xfer_size);
if (unlikely(ret_val)) {
kfree(uci_buf->data);
goto sys_interrupt;
}
ret_val = mhi_queue_xfer(chan_attr->mhi_handle, uci_buf->data,
xfer_size, MHI_EOT);
if (unlikely(ret_val)) {
kfree(uci_buf->data);
goto sys_interrupt;
}
bytes_transferrd += xfer_size;
count -= xfer_size;
buf += xfer_size;
atomic_inc(&uci_handle->out_pkt_pend_ack);
atomic_dec(&uci_handle->out_attr.avail_pkts);
list_add_tail(&uci_buf->node, &uci_handle->out_attr.buf_head);
} }
mutex_unlock(&chan_attr->chan_lock); mutex_unlock(&chan_attr->chan_lock);