From ecf3b98c7c016ac9244d6bf9c1cb1de78e2c0524 Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Thu, 30 Jan 2020 19:59:05 +0530 Subject: [PATCH 1/8] msm: ipa3: Update the channel mode before start channel Observing the race condition if channel mode configured after channel start. To avoid these race conditions configuring the channel mode and starting the channel. Change-Id: I8f8ec2d9faed320539e2b18de90ab24059a5616c --- drivers/platform/msm/gsi/gsi.c | 6 ++++-- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 11 ++++++++--- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 2 ++ drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 15 ++++++++++----- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 98edaf21c748..b070a36c0f74 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -3979,17 +3979,19 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) return -GSI_STATUS_UNSUPPORTED_OP; } + spin_lock_irqsave(&gsi_ctx->slock, flags); + if (atomic_read(&ctx->poll_mode)) curr = GSI_CHAN_MODE_POLL; else curr = GSI_CHAN_MODE_CALLBACK; if (mode == curr) { - GSIDBG("already in requested mode %u chan_hdl=%lu\n", + GSIERR("already in requested mode %u chan_hdl=%lu\n", curr, chan_hdl); + spin_unlock_irqrestore(&gsi_ctx->slock, flags); return -GSI_STATUS_UNSUPPORTED_OP; } - spin_lock_irqsave(&gsi_ctx->slock, flags); if (curr == GSI_CHAN_MODE_CALLBACK && mode == GSI_CHAN_MODE_POLL) { __gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 8bd99389e5c8..c696707f419c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1937,6 +1937,7 @@ static void ipa3_wq_handle_rx(struct work_struct *work) if (sys->napi_obj) { ipa_pm_activate_sync(sys->pm_hdl); napi_schedule(sys->napi_obj); + IPA_STATS_INC_CNT(sys->napi_sch_cnt); } else if (IPA_CLIENT_IS_LOW_LAT_CONS(sys->ep->client)) { ipa_pm_activate_sync(sys->pm_hdl); tasklet_schedule(&sys->tasklet); @@ -4590,13 +4591,16 @@ void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys) * or after NAPI poll */ clk_off = ipa_pm_activate(sys->pm_hdl); - if (!clk_off && sys->napi_obj) + if (!clk_off && sys->napi_obj) { napi_schedule(sys->napi_obj); - else if (!clk_off && + IPA_STATS_INC_CNT(sys->napi_sch_cnt); + } else if (!clk_off && IPA_CLIENT_IS_LOW_LAT_CONS(sys->ep->client)) { tasklet_schedule(&sys->tasklet); - } else + } else { queue_work(sys->wq, &sys->work); + } + } static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify) @@ -5312,6 +5316,7 @@ start_poll: if (cnt < weight && ep->sys->len > IPA_DEFAULT_SYS_YELLOW_WM && wan_def_sys->len > IPA_DEFAULT_SYS_YELLOW_WM) { napi_complete(ep->sys->napi_obj); + IPA_STATS_INC_CNT(ep->sys->napi_comp_cnt); ret = ipa3_rx_switch_to_intr_mode(ep->sys); if (ret == -GSI_STATUS_PENDING_IRQ && napi_reschedule(ep->sys->napi_obj)) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index e00ee682e10f..435550eb21f6 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1100,6 +1100,8 @@ struct ipa3_sys_context { struct workqueue_struct *repl_wq; struct ipa3_status_stats *status_stat; u32 pm_hdl; + unsigned int napi_sch_cnt; + unsigned int napi_comp_cnt; /* ordering is important - other immutable fields go below */ }; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 26a0b75a9109..06e22beba7ef 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -8507,6 +8507,16 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend) ipa_assert(); } } else { + if (IPA_CLIENT_IS_APPS_PROD(client) || + (client == IPA_CLIENT_APPS_WAN_CONS && + coal_ep_idx != IPA_EP_NOT_ALLOCATED)) + goto chan_statrt; + if (!atomic_read(&ep->sys->curr_polling_state)) { + IPADBG("switch ch %ld to callback\n", ep->gsi_chan_hdl); + gsi_config_channel_mode(ep->gsi_chan_hdl, + GSI_CHAN_MODE_CALLBACK); + } +chan_statrt: res = gsi_start_channel(ep->gsi_chan_hdl); if (res) { IPAERR("failed to start LAN channel\n"); @@ -8533,12 +8543,7 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend) gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL); if (!ipa3_gsi_channel_is_quite(ep)) return -EAGAIN; - } else if (!atomic_read(&ep->sys->curr_polling_state)) { - IPADBG("switch ch %ld to callback\n", ep->gsi_chan_hdl); - gsi_config_channel_mode(ep->gsi_chan_hdl, - GSI_CHAN_MODE_CALLBACK); } - return 0; } From efa43ef9163fddf1d7cdd1d9df0e233e6d726303 Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Wed, 15 Jul 2020 17:59:33 +0530 Subject: [PATCH 2/8] msm: ipa3: Fix to increase the inactivity timer In low latency ping scenario clock unvoting fastly due to this ping RTT was increased. To avoid these scenario increased the inactivity timer to 100msec. Change-Id: I9b11e2adbe087aa67fa2e7ed751b190abb09d0ed Signed-off-by: Ashok Vuyyuru --- drivers/platform/msm/ipa/ipa_v3/ipa_pm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h index 2468a330acba..445e373c163e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h @@ -13,7 +13,7 @@ #define IPA_PM_MAX_EX_CL 64 #define IPA_PM_THRESHOLD_MAX 5 #define IPA_PM_EXCEPTION_MAX 5 -#define IPA_PM_DEFERRED_TIMEOUT 10 +#define IPA_PM_DEFERRED_TIMEOUT 100 /* * ipa_pm group names From a565f3ec5e0b0005f8b3ce6b581f5a72e5173f7e Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Thu, 16 Jul 2020 00:51:01 +0530 Subject: [PATCH 3/8] msm: ipa3: Schedule the NAPI only from interrupt context Due scheduling the NAPI in suspend path observing race conditions in updating channel polling context and pipe polling context. To avoid these scenario scheduling NAPI only from interrupt context. Change-Id: I8eb0438618aedb9873e6eafc269435cc67c03dd5 Signed-off-by: Ashok Vuyyuru --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 26a0b75a9109..bff636232011 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -8323,13 +8323,9 @@ static bool ipa3_gsi_channel_is_quite(struct ipa3_ep_context *ep) bool empty; gsi_is_channel_empty(ep->gsi_chan_hdl, &empty); - if (!empty) { + if (!empty) IPADBG("ch %ld not empty\n", ep->gsi_chan_hdl); - /* queue a work to start polling if don't have one */ - atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1); - if (!atomic_read(&ep->sys->curr_polling_state)) - __ipa_gsi_irq_rx_scedule_poll(ep->sys); - } + /*Schedule NAPI only from interrupt context to avoid race conditions*/ return empty; } From 7224364726164f6c6c864d5c0e27cc0e5b8ad6ac Mon Sep 17 00:00:00 2001 From: Chaitanya Pratapa Date: Wed, 16 Sep 2020 23:10:04 -0700 Subject: [PATCH 4/8] msm: ipa: Fix to remove duplicate proxy vote In case if modem crashes even before uC is loaded, there is a possibility that we hold the proxy vote twice and the clock will not be disabled. Make changes to avoid duplicate proxy vote. Change-Id: Id62994c79eff6868e3a491aa53963ec127ea1213 Signed-off-by: Chaitanya Pratapa --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 4 ++-- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 2 +- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 8 +++++++- drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 3eb8c2b79341..833fda738967 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -6152,7 +6152,7 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, atomic_read(&ipa3_ctx->ipa3_active_clients.cnt)); /* move proxy vote for modem on ipa3_post_init */ if (ipa3_ctx->ipa_hw_type != IPA_HW_v4_0) - ipa3_proxy_clk_vote(); + ipa3_proxy_clk_vote(false); /* The following will retrieve and save the gsi fw version */ ipa_save_gsi_ver(); @@ -6587,7 +6587,7 @@ static void ipa3_load_ipa_fw(struct work_struct *work) IPADBG("Loading IPA uC via PIL\n"); /* Unvoting will happen when uC loaded event received. */ - ipa3_proxy_clk_vote(); + ipa3_proxy_clk_vote(false); if (ipa3_ctx->uc_fw_file_name) result = ipa3_pil_load_ipa_fws( diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 435550eb21f6..cc46fedad055 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2758,7 +2758,7 @@ int ipa3_ctx_get_type(enum ipa_type_mode type); bool ipa3_ctx_get_flag(enum ipa_flag flag); u32 ipa3_ctx_get_num_pipes(void); -void ipa3_proxy_clk_vote(void); +void ipa3_proxy_clk_vote(bool is_ssr); void ipa3_proxy_clk_unvote(void); bool ipa3_is_client_handle_valid(u32 clnt_hdl); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index adf855d0a658..a42483925202 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -7590,10 +7590,16 @@ void ipa3_proxy_clk_unvote(void) * * Return value: none */ -void ipa3_proxy_clk_vote(void) +void ipa3_proxy_clk_vote(bool is_ssr) { if (ipa3_ctx == NULL) return; + + /* Avoid duplicate votes in case we are in SSR even before uC is loaded. */ + if (is_ssr && !ipa3_uc_loaded_check()) { + IPADBG("Dup proxy vote. Ignore as uC is not yet loaded\n"); + return; + } mutex_lock(&ipa3_ctx->q6_proxy_clk_vote_mutex); if (!ipa3_ctx->q6_proxy_clk_vote_valid || (ipa3_ctx->q6_proxy_clk_vote_cnt > 0)) { diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 5506410caef8..81d093b9a3e3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -2894,7 +2894,7 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this, ipa3_q6_pre_powerup_cleanup(); } /* hold a proxy vote for the modem. */ - ipa3_proxy_clk_vote(); + ipa3_proxy_clk_vote(atomic_read(&rmnet_ipa3_ctx->is_ssr)); ipa3_reset_freeze_vote(); IPAWANINFO("IPA BEFORE_POWERUP handling is complete\n"); break; From f53c2a8a7a054286b6388dfc69a52986d8e98418 Mon Sep 17 00:00:00 2001 From: Bojun Pan Date: Fri, 11 Sep 2020 17:45:28 -0700 Subject: [PATCH 5/8] msm: ipa: correct the pointer in idr for FnR stats counter The stats counter which saved in idr was some stack memory which could be freed and cause memory corruption. The fix is to use the memory allocated in heap instead. Change-Id: Ie398b0271571fcff41cdb85de4d77d202b6552b5 Signed-off-by: Bojun Pan --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 9 +++++++ drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 2 ++ drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 29 +++++++++++++++------ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 3eb8c2b79341..e8a1a9383a1c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -7284,6 +7284,13 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, result = -ENOMEM; goto fail_hdr_offset_cache; } + ipa3_ctx->fnr_stats_cache = kmem_cache_create("IPA_FNR_STATS", + sizeof(struct ipa_ioc_flt_rt_counter_alloc), 0, 0, NULL); + if (!ipa3_ctx->fnr_stats_cache) { + IPAERR(":ipa fnr stats cache create failed\n"); + result = -ENOMEM; + goto fail_fnr_stats_cache; + } ipa3_ctx->hdr_proc_ctx_cache = kmem_cache_create("IPA_HDR_PROC_CTX", sizeof(struct ipa3_hdr_proc_ctx_entry), 0, 0, NULL); if (!ipa3_ctx->hdr_proc_ctx_cache) { @@ -7535,6 +7542,8 @@ fail_rt_tbl_cache: fail_hdr_proc_ctx_offset_cache: kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_cache); fail_hdr_proc_ctx_cache: + kmem_cache_destroy(ipa3_ctx->fnr_stats_cache); +fail_fnr_stats_cache: kmem_cache_destroy(ipa3_ctx->hdr_offset_cache); fail_hdr_offset_cache: kmem_cache_destroy(ipa3_ctx->hdr_cache); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 435550eb21f6..a0699b6555b1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1853,6 +1853,7 @@ struct ipa3_app_clock_vote { * @rt_rule_cache: routing rule cache * @hdr_cache: header cache * @hdr_offset_cache: header offset cache + * @fnr_stats_cache: FnR stats cache * @hdr_proc_ctx_cache: processing context cache * @hdr_proc_ctx_offset_cache: processing context offset cache * @rt_tbl_cache: routing table cache @@ -1957,6 +1958,7 @@ struct ipa3_context { struct kmem_cache *rt_rule_cache; struct kmem_cache *hdr_cache; struct kmem_cache *hdr_offset_cache; + struct kmem_cache *fnr_stats_cache; struct kmem_cache *hdr_proc_ctx_cache; struct kmem_cache *hdr_proc_ctx_offset_cache; struct kmem_cache *rt_tbl_cache; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index adf855d0a658..aafd3c918672 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -6918,13 +6918,21 @@ static int __ipa3_alloc_counter_hdl return id; } -int ipa3_alloc_counter_id(struct ipa_ioc_flt_rt_counter_alloc *counter) +int ipa3_alloc_counter_id(struct ipa_ioc_flt_rt_counter_alloc *header) { int i, unused_cnt, unused_max, unused_start_id; + struct ipa_ioc_flt_rt_counter_alloc *counter; idr_preload(GFP_KERNEL); spin_lock(&ipa3_ctx->flt_rt_counters.hdl_lock); + counter = kmem_cache_zalloc(ipa3_ctx->fnr_stats_cache, GFP_KERNEL); + if (!counter) { + IPAERR_RL("failed to alloc fnr stats counter object\n"); + spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock); + return -ENOMEM; + } + memcpy(counter, header, sizeof(struct ipa_ioc_flt_rt_counter_alloc)); /* allocate hw counters */ counter->hw_counter.start_id = 0; counter->hw_counter.end_id = 0; @@ -7024,7 +7032,7 @@ mark_hw_cnt: unused_start_id = counter->hw_counter.start_id; if (unused_start_id < 1 || unused_start_id > IPA_FLT_RT_HW_COUNTER) { - IPAERR("unexpected hw_counter start id %d\n", + IPAERR_RL("unexpected hw_counter start id %d\n", unused_start_id); goto err; } @@ -7039,7 +7047,7 @@ mark_sw_cnt: - IPA_FLT_RT_HW_COUNTER; if (unused_start_id < 1 || unused_start_id > IPA_FLT_RT_SW_COUNTER) { - IPAERR("unexpected sw_counter start id %d\n", + IPAERR_RL("unexpected sw_counter start id %d\n", unused_start_id); goto err; } @@ -7051,10 +7059,12 @@ done: counter->hdl = __ipa3_alloc_counter_hdl(counter); spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock); idr_preload_end(); + memcpy(header, counter, sizeof(struct ipa_ioc_flt_rt_counter_alloc)); return 0; err: counter->hdl = -1; + kmem_cache_free(ipa3_ctx->fnr_stats_cache, counter); spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock); idr_preload_end(); return -ENOMEM; @@ -7068,7 +7078,7 @@ void ipa3_counter_remove_hdl(int hdl) spin_lock(&ipa3_ctx->flt_rt_counters.hdl_lock); counter = idr_find(&ipa3_ctx->flt_rt_counters.hdl, hdl); if (counter == NULL) { - IPAERR("unexpected hdl %d\n", hdl); + IPAERR_RL("unexpected hdl %d\n", hdl); goto err; } /* remove counters belong to this hdl, set used back to 0 */ @@ -7078,7 +7088,7 @@ void ipa3_counter_remove_hdl(int hdl) memset(&ipa3_ctx->flt_rt_counters.used_hw + offset, 0, counter->hw_counter.num_counters * sizeof(bool)); } else { - IPAERR("unexpected hdl %d\n", hdl); + IPAERR_RL("unexpected hdl %d\n", hdl); goto err; } offset = counter->sw_counter.start_id - 1 - IPA_FLT_RT_HW_COUNTER; @@ -7087,11 +7097,12 @@ void ipa3_counter_remove_hdl(int hdl) memset(&ipa3_ctx->flt_rt_counters.used_sw + offset, 0, counter->sw_counter.num_counters * sizeof(bool)); } else { - IPAERR("unexpected hdl %d\n", hdl); + IPAERR_RL("unexpected hdl %d\n", hdl); goto err; } /* remove the handle */ idr_remove(&ipa3_ctx->flt_rt_counters.hdl, hdl); + kmem_cache_free(ipa3_ctx->fnr_stats_cache, counter); err: spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock); } @@ -7108,8 +7119,10 @@ void ipa3_counter_id_remove_all(void) memset(&ipa3_ctx->flt_rt_counters.used_sw, 0, sizeof(ipa3_ctx->flt_rt_counters.used_sw)); /* remove all handles */ - idr_for_each_entry(&ipa3_ctx->flt_rt_counters.hdl, counter, hdl) + idr_for_each_entry(&ipa3_ctx->flt_rt_counters.hdl, counter, hdl) { idr_remove(&ipa3_ctx->flt_rt_counters.hdl, hdl); + kmem_cache_free(ipa3_ctx->fnr_stats_cache, counter); + } spin_unlock(&ipa3_ctx->flt_rt_counters.hdl_lock); } @@ -7653,7 +7666,7 @@ u32 ipa3_get_num_pipes(void) /** * ipa3_disable_apps_wan_cons_deaggr()- - * set ipa_ctx->ipa_client_apps_wan_cons_agg_gro + * set ipa3_ctx->ipa_client_apps_wan_cons_agg_gro * * Return value: 0 or negative in case of failure */ From 3049e6f03e3a401b32aef289dadb238765509054 Mon Sep 17 00:00:00 2001 From: Sivakanth vaka Date: Tue, 22 Sep 2020 13:05:14 +0530 Subject: [PATCH 6/8] msm: ipa3: Rate limit excessive logging Rate limiting excessive logs when modem is in limited service. Signed-off-by: sivakanth vaka --- drivers/platform/msm/ipa/ipa_v3/teth_bridge.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c index fed8c18ed520..24f24c908667 100644 --- a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c +++ b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. */ #include @@ -30,6 +30,9 @@ pr_debug(TETH_BRIDGE_DRV_NAME " %s:%d EXIT\n", __func__, __LINE__) #define TETH_ERR(fmt, args...) \ pr_err(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) +#define TETH_ERR_RL(fmt, args...) \ + pr_err_ratelimited_ipa(TETH_BRIDGE_DRV_NAME " %s:%d " fmt, __func__, \ + __LINE__, ## args); /** * struct ipa3_teth_bridge_ctx - Tethering bridge driver context information @@ -65,12 +68,12 @@ static void teth_bridge_ipa_cb(void *priv, enum ipa_dp_evt_type evt, TETH_DBG_FUNC_ENTRY(); if (evt != IPA_RECEIVE) { - TETH_ERR("unexpected event %d\n", evt); + TETH_ERR_RL("unexpected event %d\n", evt); WARN_ON(1); return; } - TETH_ERR("Unexpected exception packet from USB, dropping packet\n"); + TETH_ERR_RL("Unexpected exception packet from USB, dropping packet\n"); dev_kfree_skb_any(skb); TETH_DBG_FUNC_EXIT(); } From b793aca3be73fdfd4b75ed56edc8ab3b778b0b7d Mon Sep 17 00:00:00 2001 From: Bojun Pan Date: Wed, 23 Sep 2020 11:29:22 -0700 Subject: [PATCH 7/8] msm: ipa: add state for rmnet_ctl tx/rx pipes When ssr happen in middle of egress ioctl, only tx pipe is setup and the current state in teardown cannot handle it. The fix is to add state for tx/rx setup separately. Change-Id: I0eb4011ce91139acce3a619a8179d84066873953 --- .../platform/msm/ipa/ipa_v3/rmnet_ctl_ipa.c | 68 ++++++++++++------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ctl_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ctl_ipa.c index 2f3855d5d7de..425e5f828901 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ctl_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ctl_ipa.c @@ -17,6 +17,13 @@ enum ipa_rmnet_ctl_state { IPA_RMNET_CTL_START, /* rmnet_ctl register + pipe setup */ }; +#define IPA_RMNET_CTL_PIPE_NOT_READY (0) +#define IPA_RMNET_CTL_PIPE_TX_READY (1 << 0) +#define IPA_RMNET_CTL_PIPE_RX_READY (1 << 1) +#define IPA_RMNET_CTL_PIPE_READY_ALL (IPA_RMNET_CTL_PIPE_TX_READY | \ + IPA_RMNET_CTL_PIPE_RX_READY) /* TX Ready + RX ready */ + + #define IPA_WWAN_CONS_DESC_FIFO_SZ 256 #define RMNET_CTRL_QUEUE_MAX (2 * IPA_WWAN_CONS_DESC_FIFO_SZ) @@ -44,6 +51,7 @@ struct ipa3_rmnet_ctl_stats { struct rmnet_ctl_ipa3_context { struct ipa3_rmnet_ctl_stats stats; enum ipa_rmnet_ctl_state state; + u8 pipe_state; struct ipa_sys_connect_params apps_to_ipa_low_lat_ep_cfg; struct ipa_sys_connect_params ipa_to_apps_low_lat_ep_cfg; u32 apps_to_ipa3_low_lat_hdl; @@ -105,6 +113,7 @@ int ipa3_rmnet_ctl_init(void) rmnet_ctl_ipa3_ctx->state = IPA_RMNET_CTL_NOT_REG; mutex_init(&rmnet_ctl_ipa3_ctx->lock); spin_lock_init(&rmnet_ctl_ipa3_ctx->tx_lock); + rmnet_ctl_ipa3_ctx->pipe_state = IPA_RMNET_CTL_PIPE_NOT_READY; return 0; } @@ -264,6 +273,7 @@ int ipa3_setup_apps_low_lat_cons_pipe(void) IPADBG("Low lat pipe setup fails\n"); return ret; } + rmnet_ctl_ipa3_ctx->pipe_state |= IPA_RMNET_CTL_PIPE_RX_READY; if (rmnet_ctl_ipa3_ctx->cb_info.ready_cb) { (*(rmnet_ctl_ipa3_ctx->cb_info.ready_cb)) (rmnet_ctl_ipa3_ctx->cb_info.ready_cb_user_data); @@ -331,6 +341,7 @@ int ipa3_setup_apps_low_lat_prod_pipe(void) IPAERR("failed to config apps low lat prod pipe\n"); return ret; } + rmnet_ctl_ipa3_ctx->pipe_state |= IPA_RMNET_CTL_PIPE_TX_READY; return 0; } @@ -339,36 +350,47 @@ int ipa3_teardown_apps_low_lat_pipes(void) int ret = 0; if (rmnet_ctl_ipa3_ctx->state != IPA_RMNET_CTL_PIPE_READY && - rmnet_ctl_ipa3_ctx->state != IPA_RMNET_CTL_START) { + rmnet_ctl_ipa3_ctx->state != IPA_RMNET_CTL_START && + rmnet_ctl_ipa3_ctx->pipe_state == IPA_RMNET_CTL_PIPE_NOT_READY) { IPAERR("rmnet_ctl in bad state %d\n", rmnet_ctl_ipa3_ctx->state); return -EFAULT; } - if (rmnet_ctl_ipa3_ctx->cb_info.stop_cb) { - (*(rmnet_ctl_ipa3_ctx->cb_info.stop_cb)) - (rmnet_ctl_ipa3_ctx->cb_info.stop_cb_user_data); - } else { - IPAERR("Invalid stop_cb\n"); - return -EFAULT; + if (rmnet_ctl_ipa3_ctx->pipe_state == IPA_RMNET_CTL_PIPE_READY || + rmnet_ctl_ipa3_ctx->state == IPA_RMNET_CTL_START) { + if (rmnet_ctl_ipa3_ctx->cb_info.stop_cb) { + (*(rmnet_ctl_ipa3_ctx->cb_info.stop_cb)) + (rmnet_ctl_ipa3_ctx->cb_info.stop_cb_user_data); + } else { + IPAERR("Invalid stop_cb\n"); + return -EFAULT; + } + if (rmnet_ctl_ipa3_ctx->state == IPA_RMNET_CTL_PIPE_READY) + rmnet_ctl_ipa3_ctx->state = IPA_RMNET_CTL_NOT_REG; + else + rmnet_ctl_ipa3_ctx->state = IPA_RMNET_CTL_REGD; } - if (rmnet_ctl_ipa3_ctx->state == IPA_RMNET_CTL_PIPE_READY) - rmnet_ctl_ipa3_ctx->state = IPA_RMNET_CTL_NOT_REG; - else - rmnet_ctl_ipa3_ctx->state = IPA_RMNET_CTL_REGD; - ret = ipa3_teardown_sys_pipe( - rmnet_ctl_ipa3_ctx->ipa3_to_apps_low_lat_hdl); - if (ret < 0) { - IPAERR("Failed to teardown APPS->IPA low lat pipe\n"); - return ret; + if (rmnet_ctl_ipa3_ctx->pipe_state & IPA_RMNET_CTL_PIPE_RX_READY) { + ret = ipa3_teardown_sys_pipe( + rmnet_ctl_ipa3_ctx->ipa3_to_apps_low_lat_hdl); + if (ret < 0) { + IPAERR("Failed to teardown APPS->IPA low lat pipe\n"); + return ret; + } + rmnet_ctl_ipa3_ctx->ipa3_to_apps_low_lat_hdl = -1; + rmnet_ctl_ipa3_ctx->pipe_state &= ~IPA_RMNET_CTL_PIPE_RX_READY; } - rmnet_ctl_ipa3_ctx->ipa3_to_apps_low_lat_hdl = -1; - ret = ipa3_teardown_sys_pipe( - rmnet_ctl_ipa3_ctx->apps_to_ipa3_low_lat_hdl); - if (ret < 0) { - return ret; - IPAERR("Failed to teardown APPS->IPA low lat pipe\n"); + + if (rmnet_ctl_ipa3_ctx->pipe_state & IPA_RMNET_CTL_PIPE_TX_READY) { + ret = ipa3_teardown_sys_pipe( + rmnet_ctl_ipa3_ctx->apps_to_ipa3_low_lat_hdl); + if (ret < 0) { + return ret; + IPAERR("Failed to teardown APPS->IPA low lat pipe\n"); + } + rmnet_ctl_ipa3_ctx->apps_to_ipa3_low_lat_hdl = -1; + rmnet_ctl_ipa3_ctx->pipe_state &= ~IPA_RMNET_CTL_PIPE_TX_READY; } - rmnet_ctl_ipa3_ctx->apps_to_ipa3_low_lat_hdl = -1; return ret; } From a577e8ee97c12c07b5c2d4c3f2d1b50c5cdd07c3 Mon Sep 17 00:00:00 2001 From: Armaan Siddiqui Date: Thu, 6 Aug 2020 21:26:49 +0530 Subject: [PATCH 8/8] msm: ipa: Add change to support wdi gsi db polling Changes done to support wdi gsi db polling based on the polling flag whether enabled in dtsi or not. Change-Id: Ib5559da136866dafc0b3ab3908c6073111dbab21 Signed-off-by: Armaan Siddiqui --- drivers/platform/msm/gsi/gsi.c | 38 ++++++ drivers/platform/msm/gsi/gsi.h | 33 ++++- drivers/platform/msm/gsi/gsi_reg_v2.h | 11 ++ drivers/platform/msm/ipa/ipa_v3/ipa.c | 9 +- drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 37 ++++++ drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 9 ++ drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c | 115 +++++++++++++++--- 7 files changed, 235 insertions(+), 17 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 98edaf21c748..ae1f7158d7af 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -2768,6 +2768,44 @@ int gsi_write_channel_scratch2_reg(unsigned long chan_hdl, } EXPORT_SYMBOL(gsi_write_channel_scratch2_reg); +int gsi_write_wdi3_channel_scratch_6_7_reg(unsigned long chan_hdl, + union __packed gsi_wdi3_channel_scratch_6_7_reg val) +{ + struct gsi_chan_ctx *ctx; + + if (!gsi_ctx) { + pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); + return -GSI_STATUS_NODEV; + } + + if (chan_hdl >= gsi_ctx->max_ch) { + GSIERR("bad params chan_hdl=%lu\n", chan_hdl); + return -GSI_STATUS_INVALID_PARAMS; + } + + ctx = &gsi_ctx->chan[chan_hdl]; + + mutex_lock(&ctx->mlock); + + ctx->scratch.wdi3.db_addr_wp_lsb = val.wdi3.db_addr_wp_lsb; + ctx->scratch.wdi3.db_addr_wp_msb = val.wdi3.db_addr_wp_msb; + + GSIDBG(" scratch value lsb 32 bit here %x0x & %x0x\n",val.wdi3.db_addr_wp_lsb, + ctx->scratch.wdi3.db_addr_wp_lsb ); + GSIDBG(" scratch value here %x0x & %x0x\n",val.wdi3.db_addr_wp_msb, + ctx->scratch.wdi3.db_addr_wp_msb ); + + gsi_writel(val.data.word1, gsi_ctx->base + + GSI_EE_n_GSI_CH_k_SCRATCH_6_OFFS(chan_hdl, + gsi_ctx->per.ee)); + gsi_writel(val.data.word2, gsi_ctx->base + + GSI_EE_n_GSI_CH_k_SCRATCH_7_OFFS(chan_hdl, + gsi_ctx->per.ee)); + mutex_unlock(&ctx->mlock); + return GSI_STATUS_SUCCESS; +} +EXPORT_SYMBOL(gsi_write_wdi3_channel_scratch_6_7_reg); + static void __gsi_read_channel_scratch(unsigned long chan_hdl, union __packed gsi_channel_scratch * val) { diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index d0a738835045..2c11abd9ccea 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/drivers/platform/msm/gsi/gsi.h @@ -850,6 +850,7 @@ struct __packed gsi_11ad_tx_channel_scratch { * be updated. * @qmap_id: Rx only, used for setting metadata register in IPA. Read only field * for MCS. Write for SW. + * @wdi_db_polling_enabled : set to true for cedros and lahaina WA * @resv: reserved bits. * @endp_metadata_reg_offset: Rx only, the offset of * IPA_ENDP_INIT_HDR_METADATA_n of the @@ -858,16 +859,21 @@ struct __packed gsi_11ad_tx_channel_scratch { * @rx_pkt_offset: Rx only, Since Rx header length is not fixed, * WLAN host will pass this information to IPA. * @resv: reserved bits. + * @db_addr_wp_lsb: used to store 32-bit lsb for wdi db polling + * @db_addr_wp_msb: used to store 32-bit msb for wdi db polling */ struct __packed gsi_wdi3_channel_scratch { uint32_t wifi_rp_address_low; uint32_t wifi_rp_address_high; uint32_t update_rp_moderation_threshold : 5; uint32_t qmap_id : 8; - uint32_t reserved1 : 3; + uint32_t wdi_db_polling_enabled : 1; + uint32_t reserved1 : 2; uint32_t endp_metadata_reg_offset : 16; uint32_t rx_pkt_offset : 16; uint32_t reserved2 : 16; + uint32_t db_addr_wp_lsb; + uint32_t db_addr_wp_msb; }; /** @@ -975,6 +981,19 @@ union __packed gsi_wdi2_channel_scratch2_reg { } data; }; +struct __packed gsi_wdi3_channel_scratch_6_7 { + uint32_t db_addr_wp_lsb; + uint32_t db_addr_wp_msb; +}; + +union __packed gsi_wdi3_channel_scratch_6_7_reg { + struct __packed gsi_wdi3_channel_scratch_6_7 wdi3; + struct __packed { + uint32_t word1; + uint32_t word2; + } data; +}; + /** * gsi_mhi_evt_scratch - MHI protocol SW config area of * event scratch @@ -1780,6 +1799,18 @@ int gsi_write_channel_scratch2_reg(unsigned long chan_hdl, */ int gsi_write_wdi3_channel_scratch2_reg(unsigned long chan_hdl, union __packed gsi_wdi3_channel_scratch2_reg val); +/** + * gsi_write_channel_scratch_reg - Peripheral should call this function to + * write to the scratch 6, 7 reg area of the channel context + * + * @chan_hdl: Client handle previously obtained from + * gsi_alloc_channel + * @val: Value to write + * + * @Return gsi_status + */ +int gsi_write_wdi3_channel_scratch_6_7_reg(unsigned long chan_hdl, + union __packed gsi_wdi3_channel_scratch_6_7_reg val); /** * gsi_read_channel_scratch - Peripheral should call this function to diff --git a/drivers/platform/msm/gsi/gsi_reg_v2.h b/drivers/platform/msm/gsi/gsi_reg_v2.h index d2c09fd4e7c2..b8049eecf2e6 100644 --- a/drivers/platform/msm/gsi/gsi_reg_v2.h +++ b/drivers/platform/msm/gsi/gsi_reg_v2.h @@ -592,6 +592,17 @@ #define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff #define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0 +#define GSI_EE_n_GSI_CH_k_SCRATCH_6_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f048 + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0 + +#define GSI_EE_n_GSI_CH_k_SCRATCH_7_OFFS(k, n) \ + (GSI_GSI_REG_BASE_OFFS + 0x0000f04c + 0x4000 * (n) + 0x80 * (k)) +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_BMSK 0xffffffff +#define GSI_EE_n_GSI_CH_k_SCRATCH_3_SCRATCH_SHFT 0x0 + + #define GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(k, n) \ (GSI_GSI_REG_BASE_OFFS + 0x00010000 + 0x4000 * (n) + 0x80 * (k)) #define GSI_EE_n_EV_CH_k_CNTXT_0_ELEMENT_SIZE_BMSK 0xff000000 diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 3eb8c2b79341..b1c04f970f0b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -7021,6 +7021,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->rmnet_ctl_enable = resource_p->rmnet_ctl_enable; ipa3_ctx->tx_wrapper_cache_max_size = get_tx_wrapper_cache_size( resource_p->tx_wrapper_cache_max_size); + ipa3_ctx->gsi_wdi_db_polling = resource_p->gsi_wdi_db_polling; if (resource_p->gsi_fw_file_name) { ipa3_ctx->gsi_fw_file_name = @@ -7804,7 +7805,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->ipa_endp_delay_wa = false; ipa_drv_res->skip_ieob_mask_wa = false; ipa_drv_res->ipa_gpi_event_rp_ddr = false; - + ipa_drv_res->gsi_wdi_db_polling = false; /* Get IPA HW Version */ result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-ver", &ipa_drv_res->ipa_hw_type); @@ -8053,6 +8054,12 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->rmnet_ctl_enable ? "True" : "False"); + ipa_drv_res->gsi_wdi_db_polling = + of_property_read_bool(pdev->dev.of_node, + "qcom,gsi_wdi_db_polling"); + IPADBG(": gsi wdi db polling = %s\n", + ipa_drv_res->gsi_wdi_db_polling + ? "True" : "False"); result = of_property_read_string(pdev->dev.of_node, "qcom,use-gsi-ipa-fw", &ipa_drv_res->gsi_fw_file_name); if (!result) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 7dc66375f6e7..7012182e5510 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -2716,6 +2716,38 @@ static ssize_t ipa3_enable_ipc_low(struct file *file, return count; } +static ssize_t ipa3_read_gsi_wdi3_db_polling(struct file *file, + char __user *buf, size_t count, loff_t *ppos) { + + int nbytes; + nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, + "gsi_wdi_db_polling = %d\n", + ipa3_ctx->gsi_wdi_db_polling); + return simple_read_from_buffer(buf, count, ppos, dbg_buff, nbytes); + +} +static ssize_t ipa3_write_gsi_wdi3_db_polling(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) { + + int ret; + u32 gsi_wdi_db_polling =0; + + if (count >= sizeof(dbg_buff)) + return -EFAULT; + + ret = kstrtou32_from_user(buf, count, 0, &gsi_wdi_db_polling); + if(ret) + return ret; + + if(gsi_wdi_db_polling == 1) + ipa3_ctx->gsi_wdi_db_polling = true; + else if(gsi_wdi_db_polling == 0) + ipa3_ctx->gsi_wdi_db_polling = false; + else + IPAERR("Invalid value \n"); + return count; +} + static const struct ipa3_debugfs_file debugfs_files[] = { { "gen_reg", IPA_READ_ONLY_MODE, NULL, { @@ -2889,6 +2921,11 @@ static const struct ipa3_debugfs_file debugfs_files[] = { "app_clk_vote_cnt", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_app_clk_vote, } + },{ + "wdi3_db_polling_enable", IPA_READ_WRITE_MODE, NULL, { + .read = ipa3_read_gsi_wdi3_db_polling, + .write = ipa3_write_gsi_wdi3_db_polling, + } }, }; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index e00ee682e10f..a07c22ecc5e8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -491,6 +491,11 @@ enum ipa_icc_type { #define IPA_ICC_MAX (IPA_ICC_PATH_MAX*IPA_ICC_TYPE_MAX) +enum ipa3_wdi_polling_mode { + IPA_WDI_DB_POLLING_DISABLED, + IPA_WDI_DB_POLLING_ENABLED, +}; + /** * struct ipa_rx_page_data - information needed * to send to wlan driver on receiving data from ipa hw @@ -988,6 +993,8 @@ struct ipa3_ep_context { u32 qmi_request_sent; u32 eot_in_poll_err; bool ep_delay_set; + void *tr_doorbel_va; + dma_addr_t tr_doorbel_phy; /* sys MUST be the last element of this struct */ struct ipa3_sys_context *sys; @@ -2122,6 +2129,7 @@ struct ipa3_context { bool rmnet_ctl_enable; char *gsi_fw_file_name; char *uc_fw_file_name; + bool gsi_wdi_db_polling; }; struct ipa3_plat_drv_res { @@ -2185,6 +2193,7 @@ struct ipa3_plat_drv_res { const char *gsi_fw_file_name; const char *uc_fw_file_name; u32 tx_wrapper_cache_max_size; + bool gsi_wdi_db_polling; }; /** 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 c197054f0e5f..aa7f27bb041e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c @@ -1,3 +1,4 @@ + // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018 - 2020, The Linux Foundation. All rights reserved. @@ -428,6 +429,13 @@ static int ipa3_setup_wdi3_gsi_channel(u8 is_smmu_enabled, (1 << 8)); } + /* enable/disable wdi db polling mode based on dt value*/ + if (ipa3_ctx->gsi_wdi_db_polling) { + ch_scratch.wdi3.wdi_db_polling_enabled = IPA_WDI_DB_POLLING_ENABLED; + } else { + ch_scratch.wdi3.wdi_db_polling_enabled = IPA_WDI_DB_POLLING_DISABLED; + } + result = gsi_write_channel_scratch(ep->gsi_chan_hdl, ch_scratch); if (result != GSI_STATUS_SUCCESS) { IPAERR("failed to write evt ring scratch\n"); @@ -446,6 +454,53 @@ fail_smmu_mapping: return result; } +static int ipa3_wdi_gsi_db(phys_addr_t* db_addr, struct ipa3_ep_context *ep_ctx) +{ + int result = 0; + struct ipa_mem_buffer mem; + union __packed gsi_wdi3_channel_scratch_6_7_reg gsi_ch_scratch; + + mem.base = kzalloc(sizeof(int), GFP_KERNEL); + + if (!mem.base) + { + IPAERR("failed to alloc memory mem.base\n"); + return -ENOMEM; + } + + memset(mem.base, 0, sizeof(int)); + ep_ctx->tr_doorbel_va = mem.base; + *db_addr = virt_to_phys((void *) mem.base); + mem.phys_base = dma_map_single(ipa3_ctx->pdev, mem.base, sizeof(int), DMA_BIDIRECTIONAL); + ep_ctx->tr_doorbel_phy = mem.phys_base; + IPADBG("db_addr 0x%x, mem.base = 0x%x, mem.phys_base = 0x%x\n", (*db_addr), mem.base, mem.phys_base); + if (dma_mapping_error(ipa3_ctx->pdev, mem.phys_base)) { + IPAERR("failed to do dma mapping\n"); + kfree(mem.base); + return -ENOMEM; + } + + + /* write channel scratch */ + memset(&gsi_ch_scratch, 0, sizeof(gsi_ch_scratch)); + gsi_ch_scratch.wdi3.db_addr_wp_lsb = (u32)mem.phys_base; + gsi_ch_scratch.wdi3.db_addr_wp_msb = (u32)(mem.phys_base >> 32); + IPADBG("gsi written lsb value 0x%x\n", gsi_ch_scratch.wdi3.db_addr_wp_lsb); + IPADBG("gsi written msb value 0x%x\n", gsi_ch_scratch.wdi3.db_addr_wp_msb); + + result = gsi_write_wdi3_channel_scratch_6_7_reg(ep_ctx->gsi_chan_hdl, gsi_ch_scratch); + if (result != GSI_STATUS_SUCCESS) { + IPAERR("gsi_write_channel_scratch failed %d\n", + result); + dma_unmap_single(ipa3_ctx->pdev, ep_ctx->tr_doorbel_phy, sizeof(int), DMA_BIDIRECTIONAL); + kfree(mem.base); + return result; + } + + return result; +} + + int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in, struct ipa_wdi_conn_out_params *out, ipa_wdi_meter_notifier_cb wdi_notify) @@ -550,15 +605,27 @@ int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in, result = -EFAULT; goto fail; } - if (gsi_query_channel_db_addr(ep_rx->gsi_chan_hdl, - &gsi_db_addr_low, &gsi_db_addr_high)) { - IPAERR("failed to query gsi rx db addr\n"); - result = -EFAULT; - goto fail; + + if (ipa3_ctx->gsi_wdi_db_polling) { + out->is_ddr_mapped = true; + result = ipa3_wdi_gsi_db(&(out->rx_uc_db_pa),ep_rx); + if(result){ + IPAERR("fail to write db addr \n"); + result = -EFAULT; + goto fail; + } + } else { + out->is_ddr_mapped = false; + if (gsi_query_channel_db_addr(ep_rx->gsi_chan_hdl, + &gsi_db_addr_low, &gsi_db_addr_high)) { + IPAERR("failed to query gsi rx db addr\n"); + result = -EFAULT; + goto fail; + } + /* only 32 bit lsb is used */ + out->rx_uc_db_pa = (phys_addr_t)(gsi_db_addr_low); } - /* only 32 bit lsb is used */ - out->rx_uc_db_pa = (phys_addr_t)(gsi_db_addr_low); - IPADBG("out->rx_uc_db_pa %llu\n", out->rx_uc_db_pa); + IPADBG("out->rx_uc_db_pa 0x%x\n", out->rx_uc_db_pa); ipa3_install_dflt_flt_rules(ipa_ep_idx_rx); IPADBG("client %d (ep: %d) connected\n", rx_client, @@ -601,14 +668,24 @@ int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in, result = -EFAULT; goto fail; } - if (gsi_query_channel_db_addr(ep_tx->gsi_chan_hdl, - &gsi_db_addr_low, &gsi_db_addr_high)) { - IPAERR("failed to query gsi tx db addr\n"); - result = -EFAULT; - goto fail; + + if (ipa3_ctx->gsi_wdi_db_polling) { + result = ipa3_wdi_gsi_db(&(out->tx_uc_db_pa),ep_tx); + if(result){ + IPAERR("fail to write db addr \n"); + result = -EFAULT; + goto fail; + } + } else { + if (gsi_query_channel_db_addr(ep_tx->gsi_chan_hdl, + &gsi_db_addr_low, &gsi_db_addr_high)) { + IPAERR("failed to query gsi tx db addr\n"); + result = -EFAULT; + goto fail; + } + /* only 32 bit lsb is used */ + out->tx_uc_db_pa = (phys_addr_t)(gsi_db_addr_low); } - /* only 32 bit lsb is used */ - out->tx_uc_db_pa = (phys_addr_t)(gsi_db_addr_low); IPADBG("out->tx_uc_db_pa %llu\n", out->tx_uc_db_pa); IPADBG("client %d (ep: %d) connected\n", tx_client, ipa_ep_idx_tx); @@ -690,6 +767,14 @@ int ipa3_disconn_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) ep_rx = &ipa3_ctx->ep[ipa_ep_idx_rx]; IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(ipa_ep_idx_tx)); + + if (ipa3_ctx->gsi_wdi_db_polling) { + IPADBG("gsi_wdi_db_polling enabled, free and unmap ddr addr\n"); + dma_unmap_single(ipa3_ctx->pdev, ep_tx->tr_doorbel_phy, sizeof(int), DMA_BIDIRECTIONAL); + dma_unmap_single(ipa3_ctx->pdev, ep_rx->tr_doorbel_phy, sizeof(int), DMA_BIDIRECTIONAL); + kfree(ep_tx->tr_doorbel_va); + kfree(ep_rx->tr_doorbel_va); + } /* tear down tx pipe */ result = ipa3_reset_gsi_channel(ipa_ep_idx_tx); if (result != GSI_STATUS_SUCCESS) {