From a577e8ee97c12c07b5c2d4c3f2d1b50c5cdd07c3 Mon Sep 17 00:00:00 2001 From: Armaan Siddiqui Date: Thu, 6 Aug 2020 21:26:49 +0530 Subject: [PATCH] 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) {