2012-06-04 20:23:37 +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 "ath9k.h"
/*
* TX polling - checks if the TX engine is stuck somewhere
* and issues a chip reset if so .
*/
void ath_tx_complete_poll_work ( struct work_struct * work )
{
struct ath_softc * sc = container_of ( work , struct ath_softc ,
tx_complete_work . work ) ;
struct ath_txq * txq ;
int i ;
bool needreset = false ;
2013-10-14 17:42:11 -07:00
if ( sc - > tx99_state ) {
ath_dbg ( ath9k_hw_common ( sc - > sc_ah ) , RESET ,
" skip tx hung detection on tx99 \n " ) ;
return ;
}
2013-03-15 16:18:44 +01:00
for ( i = 0 ; i < IEEE80211_NUM_ACS ; i + + ) {
txq = sc - > tx . txq_map [ i ] ;
ath_txq_lock ( sc , txq ) ;
if ( txq - > axq_depth ) {
if ( txq - > axq_tx_inprogress ) {
needreset = true ;
ath_txq_unlock ( sc , txq ) ;
break ;
} else {
txq - > axq_tx_inprogress = true ;
2012-06-04 20:23:37 +05:30
}
}
2013-08-26 11:47:22 +05:30
ath_txq_unlock ( sc , txq ) ;
2013-03-15 16:18:44 +01:00
}
2012-06-04 20:23:37 +05:30
if ( needreset ) {
ath_dbg ( ath9k_hw_common ( sc - > sc_ah ) , RESET ,
" tx hung, resetting the chip \n " ) ;
2012-07-17 17:16:42 +05:30
ath9k_queue_reset ( sc , RESET_TYPE_TX_HANG ) ;
2012-06-04 20:23:43 +05:30
return ;
2012-06-04 20:23:37 +05:30
}
ieee80211_queue_delayed_work ( sc - > hw , & sc - > tx_complete_work ,
msecs_to_jiffies ( ATH_TX_COMPLETE_POLL_INT ) ) ;
}
/*
* Checks if the BB / MAC is hung .
*/
2013-12-24 10:44:25 +05:30
bool ath_hw_check ( struct ath_softc * sc )
2012-06-04 20:23:37 +05:30
{
struct ath_common * common = ath9k_hw_common ( sc - > sc_ah ) ;
2012-07-17 17:16:42 +05:30
enum ath_reset_type type ;
2013-12-24 10:44:25 +05:30
bool is_alive ;
2012-06-04 20:23:37 +05:30
ath9k_ps_wakeup ( sc ) ;
2013-12-24 10:44:25 +05:30
2012-06-04 20:23:37 +05:30
is_alive = ath9k_hw_check_alive ( sc - > sc_ah ) ;
2013-12-24 10:44:25 +05:30
if ( ! is_alive ) {
2012-06-04 20:23:37 +05:30
ath_dbg ( common , RESET ,
2013-12-24 10:44:25 +05:30
" HW hang detected, schedule chip reset \n " ) ;
2012-07-17 17:16:42 +05:30
type = RESET_TYPE_MAC_HANG ;
2013-12-24 10:44:25 +05:30
ath9k_queue_reset ( sc , type ) ;
2012-06-04 20:23:37 +05:30
}
ath9k_ps_restore ( sc ) ;
2013-12-24 10:44:25 +05:30
return is_alive ;
2012-06-04 20:23:37 +05:30
}
/*
2012-06-04 20:23:43 +05:30
* PLL - WAR for AR9485 / AR9340
2012-06-04 20:23:37 +05:30
*/
2012-06-04 20:23:43 +05:30
static bool ath_hw_pll_rx_hang_check ( struct ath_softc * sc , u32 pll_sqsum )
2012-06-04 20:23:37 +05:30
{
static int count ;
struct ath_common * common = ath9k_hw_common ( sc - > sc_ah ) ;
if ( pll_sqsum > = 0x40000 ) {
count + + ;
if ( count = = 3 ) {
2012-06-04 20:23:43 +05:30
ath_dbg ( common , RESET , " PLL WAR, resetting the chip \n " ) ;
2012-07-17 17:16:42 +05:30
ath9k_queue_reset ( sc , RESET_TYPE_PLL_HANG ) ;
2012-06-04 20:23:37 +05:30
count = 0 ;
2012-06-04 20:23:43 +05:30
return true ;
2012-06-04 20:23:37 +05:30
}
2012-06-04 20:23:43 +05:30
} else {
2012-06-04 20:23:37 +05:30
count = 0 ;
2012-06-04 20:23:43 +05:30
}
return false ;
2012-06-04 20:23:37 +05:30
}
void ath_hw_pll_work ( struct work_struct * work )
{
2012-06-04 20:23:43 +05:30
u32 pll_sqsum ;
2012-06-04 20:23:37 +05:30
struct ath_softc * sc = container_of ( work , struct ath_softc ,
hw_pll_work . work ) ;
2014-02-27 11:40:46 +01:00
struct ath_common * common = ath9k_hw_common ( sc - > sc_ah ) ;
2012-06-12 20:13:43 +05:30
/*
* ensure that the PLL WAR is executed only
* after the STA is associated ( or ) if the
* beaconing had started in interfaces that
* uses beacons .
*/
2014-02-27 11:40:46 +01:00
if ( ! test_bit ( ATH_OP_BEACONS , & common - > op_flags ) )
2012-06-12 20:13:43 +05:30
return ;
2012-06-04 20:23:37 +05:30
2013-10-14 17:42:11 -07:00
if ( sc - > tx99_state )
return ;
2012-06-04 20:23:43 +05:30
ath9k_ps_wakeup ( sc ) ;
pll_sqsum = ar9003_get_pll_sqsum_dvc ( sc - > sc_ah ) ;
ath9k_ps_restore ( sc ) ;
if ( ath_hw_pll_rx_hang_check ( sc , pll_sqsum ) )
return ;
ieee80211_queue_delayed_work ( sc - > hw , & sc - > hw_pll_work ,
msecs_to_jiffies ( ATH_PLL_WORK_INTERVAL ) ) ;
2012-06-04 20:23:37 +05:30
}
/*
* PA Pre - distortion .
*/
static void ath_paprd_activate ( struct ath_softc * sc )
{
struct ath_hw * ah = sc - > sc_ah ;
2012-12-10 07:22:33 +05:30
struct ath_common * common = ath9k_hw_common ( ah ) ;
2012-06-04 20:23:37 +05:30
struct ath9k_hw_cal_data * caldata = ah - > caldata ;
int chain ;
2013-09-11 16:36:31 +05:30
if ( ! caldata | | ! test_bit ( PAPRD_DONE , & caldata - > cal_flags ) ) {
2012-12-10 07:22:33 +05:30
ath_dbg ( common , CALIBRATE , " Failed to activate PAPRD \n " ) ;
2012-06-04 20:23:37 +05:30
return ;
2012-12-10 07:22:33 +05:30
}
2012-06-04 20:23:37 +05:30
ar9003_paprd_enable ( ah , false ) ;
for ( chain = 0 ; chain < AR9300_MAX_CHAINS ; chain + + ) {
if ( ! ( ah - > txchainmask & BIT ( chain ) ) )
continue ;
ar9003_paprd_populate_single_table ( ah , caldata , chain ) ;
}
2012-12-10 07:22:33 +05:30
ath_dbg ( common , CALIBRATE , " Activating PAPRD \n " ) ;
2012-06-04 20:23:37 +05:30
ar9003_paprd_enable ( ah , true ) ;
}
static bool ath_paprd_send_frame ( struct ath_softc * sc , struct sk_buff * skb , int chain )
{
struct ieee80211_hw * hw = sc - > hw ;
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
struct ath_hw * ah = sc - > sc_ah ;
struct ath_common * common = ath9k_hw_common ( ah ) ;
struct ath_tx_control txctl ;
int time_left ;
memset ( & txctl , 0 , sizeof ( txctl ) ) ;
2012-11-21 18:13:10 +05:30
txctl . txq = sc - > tx . txq_map [ IEEE80211_AC_BE ] ;
2012-06-04 20:23:37 +05:30
memset ( tx_info , 0 , sizeof ( * tx_info ) ) ;
2014-06-11 16:17:52 +05:30
tx_info - > band = sc - > cur_chandef . chan - > band ;
2012-06-04 20:23:37 +05:30
tx_info - > flags | = IEEE80211_TX_CTL_NO_ACK ;
tx_info - > control . rates [ 0 ] . idx = 0 ;
tx_info - > control . rates [ 0 ] . count = 1 ;
tx_info - > control . rates [ 0 ] . flags = IEEE80211_TX_RC_MCS ;
tx_info - > control . rates [ 1 ] . idx = - 1 ;
init_completion ( & sc - > paprd_complete ) ;
txctl . paprd = BIT ( chain ) ;
if ( ath_tx_start ( hw , skb , & txctl ) ! = 0 ) {
ath_dbg ( common , CALIBRATE , " PAPRD TX failed \n " ) ;
dev_kfree_skb_any ( skb ) ;
return false ;
}
time_left = wait_for_completion_timeout ( & sc - > paprd_complete ,
msecs_to_jiffies ( ATH_PAPRD_TIMEOUT ) ) ;
if ( ! time_left )
ath_dbg ( common , CALIBRATE ,
" Timeout waiting for paprd training on TX chain %d \n " ,
chain ) ;
return ! ! time_left ;
}
void ath_paprd_calibrate ( struct work_struct * work )
{
struct ath_softc * sc = container_of ( work , struct ath_softc , paprd_work ) ;
struct ieee80211_hw * hw = sc - > hw ;
struct ath_hw * ah = sc - > sc_ah ;
struct ieee80211_hdr * hdr ;
struct sk_buff * skb = NULL ;
struct ath9k_hw_cal_data * caldata = ah - > caldata ;
struct ath_common * common = ath9k_hw_common ( ah ) ;
int ftype ;
int chain_ok = 0 ;
int chain ;
int len = 1800 ;
2012-08-27 17:00:05 +02:00
int ret ;
2012-06-04 20:23:37 +05:30
2013-09-11 16:36:31 +05:30
if ( ! caldata | |
! test_bit ( PAPRD_PACKET_SENT , & caldata - > cal_flags ) | |
test_bit ( PAPRD_DONE , & caldata - > cal_flags ) ) {
2012-12-10 07:22:33 +05:30
ath_dbg ( common , CALIBRATE , " Skipping PAPRD calibration \n " ) ;
2012-06-04 20:23:37 +05:30
return ;
2012-12-10 07:22:33 +05:30
}
2012-06-04 20:23:37 +05:30
ath9k_ps_wakeup ( sc ) ;
if ( ar9003_paprd_init_table ( ah ) < 0 )
goto fail_paprd ;
skb = alloc_skb ( len , GFP_KERNEL ) ;
if ( ! skb )
goto fail_paprd ;
skb_put ( skb , len ) ;
memset ( skb - > data , 0 , len ) ;
hdr = ( struct ieee80211_hdr * ) skb - > data ;
ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC ;
hdr - > frame_control = cpu_to_le16 ( ftype ) ;
hdr - > duration_id = cpu_to_le16 ( 10 ) ;
memcpy ( hdr - > addr1 , hw - > wiphy - > perm_addr , ETH_ALEN ) ;
memcpy ( hdr - > addr2 , hw - > wiphy - > perm_addr , ETH_ALEN ) ;
memcpy ( hdr - > addr3 , hw - > wiphy - > perm_addr , ETH_ALEN ) ;
for ( chain = 0 ; chain < AR9300_MAX_CHAINS ; chain + + ) {
if ( ! ( ah - > txchainmask & BIT ( chain ) ) )
continue ;
chain_ok = 0 ;
ar9003_paprd_setup_gain_table ( ah , chain ) ;
ath_dbg ( common , CALIBRATE ,
" Sending PAPRD training frame on chain %d \n " , chain ) ;
if ( ! ath_paprd_send_frame ( sc , skb , chain ) )
goto fail_paprd ;
if ( ! ar9003_paprd_is_done ( ah ) ) {
ath_dbg ( common , CALIBRATE ,
" PAPRD not yet done on chain %d \n " , chain ) ;
break ;
}
2012-08-27 17:00:05 +02:00
ret = ar9003_paprd_create_curve ( ah , caldata , chain ) ;
if ( ret = = - EINPROGRESS ) {
ath_dbg ( common , CALIBRATE ,
" PAPRD curve on chain %d needs to be re-trained \n " ,
chain ) ;
break ;
} else if ( ret ) {
2012-06-04 20:23:37 +05:30
ath_dbg ( common , CALIBRATE ,
" PAPRD create curve failed on chain %d \n " ,
2012-06-04 20:23:43 +05:30
chain ) ;
2012-06-04 20:23:37 +05:30
break ;
}
chain_ok = 1 ;
}
kfree_skb ( skb ) ;
if ( chain_ok ) {
2013-09-11 16:36:31 +05:30
set_bit ( PAPRD_DONE , & caldata - > cal_flags ) ;
2012-06-04 20:23:37 +05:30
ath_paprd_activate ( sc ) ;
}
fail_paprd :
ath9k_ps_restore ( sc ) ;
}
/*
* ANI performs periodic noise floor calibration
* that is used to adjust and optimize the chip performance . This
* takes environmental changes ( location , temperature ) into account .
* When the task is complete , it reschedules itself depending on the
* appropriate interval that was calculated .
*/
void ath_ani_calibrate ( unsigned long data )
{
struct ath_softc * sc = ( struct ath_softc * ) data ;
struct ath_hw * ah = sc - > sc_ah ;
struct ath_common * common = ath9k_hw_common ( ah ) ;
bool longcal = false ;
bool shortcal = false ;
bool aniflag = false ;
unsigned int timestamp = jiffies_to_msecs ( jiffies ) ;
u32 cal_interval , short_cal_interval , long_cal_interval ;
unsigned long flags ;
2013-09-11 16:36:31 +05:30
if ( ah - > caldata & & test_bit ( NFCAL_INTF , & ah - > caldata - > cal_flags ) )
2012-06-04 20:23:37 +05:30
long_cal_interval = ATH_LONG_CALINTERVAL_INT ;
else
long_cal_interval = ATH_LONG_CALINTERVAL ;
short_cal_interval = ( ah - > opmode = = NL80211_IFTYPE_AP ) ?
ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL ;
/* Only calibrate if awake */
2012-10-10 23:03:02 +05:30
if ( sc - > sc_ah - > power_mode ! = ATH9K_PM_AWAKE ) {
if ( + + ah - > ani_skip_count > = ATH_ANI_MAX_SKIP_COUNT ) {
spin_lock_irqsave ( & sc - > sc_pm_lock , flags ) ;
sc - > ps_flags | = PS_WAIT_FOR_ANI ;
spin_unlock_irqrestore ( & sc - > sc_pm_lock , flags ) ;
}
2012-06-04 20:23:37 +05:30
goto set_timer ;
2012-10-10 23:03:02 +05:30
}
ah - > ani_skip_count = 0 ;
spin_lock_irqsave ( & sc - > sc_pm_lock , flags ) ;
sc - > ps_flags & = ~ PS_WAIT_FOR_ANI ;
spin_unlock_irqrestore ( & sc - > sc_pm_lock , flags ) ;
2012-06-04 20:23:37 +05:30
ath9k_ps_wakeup ( sc ) ;
/* Long calibration runs independently of short calibration. */
if ( ( timestamp - common - > ani . longcal_timer ) > = long_cal_interval ) {
longcal = true ;
common - > ani . longcal_timer = timestamp ;
}
/* Short calibration applies only while caldone is false */
if ( ! common - > ani . caldone ) {
if ( ( timestamp - common - > ani . shortcal_timer ) > = short_cal_interval ) {
shortcal = true ;
common - > ani . shortcal_timer = timestamp ;
common - > ani . resetcal_timer = timestamp ;
}
} else {
if ( ( timestamp - common - > ani . resetcal_timer ) > =
ATH_RESTART_CALINTERVAL ) {
common - > ani . caldone = ath9k_hw_reset_calvalid ( ah ) ;
if ( common - > ani . caldone )
common - > ani . resetcal_timer = timestamp ;
}
}
/* Verify whether we must check ANI */
2013-06-03 09:19:26 +05:30
if ( ( timestamp - common - > ani . checkani_timer ) > = ah - > config . ani_poll_interval ) {
2012-06-04 20:23:37 +05:30
aniflag = true ;
common - > ani . checkani_timer = timestamp ;
}
/* Call ANI routine if necessary */
if ( aniflag ) {
2013-12-26 08:14:40 +05:30
spin_lock ( & common - > cc_lock ) ;
2012-06-04 20:23:37 +05:30
ath9k_hw_ani_monitor ( ah , ah - > curchan ) ;
ath_update_survey_stats ( sc ) ;
2013-12-26 08:14:40 +05:30
spin_unlock ( & common - > cc_lock ) ;
2012-06-04 20:23:37 +05:30
}
/* Perform calibration if necessary */
if ( longcal | | shortcal ) {
2014-10-25 17:19:30 +02:00
int ret = ath9k_hw_calibrate ( ah , ah - > curchan , ah - > rxchainmask ,
longcal ) ;
if ( ret < 0 ) {
common - > ani . caldone = 0 ;
ath9k_queue_reset ( sc , RESET_TYPE_CALIBRATION ) ;
return ;
}
common - > ani . caldone = ret ;
2012-06-04 20:23:37 +05:30
}
ath_dbg ( common , ANI ,
" Calibration @%lu finished: %s %s %s, caldone: %s \n " ,
jiffies ,
longcal ? " long " : " " , shortcal ? " short " : " " ,
aniflag ? " ani " : " " , common - > ani . caldone ? " true " : " false " ) ;
ath9k_ps_restore ( sc ) ;
set_timer :
/*
* Set timer interval based on previous results .
* The interval must be the shortest necessary to satisfy ANI ,
* short calibration and long calibration .
*/
cal_interval = ATH_LONG_CALINTERVAL ;
2013-06-03 09:19:26 +05:30
cal_interval = min ( cal_interval , ( u32 ) ah - > config . ani_poll_interval ) ;
2012-06-04 20:23:37 +05:30
if ( ! common - > ani . caldone )
cal_interval = min ( cal_interval , ( u32 ) short_cal_interval ) ;
mod_timer ( & common - > ani . timer , jiffies + msecs_to_jiffies ( cal_interval ) ) ;
2012-12-10 07:22:34 +05:30
2012-12-10 07:22:37 +05:30
if ( ar9003_is_paprd_enabled ( ah ) & & ah - > caldata ) {
2013-09-11 16:36:31 +05:30
if ( ! test_bit ( PAPRD_DONE , & ah - > caldata - > cal_flags ) ) {
2012-06-04 20:23:37 +05:30
ieee80211_queue_work ( sc - > hw , & sc - > paprd_work ) ;
2012-12-10 07:22:34 +05:30
} else if ( ! ah - > paprd_table_write_done ) {
ath9k_ps_wakeup ( sc ) ;
2012-06-04 20:23:37 +05:30
ath_paprd_activate ( sc ) ;
2012-12-10 07:22:34 +05:30
ath9k_ps_restore ( sc ) ;
}
2012-06-04 20:23:37 +05:30
}
}
2012-07-17 17:16:29 +05:30
void ath_start_ani ( struct ath_softc * sc )
2012-06-04 20:23:37 +05:30
{
2012-07-17 17:16:29 +05:30
struct ath_hw * ah = sc - > sc_ah ;
struct ath_common * common = ath9k_hw_common ( ah ) ;
2012-06-04 20:23:37 +05:30
unsigned long timestamp = jiffies_to_msecs ( jiffies ) ;
2012-07-17 17:16:29 +05:30
if ( common - > disable_ani | |
2014-02-27 11:40:46 +01:00
! test_bit ( ATH_OP_ANI_RUN , & common - > op_flags ) | |
2014-06-11 16:17:49 +05:30
sc - > cur_chan - > offchannel )
2012-06-04 20:23:37 +05:30
return ;
common - > ani . longcal_timer = timestamp ;
common - > ani . shortcal_timer = timestamp ;
common - > ani . checkani_timer = timestamp ;
2012-07-17 17:16:29 +05:30
ath_dbg ( common , ANI , " Starting ANI \n " ) ;
2012-06-04 20:23:37 +05:30
mod_timer ( & common - > ani . timer ,
jiffies + msecs_to_jiffies ( ( u32 ) ah - > config . ani_poll_interval ) ) ;
}
2012-07-17 17:16:29 +05:30
void ath_stop_ani ( struct ath_softc * sc )
{
struct ath_common * common = ath9k_hw_common ( sc - > sc_ah ) ;
ath_dbg ( common , ANI , " Stopping ANI \n " ) ;
del_timer_sync ( & common - > ani . timer ) ;
}
void ath_check_ani ( struct ath_softc * sc )
{
struct ath_hw * ah = sc - > sc_ah ;
2014-02-27 11:40:46 +01:00
struct ath_common * common = ath9k_hw_common ( sc - > sc_ah ) ;
2014-06-11 16:18:02 +05:30
struct ath_beacon_config * cur_conf = & sc - > cur_chan - > beacon ;
2012-07-17 17:16:29 +05:30
/*
* Check for the various conditions in which ANI has to
* be stopped .
*/
if ( ah - > opmode = = NL80211_IFTYPE_ADHOC ) {
if ( ! cur_conf - > enable_beacon )
goto stop_ani ;
} else if ( ah - > opmode = = NL80211_IFTYPE_AP ) {
if ( ! cur_conf - > enable_beacon ) {
/*
* Disable ANI only when there are no
* associated stations .
*/
2014-02-27 11:40:46 +01:00
if ( ! test_bit ( ATH_OP_PRIM_STA_VIF , & common - > op_flags ) )
2012-07-17 17:16:29 +05:30
goto stop_ani ;
}
} else if ( ah - > opmode = = NL80211_IFTYPE_STATION ) {
2014-02-27 11:40:46 +01:00
if ( ! test_bit ( ATH_OP_PRIM_STA_VIF , & common - > op_flags ) )
2012-07-17 17:16:29 +05:30
goto stop_ani ;
}
2014-02-27 11:40:46 +01:00
if ( ! test_bit ( ATH_OP_ANI_RUN , & common - > op_flags ) ) {
set_bit ( ATH_OP_ANI_RUN , & common - > op_flags ) ;
2012-07-17 17:16:29 +05:30
ath_start_ani ( sc ) ;
}
return ;
stop_ani :
2014-02-27 11:40:46 +01:00
clear_bit ( ATH_OP_ANI_RUN , & common - > op_flags ) ;
2012-07-17 17:16:29 +05:30
ath_stop_ani ( sc ) ;
}
2012-06-04 20:23:37 +05:30
void ath_update_survey_nf ( struct ath_softc * sc , int channel )
{
struct ath_hw * ah = sc - > sc_ah ;
struct ath9k_channel * chan = & ah - > channels [ channel ] ;
struct survey_info * survey = & sc - > survey [ channel ] ;
if ( chan - > noisefloor ) {
survey - > filled | = SURVEY_INFO_NOISE_DBM ;
2013-10-11 14:09:54 +02:00
survey - > noise = ath9k_hw_getchan_noise ( ah , chan ,
chan - > noisefloor ) ;
2012-06-04 20:23:37 +05:30
}
}
/*
* Updates the survey statistics and returns the busy time since last
* update in % , if the measurement duration was long enough for the
* result to be useful , - 1 otherwise .
*/
int ath_update_survey_stats ( struct ath_softc * sc )
{
struct ath_hw * ah = sc - > sc_ah ;
struct ath_common * common = ath9k_hw_common ( ah ) ;
int pos = ah - > curchan - & ah - > channels [ 0 ] ;
struct survey_info * survey = & sc - > survey [ pos ] ;
struct ath_cycle_counters * cc = & common - > cc_survey ;
unsigned int div = common - > clockrate * 1000 ;
int ret = 0 ;
if ( ! ah - > curchan )
return - 1 ;
if ( ah - > power_mode = = ATH9K_PM_AWAKE )
ath_hw_cycle_counters_update ( common ) ;
if ( cc - > cycles > 0 ) {
2014-11-14 16:35:34 +01:00
survey - > filled | = SURVEY_INFO_TIME |
SURVEY_INFO_TIME_BUSY |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_TX ;
survey - > time + = cc - > cycles / div ;
survey - > time_busy + = cc - > rx_busy / div ;
survey - > time_rx + = cc - > rx_frame / div ;
survey - > time_tx + = cc - > tx_frame / div ;
2012-06-04 20:23:37 +05:30
}
if ( cc - > cycles < div )
return - 1 ;
if ( cc - > cycles > 0 )
ret = cc - > rx_busy * 100 / cc - > cycles ;
memset ( cc , 0 , sizeof ( * cc ) ) ;
ath_update_survey_nf ( sc , pos ) ;
return ret ;
}