diff --git a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c index 8dfe1920c56b..0c319f951e5a 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c +++ b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c @@ -659,13 +659,21 @@ static void ecm_ipa_packet_receive_notify packet_len = skb->len; ECM_IPA_DEBUG("packet RX, len=%d\n", skb->len); + if (unlikely(ecm_ipa_ctx == NULL)) { + ECM_IPA_DEBUG("Private context is NULL. Drop SKB.\n"); + dev_kfree_skb_any(skb); + return; + } + if (unlikely(ecm_ipa_ctx->state != ECM_IPA_CONNECTED_AND_UP)) { ECM_IPA_DEBUG("Missing pipe connected and/or iface up\n"); + dev_kfree_skb_any(skb); return; } if (unlikely(evt != IPA_RECEIVE)) { ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n"); + dev_kfree_skb_any(skb); return; } diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c index 2a978706b250..b8794cedd293 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c @@ -467,6 +467,10 @@ static int ipa_uc_offload_conn_pipes_internal(struct ipa_uc_offload_conn_in_para return -EPERM; } + /*Store the connection info, required during disconnect pipe */ + memcpy(&offload_ctx->conn, &inp->u.ntn, + sizeof(struct ipa_ntn_conn_in_params)); + switch (offload_ctx->proto) { case IPA_UC_NTN: ret = ipa_uc_ntn_conn_pipes(&inp->u.ntn, &outp->u.ntn, diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c index c201aa342084..8b93ee9b0e35 100644 --- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c +++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c @@ -1135,6 +1135,12 @@ static void rndis_ipa_packet_receive_notify( ("packet Rx, len=%d\n", skb->len); + if (unlikely(rndis_ipa_ctx == NULL)) { + RNDIS_IPA_DEBUG("Private context is NULL. Drop SKB.\n"); + dev_kfree_skb_any(skb); + return; + } + if (unlikely(rndis_ipa_ctx->rx_dump_enable)) rndis_ipa_dump_skb(skb); @@ -1142,11 +1148,15 @@ static void rndis_ipa_packet_receive_notify( RNDIS_IPA_DEBUG("use connect()/up() before receive()\n"); RNDIS_IPA_DEBUG("packet dropped (length=%d)\n", skb->len); + rndis_ipa_ctx->rx_dropped++; + dev_kfree_skb_any(skb); return; } if (evt != IPA_RECEIVE) { RNDIS_IPA_ERROR_RL("a none IPA_RECEIVE event in driver RX\n"); + rndis_ipa_ctx->rx_dropped++; + dev_kfree_skb_any(skb); return; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 4ed805bf37e0..918a037392d5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -384,6 +384,8 @@ int ipa_smmu_store_sgt(struct sg_table **out_ch_ptr, struct sg_table *in_sgt_ptr) { unsigned int nents; + int i; + struct scatterlist *in_sg, *out_sg; if (in_sgt_ptr != NULL) { *out_ch_ptr = kzalloc(sizeof(struct sg_table), GFP_KERNEL); @@ -401,8 +403,12 @@ int ipa_smmu_store_sgt(struct sg_table **out_ch_ptr, return -ENOMEM; } - memcpy((*out_ch_ptr)->sgl, in_sgt_ptr->sgl, - nents*sizeof((*out_ch_ptr)->sgl)); + out_sg = (*out_ch_ptr)->sgl; + for_each_sg(in_sgt_ptr->sgl, in_sg, in_sgt_ptr->nents, i) { + memcpy(out_sg, in_sg, sizeof(struct scatterlist)); + out_sg++; + } + (*out_ch_ptr)->nents = nents; (*out_ch_ptr)->orig_nents = in_sgt_ptr->orig_nents; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 22d92a3e1c1d..df9f377adcac 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -420,14 +420,33 @@ int ipa3_smmu_map_peer_buff(u64 iova, u32 size, bool map, struct sg_table *sgt, } } } 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\n", iova); - return -EINVAL; + if (sgt != NULL) { + va = rounddown(iova, PAGE_SIZE); + len = 0; + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + len = PAGE_ALIGN(sg->offset + sg->length); + res = iommu_unmap(smmu_domain, va, + roundup(len, PAGE_SIZE)); + if (res != + roundup(len, PAGE_SIZE)) { + IPAERR("Fail to unmap iova=%llx\n", + iova); + return -EINVAL; + } + va += len; + count++; + } + } 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\n", iova); + return -EINVAL; + } } } IPADBG("Peer buff %s 0x%llx\n", map ? "map" : "unmap", iova); @@ -1523,6 +1542,12 @@ int ipa3_release_gsi_channel(u32 clnt_hdl) if (!ep->keep_ipa_awake) IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl)); + /* Set the disconnect in progress flag to avoid calling cb.*/ + spin_lock(&ipa3_ctx->disconnect_lock); + atomic_set(&ep->disconnect_in_progress, 1); + spin_unlock(&ipa3_ctx->disconnect_lock); + + gsi_res = gsi_dealloc_channel(ep->gsi_chan_hdl); if (gsi_res != GSI_STATUS_SUCCESS) { IPAERR("Error deallocating channel: %d\n", gsi_res); @@ -1541,7 +1566,9 @@ int ipa3_release_gsi_channel(u32 clnt_hdl) if (!ep->keep_ipa_awake) IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); + spin_lock(&ipa3_ctx->disconnect_lock); memset(&ipa3_ctx->ep[clnt_hdl], 0, sizeof(struct ipa3_ep_context)); + spin_unlock(&ipa3_ctx->disconnect_lock); IPADBG("exit\n"); return 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index dd341697d6ea..678fb5bc76bf 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1202,7 +1202,7 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) if (ipa3_assign_policy(sys_in, ep->sys)) { IPAERR("failed to sys ctx for client %d\n", sys_in->client); result = -ENOMEM; - goto fail_gen2; + goto fail_napi; } ep->valid = 1; @@ -1219,17 +1219,17 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) ep->sys->status_stat = kzalloc(sizeof(struct ipa3_status_stats), GFP_KERNEL); if (!ep->sys->status_stat) - goto fail_gen2; + goto fail_napi; } if (!ep->skip_ep_cfg) { if (ipa3_cfg_ep(ipa_ep_idx, &sys_in->ipa_ep_cfg)) { IPAERR("fail to configure EP.\n"); - goto fail_gen2; + goto fail_napi; } if (ipa3_cfg_ep_status(ipa_ep_idx, &ep->status)) { IPAERR("fail to configure status of EP.\n"); - goto fail_gen2; + goto fail_napi; } IPADBG("ep %d configuration successful\n", ipa_ep_idx); } else { @@ -1239,7 +1239,7 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) result = ipa_gsi_setup_channel(sys_in, ep); if (result) { IPAERR("Failed to setup GSI channel\n"); - goto fail_gen2; + goto fail_napi; } *clnt_hdl = ipa_ep_idx; @@ -1250,7 +1250,7 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) IPAERR("failed to alloc repl for client %d\n", sys_in->client); result = -ENOMEM; - goto fail_gen2; + goto fail_napi; } atomic_set(&ep->sys->repl->pending, 0); ep->sys->repl->capacity = ep->sys->rx_pool_sz + 1; @@ -1275,7 +1275,7 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) IPAERR("failed to alloc repl for client %d\n", sys_in->client); result = -ENOMEM; - goto fail_gen2; + goto fail_napi; } atomic_set(&ep->sys->page_recycle_repl->pending, 0); ep->sys->page_recycle_repl->capacity = @@ -1380,6 +1380,11 @@ fail_page_recycle_repl: ep->sys->page_recycle_repl->capacity = 0; kfree(ep->sys->page_recycle_repl); } +fail_napi: + /* Delete NAPI TX object. */ + if (ipa3_ctx->tx_napi_enable && + (IPA_CLIENT_IS_PROD(sys_in->client))) + netif_napi_del(&ep->sys->napi_tx); fail_gen2: ipa_pm_deregister(ep->sys->pm_hdl); fail_pm: @@ -3402,14 +3407,18 @@ void ipa3_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data) unsigned int src_pipe; u32 metadata; u8 ucp; + void (*client_notify)(void *client_priv, enum ipa_dp_evt_type evt, + unsigned long data); + void *client_priv; ipahal_pkt_status_parse_thin(rx_skb->data, &status); src_pipe = status.endp_src_idx; metadata = status.metadata; ucp = status.ucp; ep = &ipa3_ctx->ep[src_pipe]; - if (unlikely(src_pipe >= ipa3_ctx->ipa_num_pipes)) { - IPAERR_RL("drop pipe=%d\n", src_pipe); + if (unlikely(src_pipe >= ipa3_ctx->ipa_num_pipes) || + unlikely(atomic_read(&ep->disconnect_in_progress))) { + IPAERR("drop pipe=%d\n", src_pipe); dev_kfree_skb_any(rx_skb); return; } @@ -3431,12 +3440,19 @@ void ipa3_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data) metadata, *(u32 *)rx_skb->cb); IPADBG_LOW("ucp: %d\n", *(u8 *)(rx_skb->cb + 4)); + spin_lock(&ipa3_ctx->disconnect_lock); if (likely((!atomic_read(&ep->disconnect_in_progress)) && - ep->valid && ep->client_notify)) - ep->client_notify(ep->priv, IPA_RECEIVE, + ep->valid && ep->client_notify)) { + client_notify = ep->client_notify; + client_priv = ep->priv; + spin_unlock(&ipa3_ctx->disconnect_lock); + client_notify(client_priv, IPA_RECEIVE, (unsigned long)(rx_skb)); - else + } else { + spin_unlock(&ipa3_ctx->disconnect_lock); dev_kfree_skb_any(rx_skb); + } + } static void ipa3_recycle_rx_wrapper(struct ipa3_rx_pkt_wrapper *rx_pkt) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c index 3adf6e11b83d..85a26d32c888 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c @@ -259,7 +259,7 @@ static int ipa3_uc_send_ntn_setup_pipe_cmd( } static int ipa3_smmu_map_uc_ntn_pipes(struct ipa_ntn_setup_info *params, - bool map) + bool map, bool map_unmap_once) { struct iommu_domain *smmu_domain; int result; @@ -275,14 +275,16 @@ static int ipa3_smmu_map_uc_ntn_pipes(struct ipa_ntn_setup_info *params, return -EINVAL; } - result = ipa3_smmu_map_peer_reg(rounddown(params->ntn_reg_base_ptr_pa, - PAGE_SIZE), map, IPA_SMMU_CB_UC); - if (result) { - IPAERR("failed to %s uC regs %d\n", - map ? "map" : "unmap", result); - goto fail; + if (map_unmap_once) { + result = ipa3_smmu_map_peer_reg(rounddown( + params->ntn_reg_base_ptr_pa, PAGE_SIZE), + map, IPA_SMMU_CB_UC); + if (result) { + IPAERR("failed to %s uC regs %d\n", + map ? "map" : "unmap", result); + goto fail; + } } - if (params->smmu_enabled) { IPADBG("smmu is enabled on EMAC\n"); result = ipa3_smmu_map_peer_buff((u64)params->ring_base_iova, @@ -345,14 +347,13 @@ static int ipa3_smmu_map_uc_ntn_pipes(struct ipa_ntn_setup_info *params, IPAERR("Fail to map 0x%llx\n", iova); } else { result = iommu_unmap(smmu_domain, iova_p, size_p); - if (result != params->data_buff_size) + if (result != size_p) { IPAERR("Fail to unmap 0x%llx\n", iova); - } - if (result) { - if (params->smmu_enabled) - goto fail_map_data_buff_smmu_enabled; - else - goto fail_map_data_buff_smmu_disabled; + if (params->smmu_enabled) + goto fail_map_data_buff_smmu_enabled; + else + goto fail_map_data_buff_smmu_disabled; + } } } return 0; @@ -392,6 +393,7 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, int ipa_ep_idx_ul; int ipa_ep_idx_dl; int result = 0; + bool unmapped = false; if (in == NULL) { IPAERR("invalid input\n"); @@ -445,7 +447,7 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, goto fail; } - result = ipa3_smmu_map_uc_ntn_pipes(&in->ul, true); + result = ipa3_smmu_map_uc_ntn_pipes(&in->ul, true, true); if (result) { IPAERR("failed to map SMMU for UL %d\n", result); goto fail; @@ -484,7 +486,7 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, goto fail_disable_dp_ul; } - result = ipa3_smmu_map_uc_ntn_pipes(&in->dl, true); + result = ipa3_smmu_map_uc_ntn_pipes(&in->dl, true, false); if (result) { IPAERR("failed to map SMMU for DL %d\n", result); goto fail_disable_dp_ul; @@ -515,11 +517,12 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, fail_disable_dp_dl: ipa3_disable_data_path(ipa_ep_idx_dl); fail_smmu_unmap_dl: - ipa3_smmu_map_uc_ntn_pipes(&in->dl, false); + ipa3_smmu_map_uc_ntn_pipes(&in->dl, false, true); + unmapped = true; fail_disable_dp_ul: ipa3_disable_data_path(ipa_ep_idx_ul); fail_smmu_unmap_ul: - ipa3_smmu_map_uc_ntn_pipes(&in->ul, false); + ipa3_smmu_map_uc_ntn_pipes(&in->ul, false, !unmapped); fail: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return result; @@ -600,7 +603,7 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, } /* unmap the DL pipe */ - result = ipa3_smmu_map_uc_ntn_pipes(¶ms->dl, false); + result = ipa3_smmu_map_uc_ntn_pipes(¶ms->dl, false, false); if (result) { IPAERR("failed to unmap SMMU for DL %d\n", result); goto fail; @@ -621,7 +624,7 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, } /* unmap the UL pipe */ - result = ipa3_smmu_map_uc_ntn_pipes(¶ms->ul, false); + result = ipa3_smmu_map_uc_ntn_pipes(¶ms->ul, false, true); if (result) { IPAERR("failed to unmap SMMU for UL %d\n", result); goto fail; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index 1260c115afb1..6905fd163476 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -2636,23 +2636,25 @@ int ipa3_suspend_gsi_wdi_pipe(u32 clnt_hdl) } if (ep->valid) { IPADBG("suspended pipe %d\n", ipa_ep_idx); - source_pipe_bitmask = 1 << - ipa3_get_ep_mapping(ep->client); - res = ipa3_enable_force_clear(clnt_hdl, - false, source_pipe_bitmask); - if (res) { - /* - * assuming here modem SSR, AP can remove - * the delay in this case - */ - IPAERR("failed to force clear %d\n", res); - IPAERR("remove delay from SCND reg\n"); - ep_ctrl_scnd.endp_delay = false; - ipahal_write_reg_n_fields( - IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl, - &ep_ctrl_scnd); - } else { - disable_force_clear = true; + if (IPA_CLIENT_IS_PROD(ep->client)) { + source_pipe_bitmask = 1 << + ipa3_get_ep_mapping(ep->client); + res = ipa3_enable_force_clear(clnt_hdl, + false, source_pipe_bitmask); + if (res) { + /* + * assuming here modem SSR, AP can remove + * the delay in this case + */ + IPAERR("failed to force clear %d\n", res); + IPAERR("remove delay from SCND reg\n"); + ep_ctrl_scnd.endp_delay = false; + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl, + &ep_ctrl_scnd); + } else { + disable_force_clear = true; + } } retry_gsi_stop: res = ipa3_stop_gsi_channel(ipa_ep_idx); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c index aa7f27bb041e..8288d77831a4 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c @@ -962,23 +962,25 @@ int ipa3_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) * as IPA uC will fail to suspend the pipe otherwise. */ ep = &ipa3_ctx->ep[ipa_ep_idx_rx]; - source_pipe_bitmask = 1 << + if (IPA_CLIENT_IS_PROD(ep->client)) { + source_pipe_bitmask = 1 << ipa3_get_ep_mapping(ep->client); - result = ipa3_enable_force_clear(ipa_ep_idx_rx, - false, source_pipe_bitmask); - if (result) { - /* - * assuming here modem SSR, AP can remove - * the delay in this case - */ - IPAERR("failed to force clear %d\n", result); - IPAERR("remove delay from SCND reg\n"); - ep_ctrl_scnd.endp_delay = false; - ipahal_write_reg_n_fields( - IPA_ENDP_INIT_CTRL_SCND_n, ipa_ep_idx_rx, - &ep_ctrl_scnd); - } else { - disable_force_clear = true; + result = ipa3_enable_force_clear(ipa_ep_idx_rx, + false, source_pipe_bitmask); + if (result) { + /* + * assuming here modem SSR, AP can remove + * the delay in this case + */ + IPAERR("failed to force clear %d\n", result); + IPAERR("remove delay from SCND reg\n"); + ep_ctrl_scnd.endp_delay = false; + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_CTRL_SCND_n, ipa_ep_idx_rx, + &ep_ctrl_scnd); + } else { + disable_force_clear = true; + } } /* stop gsi rx channel */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c index 2aca4cbba146..e50a93c281c1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c @@ -1809,22 +1809,24 @@ int ipa3_disable_wigig_pipe_i(enum ipa_client_type client) } IPADBG("pipe %d\n", ipa_ep_idx); - source_pipe_bitmask = 1 << ipa_ep_idx; - res = ipa3_enable_force_clear(ipa_ep_idx, - false, source_pipe_bitmask); - if (res) { - /* - * assuming here modem SSR, AP can remove - * the delay in this case - */ - IPAERR("failed to force clear %d\n", res); - IPAERR("remove delay from SCND reg\n"); - ep_ctrl_scnd.endp_delay = false; - ipahal_write_reg_n_fields( - IPA_ENDP_INIT_CTRL_SCND_n, ipa_ep_idx, - &ep_ctrl_scnd); - } else { - disable_force_clear = true; + if (IPA_CLIENT_IS_PROD(ep->client)) { + source_pipe_bitmask = 1 << ipa_ep_idx; + res = ipa3_enable_force_clear(ipa_ep_idx, + false, source_pipe_bitmask); + if (res) { + /* + * assuming here modem SSR, AP can remove + * the delay in this case + */ + IPAERR("failed to force clear %d\n", res); + IPAERR("remove delay from SCND reg\n"); + ep_ctrl_scnd.endp_delay = false; + ipahal_write_reg_n_fields( + IPA_ENDP_INIT_CTRL_SCND_n, ipa_ep_idx, + &ep_ctrl_scnd); + } else { + disable_force_clear = true; + } } retry_gsi_stop: res = ipa3_stop_gsi_channel(ipa_ep_idx);