Loading drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +93 −17 Original line number Diff line number Diff line Loading @@ -72,6 +72,11 @@ IPA_USB_DRV_NAME " %s:%d " fmt, ## args); \ } while (0) enum ipa_usb_direction { IPA_USB_DIR_UL, IPA_USB_DIR_DL, }; struct ipa_usb_xdci_connect_params_internal { enum ipa_usb_max_usb_packet_size max_pkt_size; u32 ipa_to_usb_clnt_hdl; Loading Loading @@ -167,7 +172,8 @@ struct ipa3_usb_transport_type_ctx { int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, void *user_data); void *user_data; enum ipa3_usb_state state; struct ipa_usb_xdci_chan_params ch_params; struct ipa_usb_xdci_chan_params ul_ch_params; struct ipa_usb_xdci_chan_params dl_ch_params; struct ipa3_usb_teth_prot_conn_params teth_conn_params; }; Loading Loading @@ -1069,8 +1075,6 @@ static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params) params->gevntcount_hi_addr); IPA_USB_DBG_LOW("dir = %d\n", params->dir); IPA_USB_DBG_LOW("xfer_ring_len = %d\n", params->xfer_ring_len); IPA_USB_DBG_LOW("xfer_ring_base_addr = %llx\n", params->xfer_ring_base_addr); IPA_USB_DBG_LOW("last_trb_addr_iova = %x\n", params->xfer_scratch.last_trb_addr_iova); IPA_USB_DBG_LOW("const_buffer_size = %d\n", Loading Loading @@ -1174,15 +1178,16 @@ static int ipa3_usb_smmu_map_xdci_channel( ipa3_usb_ctx->smmu_reg_map.cnt--; } result = ipa3_smmu_map_peer_buff(params->xfer_ring_base_addr_iova, params->xfer_ring_base_addr, params->xfer_ring_len, map); params->xfer_ring_len, map, params->sgt_xfer_rings); if (result) { IPA_USB_ERR("failed to map Xfer ring %d\n", result); return result; } result = ipa3_smmu_map_peer_buff(params->data_buff_base_addr_iova, params->data_buff_base_addr, params->data_buff_base_len, map); params->data_buff_base_len, map, params->sgt_data_buff); if (result) { IPA_USB_ERR("failed to map TRBs buff %d\n", result); return result; Loading @@ -1191,13 +1196,52 @@ static int ipa3_usb_smmu_map_xdci_channel( return 0; } static int ipa3_usb_smmu_store_sgt(struct sg_table **out_ch_ptr, struct sg_table *in_sgt_ptr) { unsigned int nents; if (in_sgt_ptr != NULL) { *out_ch_ptr = kzalloc(sizeof(struct sg_table), GFP_KERNEL); if (*out_ch_ptr == NULL) return -ENOMEM; nents = in_sgt_ptr->nents; (*out_ch_ptr)->sgl = kcalloc(nents, sizeof(struct scatterlist), GFP_KERNEL); if ((*out_ch_ptr)->sgl == NULL) return -ENOMEM; memcpy((*out_ch_ptr)->sgl, in_sgt_ptr->sgl, nents*sizeof((*out_ch_ptr)->sgl)); (*out_ch_ptr)->nents = nents; (*out_ch_ptr)->orig_nents = in_sgt_ptr->orig_nents; } return 0; } static int ipa3_usb_smmu_free_sgt(struct sg_table **out_sgt_ptr) { if (*out_sgt_ptr != NULL) { kfree((*out_sgt_ptr)->sgl); (*out_sgt_ptr)->sgl = NULL; kfree(*out_sgt_ptr); *out_sgt_ptr = NULL; } return 0; } static int ipa3_usb_request_xdci_channel( struct ipa_usb_xdci_chan_params *params, enum ipa_usb_direction dir, struct ipa_req_chan_out_params *out_params) { int result = -EFAULT; struct ipa_request_gsi_channel_params chan_params; enum ipa3_usb_transport_type ttype; struct ipa_usb_xdci_chan_params *xdci_ch_params; IPA_USB_DBG_LOW("entry\n"); if (params == NULL || out_params == NULL || Loading Loading @@ -1273,8 +1317,26 @@ static int ipa3_usb_request_xdci_channel( } /* store channel params for SMMU unmap */ ipa3_usb_ctx->ttype_ctx[ttype].ch_params = *params; if (dir == IPA_USB_DIR_UL) xdci_ch_params = &ipa3_usb_ctx->ttype_ctx[ttype].ul_ch_params; else xdci_ch_params = &ipa3_usb_ctx->ttype_ctx[ttype].dl_ch_params; *xdci_ch_params = *params; result = ipa3_usb_smmu_store_sgt( &xdci_ch_params->sgt_xfer_rings, params->sgt_xfer_rings); if (result) { ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_xfer_rings); return result; } result = ipa3_usb_smmu_store_sgt( &xdci_ch_params->sgt_data_buff, params->sgt_data_buff); if (result) { ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_data_buff); return result; } chan_params.keep_ipa_awake = params->keep_ipa_awake; chan_params.evt_ring_params.intf = GSI_EVT_CHTYPE_XDCI_EV; chan_params.evt_ring_params.intr = GSI_INTR_IRQ; Loading @@ -1282,7 +1344,7 @@ static int ipa3_usb_request_xdci_channel( chan_params.evt_ring_params.ring_len = params->xfer_ring_len - chan_params.evt_ring_params.re_size; chan_params.evt_ring_params.ring_base_addr = params->xfer_ring_base_addr; params->xfer_ring_base_addr_iova; chan_params.evt_ring_params.ring_base_vaddr = NULL; chan_params.evt_ring_params.int_modt = 0; chan_params.evt_ring_params.int_modt = 0; Loading @@ -1302,7 +1364,7 @@ static int ipa3_usb_request_xdci_channel( chan_params.chan_params.re_size = GSI_CHAN_RE_SIZE_16B; chan_params.chan_params.ring_len = params->xfer_ring_len; chan_params.chan_params.ring_base_addr = params->xfer_ring_base_addr; params->xfer_ring_base_addr_iova; chan_params.chan_params.ring_base_vaddr = NULL; chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE; chan_params.chan_params.max_prefetch = GSI_ONE_PREFETCH_SEG; Loading Loading @@ -1345,9 +1407,11 @@ static int ipa3_usb_request_xdci_channel( } static int ipa3_usb_release_xdci_channel(u32 clnt_hdl, enum ipa_usb_direction dir, enum ipa3_usb_transport_type ttype) { int result = 0; struct ipa_usb_xdci_chan_params *xdci_ch_params; IPA_USB_DBG_LOW("entry\n"); if (ttype < 0 || ttype >= IPA_USB_TRANSPORT_MAX) { Loading @@ -1367,8 +1431,17 @@ static int ipa3_usb_release_xdci_channel(u32 clnt_hdl, return result; } result = ipa3_usb_smmu_map_xdci_channel( &ipa3_usb_ctx->ttype_ctx[ttype].ch_params, false); if (dir == IPA_USB_DIR_UL) xdci_ch_params = &ipa3_usb_ctx->ttype_ctx[ttype].ul_ch_params; else xdci_ch_params = &ipa3_usb_ctx->ttype_ctx[ttype].dl_ch_params; result = ipa3_usb_smmu_map_xdci_channel(xdci_ch_params, false); if (xdci_ch_params->sgt_xfer_rings != NULL) ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_xfer_rings); if (xdci_ch_params->sgt_data_buff != NULL) ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_data_buff); /* Change ipa_usb state to INITIALIZED */ if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype)) Loading Loading @@ -2131,14 +2204,15 @@ int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params, if (connect_params->teth_prot != IPA_USB_DIAG) { result = ipa3_usb_request_xdci_channel(ul_chan_params, ul_out_params); IPA_USB_DIR_UL, ul_out_params); if (result) { IPA_USB_ERR("failed to allocate UL channel.\n"); goto bad_params; } } result = ipa3_usb_request_xdci_channel(dl_chan_params, dl_out_params); result = ipa3_usb_request_xdci_channel(dl_chan_params, IPA_USB_DIR_DL, dl_out_params); if (result) { IPA_USB_ERR("failed to allocate DL/DPL channel.\n"); goto alloc_dl_chan_fail; Loading Loading @@ -2174,11 +2248,12 @@ int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params, return 0; connect_fail: ipa3_usb_release_xdci_channel(dl_out_params->clnt_hdl, ipa3_usb_release_xdci_channel(dl_out_params->clnt_hdl, IPA_USB_DIR_DL, IPA3_USB_GET_TTYPE(dl_chan_params->teth_prot)); alloc_dl_chan_fail: if (connect_params->teth_prot != IPA_USB_DIAG) ipa3_usb_release_xdci_channel(ul_out_params->clnt_hdl, IPA_USB_DIR_UL, IPA3_USB_GET_TTYPE(ul_chan_params->teth_prot)); bad_params: mutex_unlock(&ipa3_usb_ctx->general_mutex); Loading Loading @@ -2250,14 +2325,16 @@ static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl, IPA_USB_ERR("failed to change state to stopped\n"); if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype); result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, IPA_USB_DIR_UL, ttype); if (result) { IPA_USB_ERR("failed to release UL channel.\n"); return result; } } result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype); result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, IPA_USB_DIR_DL, ttype); if (result) { IPA_USB_ERR("failed to release DL channel.\n"); return result; Loading Loading @@ -2869,9 +2946,8 @@ static int __init ipa3_usb_init(void) pr_debug("entry\n"); ipa3_usb_ctx = kzalloc(sizeof(struct ipa3_usb_context), GFP_KERNEL); if (ipa3_usb_ctx == NULL) { pr_err("failed to allocate memory\n"); pr_err(":ipa_usb init failed\n"); return -EFAULT; return -ENOMEM; } memset(ipa3_usb_ctx, 0, sizeof(struct ipa3_usb_context)); Loading drivers/platform/msm/ipa/ipa_v3/ipa_client.c +46 −19 Original line number Diff line number Diff line Loading @@ -548,10 +548,17 @@ int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map) return 0; } int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map) int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt) { struct iommu_domain *smmu_domain; int res; phys_addr_t phys; unsigned long va; struct scatterlist *sg; int count = 0; size_t len; int i; struct page *page; if (ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]) return 0; Loading @@ -562,17 +569,41 @@ int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map) return -EINVAL; } /* * USB GSI driver would update sgt irrespective of USB S1 * is enable or bypass. * If USB S1 is enabled using IOMMU, iova != pa. * If USB S1 is bypass, iova == pa. */ if (map) { if (sgt != NULL) { va = rounddown(iova, PAGE_SIZE); for_each_sg(sgt->sgl, sg, sgt->nents, i) { page = sg_page(sg); phys = page_to_phys(page); len = PAGE_ALIGN(sg->offset + sg->length); res = ipa3_iommu_map(smmu_domain, va, phys, len, IOMMU_READ | IOMMU_WRITE); if (res) { IPAERR("Fail to map pa=%pa\n", &phys); return -EINVAL; } va += len; count++; } } else { res = ipa3_iommu_map(smmu_domain, rounddown(iova, PAGE_SIZE), rounddown(phys_addr, PAGE_SIZE), roundup(size + iova - rounddown(iova, PAGE_SIZE), rounddown(iova, PAGE_SIZE), roundup(size + iova - rounddown(iova, PAGE_SIZE), PAGE_SIZE), IOMMU_READ | IOMMU_WRITE); if (res) { IPAERR("Fail to map 0x%llx->0x%pa\n", iova, &phys_addr); IPAERR("Fail to map 0x%llx\n", iova); return -EINVAL; } } } else { res = iommu_unmap(smmu_domain, rounddown(iova, PAGE_SIZE), Loading @@ -580,15 +611,11 @@ int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map) PAGE_SIZE)); if (res != roundup(size + iova - rounddown(iova, PAGE_SIZE), PAGE_SIZE)) { IPAERR("Fail to unmap 0x%llx->0x%pa\n", iova, &phys_addr); IPAERR("Fail to unmap 0x%llx\n", iova); return -EINVAL; } } IPADBG("Peer buff %s 0x%llx->0x%pa\n", map ? "map" : "unmap", iova, &phys_addr); IPADBG("Peer buff %s 0x%llx\n", map ? "map" : "unmap", iova); return 0; } Loading drivers/platform/msm/ipa/ipa_v3/ipa_i.h +1 −2 Original line number Diff line number Diff line Loading @@ -2301,8 +2301,7 @@ int ipa_gsi_ch20_wa(void); int ipa3_rx_poll(u32 clnt_hdl, int budget); void ipa3_recycle_wan_skb(struct sk_buff *skb); int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map); int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map); int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt); void ipa3_reset_freeze_vote(void); int ipa3_ntn_init(void); int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats); Loading drivers/usb/gadget/function/f_gsi.c +6 −10 Original line number Diff line number Diff line Loading @@ -300,15 +300,13 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) gsi_channel_info.gevntcount_hi_addr; in_params->dir = GSI_CHAN_DIR_FROM_GSI; in_params->xfer_ring_len = gsi_channel_info.xfer_ring_len; in_params->xfer_ring_base_addr = gsi_channel_info.xfer_ring_base_addr; in_params->xfer_scratch.last_trb_addr_iova = gsi_channel_info.last_trb_addr; in_params->xfer_ring_base_addr = in_params->xfer_ring_base_addr_iova = in_params->xfer_ring_base_addr_iova = gsi_channel_info.xfer_ring_base_addr; in_params->data_buff_base_len = d_port->in_request.buf_len * d_port->in_request.num_bufs; in_params->data_buff_base_addr = in_params->data_buff_base_addr_iova = d_port->in_request.dma; in_params->data_buff_base_addr_iova = d_port->in_request.dma; in_params->xfer_scratch.const_buffer_size = gsi_channel_info.const_buffer_size; in_params->xfer_scratch.depcmd_low_addr = Loading Loading @@ -340,12 +338,10 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) out_params->dir = GSI_CHAN_DIR_TO_GSI; out_params->xfer_ring_len = gsi_channel_info.xfer_ring_len; out_params->xfer_ring_base_addr = out_params->xfer_ring_base_addr_iova = gsi_channel_info.xfer_ring_base_addr; out_params->data_buff_base_len = d_port->out_request.buf_len * d_port->out_request.num_bufs; out_params->data_buff_base_addr = out_params->data_buff_base_addr_iova = d_port->out_request.dma; out_params->xfer_scratch.last_trb_addr_iova = Loading Loading @@ -3069,7 +3065,7 @@ static ssize_t gsi_info_show(struct config_item *item, char *page) ipa_chnl_params->xfer_ring_len); len += scnprintf(buf + len, PAGE_SIZE - len, "%25s %10x\n", "IN TRB Base Addr: ", (unsigned int) ipa_chnl_params->xfer_ring_base_addr); ipa_chnl_params->xfer_ring_base_addr_iova); len += scnprintf(buf + len, PAGE_SIZE - len, "%25s %10x\n", "GEVENTCNTLO IN Addr: ", ipa_chnl_params->gevntcount_low_addr); Loading Loading @@ -3103,7 +3099,7 @@ static ssize_t gsi_info_show(struct config_item *item, char *page) ipa_chnl_params->xfer_ring_len); len += scnprintf(buf + len, PAGE_SIZE - len, "%25s %10x\n", "OUT TRB Base Addr: ", (unsigned int) ipa_chnl_params->xfer_ring_base_addr); ipa_chnl_params->xfer_ring_base_addr_iova); len += scnprintf(buf + len, PAGE_SIZE - len, "%25s %10x\n", "GEVENTCNTLO OUT Addr: ", ipa_chnl_params->gevntcount_low_addr); Loading include/linux/ipa_usb.h +11 −9 Original line number Diff line number Diff line /* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-2018, 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 Loading Loading @@ -121,14 +121,16 @@ struct ipa_usb_xdci_chan_scratch { * @dir: channel direction * @xfer_ring_len: length of transfer ring in bytes (must be integral * multiple of transfer element size - 16B for xDCI) * @xfer_ring_base_addr: physical base address of transfer ring. Address must be * aligned to xfer_ring_len rounded to power of two * @xfer_scratch: parameters for xDCI channel scratch * @xfer_ring_base_addr_iova: IO virtual address mapped to xfer_ring_base_addr * @xfer_ring_base_addr_iova: IO virtual address mapped to pysical base address * @data_buff_base_len: length of data buffer allocated by USB driver * @data_buff_base_addr: physical base address for the data buffer (where TRBs * points) * @data_buff_base_addr_iova: IO virtual address mapped to data_buff_base_addr * @data_buff_base_addr_iova: IO virtual address mapped to pysical base address * @sgt_xfer_rings: Scatter table for Xfer rings,contains valid non NULL * value * when USB S1-SMMU enabed, else NULL. * @sgt_data_buff: Scatter table for data buffs,contains valid non NULL * value * when USB S1-SMMU enabed, else NULL. * */ struct ipa_usb_xdci_chan_params { Loading @@ -143,12 +145,12 @@ struct ipa_usb_xdci_chan_params { /* transfer ring params */ enum gsi_chan_dir dir; u16 xfer_ring_len; u64 xfer_ring_base_addr; struct ipa_usb_xdci_chan_scratch xfer_scratch; u64 xfer_ring_base_addr_iova; u32 data_buff_base_len; u64 data_buff_base_addr; u64 data_buff_base_addr_iova; struct sg_table *sgt_xfer_rings; struct sg_table *sgt_data_buff; }; /** Loading Loading
drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +93 −17 Original line number Diff line number Diff line Loading @@ -72,6 +72,11 @@ IPA_USB_DRV_NAME " %s:%d " fmt, ## args); \ } while (0) enum ipa_usb_direction { IPA_USB_DIR_UL, IPA_USB_DIR_DL, }; struct ipa_usb_xdci_connect_params_internal { enum ipa_usb_max_usb_packet_size max_pkt_size; u32 ipa_to_usb_clnt_hdl; Loading Loading @@ -167,7 +172,8 @@ struct ipa3_usb_transport_type_ctx { int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, void *user_data); void *user_data; enum ipa3_usb_state state; struct ipa_usb_xdci_chan_params ch_params; struct ipa_usb_xdci_chan_params ul_ch_params; struct ipa_usb_xdci_chan_params dl_ch_params; struct ipa3_usb_teth_prot_conn_params teth_conn_params; }; Loading Loading @@ -1069,8 +1075,6 @@ static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params) params->gevntcount_hi_addr); IPA_USB_DBG_LOW("dir = %d\n", params->dir); IPA_USB_DBG_LOW("xfer_ring_len = %d\n", params->xfer_ring_len); IPA_USB_DBG_LOW("xfer_ring_base_addr = %llx\n", params->xfer_ring_base_addr); IPA_USB_DBG_LOW("last_trb_addr_iova = %x\n", params->xfer_scratch.last_trb_addr_iova); IPA_USB_DBG_LOW("const_buffer_size = %d\n", Loading Loading @@ -1174,15 +1178,16 @@ static int ipa3_usb_smmu_map_xdci_channel( ipa3_usb_ctx->smmu_reg_map.cnt--; } result = ipa3_smmu_map_peer_buff(params->xfer_ring_base_addr_iova, params->xfer_ring_base_addr, params->xfer_ring_len, map); params->xfer_ring_len, map, params->sgt_xfer_rings); if (result) { IPA_USB_ERR("failed to map Xfer ring %d\n", result); return result; } result = ipa3_smmu_map_peer_buff(params->data_buff_base_addr_iova, params->data_buff_base_addr, params->data_buff_base_len, map); params->data_buff_base_len, map, params->sgt_data_buff); if (result) { IPA_USB_ERR("failed to map TRBs buff %d\n", result); return result; Loading @@ -1191,13 +1196,52 @@ static int ipa3_usb_smmu_map_xdci_channel( return 0; } static int ipa3_usb_smmu_store_sgt(struct sg_table **out_ch_ptr, struct sg_table *in_sgt_ptr) { unsigned int nents; if (in_sgt_ptr != NULL) { *out_ch_ptr = kzalloc(sizeof(struct sg_table), GFP_KERNEL); if (*out_ch_ptr == NULL) return -ENOMEM; nents = in_sgt_ptr->nents; (*out_ch_ptr)->sgl = kcalloc(nents, sizeof(struct scatterlist), GFP_KERNEL); if ((*out_ch_ptr)->sgl == NULL) return -ENOMEM; memcpy((*out_ch_ptr)->sgl, in_sgt_ptr->sgl, nents*sizeof((*out_ch_ptr)->sgl)); (*out_ch_ptr)->nents = nents; (*out_ch_ptr)->orig_nents = in_sgt_ptr->orig_nents; } return 0; } static int ipa3_usb_smmu_free_sgt(struct sg_table **out_sgt_ptr) { if (*out_sgt_ptr != NULL) { kfree((*out_sgt_ptr)->sgl); (*out_sgt_ptr)->sgl = NULL; kfree(*out_sgt_ptr); *out_sgt_ptr = NULL; } return 0; } static int ipa3_usb_request_xdci_channel( struct ipa_usb_xdci_chan_params *params, enum ipa_usb_direction dir, struct ipa_req_chan_out_params *out_params) { int result = -EFAULT; struct ipa_request_gsi_channel_params chan_params; enum ipa3_usb_transport_type ttype; struct ipa_usb_xdci_chan_params *xdci_ch_params; IPA_USB_DBG_LOW("entry\n"); if (params == NULL || out_params == NULL || Loading Loading @@ -1273,8 +1317,26 @@ static int ipa3_usb_request_xdci_channel( } /* store channel params for SMMU unmap */ ipa3_usb_ctx->ttype_ctx[ttype].ch_params = *params; if (dir == IPA_USB_DIR_UL) xdci_ch_params = &ipa3_usb_ctx->ttype_ctx[ttype].ul_ch_params; else xdci_ch_params = &ipa3_usb_ctx->ttype_ctx[ttype].dl_ch_params; *xdci_ch_params = *params; result = ipa3_usb_smmu_store_sgt( &xdci_ch_params->sgt_xfer_rings, params->sgt_xfer_rings); if (result) { ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_xfer_rings); return result; } result = ipa3_usb_smmu_store_sgt( &xdci_ch_params->sgt_data_buff, params->sgt_data_buff); if (result) { ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_data_buff); return result; } chan_params.keep_ipa_awake = params->keep_ipa_awake; chan_params.evt_ring_params.intf = GSI_EVT_CHTYPE_XDCI_EV; chan_params.evt_ring_params.intr = GSI_INTR_IRQ; Loading @@ -1282,7 +1344,7 @@ static int ipa3_usb_request_xdci_channel( chan_params.evt_ring_params.ring_len = params->xfer_ring_len - chan_params.evt_ring_params.re_size; chan_params.evt_ring_params.ring_base_addr = params->xfer_ring_base_addr; params->xfer_ring_base_addr_iova; chan_params.evt_ring_params.ring_base_vaddr = NULL; chan_params.evt_ring_params.int_modt = 0; chan_params.evt_ring_params.int_modt = 0; Loading @@ -1302,7 +1364,7 @@ static int ipa3_usb_request_xdci_channel( chan_params.chan_params.re_size = GSI_CHAN_RE_SIZE_16B; chan_params.chan_params.ring_len = params->xfer_ring_len; chan_params.chan_params.ring_base_addr = params->xfer_ring_base_addr; params->xfer_ring_base_addr_iova; chan_params.chan_params.ring_base_vaddr = NULL; chan_params.chan_params.use_db_eng = GSI_CHAN_DB_MODE; chan_params.chan_params.max_prefetch = GSI_ONE_PREFETCH_SEG; Loading Loading @@ -1345,9 +1407,11 @@ static int ipa3_usb_request_xdci_channel( } static int ipa3_usb_release_xdci_channel(u32 clnt_hdl, enum ipa_usb_direction dir, enum ipa3_usb_transport_type ttype) { int result = 0; struct ipa_usb_xdci_chan_params *xdci_ch_params; IPA_USB_DBG_LOW("entry\n"); if (ttype < 0 || ttype >= IPA_USB_TRANSPORT_MAX) { Loading @@ -1367,8 +1431,17 @@ static int ipa3_usb_release_xdci_channel(u32 clnt_hdl, return result; } result = ipa3_usb_smmu_map_xdci_channel( &ipa3_usb_ctx->ttype_ctx[ttype].ch_params, false); if (dir == IPA_USB_DIR_UL) xdci_ch_params = &ipa3_usb_ctx->ttype_ctx[ttype].ul_ch_params; else xdci_ch_params = &ipa3_usb_ctx->ttype_ctx[ttype].dl_ch_params; result = ipa3_usb_smmu_map_xdci_channel(xdci_ch_params, false); if (xdci_ch_params->sgt_xfer_rings != NULL) ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_xfer_rings); if (xdci_ch_params->sgt_data_buff != NULL) ipa3_usb_smmu_free_sgt(&xdci_ch_params->sgt_data_buff); /* Change ipa_usb state to INITIALIZED */ if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype)) Loading Loading @@ -2131,14 +2204,15 @@ int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params, if (connect_params->teth_prot != IPA_USB_DIAG) { result = ipa3_usb_request_xdci_channel(ul_chan_params, ul_out_params); IPA_USB_DIR_UL, ul_out_params); if (result) { IPA_USB_ERR("failed to allocate UL channel.\n"); goto bad_params; } } result = ipa3_usb_request_xdci_channel(dl_chan_params, dl_out_params); result = ipa3_usb_request_xdci_channel(dl_chan_params, IPA_USB_DIR_DL, dl_out_params); if (result) { IPA_USB_ERR("failed to allocate DL/DPL channel.\n"); goto alloc_dl_chan_fail; Loading Loading @@ -2174,11 +2248,12 @@ int ipa_usb_xdci_connect(struct ipa_usb_xdci_chan_params *ul_chan_params, return 0; connect_fail: ipa3_usb_release_xdci_channel(dl_out_params->clnt_hdl, ipa3_usb_release_xdci_channel(dl_out_params->clnt_hdl, IPA_USB_DIR_DL, IPA3_USB_GET_TTYPE(dl_chan_params->teth_prot)); alloc_dl_chan_fail: if (connect_params->teth_prot != IPA_USB_DIAG) ipa3_usb_release_xdci_channel(ul_out_params->clnt_hdl, IPA_USB_DIR_UL, IPA3_USB_GET_TTYPE(ul_chan_params->teth_prot)); bad_params: mutex_unlock(&ipa3_usb_ctx->general_mutex); Loading Loading @@ -2250,14 +2325,16 @@ static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl, IPA_USB_ERR("failed to change state to stopped\n"); if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype); result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, IPA_USB_DIR_UL, ttype); if (result) { IPA_USB_ERR("failed to release UL channel.\n"); return result; } } result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype); result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, IPA_USB_DIR_DL, ttype); if (result) { IPA_USB_ERR("failed to release DL channel.\n"); return result; Loading Loading @@ -2869,9 +2946,8 @@ static int __init ipa3_usb_init(void) pr_debug("entry\n"); ipa3_usb_ctx = kzalloc(sizeof(struct ipa3_usb_context), GFP_KERNEL); if (ipa3_usb_ctx == NULL) { pr_err("failed to allocate memory\n"); pr_err(":ipa_usb init failed\n"); return -EFAULT; return -ENOMEM; } memset(ipa3_usb_ctx, 0, sizeof(struct ipa3_usb_context)); Loading
drivers/platform/msm/ipa/ipa_v3/ipa_client.c +46 −19 Original line number Diff line number Diff line Loading @@ -548,10 +548,17 @@ int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map) return 0; } int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map) int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt) { struct iommu_domain *smmu_domain; int res; phys_addr_t phys; unsigned long va; struct scatterlist *sg; int count = 0; size_t len; int i; struct page *page; if (ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]) return 0; Loading @@ -562,17 +569,41 @@ int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map) return -EINVAL; } /* * USB GSI driver would update sgt irrespective of USB S1 * is enable or bypass. * If USB S1 is enabled using IOMMU, iova != pa. * If USB S1 is bypass, iova == pa. */ if (map) { if (sgt != NULL) { va = rounddown(iova, PAGE_SIZE); for_each_sg(sgt->sgl, sg, sgt->nents, i) { page = sg_page(sg); phys = page_to_phys(page); len = PAGE_ALIGN(sg->offset + sg->length); res = ipa3_iommu_map(smmu_domain, va, phys, len, IOMMU_READ | IOMMU_WRITE); if (res) { IPAERR("Fail to map pa=%pa\n", &phys); return -EINVAL; } va += len; count++; } } else { res = ipa3_iommu_map(smmu_domain, rounddown(iova, PAGE_SIZE), rounddown(phys_addr, PAGE_SIZE), roundup(size + iova - rounddown(iova, PAGE_SIZE), rounddown(iova, PAGE_SIZE), roundup(size + iova - rounddown(iova, PAGE_SIZE), PAGE_SIZE), IOMMU_READ | IOMMU_WRITE); if (res) { IPAERR("Fail to map 0x%llx->0x%pa\n", iova, &phys_addr); IPAERR("Fail to map 0x%llx\n", iova); return -EINVAL; } } } else { res = iommu_unmap(smmu_domain, rounddown(iova, PAGE_SIZE), Loading @@ -580,15 +611,11 @@ int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map) PAGE_SIZE)); if (res != roundup(size + iova - rounddown(iova, PAGE_SIZE), PAGE_SIZE)) { IPAERR("Fail to unmap 0x%llx->0x%pa\n", iova, &phys_addr); IPAERR("Fail to unmap 0x%llx\n", iova); return -EINVAL; } } IPADBG("Peer buff %s 0x%llx->0x%pa\n", map ? "map" : "unmap", iova, &phys_addr); IPADBG("Peer buff %s 0x%llx\n", map ? "map" : "unmap", iova); return 0; } Loading
drivers/platform/msm/ipa/ipa_v3/ipa_i.h +1 −2 Original line number Diff line number Diff line Loading @@ -2301,8 +2301,7 @@ int ipa_gsi_ch20_wa(void); int ipa3_rx_poll(u32 clnt_hdl, int budget); void ipa3_recycle_wan_skb(struct sk_buff *skb); int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map); int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map); int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt); void ipa3_reset_freeze_vote(void); int ipa3_ntn_init(void); int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats); Loading
drivers/usb/gadget/function/f_gsi.c +6 −10 Original line number Diff line number Diff line Loading @@ -300,15 +300,13 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) gsi_channel_info.gevntcount_hi_addr; in_params->dir = GSI_CHAN_DIR_FROM_GSI; in_params->xfer_ring_len = gsi_channel_info.xfer_ring_len; in_params->xfer_ring_base_addr = gsi_channel_info.xfer_ring_base_addr; in_params->xfer_scratch.last_trb_addr_iova = gsi_channel_info.last_trb_addr; in_params->xfer_ring_base_addr = in_params->xfer_ring_base_addr_iova = in_params->xfer_ring_base_addr_iova = gsi_channel_info.xfer_ring_base_addr; in_params->data_buff_base_len = d_port->in_request.buf_len * d_port->in_request.num_bufs; in_params->data_buff_base_addr = in_params->data_buff_base_addr_iova = d_port->in_request.dma; in_params->data_buff_base_addr_iova = d_port->in_request.dma; in_params->xfer_scratch.const_buffer_size = gsi_channel_info.const_buffer_size; in_params->xfer_scratch.depcmd_low_addr = Loading Loading @@ -340,12 +338,10 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) out_params->dir = GSI_CHAN_DIR_TO_GSI; out_params->xfer_ring_len = gsi_channel_info.xfer_ring_len; out_params->xfer_ring_base_addr = out_params->xfer_ring_base_addr_iova = gsi_channel_info.xfer_ring_base_addr; out_params->data_buff_base_len = d_port->out_request.buf_len * d_port->out_request.num_bufs; out_params->data_buff_base_addr = out_params->data_buff_base_addr_iova = d_port->out_request.dma; out_params->xfer_scratch.last_trb_addr_iova = Loading Loading @@ -3069,7 +3065,7 @@ static ssize_t gsi_info_show(struct config_item *item, char *page) ipa_chnl_params->xfer_ring_len); len += scnprintf(buf + len, PAGE_SIZE - len, "%25s %10x\n", "IN TRB Base Addr: ", (unsigned int) ipa_chnl_params->xfer_ring_base_addr); ipa_chnl_params->xfer_ring_base_addr_iova); len += scnprintf(buf + len, PAGE_SIZE - len, "%25s %10x\n", "GEVENTCNTLO IN Addr: ", ipa_chnl_params->gevntcount_low_addr); Loading Loading @@ -3103,7 +3099,7 @@ static ssize_t gsi_info_show(struct config_item *item, char *page) ipa_chnl_params->xfer_ring_len); len += scnprintf(buf + len, PAGE_SIZE - len, "%25s %10x\n", "OUT TRB Base Addr: ", (unsigned int) ipa_chnl_params->xfer_ring_base_addr); ipa_chnl_params->xfer_ring_base_addr_iova); len += scnprintf(buf + len, PAGE_SIZE - len, "%25s %10x\n", "GEVENTCNTLO OUT Addr: ", ipa_chnl_params->gevntcount_low_addr); Loading
include/linux/ipa_usb.h +11 −9 Original line number Diff line number Diff line /* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-2018, 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 Loading Loading @@ -121,14 +121,16 @@ struct ipa_usb_xdci_chan_scratch { * @dir: channel direction * @xfer_ring_len: length of transfer ring in bytes (must be integral * multiple of transfer element size - 16B for xDCI) * @xfer_ring_base_addr: physical base address of transfer ring. Address must be * aligned to xfer_ring_len rounded to power of two * @xfer_scratch: parameters for xDCI channel scratch * @xfer_ring_base_addr_iova: IO virtual address mapped to xfer_ring_base_addr * @xfer_ring_base_addr_iova: IO virtual address mapped to pysical base address * @data_buff_base_len: length of data buffer allocated by USB driver * @data_buff_base_addr: physical base address for the data buffer (where TRBs * points) * @data_buff_base_addr_iova: IO virtual address mapped to data_buff_base_addr * @data_buff_base_addr_iova: IO virtual address mapped to pysical base address * @sgt_xfer_rings: Scatter table for Xfer rings,contains valid non NULL * value * when USB S1-SMMU enabed, else NULL. * @sgt_data_buff: Scatter table for data buffs,contains valid non NULL * value * when USB S1-SMMU enabed, else NULL. * */ struct ipa_usb_xdci_chan_params { Loading @@ -143,12 +145,12 @@ struct ipa_usb_xdci_chan_params { /* transfer ring params */ enum gsi_chan_dir dir; u16 xfer_ring_len; u64 xfer_ring_base_addr; struct ipa_usb_xdci_chan_scratch xfer_scratch; u64 xfer_ring_base_addr_iova; u32 data_buff_base_len; u64 data_buff_base_addr; u64 data_buff_base_addr_iova; struct sg_table *sgt_xfer_rings; struct sg_table *sgt_data_buff; }; /** Loading