diff options
-rw-r--r-- | Documentation/devicetree/bindings/platform/msm/ipa.txt | 4 | ||||
-rw-r--r-- | drivers/platform/msm/ipa/ipa_v3/ipa.c | 18 | ||||
-rw-r--r-- | drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 77 | ||||
-rw-r--r-- | drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 4 |
4 files changed, 101 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt index 74c95f8f65f9..a407b736d481 100644 --- a/Documentation/devicetree/bindings/platform/msm/ipa.txt +++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt @@ -65,7 +65,9 @@ memory allocation over a PCIe bridge - qcom,use-rg10-limitation-mitigation: Boolean context flag to activate the mitigation to register group 10 AP access limitation - +- qcom,do-not-use-ch-gsi-20: Boolean context flag to activate + software workaround for IPA limitation + to not use GSI physical channel 20 - qcom,tethered-flow-control: Boolean context flag to indicate whether apps based flow control is needed for tethered call. diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 858693c1fc44..535ed4d767b4 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -2634,6 +2634,15 @@ static int ipa3_setup_apps_pipes(void) struct ipa_sys_connect_params sys_in; int result = 0; + if (ipa3_ctx->gsi_ch20_wa) { + IPADBG("Allocating GSI physical channel 20\n"); + result = ipa_gsi_ch20_wa(); + if (result) { + IPAERR("ipa_gsi_ch20_wa failed %d\n", result); + goto fail_cmd; + } + } + /* CMD OUT (AP->IPA) */ memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params)); sys_in.client = IPA_CLIENT_APPS_CMD_PROD; @@ -3984,6 +3993,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->transport_prototype = resource_p->transport_prototype; ipa3_ctx->ee = resource_p->ee; ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa; + ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa; ipa3_ctx->ipa3_active_clients_logging.log_rdy = false; /* default aggregation parameters */ @@ -4482,6 +4492,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->ipa_wdi2 = false; ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ; ipa_drv_res->apply_rg10_wa = false; + ipa_drv_res->gsi_ch20_wa = false; smmu_disable_htw = of_property_read_bool(pdev->dev.of_node, "qcom,smmu-disable-htw"); @@ -4667,6 +4678,13 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->apply_rg10_wa ? "True" : "False"); + ipa_drv_res->gsi_ch20_wa = + of_property_read_bool(pdev->dev.of_node, + "qcom,do-not-use-ch-gsi-20"); + IPADBG(": GSI CH 20 WA is = %s\n", + ipa_drv_res->apply_rg10_wa + ? "Needed" : "Not needed"); + 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 3b5ce662e3a4..a556476f44d1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -55,6 +55,10 @@ #define IPA_GSI_MAX_CH_LOW_WEIGHT 15 #define IPA_GSI_EVT_RING_INT_MODT 3200 /* 0.1s under 32KHz clock */ +#define IPA_GSI_CH_20_WA_NUM_CH_TO_ALLOC 10 +/* The below virtual channel cannot be used by any entity */ +#define IPA_GSI_CH_20_WA_VIRT_CHAN 29 + static struct sk_buff *ipa3_get_skb_ipa_rx(unsigned int len, gfp_t flags); static void ipa3_replenish_wlan_rx_cache(struct ipa3_sys_context *sys); static void ipa3_replenish_rx_cache(struct ipa3_sys_context *sys); @@ -3597,7 +3601,6 @@ static void ipa_dma_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify) } } - static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, struct ipa3_ep_context *ep) { @@ -3891,3 +3894,75 @@ static uint64_t pointer_to_tag_wa(struct ipa3_tx_pkt_wrapper *tx_pkt) } return (unsigned long)tx_pkt & 0x0000FFFFFFFFFFFF; } + +/** + * ipa_gsi_ch20_wa() - software workaround for IPA GSI channel 20 + * + * A hardware limitation requires to avoid using GSI physical channel 20. + * This function allocates GSI physical channel 20 and holds it to prevent + * others to use it. + * + * Return codes: 0 on success, negative on failure + */ +int ipa_gsi_ch20_wa(void) +{ + struct gsi_chan_props gsi_channel_props; + dma_addr_t dma_addr; + int result; + int i; + unsigned long chan_hdl[IPA_GSI_CH_20_WA_NUM_CH_TO_ALLOC]; + unsigned long chan_hdl_to_keep; + + + memset(&gsi_channel_props, 0, sizeof(gsi_channel_props)); + gsi_channel_props.prot = GSI_CHAN_PROT_GPI; + gsi_channel_props.dir = GSI_CHAN_DIR_TO_GSI; + gsi_channel_props.evt_ring_hdl = ~0; + gsi_channel_props.re_size = GSI_CHAN_RE_SIZE_16B; + gsi_channel_props.ring_len = 4 * gsi_channel_props.re_size; + gsi_channel_props.ring_base_vaddr = + dma_alloc_coherent(ipa3_ctx->pdev, gsi_channel_props.ring_len, + &dma_addr, 0); + gsi_channel_props.ring_base_addr = dma_addr; + gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + gsi_channel_props.max_prefetch = GSI_ONE_PREFETCH_SEG; + gsi_channel_props.low_weight = 1; + gsi_channel_props.err_cb = ipa_gsi_chan_err_cb; + gsi_channel_props.xfer_cb = ipa_gsi_irq_tx_notify_cb; + + /* first allocate channels up to channel 20 */ + for (i = 0; i < IPA_GSI_CH_20_WA_NUM_CH_TO_ALLOC; i++) { + gsi_channel_props.ch_id = i; + result = gsi_alloc_channel(&gsi_channel_props, + ipa3_ctx->gsi_dev_hdl, + &chan_hdl[i]); + if (result != GSI_STATUS_SUCCESS) { + IPAERR("failed to alloc channel %d err %d\n", + i, result); + return result; + } + } + + /* allocate channel 20 */ + gsi_channel_props.ch_id = IPA_GSI_CH_20_WA_VIRT_CHAN; + result = gsi_alloc_channel(&gsi_channel_props, ipa3_ctx->gsi_dev_hdl, + &chan_hdl_to_keep); + if (result != GSI_STATUS_SUCCESS) { + IPAERR("failed to alloc channel %d err %d\n", + i, result); + return result; + } + + /* release all other channels */ + for (i = 0; i < IPA_GSI_CH_20_WA_NUM_CH_TO_ALLOC; i++) { + result = gsi_dealloc_channel(chan_hdl[i]); + if (result != GSI_STATUS_SUCCESS) { + IPAERR("failed to dealloc channel %d err %d\n", + i, result); + return result; + } + } + + /* DMA memory shall not be freed as it is used by channel 20 */ + return 0; +} diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 2331adb8d7e1..72222d19d928 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1348,6 +1348,7 @@ struct ipa3_ready_cb_info { * @ipa_num_pipes: The number of pipes used by IPA HW * @skip_uc_pipe_reset: Indicates whether pipe reset via uC needs to be avoided * @apply_rg10_wa: Indicates whether to use register group 10 workaround + * @gsi_ch20_wa: Indicates whether to apply GSI physical channel 20 workaround * @w_lock: Indicates the wakeup source. * @wakelock_ref_cnt: Indicates the number of times wakelock is acquired * @ipa_initialization_complete: Indicates that IPA is fully initialized @@ -1460,6 +1461,7 @@ struct ipa3_context { unsigned long gsi_dev_hdl; u32 ee; bool apply_rg10_wa; + bool gsi_ch20_wa; bool smmu_present; bool smmu_s1_bypass; unsigned long peer_bam_iova; @@ -1513,6 +1515,7 @@ struct ipa3_plat_drv_res { bool skip_uc_pipe_reset; enum ipa_transport_type transport_prototype; bool apply_rg10_wa; + bool gsi_ch20_wa; bool tethered_flow_control; }; @@ -2181,4 +2184,5 @@ void ipa3_dec_release_wakelock(void); int ipa3_load_fws(const struct firmware *firmware); int ipa3_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data); const char *ipa_hw_error_str(enum ipa3_hw_errors err_type); +int ipa_gsi_ch20_wa(void); #endif /* _IPA3_I_H_ */ |