2010-03-17 14:25:25 +05:30
/*
2011-05-17 13:36:18 +05:30
* Copyright ( c ) 2010 - 2011 Atheros Communications Inc .
2010-03-17 14:25:25 +05:30
*
* 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 "htc.h"
# define FUDGE 2
2011-04-13 11:23:26 +05:30
void ath9k_htc_beaconq_config ( struct ath9k_htc_priv * priv )
{
struct ath_hw * ah = priv - > ah ;
struct ath9k_tx_queue_info qi , qi_be ;
memset ( & qi , 0 , sizeof ( struct ath9k_tx_queue_info ) ) ;
memset ( & qi_be , 0 , sizeof ( struct ath9k_tx_queue_info ) ) ;
ath9k_hw_get_txq_props ( ah , priv - > beaconq , & qi ) ;
if ( priv - > ah - > opmode = = NL80211_IFTYPE_AP ) {
qi . tqi_aifs = 1 ;
qi . tqi_cwmin = 0 ;
qi . tqi_cwmax = 0 ;
} else if ( priv - > ah - > opmode = = NL80211_IFTYPE_ADHOC ) {
2012-11-21 18:13:10 +05:30
int qnum = priv - > hwq_map [ IEEE80211_AC_BE ] ;
2011-04-13 11:23:26 +05:30
ath9k_hw_get_txq_props ( ah , qnum , & qi_be ) ;
qi . tqi_aifs = qi_be . tqi_aifs ;
/*
* For WIFI Beacon Distribution
* Long slot time : 2 x cwmin
* Short slot time : 4 x cwmin
*/
if ( ah - > slottime = = ATH9K_SLOT_TIME_20 )
qi . tqi_cwmin = 2 * qi_be . tqi_cwmin ;
else
qi . tqi_cwmin = 4 * qi_be . tqi_cwmin ;
qi . tqi_cwmax = qi_be . tqi_cwmax ;
}
if ( ! ath9k_hw_set_txq_props ( ah , priv - > beaconq , & qi ) ) {
ath_err ( ath9k_hw_common ( ah ) ,
" Unable to update beacon queue %u! \n " , priv - > beaconq ) ;
} else {
ath9k_hw_resettxqueue ( ah , priv - > beaconq ) ;
}
}
2010-03-17 14:25:25 +05:30
static void ath9k_htc_beacon_config_sta ( struct ath9k_htc_priv * priv ,
2010-04-05 14:48:06 +05:30
struct htc_beacon_config * bss_conf )
2010-03-17 14:25:25 +05:30
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
struct ath9k_beacon_state bs ;
enum ath9k_int imask = 0 ;
int dtimperiod , dtimcount , sleepduration ;
int cfpperiod , cfpcount , bmiss_timeout ;
2010-04-16 11:54:03 +05:30
u32 nexttbtt = 0 , intval , tsftu ;
__be32 htc_imask = 0 ;
2010-03-17 14:25:25 +05:30
u64 tsf ;
int num_beacons , offset , dtim_dec_count , cfp_dec_count ;
2011-04-20 11:00:34 +05:30
int ret __attribute__ ( ( unused ) ) ;
2010-03-17 14:25:25 +05:30
u8 cmd_rsp ;
memset ( & bs , 0 , sizeof ( bs ) ) ;
2011-05-20 17:52:11 +05:30
intval = bss_conf - > beacon_interval ;
2010-04-05 14:48:06 +05:30
bmiss_timeout = ( ATH_DEFAULT_BMISS_LIMIT * bss_conf - > beacon_interval ) ;
2010-03-17 14:25:25 +05:30
/*
* Setup dtim and cfp parameters according to
* last beacon we received ( which may be none ) .
*/
dtimperiod = bss_conf - > dtim_period ;
if ( dtimperiod < = 0 ) /* NB: 0 if not known */
dtimperiod = 1 ;
dtimcount = 1 ;
if ( dtimcount > = dtimperiod ) /* NB: sanity check */
dtimcount = 0 ;
cfpperiod = 1 ; /* NB: no PCF support yet */
cfpcount = 0 ;
sleepduration = intval ;
if ( sleepduration < = 0 )
sleepduration = intval ;
/*
* Pull nexttbtt forward to reflect the current
* TSF and calculate dtim + cfp state for the result .
*/
tsf = ath9k_hw_gettsf64 ( priv - > ah ) ;
tsftu = TSF_TO_TU ( tsf > > 32 , tsf ) + FUDGE ;
num_beacons = tsftu / intval + 1 ;
offset = tsftu % intval ;
nexttbtt = tsftu - offset ;
if ( offset )
nexttbtt + = intval ;
/* DTIM Beacon every dtimperiod Beacon */
dtim_dec_count = num_beacons % dtimperiod ;
/* CFP every cfpperiod DTIM Beacon */
cfp_dec_count = ( num_beacons / dtimperiod ) % cfpperiod ;
if ( dtim_dec_count )
cfp_dec_count + + ;
dtimcount - = dtim_dec_count ;
if ( dtimcount < 0 )
dtimcount + = dtimperiod ;
cfpcount - = cfp_dec_count ;
if ( cfpcount < 0 )
cfpcount + = cfpperiod ;
bs . bs_intval = intval ;
bs . bs_nexttbtt = nexttbtt ;
bs . bs_dtimperiod = dtimperiod * intval ;
bs . bs_nextdtim = bs . bs_nexttbtt + dtimcount * intval ;
bs . bs_cfpperiod = cfpperiod * bs . bs_dtimperiod ;
bs . bs_cfpnext = bs . bs_nextdtim + cfpcount * bs . bs_dtimperiod ;
bs . bs_cfpmaxduration = 0 ;
/*
* Calculate the number of consecutive beacons to miss * before taking
* a BMISS interrupt . The configuration is specified in TU so we only
* need calculate based on the beacon interval . Note that we clamp the
* result to at most 15 beacons .
*/
if ( sleepduration > intval ) {
bs . bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2 ;
} else {
bs . bs_bmissthreshold = DIV_ROUND_UP ( bmiss_timeout , intval ) ;
if ( bs . bs_bmissthreshold > 15 )
bs . bs_bmissthreshold = 15 ;
else if ( bs . bs_bmissthreshold < = 0 )
bs . bs_bmissthreshold = 1 ;
}
/*
* Calculate sleep duration . The configuration is given in ms .
* We ensure a multiple of the beacon period is used . Also , if the sleep
* duration is greater than the DTIM period then it makes senses
* to make it a multiple of that .
*
* XXX fixed at 100 ms
*/
bs . bs_sleepduration = roundup ( IEEE80211_MS_TO_TU ( 100 ) , sleepduration ) ;
if ( bs . bs_sleepduration > bs . bs_dtimperiod )
bs . bs_sleepduration = bs . bs_dtimperiod ;
/* TSF out of range threshold fixed at 1 second */
bs . bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG , " intval: %u tsf: %llu tsftu: %u \n " ,
2011-02-27 09:20:40 +05:30
intval , tsf , tsftu ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG ,
2010-12-02 19:12:37 -08:00
" bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u \n " ,
bs . bs_bmissthreshold , bs . bs_sleepduration ,
bs . bs_cfpperiod , bs . bs_cfpmaxduration , bs . bs_cfpnext ) ;
2010-03-17 14:25:25 +05:30
/* Set the computed STA beacon timers */
WMI_CMD ( WMI_DISABLE_INTR_CMDID ) ;
ath9k_hw_set_sta_beacon_timers ( priv - > ah , & bs ) ;
imask | = ATH9K_INT_BMISS ;
htc_imask = cpu_to_be32 ( imask ) ;
WMI_CMD_BUF ( WMI_ENABLE_INTR_CMDID , & htc_imask ) ;
}
2011-02-21 07:49:53 +05:30
static void ath9k_htc_beacon_config_ap ( struct ath9k_htc_priv * priv ,
struct htc_beacon_config * bss_conf )
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
enum ath9k_int imask = 0 ;
u32 nexttbtt , intval , tsftu ;
__be32 htc_imask = 0 ;
2011-04-20 11:00:34 +05:30
int ret __attribute__ ( ( unused ) ) ;
2011-02-21 07:49:53 +05:30
u8 cmd_rsp ;
u64 tsf ;
2011-05-20 17:52:11 +05:30
intval = bss_conf - > beacon_interval ;
2011-02-21 07:49:53 +05:30
intval / = ATH9K_HTC_MAX_BCN_VIF ;
nexttbtt = intval ;
2011-04-13 11:23:44 +05:30
/*
* To reduce beacon misses under heavy TX load ,
* set the beacon response time to a larger value .
*/
if ( intval > DEFAULT_SWBA_RESPONSE )
priv - > ah - > config . sw_beacon_response_time = DEFAULT_SWBA_RESPONSE ;
else
priv - > ah - > config . sw_beacon_response_time = MIN_SWBA_RESPONSE ;
2012-06-25 13:54:41 +05:30
if ( test_bit ( OP_TSF_RESET , & priv - > op_flags ) ) {
2011-03-22 21:54:17 +01:00
ath9k_hw_reset_tsf ( priv - > ah ) ;
2012-06-25 13:54:41 +05:30
clear_bit ( OP_TSF_RESET , & priv - > op_flags ) ;
2011-02-21 07:49:53 +05:30
} else {
/*
* Pull nexttbtt forward to reflect the current TSF .
*/
tsf = ath9k_hw_gettsf64 ( priv - > ah ) ;
tsftu = TSF_TO_TU ( tsf > > 32 , tsf ) + FUDGE ;
do {
nexttbtt + = intval ;
} while ( nexttbtt < tsftu ) ;
}
2012-06-25 13:54:41 +05:30
if ( test_bit ( OP_ENABLE_BEACON , & priv - > op_flags ) )
2011-02-21 07:49:53 +05:30
imask | = ATH9K_INT_SWBA ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG ,
" AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d imask: 0x%x \n " ,
2011-04-13 11:23:44 +05:30
bss_conf - > beacon_interval , nexttbtt ,
priv - > ah - > config . sw_beacon_response_time , imask ) ;
2011-02-21 07:49:53 +05:30
2011-04-13 11:23:26 +05:30
ath9k_htc_beaconq_config ( priv ) ;
2011-02-21 07:49:53 +05:30
WMI_CMD ( WMI_DISABLE_INTR_CMDID ) ;
2011-03-22 21:54:17 +01:00
ath9k_hw_beaconinit ( priv - > ah , TU_TO_USEC ( nexttbtt ) , TU_TO_USEC ( intval ) ) ;
2011-04-13 11:23:08 +05:30
priv - > cur_beacon_conf . bmiss_cnt = 0 ;
2011-02-21 07:49:53 +05:30
htc_imask = cpu_to_be32 ( imask ) ;
WMI_CMD_BUF ( WMI_ENABLE_INTR_CMDID , & htc_imask ) ;
}
2010-03-17 14:25:25 +05:30
static void ath9k_htc_beacon_config_adhoc ( struct ath9k_htc_priv * priv ,
2010-04-05 14:48:06 +05:30
struct htc_beacon_config * bss_conf )
2010-03-17 14:25:25 +05:30
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
enum ath9k_int imask = 0 ;
2011-02-21 07:50:01 +05:30
u32 nexttbtt , intval , tsftu ;
2010-04-16 11:54:03 +05:30
__be32 htc_imask = 0 ;
2011-04-20 11:00:34 +05:30
int ret __attribute__ ( ( unused ) ) ;
2010-03-17 14:25:25 +05:30
u8 cmd_rsp ;
2011-02-21 07:50:01 +05:30
u64 tsf ;
2010-03-17 14:25:25 +05:30
2011-05-20 17:52:11 +05:30
intval = bss_conf - > beacon_interval ;
2010-03-17 14:25:25 +05:30
nexttbtt = intval ;
2011-02-21 07:50:01 +05:30
/*
* Pull nexttbtt forward to reflect the current TSF .
*/
tsf = ath9k_hw_gettsf64 ( priv - > ah ) ;
tsftu = TSF_TO_TU ( tsf > > 32 , tsf ) + FUDGE ;
do {
nexttbtt + = intval ;
} while ( nexttbtt < tsftu ) ;
2011-04-13 11:23:44 +05:30
/*
* Only one IBSS interfce is allowed .
*/
if ( intval > DEFAULT_SWBA_RESPONSE )
priv - > ah - > config . sw_beacon_response_time = DEFAULT_SWBA_RESPONSE ;
else
priv - > ah - > config . sw_beacon_response_time = MIN_SWBA_RESPONSE ;
2012-06-25 13:54:41 +05:30
if ( test_bit ( OP_ENABLE_BEACON , & priv - > op_flags ) )
2010-03-17 14:25:25 +05:30
imask | = ATH9K_INT_SWBA ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG ,
" IBSS Beacon config, intval: %d, nexttbtt: %u, resp_time: %d, imask: 0x%x \n " ,
2011-04-13 11:23:44 +05:30
bss_conf - > beacon_interval , nexttbtt ,
priv - > ah - > config . sw_beacon_response_time , imask ) ;
2010-03-17 14:25:25 +05:30
WMI_CMD ( WMI_DISABLE_INTR_CMDID ) ;
2011-03-22 21:54:17 +01:00
ath9k_hw_beaconinit ( priv - > ah , TU_TO_USEC ( nexttbtt ) , TU_TO_USEC ( intval ) ) ;
2011-04-13 11:23:08 +05:30
priv - > cur_beacon_conf . bmiss_cnt = 0 ;
2010-03-17 14:25:25 +05:30
htc_imask = cpu_to_be32 ( imask ) ;
WMI_CMD_BUF ( WMI_ENABLE_INTR_CMDID , & htc_imask ) ;
}
2010-05-06 14:45:47 +05:30
void ath9k_htc_beaconep ( void * drv_priv , struct sk_buff * skb ,
enum htc_endpoint_id ep_id , bool txok )
2010-03-17 14:25:25 +05:30
{
2010-05-06 14:45:47 +05:30
dev_kfree_skb_any ( skb ) ;
2010-03-17 14:25:25 +05:30
}
2011-04-13 11:23:34 +05:30
static void ath9k_htc_send_buffered ( struct ath9k_htc_priv * priv ,
int slot )
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
struct ieee80211_vif * vif ;
struct sk_buff * skb ;
struct ieee80211_hdr * hdr ;
2011-04-13 11:25:47 +05:30
int padpos , padsize , ret , tx_slot ;
2011-04-13 11:23:34 +05:30
spin_lock_bh ( & priv - > beacon_lock ) ;
vif = priv - > cur_beacon_conf . bslot [ slot ] ;
skb = ieee80211_get_buffered_bc ( priv - > hw , vif ) ;
while ( skb ) {
hdr = ( struct ieee80211_hdr * ) skb - > data ;
padpos = ath9k_cmn_padpos ( hdr - > frame_control ) ;
padsize = padpos & 3 ;
if ( padsize & & skb - > len > padpos ) {
if ( skb_headroom ( skb ) < padsize ) {
dev_kfree_skb_any ( skb ) ;
goto next ;
}
skb_push ( skb , padsize ) ;
memmove ( skb - > data , skb - > data + padsize , padpos ) ;
}
2011-04-13 11:25:47 +05:30
tx_slot = ath9k_htc_tx_get_slot ( priv ) ;
2011-04-16 14:17:39 +05:30
if ( tx_slot < 0 ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , XMIT , " No free CAB slot \n " ) ;
2011-04-13 11:25:47 +05:30
dev_kfree_skb_any ( skb ) ;
goto next ;
}
2012-07-23 21:33:42 +02:00
ret = ath9k_htc_tx_start ( priv , NULL , skb , tx_slot , true ) ;
2011-04-13 11:23:34 +05:30
if ( ret ! = 0 ) {
2011-04-13 11:25:47 +05:30
ath9k_htc_tx_clear_slot ( priv , tx_slot ) ;
2011-04-13 11:23:34 +05:30
dev_kfree_skb_any ( skb ) ;
2011-04-13 11:25:47 +05:30
2011-12-15 14:55:53 -08:00
ath_dbg ( common , XMIT , " Failed to send CAB frame \n " ) ;
2011-04-13 11:25:29 +05:30
} else {
spin_lock_bh ( & priv - > tx . tx_lock ) ;
priv - > tx . queued_cnt + + ;
spin_unlock_bh ( & priv - > tx . tx_lock ) ;
2011-04-13 11:23:34 +05:30
}
next :
skb = ieee80211_get_buffered_bc ( priv - > hw , vif ) ;
}
spin_unlock_bh ( & priv - > beacon_lock ) ;
}
2011-04-13 11:23:08 +05:30
static void ath9k_htc_send_beacon ( struct ath9k_htc_priv * priv ,
int slot )
2010-03-17 14:25:25 +05:30
{
2011-04-13 11:23:44 +05:30
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
2011-04-13 11:23:08 +05:30
struct ieee80211_vif * vif ;
struct ath9k_htc_vif * avp ;
2010-03-17 14:25:25 +05:30
struct tx_beacon_header beacon_hdr ;
2011-04-13 11:24:31 +05:30
struct ath9k_htc_tx_ctl * tx_ctl ;
2010-03-17 14:25:25 +05:30
struct ieee80211_tx_info * info ;
2011-04-13 11:23:17 +05:30
struct ieee80211_mgmt * mgmt ;
2010-05-06 14:45:47 +05:30
struct sk_buff * beacon ;
2010-03-17 14:25:25 +05:30
u8 * tx_fhdr ;
2011-04-13 11:23:44 +05:30
int ret ;
2010-03-17 14:25:25 +05:30
memset ( & beacon_hdr , 0 , sizeof ( struct tx_beacon_header ) ) ;
spin_lock_bh ( & priv - > beacon_lock ) ;
2011-04-13 11:23:08 +05:30
vif = priv - > cur_beacon_conf . bslot [ slot ] ;
avp = ( struct ath9k_htc_vif * ) vif - > drv_priv ;
2012-06-25 13:54:41 +05:30
if ( unlikely ( test_bit ( OP_SCANNING , & priv - > op_flags ) ) ) {
2010-03-17 14:25:25 +05:30
spin_unlock_bh ( & priv - > beacon_lock ) ;
return ;
}
/* Get a new beacon */
2011-04-13 11:23:08 +05:30
beacon = ieee80211_beacon_get ( priv - > hw , vif ) ;
2010-05-06 14:45:47 +05:30
if ( ! beacon ) {
2010-03-17 14:25:25 +05:30
spin_unlock_bh ( & priv - > beacon_lock ) ;
return ;
}
2011-04-13 11:23:17 +05:30
/*
* Update the TSF adjust value here , the HW will
* add this value for every beacon .
*/
mgmt = ( struct ieee80211_mgmt * ) beacon - > data ;
mgmt - > u . beacon . timestamp = avp - > tsfadjust ;
2010-05-06 14:45:47 +05:30
info = IEEE80211_SKB_CB ( beacon ) ;
2010-03-17 14:25:25 +05:30
if ( info - > flags & IEEE80211_TX_CTL_ASSIGN_SEQ ) {
struct ieee80211_hdr * hdr =
2010-05-06 14:45:47 +05:30
( struct ieee80211_hdr * ) beacon - > data ;
2011-02-21 07:48:53 +05:30
avp - > seq_no + = 0x10 ;
2010-03-17 14:25:25 +05:30
hdr - > seq_ctrl & = cpu_to_le16 ( IEEE80211_SCTL_FRAG ) ;
2011-02-21 07:48:53 +05:30
hdr - > seq_ctrl | = cpu_to_le16 ( avp - > seq_no ) ;
2010-03-17 14:25:25 +05:30
}
2011-04-13 11:24:31 +05:30
tx_ctl = HTC_SKB_CB ( beacon ) ;
memset ( tx_ctl , 0 , sizeof ( * tx_ctl ) ) ;
tx_ctl - > type = ATH9K_HTC_BEACON ;
2011-04-13 11:25:35 +05:30
tx_ctl - > epid = priv - > beacon_ep ;
2011-04-13 11:24:31 +05:30
2010-03-17 14:25:25 +05:30
beacon_hdr . vif_index = avp - > index ;
2010-05-06 14:45:47 +05:30
tx_fhdr = skb_push ( beacon , sizeof ( beacon_hdr ) ) ;
2010-03-17 14:25:25 +05:30
memcpy ( tx_fhdr , ( u8 * ) & beacon_hdr , sizeof ( beacon_hdr ) ) ;
2011-04-13 11:25:35 +05:30
ret = htc_send ( priv - > htc , beacon ) ;
2011-04-13 11:23:44 +05:30
if ( ret ! = 0 ) {
if ( ret = = - ENOMEM ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , BSTUCK ,
2011-04-13 11:23:44 +05:30
" Failed to send beacon, no free TX buffer \n " ) ;
}
dev_kfree_skb_any ( beacon ) ;
}
2010-03-17 14:25:25 +05:30
spin_unlock_bh ( & priv - > beacon_lock ) ;
}
2011-04-13 11:23:52 +05:30
static int ath9k_htc_choose_bslot ( struct ath9k_htc_priv * priv ,
struct wmi_event_swba * swba )
2011-04-13 11:23:08 +05:30
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
u64 tsf ;
u32 tsftu ;
u16 intval ;
int slot ;
2011-05-20 17:52:11 +05:30
intval = priv - > cur_beacon_conf . beacon_interval ;
2011-04-13 11:23:08 +05:30
2011-04-13 11:23:52 +05:30
tsf = be64_to_cpu ( swba - > tsf ) ;
2011-04-13 11:23:08 +05:30
tsftu = TSF_TO_TU ( tsf > > 32 , tsf ) ;
slot = ( ( tsftu % intval ) * ATH9K_HTC_MAX_BCN_VIF ) / intval ;
slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1 ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , BEACON ,
2011-04-13 11:23:08 +05:30
" Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u \n " ,
slot , tsf , tsftu , intval ) ;
return slot ;
}
2011-04-13 11:23:52 +05:30
void ath9k_htc_swba ( struct ath9k_htc_priv * priv ,
struct wmi_event_swba * swba )
2011-04-13 11:23:08 +05:30
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
int slot ;
2011-04-13 11:23:52 +05:30
if ( swba - > beacon_pending ! = 0 ) {
2011-04-13 11:23:08 +05:30
priv - > cur_beacon_conf . bmiss_cnt + + ;
if ( priv - > cur_beacon_conf . bmiss_cnt > BSTUCK_THRESHOLD ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , BSTUCK , " Beacon stuck, HW reset \n " ) ;
2011-04-13 11:23:52 +05:30
ieee80211_queue_work ( priv - > hw ,
& priv - > fatal_work ) ;
2011-04-13 11:23:08 +05:30
}
return ;
}
if ( priv - > cur_beacon_conf . bmiss_cnt ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , BSTUCK ,
2011-04-13 11:23:08 +05:30
" Resuming beacon xmit after %u misses \n " ,
priv - > cur_beacon_conf . bmiss_cnt ) ;
priv - > cur_beacon_conf . bmiss_cnt = 0 ;
}
2011-04-13 11:23:52 +05:30
slot = ath9k_htc_choose_bslot ( priv , swba ) ;
2011-04-13 11:23:08 +05:30
spin_lock_bh ( & priv - > beacon_lock ) ;
if ( priv - > cur_beacon_conf . bslot [ slot ] = = NULL ) {
spin_unlock_bh ( & priv - > beacon_lock ) ;
return ;
}
spin_unlock_bh ( & priv - > beacon_lock ) ;
2011-04-13 11:23:34 +05:30
ath9k_htc_send_buffered ( priv , slot ) ;
2011-04-13 11:23:08 +05:30
ath9k_htc_send_beacon ( priv , slot ) ;
}
void ath9k_htc_assign_bslot ( struct ath9k_htc_priv * priv ,
struct ieee80211_vif * vif )
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
struct ath9k_htc_vif * avp = ( struct ath9k_htc_vif * ) vif - > drv_priv ;
int i = 0 ;
spin_lock_bh ( & priv - > beacon_lock ) ;
for ( i = 0 ; i < ATH9K_HTC_MAX_BCN_VIF ; i + + ) {
if ( priv - > cur_beacon_conf . bslot [ i ] = = NULL ) {
avp - > bslot = i ;
break ;
}
}
priv - > cur_beacon_conf . bslot [ avp - > bslot ] = vif ;
spin_unlock_bh ( & priv - > beacon_lock ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG , " Added interface at beacon slot: %d \n " ,
avp - > bslot ) ;
2011-04-13 11:23:08 +05:30
}
void ath9k_htc_remove_bslot ( struct ath9k_htc_priv * priv ,
struct ieee80211_vif * vif )
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
struct ath9k_htc_vif * avp = ( struct ath9k_htc_vif * ) vif - > drv_priv ;
spin_lock_bh ( & priv - > beacon_lock ) ;
priv - > cur_beacon_conf . bslot [ avp - > bslot ] = NULL ;
spin_unlock_bh ( & priv - > beacon_lock ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG , " Removed interface at beacon slot: %d \n " ,
avp - > bslot ) ;
2011-04-13 11:23:08 +05:30
}
2011-04-13 11:23:17 +05:30
/*
* Calculate the TSF adjustment value for all slots
* other than zero .
*/
void ath9k_htc_set_tsfadjust ( struct ath9k_htc_priv * priv ,
struct ieee80211_vif * vif )
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
struct ath9k_htc_vif * avp = ( struct ath9k_htc_vif * ) vif - > drv_priv ;
struct htc_beacon_config * cur_conf = & priv - > cur_beacon_conf ;
u64 tsfadjust ;
if ( avp - > bslot = = 0 )
return ;
/*
* The beacon interval cannot be different for multi - AP mode ,
* and we reach here only for VIF slots greater than zero ,
* so beacon_interval is guaranteed to be set in cur_conf .
*/
tsfadjust = cur_conf - > beacon_interval * avp - > bslot / ATH9K_HTC_MAX_BCN_VIF ;
avp - > tsfadjust = cpu_to_le64 ( TU_TO_USEC ( tsfadjust ) ) ;
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG , " tsfadjust is: %llu for bslot: %d \n " ,
2011-04-13 11:23:17 +05:30
( unsigned long long ) tsfadjust , avp - > bslot ) ;
}
2011-02-27 09:20:40 +05:30
static void ath9k_htc_beacon_iter ( void * data , u8 * mac , struct ieee80211_vif * vif )
{
bool * beacon_configured = ( bool * ) data ;
struct ath9k_htc_vif * avp = ( struct ath9k_htc_vif * ) vif - > drv_priv ;
if ( vif - > type = = NL80211_IFTYPE_STATION & &
avp - > beacon_configured )
* beacon_configured = true ;
}
static bool ath9k_htc_check_beacon_config ( struct ath9k_htc_priv * priv ,
struct ieee80211_vif * vif )
2010-03-17 14:25:25 +05:30
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
2010-04-05 14:48:06 +05:30
struct htc_beacon_config * cur_conf = & priv - > cur_beacon_conf ;
2010-04-16 11:53:48 +05:30
struct ieee80211_bss_conf * bss_conf = & vif - > bss_conf ;
2011-02-27 09:20:40 +05:30
bool beacon_configured ;
2010-04-05 14:48:06 +05:30
2011-02-21 07:49:53 +05:30
/*
* Changing the beacon interval when multiple AP interfaces
* are configured will affect beacon transmission of all
* of them .
*/
if ( ( priv - > ah - > opmode = = NL80211_IFTYPE_AP ) & &
( priv - > num_ap_vif > 1 ) & &
( vif - > type = = NL80211_IFTYPE_AP ) & &
( cur_conf - > beacon_interval ! = bss_conf - > beacon_int ) ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG ,
2011-02-21 07:49:53 +05:30
" Changing beacon interval of multiple AP interfaces ! \n " ) ;
2011-02-27 09:20:40 +05:30
return false ;
2011-02-21 07:49:53 +05:30
}
/*
* If the HW is operating in AP mode , any new station interfaces that
* are added cannot change the beacon parameters .
*/
if ( priv - > num_ap_vif & &
( vif - > type ! = NL80211_IFTYPE_AP ) ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG ,
2011-02-21 07:49:53 +05:30
" HW in AP mode, cannot set STA beacon parameters \n " ) ;
2011-02-27 09:20:40 +05:30
return false ;
}
/*
* The beacon parameters are configured only for the first
* station interface .
*/
if ( ( priv - > ah - > opmode = = NL80211_IFTYPE_STATION ) & &
( priv - > num_sta_vif > 1 ) & &
( vif - > type = = NL80211_IFTYPE_STATION ) ) {
beacon_configured = false ;
2012-11-06 20:23:30 +01:00
ieee80211_iterate_active_interfaces_atomic (
priv - > hw , IEEE80211_IFACE_ITER_RESUME_ALL ,
ath9k_htc_beacon_iter , & beacon_configured ) ;
2011-02-27 09:20:40 +05:30
if ( beacon_configured ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG ,
2011-02-27 09:20:40 +05:30
" Beacon already configured for a station interface \n " ) ;
return false ;
}
2011-02-21 07:49:53 +05:30
}
2011-02-27 09:20:40 +05:30
return true ;
}
void ath9k_htc_beacon_config ( struct ath9k_htc_priv * priv ,
struct ieee80211_vif * vif )
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
struct htc_beacon_config * cur_conf = & priv - > cur_beacon_conf ;
struct ieee80211_bss_conf * bss_conf = & vif - > bss_conf ;
struct ath9k_htc_vif * avp = ( struct ath9k_htc_vif * ) vif - > drv_priv ;
if ( ! ath9k_htc_check_beacon_config ( priv , vif ) )
return ;
2010-04-16 11:53:48 +05:30
cur_conf - > beacon_interval = bss_conf - > beacon_int ;
2010-04-05 14:48:06 +05:30
if ( cur_conf - > beacon_interval = = 0 )
cur_conf - > beacon_interval = 100 ;
2010-04-16 11:53:48 +05:30
cur_conf - > dtim_period = bss_conf - > dtim_period ;
cur_conf - > bmiss_timeout =
ATH_DEFAULT_BMISS_LIMIT * cur_conf - > beacon_interval ;
switch ( vif - > type ) {
2010-03-17 14:25:25 +05:30
case NL80211_IFTYPE_STATION :
2010-04-05 14:48:06 +05:30
ath9k_htc_beacon_config_sta ( priv , cur_conf ) ;
2011-02-27 09:20:40 +05:30
avp - > beacon_configured = true ;
2010-03-17 14:25:25 +05:30
break ;
case NL80211_IFTYPE_ADHOC :
2010-04-05 14:48:06 +05:30
ath9k_htc_beacon_config_adhoc ( priv , cur_conf ) ;
2010-03-17 14:25:25 +05:30
break ;
2011-02-21 07:49:53 +05:30
case NL80211_IFTYPE_AP :
ath9k_htc_beacon_config_ap ( priv , cur_conf ) ;
break ;
2010-03-17 14:25:25 +05:30
default :
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG , " Unsupported beaconing mode \n " ) ;
2010-03-17 14:25:25 +05:30
return ;
}
}
2011-02-21 07:48:39 +05:30
void ath9k_htc_beacon_reconfig ( struct ath9k_htc_priv * priv )
{
struct ath_common * common = ath9k_hw_common ( priv - > ah ) ;
struct htc_beacon_config * cur_conf = & priv - > cur_beacon_conf ;
switch ( priv - > ah - > opmode ) {
case NL80211_IFTYPE_STATION :
ath9k_htc_beacon_config_sta ( priv , cur_conf ) ;
break ;
case NL80211_IFTYPE_ADHOC :
ath9k_htc_beacon_config_adhoc ( priv , cur_conf ) ;
break ;
2011-02-21 07:49:53 +05:30
case NL80211_IFTYPE_AP :
ath9k_htc_beacon_config_ap ( priv , cur_conf ) ;
break ;
2011-02-21 07:48:39 +05:30
default :
2011-12-15 14:55:53 -08:00
ath_dbg ( common , CONFIG , " Unsupported beaconing mode \n " ) ;
2011-02-21 07:48:39 +05:30
return ;
}
}