Loading drivers/platform/msm/ipa/ipa_api.c +1 −0 Original line number Diff line number Diff line Loading @@ -2944,6 +2944,7 @@ static const struct of_device_id ipa_plat_drv_match[] = { { .compatible = "qcom,ipa-smmu-ap-cb", }, { .compatible = "qcom,ipa-smmu-wlan-cb", }, { .compatible = "qcom,ipa-smmu-uc-cb", }, { .compatible = "qcom,ipa-smmu-11ad-cb", }, { .compatible = "qcom,smp2p-map-ipa-1-in", }, { .compatible = "qcom,smp2p-map-ipa-1-out", }, {} Loading drivers/platform/msm/ipa/ipa_clients/ipa_wigig.c +130 −90 Original line number Diff line number Diff line Loading @@ -63,6 +63,9 @@ struct ipa_wigig_context { struct ipa_wigig_tx_pipe_data_buffer_info_smmu tx_buff_smmu[IPA_WIGIG_TX_PIPE_NUM]; char clients_mac[IPA_WIGIG_TX_PIPE_NUM][IPA_MAC_ADDR_SIZE]; bool smmu_en; bool shared_cb; bool rx_connected; }; static struct ipa_wigig_context *ipa_wigig_ctx; Loading Loading @@ -155,8 +158,7 @@ bool ipa_wigig_is_smmu_enabled(void) IPA_WIGIG_DBG("\n"); in.smmu_client = IPA_SMMU_WLAN_CLIENT; in.smmu_client = IPA_SMMU_WIGIG_CLIENT; ipa_get_smmu_params(&in, &out); IPA_WIGIG_DBG("exit (%d)\n", out.smmu_enable); Loading @@ -165,6 +167,29 @@ bool ipa_wigig_is_smmu_enabled(void) } EXPORT_SYMBOL(ipa_wigig_is_smmu_enabled); static int ipa_wigig_init_smmu_params(void) { struct ipa_smmu_in_params in; struct ipa_smmu_out_params out; int ret; IPA_WIGIG_DBG("\n"); in.smmu_client = IPA_SMMU_WIGIG_CLIENT; ret = ipa_get_smmu_params(&in, &out); if (ret) { IPA_WIGIG_ERR("couldn't get SMMU params %d\n", ret); return ret; } ipa_wigig_ctx->smmu_en = out.smmu_enable; ipa_wigig_ctx->shared_cb = out.shared_cb; IPA_WIGIG_DBG("SMMU (%s), 11ad CB (%s)\n", out.smmu_enable ? "enabled" : "disabled", out.shared_cb ? "shared" : "not shared"); return 0; } static int ipa_wigig_commit_partial_hdr( struct ipa_ioc_add_hdr *hdr, const char *netdev_name, Loading Loading @@ -550,17 +575,20 @@ int ipa_wigig_conn_rx_pipe(struct ipa_wigig_conn_rx_in_params *in, return -EPERM; } if (ipa_wigig_is_smmu_enabled()) { IPA_WIGIG_ERR("IPA SMMU is enabled, wrong API used\n"); return -EFAULT; } ret = ipa_uc_state_check(); if (ret) { IPA_WIGIG_ERR("uC not ready\n"); return ret; } if (ipa_wigig_init_smmu_params()) return -EINVAL; if (ipa_wigig_ctx->smmu_en) { IPA_WIGIG_ERR("IPA SMMU is enabled, wrong API used\n"); return -EFAULT; } memset(&pm_params, 0, sizeof(pm_params)); pm_params.name = "wigig"; pm_params.callback = ipa_wigig_pm_cb; Loading Loading @@ -591,6 +619,8 @@ int ipa_wigig_conn_rx_pipe(struct ipa_wigig_conn_rx_in_params *in, goto fail_connect_pipe; } ipa_wigig_ctx->rx_connected = true; IPA_WIGIG_DBG("exit\n"); return 0; Loading Loading @@ -641,8 +671,9 @@ static int ipa_wigig_clean_pipe_smmu_info(unsigned int idx) IPA_WIGIG_ERR("invalid index %d\n", idx); return -EINVAL; } kfree(ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base.sgl); kfree(ipa_wigig_ctx->pipes_smmu[idx].status_ring_base.sgl); sg_free_table(&ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base); sg_free_table(&ipa_wigig_ctx->pipes_smmu[idx].status_ring_base); memset(ipa_wigig_ctx->pipes_smmu + idx, 0, Loading @@ -653,11 +684,30 @@ static int ipa_wigig_clean_pipe_smmu_info(unsigned int idx) return 0; } static int ipa_wigig_clone_sg_table(struct sg_table *source, struct sg_table *dst) { struct scatterlist *next, *s, *sglist; int i, nents = source->nents; if (sg_alloc_table(dst, nents, GFP_KERNEL)) return -EINVAL; next = dst->sgl; sglist = source->sgl; for_each_sg(sglist, s, nents, i) { *next = *s; next = sg_next(next); } dst->nents = nents; dst->orig_nents = source->orig_nents; return 0; } static int ipa_wigig_store_pipe_smmu_info (struct ipa_wigig_pipe_setup_info_smmu *pipe_smmu, unsigned int idx) { unsigned int nents; struct scatterlist *sgl; int ret; IPA_WIGIG_DBG("\n"); Loading @@ -680,37 +730,21 @@ static int ipa_wigig_store_pipe_smmu_info pipe_smmu->status_ring_base_iova; /* copy sgt */ nents = pipe_smmu->desc_ring_base.nents; sgl = kmemdup(pipe_smmu->desc_ring_base.sgl, nents * sizeof(struct scatterlist), GFP_KERNEL); if (sgl == NULL) { ret = -ENOMEM; ret = ipa_wigig_clone_sg_table(&pipe_smmu->desc_ring_base, &ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base); if (ret) goto fail_desc; } ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base.sgl = sgl; ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base.nents = nents; ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base.orig_nents = pipe_smmu->desc_ring_base.orig_nents; nents = pipe_smmu->status_ring_base.nents; sgl = kmemdup(pipe_smmu->status_ring_base.sgl, nents * sizeof(struct scatterlist), GFP_KERNEL); if (sgl == NULL) { ret = -ENOMEM; ret = ipa_wigig_clone_sg_table(&pipe_smmu->status_ring_base, &ipa_wigig_ctx->pipes_smmu[idx].status_ring_base); if (ret) goto fail_stat; } ipa_wigig_ctx->pipes_smmu[idx].status_ring_base.sgl = sgl; ipa_wigig_ctx->pipes_smmu[idx].status_ring_base.nents = nents; ipa_wigig_ctx->pipes_smmu[idx].status_ring_base.orig_nents = pipe_smmu->status_ring_base.orig_nents; IPA_WIGIG_DBG("exit\n"); return 0; fail_stat: kfree(ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base.sgl); sg_free_table(&ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base); memset(&ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base, 0, sizeof(ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base)); fail_desc: Loading @@ -734,7 +768,7 @@ static void ipa_wigig_clean_rx_buff_smmu_info(void) { IPA_WIGIG_DBG("clearing rx buff smmu info\n"); kfree(ipa_wigig_ctx->rx_buff_smmu.data_buffer_base.sgl); sg_free_table(&ipa_wigig_ctx->rx_buff_smmu.data_buffer_base); memset(&ipa_wigig_ctx->rx_buff_smmu, 0, sizeof(ipa_wigig_ctx->rx_buff_smmu)); Loading @@ -748,22 +782,11 @@ static void ipa_wigig_clean_rx_buff_smmu_info(void) static int ipa_wigig_store_rx_buff_smmu_info( struct ipa_wigig_rx_pipe_data_buffer_info_smmu *dbuff_smmu) { unsigned int nents; struct scatterlist *sgl; IPA_WIGIG_DBG("\n"); if (ipa_wigig_clone_sg_table(&dbuff_smmu->data_buffer_base, &ipa_wigig_ctx->rx_buff_smmu.data_buffer_base)) return -EINVAL; nents = dbuff_smmu->data_buffer_base.nents; sgl = kmemdup(dbuff_smmu->data_buffer_base.sgl, nents * sizeof(struct scatterlist), GFP_KERNEL); if (sgl == NULL) return -ENOMEM; ipa_wigig_ctx->rx_buff_smmu.data_buffer_base.sgl = sgl; ipa_wigig_ctx->rx_buff_smmu.data_buffer_base.nents = nents; ipa_wigig_ctx->rx_buff_smmu.data_buffer_base.orig_nents = dbuff_smmu->data_buffer_base.orig_nents; ipa_wigig_ctx->rx_buff_smmu.data_buffer_base_iova = dbuff_smmu->data_buffer_base_iova; ipa_wigig_ctx->rx_buff_smmu.data_buffer_size = Loading @@ -790,8 +813,6 @@ static int ipa_wigig_store_tx_buff_smmu_info( struct ipa_wigig_tx_pipe_data_buffer_info_smmu *dbuff_smmu, unsigned int idx) { unsigned int nents; struct scatterlist *sgl; int result, i; struct ipa_wigig_tx_pipe_data_buffer_info_smmu *tx_buff_smmu; Loading Loading @@ -819,21 +840,12 @@ static int ipa_wigig_store_tx_buff_smmu_info( } for (i = 0; i < dbuff_smmu->num_buffers; i++) { nents = dbuff_smmu->data_buffer_base[i].nents; sgl = kmemdup(dbuff_smmu->data_buffer_base[i].sgl, nents * sizeof(struct scatterlist), GFP_KERNEL); if (sgl == NULL) { result = -ENOMEM; goto fail_sgl; } result = ipa_wigig_clone_sg_table( dbuff_smmu->data_buffer_base + i, tx_buff_smmu->data_buffer_base + i); if (result) goto fail_sg_clone; tx_buff_smmu->data_buffer_base[i].sgl = sgl; tx_buff_smmu->data_buffer_base[i].nents = nents; tx_buff_smmu->data_buffer_base[i].orig_nents = dbuff_smmu->data_buffer_base[i].orig_nents; tx_buff_smmu->data_buffer_base_iova[i] = dbuff_smmu->data_buffer_base_iova[i]; } Loading @@ -844,11 +856,10 @@ static int ipa_wigig_store_tx_buff_smmu_info( IPA_WIGIG_DBG("exit\n"); return 0; fail_sgl: fail_sg_clone: i--; for (; i >= 0; i--) kfree(tx_buff_smmu->data_buffer_base[i].sgl); sg_free_table(tx_buff_smmu->data_buffer_base + i); kfree(tx_buff_smmu->data_buffer_base_iova); tx_buff_smmu->data_buffer_base_iova = NULL; fail_iova: Loading Loading @@ -877,7 +888,7 @@ static int ipa_wigig_clean_tx_buff_smmu_info(unsigned int idx) } for (i = 0; i < dbuff_smmu->num_buffers; i++) kfree(dbuff_smmu->data_buffer_base[i].sgl); sg_free_table(dbuff_smmu->data_buffer_base + i); kfree(dbuff_smmu->data_buffer_base); dbuff_smmu->data_buffer_base = NULL; Loading Loading @@ -919,9 +930,11 @@ static int ipa_wigig_store_rx_smmu_info if (ret) return ret; if (!ipa_wigig_ctx->shared_cb) { ret = ipa_wigig_store_rx_buff_smmu_info(&in->dbuff_smmu); if (ret) goto fail_buff; } IPA_WIGIG_DBG("exit\n"); Loading @@ -948,9 +961,12 @@ static int ipa_wigig_store_client_smmu_info if (ret) return ret; ret = ipa_wigig_store_tx_buff_smmu_info(&in->dbuff_smmu, idx - 1); if (!ipa_wigig_ctx->shared_cb) { ret = ipa_wigig_store_tx_buff_smmu_info( &in->dbuff_smmu, idx - 1); if (ret) goto fail_buff; } IPA_WIGIG_DBG("exit\n"); Loading Loading @@ -1009,6 +1025,7 @@ static int ipa_wigig_clean_smmu_info(enum ipa_client_type client) ret = ipa_wigig_clean_pipe_smmu_info(IPA_WIGIG_RX_PIPE_IDX); if (ret) return ret; if (!ipa_wigig_ctx->shared_cb) ipa_wigig_clean_rx_buff_smmu_info(); } else { unsigned int idx; Loading @@ -1021,6 +1038,7 @@ static int ipa_wigig_clean_smmu_info(enum ipa_client_type client) if (ret) return ret; if (!ipa_wigig_ctx->shared_cb) { ret = ipa_wigig_clean_tx_buff_smmu_info(idx - 1); if (ret) { IPA_WIGIG_ERR( Loading @@ -1030,6 +1048,7 @@ static int ipa_wigig_clean_smmu_info(enum ipa_client_type client) return ret; } } } return 0; } Loading @@ -1052,17 +1071,20 @@ int ipa_wigig_conn_rx_pipe_smmu( return -EPERM; } if (!ipa_wigig_is_smmu_enabled()) { IPA_WIGIG_ERR("IPA SMMU is disabled, wrong API used\n"); return -EFAULT; } ret = ipa_uc_state_check(); if (ret) { IPA_WIGIG_ERR("uC not ready\n"); return ret; } if (ipa_wigig_init_smmu_params()) return -EINVAL; if (!ipa_wigig_ctx->smmu_en) { IPA_WIGIG_ERR("IPA SMMU is disabled, wrong API used\n"); return -EFAULT; } memset(&pm_params, 0, sizeof(pm_params)); pm_params.name = "wigig"; pm_params.callback = ipa_wigig_pm_cb; Loading Loading @@ -1098,6 +1120,8 @@ int ipa_wigig_conn_rx_pipe_smmu( goto fail_smmu_store; } ipa_wigig_ctx->rx_connected = true; IPA_WIGIG_DBG("exit\n"); return 0; Loading Loading @@ -1190,7 +1214,14 @@ int ipa_wigig_conn_client(struct ipa_wigig_conn_tx_in_params *in, return -EPERM; } if (ipa_wigig_is_smmu_enabled()) { if (!ipa_wigig_ctx->rx_connected) { IPA_WIGIG_ERR( "must connect rx pipe before connecting any client\n" ); return -EINVAL; } if (ipa_wigig_ctx->smmu_en) { IPA_WIGIG_ERR("IPA SMMU is enabled, wrong API used\n"); return -EFAULT; } Loading Loading @@ -1249,7 +1280,14 @@ int ipa_wigig_conn_client_smmu( return -EPERM; } if (!ipa_wigig_is_smmu_enabled()) { if (!ipa_wigig_ctx->rx_connected) { IPA_WIGIG_ERR( "must connect rx pipe before connecting any client\n" ); return -EINVAL; } if (!ipa_wigig_ctx->smmu_en) { IPA_WIGIG_ERR("IPA SMMU is disabled, wrong API used\n"); return -EFAULT; } Loading Loading @@ -1400,6 +1438,8 @@ int ipa_wigig_disconn_pipe(enum ipa_client_type client) IPA_WIGIG_ERR("failed dereg pm\n"); WARN_ON(1); } ipa_wigig_ctx->rx_connected = false; } else { /* * wigig clients are disconnected with legacy message since Loading drivers/platform/msm/ipa/ipa_v3/ipa.c +108 −7 Original line number Diff line number Diff line Loading @@ -381,11 +381,22 @@ struct iommu_domain *ipa3_get_wlan_smmu_domain(void) return NULL; } struct iommu_domain *ipa3_get_11ad_smmu_domain(void) { if (smmu_cb[IPA_SMMU_CB_11AD].valid) return smmu_cb[IPA_SMMU_CB_11AD].iommu; IPAERR("CB not valid\n"); return NULL; } struct iommu_domain *ipa3_get_smmu_domain_by_type(enum ipa_smmu_cb_type cb_type) { if (cb_type == IPA_SMMU_CB_WLAN && smmu_cb[IPA_SMMU_CB_WLAN].valid) return smmu_cb[IPA_SMMU_CB_WLAN].iommu; if ((cb_type == IPA_SMMU_CB_WLAN || cb_type == IPA_SMMU_CB_11AD) && smmu_cb[cb_type].valid) return smmu_cb[cb_type].iommu; if (smmu_cb[cb_type].valid) return smmu_cb[cb_type].mapping->domain; Loading Loading @@ -6690,6 +6701,54 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) return 0; } static int ipa_smmu_11ad_cb_probe(struct device *dev) { int ret; int s1_bypass = 0; struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_11AD); IPADBG("11ad CB probe: sub dev=%pK\n", dev); if (!smmu_info.present[IPA_SMMU_CB_11AD]) { IPAERR("11ad SMMU is disabled"); return 0; } cb->dev = dev; cb->iommu = iommu_get_domain_for_dev(dev); if (!cb->iommu) { IPAERR("could not get iommu domain\n"); /* assume this failure is because iommu driver is not ready */ return -EPROBE_DEFER; } cb->valid = true; ret = iommu_domain_get_attr( cb->iommu, DOMAIN_ATTR_S1_BYPASS, &s1_bypass); if (ret) { IPAERR("can't get DOMAIN_ATTR_S1_BYPASS\n"); return ret; } if (s1_bypass) { IPADBG("11AD SMMU S1 BYPASS\n"); smmu_info.s1_bypass_arr[IPA_SMMU_CB_11AD] = true; ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD] = true; } else { IPADBG("11AD SMMU S1 enabled\n"); smmu_info.s1_bypass_arr[IPA_SMMU_CB_11AD] = false; ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD] = false; } if (of_property_read_bool(dev->of_node, "qcom,shared-cb")) { IPADBG("using shared CB\n"); cb->shared = true; } return 0; IPADBG("exit\n"); } static int ipa_smmu_cb_probe(struct device *dev, enum ipa_smmu_cb_type cb_type) { switch (cb_type) { Loading @@ -6699,6 +6758,8 @@ static int ipa_smmu_cb_probe(struct device *dev, enum ipa_smmu_cb_type cb_type) return ipa_smmu_wlan_cb_probe(dev); case IPA_SMMU_CB_UC: return ipa_smmu_uc_cb_probe(dev); case IPA_SMMU_CB_11AD: return ipa_smmu_11ad_cb_probe(dev); case IPA_SMMU_CB_MAX: IPAERR("Invalid cb_type\n"); } Loading Loading @@ -6818,6 +6879,14 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p, return 0; } if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-11ad-cb")) { cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_11AD); cb->dev = dev; smmu_info.present[IPA_SMMU_CB_11AD] = true; return 0; } if (of_device_is_compatible(dev->of_node, "qcom,smp2p-map-ipa-1-out")) return ipa3_smp2p_probe(dev); Loading Loading @@ -7037,8 +7106,9 @@ int ipa3_iommu_map(struct iommu_domain *domain, ipa_assert(); return -EFAULT; } } else if (domain == ipa3_get_wlan_smmu_domain()) { /* wlan is one time map */ } else if (domain == ipa3_get_wlan_smmu_domain() || domain == ipa3_get_11ad_smmu_domain()) { /* wlan\11ad is one time map */ } else if (domain == ipa3_get_uc_smmu_domain()) { if (iova >= uc_cb->va_start && iova < uc_cb->va_end) { IPAERR("iommu uC overlap addr 0x%lx\n", iova); Loading Loading @@ -7072,17 +7142,48 @@ int ipa3_get_smmu_params(struct ipa_smmu_in_params *in, return -EINVAL; } out->shared_cb = false; switch (in->smmu_client) { case IPA_SMMU_WLAN_CLIENT: if (ipa3_ctx->ipa_wdi3_over_gsi) is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] | !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN]); else is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] | !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN]); break; case IPA_SMMU_WIGIG_CLIENT: is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]); if (is_smmu_enable) { if (ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]) { IPAERR("11AD SMMU Discrepancy (%d %d %d)\n", ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC], ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP], ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD]); WARN_ON(1); return -EINVAL; } } else { if (!ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] || !ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD] || !ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]) { IPAERR("11AD SMMU Discrepancy (%d %d %d)\n", ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC], ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP], ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD]); WARN_ON(1); return -EINVAL; } } out->shared_cb = (ipa3_get_smmu_ctx(IPA_SMMU_CB_11AD))->shared; break; case IPA_SMMU_AP_CLIENT: is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]); Loading drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +2 −2 Original line number Diff line number Diff line Loading @@ -447,7 +447,7 @@ int ipa3_send(struct ipa3_sys_context *sys, result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, num_desc, gsi_xfer, true); if (result != GSI_STATUS_SUCCESS) { IPAERR("GSI xfer failed.\n"); IPAERR_RL("GSI xfer failed.\n"); result = -EFAULT; goto failure; } Loading Loading @@ -1722,7 +1722,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, } if (ipa3_send(sys, num_frags + data_idx, desc, true)) { IPAERR("fail to send skb %pK num_frags %u SWP\n", IPAERR_RL("fail to send skb %pK num_frags %u SWP\n", skb, num_frags); goto fail_send; } Loading drivers/platform/msm/ipa/ipa_v3/ipa_i.h +2 −0 Original line number Diff line number Diff line Loading @@ -451,6 +451,7 @@ struct ipa_smmu_cb_ctx { u32 va_start; u32 va_size; u32 va_end; bool shared; }; /** Loading Loading @@ -1428,6 +1429,7 @@ enum ipa_smmu_cb_type { IPA_SMMU_CB_AP, IPA_SMMU_CB_WLAN, IPA_SMMU_CB_UC, IPA_SMMU_CB_11AD, IPA_SMMU_CB_MAX }; Loading Loading
drivers/platform/msm/ipa/ipa_api.c +1 −0 Original line number Diff line number Diff line Loading @@ -2944,6 +2944,7 @@ static const struct of_device_id ipa_plat_drv_match[] = { { .compatible = "qcom,ipa-smmu-ap-cb", }, { .compatible = "qcom,ipa-smmu-wlan-cb", }, { .compatible = "qcom,ipa-smmu-uc-cb", }, { .compatible = "qcom,ipa-smmu-11ad-cb", }, { .compatible = "qcom,smp2p-map-ipa-1-in", }, { .compatible = "qcom,smp2p-map-ipa-1-out", }, {} Loading
drivers/platform/msm/ipa/ipa_clients/ipa_wigig.c +130 −90 Original line number Diff line number Diff line Loading @@ -63,6 +63,9 @@ struct ipa_wigig_context { struct ipa_wigig_tx_pipe_data_buffer_info_smmu tx_buff_smmu[IPA_WIGIG_TX_PIPE_NUM]; char clients_mac[IPA_WIGIG_TX_PIPE_NUM][IPA_MAC_ADDR_SIZE]; bool smmu_en; bool shared_cb; bool rx_connected; }; static struct ipa_wigig_context *ipa_wigig_ctx; Loading Loading @@ -155,8 +158,7 @@ bool ipa_wigig_is_smmu_enabled(void) IPA_WIGIG_DBG("\n"); in.smmu_client = IPA_SMMU_WLAN_CLIENT; in.smmu_client = IPA_SMMU_WIGIG_CLIENT; ipa_get_smmu_params(&in, &out); IPA_WIGIG_DBG("exit (%d)\n", out.smmu_enable); Loading @@ -165,6 +167,29 @@ bool ipa_wigig_is_smmu_enabled(void) } EXPORT_SYMBOL(ipa_wigig_is_smmu_enabled); static int ipa_wigig_init_smmu_params(void) { struct ipa_smmu_in_params in; struct ipa_smmu_out_params out; int ret; IPA_WIGIG_DBG("\n"); in.smmu_client = IPA_SMMU_WIGIG_CLIENT; ret = ipa_get_smmu_params(&in, &out); if (ret) { IPA_WIGIG_ERR("couldn't get SMMU params %d\n", ret); return ret; } ipa_wigig_ctx->smmu_en = out.smmu_enable; ipa_wigig_ctx->shared_cb = out.shared_cb; IPA_WIGIG_DBG("SMMU (%s), 11ad CB (%s)\n", out.smmu_enable ? "enabled" : "disabled", out.shared_cb ? "shared" : "not shared"); return 0; } static int ipa_wigig_commit_partial_hdr( struct ipa_ioc_add_hdr *hdr, const char *netdev_name, Loading Loading @@ -550,17 +575,20 @@ int ipa_wigig_conn_rx_pipe(struct ipa_wigig_conn_rx_in_params *in, return -EPERM; } if (ipa_wigig_is_smmu_enabled()) { IPA_WIGIG_ERR("IPA SMMU is enabled, wrong API used\n"); return -EFAULT; } ret = ipa_uc_state_check(); if (ret) { IPA_WIGIG_ERR("uC not ready\n"); return ret; } if (ipa_wigig_init_smmu_params()) return -EINVAL; if (ipa_wigig_ctx->smmu_en) { IPA_WIGIG_ERR("IPA SMMU is enabled, wrong API used\n"); return -EFAULT; } memset(&pm_params, 0, sizeof(pm_params)); pm_params.name = "wigig"; pm_params.callback = ipa_wigig_pm_cb; Loading Loading @@ -591,6 +619,8 @@ int ipa_wigig_conn_rx_pipe(struct ipa_wigig_conn_rx_in_params *in, goto fail_connect_pipe; } ipa_wigig_ctx->rx_connected = true; IPA_WIGIG_DBG("exit\n"); return 0; Loading Loading @@ -641,8 +671,9 @@ static int ipa_wigig_clean_pipe_smmu_info(unsigned int idx) IPA_WIGIG_ERR("invalid index %d\n", idx); return -EINVAL; } kfree(ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base.sgl); kfree(ipa_wigig_ctx->pipes_smmu[idx].status_ring_base.sgl); sg_free_table(&ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base); sg_free_table(&ipa_wigig_ctx->pipes_smmu[idx].status_ring_base); memset(ipa_wigig_ctx->pipes_smmu + idx, 0, Loading @@ -653,11 +684,30 @@ static int ipa_wigig_clean_pipe_smmu_info(unsigned int idx) return 0; } static int ipa_wigig_clone_sg_table(struct sg_table *source, struct sg_table *dst) { struct scatterlist *next, *s, *sglist; int i, nents = source->nents; if (sg_alloc_table(dst, nents, GFP_KERNEL)) return -EINVAL; next = dst->sgl; sglist = source->sgl; for_each_sg(sglist, s, nents, i) { *next = *s; next = sg_next(next); } dst->nents = nents; dst->orig_nents = source->orig_nents; return 0; } static int ipa_wigig_store_pipe_smmu_info (struct ipa_wigig_pipe_setup_info_smmu *pipe_smmu, unsigned int idx) { unsigned int nents; struct scatterlist *sgl; int ret; IPA_WIGIG_DBG("\n"); Loading @@ -680,37 +730,21 @@ static int ipa_wigig_store_pipe_smmu_info pipe_smmu->status_ring_base_iova; /* copy sgt */ nents = pipe_smmu->desc_ring_base.nents; sgl = kmemdup(pipe_smmu->desc_ring_base.sgl, nents * sizeof(struct scatterlist), GFP_KERNEL); if (sgl == NULL) { ret = -ENOMEM; ret = ipa_wigig_clone_sg_table(&pipe_smmu->desc_ring_base, &ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base); if (ret) goto fail_desc; } ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base.sgl = sgl; ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base.nents = nents; ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base.orig_nents = pipe_smmu->desc_ring_base.orig_nents; nents = pipe_smmu->status_ring_base.nents; sgl = kmemdup(pipe_smmu->status_ring_base.sgl, nents * sizeof(struct scatterlist), GFP_KERNEL); if (sgl == NULL) { ret = -ENOMEM; ret = ipa_wigig_clone_sg_table(&pipe_smmu->status_ring_base, &ipa_wigig_ctx->pipes_smmu[idx].status_ring_base); if (ret) goto fail_stat; } ipa_wigig_ctx->pipes_smmu[idx].status_ring_base.sgl = sgl; ipa_wigig_ctx->pipes_smmu[idx].status_ring_base.nents = nents; ipa_wigig_ctx->pipes_smmu[idx].status_ring_base.orig_nents = pipe_smmu->status_ring_base.orig_nents; IPA_WIGIG_DBG("exit\n"); return 0; fail_stat: kfree(ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base.sgl); sg_free_table(&ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base); memset(&ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base, 0, sizeof(ipa_wigig_ctx->pipes_smmu[idx].desc_ring_base)); fail_desc: Loading @@ -734,7 +768,7 @@ static void ipa_wigig_clean_rx_buff_smmu_info(void) { IPA_WIGIG_DBG("clearing rx buff smmu info\n"); kfree(ipa_wigig_ctx->rx_buff_smmu.data_buffer_base.sgl); sg_free_table(&ipa_wigig_ctx->rx_buff_smmu.data_buffer_base); memset(&ipa_wigig_ctx->rx_buff_smmu, 0, sizeof(ipa_wigig_ctx->rx_buff_smmu)); Loading @@ -748,22 +782,11 @@ static void ipa_wigig_clean_rx_buff_smmu_info(void) static int ipa_wigig_store_rx_buff_smmu_info( struct ipa_wigig_rx_pipe_data_buffer_info_smmu *dbuff_smmu) { unsigned int nents; struct scatterlist *sgl; IPA_WIGIG_DBG("\n"); if (ipa_wigig_clone_sg_table(&dbuff_smmu->data_buffer_base, &ipa_wigig_ctx->rx_buff_smmu.data_buffer_base)) return -EINVAL; nents = dbuff_smmu->data_buffer_base.nents; sgl = kmemdup(dbuff_smmu->data_buffer_base.sgl, nents * sizeof(struct scatterlist), GFP_KERNEL); if (sgl == NULL) return -ENOMEM; ipa_wigig_ctx->rx_buff_smmu.data_buffer_base.sgl = sgl; ipa_wigig_ctx->rx_buff_smmu.data_buffer_base.nents = nents; ipa_wigig_ctx->rx_buff_smmu.data_buffer_base.orig_nents = dbuff_smmu->data_buffer_base.orig_nents; ipa_wigig_ctx->rx_buff_smmu.data_buffer_base_iova = dbuff_smmu->data_buffer_base_iova; ipa_wigig_ctx->rx_buff_smmu.data_buffer_size = Loading @@ -790,8 +813,6 @@ static int ipa_wigig_store_tx_buff_smmu_info( struct ipa_wigig_tx_pipe_data_buffer_info_smmu *dbuff_smmu, unsigned int idx) { unsigned int nents; struct scatterlist *sgl; int result, i; struct ipa_wigig_tx_pipe_data_buffer_info_smmu *tx_buff_smmu; Loading Loading @@ -819,21 +840,12 @@ static int ipa_wigig_store_tx_buff_smmu_info( } for (i = 0; i < dbuff_smmu->num_buffers; i++) { nents = dbuff_smmu->data_buffer_base[i].nents; sgl = kmemdup(dbuff_smmu->data_buffer_base[i].sgl, nents * sizeof(struct scatterlist), GFP_KERNEL); if (sgl == NULL) { result = -ENOMEM; goto fail_sgl; } result = ipa_wigig_clone_sg_table( dbuff_smmu->data_buffer_base + i, tx_buff_smmu->data_buffer_base + i); if (result) goto fail_sg_clone; tx_buff_smmu->data_buffer_base[i].sgl = sgl; tx_buff_smmu->data_buffer_base[i].nents = nents; tx_buff_smmu->data_buffer_base[i].orig_nents = dbuff_smmu->data_buffer_base[i].orig_nents; tx_buff_smmu->data_buffer_base_iova[i] = dbuff_smmu->data_buffer_base_iova[i]; } Loading @@ -844,11 +856,10 @@ static int ipa_wigig_store_tx_buff_smmu_info( IPA_WIGIG_DBG("exit\n"); return 0; fail_sgl: fail_sg_clone: i--; for (; i >= 0; i--) kfree(tx_buff_smmu->data_buffer_base[i].sgl); sg_free_table(tx_buff_smmu->data_buffer_base + i); kfree(tx_buff_smmu->data_buffer_base_iova); tx_buff_smmu->data_buffer_base_iova = NULL; fail_iova: Loading Loading @@ -877,7 +888,7 @@ static int ipa_wigig_clean_tx_buff_smmu_info(unsigned int idx) } for (i = 0; i < dbuff_smmu->num_buffers; i++) kfree(dbuff_smmu->data_buffer_base[i].sgl); sg_free_table(dbuff_smmu->data_buffer_base + i); kfree(dbuff_smmu->data_buffer_base); dbuff_smmu->data_buffer_base = NULL; Loading Loading @@ -919,9 +930,11 @@ static int ipa_wigig_store_rx_smmu_info if (ret) return ret; if (!ipa_wigig_ctx->shared_cb) { ret = ipa_wigig_store_rx_buff_smmu_info(&in->dbuff_smmu); if (ret) goto fail_buff; } IPA_WIGIG_DBG("exit\n"); Loading @@ -948,9 +961,12 @@ static int ipa_wigig_store_client_smmu_info if (ret) return ret; ret = ipa_wigig_store_tx_buff_smmu_info(&in->dbuff_smmu, idx - 1); if (!ipa_wigig_ctx->shared_cb) { ret = ipa_wigig_store_tx_buff_smmu_info( &in->dbuff_smmu, idx - 1); if (ret) goto fail_buff; } IPA_WIGIG_DBG("exit\n"); Loading Loading @@ -1009,6 +1025,7 @@ static int ipa_wigig_clean_smmu_info(enum ipa_client_type client) ret = ipa_wigig_clean_pipe_smmu_info(IPA_WIGIG_RX_PIPE_IDX); if (ret) return ret; if (!ipa_wigig_ctx->shared_cb) ipa_wigig_clean_rx_buff_smmu_info(); } else { unsigned int idx; Loading @@ -1021,6 +1038,7 @@ static int ipa_wigig_clean_smmu_info(enum ipa_client_type client) if (ret) return ret; if (!ipa_wigig_ctx->shared_cb) { ret = ipa_wigig_clean_tx_buff_smmu_info(idx - 1); if (ret) { IPA_WIGIG_ERR( Loading @@ -1030,6 +1048,7 @@ static int ipa_wigig_clean_smmu_info(enum ipa_client_type client) return ret; } } } return 0; } Loading @@ -1052,17 +1071,20 @@ int ipa_wigig_conn_rx_pipe_smmu( return -EPERM; } if (!ipa_wigig_is_smmu_enabled()) { IPA_WIGIG_ERR("IPA SMMU is disabled, wrong API used\n"); return -EFAULT; } ret = ipa_uc_state_check(); if (ret) { IPA_WIGIG_ERR("uC not ready\n"); return ret; } if (ipa_wigig_init_smmu_params()) return -EINVAL; if (!ipa_wigig_ctx->smmu_en) { IPA_WIGIG_ERR("IPA SMMU is disabled, wrong API used\n"); return -EFAULT; } memset(&pm_params, 0, sizeof(pm_params)); pm_params.name = "wigig"; pm_params.callback = ipa_wigig_pm_cb; Loading Loading @@ -1098,6 +1120,8 @@ int ipa_wigig_conn_rx_pipe_smmu( goto fail_smmu_store; } ipa_wigig_ctx->rx_connected = true; IPA_WIGIG_DBG("exit\n"); return 0; Loading Loading @@ -1190,7 +1214,14 @@ int ipa_wigig_conn_client(struct ipa_wigig_conn_tx_in_params *in, return -EPERM; } if (ipa_wigig_is_smmu_enabled()) { if (!ipa_wigig_ctx->rx_connected) { IPA_WIGIG_ERR( "must connect rx pipe before connecting any client\n" ); return -EINVAL; } if (ipa_wigig_ctx->smmu_en) { IPA_WIGIG_ERR("IPA SMMU is enabled, wrong API used\n"); return -EFAULT; } Loading Loading @@ -1249,7 +1280,14 @@ int ipa_wigig_conn_client_smmu( return -EPERM; } if (!ipa_wigig_is_smmu_enabled()) { if (!ipa_wigig_ctx->rx_connected) { IPA_WIGIG_ERR( "must connect rx pipe before connecting any client\n" ); return -EINVAL; } if (!ipa_wigig_ctx->smmu_en) { IPA_WIGIG_ERR("IPA SMMU is disabled, wrong API used\n"); return -EFAULT; } Loading Loading @@ -1400,6 +1438,8 @@ int ipa_wigig_disconn_pipe(enum ipa_client_type client) IPA_WIGIG_ERR("failed dereg pm\n"); WARN_ON(1); } ipa_wigig_ctx->rx_connected = false; } else { /* * wigig clients are disconnected with legacy message since Loading
drivers/platform/msm/ipa/ipa_v3/ipa.c +108 −7 Original line number Diff line number Diff line Loading @@ -381,11 +381,22 @@ struct iommu_domain *ipa3_get_wlan_smmu_domain(void) return NULL; } struct iommu_domain *ipa3_get_11ad_smmu_domain(void) { if (smmu_cb[IPA_SMMU_CB_11AD].valid) return smmu_cb[IPA_SMMU_CB_11AD].iommu; IPAERR("CB not valid\n"); return NULL; } struct iommu_domain *ipa3_get_smmu_domain_by_type(enum ipa_smmu_cb_type cb_type) { if (cb_type == IPA_SMMU_CB_WLAN && smmu_cb[IPA_SMMU_CB_WLAN].valid) return smmu_cb[IPA_SMMU_CB_WLAN].iommu; if ((cb_type == IPA_SMMU_CB_WLAN || cb_type == IPA_SMMU_CB_11AD) && smmu_cb[cb_type].valid) return smmu_cb[cb_type].iommu; if (smmu_cb[cb_type].valid) return smmu_cb[cb_type].mapping->domain; Loading Loading @@ -6690,6 +6701,54 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) return 0; } static int ipa_smmu_11ad_cb_probe(struct device *dev) { int ret; int s1_bypass = 0; struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_11AD); IPADBG("11ad CB probe: sub dev=%pK\n", dev); if (!smmu_info.present[IPA_SMMU_CB_11AD]) { IPAERR("11ad SMMU is disabled"); return 0; } cb->dev = dev; cb->iommu = iommu_get_domain_for_dev(dev); if (!cb->iommu) { IPAERR("could not get iommu domain\n"); /* assume this failure is because iommu driver is not ready */ return -EPROBE_DEFER; } cb->valid = true; ret = iommu_domain_get_attr( cb->iommu, DOMAIN_ATTR_S1_BYPASS, &s1_bypass); if (ret) { IPAERR("can't get DOMAIN_ATTR_S1_BYPASS\n"); return ret; } if (s1_bypass) { IPADBG("11AD SMMU S1 BYPASS\n"); smmu_info.s1_bypass_arr[IPA_SMMU_CB_11AD] = true; ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD] = true; } else { IPADBG("11AD SMMU S1 enabled\n"); smmu_info.s1_bypass_arr[IPA_SMMU_CB_11AD] = false; ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD] = false; } if (of_property_read_bool(dev->of_node, "qcom,shared-cb")) { IPADBG("using shared CB\n"); cb->shared = true; } return 0; IPADBG("exit\n"); } static int ipa_smmu_cb_probe(struct device *dev, enum ipa_smmu_cb_type cb_type) { switch (cb_type) { Loading @@ -6699,6 +6758,8 @@ static int ipa_smmu_cb_probe(struct device *dev, enum ipa_smmu_cb_type cb_type) return ipa_smmu_wlan_cb_probe(dev); case IPA_SMMU_CB_UC: return ipa_smmu_uc_cb_probe(dev); case IPA_SMMU_CB_11AD: return ipa_smmu_11ad_cb_probe(dev); case IPA_SMMU_CB_MAX: IPAERR("Invalid cb_type\n"); } Loading Loading @@ -6818,6 +6879,14 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p, return 0; } if (of_device_is_compatible(dev->of_node, "qcom,ipa-smmu-11ad-cb")) { cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_11AD); cb->dev = dev; smmu_info.present[IPA_SMMU_CB_11AD] = true; return 0; } if (of_device_is_compatible(dev->of_node, "qcom,smp2p-map-ipa-1-out")) return ipa3_smp2p_probe(dev); Loading Loading @@ -7037,8 +7106,9 @@ int ipa3_iommu_map(struct iommu_domain *domain, ipa_assert(); return -EFAULT; } } else if (domain == ipa3_get_wlan_smmu_domain()) { /* wlan is one time map */ } else if (domain == ipa3_get_wlan_smmu_domain() || domain == ipa3_get_11ad_smmu_domain()) { /* wlan\11ad is one time map */ } else if (domain == ipa3_get_uc_smmu_domain()) { if (iova >= uc_cb->va_start && iova < uc_cb->va_end) { IPAERR("iommu uC overlap addr 0x%lx\n", iova); Loading Loading @@ -7072,17 +7142,48 @@ int ipa3_get_smmu_params(struct ipa_smmu_in_params *in, return -EINVAL; } out->shared_cb = false; switch (in->smmu_client) { case IPA_SMMU_WLAN_CLIENT: if (ipa3_ctx->ipa_wdi3_over_gsi) is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] | !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN]); else is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] | !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_WLAN]); break; case IPA_SMMU_WIGIG_CLIENT: is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]); if (is_smmu_enable) { if (ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD] || ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]) { IPAERR("11AD SMMU Discrepancy (%d %d %d)\n", ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC], ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP], ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD]); WARN_ON(1); return -EINVAL; } } else { if (!ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC] || !ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD] || !ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]) { IPAERR("11AD SMMU Discrepancy (%d %d %d)\n", ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_UC], ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP], ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_11AD]); WARN_ON(1); return -EINVAL; } } out->shared_cb = (ipa3_get_smmu_ctx(IPA_SMMU_CB_11AD))->shared; break; case IPA_SMMU_AP_CLIENT: is_smmu_enable = !(ipa3_ctx->s1_bypass_arr[IPA_SMMU_CB_AP]); Loading
drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +2 −2 Original line number Diff line number Diff line Loading @@ -447,7 +447,7 @@ int ipa3_send(struct ipa3_sys_context *sys, result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, num_desc, gsi_xfer, true); if (result != GSI_STATUS_SUCCESS) { IPAERR("GSI xfer failed.\n"); IPAERR_RL("GSI xfer failed.\n"); result = -EFAULT; goto failure; } Loading Loading @@ -1722,7 +1722,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, } if (ipa3_send(sys, num_frags + data_idx, desc, true)) { IPAERR("fail to send skb %pK num_frags %u SWP\n", IPAERR_RL("fail to send skb %pK num_frags %u SWP\n", skb, num_frags); goto fail_send; } Loading
drivers/platform/msm/ipa/ipa_v3/ipa_i.h +2 −0 Original line number Diff line number Diff line Loading @@ -451,6 +451,7 @@ struct ipa_smmu_cb_ctx { u32 va_start; u32 va_size; u32 va_end; bool shared; }; /** Loading Loading @@ -1428,6 +1429,7 @@ enum ipa_smmu_cb_type { IPA_SMMU_CB_AP, IPA_SMMU_CB_WLAN, IPA_SMMU_CB_UC, IPA_SMMU_CB_11AD, IPA_SMMU_CB_MAX }; Loading