diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 98edaf21c748..019a666ef9cb 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) { @@ -3979,17 +4017,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/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..9fc695955f34 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( @@ -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 = @@ -7284,6 +7285,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 +7543,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); @@ -7804,7 +7814,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 +8063,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_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..5f8c47ada451 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; @@ -1100,6 +1107,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 */ }; @@ -1851,6 +1860,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 @@ -1955,6 +1965,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; @@ -2122,6 +2133,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 +2197,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; }; /** @@ -2756,7 +2769,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_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 diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 26a0b75a9109..7c44b78b87c9 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); } @@ -7590,10 +7603,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)) { @@ -7653,7 +7672,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 */ @@ -8323,13 +8342,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; } @@ -8507,6 +8522,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 +8558,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; } 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) { 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; } 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; 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(); }