msm: ipa3: WA for incorrect state retention for GSI channel 20

This change in a software workaround for a hardware limitation
to not use GSI channel 20.

CRs-Fixed: 1005061
Change-Id: I4ed9f1c6ad089f80dcd19762fda151ce1572f471
Acked-by: Ady Abraham <adya@qti.qualcomm.com>
Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
This commit is contained in:
Skylar Chang 2016-05-17 15:27:19 -07:00 committed by Kyle Yan
parent e454b281ea
commit 1461f9a12d
4 changed files with 101 additions and 2 deletions

View file

@ -65,7 +65,9 @@ memory allocation over a PCIe bridge
- qcom,use-rg10-limitation-mitigation: Boolean context flag to activate - qcom,use-rg10-limitation-mitigation: Boolean context flag to activate
the mitigation to register group 10 the mitigation to register group 10
AP access limitation 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 - qcom,tethered-flow-control: Boolean context flag to indicate whether
apps based flow control is needed for tethered apps based flow control is needed for tethered
call. call.

View file

@ -2634,6 +2634,15 @@ static int ipa3_setup_apps_pipes(void)
struct ipa_sys_connect_params sys_in; struct ipa_sys_connect_params sys_in;
int result = 0; 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) */ /* CMD OUT (AP->IPA) */
memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params)); memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
sys_in.client = IPA_CLIENT_APPS_CMD_PROD; 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->transport_prototype = resource_p->transport_prototype;
ipa3_ctx->ee = resource_p->ee; ipa3_ctx->ee = resource_p->ee;
ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa; 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; ipa3_ctx->ipa3_active_clients_logging.log_rdy = false;
/* default aggregation parameters */ /* 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->ipa_wdi2 = false;
ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ; ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ;
ipa_drv_res->apply_rg10_wa = false; 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, smmu_disable_htw = of_property_read_bool(pdev->dev.of_node,
"qcom,smmu-disable-htw"); "qcom,smmu-disable-htw");
@ -4667,6 +4678,13 @@ static int get_ipa_dts_configuration(struct platform_device *pdev,
ipa_drv_res->apply_rg10_wa ipa_drv_res->apply_rg10_wa
? "True" : "False"); ? "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; return 0;
} }

View file

@ -55,6 +55,10 @@
#define IPA_GSI_MAX_CH_LOW_WEIGHT 15 #define IPA_GSI_MAX_CH_LOW_WEIGHT 15
#define IPA_GSI_EVT_RING_INT_MODT 3200 /* 0.1s under 32KHz clock */ #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 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_wlan_rx_cache(struct ipa3_sys_context *sys);
static void ipa3_replenish_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, static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
struct ipa3_ep_context *ep) 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; 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;
}

View file

@ -1348,6 +1348,7 @@ struct ipa3_ready_cb_info {
* @ipa_num_pipes: The number of pipes used by IPA HW * @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 * @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 * @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. * @w_lock: Indicates the wakeup source.
* @wakelock_ref_cnt: Indicates the number of times wakelock is acquired * @wakelock_ref_cnt: Indicates the number of times wakelock is acquired
* @ipa_initialization_complete: Indicates that IPA is fully initialized * @ipa_initialization_complete: Indicates that IPA is fully initialized
@ -1460,6 +1461,7 @@ struct ipa3_context {
unsigned long gsi_dev_hdl; unsigned long gsi_dev_hdl;
u32 ee; u32 ee;
bool apply_rg10_wa; bool apply_rg10_wa;
bool gsi_ch20_wa;
bool smmu_present; bool smmu_present;
bool smmu_s1_bypass; bool smmu_s1_bypass;
unsigned long peer_bam_iova; unsigned long peer_bam_iova;
@ -1513,6 +1515,7 @@ struct ipa3_plat_drv_res {
bool skip_uc_pipe_reset; bool skip_uc_pipe_reset;
enum ipa_transport_type transport_prototype; enum ipa_transport_type transport_prototype;
bool apply_rg10_wa; bool apply_rg10_wa;
bool gsi_ch20_wa;
bool tethered_flow_control; bool tethered_flow_control;
}; };
@ -2181,4 +2184,5 @@ void ipa3_dec_release_wakelock(void);
int ipa3_load_fws(const struct firmware *firmware); int ipa3_load_fws(const struct firmware *firmware);
int ipa3_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data); 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); const char *ipa_hw_error_str(enum ipa3_hw_errors err_type);
int ipa_gsi_ch20_wa(void);
#endif /* _IPA3_I_H_ */ #endif /* _IPA3_I_H_ */