2012-08-29 19:40:26 +05:30
/*
* Copyright ( c ) 2012 Qualcomm Atheros , Inc .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*/
# include "core.h"
# include "cfg80211.h"
# include "debug.h"
static void ath6kl_recovery_work ( struct work_struct * work )
{
struct ath6kl * ar = container_of ( work , struct ath6kl ,
fw_recovery . recovery_work ) ;
2012-08-29 19:40:27 +05:30
ar - > state = ATH6KL_STATE_RECOVERY ;
del_timer_sync ( & ar - > fw_recovery . hb_timer ) ;
2012-08-29 19:40:26 +05:30
ath6kl_init_hw_restart ( ar ) ;
2012-08-29 19:40:27 +05:30
ar - > state = ATH6KL_STATE_ON ;
2012-08-29 19:40:28 +05:30
clear_bit ( WMI_CTRL_EP_FULL , & ar - > flag ) ;
2012-08-29 19:40:27 +05:30
ar - > fw_recovery . err_reason = 0 ;
2012-09-03 12:49:34 +05:30
if ( ar - > fw_recovery . hb_poll )
2012-08-29 19:40:27 +05:30
mod_timer ( & ar - > fw_recovery . hb_timer , jiffies +
msecs_to_jiffies ( ar - > fw_recovery . hb_poll ) ) ;
2012-08-29 19:40:26 +05:30
}
void ath6kl_recovery_err_notify ( struct ath6kl * ar , enum ath6kl_fw_err reason )
{
2012-09-03 12:49:37 +05:30
if ( ! ar - > fw_recovery . enable )
return ;
2012-08-29 19:40:26 +05:30
ath6kl_dbg ( ATH6KL_DBG_RECOVERY , " Fw error detected, reason:%d \n " ,
reason ) ;
set_bit ( reason , & ar - > fw_recovery . err_reason ) ;
2012-09-03 12:49:36 +05:30
if ( ! test_bit ( RECOVERY_CLEANUP , & ar - > flag ) & &
ar - > state ! = ATH6KL_STATE_RECOVERY )
2012-08-29 19:40:26 +05:30
queue_work ( ar - > ath6kl_wq , & ar - > fw_recovery . recovery_work ) ;
}
2012-08-29 19:40:27 +05:30
void ath6kl_recovery_hb_event ( struct ath6kl * ar , u32 cookie )
{
if ( cookie = = ar - > fw_recovery . seq_num )
ar - > fw_recovery . hb_pending = false ;
}
2017-10-04 16:26:59 -07:00
static void ath6kl_recovery_hb_timer ( struct timer_list * t )
2012-08-29 19:40:27 +05:30
{
2017-10-04 16:26:59 -07:00
struct ath6kl * ar = from_timer ( ar , t , fw_recovery . hb_timer ) ;
2012-08-29 19:40:27 +05:30
int err ;
2012-09-03 12:49:36 +05:30
if ( test_bit ( RECOVERY_CLEANUP , & ar - > flag ) | |
( ar - > state = = ATH6KL_STATE_RECOVERY ) )
2012-08-29 19:40:27 +05:30
return ;
if ( ar - > fw_recovery . hb_pending )
ar - > fw_recovery . hb_misscnt + + ;
else
ar - > fw_recovery . hb_misscnt = 0 ;
if ( ar - > fw_recovery . hb_misscnt > ATH6KL_HB_RESP_MISS_THRES ) {
ar - > fw_recovery . hb_misscnt = 0 ;
ar - > fw_recovery . seq_num = 0 ;
ar - > fw_recovery . hb_pending = false ;
ath6kl_recovery_err_notify ( ar , ATH6KL_FW_HB_RESP_FAILURE ) ;
return ;
}
ar - > fw_recovery . seq_num + + ;
ar - > fw_recovery . hb_pending = true ;
err = ath6kl_wmi_get_challenge_resp_cmd ( ar - > wmi ,
ar - > fw_recovery . seq_num , 0 ) ;
if ( err )
ath6kl_warn ( " Failed to send hb challenge request, err:%d \n " ,
err ) ;
mod_timer ( & ar - > fw_recovery . hb_timer , jiffies +
msecs_to_jiffies ( ar - > fw_recovery . hb_poll ) ) ;
}
2012-08-29 19:40:26 +05:30
void ath6kl_recovery_init ( struct ath6kl * ar )
{
struct ath6kl_fw_recovery * recovery = & ar - > fw_recovery ;
2012-09-03 12:49:36 +05:30
clear_bit ( RECOVERY_CLEANUP , & ar - > flag ) ;
2012-08-29 19:40:26 +05:30
INIT_WORK ( & recovery - > recovery_work , ath6kl_recovery_work ) ;
2012-08-29 19:40:27 +05:30
recovery - > seq_num = 0 ;
recovery - > hb_misscnt = 0 ;
ar - > fw_recovery . hb_pending = false ;
2017-10-04 16:26:59 -07:00
timer_setup ( & ar - > fw_recovery . hb_timer , ath6kl_recovery_hb_timer ,
TIMER_DEFERRABLE ) ;
2012-08-29 19:40:27 +05:30
if ( ar - > fw_recovery . hb_poll )
mod_timer ( & ar - > fw_recovery . hb_timer , jiffies +
msecs_to_jiffies ( ar - > fw_recovery . hb_poll ) ) ;
2012-08-29 19:40:26 +05:30
}
void ath6kl_recovery_cleanup ( struct ath6kl * ar )
{
2012-09-03 12:49:37 +05:30
if ( ! ar - > fw_recovery . enable )
return ;
2012-09-03 12:49:36 +05:30
set_bit ( RECOVERY_CLEANUP , & ar - > flag ) ;
2012-08-29 19:40:26 +05:30
2012-08-29 19:40:27 +05:30
del_timer_sync ( & ar - > fw_recovery . hb_timer ) ;
2012-08-29 19:40:26 +05:30
cancel_work_sync ( & ar - > fw_recovery . recovery_work ) ;
}
void ath6kl_recovery_suspend ( struct ath6kl * ar )
{
2012-09-03 12:49:37 +05:30
if ( ! ar - > fw_recovery . enable )
return ;
2012-08-29 19:40:26 +05:30
ath6kl_recovery_cleanup ( ar ) ;
2012-08-29 19:40:27 +05:30
if ( ! ar - > fw_recovery . err_reason )
return ;
2012-08-29 19:40:26 +05:30
/* Process pending fw error detection */
2012-08-29 19:40:27 +05:30
ar - > fw_recovery . err_reason = 0 ;
WARN_ON ( ar - > state ! = ATH6KL_STATE_ON ) ;
ar - > state = ATH6KL_STATE_RECOVERY ;
ath6kl_init_hw_restart ( ar ) ;
ar - > state = ATH6KL_STATE_ON ;
}
void ath6kl_recovery_resume ( struct ath6kl * ar )
{
2012-09-03 12:49:37 +05:30
if ( ! ar - > fw_recovery . enable )
return ;
2012-09-03 12:49:36 +05:30
clear_bit ( RECOVERY_CLEANUP , & ar - > flag ) ;
2012-08-29 19:40:27 +05:30
if ( ! ar - > fw_recovery . hb_poll )
return ;
ar - > fw_recovery . hb_pending = false ;
ar - > fw_recovery . seq_num = 0 ;
ar - > fw_recovery . hb_misscnt = 0 ;
mod_timer ( & ar - > fw_recovery . hb_timer ,
jiffies + msecs_to_jiffies ( ar - > fw_recovery . hb_poll ) ) ;
2012-08-29 19:40:26 +05:30
}