soc: qcom: ipc_router_mhi_xprt: Code Refactor to handle interface changes

MHI supports virtual memory to dma mapping implicitly. Update IPC Router
to pass virtual address directly to MHI. MHI driver also returns
standard Linux error codes in case of failure. Update IPC Router to
handle this change.

CRs-Fixed: 994871
Change-Id: I907adfb5f5d24c06dd038b07a17b31d42b91dfad
Signed-off-by: Chris Lew <clew@codeaurora.org>
This commit is contained in:
Chris Lew 2016-03-28 18:48:58 -07:00 committed by Jeevan Shriram
parent 67f57cd267
commit 62be3545d8

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -39,18 +39,15 @@ if (ipc_router_mhi_xprt_debug_mask) \
#define IPC_ROUTER_MHI_XPRT_NUM_TRBS 10
/**
* ipc_router_mhi_addr_map - DMA to virtual address mapping for an IPC Router
* packet.
* ipc_router_mhi_addr_map - Struct for virtual address to IPC Router
* packet mapping.
* @list_node: Address mapping list node used by mhi transport map list.
* @virt_addr: The virtual address in mapping.
* @dma_addr: The dma address in mapping.
* @pkt: The IPC Router packet for which the virtual address of skbs are mapped
* to DMA address during TX/RX operations.
* @pkt: The IPC Router packet for the virtual address
*/
struct ipc_router_mhi_addr_map {
struct list_head list_node;
void *virt_addr;
dma_addr_t dma_addr;
struct rr_packet *pkt;
};
@ -109,10 +106,10 @@ struct ipc_router_mhi_channel {
* @xprt_option: XPRT specific options to be handled by IPC Router.
* @tx_addr_map_list_lock: The lock to protect the address mapping list for TX
* operations.
* @tx_addr_map_list: DMA to virtual address mapping list for TX operations.
* @tx_addr_map_list: Virtual address mapping list for TX operations.
* @rx_addr_map_list_lock: The lock to protect the address mapping list for RX
* operations.
* @rx_addr_map_list: DMA to virtual address mapping list for RX operations.
* @rx_addr_map_list: Virtual address mapping list for RX operations.
*/
struct ipc_router_mhi_xprt {
struct list_head list;
@ -177,13 +174,13 @@ void ipc_router_mhi_release_pkt(struct kref *ref)
* ipc_router_mhi_xprt_find_addr_map() - Search the mapped virtual address
* @addr_map_list: The list of address mappings.
* @addr_map_list_lock: Reference to the lock that protects the @addr_map_list.
* @addr: The dma address for which mapped virtual address need to be found.
* @addr: The virtual address that needs to be found.
*
* Return: The mapped virtual Address if found, NULL otherwise.
*/
void *ipc_router_mhi_xprt_find_addr_map(struct list_head *addr_map_list,
struct mutex *addr_map_list_lock,
dma_addr_t addr)
void *addr)
{
struct ipc_router_mhi_addr_map *addr_mapping;
struct ipc_router_mhi_addr_map *tmp_addr_mapping;
@ -194,7 +191,7 @@ void *ipc_router_mhi_xprt_find_addr_map(struct list_head *addr_map_list,
mutex_lock(addr_map_list_lock);
list_for_each_entry_safe(addr_mapping, tmp_addr_mapping,
addr_map_list, list_node) {
if (addr_mapping->dma_addr == addr) {
if (addr_mapping->virt_addr == addr) {
virt_addr = addr_mapping->virt_addr;
list_del(&addr_mapping->list_node);
if (addr_mapping->pkt)
@ -207,26 +204,23 @@ void *ipc_router_mhi_xprt_find_addr_map(struct list_head *addr_map_list,
}
mutex_unlock(addr_map_list_lock);
IPC_RTR_ERR(
"%s: Virtual address mapping for DMA addr [%p] not found\n",
"%s: Virtual address mapping [%p] not found\n",
__func__, (void *)addr);
return NULL;
}
/*
* ipc_router_mhi_xprt_add_addr_map() - Add a mapping of virtual address to dma
* address
* ipc_router_mhi_xprt_add_addr_map() - Add a virtual address mapping structure
* @addr_map_list: The list of address mappings.
* @addr_map_list_lock: Reference to the lock that protects the @addr_map_list.
* @pkt: The IPC Router packet that contains the virtual address in skbs.
* @addr: The virtual address which needs to be added.
* @dma_addr: The dma address which needs to be added.
* @virt_addr: The virtual address which needs to be added.
*
* Return: 0 on success, standard Linux error code otherwise.
*/
int ipc_router_mhi_xprt_add_addr_map(struct list_head *addr_map_list,
struct mutex *addr_map_list_lock,
struct rr_packet *pkt, void *virt_addr,
dma_addr_t dma_addr)
struct rr_packet *pkt, void *virt_addr)
{
struct ipc_router_mhi_addr_map *addr_mapping;
@ -236,7 +230,6 @@ int ipc_router_mhi_xprt_add_addr_map(struct list_head *addr_map_list,
if (!addr_mapping)
return -ENOMEM;
addr_mapping->virt_addr = virt_addr;
addr_mapping->dma_addr = dma_addr;
addr_mapping->pkt = pkt;
mutex_lock(addr_map_list_lock);
if (addr_mapping->pkt)
@ -258,9 +251,8 @@ int mhi_xprt_queue_in_buffers(struct ipc_router_mhi_xprt *mhi_xprtp,
{
int i;
struct sk_buff *skb;
dma_addr_t dma_addr;
uint32_t buf_size = mhi_xprtp->ch_hndl.max_packet_size;
enum MHI_STATUS rc_val = MHI_STATUS_SUCCESS;
int rc_val = 0;
for (i = 0; i < num_trbs; i++) {
skb = alloc_skb(buf_size, GFP_KERNEL);
@ -269,31 +261,21 @@ int mhi_xprt_queue_in_buffers(struct ipc_router_mhi_xprt *mhi_xprtp,
__func__, (i + 1));
break;
}
dma_addr = dma_map_single(NULL, skb->data,
buf_size, DMA_BIDIRECTIONAL);
if (dma_mapping_error(NULL, dma_addr)) {
IPC_RTR_ERR("%s: Failed to map DMA for SKB # %d\n",
__func__, (i + 1));
kfree_skb(skb);
break;
}
if (ipc_router_mhi_xprt_add_addr_map(
&mhi_xprtp->rx_addr_map_list,
&mhi_xprtp->rx_addr_map_list_lock, NULL,
skb->data, dma_addr) < 0) {
IPC_RTR_ERR("%s: Could not map %d SKB->DMA address\n",
skb->data) < 0) {
IPC_RTR_ERR("%s: Could not map %d SKB address\n",
__func__, (i + 1));
break;
}
mutex_lock(&mhi_xprtp->ch_hndl.in_skbq_lock);
rc_val = mhi_queue_xfer(mhi_xprtp->ch_hndl.in_handle,
dma_addr, buf_size, MHI_EOT);
if (rc_val != MHI_STATUS_SUCCESS) {
skb->data, buf_size, MHI_EOT);
if (rc_val) {
mutex_unlock(&mhi_xprtp->ch_hndl.in_skbq_lock);
IPC_RTR_ERR("%s: Failed to queue TRB # %d into MHI\n",
__func__, (i + 1));
dma_unmap_single(NULL, dma_addr,
buf_size, DMA_TO_DEVICE);
kfree_skb(skb);
break;
}
@ -388,7 +370,6 @@ static int ipc_router_mhi_write_skb(struct ipc_router_mhi_xprt *mhi_xprtp,
size_t sz_to_write = 0;
size_t offset = 0;
int rc;
dma_addr_t dma_addr;
while (offset < skb->len) {
wait_event(mhi_xprtp->write_wait_q,
@ -404,29 +385,20 @@ static int ipc_router_mhi_write_skb(struct ipc_router_mhi_xprt *mhi_xprtp,
sz_to_write = min((size_t)(skb->len - offset),
(size_t)IPC_ROUTER_MHI_XPRT_MAX_PKT_SIZE);
dma_addr = dma_map_single(NULL, skb->data + offset,
sz_to_write, DMA_TO_DEVICE);
if (dma_mapping_error(NULL, dma_addr)) {
mutex_unlock(&mhi_xprtp->ch_hndl.state_lock);
IPC_RTR_ERR("%s: Failed to map DMA 0x%zx\n",
__func__, sz_to_write);
return -ENOMEM;
}
if (ipc_router_mhi_xprt_add_addr_map(
&mhi_xprtp->tx_addr_map_list,
&mhi_xprtp->tx_addr_map_list_lock, pkt,
skb->data + offset, dma_addr) < 0) {
IPC_RTR_ERR("%s: Could not map SKB->DMA address\n",
skb->data + offset) < 0) {
IPC_RTR_ERR("%s: Could not map SKB address\n",
__func__);
break;
}
rc = mhi_queue_xfer(mhi_xprtp->ch_hndl.out_handle,
dma_addr, sz_to_write, MHI_EOT | MHI_EOB);
if (rc != 0) {
skb->data + offset, sz_to_write,
MHI_EOT | MHI_EOB);
if (rc) {
mutex_unlock(&mhi_xprtp->ch_hndl.state_lock);
dma_unmap_single(NULL, dma_addr, sz_to_write,
DMA_TO_DEVICE);
IPC_RTR_ERR("%s: Error queueing mhi_xfer 0x%zx\n",
__func__, sz_to_write);
return -EFAULT;
@ -496,7 +468,7 @@ static int ipc_router_mhi_write(void *data,
*/
static void mhi_xprt_read_data(struct work_struct *work)
{
dma_addr_t data_addr;
void *data_addr;
ssize_t data_sz;
void *skb_data;
struct sk_buff *skb;
@ -520,15 +492,15 @@ static void mhi_xprt_read_data(struct work_struct *work)
while (1) {
rc = mhi_poll_inbound(mhi_xprtp->ch_hndl.in_handle, &result);
if (rc || !result.payload_buf || !result.bytes_xferd) {
if (rc != MHI_STATUS_RING_EMPTY)
if (rc || !result.buf_addr || !result.bytes_xferd) {
if (rc != -ENODATA)
IPC_RTR_ERR("%s: Poll failed %s:%d:%p:%u\n",
__func__, mhi_xprtp->xprt_name, rc,
(void *)result.payload_buf,
result.bytes_xferd);
result.buf_addr,
(unsigned int) result.bytes_xferd);
break;
}
data_addr = result.payload_buf;
data_addr = result.buf_addr;
data_sz = result.bytes_xferd;
/* Create a new rr_packet, if first fragment */
@ -547,7 +519,6 @@ static void mhi_xprt_read_data(struct work_struct *work)
&mhi_xprtp->rx_addr_map_list_lock,
data_addr);
dma_unmap_single(NULL, data_addr, data_sz, DMA_BIDIRECTIONAL);
if (!skb_data)
continue;
mutex_lock(&mhi_xprtp->ch_hndl.in_skbq_lock);
@ -638,7 +609,7 @@ static void mhi_xprt_enable_event(struct work_struct *work)
if (xprt_work->chan_id == mhi_xprtp->ch_hndl.out_chan_id) {
rc = mhi_open_channel(mhi_xprtp->ch_hndl.out_handle);
if (rc != MHI_STATUS_SUCCESS) {
if (rc) {
IPC_RTR_ERR("%s Failed to open chan 0x%x, rc %d\n",
__func__, mhi_xprtp->ch_hndl.out_chan_id, rc);
goto out_enable_event;
@ -650,7 +621,7 @@ static void mhi_xprt_enable_event(struct work_struct *work)
mutex_unlock(&mhi_xprtp->ch_hndl.state_lock);
} else if (xprt_work->chan_id == mhi_xprtp->ch_hndl.in_chan_id) {
rc = mhi_open_channel(mhi_xprtp->ch_hndl.in_handle);
if (rc != MHI_STATUS_SUCCESS) {
if (rc) {
IPC_RTR_ERR("%s Failed to open chan 0x%x, rc %d\n",
__func__, mhi_xprtp->ch_hndl.in_chan_id, rc);
goto out_enable_event;
@ -743,17 +714,15 @@ static void mhi_xprt_disable_event(struct work_struct *work)
static void mhi_xprt_xfer_event(struct mhi_cb_info *cb_info)
{
struct ipc_router_mhi_xprt *mhi_xprtp;
dma_addr_t out_dma_addr;
void *out_addr;
mhi_xprtp = (struct ipc_router_mhi_xprt *)(cb_info->result->user_data);
if (cb_info->chan == mhi_xprtp->ch_hndl.out_chan_id) {
out_dma_addr = (dma_addr_t)cb_info->result->payload_buf;
dma_unmap_single(NULL, out_dma_addr,
cb_info->result->bytes_xferd, DMA_TO_DEVICE);
out_addr = cb_info->result->buf_addr;
mutex_lock(&mhi_xprtp->ch_hndl.state_lock);
ipc_router_mhi_xprt_find_addr_map(&mhi_xprtp->tx_addr_map_list,
&mhi_xprtp->tx_addr_map_list_lock,
out_dma_addr);
out_addr);
wake_up(&mhi_xprtp->write_wait_q);
mutex_unlock(&mhi_xprtp->ch_hndl.state_lock);
} else if (cb_info->chan == mhi_xprtp->ch_hndl.in_chan_id) {
@ -821,13 +790,13 @@ static void ipc_router_mhi_xprt_cb(struct mhi_cb_info *cb_info)
static int ipc_router_mhi_driver_register(
struct ipc_router_mhi_xprt *mhi_xprtp)
{
enum MHI_STATUS rc_status;
int rc_status;
rc_status = mhi_register_channel(&mhi_xprtp->ch_hndl.out_handle,
mhi_xprtp->ch_hndl.out_chan_id, 0,
&mhi_xprtp->ch_hndl.out_clnt_info,
(void *)mhi_xprtp);
if (rc_status != MHI_STATUS_SUCCESS) {
if (rc_status) {
IPC_RTR_ERR("%s: Error %d registering out_chan for %s\n",
__func__, rc_status, mhi_xprtp->xprt_name);
return -EFAULT;
@ -837,7 +806,7 @@ static int ipc_router_mhi_driver_register(
mhi_xprtp->ch_hndl.in_chan_id, 0,
&mhi_xprtp->ch_hndl.in_clnt_info,
(void *)mhi_xprtp);
if (rc_status != MHI_STATUS_SUCCESS) {
if (rc_status) {
mhi_deregister_channel(mhi_xprtp->ch_hndl.out_handle);
IPC_RTR_ERR("%s: Error %d registering in_chan for %s\n",
__func__, rc_status, mhi_xprtp->xprt_name);