diff --git a/drivers/platform/msm/ipa/Makefile b/drivers/platform/msm/ipa/Makefile index 1e60bd3f866a..4d1add2067df 100644 --- a/drivers/platform/msm/ipa/Makefile +++ b/drivers/platform/msm/ipa/Makefile @@ -25,6 +25,7 @@ ipam-y += \ ipa_v3/ipa_wdi3_i.o \ ipa_v3/ipa_odl.o \ ipa_v3/ipa_wigig_i.o \ + ipa_v3/ipa_uc_holb_monitor.o \ ipa_v3/ipahal/ipahal.o \ ipa_v3/ipahal/ipahal_reg.o \ ipa_v3/ipahal/ipahal_fltrt.o \ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 3a7aa394bdf2..cffd9a64b886 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -6056,8 +6056,8 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, IPAERR(":ipa Uc interface init failed (%d)\n", -result); else IPADBG(":ipa Uc interface init ok\n"); - uc_hdlrs.ipa_uc_loaded_hdlr = ipa3_uc_is_loaded; + uc_hdlrs.ipa_uc_holb_enabled_hdlr = ipa3_uc_holb_client_handler; ipa3_uc_register_handlers(IPA_HW_FEATURE_COMMON, &uc_hdlrs); result = ipa3_wdi_init(); @@ -6653,6 +6653,16 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->wan_rx_ring_size = resource_p->wan_rx_ring_size; ipa3_ctx->lan_rx_ring_size = resource_p->lan_rx_ring_size; ipa3_ctx->ipa_wan_skb_page = resource_p->ipa_wan_skb_page; + ipa3_ctx->uc_ctx.ipa_use_uc_holb_monitor = + resource_p->ipa_use_uc_holb_monitor; + ipa3_ctx->uc_ctx.holb_monitor.poll_period = + resource_p->ipa_holb_monitor_poll_period; + ipa3_ctx->uc_ctx.holb_monitor.max_cnt_wlan = + resource_p->ipa_holb_monitor_max_cnt_wlan; + ipa3_ctx->uc_ctx.holb_monitor.max_cnt_usb = + resource_p->ipa_holb_monitor_max_cnt_usb; + ipa3_ctx->uc_ctx.holb_monitor.max_cnt_11ad = + resource_p->ipa_holb_monitor_max_cnt_11ad; ipa3_ctx->stats.page_recycle_stats[0].total_replenished = 0; ipa3_ctx->stats.page_recycle_stats[0].tmp_alloc = 0; ipa3_ctx->stats.page_recycle_stats[1].total_replenished = 0; @@ -7414,6 +7424,10 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, u32 *ipa_tz_unlock_reg; int elem_num; u32 mhi_evid_limits[2]; + u32 ipa_holb_monitor_poll_period; + u32 ipa_holb_monitor_max_cnt_wlan; + u32 ipa_holb_monitor_max_cnt_usb; + u32 ipa_holb_monitor_max_cnt_11ad; /* initialize ipa3_res */ ipa_drv_res->ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST; @@ -7424,6 +7438,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->modem_cfg_emb_pipe_flt = false; ipa_drv_res->ipa_wdi2 = false; ipa_drv_res->ipa_wan_skb_page = false; + ipa_drv_res->ipa_use_uc_holb_monitor = false; ipa_drv_res->ipa_wdi2_over_gsi = false; ipa_drv_res->ipa_wdi3_over_gsi = false; ipa_drv_res->ipa_mhi_dynamic_config = false; @@ -7553,6 +7568,74 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->ipa_wan_skb_page ? "True" : "False"); + ipa_drv_res->ipa_use_uc_holb_monitor = + of_property_read_bool(pdev->dev.of_node, + "qcom,ipa-uc-holb-monitor"); + IPADBG(": uC HOLB monitor = %s\n", + ipa_drv_res->ipa_use_uc_holb_monitor + ? "True" : "False"); + + /* Get HOLB Monitor Polling Period */ + result = of_property_read_u32(pdev->dev.of_node, + "qcom,ipa-holb-monitor-poll-period", + &ipa_holb_monitor_poll_period); + if (result) { + IPADBG("ipa holb monitor poll period = %u\n", + IPA_HOLB_POLLING_PERIOD_MS); + ipa_holb_monitor_poll_period = IPA_HOLB_POLLING_PERIOD_MS; + } else + IPADBG("ipa holb monitor poll period = %u\n", + ipa_holb_monitor_poll_period); + + ipa_drv_res->ipa_holb_monitor_poll_period = + ipa_holb_monitor_poll_period; + + /* Get HOLB Monitor Max Stuck Cnt Values */ + result = of_property_read_u32(pdev->dev.of_node, + "qcom,ipa-holb-monitor-max-cnt-wlan", + &ipa_holb_monitor_max_cnt_wlan); + if (result) { + IPADBG("ipa holb monitor max count wlan = %u\n", + IPA_HOLB_MONITOR_MAX_STUCK_COUNT); + ipa_holb_monitor_max_cnt_wlan = + IPA_HOLB_MONITOR_MAX_STUCK_COUNT; + } else + IPADBG("ipa holb monitor max count wlan = %u\n", + ipa_holb_monitor_max_cnt_wlan); + + ipa_drv_res->ipa_holb_monitor_max_cnt_wlan = + ipa_holb_monitor_max_cnt_wlan; + + result = of_property_read_u32(pdev->dev.of_node, + "qcom,ipa-holb-monitor-max-cnt-usb", + &ipa_holb_monitor_max_cnt_usb); + if (result) { + IPADBG("ipa holb monitor max count usb = %u\n", + IPA_HOLB_MONITOR_MAX_STUCK_COUNT); + ipa_holb_monitor_max_cnt_usb = + IPA_HOLB_MONITOR_MAX_STUCK_COUNT; + } else + IPADBG("ipa holb monitor max count usb = %u\n", + ipa_holb_monitor_max_cnt_usb); + + ipa_drv_res->ipa_holb_monitor_max_cnt_usb = + ipa_holb_monitor_max_cnt_usb; + + result = of_property_read_u32(pdev->dev.of_node, + "qcom,ipa-holb-monitor-max-cnt-11ad", + &ipa_holb_monitor_max_cnt_11ad); + if (result) { + IPADBG("ipa holb monitor max count 11ad = %u\n", + IPA_HOLB_MONITOR_MAX_STUCK_COUNT); + ipa_holb_monitor_max_cnt_11ad = + IPA_HOLB_MONITOR_MAX_STUCK_COUNT; + } else + IPADBG("ipa holb monitor max count 11ad = %u\n", + ipa_holb_monitor_max_cnt_11ad); + + ipa_drv_res->ipa_holb_monitor_max_cnt_11ad = + ipa_holb_monitor_max_cnt_11ad; + ipa_drv_res->ipa_fltrt_not_hashable = of_property_read_bool(pdev->dev.of_node, "qcom,ipa-fltrt-not-hashable"); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index f12a23a57a1f..7e2494454027 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -824,6 +824,7 @@ int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid) int result = -EFAULT; enum gsi_status gsi_res; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; + u32 holb_max_cnt = ipa3_ctx->uc_ctx.holb_monitor.max_cnt_usb; IPADBG("entry\n"); if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || @@ -866,6 +867,16 @@ int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid) IPAERR("Error starting channel: %d\n", gsi_res); goto write_chan_scratch_fail; } + + if (IPA_CLIENT_IS_HOLB_CONS(ep->client)) { + result = ipa3_uc_client_add_holb_monitor(ep->gsi_chan_hdl, + HOLB_MONITOR_MASK, + holb_max_cnt, IPA_EE_AP); + if (result) + IPAERR("Add HOLB monitor failed for gsi ch %d\n", + ep->gsi_chan_hdl); + } + ipa3_start_gsi_debug_monitor(clnt_hdl); if (!ep->keep_ipa_awake) IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); @@ -1520,6 +1531,8 @@ int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, struct gsi_chan_info ul_gsi_chan_info, dl_gsi_chan_info; int aggr_active_bitmap = 0; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; + u32 holb_max_cnt = ipa3_ctx->uc_ctx.holb_monitor.max_cnt_usb; + int res = 0; /* In case of DPL, dl is the DPL channel/client */ @@ -1633,6 +1646,14 @@ int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, start_dl_and_exit: gsi_start_channel(dl_ep->gsi_chan_hdl); + if (IPA_CLIENT_IS_HOLB_CONS(dl_ep->client)) { + res = ipa3_uc_client_add_holb_monitor(dl_ep->gsi_chan_hdl, + HOLB_MONITOR_MASK, holb_max_cnt, + IPA_EE_AP); + if (res) + IPAERR("Add HOLB monitor failed for gsi ch %d\n", + dl_ep->gsi_chan_hdl); + } ipa3_start_gsi_debug_monitor(dl_clnt_hdl); unsuspend_dl_and_exit: if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) { @@ -1653,6 +1674,8 @@ int ipa3_start_gsi_channel(u32 clnt_hdl) int result = -EFAULT; enum gsi_status gsi_res; enum ipa_client_type client_type; + int res = 0; + u32 holb_max_cnt = ipa3_ctx->uc_ctx.holb_monitor.max_cnt_usb; IPADBG("entry\n"); if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || @@ -1671,6 +1694,14 @@ int ipa3_start_gsi_channel(u32 clnt_hdl) IPAERR("Error starting channel: %d\n", gsi_res); goto start_chan_fail; } + if (IPA_CLIENT_IS_HOLB_CONS(ep->client)) { + res = ipa3_uc_client_add_holb_monitor(ep->gsi_chan_hdl, + HOLB_MONITOR_MASK, + holb_max_cnt, IPA_EE_AP); + if (res) + IPAERR("Add HOLB monitor failed for gsi ch %d\n", + ep->gsi_chan_hdl); + } ipa3_start_gsi_debug_monitor(clnt_hdl); if (!ep->keep_ipa_awake) @@ -1692,6 +1723,8 @@ int ipa3_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool is_dpl) struct ipa3_ep_context *dl_ep = NULL; enum gsi_status gsi_res; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; + int result; + u32 holb_max_cnt = ipa3_ctx->uc_ctx.holb_monitor.max_cnt_usb; /* In case of DPL, dl is the DPL channel/client */ @@ -1720,6 +1753,14 @@ int ipa3_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool is_dpl) gsi_res = gsi_start_channel(dl_ep->gsi_chan_hdl); if (gsi_res != GSI_STATUS_SUCCESS) IPAERR("Error starting DL channel: %d\n", gsi_res); + if (!is_dpl) { + result = ipa3_uc_client_add_holb_monitor(dl_ep->gsi_chan_hdl, + HOLB_MONITOR_MASK, + holb_max_cnt, IPA_EE_AP); + if (result) + IPAERR("Add HOLB monitor failed for gsi ch %d\n", + dl_ep->gsi_chan_hdl); + } ipa3_start_gsi_debug_monitor(dl_clnt_hdl); /* Start UL channel */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 84bddff691fb..2a507c9344b4 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -186,6 +186,117 @@ static ssize_t ipa3_write_ep_holb(struct file *file, return count; } +static ssize_t ipa3_write_holb_monitor_client(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct ipa_uc_holb_client_info holb_client; + u32 max_stuck_cnt; + u16 gsi_ch; + u8 set_client; + unsigned long missing; + char *sptr, *token; + + if (count >= sizeof(dbg_buff)) + return -EFAULT; + + missing = copy_from_user(dbg_buff, buf, count); + if (missing) + return -EFAULT; + + dbg_buff[count] = '\0'; + + sptr = dbg_buff; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou16(token, 0, &gsi_ch)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &max_stuck_cnt)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &set_client)) + return -EINVAL; + + holb_client.gsi_chan_hdl = gsi_ch; + holb_client.debugfs_param = set_client; + holb_client.max_stuck_cnt = max_stuck_cnt; + holb_client.action_mask = HOLB_MONITOR_MASK; + holb_client.ee = IPA_EE_AP; + + + ipa3_set_holb_client_by_ch(holb_client); + + return count; +} + +static ssize_t ipa3_write_holb_monitor_client_add_del(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + u32 max_stuck_cnt, action_mask; + u16 gsi_ch; + u8 ee, add_client; + + unsigned long missing; + char *sptr, *token; + + if (count >= sizeof(dbg_buff)) + return -EFAULT; + + missing = copy_from_user(dbg_buff, buf, count); + if (missing) + return -EFAULT; + + dbg_buff[count] = '\0'; + + sptr = dbg_buff; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou16(token, 0, &gsi_ch)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &action_mask)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &max_stuck_cnt)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &ee)) + return -EINVAL; + + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &add_client)) + return -EINVAL; + + if (add_client) + ipa3_uc_client_add_holb_monitor(gsi_ch, action_mask, + max_stuck_cnt, ee); + else + ipa3_uc_client_del_holb_monitor(gsi_ch, ee); + + return count; +} static ssize_t ipa3_write_ep_reg(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -2856,6 +2967,14 @@ static const struct ipa3_debugfs_file debugfs_files[] = { "holb", IPA_WRITE_ONLY_MODE, NULL, { .write = ipa3_write_ep_holb, } + }, { + "holb_monitor_client_param", IPA_WRITE_ONLY_MODE, NULL, { + .write = ipa3_write_holb_monitor_client, + } + }, { + "holb_monitor_client_add_del", IPA_WRITE_ONLY_MODE, NULL, { + .write = ipa3_write_holb_monitor_client_add_del, + } }, { "hdr", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_hdr, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 48ef4909d2da..77fd0b652fc1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -36,6 +36,7 @@ #include #include #include +#include "ipa_uc_holb_monitor.h" #define IPA_DEV_NAME_MAX_LEN 15 #define DRV_NAME "ipa" @@ -1444,12 +1445,19 @@ struct ipa3_tag_completion { struct ipa3_controller; +enum ipa_ees { + IPA_EE_AP = 0, + IPA_EE_Q6 = 1, + IPA_EE_UC = 2, +}; + /** * struct ipa3_uc_hdlrs - IPA uC callback functions * @ipa_uc_loaded_hdlr: Function handler when uC is loaded * @ipa_uc_event_hdlr: Event handler function * @ipa3_uc_response_hdlr: Response handler function * @ipa_uc_event_log_info_hdlr: Log event handler function + * @ipa_uc_holb_enabled_hdlr: Function handler when uC HOLB is enabled */ struct ipa3_uc_hdlrs { void (*ipa_uc_loaded_hdlr)(void); @@ -1463,6 +1471,8 @@ struct ipa3_uc_hdlrs { void (*ipa_uc_event_log_info_hdlr) (struct IpaHwEventLogInfoData_t *uc_event_top_mmio); + + void (*ipa_uc_holb_enabled_hdlr)(void); }; /** @@ -1497,6 +1507,7 @@ enum ipa3_hw_flags { * @uc_inited: Indicates if uC interface has been initialized * @uc_loaded: Indicates if uC has loaded * @uc_failed: Indicates if uC has failed / returned an error + * @uc_holb_enabled: Indicates if uC HOLB enable cmd is sent. * @uc_lock: uC interface lock to allow only one uC interaction at a time * @uc_spinlock: same as uc_lock but for irq contexts * @uc_completation: Completion mechanism to wait for uC commands @@ -1505,11 +1516,14 @@ enum ipa3_hw_flags { * @uc_status: The last status provided by the uC * @uc_error_type: error type from uC error event * @uc_error_timestamp: tag timer sampled after uC crashed + * @ipa_use_uc_holb_monitor: Indicates if uC HOLB feature is enabled + * @ipa_holb_monitor: Struct with all info needed for uC HOLB feature */ struct ipa3_uc_ctx { bool uc_inited; bool uc_loaded; bool uc_failed; + bool uc_holb_enabled; struct mutex uc_lock; spinlock_t uc_spinlock; struct completion uc_completion; @@ -1534,6 +1548,8 @@ struct ipa3_uc_ctx { u32 ering_rp_local; u32 ering_wp; u32 ering_rp; + bool ipa_use_uc_holb_monitor; + struct ipa_holb_monitor holb_monitor; }; /** @@ -2124,6 +2140,11 @@ struct ipa3_plat_drv_res { const char *icc_path_name[IPA_ICC_PATH_MAX]; u32 icc_clk_val[IPA_ICC_LVL_MAX][IPA_ICC_MAX]; bool rmnet_ctl_enable; + bool ipa_use_uc_holb_monitor; + u32 ipa_holb_monitor_poll_period; + u32 ipa_holb_monitor_max_cnt_wlan; + u32 ipa_holb_monitor_max_cnt_usb; + u32 ipa_holb_monitor_max_cnt_11ad; const char *gsi_fw_file_name; const char *uc_fw_file_name; u32 tx_wrapper_cache_max_size; @@ -3006,6 +3027,7 @@ int ipa3_uc_interface_init(void); int ipa3_uc_is_gsi_channel_empty(enum ipa_client_type ipa_client); int ipa3_uc_state_check(void); int ipa3_uc_loaded_check(void); +int ipa3_uc_holb_enabled_check(void); int ipa3_uc_register_ready_cb(struct notifier_block *nb); int ipa3_uc_unregister_ready_cb(struct notifier_block *nb); int ipa3_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status, @@ -3039,6 +3061,11 @@ int ipa3_uc_debug_stats_alloc( struct IpaHwOffloadStatsAllocCmdData_t cmdinfo); int ipa3_uc_debug_stats_dealloc(uint32_t protocol); int ipa3_uc_quota_monitor(uint64_t quota); +int ipa3_uc_enable_holb_monitor(uint32_t polling_period); +int ipa3_uc_add_holb_monitor(uint16_t gsi_ch, uint32_t action_mask, + uint32_t max_stuck_count, uint8_t ee); +int ipa3_uc_del_holb_monitor(uint16_t gsi_ch, uint8_t ee); +int ipa3_uc_disable_holb_monitor(void); int ipa3_uc_bw_monitor(struct ipa_wdi_bw_info *info); int ipa3_uc_setup_event_ring(void); int ipa3_set_wlan_tx_info(struct ipa_wdi_tx_info *info); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c index 63ddd25bb855..2a751853ab3e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c @@ -28,6 +28,7 @@ #define IPA_UC_ERING_n_r 1 #define IPA_UC_ERING_n_w 0 #define IPA_UC_MON_INTERVAL 5 +#define IPA_UC_HOLB_WORKQUEUE_NAME "ipa_uc_holb_wq" /** * enum ipa3_cpu_2_hw_commands - Values that represent the commands from the CPU @@ -49,6 +50,12 @@ * 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. + * IPA_CPU_2_HW_CMD_ENABLE_HOLB_MONITOR: Command to enable HOLB monitoring. + * IPA_CPU_2_HW_CMD_ADD_HOLB_MONITOR: Command to add GSI channel to HOLB + * monitor. + * IPA_CPU_2_HW_CMD_DEL_HOLB_MONITOR: Command to delete GSI channel to HOLB + * monitor. + * IPA_CPU_2_HW_CMD_DISABLE_HOLB_MONITOR: Command to disable HOLB monitoring. */ enum ipa3_cpu_2_hw_commands { IPA_CPU_2_HW_CMD_NO_OP = @@ -83,7 +90,14 @@ enum ipa3_cpu_2_hw_commands { 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), - + IPA_CPU_2_HW_CMD_ENABLE_HOLB_MONITOR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 17), + IPA_CPU_2_HW_CMD_ADD_HOLB_MONITOR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 18), + IPA_CPU_2_HW_CMD_DEL_HOLB_MONITOR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 19), + IPA_CPU_2_HW_CMD_DISABLE_HOLB_MONITOR = + FEATURE_ENUM_VAL(IPA_HW_FEATURE_COMMON, 20), }; /** @@ -239,9 +253,64 @@ struct IpaUpdateFlowCtlMonitorData_t { u8 add_delete; }; +/** + * @brief Structure holding the parameter for + * IPA_CPU_2_HW_CMD_ENABLE_HOLB_MONITOR command: HOLB + * monitor polling period in ms (expected range min: + * 5ms, max: 50ms) + */ +union IpaEnableHolbMonitorCmdData_t { + struct IpaEnableHolbMonitorParams_t { + uint32_t holbMonitorPollingPeriod; + } params; + uint32_t raw32b; +} __packed; + +/** + * @brief Structure holding the parameters for + * IPA_CPU_2_HW_CMD_ADD_HOLB_MONITOR command + * + * @param ipaProdGsiChid GSI chid to be HOLB monitored + * @param EE EE that the chid belongs to + * @param holbActionMask bit0: uC enables HOLB on + * corresponding pipe with timer = 0 + * bit1: Notify AP of bad chid + * bits can be set independently or + * together + * @param maxStuckSampleCnt Max stuck sample count before + * taking action + */ +union IpaAddHolbMonitorCmdData_t { + struct IpaAddHolbMonitorParams_t { + uint32_t ipaProdGsiChid :8; + uint32_t EE :8; + uint32_t holbActionMask :8; + uint32_t maxStuckSampleCnt :8; + } __packed params; + uint32_t raw32b; +} __packed; + +/** + * @brief Structure holding the parameters for + * IPA_CPU_2_HW_CMD_DEL_HOLB_MONITOR command. + * + * @param ipaProdGsiChid GSI chid to be removed from HOLB + * monitoring + * @param EE EE that the chid belongs to + */ +union IpaDelHolbMonitorCmdData_t { + struct IpaDelHolbMonitorParams_t { + uint32_t ipaProdGsiChid :8; + uint32_t EE :8; + uint32_t reserved :16; + } __packed params; + uint32_t raw32b; +} __packed; + static DEFINE_MUTEX(uc_loaded_nb_lock); static BLOCKING_NOTIFIER_HEAD(uc_loaded_notifier); +static struct workqueue_struct *ipa_uc_holb_wq; struct ipa3_uc_hdlrs ipa3_uc_hdlrs[IPA_HW_NUM_FEATURES] = { { 0 } }; const char *ipa_hw_error_str(enum ipa3_hw_errors err_type) @@ -283,6 +352,34 @@ const char *ipa_hw_error_str(enum ipa3_hw_errors err_type) return str; } +static void ipa3_deferred_holb_work(struct work_struct *work) +{ + + int res; + u32 poll_period = ipa3_ctx->uc_ctx.holb_monitor.poll_period; + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + res = ipa3_uc_enable_holb_monitor(poll_period); + if (res) { + IPAERR("Failed to enable HOLB monitoring %d\n", res); + goto fail_holb_enable; + } + if (!ipa3_ctx->uc_ctx.uc_event_ring_valid) { + if (ipa3_uc_setup_event_ring()) { + IPAERR("failed to set uc event ring\n"); + goto fail_holb_enable; + } + } + + if (ipa3_uc_hdlrs[IPA_HW_FEATURE_COMMON].ipa_uc_holb_enabled_hdlr) + ipa3_uc_hdlrs[IPA_HW_FEATURE_COMMON].ipa_uc_holb_enabled_hdlr(); + + +fail_holb_enable: + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); +} +DECLARE_WORK(ipa3_holb_enabled_work, ipa3_deferred_holb_work); + static void ipa3_uc_save_dbg_stats(u32 size) { u8 prot_id; @@ -418,7 +515,7 @@ static void ipa3_event_ring_hdlr(void) u32 ering_rp, offset; void *rp_va; struct ipa_inform_wlan_bw bw_info; - struct eventElement_t *e_b = NULL, *e_q = NULL; + struct eventElement_t *e_b = NULL, *e_q = NULL, *e_h = NULL; int mul = 0; ering_rp = ipahal_read_reg_mn(IPA_UC_MAILBOX_m_n, @@ -456,7 +553,21 @@ static void ipa3_event_ring_hdlr(void) if (ipa3_broadcast_wdi_quota_reach_ind(0, e_q->Value.quota_param.usage)) IPAERR_RL("failed on quota_reach for %d\n", - e_q->Protocol); + e_q->Protocol); + } else if (((struct eventElement_t *) rp_va)->Opcode + == IPA_HOLB_BAD_PERIPHERAL_EVENT) { + e_h = ((struct eventElement_t *) rp_va); + IPAERR("Bad Periph for Chan %d QTimer %u %u\n", + e_h->Value.holb_notify_param.ipaProdGsiChid, + e_h->Value.holb_notify_param.qTimerMSB, + e_h->Value.holb_notify_param.qTimerLSB); + } else if (((struct eventElement_t *) rp_va)->Opcode + == IPA_HOLB_PERIPHERAL_RECOVERED_EVENT) { + e_h = ((struct eventElement_t *) rp_va); + IPAERR("Recovered Periph Chan %d QTimer %u %u\n", + e_h->Value.holb_notify_param.ipaProdGsiChid, + e_h->Value.holb_notify_param.qTimerMSB, + e_h->Value.holb_notify_param.qTimerLSB); } ipa3_ctx->uc_ctx.ering_rp_local += offset; ipa3_ctx->uc_ctx.ering_rp_local %= @@ -508,6 +619,17 @@ int ipa3_uc_loaded_check(void) } EXPORT_SYMBOL(ipa3_uc_loaded_check); +/** + * ipa3_uc_holb_enabled_check() - Check the uC has been loaded + * + * Return value: 1 if the uC is loaded, 0 otherwise + */ +int ipa3_uc_holb_enabled_check(void) +{ + return ipa3_ctx->uc_ctx.uc_holb_enabled; +} +EXPORT_SYMBOL(ipa3_uc_holb_enabled_check); + /** * ipa3_uc_register_ready_cb() - register a uC ready callback notifier block * @nb: notifier @@ -694,6 +816,9 @@ static void ipa3_uc_response_hdlr(enum ipa_irq_type interrupt, ipa3_ctx->uc_ctx.uc_loaded = true; + if (ipa3_ctx->uc_ctx.ipa_use_uc_holb_monitor) + queue_work(ipa_uc_holb_wq, &ipa3_holb_enabled_work); + (void) blocking_notifier_call_chain(&uc_loaded_notifier, true, ipa3_ctx); @@ -741,6 +866,7 @@ static void ipa3_uc_response_hdlr(enum ipa_irq_type interrupt, ipa3_ctx->uc_ctx.uc_sram_mmio->responseOp); } IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + } static void ipa3_uc_wigig_misc_int_handler(enum ipa_irq_type interrupt, @@ -904,6 +1030,7 @@ int ipa3_uc_interface_init(void) } mutex_init(&ipa3_ctx->uc_ctx.uc_lock); + mutex_init(&ipa3_ctx->uc_ctx.holb_monitor.uc_holb_lock); spin_lock_init(&ipa3_ctx->uc_ctx.uc_spinlock); phys_addr = ipa3_ctx->ipa_wrapper_base + @@ -944,10 +1071,22 @@ int ipa3_uc_interface_init(void) goto irq_fail2; } + if (ipa3_ctx->uc_ctx.ipa_use_uc_holb_monitor) { + ipa_uc_holb_wq = alloc_workqueue(IPA_UC_HOLB_WORKQUEUE_NAME, + WQ_MEM_RECLAIM | WQ_UNBOUND | WQ_SYSFS, 1); + + if (!ipa_uc_holb_wq) { + IPAERR("Failed to create ipa_uc_holb_wq\n"); + result = -EFAULT; + goto fail_wq; + } + } ipa3_ctx->uc_ctx.uc_inited = true; IPADBG("IPA uC interface is initialized\n"); return 0; +fail_wq: + destroy_workqueue(ipa_uc_holb_wq); irq_fail2: ipa3_remove_interrupt_handler(IPA_UC_IRQ_1); irq_fail1: @@ -1038,6 +1177,100 @@ int ipa3_uc_is_gsi_channel_empty(enum ipa_client_type ipa_client) return ret; } +/** + * ipa3_uc_enable_holb_monitor() - Enable HOLB monitoring + * + * Return value: 0 on success, negative value otherwise + */ +int ipa3_uc_enable_holb_monitor(uint32_t polling_period) +{ + union IpaEnableHolbMonitorCmdData_t cmd; + int ret; + + cmd.params.holbMonitorPollingPeriod = polling_period; + + IPADBG("Sending uc CMD ENABLE_HOLB_MONITOR with polling_period (%d)\n", + polling_period); + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + ret = ipa3_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_ENABLE_HOLB_MONITOR, + 0, false, 10*HZ); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + + return ret; +} + +/** + * ipa3_uc_add_holb_monitor() - Add a gsi channel that needs to be monitored + * + * Return value: 0 on success, negative value otherwise + */ +int ipa3_uc_add_holb_monitor(uint16_t gsi_ch, uint32_t action_mask, + uint32_t max_stuck_cnt, uint8_t ee) +{ + union IpaAddHolbMonitorCmdData_t cmd; + int ret; + + cmd.params.ipaProdGsiChid = gsi_ch; + cmd.params.EE = ee; + cmd.params.holbActionMask = action_mask; + cmd.params.maxStuckSampleCnt = max_stuck_cnt; + + IPADBG("Sending uc CMD ADD_HOLB_MONITOR"); + IPADBG("CMD params gsi_chid (%d), mask (%d), max_stuck_cnt (%d)\n", + gsi_ch, action_mask, max_stuck_cnt); + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + ret = ipa3_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_ADD_HOLB_MONITOR, 0, + false, 10*HZ); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + + return ret; +} + +/** + * ipa3_uc_del_holb_monitor() - Disable monitoring for a particular + * gsi channel + * + * Return value: 0 on success, negative value otherwise + */ +int ipa3_uc_del_holb_monitor(uint16_t gsi_ch, uint8_t ee) +{ + union IpaDelHolbMonitorCmdData_t cmd; + int ret; + + cmd.params.ipaProdGsiChid = gsi_ch; + cmd.params.EE = ee; + + IPADBG("Sending uc IPA_CPU_2_HW_CMD_DEL_HOLB_MONITOR for gsi_ch %d\n", + gsi_ch); + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + ret = ipa3_uc_send_cmd(cmd.raw32b, IPA_CPU_2_HW_CMD_DEL_HOLB_MONITOR, 0, + false, 10*HZ); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + + return ret; +} + +/** + * ipa3_uc_disable_holb_monitor() - Disable HOLB monitoring + * + * Return value: 0 on success, negative value otherwise + */ +int ipa3_uc_disable_holb_monitor(void) +{ + int ret; + + IPADBG("Sending uc IPA_CPU_2_HW_CMD_DISABLE_HOLB_MONITOR\n"); + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + ret = ipa3_uc_send_cmd(0, IPA_CPU_2_HW_CMD_DISABLE_HOLB_MONITOR, 0, + false, 10*HZ); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + + return ret; +} /** * ipa3_uc_notify_clk_state() - notify to uC of clock enable / disable diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_holb_monitor.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_holb_monitor.c new file mode 100644 index 000000000000..4d62cd2bc8b2 --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_holb_monitor.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include "ipa_i.h" +#include "ipa_uc_holb_monitor.h" + + +/** + * ipa3_uc_holb_client_handler - Iterates through all HOLB clients and sends + * ADD_HOLB_MONITOR command if necessary. + * + */ +void ipa3_uc_holb_client_handler(void) +{ + int client_idx; + struct ipa_uc_holb_client_info *holb_client; + int num_clients; + + if (!ipa3_ctx->uc_ctx.ipa_use_uc_holb_monitor) + return; + + mutex_lock(&ipa3_ctx->uc_ctx.holb_monitor.uc_holb_lock); + + num_clients = ipa3_ctx->uc_ctx.holb_monitor.num_holb_clients; + ipa3_ctx->uc_ctx.uc_holb_enabled = true; + + for (client_idx = 0; client_idx < num_clients; client_idx++) { + holb_client = + &(ipa3_ctx->uc_ctx.holb_monitor.client[client_idx]); + if (holb_client->state == IPA_HOLB_ADD_PENDING) { + ipa3_uc_add_holb_monitor(holb_client->gsi_chan_hdl, + holb_client->action_mask, holb_client->max_stuck_cnt, + holb_client->ee); + IPADBG("HOLB Client with GSI %d moved to ADD state\n", + holb_client->gsi_chan_hdl); + holb_client->state = IPA_HOLB_ADD; + } + } + + mutex_unlock(&ipa3_ctx->uc_ctx.holb_monitor.uc_holb_lock); +} + +/** + * ipa3_get_holb_client_idx_by_ch() - Get client index in client + * array with a specified gsi channel + * @gsi_chan_hdl: GSI Channel of the client to be monitored + * + * Returns client index in client array + */ +static int ipa3_get_holb_client_idx_by_ch(uint16_t gsi_ch) +{ + int client_idx; + int num_clients = ipa3_ctx->uc_ctx.holb_monitor.num_holb_clients; + struct ipa_uc_holb_client_info *holb_client; + + for (client_idx = 0; client_idx < num_clients; client_idx++) { + holb_client = + &(ipa3_ctx->uc_ctx.holb_monitor.client[client_idx]); + if (holb_client->gsi_chan_hdl == gsi_ch) + return client_idx; + } + return -EINVAL; +} + +/** + * ipa3_set_holb_client_by_ch() - Set client parameters for specific + * gsi channel + * @client: Client values to be set for the gsi channel + * + */ +void ipa3_set_holb_client_by_ch(struct ipa_uc_holb_client_info client) +{ + uint16_t gsi_ch; + int client_idx, num_clients; + struct ipa_uc_holb_client_info *holb_client; + + + mutex_lock(&ipa3_ctx->uc_ctx.holb_monitor.uc_holb_lock); + + gsi_ch = client.gsi_chan_hdl; + client_idx = ipa3_get_holb_client_idx_by_ch(gsi_ch); + + if (client_idx != -EINVAL) { + holb_client = + &(ipa3_ctx->uc_ctx.holb_monitor.client[client_idx]); + } else { + num_clients = ipa3_ctx->uc_ctx.holb_monitor.num_holb_clients; + holb_client = + &(ipa3_ctx->uc_ctx.holb_monitor.client[num_clients]); + ipa3_ctx->uc_ctx.holb_monitor.num_holb_clients = ++num_clients; + holb_client->gsi_chan_hdl = gsi_ch; + } + + holb_client->debugfs_param = client.debugfs_param; + if (holb_client->debugfs_param) + holb_client->max_stuck_cnt = client.max_stuck_cnt; + IPADBG("HOLB gsi_chan %d with max_stuck_cnt %d, set %d\n", + gsi_ch, holb_client->max_stuck_cnt, holb_client->debugfs_param); + + mutex_unlock(&ipa3_ctx->uc_ctx.holb_monitor.uc_holb_lock); +} + +/** + * ipa3_uc_client_add_holb_monitor() - Sends ADD_HOLB_MONITOR for gsi channels + * if uC is enabled, else saves client state + * @gsi_chan_hdl: GSI Channel of the client to be monitored + * @action_mask: HOLB action mask + * @max_stuck_cnt: Max number of attempts uC should try before sending an event + * @ee: EE that the chid belongs to + * + * Return value: 0 on success, negative value otherwise + */ +int ipa3_uc_client_add_holb_monitor(uint16_t gsi_ch, uint32_t action_mask, + uint32_t max_stuck_cnt, uint8_t ee) +{ + + struct ipa_uc_holb_client_info *holb_client; + int ret = 0; + int client_idx, num_clients; + + if (!ipa3_ctx->uc_ctx.ipa_use_uc_holb_monitor) + return ret; + + mutex_lock(&ipa3_ctx->uc_ctx.holb_monitor.uc_holb_lock); + + client_idx = ipa3_get_holb_client_idx_by_ch(gsi_ch); + if (client_idx != -EINVAL) { + holb_client = + &(ipa3_ctx->uc_ctx.holb_monitor.client[client_idx]); + } else { + num_clients = ipa3_ctx->uc_ctx.holb_monitor.num_holb_clients; + holb_client = + &(ipa3_ctx->uc_ctx.holb_monitor.client[num_clients]); + ipa3_ctx->uc_ctx.holb_monitor.num_holb_clients = ++num_clients; + } + + holb_client->gsi_chan_hdl = gsi_ch; + holb_client->action_mask = action_mask; + if (!holb_client->debugfs_param) + holb_client->max_stuck_cnt = max_stuck_cnt; + holb_client->ee = ee; + + if (ipa3_uc_holb_enabled_check()) { + if (holb_client->state != IPA_HOLB_ADD) { + IPADBG("GSI chan %d going to ADD state\n", + holb_client->gsi_chan_hdl); + ret = ipa3_uc_add_holb_monitor( + holb_client->gsi_chan_hdl, + holb_client->action_mask, holb_client->max_stuck_cnt, + holb_client->ee); + holb_client->state = IPA_HOLB_ADD; + } + } else { + IPADBG("GSI chan %d going to ADD_PENDING state\n", + holb_client->gsi_chan_hdl); + holb_client->state = IPA_HOLB_ADD_PENDING; + } + + + mutex_unlock(&ipa3_ctx->uc_ctx.holb_monitor.uc_holb_lock); + return ret; +} + +/** + * ipa3_uc_client_del_holb_monitor() - Sends DEL_HOLB_MONITOR for gsi channels + * if uC is enabled, else saves client state + * @gsi_chan_hdl: GSI Channel of the client to be monitored + * @ee: EE that the chid belongs to + * + * Return value: 0 on success, negative value otherwise + */ +int ipa3_uc_client_del_holb_monitor(uint16_t gsi_ch, uint8_t ee) +{ + + struct ipa_uc_holb_client_info *holb_client; + int ret = 0; + int client_idx; + + if (!ipa3_ctx->uc_ctx.ipa_use_uc_holb_monitor) + return ret; + + mutex_lock(&ipa3_ctx->uc_ctx.holb_monitor.uc_holb_lock); + + client_idx = ipa3_get_holb_client_idx_by_ch(gsi_ch); + if (client_idx == -EINVAL) { + IPAERR("Invalid client with GSI chan %d\n", gsi_ch); + ret = client_idx; + } + + holb_client = &(ipa3_ctx->uc_ctx.holb_monitor.client[client_idx]); + if (ipa3_uc_holb_enabled_check() && + holb_client->state == IPA_HOLB_ADD) { + IPADBG("GSI chan %d going from ADD to DEL state\n", + holb_client->gsi_chan_hdl); + ret = ipa3_uc_del_holb_monitor(holb_client->gsi_chan_hdl, + ee); + holb_client->state = IPA_HOLB_DEL; + + } else if (!ipa3_uc_holb_enabled_check() && + holb_client->state == IPA_HOLB_ADD_PENDING) { + IPADBG("GSI chan %d going from ADD_PENDING to DEL state\n", + holb_client->gsi_chan_hdl); + holb_client->state = IPA_HOLB_DEL; + } + + mutex_unlock(&ipa3_ctx->uc_ctx.holb_monitor.uc_holb_lock); + return ret; +} diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_holb_monitor.h b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_holb_monitor.h new file mode 100644 index 000000000000..5a450a8ab69a --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_holb_monitor.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef IPA_UC_HOLB_MONITOR_H +#define IPA_UC_HOLB_MONITOR_H + +#define IPA_HOLB_MONITOR_MAX_STUCK_COUNT 5 +#define IPA_HOLB_POLLING_PERIOD_MS 10 +#define HOLB_OP 0x1 +#define NOTIFY_AP_ON_HOLB 0x2 +#define HOLB_MONITOR_MASK (HOLB_OP | NOTIFY_AP_ON_HOLB) +#define IPA_HOLB_CLIENT_MAX 30 +#define IPA_CLIENT_IS_HOLB_CONS(x) \ +(x == IPA_CLIENT_USB_CONS || x == IPA_CLIENT_WLAN2_CONS || \ +x == IPA_CLIENT_WLAN1_CONS || x == IPA_CLIENT_WIGIG1_CONS || \ +x == IPA_CLIENT_WIGIG2_CONS || x == IPA_CLIENT_WIGIG3_CONS || \ +x == IPA_CLIENT_WIGIG4_CONS) + +/* + * enum holb_client_state - Client state for HOLB + * IPA_HOLB_INIT : Initial state on bootup before client connect/disconnect + * IPA_HOLB_ADD_PENDING : Client GSI channel started but uC not enabled. + * IPA_HOLB_ADD : ADD_HOLB_MONITOR command sent for client. + * IPA_HOLB_DEL : DEL_HOLB_MONITOR command sent for client. + */ +enum ipa_holb_client_state { + IPA_HOLB_INIT = 0, + IPA_HOLB_ADD_PENDING = 1, + IPA_HOLB_ADD = 2, + IPA_HOLB_DEL = 3, +}; + +/** + * struct ipa_uc_holb_client_info - Client info needed for HOLB callback + * @gsi_chan_hdl: GSI Channel of the client to be monitored + * @action_mask: HOLB action mask + * @max_stuck_cnt: Max number of attempts uC should try before sending an event + * @ee: EE that the chid belongs to + * @debugfs_param: If debugfs is used to set the client parameters + * @state: Client state + * + */ +struct ipa_uc_holb_client_info { + uint16_t gsi_chan_hdl; + uint32_t action_mask; + uint32_t max_stuck_cnt; + uint8_t ee; + bool debugfs_param; + enum ipa_holb_client_state state; +}; + +/** + * struct ipa_holb_monitor - Parameters needed for the HOLB monitor feature + * @num_holb_clients: Number of clients with holb monitor enabled + * @client: Array of clients tracked for HOLB Monitor + * @ipa_uc_holb_monitor_poll_period : Polling period in ms + * @uc_holb_lock : Lock for feature operations + * + */ +struct ipa_holb_monitor { + u32 num_holb_clients; + u32 poll_period; + u32 max_cnt_wlan; + u32 max_cnt_usb; + u32 max_cnt_11ad; + struct ipa_uc_holb_client_info client[IPA_HOLB_CLIENT_MAX]; + struct mutex uc_holb_lock; +}; + +/** + * ipa3_uc_holb_client_handler - Iterates through all HOLB clients and sends + * ADD_HOLB_MONITOR command if necessary. + * + */ +void ipa3_uc_holb_client_handler(void); + +/** + * ipa3_uc_client_add_holb_monitor() - Sends ADD_HOLB_MONITOR for gsi channels + * if uC is enabled, else saves client state + * @gsi_chan_hdl: GSI Channel of the client to be monitored + * @action_mask: HOLB action mask + * @max_stuck_cnt: Max number of attempts uC should try before sending an event + * @ee: EE that the chid belongs to + * + * Return value: 0 on success, negative value otherwise + */ +int ipa3_uc_client_add_holb_monitor(uint16_t gsi_ch, uint32_t action_mask, + uint32_t max_stuck_cnt, uint8_t ee); + +/** + * ipa3_uc_client_del_holb_monitor() - Sends DEL_HOLB_MONITOR for gsi channels + * if uC is enabled, else saves client state + * @gsi_chan_hdl: GSI Channel of the client to be monitored + * @ee: EE that the chid belongs to + * + * Return value: 0 on success, negative value otherwise + */ +int ipa3_uc_client_del_holb_monitor(uint16_t gsi_ch, uint8_t ee); + +/** + * ipa3_set_holb_client_by_ch() - Set client parameters for specific + * gsi channel + * @client: Client values to be set for the gsi channel + * + */ +void ipa3_set_holb_client_by_ch(struct ipa_uc_holb_client_info client); +#endif /* IPA_UC_HOLB_MONITOR_H */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h index 2c891160f7a9..8772ff6d3c7f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _IPA_UC_OFFLOAD_I_H_ @@ -673,6 +673,8 @@ struct IpaHwOffloadCommonChCmdData_t { enum EVENT_2_CPU_OPCODE { BW_NOTIFY = 0x0, QUOTA_NOTIFY = 0x1, + IPA_HOLB_BAD_PERIPHERAL_EVENT = 0x2, + IPA_HOLB_PERIPHERAL_RECOVERED_EVENT = 0x3 }; struct EventStructureBwMonitoring_t { @@ -686,9 +688,27 @@ struct EventStructureQuotaMonitoring_t { uint64_t usage; } __packed; + +/** + * @brief Structure holding the parameters for + * IPA_HW_2_CPU_EVENT_PERIPH_BAD and + * IPA_HW_2_CPU_EVENT_PERIPH_RECOVERED events. + * + * @param ipaProdGsiChid bad OR recovered GSI chid + * @param EE EE that the chid belongs to + */ +struct EventStructureHolbMonitoring_t { + uint32_t ipaProdGsiChid :8; + uint32_t EE :8; + uint32_t reserved :16; + uint32_t qTimerLSB; + uint32_t qTimerMSB; +} __packed; + union EventParamFormat_t { struct EventStructureBwMonitoring_t bw_param; struct EventStructureQuotaMonitoring_t quota_param; + struct EventStructureHolbMonitoring_t holb_notify_param; } __packed; /* EVT RING STRUCTURE diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index c0f66ecb100a..00b9ec402295 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -2470,6 +2470,8 @@ int ipa3_resume_gsi_wdi_pipe(u32 clnt_hdl) struct gsi_chan_info chan_info; union __packed gsi_channel_scratch gsi_scratch; struct IpaHwOffloadStatsAllocCmdData_t *pcmd_t = NULL; + u32 holb_max_cnt = ipa3_ctx->uc_ctx.holb_monitor.max_cnt_wlan; + int res = 0; IPADBG("ep=%d\n", clnt_hdl); ep = &ipa3_ctx->ep[clnt_hdl]; @@ -2493,6 +2495,14 @@ int ipa3_resume_gsi_wdi_pipe(u32 clnt_hdl) IPAERR("gsi_start_channel failed %d\n", result); ipa_assert(); } + if (IPA_CLIENT_IS_HOLB_CONS(ep->client)) { + res = ipa3_uc_client_add_holb_monitor(ep->gsi_chan_hdl, + HOLB_MONITOR_MASK, holb_max_cnt, + IPA_EE_AP); + if (res) + IPAERR("Add HOLB monitor failed for gsi ch %d\n", + ep->gsi_chan_hdl); + } pcmd_t = &ipa3_ctx->gsi_info[IPA_HW_PROTOCOL_WDI]; /* start uC gsi dbg stats monitor */ if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5 && diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 10b1c1215d09..7532c3bd90d8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -646,11 +646,6 @@ static const u32 ipa3_rsrc_rx_grp_hps_weight_config }, }; -enum ipa_ees { - IPA_EE_AP = 0, - IPA_EE_Q6 = 1, - IPA_EE_UC = 2, -}; enum ipa_qmb_instance_type { IPA_QMB_INSTANCE_DDR = 0, @@ -7964,6 +7959,13 @@ static int __ipa3_stop_gsi_channel(u32 clnt_hdl) ep = &ipa3_ctx->ep[clnt_hdl]; client_type = ipa3_get_client_mapping(clnt_hdl); + if (IPA_CLIENT_IS_HOLB_CONS(client_type)) { + res = ipa3_uc_client_del_holb_monitor(ep->gsi_chan_hdl, + IPA_EE_AP); + if (res) + IPAERR("Delete HOLB monitor failed for ch %d\n", + ep->gsi_chan_hdl); + } memset(&mem, 0, sizeof(mem)); /* stop uC gsi dbg stats monitor */ 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 99b031dd2059..5237c6b57e41 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c @@ -726,6 +726,7 @@ int ipa3_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) { struct ipa3_ep_context *ep_tx, *ep_rx; int result = 0; + u32 holb_max_cnt = ipa3_ctx->uc_ctx.holb_monitor.max_cnt_wlan; /* wdi3 only support over gsi */ if (!ipa3_ctx->ipa_wdi3_over_gsi) { @@ -778,6 +779,13 @@ int ipa3_enable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) goto fail_enable_path2; } + result = ipa3_uc_client_add_holb_monitor(ep_tx->gsi_chan_hdl, + HOLB_MONITOR_MASK, holb_max_cnt, + IPA_EE_AP); + if (result) + IPAERR("Add HOLB monitor failed for gsi ch %d\n", + ep_tx->gsi_chan_hdl); + /* start gsi rx channel */ result = gsi_start_channel(ep_rx->gsi_chan_hdl); if (result) { @@ -875,6 +883,7 @@ int ipa3_disable_wdi3_pipes(int ipa_ep_idx_tx, int ipa_ep_idx_rx) result = -EFAULT; goto fail; } + /* stop gsi tx channel */ result = ipa3_stop_gsi_channel(ipa_ep_idx_tx); if (result) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c index faab2b1fe689..77d7937600dd 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include "ipa_i.h" @@ -1650,6 +1650,7 @@ int ipa3_enable_wigig_pipe_i(enum ipa_client_type client) struct ipa_ep_cfg_ctrl ep_cfg_ctrl; int retry_cnt = 0; uint64_t val; + u32 holb_max_cnt = ipa3_ctx->uc_ctx.holb_monitor.max_cnt_11ad; IPADBG("\n"); @@ -1704,6 +1705,14 @@ int ipa3_enable_wigig_pipe_i(enum ipa_client_type client) res = -EFAULT; goto fail_gsi_start; } + if (IPA_CLIENT_IS_HOLB_CONS(ep->client)) { + res = ipa3_uc_client_add_holb_monitor(ep->gsi_chan_hdl, + HOLB_MONITOR_MASK, holb_max_cnt, + IPA_EE_AP); + if (res) + IPAERR("Add HOLB monitor failed for gsi ch %d\n", + ep->gsi_chan_hdl); + } /* for TX we have to ring the channel db (last desc in the ring) */ if (client != IPA_CLIENT_WIGIG_PROD) {