Loading drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +89 −0 Original line number Diff line number Diff line Loading @@ -162,6 +162,12 @@ struct ipa3_usb_transport_type_ctx { void *user_data; enum ipa3_usb_state state; struct finish_suspend_work_context finish_suspend_work; struct ipa_usb_xdci_chan_params ch_params; }; struct ipa3_usb_smmu_reg_map { int cnt; phys_addr_t addr; }; struct ipa3_usb_context { Loading @@ -179,6 +185,7 @@ struct ipa3_usb_context { ttype_ctx[IPA_USB_TRANSPORT_MAX]; struct dentry *dfile_state_info; struct dentry *dent; struct ipa3_usb_smmu_reg_map smmu_reg_map; }; enum ipa3_usb_op { Loading Loading @@ -1112,6 +1119,74 @@ static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params) return true; } static int ipa3_usb_smmu_map_xdci_channel( struct ipa_usb_xdci_chan_params *params, bool map) { int result; u32 gevntcount_r = rounddown(params->gevntcount_low_addr, PAGE_SIZE); u32 xfer_scratch_r = rounddown(params->xfer_scratch.depcmd_low_addr, PAGE_SIZE); if (gevntcount_r != xfer_scratch_r) { IPA_USB_ERR("No support more than 1 page map for USB regs\n"); WARN_ON(1); return -EINVAL; } if (map) { if (ipa3_usb_ctx->smmu_reg_map.cnt == 0) { ipa3_usb_ctx->smmu_reg_map.addr = gevntcount_r; result = ipa3_smmu_map_peer_reg( ipa3_usb_ctx->smmu_reg_map.addr, true); if (result) { IPA_USB_ERR("failed to map USB regs %d\n", result); return result; } } else { if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) { IPA_USB_ERR( "No support for map different reg\n"); return -EINVAL; } } ipa3_usb_ctx->smmu_reg_map.cnt++; } else { if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) { IPA_USB_ERR( "No support for map different reg\n"); return -EINVAL; } if (ipa3_usb_ctx->smmu_reg_map.cnt == 1) { result = ipa3_smmu_map_peer_reg( ipa3_usb_ctx->smmu_reg_map.addr, false); if (result) { IPA_USB_ERR("failed to unmap USB regs %d\n", result); return result; } } 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); 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); if (result) { IPA_USB_ERR("failed to map TRBs buff %d\n", result); return result; } return 0; } static int ipa3_usb_request_xdci_channel( struct ipa_usb_xdci_chan_params *params, struct ipa_req_chan_out_params *out_params) Loading Loading @@ -1186,6 +1261,16 @@ static int ipa3_usb_request_xdci_channel( default: break; } result = ipa3_usb_smmu_map_xdci_channel(params, true); if (result) { IPA_USB_ERR("failed to smmu map %d\n", result); return result; } /* store channel params for SMMU unmap */ ipa3_usb_ctx->ttype_ctx[ttype].ch_params = *params; 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 Loading @@ -1243,6 +1328,7 @@ static int ipa3_usb_request_xdci_channel( result = ipa3_request_gsi_channel(&chan_params, out_params); if (result) { IPA_USB_ERR("failed to allocate GSI channel\n"); ipa3_usb_smmu_map_xdci_channel(params, false); return result; } Loading Loading @@ -1273,6 +1359,9 @@ 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); /* Change ipa_usb state to INITIALIZED */ if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype)) IPA_USB_ERR("failed to change state to initialized\n"); Loading drivers/platform/msm/ipa/ipa_v3/ipa_client.c +77 −0 Original line number Diff line number Diff line Loading @@ -1055,6 +1055,83 @@ static bool ipa3_is_legal_params(struct ipa_request_gsi_channel_params *params) return true; } int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map) { struct iommu_domain *smmu_domain; int res; if (ipa3_ctx->smmu_s1_bypass) return 0; smmu_domain = ipa3_get_smmu_domain(); if (!smmu_domain) { IPAERR("invalid smmu domain\n"); return -EINVAL; } if (map) { res = ipa3_iommu_map(smmu_domain, phys_addr, phys_addr, PAGE_SIZE, IOMMU_READ | IOMMU_WRITE | IOMMU_DEVICE); } else { res = iommu_unmap(smmu_domain, phys_addr, PAGE_SIZE); res = (res != PAGE_SIZE); } if (res) { IPAERR("Fail to %s reg 0x%pa\n", map ? "map" : "unmap", &phys_addr); return -EINVAL; } IPADBG("Peer reg 0x%pa %s\n", &phys_addr, map ? "map" : "unmap"); return 0; } int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map) { struct iommu_domain *smmu_domain; int res; if (ipa3_ctx->smmu_s1_bypass) return 0; smmu_domain = ipa3_get_smmu_domain(); if (!smmu_domain) { IPAERR("invalid smmu domain\n"); return -EINVAL; } if (map) { res = ipa3_iommu_map(smmu_domain, rounddown(iova, PAGE_SIZE), rounddown(phys_addr, 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); return -EINVAL; } } else { res = iommu_unmap(smmu_domain, rounddown(iova, PAGE_SIZE), roundup(size + iova - rounddown(iova, PAGE_SIZE), 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); return -EINVAL; } } IPADBG("Peer buff %s 0x%llx->0x%pa\n", map ? "map" : "unmap", iova, &phys_addr); return 0; } int ipa3_request_gsi_channel(struct ipa_request_gsi_channel_params *params, struct ipa_req_chan_out_params *out_params) { Loading drivers/platform/msm/ipa/ipa_v3/ipa_i.h +3 −0 Original line number Diff line number Diff line Loading @@ -2194,4 +2194,7 @@ const char *ipa_hw_error_str(enum ipa3_hw_errors err_type); 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); #endif /* _IPA3_I_H_ */ Loading
drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +89 −0 Original line number Diff line number Diff line Loading @@ -162,6 +162,12 @@ struct ipa3_usb_transport_type_ctx { void *user_data; enum ipa3_usb_state state; struct finish_suspend_work_context finish_suspend_work; struct ipa_usb_xdci_chan_params ch_params; }; struct ipa3_usb_smmu_reg_map { int cnt; phys_addr_t addr; }; struct ipa3_usb_context { Loading @@ -179,6 +185,7 @@ struct ipa3_usb_context { ttype_ctx[IPA_USB_TRANSPORT_MAX]; struct dentry *dfile_state_info; struct dentry *dent; struct ipa3_usb_smmu_reg_map smmu_reg_map; }; enum ipa3_usb_op { Loading Loading @@ -1112,6 +1119,74 @@ static bool ipa3_usb_check_chan_params(struct ipa_usb_xdci_chan_params *params) return true; } static int ipa3_usb_smmu_map_xdci_channel( struct ipa_usb_xdci_chan_params *params, bool map) { int result; u32 gevntcount_r = rounddown(params->gevntcount_low_addr, PAGE_SIZE); u32 xfer_scratch_r = rounddown(params->xfer_scratch.depcmd_low_addr, PAGE_SIZE); if (gevntcount_r != xfer_scratch_r) { IPA_USB_ERR("No support more than 1 page map for USB regs\n"); WARN_ON(1); return -EINVAL; } if (map) { if (ipa3_usb_ctx->smmu_reg_map.cnt == 0) { ipa3_usb_ctx->smmu_reg_map.addr = gevntcount_r; result = ipa3_smmu_map_peer_reg( ipa3_usb_ctx->smmu_reg_map.addr, true); if (result) { IPA_USB_ERR("failed to map USB regs %d\n", result); return result; } } else { if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) { IPA_USB_ERR( "No support for map different reg\n"); return -EINVAL; } } ipa3_usb_ctx->smmu_reg_map.cnt++; } else { if (gevntcount_r != ipa3_usb_ctx->smmu_reg_map.addr) { IPA_USB_ERR( "No support for map different reg\n"); return -EINVAL; } if (ipa3_usb_ctx->smmu_reg_map.cnt == 1) { result = ipa3_smmu_map_peer_reg( ipa3_usb_ctx->smmu_reg_map.addr, false); if (result) { IPA_USB_ERR("failed to unmap USB regs %d\n", result); return result; } } 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); 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); if (result) { IPA_USB_ERR("failed to map TRBs buff %d\n", result); return result; } return 0; } static int ipa3_usb_request_xdci_channel( struct ipa_usb_xdci_chan_params *params, struct ipa_req_chan_out_params *out_params) Loading Loading @@ -1186,6 +1261,16 @@ static int ipa3_usb_request_xdci_channel( default: break; } result = ipa3_usb_smmu_map_xdci_channel(params, true); if (result) { IPA_USB_ERR("failed to smmu map %d\n", result); return result; } /* store channel params for SMMU unmap */ ipa3_usb_ctx->ttype_ctx[ttype].ch_params = *params; 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 Loading @@ -1243,6 +1328,7 @@ static int ipa3_usb_request_xdci_channel( result = ipa3_request_gsi_channel(&chan_params, out_params); if (result) { IPA_USB_ERR("failed to allocate GSI channel\n"); ipa3_usb_smmu_map_xdci_channel(params, false); return result; } Loading Loading @@ -1273,6 +1359,9 @@ 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); /* Change ipa_usb state to INITIALIZED */ if (!ipa3_usb_set_state(IPA_USB_INITIALIZED, false, ttype)) IPA_USB_ERR("failed to change state to initialized\n"); Loading
drivers/platform/msm/ipa/ipa_v3/ipa_client.c +77 −0 Original line number Diff line number Diff line Loading @@ -1055,6 +1055,83 @@ static bool ipa3_is_legal_params(struct ipa_request_gsi_channel_params *params) return true; } int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map) { struct iommu_domain *smmu_domain; int res; if (ipa3_ctx->smmu_s1_bypass) return 0; smmu_domain = ipa3_get_smmu_domain(); if (!smmu_domain) { IPAERR("invalid smmu domain\n"); return -EINVAL; } if (map) { res = ipa3_iommu_map(smmu_domain, phys_addr, phys_addr, PAGE_SIZE, IOMMU_READ | IOMMU_WRITE | IOMMU_DEVICE); } else { res = iommu_unmap(smmu_domain, phys_addr, PAGE_SIZE); res = (res != PAGE_SIZE); } if (res) { IPAERR("Fail to %s reg 0x%pa\n", map ? "map" : "unmap", &phys_addr); return -EINVAL; } IPADBG("Peer reg 0x%pa %s\n", &phys_addr, map ? "map" : "unmap"); return 0; } int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map) { struct iommu_domain *smmu_domain; int res; if (ipa3_ctx->smmu_s1_bypass) return 0; smmu_domain = ipa3_get_smmu_domain(); if (!smmu_domain) { IPAERR("invalid smmu domain\n"); return -EINVAL; } if (map) { res = ipa3_iommu_map(smmu_domain, rounddown(iova, PAGE_SIZE), rounddown(phys_addr, 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); return -EINVAL; } } else { res = iommu_unmap(smmu_domain, rounddown(iova, PAGE_SIZE), roundup(size + iova - rounddown(iova, PAGE_SIZE), 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); return -EINVAL; } } IPADBG("Peer buff %s 0x%llx->0x%pa\n", map ? "map" : "unmap", iova, &phys_addr); return 0; } int ipa3_request_gsi_channel(struct ipa_request_gsi_channel_params *params, struct ipa_req_chan_out_params *out_params) { Loading
drivers/platform/msm/ipa/ipa_v3/ipa_i.h +3 −0 Original line number Diff line number Diff line Loading @@ -2194,4 +2194,7 @@ const char *ipa_hw_error_str(enum ipa3_hw_errors err_type); 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); #endif /* _IPA3_I_H_ */