qcacld-3.0: Set up watchdog timers for pld driver ops

Requirement 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
This commit is contained in:
Nachiket Kukade 2017-09-18 15:37:00 +05:30 • committed by snandini
commit be8850b4c6
3 changed files with 122 additions and 0 deletions

View file

@ -1950,6 +1950,19 @@ struct hdd_channel_info {
u_int8_t vht_center_freq_seg1;
};
/*
* @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
};
/*
* Function declarations and documentation
*/
@ -2872,4 +2885,27 @@ void hdd_dp_trace_init(struct hdd_config *config);
int hdd_set_limit_off_chan_for_tos(struct hdd_adapter *adapter, enum tos tos,
bool is_tos_active);
/**
* 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) */

View file

@ -334,6 +334,11 @@ static int wlan_hdd_probe(struct device *dev, void *bdev,
reinit ? "re-" : "", QWLAN_VERSIONSTR);
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);
hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT);
/*
@ -378,6 +383,7 @@ static int wlan_hdd_probe(struct device *dev, void *bdev,
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;
@ -399,6 +405,7 @@ err_hdd_deinit:
hdd_remove_pm_qos(dev);
cds_set_fw_down(false);
hdd_stop_driver_ops_timer();
mutex_unlock(&hdd_init_deinit_lock);
return ret;
}
@ -1153,7 +1160,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();
}
@ -1170,7 +1181,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();
}

View file

@ -174,6 +174,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];
@ -10987,6 +10993,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_qdf_print_init();
@ -11006,6 +11016,7 @@ err_out:
void hdd_deinit(void)
{
hdd_deinit_wowl();
qdf_timer_free(&hdd_drv_ops_inactivity_timer);
hdd_qdf_print_deinit();
@ -12668,6 +12679,66 @@ int hdd_set_limit_off_chan_for_tos(struct hdd_adapter *adapter, enum tos tos,
return ret;
}
/**
* 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();
else
QDF_BUG(0);
}
/* Register the module init/exit functions */
module_init(hdd_module_init);
module_exit(hdd_module_exit);