From d793dadff1c4a9e3010ff306d6aa4271c6604098 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Mon, 11 Sep 2017 19:43:52 +0530 Subject: qcacld-3.0: Set up watchdog timers for pld driver ops Requrement to detect if a PLD OP has stuck for a long time. Define a timer for 30 seconds and let it run during pld ops probe, reinit, remove and shutdown. Upon expiry print important debug information then either trigger recovery or BUG ON. Change-Id: I6c132cb71917cec7dead9c6c91ce6778e20bffe7 CRs-Fixed: 2090785 --- core/hdd/inc/wlan_hdd_main.h | 36 +++++++++++++++++++ core/hdd/src/wlan_hdd_driver_ops.c | 15 ++++++++ core/hdd/src/wlan_hdd_main.c | 71 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 753093d88f57..fd60b2ff11f0 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -322,6 +322,19 @@ /* ARP packet type for NUD debug stats */ #define WLAN_NUD_STATS_ARP_PKT_TYPE 1 +/* + * @eHDD_DRV_OP_PROBE: Refers to .probe operation + * @eHDD_DRV_OP_REMOVE: Refers to .remove operation + * @eHDD_DRV_OP_SHUTDOWN: Refers to .shutdown operation + * @eHDD_DRV_OP_REINIT: Refers to .reinit operation + */ +enum { + eHDD_DRV_OP_PROBE = 0, + eHDD_DRV_OP_REMOVE, + eHDD_DRV_OP_SHUTDOWN, + eHDD_DRV_OP_REINIT +}; + /* * @eHDD_SCAN_REJECT_DEFAULT: default value * @eHDD_CONNECTION_IN_PROGRESS: connection is in progress @@ -2796,4 +2809,27 @@ hdd_nla_parse_nested(struct nlattr *tb[], int maxtype, const struct nlattr *nla, */ void hdd_pld_ipa_uc_shutdown_pipes(void); +/** + * hdd_drv_ops_inactivity_handler() - Timeout handler for driver ops + * inactivity timer + * + * Return: None + */ +void hdd_drv_ops_inactivity_handler(void); + +/** + * hdd_start_driver_ops_timer() - Starts driver ops inactivity timer + * @drv_op: Enum indicating driver op + * + * Return: none + */ +void hdd_start_driver_ops_timer(int drv_op); + +/** + * hdd_stop_driver_ops_timer() - Stops driver ops inactivity timer + * + * Return: none + */ +void hdd_stop_driver_ops_timer(void); + #endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index e1335e475401..45ced4b8c1eb 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -338,6 +338,11 @@ static int wlan_hdd_probe(struct device *dev, void *bdev, const struct hif_bus_i int ret = 0; mutex_lock(&hdd_init_deinit_lock); + if (!reinit) + hdd_start_driver_ops_timer(eHDD_DRV_OP_PROBE); + else + hdd_start_driver_ops_timer(eHDD_DRV_OP_REINIT); + pr_info("%s: %sprobing driver v%s\n", WLAN_MODULE_NAME, reinit ? "re-" : "", QWLAN_VERSIONSTR); @@ -387,6 +392,7 @@ static int wlan_hdd_probe(struct device *dev, void *bdev, const struct hif_bus_i cds_set_driver_in_bad_state(false); probe_fail_cnt = 0; re_init_fail_cnt = 0; + hdd_stop_driver_ops_timer(); mutex_unlock(&hdd_init_deinit_lock); return 0; @@ -408,6 +414,7 @@ err_hdd_deinit: hdd_remove_pm_qos(dev); cds_clear_fw_state(CDS_FW_STATE_DOWN); + hdd_stop_driver_ops_timer(); mutex_unlock(&hdd_init_deinit_lock); return ret; } @@ -1107,7 +1114,11 @@ static void wlan_hdd_pld_remove(struct device *dev, { ENTER(); mutex_lock(&hdd_init_deinit_lock); + hdd_start_driver_ops_timer(eHDD_DRV_OP_REMOVE); + wlan_hdd_remove(dev); + + hdd_stop_driver_ops_timer(); mutex_unlock(&hdd_init_deinit_lock); EXIT(); } @@ -1124,7 +1135,11 @@ static void wlan_hdd_pld_shutdown(struct device *dev, { ENTER(); mutex_lock(&hdd_init_deinit_lock); + hdd_start_driver_ops_timer(eHDD_DRV_OP_SHUTDOWN); + wlan_hdd_shutdown(); + + hdd_stop_driver_ops_timer(); mutex_unlock(&hdd_init_deinit_lock); EXIT(); } diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 39f5944a25d2..87858cf66631 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -162,6 +162,12 @@ static struct attribute *attrs[] = { #define MODULE_INITIALIZED 1 #endif +#define HDD_OPS_INACTIVITY_TIMEOUT (120000) +#define MAX_OPS_NAME_STRING_SIZE 20 + +static qdf_timer_t hdd_drv_ops_inactivity_timer; +static char drv_ops_string[MAX_OPS_NAME_STRING_SIZE]; + /* the Android framework expects this param even though we don't use it */ #define BUF_LEN 20 static char fwpath_buffer[BUF_LEN]; @@ -11049,6 +11055,10 @@ int hdd_init(void) goto err_out; } + qdf_timer_init(NULL, &hdd_drv_ops_inactivity_timer, + (void *)hdd_drv_ops_inactivity_handler, NULL, + QDF_TIMER_TYPE_SW); + hdd_trace_init(); hdd_register_debug_callback(); @@ -11071,6 +11081,7 @@ void hdd_deinit(void) wlan_logging_sock_deinit_svc(); #endif + qdf_timer_free(&hdd_drv_ops_inactivity_timer); wlan_destroy_bug_report_lock(); cds_deinit(); } @@ -12146,6 +12157,66 @@ void hdd_pld_ipa_uc_shutdown_pipes(void) hdd_ipa_uc_force_pipe_shutdown(hdd_ctx); } +/** + * hdd_start_driver_ops_timer() - Starts driver ops inactivity timer + * @drv_op: Enum indicating driver op + * + * Return: none + */ +void hdd_start_driver_ops_timer(int drv_op) +{ + memset(drv_ops_string, 0, MAX_OPS_NAME_STRING_SIZE); + switch (drv_op) { + case eHDD_DRV_OP_PROBE: + memcpy(drv_ops_string, "probe", sizeof("probe")); + break; + case eHDD_DRV_OP_REMOVE: + memcpy(drv_ops_string, "remove", sizeof("remove")); + break; + case eHDD_DRV_OP_SHUTDOWN: + memcpy(drv_ops_string, "shutdown", sizeof("shutdown")); + break; + case eHDD_DRV_OP_REINIT: + memcpy(drv_ops_string, "reinit", sizeof("reinit")); + break; + } + + qdf_timer_start(&hdd_drv_ops_inactivity_timer, + HDD_OPS_INACTIVITY_TIMEOUT); +} + +/** + * hdd_stop_driver_ops_timer() - Stops driver ops inactivity timer + * + * Return: none + */ +void hdd_stop_driver_ops_timer(void) +{ + qdf_timer_sync_cancel(&hdd_drv_ops_inactivity_timer); +} + +/** + * hdd_drv_ops_inactivity_handler() - Timeout handler for driver ops + * inactivity timer + * + * Return: None + */ +void hdd_drv_ops_inactivity_handler(void) +{ + hdd_err("%s: %d Sec timer expired while in .%s", + __func__, HDD_OPS_INACTIVITY_TIMEOUT/1000, drv_ops_string); + + /* Driver shutdown is stuck, no recovery possible at this point */ + if (0 == qdf_mem_cmp(&drv_ops_string[0], "shutdown", + sizeof("shutdown"))) + QDF_BUG(0); + + if (cds_is_self_recovery_enabled()) + cds_trigger_recovery(false); + else + QDF_BUG(0); +} + /* Register the module init/exit functions */ module_init(hdd_module_init); module_exit(hdd_module_exit); -- cgit v1.2.3