diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 25eebad4b618..dde7e7b80a34 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -3260,4 +3260,10 @@ static inline void *alloc_and_init(u32 size, u32 init_val) bool ipa3_is_apq(void); /* check if odl is connected */ bool ipa3_is_odl_connected(void); + +int ipa3_uc_send_enable_flow_control(uint16_t gsi_chid, + uint16_t redMarkerThreshold); +int ipa3_uc_send_disable_flow_control(void); +int ipa3_uc_send_update_flow_control(uint32_t bitmask, + uint8_t add_delete); #endif /* _IPA3_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c index 3a97943ebc84..55bfee20a3a1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c @@ -71,6 +71,8 @@ #define IPA_CHANNEL_STOP_IN_PROC_TO_MSEC 5 #define IPA_CHANNEL_STOP_IN_PROC_SLEEP_USEC 200 #define IPA_MHIP_HOLB_TMO 31 /* value to match granularity on ipa HW 4.5 */ +#define IPA_MPM_FLOW_CTRL_ADD 1 +#define IPA_MPM_FLOW_CTRL_DELETE 0 enum mhip_re_type { MHIP_RE_XFER = 0x2, @@ -393,6 +395,7 @@ struct ipa_mpm_context { atomic_t probe_cnt; atomic_t pcie_clk_total_cnt; atomic_t ipa_clk_total_cnt; + atomic_t flow_ctrl_mask; atomic_t adpl_over_usb_available; struct device *parent_pdev; struct ipa_smmu_cb_ctx carved_smmu_cb; @@ -1719,6 +1722,8 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state) int ret = 0; enum ipa_mpm_mhip_client_type mhip_client = IPA_MPM_MHIP_TETH; bool is_acted = true; + const struct ipa_gsi_ep_config *ep_cfg; + uint32_t flow_ctrl_mask = 0; if (!state) return -EPERM; @@ -1775,6 +1780,35 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state) } IPA_MPM_DBG("MHIP remote channels are started\n"); + /* + * Update flow control monitoring end point info. + * This info will be used to set delay on the end points upon + * hitting RED water mark. + */ + ep_cfg = ipa3_get_gsi_ep_info(IPA_CLIENT_WLAN2_PROD); + + if (!ep_cfg) + IPA_MPM_ERR("ep = %d not allocated yet\n", + IPA_CLIENT_WLAN2_PROD); + else + flow_ctrl_mask |= 1 << (ep_cfg->ipa_gsi_chan_num); + + ep_cfg = ipa3_get_gsi_ep_info(IPA_CLIENT_USB_PROD); + + if (!ep_cfg) + IPA_MPM_ERR("ep = %d not allocated yet\n", + IPA_CLIENT_USB_PROD); + else + flow_ctrl_mask |= 1 << (ep_cfg->ipa_gsi_chan_num); + + atomic_set(&ipa_mpm_ctx->flow_ctrl_mask, flow_ctrl_mask); + + ret = ipa3_uc_send_update_flow_control(flow_ctrl_mask, + IPA_MPM_FLOW_CTRL_ADD); + + if (ret) + IPA_MPM_ERR("Err = %d setting uc flow control\n", ret); + status = ipa_mpm_start_stop_mhip_chan( IPA_MPM_MHIP_CHAN_UL, probe_id, MPM_MHIP_START); switch (status) { @@ -1812,6 +1846,23 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state) } ipa_mpm_ctx->md[probe_id].mhip_client = mhip_client; } else { + /* + * Update flow control monitoring end point info. + * This info will be used to reset delay on the end points. + */ + flow_ctrl_mask = + atomic_read(&ipa_mpm_ctx->flow_ctrl_mask); + + ret = ipa3_uc_send_update_flow_control(flow_ctrl_mask, + IPA_MPM_FLOW_CTRL_DELETE); + flow_ctrl_mask = 0; + atomic_set(&ipa_mpm_ctx->flow_ctrl_mask, 0); + + if (ret) { + IPA_MPM_ERR("Err = %d resetting uc flow control\n", + ret); + ipa_assert(); + } /* * Make sure to stop Device side channels before * stopping Host side UL channels. This is to make @@ -1968,6 +2019,8 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev, u32 wp_addr; int pipe_idx; bool is_acted = true; + uint64_t flow_ctrl_mask = 0; + bool add_delete = false; IPA_MPM_FUNC_ENTRY(); @@ -2348,6 +2401,27 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev, mutex_lock(&ipa_mpm_ctx->md[probe_id].mhi_mutex); ipa_mpm_ctx->md[probe_id].init_complete = true; mutex_unlock(&ipa_mpm_ctx->md[probe_id].mhi_mutex); + /* Update Flow control Monitoring, only for the teth UL Prod pipes */ + if (probe_id == IPA_MPM_MHIP_CH_ID_0) { + ipa_ep_idx = ipa3_get_ep_mapping(ul_prod); + ep = &ipa3_ctx->ep[ipa_ep_idx]; + ret = ipa3_uc_send_enable_flow_control(ep->gsi_chan_hdl, + IPA_MPM_RING_LEN / 4); + if (ret) { + IPA_MPM_ERR("Err %d flow control enable\n", ret); + goto fail_flow_control; + } + IPA_MPM_DBG("Flow Control enabled for %d", probe_id); + flow_ctrl_mask = atomic_read(&ipa_mpm_ctx->flow_ctrl_mask); + add_delete = flow_ctrl_mask > 0 ? 1 : 0; + ret = ipa3_uc_send_update_flow_control(flow_ctrl_mask, + add_delete); + if (ret) { + IPA_MPM_ERR("Err %d flow control update\n", ret); + goto fail_flow_control; + } + IPA_MPM_DBG("Flow Control updated for %d", probe_id); + } IPA_MPM_FUNC_EXIT(); return 0; @@ -2355,6 +2429,7 @@ fail_gsi_setup: fail_start_channel: fail_stop_channel: fail_smmu: +fail_flow_control: if (ipa_mpm_ctx->dev_info.ipa_smmu_enabled) IPA_MPM_DBG("SMMU failed\n"); if (is_acted) @@ -2424,6 +2499,9 @@ static void ipa_mpm_mhi_remove_cb(struct mhi_device *mhi_dev) ipa_mpm_ctx->md[mhip_idx].init_complete = false; mutex_unlock(&ipa_mpm_ctx->md[mhip_idx].mhi_mutex); + if (mhip_idx == IPA_MPM_MHIP_CH_ID_0) + ipa3_uc_send_disable_flow_control(); + ipa_mpm_mhip_shutdown(mhip_idx); atomic_dec(&ipa_mpm_ctx->probe_cnt); @@ -2909,6 +2987,7 @@ static int ipa_mpm_probe(struct platform_device *pdev) atomic_set(&ipa_mpm_ctx->ipa_clk_total_cnt, 0); atomic_set(&ipa_mpm_ctx->pcie_clk_total_cnt, 0); + atomic_set(&ipa_mpm_ctx->flow_ctrl_mask, 0); for (idx = 0; idx < IPA_MPM_MHIP_CH_ID_MAX; idx++) { ipa_mpm_ctx->md[idx].ul_prod.gsi_state = GSI_INIT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c index dc63a5da37eb..403b279fe3d7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c @@ -45,6 +45,10 @@ * IPA_CPU_2_HW_CMD_GSI_CH_EMPTY : Command to check for GSI channel emptiness. * IPA_CPU_2_HW_CMD_REMOTE_IPA_INFO: Command to store remote IPA Info * IPA_CPU_2_HW_CMD_SETUP_EVENT_RING: Command to setup the event ring + * IPA_CPU_2_HW_CMD_ENABLE_FLOW_CTL_MONITOR: Command to enable pipe monitoring. + * IPA_CPU_2_HW_CMD_UPDATE_FLOW_CTL_MONITOR: Command to update pipes to monitor. + * IPA_CPU_2_HW_CMD_DISABLE_FLOW_CTL_MONITOR: Command to disable pipe + monitoring, no parameter required. */ enum ipa3_cpu_2_hw_commands { IPA_CPU_2_HW_CMD_NO_OP = @@ -73,6 +77,13 @@ enum ipa3_cpu_2_hw_commands { FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 11), IPA_CPU_2_HW_CMD_SETUP_EVENT_RING = FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 12), + IPA_CPU_2_HW_CMD_ENABLE_FLOW_CTL_MONITOR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 13), + IPA_CPU_2_HW_CMD_UPDATE_FLOW_CTL_MONITOR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 14), + IPA_CPU_2_HW_CMD_DISABLE_FLOW_CTL_MONITOR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 15), + }; /** @@ -198,6 +209,36 @@ struct IpaHwDbAddrInfo_t { uint32_t mboxN; } __packed; + +/** + * Structure holding the parameters for IPA_CPU_2_HW_CMD_ENABLE_PIPE_MONITOR + * command. + * @ipaProdGsiChid IPA prod GSI chid to monitor + * @redMarkerThreshold red marker threshold in elements for the GSI channel + */ +union IpaEnablePipeMonitorCmdData_t { + struct IpaEnablePipeMonitorCmdParams_t { + u32 ipaProdGsiChid:16; + u32 redMarkerThreshold:16; + } __packed params; + u32 raw32b; +} __packed; + +/** + * Structure holding the parameters for IPA_CPU_2_HW_CMD_UPDATE_PIPE_MONITOR + * command. + * + * @bitmask The parameter of bitmask to add/delete channels/pipes from + * global monitoring pipemask + * IPA pipe# bitmask or GSI chid bitmask + * add_delete 1: add pipes to monitor + * 0: delete pipes to monitor + */ +struct IpaUpdateFlowCtlMonitorData_t { + u32 bitmask; + u8 add_delete; +}; + static DEFINE_MUTEX(uc_loaded_nb_lock); static BLOCKING_NOTIFIER_HEAD(uc_loaded_notifier); @@ -1484,3 +1525,65 @@ int ipa3_set_wlan_tx_info(struct ipa_wdi_tx_info *info) return 0; } + +int ipa3_uc_send_enable_flow_control(uint16_t gsi_chid, + uint16_t redMarkerThreshold) +{ + + int res; + union IpaEnablePipeMonitorCmdData_t cmd; + + cmd.params.ipaProdGsiChid = gsi_chid; + cmd.params.redMarkerThreshold = redMarkerThreshold; + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + res = ipa3_uc_send_cmd((cmd.raw32b), + IPA_CPU_2_HW_CMD_ENABLE_FLOW_CTL_MONITOR, 0, + false, 10 * HZ); + + if (res) + IPAERR("fail to enable flow ctrl for 0x%x\n", + cmd.params.ipaProdGsiChid); + + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return res; +} + +int ipa3_uc_send_disable_flow_control(void) +{ + int res; + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + res = ipa3_uc_send_cmd(0, + IPA_CPU_2_HW_CMD_DISABLE_FLOW_CTL_MONITOR, 0, + false, 10 * HZ); + + if (res) + IPAERR("fail to disable flow control\n"); + + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return res; +} + +int ipa3_uc_send_update_flow_control(uint32_t bitmask, + uint8_t add_delete) +{ + int res; + + if (bitmask == 0) { + IPAERR("Err update flow control, mask = 0\n"); + return 0; + } + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + res = ipa3_uc_send_cmd_64b_param(bitmask, add_delete, + IPA_CPU_2_HW_CMD_UPDATE_FLOW_CTL_MONITOR, 0, + false, 10 * HZ); + + if (res) + IPAERR("fail flowCtrl update mask = 0x%x add_del = 0x%x\n", + bitmask, add_delete); + + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return res; +}