2008-08-04 00:16:41 -07:00
/*
2009-03-13 09:07:23 +05:30
* Copyright ( c ) 2008 - 2009 Atheros Communications Inc .
2008-08-04 00:16:41 -07:00
*
* 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 .
*/
2009-02-09 13:26:54 +05:30
# include "ath9k.h"
2008-08-04 00:16:41 -07:00
# define BITS_PER_BYTE 8
# define OFDM_PLCP_BITS 22
# define HT_RC_2_MCS(_rc) ((_rc) & 0x0f)
# define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
# define L_STF 8
# define L_LTF 8
# define L_SIG 4
# define HT_SIG 8
# define HT_STF 4
# define HT_LTF(_ns) (4 * (_ns))
# define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */
# define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
# define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
# define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4) / 18)
# define OFDM_SIFS_TIME 16
static u32 bits_per_symbol [ ] [ 2 ] = {
/* 20MHz 40MHz */
{ 26 , 54 } , /* 0: BPSK */
{ 52 , 108 } , /* 1: QPSK 1/2 */
{ 78 , 162 } , /* 2: QPSK 3/4 */
{ 104 , 216 } , /* 3: 16-QAM 1/2 */
{ 156 , 324 } , /* 4: 16-QAM 3/4 */
{ 208 , 432 } , /* 5: 64-QAM 2/3 */
{ 234 , 486 } , /* 6: 64-QAM 3/4 */
{ 260 , 540 } , /* 7: 64-QAM 5/6 */
{ 52 , 108 } , /* 8: BPSK */
{ 104 , 216 } , /* 9: QPSK 1/2 */
{ 156 , 324 } , /* 10: QPSK 3/4 */
{ 208 , 432 } , /* 11: 16-QAM 1/2 */
{ 312 , 648 } , /* 12: 16-QAM 3/4 */
{ 416 , 864 } , /* 13: 64-QAM 2/3 */
{ 468 , 972 } , /* 14: 64-QAM 3/4 */
{ 520 , 1080 } , /* 15: 64-QAM 5/6 */
} ;
# define IS_HT_RATE(_rate) ((_rate) & 0x80)
2009-03-09 09:31:57 +05:30
static void ath_tx_send_ht_normal ( struct ath_softc * sc , struct ath_txq * txq ,
struct ath_atx_tid * tid ,
struct list_head * bf_head ) ;
2009-01-16 21:38:42 +05:30
static void ath_tx_complete_buf ( struct ath_softc * sc , struct ath_buf * bf ,
struct list_head * bf_q ,
int txok , int sendbar ) ;
2008-10-29 10:15:16 +05:30
static void ath_tx_txqaddbuf ( struct ath_softc * sc , struct ath_txq * txq ,
2009-01-16 21:38:42 +05:30
struct list_head * head ) ;
static void ath_buf_set_rate ( struct ath_softc * sc , struct ath_buf * bf ) ;
2009-03-18 20:22:00 +05:30
static int ath_tx_num_badfrms ( struct ath_softc * sc , struct ath_buf * bf ,
int txok ) ;
static void ath_tx_rc_status ( struct ath_buf * bf , struct ath_desc * ds ,
2009-03-20 15:27:49 +05:30
int nbad , int txok , bool update_rc ) ;
2008-11-18 09:09:30 +05:30
2009-01-16 21:38:42 +05:30
/*********************/
/* Aggregation logic */
/*********************/
2008-08-04 00:16:41 -07:00
2008-10-29 10:15:40 +05:30
static int ath_aggr_query ( struct ath_softc * sc , struct ath_node * an , u8 tidno )
2008-08-04 00:16:41 -07:00
{
struct ath_atx_tid * tid ;
tid = ATH_AN_2_TID ( an , tidno ) ;
2008-10-29 10:15:40 +05:30
if ( tid - > state & AGGR_ADDBA_COMPLETE | |
tid - > state & AGGR_ADDBA_PROGRESS )
2008-08-04 00:16:41 -07:00
return 1 ;
else
return 0 ;
}
2009-01-16 21:38:42 +05:30
static void ath_tx_queue_tid ( struct ath_txq * txq , struct ath_atx_tid * tid )
2008-11-24 12:07:55 +05:30
{
2009-01-16 21:38:42 +05:30
struct ath_atx_ac * ac = tid - > ac ;
2008-11-24 12:07:55 +05:30
2009-01-16 21:38:42 +05:30
if ( tid - > paused )
return ;
2008-11-24 12:07:55 +05:30
2009-01-16 21:38:42 +05:30
if ( tid - > sched )
return ;
2008-11-24 12:07:55 +05:30
2009-01-16 21:38:42 +05:30
tid - > sched = true ;
list_add_tail ( & tid - > list , & ac - > tid_q ) ;
2008-10-29 10:14:26 +05:30
2009-01-16 21:38:42 +05:30
if ( ac - > sched )
return ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
ac - > sched = true ;
list_add_tail ( & ac - > list , & txq - > axq_acq ) ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
static void ath_tx_pause_tid ( struct ath_softc * sc , struct ath_atx_tid * tid )
{
struct ath_txq * txq = & sc - > tx . txq [ tid - > ac - > qnum ] ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
spin_lock_bh ( & txq - > axq_lock ) ;
tid - > paused + + ;
spin_unlock_bh ( & txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
static void ath_tx_resume_tid ( struct ath_softc * sc , struct ath_atx_tid * tid )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
struct ath_txq * txq = & sc - > tx . txq [ tid - > ac - > qnum ] ;
2008-10-21 12:40:02 +02:00
2009-01-16 21:38:42 +05:30
ASSERT ( tid - > paused > 0 ) ;
spin_lock_bh ( & txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
tid - > paused - - ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( tid - > paused > 0 )
goto unlock ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( list_empty ( & tid - > buf_q ) )
goto unlock ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
ath_tx_queue_tid ( txq , tid ) ;
ath_txq_schedule ( sc , txq ) ;
unlock :
spin_unlock_bh ( & txq - > axq_lock ) ;
2008-10-29 10:14:26 +05:30
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
static void ath_tx_flush_tid ( struct ath_softc * sc , struct ath_atx_tid * tid )
2008-10-29 10:14:26 +05:30
{
2009-01-16 21:38:42 +05:30
struct ath_txq * txq = & sc - > tx . txq [ tid - > ac - > qnum ] ;
struct ath_buf * bf ;
struct list_head bf_head ;
INIT_LIST_HEAD ( & bf_head ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
ASSERT ( tid - > paused > 0 ) ;
spin_lock_bh ( & txq - > axq_lock ) ;
2008-10-21 12:40:02 +02:00
2009-01-16 21:38:42 +05:30
tid - > paused - - ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( tid - > paused > 0 ) {
spin_unlock_bh ( & txq - > axq_lock ) ;
return ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
while ( ! list_empty ( & tid - > buf_q ) ) {
bf = list_first_entry ( & tid - > buf_q , struct ath_buf , list ) ;
ASSERT ( ! bf_isretried ( bf ) ) ;
2009-01-16 21:38:53 +05:30
list_move_tail ( & bf - > list , & bf_head ) ;
2009-03-09 09:31:57 +05:30
ath_tx_send_ht_normal ( sc , txq , tid , & bf_head ) ;
2008-10-29 10:14:26 +05:30
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
spin_unlock_bh ( & txq - > axq_lock ) ;
2008-10-29 10:14:26 +05:30
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
static void ath_tx_update_baw ( struct ath_softc * sc , struct ath_atx_tid * tid ,
int seqno )
2008-10-29 10:14:26 +05:30
{
2009-01-16 21:38:42 +05:30
int index , cindex ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
index = ATH_BA_INDEX ( tid - > seq_start , seqno ) ;
cindex = ( tid - > baw_head + index ) & ( ATH_TID_MAX_BUFS - 1 ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
tid - > tx_buf [ cindex ] = NULL ;
2008-10-29 10:14:26 +05:30
2009-01-16 21:38:42 +05:30
while ( tid - > baw_head ! = tid - > baw_tail & & ! tid - > tx_buf [ tid - > baw_head ] ) {
INCR ( tid - > seq_start , IEEE80211_SEQ_MAX ) ;
INCR ( tid - > baw_head , ATH_TID_MAX_BUFS ) ;
}
2008-10-29 10:14:26 +05:30
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
static void ath_tx_addto_baw ( struct ath_softc * sc , struct ath_atx_tid * tid ,
struct ath_buf * bf )
2008-10-29 10:14:26 +05:30
{
2009-01-16 21:38:42 +05:30
int index , cindex ;
2008-10-29 10:14:26 +05:30
2009-01-16 21:38:42 +05:30
if ( bf_isretried ( bf ) )
return ;
2008-10-29 10:14:26 +05:30
2009-01-16 21:38:42 +05:30
index = ATH_BA_INDEX ( tid - > seq_start , bf - > bf_seqno ) ;
cindex = ( tid - > baw_head + index ) & ( ATH_TID_MAX_BUFS - 1 ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
ASSERT ( tid - > tx_buf [ cindex ] = = NULL ) ;
tid - > tx_buf [ cindex ] = bf ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( index > = ( ( tid - > baw_tail - tid - > baw_head ) &
( ATH_TID_MAX_BUFS - 1 ) ) ) {
tid - > baw_tail = cindex ;
INCR ( tid - > baw_tail , ATH_TID_MAX_BUFS ) ;
2008-08-04 00:16:41 -07:00
}
}
/*
2009-01-16 21:38:42 +05:30
* TODO : For frame ( s ) that are in the retry state , we will reuse the
* sequence number ( s ) without setting the retry bit . The
* alternative is to give up on these and BAR the receiver ' s window
* forward .
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:42 +05:30
static void ath_tid_drain ( struct ath_softc * sc , struct ath_txq * txq ,
struct ath_atx_tid * tid )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
struct ath_buf * bf ;
struct list_head bf_head ;
INIT_LIST_HEAD ( & bf_head ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
for ( ; ; ) {
if ( list_empty ( & tid - > buf_q ) )
break ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
bf = list_first_entry ( & tid - > buf_q , struct ath_buf , list ) ;
list_move_tail ( & bf - > list , & bf_head ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( bf_isretried ( bf ) )
ath_tx_update_baw ( sc , tid , bf - > bf_seqno ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
spin_unlock ( & txq - > axq_lock ) ;
ath_tx_complete_buf ( sc , bf , & bf_head , 0 , 0 ) ;
spin_lock ( & txq - > axq_lock ) ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
tid - > seq_next = tid - > seq_start ;
tid - > baw_tail = tid - > baw_head ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
static void ath_tx_set_retry ( struct ath_softc * sc , struct ath_buf * bf )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
struct sk_buff * skb ;
struct ieee80211_hdr * hdr ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
bf - > bf_state . bf_type | = BUF_RETRY ;
bf - > bf_retries + + ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
skb = bf - > bf_mpdu ;
hdr = ( struct ieee80211_hdr * ) skb - > data ;
hdr - > frame_control | = cpu_to_le16 ( IEEE80211_FCTL_RETRY ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:53 +05:30
static struct ath_buf * ath_clone_txbuf ( struct ath_softc * sc , struct ath_buf * bf )
{
struct ath_buf * tbf ;
spin_lock_bh ( & sc - > tx . txbuflock ) ;
ASSERT ( ! list_empty ( ( & sc - > tx . txbuf ) ) ) ;
tbf = list_first_entry ( & sc - > tx . txbuf , struct ath_buf , list ) ;
list_del ( & tbf - > list ) ;
spin_unlock_bh ( & sc - > tx . txbuflock ) ;
ATH_TXBUF_RESET ( tbf ) ;
tbf - > bf_mpdu = bf - > bf_mpdu ;
tbf - > bf_buf_addr = bf - > bf_buf_addr ;
* ( tbf - > bf_desc ) = * ( bf - > bf_desc ) ;
tbf - > bf_state = bf - > bf_state ;
tbf - > bf_dmacontext = bf - > bf_dmacontext ;
return tbf ;
}
static void ath_tx_complete_aggr ( struct ath_softc * sc , struct ath_txq * txq ,
struct ath_buf * bf , struct list_head * bf_q ,
int txok )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
struct ath_node * an = NULL ;
struct sk_buff * skb ;
2009-01-27 13:30:37 +05:30
struct ieee80211_sta * sta ;
struct ieee80211_hdr * hdr ;
2009-01-16 21:38:42 +05:30
struct ath_atx_tid * tid = NULL ;
2009-01-16 21:38:53 +05:30
struct ath_buf * bf_next , * bf_last = bf - > bf_lastbf ;
2008-08-04 00:16:41 -07:00
struct ath_desc * ds = bf_last - > bf_desc ;
2009-01-16 21:38:42 +05:30
struct list_head bf_head , bf_pending ;
2009-03-18 20:22:00 +05:30
u16 seq_st = 0 , acked_cnt = 0 , txfail_cnt = 0 ;
2008-08-04 00:16:41 -07:00
u32 ba [ WME_BA_BMP_SIZE > > 5 ] ;
2009-03-18 20:22:00 +05:30
int isaggr , txfail , txpending , sendbar = 0 , needreset = 0 , nbad = 0 ;
bool rc_update = true ;
2008-08-04 00:16:41 -07:00
2009-03-30 15:28:36 +05:30
skb = bf - > bf_mpdu ;
2009-01-27 13:30:37 +05:30
hdr = ( struct ieee80211_hdr * ) skb - > data ;
rcu_read_lock ( ) ;
2008-08-04 00:16:41 -07:00
2009-01-27 13:30:37 +05:30
sta = ieee80211_find_sta ( sc - > hw , hdr - > addr1 ) ;
if ( ! sta ) {
rcu_read_unlock ( ) ;
return ;
2008-08-04 00:16:41 -07:00
}
2009-01-27 13:30:37 +05:30
an = ( struct ath_node * ) sta - > drv_priv ;
tid = ATH_AN_2_TID ( an , bf - > bf_tidno ) ;
2009-01-16 21:38:42 +05:30
isaggr = bf_isaggr ( bf ) ;
2009-01-16 21:38:53 +05:30
memset ( ba , 0 , WME_BA_BMP_SIZE > > 3 ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
if ( isaggr & & txok ) {
if ( ATH_DS_TX_BA ( ds ) ) {
seq_st = ATH_DS_BA_SEQ ( ds ) ;
memcpy ( ba , ATH_DS_BA_BITMAP ( ds ) ,
WME_BA_BMP_SIZE > > 3 ) ;
2009-01-16 21:38:42 +05:30
} else {
2009-01-16 21:38:53 +05:30
/*
* AR5416 can become deaf / mute when BA
* issue happens . Chip needs to be reset .
* But AP code may have sychronization issues
* when perform internal reset in this routine .
* Only enable reset in STA mode for now .
*/
2009-02-09 13:27:26 +05:30
if ( sc - > sc_ah - > opmode = = NL80211_IFTYPE_STATION )
2009-01-16 21:38:53 +05:30
needreset = 1 ;
2009-01-16 21:38:42 +05:30
}
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
INIT_LIST_HEAD ( & bf_pending ) ;
INIT_LIST_HEAD ( & bf_head ) ;
2008-08-04 00:16:41 -07:00
2009-03-18 20:22:00 +05:30
nbad = ath_tx_num_badfrms ( sc , bf , txok ) ;
2009-01-16 21:38:42 +05:30
while ( bf ) {
txfail = txpending = 0 ;
bf_next = bf - > bf_next ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( ATH_BA_ISSET ( ba , ATH_BA_INDEX ( seq_st , bf - > bf_seqno ) ) ) {
/* transmit completion, subframe is
* acked by block ack */
2009-03-18 20:22:00 +05:30
acked_cnt + + ;
2009-01-16 21:38:42 +05:30
} else if ( ! isaggr & & txok ) {
/* transmit completion */
2009-03-18 20:22:00 +05:30
acked_cnt + + ;
2009-01-16 21:38:42 +05:30
} else {
if ( ! ( tid - > state & AGGR_CLEANUP ) & &
ds - > ds_txstat . ts_flags ! = ATH9K_TX_SW_ABORTED ) {
if ( bf - > bf_retries < ATH_MAX_SW_RETRIES ) {
ath_tx_set_retry ( sc , bf ) ;
txpending = 1 ;
} else {
bf - > bf_state . bf_type | = BUF_XRETRY ;
txfail = 1 ;
sendbar = 1 ;
2009-03-18 20:22:00 +05:30
txfail_cnt + + ;
2009-01-16 21:38:42 +05:30
}
} else {
/*
* cleanup in progress , just fail
* the un - acked sub - frames
*/
txfail = 1 ;
}
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( bf_next = = NULL ) {
2009-06-24 18:58:47 +05:30
/*
* Make sure the last desc is reclaimed if it
* not a holding desc .
*/
if ( ! bf_last - > bf_stale )
list_move_tail ( & bf - > list , & bf_head ) ;
else
INIT_LIST_HEAD ( & bf_head ) ;
2009-01-16 21:38:42 +05:30
} else {
ASSERT ( ! list_empty ( bf_q ) ) ;
2009-01-16 21:38:53 +05:30
list_move_tail ( & bf - > list , & bf_head ) ;
2009-01-16 21:38:42 +05:30
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( ! txpending ) {
/*
* complete the acked - ones / xretried ones ; update
* block - ack window
*/
spin_lock_bh ( & txq - > axq_lock ) ;
ath_tx_update_baw ( sc , tid , bf - > bf_seqno ) ;
spin_unlock_bh ( & txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
2009-03-20 15:27:49 +05:30
if ( rc_update & & ( acked_cnt = = 1 | | txfail_cnt = = 1 ) ) {
ath_tx_rc_status ( bf , ds , nbad , txok , true ) ;
rc_update = false ;
} else {
ath_tx_rc_status ( bf , ds , nbad , txok , false ) ;
}
2009-01-16 21:38:42 +05:30
ath_tx_complete_buf ( sc , bf , & bf_head , ! txfail , sendbar ) ;
} else {
2009-01-16 21:38:53 +05:30
/* retry the un-acked ones */
2009-03-30 15:28:38 +05:30
if ( bf - > bf_next = = NULL & & bf_last - > bf_stale ) {
2009-01-16 21:38:42 +05:30
struct ath_buf * tbf ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
tbf = ath_clone_txbuf ( sc , bf_last ) ;
ath9k_hw_cleartxdesc ( sc - > sc_ah , tbf - > bf_desc ) ;
2009-01-16 21:38:42 +05:30
list_add_tail ( & tbf - > list , & bf_head ) ;
} else {
/*
* Clear descriptor status words for
* software retry
*/
2009-01-16 21:38:53 +05:30
ath9k_hw_cleartxdesc ( sc - > sc_ah , bf - > bf_desc ) ;
2009-01-16 21:38:42 +05:30
}
/*
* Put this buffer to the temporary pending
* queue to retain ordering
*/
list_splice_tail_init ( & bf_head , & bf_pending ) ;
}
bf = bf_next ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
if ( tid - > state & AGGR_CLEANUP ) {
if ( tid - > baw_head = = tid - > baw_tail ) {
tid - > state & = ~ AGGR_ADDBA_COMPLETE ;
tid - > addba_exchangeattempts = 0 ;
tid - > state & = ~ AGGR_CLEANUP ;
2008-11-18 09:07:53 +05:30
2009-01-16 21:38:42 +05:30
/* send buffered frames as singles */
ath_tx_flush_tid ( sc , tid ) ;
2009-01-16 21:38:53 +05:30
}
2009-01-27 13:30:37 +05:30
rcu_read_unlock ( ) ;
2009-01-16 21:38:42 +05:30
return ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
/* prepend un-acked frames to the beginning of the pending frame queue */
2009-01-16 21:38:42 +05:30
if ( ! list_empty ( & bf_pending ) ) {
spin_lock_bh ( & txq - > axq_lock ) ;
list_splice ( & bf_pending , & tid - > buf_q ) ;
ath_tx_queue_tid ( txq , tid ) ;
spin_unlock_bh ( & txq - > axq_lock ) ;
}
2008-10-29 10:15:16 +05:30
2009-01-27 13:30:37 +05:30
rcu_read_unlock ( ) ;
2009-01-16 21:38:42 +05:30
if ( needreset )
ath_reset ( sc , false ) ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
static u32 ath_lookup_rate ( struct ath_softc * sc , struct ath_buf * bf ,
struct ath_atx_tid * tid )
2008-08-04 00:16:41 -07:00
{
2009-05-06 02:20:00 -04:00
const struct ath_rate_table * rate_table = sc - > cur_rate_table ;
2008-10-29 10:14:26 +05:30
struct sk_buff * skb ;
struct ieee80211_tx_info * tx_info ;
2008-11-18 09:07:30 +05:30
struct ieee80211_tx_rate * rates ;
2009-01-16 21:38:42 +05:30
struct ath_tx_info_priv * tx_info_priv ;
2009-01-16 21:38:53 +05:30
u32 max_4ms_framelen , frmlen ;
2009-01-16 21:38:42 +05:30
u16 aggr_limit , legacy = 0 , maxampdu ;
int i ;
2008-10-29 10:14:26 +05:30
2009-03-30 15:28:36 +05:30
skb = bf - > bf_mpdu ;
2008-10-29 10:14:26 +05:30
tx_info = IEEE80211_SKB_CB ( skb ) ;
2008-11-18 09:07:53 +05:30
rates = tx_info - > control . rates ;
2009-01-16 21:38:53 +05:30
tx_info_priv = ( struct ath_tx_info_priv * ) tx_info - > rate_driver_data [ 0 ] ;
2008-10-29 10:14:26 +05:30
2009-01-16 21:38:42 +05:30
/*
* Find the lowest frame length among the rate series that will have a
* 4 ms transmit duration .
* TODO - TXOP limit needs to be considered .
*/
max_4ms_framelen = ATH_AMPDU_LIMIT_MAX ;
2008-11-18 09:07:53 +05:30
2009-01-16 21:38:42 +05:30
for ( i = 0 ; i < 4 ; i + + ) {
if ( rates [ i ] . count ) {
if ( ! WLAN_RC_PHY_HT ( rate_table - > info [ rates [ i ] . idx ] . phy ) ) {
legacy = 1 ;
break ;
}
2009-01-16 21:38:53 +05:30
frmlen = rate_table - > info [ rates [ i ] . idx ] . max_4ms_framelen ;
max_4ms_framelen = min ( max_4ms_framelen , frmlen ) ;
2008-08-04 00:16:41 -07:00
}
}
2008-11-18 09:07:53 +05:30
2008-08-04 00:16:41 -07:00
/*
2009-01-16 21:38:42 +05:30
* limit aggregate size by the minimum rate if rate selected is
* not a probe rate , if rate selected is a probe rate then
* avoid aggregation of this packet .
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:42 +05:30
if ( tx_info - > flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE | | legacy )
return 0 ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
aggr_limit = min ( max_4ms_framelen , ( u32 ) ATH_AMPDU_LIMIT_DEFAULT ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
/*
* h / w can accept aggregates upto 16 bit lengths ( 65535 ) .
* The IE , however can hold upto 65536 , which shows up here
* as zero . Ignore 65536 since we are constrained by hw .
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:42 +05:30
maxampdu = tid - > an - > maxampdu ;
if ( maxampdu )
aggr_limit = min ( aggr_limit , maxampdu ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
return aggr_limit ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
/*
2009-01-16 21:38:53 +05:30
* Returns the number of delimiters to be added to
2009-01-16 21:38:42 +05:30
* meet the minimum required mpdudensity .
2009-01-16 21:38:53 +05:30
* caller should make sure that the rate is HT rate .
2009-01-16 21:38:42 +05:30
*/
static int ath_compute_num_delims ( struct ath_softc * sc , struct ath_atx_tid * tid ,
struct ath_buf * bf , u16 frmlen )
{
2009-05-06 02:20:00 -04:00
const struct ath_rate_table * rt = sc - > cur_rate_table ;
2009-01-16 21:38:42 +05:30
struct sk_buff * skb = bf - > bf_mpdu ;
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
u32 nsymbits , nsymbols , mpdudensity ;
u16 minlen ;
u8 rc , flags , rix ;
int width , half_gi , ndelim , mindelim ;
/* Select standard number of delimiters based on frame length alone */
ndelim = ATH_AGGR_GET_NDELIM ( frmlen ) ;
2008-08-04 00:16:41 -07:00
/*
2009-01-16 21:38:42 +05:30
* If encryption enabled , hardware requires some more padding between
* subframes .
* TODO - this could be improved to be dependent on the rate .
* The hardware can keep up at lower rates , but not higher rates
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:42 +05:30
if ( bf - > bf_keytype ! = ATH9K_KEY_TYPE_CLEAR )
ndelim + = ATH_AGGR_ENCRYPTDELIM ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
/*
* Convert desired mpdu density from microeconds to bytes based
* on highest rate in rate series ( i . e . first rate ) to determine
* required minimum length for subframe . Take into account
* whether high rate is 20 or 40 Mhz and half or full GI .
*/
mpdudensity = tid - > an - > mpdudensity ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
/*
* If there is no mpdu density restriction , no further calculation
* is needed .
*/
if ( mpdudensity = = 0 )
return ndelim ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
rix = tx_info - > control . rates [ 0 ] . idx ;
flags = tx_info - > control . rates [ 0 ] . flags ;
rc = rt - > info [ rix ] . ratecode ;
width = ( flags & IEEE80211_TX_RC_40_MHZ_WIDTH ) ? 1 : 0 ;
half_gi = ( flags & IEEE80211_TX_RC_SHORT_GI ) ? 1 : 0 ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( half_gi )
nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI ( mpdudensity ) ;
else
nsymbols = NUM_SYMBOLS_PER_USEC ( mpdudensity ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( nsymbols = = 0 )
nsymbols = 1 ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
nsymbits = bits_per_symbol [ HT_RC_2_MCS ( rc ) ] [ width ] ;
minlen = ( nsymbols * nsymbits ) / BITS_PER_BYTE ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( frmlen < minlen ) {
mindelim = ( minlen - frmlen ) / ATH_AGGR_DELIM_SZ ;
ndelim = max ( mindelim , ndelim ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
return ndelim ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
static enum ATH_AGGR_STATUS ath_tx_form_aggr ( struct ath_softc * sc ,
2009-01-16 21:38:53 +05:30
struct ath_atx_tid * tid ,
struct list_head * bf_q )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
# define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
2009-01-16 21:38:53 +05:30
struct ath_buf * bf , * bf_first , * bf_prev = NULL ;
int rl = 0 , nframes = 0 , ndelim , prev_al = 0 ;
2009-01-16 21:38:42 +05:30
u16 aggr_limit = 0 , al = 0 , bpad = 0 ,
al_delta , h_baw = tid - > baw_size / 2 ;
enum ATH_AGGR_STATUS status = ATH_AGGR_DONE ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
bf_first = list_first_entry ( & tid - > buf_q , struct ath_buf , list ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
do {
bf = list_first_entry ( & tid - > buf_q , struct ath_buf , list ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
/* do not step over block-ack window */
2009-01-16 21:38:42 +05:30
if ( ! BAW_WITHIN ( tid - > seq_start , tid - > baw_size , bf - > bf_seqno ) ) {
status = ATH_AGGR_BAW_CLOSED ;
break ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( ! rl ) {
aggr_limit = ath_lookup_rate ( sc , bf , tid ) ;
rl = 1 ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
/* do not exceed aggregation limit */
2009-01-16 21:38:42 +05:30
al_delta = ATH_AGGR_DELIM_SZ + bf - > bf_frmlen ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
if ( nframes & &
( aggr_limit < ( al + bpad + al_delta + prev_al ) ) ) {
2009-01-16 21:38:42 +05:30
status = ATH_AGGR_LIMITED ;
break ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
/* do not exceed subframe limit */
if ( nframes > = min ( ( int ) h_baw , ATH_AMPDU_SUBFRAME_DEFAULT ) ) {
2009-01-16 21:38:42 +05:30
status = ATH_AGGR_LIMITED ;
break ;
}
2009-01-16 21:38:53 +05:30
nframes + + ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
/* add padding for previous frame to aggregation length */
2009-01-16 21:38:42 +05:30
al + = bpad + al_delta ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
/*
* Get the delimiters needed to meet the MPDU
* density for this node .
*/
ndelim = ath_compute_num_delims ( sc , tid , bf_first , bf - > bf_frmlen ) ;
bpad = PADBYTES ( al_delta ) + ( ndelim < < 2 ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
bf - > bf_next = NULL ;
2009-01-16 21:38:53 +05:30
bf - > bf_desc - > ds_link = 0 ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
/* link buffers of this frame to the aggregate */
2009-01-16 21:38:42 +05:30
ath_tx_addto_baw ( sc , tid , bf ) ;
2009-01-16 21:38:53 +05:30
ath9k_hw_set11n_aggr_middle ( sc - > sc_ah , bf - > bf_desc , ndelim ) ;
list_move_tail ( & bf - > list , bf_q ) ;
2009-01-16 21:38:42 +05:30
if ( bf_prev ) {
bf_prev - > bf_next = bf ;
2009-01-16 21:38:53 +05:30
bf_prev - > bf_desc - > ds_link = bf - > bf_daddr ;
2009-01-16 21:38:42 +05:30
}
bf_prev = bf ;
} while ( ! list_empty ( & tid - > buf_q ) ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
bf_first - > bf_al = al ;
bf_first - > bf_nframes = nframes ;
2009-01-16 21:38:53 +05:30
2009-01-16 21:38:42 +05:30
return status ;
# undef PADBYTES
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
static void ath_tx_sched_aggr ( struct ath_softc * sc , struct ath_txq * txq ,
struct ath_atx_tid * tid )
{
2009-01-16 21:38:53 +05:30
struct ath_buf * bf ;
2009-01-16 21:38:42 +05:30
enum ATH_AGGR_STATUS status ;
struct list_head bf_q ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
do {
if ( list_empty ( & tid - > buf_q ) )
return ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
INIT_LIST_HEAD ( & bf_q ) ;
2009-01-16 21:38:53 +05:30
status = ath_tx_form_aggr ( sc , tid , & bf_q ) ;
2008-08-04 00:16:41 -07:00
/*
2009-01-16 21:38:53 +05:30
* no frames picked up to be aggregated ;
* block - ack window is not open .
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:42 +05:30
if ( list_empty ( & bf_q ) )
break ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
bf = list_first_entry ( & bf_q , struct ath_buf , list ) ;
2009-01-16 21:38:53 +05:30
bf - > bf_lastbf = list_entry ( bf_q . prev , struct ath_buf , list ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
/* if only one frame, send as non-aggregate */
2009-01-16 21:38:42 +05:30
if ( bf - > bf_nframes = = 1 ) {
bf - > bf_state . bf_type & = ~ BUF_AGGR ;
2009-01-16 21:38:53 +05:30
ath9k_hw_clr11n_aggr ( sc - > sc_ah , bf - > bf_desc ) ;
2009-01-16 21:38:42 +05:30
ath_buf_set_rate ( sc , bf ) ;
ath_tx_txqaddbuf ( sc , txq , & bf_q ) ;
continue ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
/* setup first desc of aggregate */
2009-01-16 21:38:42 +05:30
bf - > bf_state . bf_type | = BUF_AGGR ;
ath_buf_set_rate ( sc , bf ) ;
ath9k_hw_set11n_aggr_first ( sc - > sc_ah , bf - > bf_desc , bf - > bf_al ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:53 +05:30
/* anchor last desc of aggregate */
ath9k_hw_set11n_aggr_last ( sc - > sc_ah , bf - > bf_lastbf - > bf_desc ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
txq - > axq_aggr_depth + + ;
ath_tx_txqaddbuf ( sc , txq , & bf_q ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
} while ( txq - > axq_depth < ATH_AGGR_MIN_QDEPTH & &
status ! = ATH_AGGR_BAW_CLOSED ) ;
}
int ath_tx_aggr_start ( struct ath_softc * sc , struct ieee80211_sta * sta ,
u16 tid , u16 * ssn )
{
struct ath_atx_tid * txtid ;
struct ath_node * an ;
an = ( struct ath_node * ) sta - > drv_priv ;
if ( sc - > sc_flags & SC_OP_TXAGGR ) {
txtid = ATH_AN_2_TID ( an , tid ) ;
txtid - > state | = AGGR_ADDBA_PROGRESS ;
ath_tx_pause_tid ( sc , txtid ) ;
ath9k: Fix lockdep warning
This patch fixes the lockdep warning shown below, and also
initializes the starting sequence number when starting a TX
aggregation session.
=============================================
[ INFO: possible recursive locking detected ]
2.6.29-rc2-wl #21
---------------------------------------------
swapper/0 is trying to acquire lock:
(_xmit_IEEE80211#2){-+..}, at: [<ffffffff80456d71>] __qdisc_run+0x221/0x290
but task is already holding lock:
(_xmit_IEEE80211#2){-+..}, at: [<ffffffff80456d71>] __qdisc_run+0x221/0x290
other info that might help us debug this:
7 locks held by swapper/0:
#0: (rcu_read_lock){..--}, at: [<ffffffff80442a63>] dev_queue_xmit+0x53/0x620
#1: (_xmit_ETHER#2){-+..}, at: [<ffffffff80456d71>] __qdisc_run+0x221/0x290
#2: (rcu_read_lock){..--}, at: [<ffffffff80442a63>] dev_queue_xmit+0x53/0x620
#3: (_xmit_IEEE80211#2){-+..}, at: [<ffffffff80456d71>] __qdisc_run+0x221/0x290
#4: (rcu_read_lock){..--}, at: [<ffffffffa0154919>] ieee80211_master_start_xmit+0x219/0x6c0 [mac80211]
#5: (rcu_read_lock){..--}, at: [<ffffffffa01427c6>] ieee80211_start_tx_ba_session+0x66/0x4e0 [mac80211]
#6: (rcu_read_lock){..--}, at: [<ffffffff80442a63>] dev_queue_xmit+0x53/0x620
stack backtrace:
Pid: 0, comm: swapper Not tainted 2.6.29-rc2-wl #21
Call Trace:
<IRQ> [<ffffffff8026c329>] __lock_acquire+0x1be9/0x1c40
[<ffffffff80442af1>] dev_queue_xmit+0xe1/0x620
[<ffffffff8026a8cc>] __lock_acquire+0x18c/0x1c40
[<ffffffff8026c3d5>] lock_acquire+0x55/0x70
[<ffffffff80456d71>] __qdisc_run+0x221/0x290
[<ffffffff804dbeb9>] _spin_lock+0x39/0x50
[<ffffffff80456d71>] __qdisc_run+0x221/0x290
[<ffffffff804dbd2f>] _spin_unlock+0x1f/0x50
[<ffffffff80456d71>] __qdisc_run+0x221/0x290
[<ffffffff80442d18>] dev_queue_xmit+0x308/0x620
[<ffffffff80442a63>] dev_queue_xmit+0x53/0x620
[<ffffffffa0142a63>] ieee80211_start_tx_ba_session+0x303/0x4e0 [mac80211]
[<ffffffffa01427c6>] ieee80211_start_tx_ba_session+0x66/0x4e0 [mac80211]
[<ffffffffa0149dae>] rate_control_get_rate+0xae/0xc0 [mac80211]
[<ffffffffa01526b5>] invoke_tx_handlers+0x655/0x1000 [mac80211]
[<ffffffff802699fd>] mark_held_locks+0x4d/0x90
[<ffffffff804dbcf5>] _spin_unlock_irqrestore+0x65/0x80
[<ffffffffa0151aaa>] __ieee80211_tx_prepare+0x16a/0x310 [mac80211]
[<ffffffffa0151adc>] __ieee80211_tx_prepare+0x19c/0x310 [mac80211]
[<ffffffff80439cc2>] pskb_expand_head+0x112/0x190
[<ffffffffa0154986>] ieee80211_master_start_xmit+0x286/0x6c0 [mac80211]
[<ffffffffa0154919>] ieee80211_master_start_xmit+0x219/0x6c0 [mac80211]
[<ffffffff8026a8cc>] __lock_acquire+0x18c/0x1c40
[<ffffffff80456d8e>] __qdisc_run+0x23e/0x290
[<ffffffff80442d18>] dev_queue_xmit+0x308/0x620
[<ffffffff80442a63>] dev_queue_xmit+0x53/0x620
[<ffffffffa0154221>] ieee80211_subif_start_xmit+0x4a1/0x980 [mac80211]
[<ffffffffa0153f18>] ieee80211_subif_start_xmit+0x198/0x980 [mac80211]
[<ffffffff80456d8e>] __qdisc_run+0x23e/0x290
[<ffffffff80442d18>] dev_queue_xmit+0x308/0x620
[<ffffffff80442a63>] dev_queue_xmit+0x53/0x620
[<ffffffffa028ecfd>] ip6_output+0x62d/0x1230 [ipv6]
[<ffffffff8024ca00>] __mod_timer+0xb0/0xd0
[<ffffffffa02ad25a>] mld_sendpack+0x3fa/0x4a0 [ipv6]
[<ffffffffa02ace60>] mld_sendpack+0x0/0x4a0 [ipv6]
[<ffffffffa02adf90>] mld_ifc_timer_expire+0x0/0x340 [ipv6]
[<ffffffffa02ae219>] mld_ifc_timer_expire+0x289/0x340 [ipv6]
[<ffffffffa02adf90>] mld_ifc_timer_expire+0x0/0x340 [ipv6]
[<ffffffff8024c097>] run_timer_softirq+0x147/0x220
[<ffffffff802473fb>] __do_softirq+0x9b/0x180
[<ffffffff80265516>] tick_dev_program_event+0x36/0xb0
[<ffffffff8020d77c>] call_softirq+0x1c/0x30
[<ffffffff8020f2c5>] do_softirq+0x65/0xb0
[<ffffffff80246ebd>] irq_exit+0x9d/0xc0
[<ffffffff80221db6>] smp_apic_timer_interrupt+0x86/0xd0
[<ffffffff8020d1b3>] apic_timer_interrupt+0x13/0x20
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-01-28 11:55:45 +05:30
* ssn = txtid - > seq_start ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
return 0 ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
int ath_tx_aggr_stop ( struct ath_softc * sc , struct ieee80211_sta * sta , u16 tid )
{
struct ath_node * an = ( struct ath_node * ) sta - > drv_priv ;
struct ath_atx_tid * txtid = ATH_AN_2_TID ( an , tid ) ;
struct ath_txq * txq = & sc - > tx . txq [ txtid - > ac - > qnum ] ;
struct ath_buf * bf ;
struct list_head bf_head ;
INIT_LIST_HEAD ( & bf_head ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( txtid - > state & AGGR_CLEANUP )
return 0 ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( ! ( txtid - > state & AGGR_ADDBA_COMPLETE ) ) {
2009-06-09 15:28:21 +05:30
txtid - > state & = ~ AGGR_ADDBA_PROGRESS ;
2009-01-16 21:38:42 +05:30
txtid - > addba_exchangeattempts = 0 ;
return 0 ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
ath_tx_pause_tid ( sc , txtid ) ;
/* drop all software retried frames and mark this TID */
spin_lock_bh ( & txq - > axq_lock ) ;
while ( ! list_empty ( & txtid - > buf_q ) ) {
bf = list_first_entry ( & txtid - > buf_q , struct ath_buf , list ) ;
if ( ! bf_isretried ( bf ) ) {
/*
* NB : it ' s based on the assumption that
* software retried frame will always stay
* at the head of software queue .
*/
break ;
}
2009-01-16 21:38:53 +05:30
list_move_tail ( & bf - > list , & bf_head ) ;
2009-01-16 21:38:42 +05:30
ath_tx_update_baw ( sc , txtid , bf - > bf_seqno ) ;
ath_tx_complete_buf ( sc , bf , & bf_head , 0 , 0 ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:53 +05:30
spin_unlock_bh ( & txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( txtid - > baw_head ! = txtid - > baw_tail ) {
txtid - > state | = AGGR_CLEANUP ;
} else {
txtid - > state & = ~ AGGR_ADDBA_COMPLETE ;
txtid - > addba_exchangeattempts = 0 ;
ath_tx_flush_tid ( sc , txtid ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
return 0 ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
void ath_tx_aggr_resume ( struct ath_softc * sc , struct ieee80211_sta * sta , u16 tid )
{
struct ath_atx_tid * txtid ;
struct ath_node * an ;
an = ( struct ath_node * ) sta - > drv_priv ;
if ( sc - > sc_flags & SC_OP_TXAGGR ) {
txtid = ATH_AN_2_TID ( an , tid ) ;
txtid - > baw_size =
IEEE80211_MIN_AMPDU_BUF < < sta - > ht_cap . ampdu_factor ;
txtid - > state | = AGGR_ADDBA_COMPLETE ;
txtid - > state & = ~ AGGR_ADDBA_PROGRESS ;
ath_tx_resume_tid ( sc , txtid ) ;
}
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
bool ath_tx_aggr_check ( struct ath_softc * sc , struct ath_node * an , u8 tidno )
2008-11-18 09:09:30 +05:30
{
2009-01-16 21:38:42 +05:30
struct ath_atx_tid * txtid ;
2008-11-18 09:09:30 +05:30
2009-01-16 21:38:42 +05:30
if ( ! ( sc - > sc_flags & SC_OP_TXAGGR ) )
return false ;
2008-11-18 09:09:30 +05:30
2009-01-16 21:38:42 +05:30
txtid = ATH_AN_2_TID ( an , tidno ) ;
if ( ! ( txtid - > state & AGGR_ADDBA_COMPLETE ) ) {
if ( ! ( txtid - > state & AGGR_ADDBA_PROGRESS ) & &
( txtid - > addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS ) ) {
txtid - > addba_exchangeattempts + + ;
return true ;
2008-11-18 09:09:30 +05:30
}
}
2009-01-16 21:38:42 +05:30
return false ;
2008-11-18 09:09:30 +05:30
}
2009-01-16 21:38:42 +05:30
/********************/
/* Queue Management */
/********************/
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
static void ath_txq_drain_pending_buffers ( struct ath_softc * sc ,
struct ath_txq * txq )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
struct ath_atx_ac * ac , * ac_tmp ;
struct ath_atx_tid * tid , * tid_tmp ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
list_for_each_entry_safe ( ac , ac_tmp , & txq - > axq_acq , list ) {
list_del ( & ac - > list ) ;
ac - > sched = false ;
list_for_each_entry_safe ( tid , tid_tmp , & ac - > tid_q , list ) {
list_del ( & tid - > list ) ;
tid - > sched = false ;
ath_tid_drain ( sc , txq , tid ) ;
}
2008-08-04 00:16:41 -07:00
}
}
2009-01-16 21:38:42 +05:30
struct ath_txq * ath_txq_setup ( struct ath_softc * sc , int qtype , int subtype )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
struct ath_hw * ah = sc - > sc_ah ;
2009-01-16 21:38:42 +05:30
struct ath9k_tx_queue_info qi ;
int qnum ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
memset ( & qi , 0 , sizeof ( qi ) ) ;
qi . tqi_subtype = subtype ;
qi . tqi_aifs = ATH9K_TXQ_USEDEFAULT ;
qi . tqi_cwmin = ATH9K_TXQ_USEDEFAULT ;
qi . tqi_cwmax = ATH9K_TXQ_USEDEFAULT ;
qi . tqi_physCompBuf = 0 ;
2008-08-04 00:16:41 -07:00
/*
2009-01-16 21:38:42 +05:30
* Enable interrupts only for EOL and DESC conditions .
* We mark tx descriptors to receive a DESC interrupt
* when a tx queue gets deep ; otherwise waiting for the
* EOL to reap descriptors . Note that this is done to
* reduce interrupt load and this only defers reaping
* descriptors , never transmitting frames . Aside from
* reducing interrupts this also permits more concurrency .
* The only potential downside is if the tx queue backs
* up in which case the top half of the kernel may backup
* due to a lack of tx descriptors .
*
* The UAPSD queue is an exception , since we take a desc -
* based intr on the EOSP frames .
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:42 +05:30
if ( qtype = = ATH9K_TX_QUEUE_UAPSD )
qi . tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE ;
else
qi . tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
TXQ_FLAG_TXDESCINT_ENABLE ;
qnum = ath9k_hw_setuptxqueue ( ah , qtype , & qi ) ;
if ( qnum = = - 1 ) {
2008-08-04 00:16:41 -07:00
/*
2009-01-16 21:38:42 +05:30
* NB : don ' t print a message , this happens
* normally on parts with too few tx queues
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:42 +05:30
return NULL ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
if ( qnum > = ARRAY_SIZE ( sc - > tx . txq ) ) {
DPRINTF ( sc , ATH_DBG_FATAL ,
" qnum %u out of range, max %u! \n " ,
qnum , ( unsigned int ) ARRAY_SIZE ( sc - > tx . txq ) ) ;
ath9k_hw_releasetxqueue ( ah , qnum ) ;
return NULL ;
}
if ( ! ATH_TXQ_SETUP ( sc , qnum ) ) {
struct ath_txq * txq = & sc - > tx . txq [ qnum ] ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
txq - > axq_qnum = qnum ;
txq - > axq_link = NULL ;
INIT_LIST_HEAD ( & txq - > axq_q ) ;
INIT_LIST_HEAD ( & txq - > axq_acq ) ;
spin_lock_init ( & txq - > axq_lock ) ;
txq - > axq_depth = 0 ;
txq - > axq_aggr_depth = 0 ;
txq - > axq_totalqueued = 0 ;
txq - > axq_linkbuf = NULL ;
sc - > tx . txqsetup | = 1 < < qnum ;
}
return & sc - > tx . txq [ qnum ] ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
static int ath_tx_get_qnum ( struct ath_softc * sc , int qtype , int haltype )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
int qnum ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
switch ( qtype ) {
case ATH9K_TX_QUEUE_DATA :
if ( haltype > = ARRAY_SIZE ( sc - > tx . hwq_map ) ) {
DPRINTF ( sc , ATH_DBG_FATAL ,
" HAL AC %u out of range, max %zu! \n " ,
haltype , ARRAY_SIZE ( sc - > tx . hwq_map ) ) ;
return - 1 ;
}
qnum = sc - > tx . hwq_map [ haltype ] ;
break ;
case ATH9K_TX_QUEUE_BEACON :
qnum = sc - > beacon . beaconq ;
break ;
case ATH9K_TX_QUEUE_CAB :
qnum = sc - > beacon . cabq - > axq_qnum ;
break ;
default :
qnum = - 1 ;
}
return qnum ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
struct ath_txq * ath_test_get_txq ( struct ath_softc * sc , struct sk_buff * skb )
{
struct ath_txq * txq = NULL ;
int qnum ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
qnum = ath_get_hal_qnum ( skb_get_queue_mapping ( skb ) , sc ) ;
txq = & sc - > tx . txq [ qnum ] ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
spin_lock_bh ( & txq - > axq_lock ) ;
if ( txq - > axq_depth > = ( ATH_TXBUF - 20 ) ) {
2009-03-09 22:09:41 -04:00
DPRINTF ( sc , ATH_DBG_XMIT ,
2009-01-16 21:38:42 +05:30
" TX queue: %d is full, depth: %d \n " ,
qnum , txq - > axq_depth ) ;
ieee80211_stop_queue ( sc - > hw , skb_get_queue_mapping ( skb ) ) ;
txq - > stopped = 1 ;
spin_unlock_bh ( & txq - > axq_lock ) ;
return NULL ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
spin_unlock_bh ( & txq - > axq_lock ) ;
return txq ;
}
int ath_txq_update ( struct ath_softc * sc , int qnum ,
struct ath9k_tx_queue_info * qinfo )
{
2009-02-09 13:27:12 +05:30
struct ath_hw * ah = sc - > sc_ah ;
2009-01-16 21:38:42 +05:30
int error = 0 ;
struct ath9k_tx_queue_info qi ;
if ( qnum = = sc - > beacon . beaconq ) {
/*
* XXX : for beacon queue , we just save the parameter .
* It will be picked up by ath_beaconq_config when
* it ' s necessary .
*/
sc - > beacon . beacon_qi = * qinfo ;
2008-08-04 00:16:41 -07:00
return 0 ;
2009-01-16 21:38:42 +05:30
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
ASSERT ( sc - > tx . txq [ qnum ] . axq_qnum = = qnum ) ;
ath9k_hw_get_txq_props ( ah , qnum , & qi ) ;
qi . tqi_aifs = qinfo - > tqi_aifs ;
qi . tqi_cwmin = qinfo - > tqi_cwmin ;
qi . tqi_cwmax = qinfo - > tqi_cwmax ;
qi . tqi_burstTime = qinfo - > tqi_burstTime ;
qi . tqi_readyTime = qinfo - > tqi_readyTime ;
if ( ! ath9k_hw_set_txq_props ( ah , qnum , & qi ) ) {
DPRINTF ( sc , ATH_DBG_FATAL ,
" Unable to update hardware queue %u! \n " , qnum ) ;
error = - EIO ;
} else {
ath9k_hw_resettxqueue ( ah , qnum ) ;
}
return error ;
}
int ath_cabq_update ( struct ath_softc * sc )
{
struct ath9k_tx_queue_info qi ;
int qnum = sc - > beacon . cabq - > axq_qnum ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
ath9k_hw_get_txq_props ( sc - > sc_ah , qnum , & qi ) ;
2008-08-04 00:16:41 -07:00
/*
2009-01-16 21:38:42 +05:30
* Ensure the readytime % is within the bounds .
2008-08-04 00:16:41 -07:00
*/
2009-02-09 13:27:03 +05:30
if ( sc - > config . cabqReadytime < ATH9K_READY_TIME_LO_BOUND )
sc - > config . cabqReadytime = ATH9K_READY_TIME_LO_BOUND ;
else if ( sc - > config . cabqReadytime > ATH9K_READY_TIME_HI_BOUND )
sc - > config . cabqReadytime = ATH9K_READY_TIME_HI_BOUND ;
2008-08-04 00:16:41 -07:00
2009-04-23 16:10:04 +02:00
qi . tqi_readyTime = ( sc - > beacon_interval *
2009-02-17 15:36:35 +05:30
sc - > config . cabqReadytime ) / 100 ;
2009-01-16 21:38:42 +05:30
ath_txq_update ( sc , qnum , & qi ) ;
return 0 ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:47 +05:30
/*
* Drain a given TX queue ( could be Beacon or Data )
*
* This assumes output has been stopped and
* we do not need to block ath_tx_tasklet .
*/
void ath_draintxq ( struct ath_softc * sc , struct ath_txq * txq , bool retry_tx )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
struct ath_buf * bf , * lastbf ;
struct list_head bf_head ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
INIT_LIST_HEAD ( & bf_head ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
for ( ; ; ) {
spin_lock_bh ( & txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( list_empty ( & txq - > axq_q ) ) {
txq - > axq_link = NULL ;
txq - > axq_linkbuf = NULL ;
spin_unlock_bh ( & txq - > axq_lock ) ;
break ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
bf = list_first_entry ( & txq - > axq_q , struct ath_buf , list ) ;
2008-08-04 00:16:41 -07:00
2009-03-30 15:28:38 +05:30
if ( bf - > bf_stale ) {
2009-01-16 21:38:42 +05:30
list_del ( & bf - > list ) ;
spin_unlock_bh ( & txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
spin_lock_bh ( & sc - > tx . txbuflock ) ;
list_add_tail ( & bf - > list , & sc - > tx . txbuf ) ;
spin_unlock_bh ( & sc - > tx . txbuflock ) ;
continue ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
lastbf = bf - > bf_lastbf ;
if ( ! retry_tx )
lastbf - > bf_desc - > ds_txstat . ts_flags =
ATH9K_TX_SW_ABORTED ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
/* remove ath_buf's of the same mpdu from txq */
list_cut_position ( & bf_head , & txq - > axq_q , & lastbf - > list ) ;
txq - > axq_depth - - ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
spin_unlock_bh ( & txq - > axq_lock ) ;
if ( bf_isampdu ( bf ) )
2009-01-16 21:38:53 +05:30
ath_tx_complete_aggr ( sc , txq , bf , & bf_head , 0 ) ;
2009-01-16 21:38:42 +05:30
else
ath_tx_complete_buf ( sc , bf , & bf_head , 0 , 0 ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
/* flush any pending frames if aggregation is enabled */
if ( sc - > sc_flags & SC_OP_TXAGGR ) {
if ( ! retry_tx ) {
spin_lock_bh ( & txq - > axq_lock ) ;
ath_txq_drain_pending_buffers ( sc , txq ) ;
spin_unlock_bh ( & txq - > axq_lock ) ;
}
}
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:47 +05:30
void ath_drain_all_txq ( struct ath_softc * sc , bool retry_tx )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
struct ath_hw * ah = sc - > sc_ah ;
2009-01-16 21:38:47 +05:30
struct ath_txq * txq ;
int i , npend = 0 ;
if ( sc - > sc_flags & SC_OP_INVALID )
return ;
/* Stop beacon queue */
ath9k_hw_stoptxdma ( sc - > sc_ah , sc - > beacon . beaconq ) ;
/* Stop data queues */
for ( i = 0 ; i < ATH9K_NUM_TX_QUEUES ; i + + ) {
if ( ATH_TXQ_SETUP ( sc , i ) ) {
txq = & sc - > tx . txq [ i ] ;
ath9k_hw_stoptxdma ( ah , txq - > axq_qnum ) ;
npend + = ath9k_hw_numtxpending ( ah , txq - > axq_qnum ) ;
}
}
if ( npend ) {
int r ;
DPRINTF ( sc , ATH_DBG_XMIT , " Unable to stop TxDMA. Reset HAL! \n " ) ;
spin_lock_bh ( & sc - > sc_resetlock ) ;
2009-02-09 13:27:26 +05:30
r = ath9k_hw_reset ( ah , sc - > sc_ah - > curchan , true ) ;
2009-01-16 21:38:47 +05:30
if ( r )
DPRINTF ( sc , ATH_DBG_FATAL ,
2009-05-15 18:59:20 +05:30
" Unable to reset hardware; reset status %d \n " ,
2009-01-16 21:38:47 +05:30
r ) ;
spin_unlock_bh ( & sc - > sc_resetlock ) ;
}
for ( i = 0 ; i < ATH9K_NUM_TX_QUEUES ; i + + ) {
if ( ATH_TXQ_SETUP ( sc , i ) )
ath_draintxq ( sc , & sc - > tx . txq [ i ] , retry_tx ) ;
}
2009-01-16 21:38:42 +05:30
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:47 +05:30
void ath_tx_cleanupq ( struct ath_softc * sc , struct ath_txq * txq )
2009-01-16 21:38:42 +05:30
{
2009-01-16 21:38:47 +05:30
ath9k_hw_releasetxqueue ( sc - > sc_ah , txq - > axq_qnum ) ;
sc - > tx . txqsetup & = ~ ( 1 < < txq - > axq_qnum ) ;
2009-01-16 21:38:42 +05:30
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
void ath_txq_schedule ( struct ath_softc * sc , struct ath_txq * txq )
{
struct ath_atx_ac * ac ;
struct ath_atx_tid * tid ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( list_empty ( & txq - > axq_acq ) )
return ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
ac = list_first_entry ( & txq - > axq_acq , struct ath_atx_ac , list ) ;
list_del ( & ac - > list ) ;
ac - > sched = false ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
do {
if ( list_empty ( & ac - > tid_q ) )
return ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
tid = list_first_entry ( & ac - > tid_q , struct ath_atx_tid , list ) ;
list_del ( & tid - > list ) ;
tid - > sched = false ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( tid - > paused )
continue ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( ( txq - > axq_depth % 2 ) = = 0 )
ath_tx_sched_aggr ( sc , txq , tid ) ;
2008-08-04 00:16:41 -07:00
/*
2009-01-16 21:38:42 +05:30
* add tid to round - robin queue if more frames
* are pending for the tid
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:42 +05:30
if ( ! list_empty ( & tid - > buf_q ) )
ath_tx_queue_tid ( txq , tid ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
break ;
} while ( ! list_empty ( & ac - > tid_q ) ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( ! list_empty ( & ac - > tid_q ) ) {
if ( ! ac - > sched ) {
ac - > sched = true ;
list_add_tail ( & ac - > list , & txq - > axq_acq ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
}
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
int ath_tx_setup ( struct ath_softc * sc , int haltype )
{
struct ath_txq * txq ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( haltype > = ARRAY_SIZE ( sc - > tx . hwq_map ) ) {
DPRINTF ( sc , ATH_DBG_FATAL ,
" HAL AC %u out of range, max %zu! \n " ,
haltype , ARRAY_SIZE ( sc - > tx . hwq_map ) ) ;
return 0 ;
}
txq = ath_txq_setup ( sc , ATH9K_TX_QUEUE_DATA , haltype ) ;
if ( txq ! = NULL ) {
sc - > tx . hwq_map [ haltype ] = txq - > axq_qnum ;
return 1 ;
} else
return 0 ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
/***********/
/* TX, DMA */
/***********/
2008-08-04 00:16:41 -07:00
/*
2009-01-16 21:38:42 +05:30
* Insert a chain of ath_buf ( descriptors ) on a txq and
* assume the descriptors are already chained together by caller .
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:42 +05:30
static void ath_tx_txqaddbuf ( struct ath_softc * sc , struct ath_txq * txq ,
struct list_head * head )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
struct ath_hw * ah = sc - > sc_ah ;
2009-01-16 21:38:42 +05:30
struct ath_buf * bf ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
/*
* Insert the frame on the outbound list and
* pass it on to the hardware .
*/
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( list_empty ( head ) )
return ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
bf = list_first_entry ( head , struct ath_buf , list ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
list_splice_tail_init ( head , & txq - > axq_q ) ;
txq - > axq_depth + + ;
txq - > axq_totalqueued + + ;
txq - > axq_linkbuf = list_entry ( txq - > axq_q . prev , struct ath_buf , list ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
DPRINTF ( sc , ATH_DBG_QUEUE ,
" qnum: %d, txq depth: %d \n " , txq - > axq_qnum , txq - > axq_depth ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( txq - > axq_link = = NULL ) {
ath9k_hw_puttxbuf ( ah , txq - > axq_qnum , bf - > bf_daddr ) ;
DPRINTF ( sc , ATH_DBG_XMIT ,
" TXDP[%u] = %llx (%p) \n " ,
txq - > axq_qnum , ito64 ( bf - > bf_daddr ) , bf - > bf_desc ) ;
} else {
* txq - > axq_link = bf - > bf_daddr ;
DPRINTF ( sc , ATH_DBG_XMIT , " link[%u] (%p)=%llx (%p) \n " ,
txq - > axq_qnum , txq - > axq_link ,
ito64 ( bf - > bf_daddr ) , bf - > bf_desc ) ;
}
txq - > axq_link = & ( bf - > bf_lastbf - > bf_desc - > ds_link ) ;
ath9k_hw_txstart ( ah , txq - > axq_qnum ) ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
static struct ath_buf * ath_tx_get_buffer ( struct ath_softc * sc )
{
struct ath_buf * bf = NULL ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
spin_lock_bh ( & sc - > tx . txbuflock ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( unlikely ( list_empty ( & sc - > tx . txbuf ) ) ) {
spin_unlock_bh ( & sc - > tx . txbuflock ) ;
return NULL ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
bf = list_first_entry ( & sc - > tx . txbuf , struct ath_buf , list ) ;
list_del ( & bf - > list ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
spin_unlock_bh ( & sc - > tx . txbuflock ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
return bf ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
static void ath_tx_send_ampdu ( struct ath_softc * sc , struct ath_atx_tid * tid ,
struct list_head * bf_head ,
struct ath_tx_control * txctl )
2008-08-04 00:16:41 -07:00
{
struct ath_buf * bf ;
2009-01-16 21:38:42 +05:30
bf = list_first_entry ( bf_head , struct ath_buf , list ) ;
bf - > bf_state . bf_type | = BUF_AMPDU ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
/*
* Do not queue to h / w when any of the following conditions is true :
* - there are pending frames in software queue
* - the TID is currently paused for ADDBA / BAR request
* - seqno is not within block - ack window
* - h / w queue depth exceeds low water mark
*/
if ( ! list_empty ( & tid - > buf_q ) | | tid - > paused | |
! BAW_WITHIN ( tid - > seq_start , tid - > baw_size , bf - > bf_seqno ) | |
txctl - > txq - > axq_depth > = ATH_AGGR_MIN_QDEPTH ) {
2008-08-04 00:16:41 -07:00
/*
2009-01-16 21:38:42 +05:30
* Add this frame to software queue for scheduling later
* for aggregation .
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:53 +05:30
list_move_tail ( & bf - > list , & tid - > buf_q ) ;
2009-01-16 21:38:42 +05:30
ath_tx_queue_tid ( txctl - > txq , tid ) ;
return ;
}
/* Add sub-frame to BAW */
ath_tx_addto_baw ( sc , tid , bf ) ;
/* Queue to h/w without aggregation */
bf - > bf_nframes = 1 ;
2009-01-16 21:38:53 +05:30
bf - > bf_lastbf = bf ;
2009-01-16 21:38:42 +05:30
ath_buf_set_rate ( sc , bf ) ;
ath_tx_txqaddbuf ( sc , txctl - > txq , bf_head ) ;
}
2009-03-09 09:31:57 +05:30
static void ath_tx_send_ht_normal ( struct ath_softc * sc , struct ath_txq * txq ,
struct ath_atx_tid * tid ,
struct list_head * bf_head )
2009-01-16 21:38:42 +05:30
{
struct ath_buf * bf ;
bf = list_first_entry ( bf_head , struct ath_buf , list ) ;
bf - > bf_state . bf_type & = ~ BUF_AMPDU ;
/* update starting sequence number for subsequent ADDBA request */
INCR ( tid - > seq_start , IEEE80211_SEQ_MAX ) ;
bf - > bf_nframes = 1 ;
2009-01-16 21:38:53 +05:30
bf - > bf_lastbf = bf ;
2009-01-16 21:38:42 +05:30
ath_buf_set_rate ( sc , bf ) ;
ath_tx_txqaddbuf ( sc , txq , bf_head ) ;
}
2009-03-09 09:31:57 +05:30
static void ath_tx_send_normal ( struct ath_softc * sc , struct ath_txq * txq ,
struct list_head * bf_head )
{
struct ath_buf * bf ;
bf = list_first_entry ( bf_head , struct ath_buf , list ) ;
bf - > bf_lastbf = bf ;
bf - > bf_nframes = 1 ;
ath_buf_set_rate ( sc , bf ) ;
ath_tx_txqaddbuf ( sc , txq , bf_head ) ;
}
2009-01-16 21:38:42 +05:30
static enum ath9k_pkt_type get_hw_packet_type ( struct sk_buff * skb )
{
struct ieee80211_hdr * hdr ;
enum ath9k_pkt_type htype ;
__le16 fc ;
hdr = ( struct ieee80211_hdr * ) skb - > data ;
fc = hdr - > frame_control ;
if ( ieee80211_is_beacon ( fc ) )
htype = ATH9K_PKT_TYPE_BEACON ;
else if ( ieee80211_is_probe_resp ( fc ) )
htype = ATH9K_PKT_TYPE_PROBE_RESP ;
else if ( ieee80211_is_atim ( fc ) )
htype = ATH9K_PKT_TYPE_ATIM ;
else if ( ieee80211_is_pspoll ( fc ) )
htype = ATH9K_PKT_TYPE_PSPOLL ;
else
htype = ATH9K_PKT_TYPE_NORMAL ;
return htype ;
}
static bool is_pae ( struct sk_buff * skb )
{
struct ieee80211_hdr * hdr ;
__le16 fc ;
hdr = ( struct ieee80211_hdr * ) skb - > data ;
fc = hdr - > frame_control ;
if ( ieee80211_is_data ( fc ) ) {
if ( ieee80211_is_nullfunc ( fc ) | |
/* Port Access Entity (IEEE 802.1X) */
( skb - > protocol = = cpu_to_be16 ( ETH_P_PAE ) ) ) {
return true ;
}
}
return false ;
}
static int get_hw_crypto_keytype ( struct sk_buff * skb )
{
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
if ( tx_info - > control . hw_key ) {
if ( tx_info - > control . hw_key - > alg = = ALG_WEP )
return ATH9K_KEY_TYPE_WEP ;
else if ( tx_info - > control . hw_key - > alg = = ALG_TKIP )
return ATH9K_KEY_TYPE_TKIP ;
else if ( tx_info - > control . hw_key - > alg = = ALG_CCMP )
return ATH9K_KEY_TYPE_AES ;
}
return ATH9K_KEY_TYPE_CLEAR ;
}
static void assign_aggr_tid_seqno ( struct sk_buff * skb ,
struct ath_buf * bf )
{
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
struct ieee80211_hdr * hdr ;
struct ath_node * an ;
struct ath_atx_tid * tid ;
__le16 fc ;
u8 * qc ;
if ( ! tx_info - > control . sta )
return ;
an = ( struct ath_node * ) tx_info - > control . sta - > drv_priv ;
hdr = ( struct ieee80211_hdr * ) skb - > data ;
fc = hdr - > frame_control ;
if ( ieee80211_is_data_qos ( fc ) ) {
qc = ieee80211_get_qos_ctl ( hdr ) ;
bf - > bf_tidno = qc [ 0 ] & 0xf ;
}
/*
* For HT capable stations , we save tidno for later use .
* We also override seqno set by upper layer with the one
* in tx aggregation state .
*
* If fragmentation is on , the sequence number is
* not overridden , since it has been
* incremented by the fragmentation routine .
*
* FIXME : check if the fragmentation threshold exceeds
* IEEE80211 max .
*/
tid = ATH_AN_2_TID ( an , bf - > bf_tidno ) ;
hdr - > seq_ctrl = cpu_to_le16 ( tid - > seq_next < <
IEEE80211_SEQ_SEQ_SHIFT ) ;
bf - > bf_seqno = tid - > seq_next ;
INCR ( tid - > seq_next , IEEE80211_SEQ_MAX ) ;
}
static int setup_tx_flags ( struct ath_softc * sc , struct sk_buff * skb ,
struct ath_txq * txq )
{
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
int flags = 0 ;
flags | = ATH9K_TXDESC_CLRDMASK ; /* needed for crypto errors */
flags | = ATH9K_TXDESC_INTREQ ;
if ( tx_info - > flags & IEEE80211_TX_CTL_NO_ACK )
flags | = ATH9K_TXDESC_NOACK ;
return flags ;
}
/*
* rix - rate index
* pktlen - total bytes ( delims + data + fcs + pads + pad delims )
* width - 0 for 20 MHz , 1 for 40 MHz
* half_gi - to use 4u s v / s 3.6 us for symbol time
*/
static u32 ath_pkt_duration ( struct ath_softc * sc , u8 rix , struct ath_buf * bf ,
int width , int half_gi , bool shortPreamble )
{
2009-05-06 02:20:00 -04:00
const struct ath_rate_table * rate_table = sc - > cur_rate_table ;
2009-01-16 21:38:42 +05:30
u32 nbits , nsymbits , duration , nsymbols ;
u8 rc ;
int streams , pktlen ;
pktlen = bf_isaggr ( bf ) ? bf - > bf_al : bf - > bf_frmlen ;
rc = rate_table - > info [ rix ] . ratecode ;
/* for legacy rates, use old function to compute packet duration */
if ( ! IS_HT_RATE ( rc ) )
return ath9k_hw_computetxtime ( sc - > sc_ah , rate_table , pktlen ,
rix , shortPreamble ) ;
/* find number of symbols: PLCP + data */
nbits = ( pktlen < < 3 ) + OFDM_PLCP_BITS ;
nsymbits = bits_per_symbol [ HT_RC_2_MCS ( rc ) ] [ width ] ;
nsymbols = ( nbits + nsymbits - 1 ) / nsymbits ;
if ( ! half_gi )
duration = SYMBOL_TIME ( nsymbols ) ;
else
duration = SYMBOL_TIME_HALFGI ( nsymbols ) ;
/* addup duration for legacy/ht training and signal fields */
streams = HT_RC_2_STREAMS ( rc ) ;
duration + = L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF ( streams ) ;
return duration ;
}
static void ath_buf_set_rate ( struct ath_softc * sc , struct ath_buf * bf )
{
2009-05-06 02:20:00 -04:00
const struct ath_rate_table * rt = sc - > cur_rate_table ;
2009-01-16 21:38:42 +05:30
struct ath9k_11n_rate_series series [ 4 ] ;
struct sk_buff * skb ;
struct ieee80211_tx_info * tx_info ;
struct ieee80211_tx_rate * rates ;
2009-02-04 08:10:19 +05:30
struct ieee80211_hdr * hdr ;
2009-01-30 14:29:28 +05:30
int i , flags = 0 ;
u8 rix = 0 , ctsrate = 0 ;
2009-02-04 08:10:19 +05:30
bool is_pspoll ;
2009-01-16 21:38:42 +05:30
memset ( series , 0 , sizeof ( struct ath9k_11n_rate_series ) * 4 ) ;
2009-03-30 15:28:36 +05:30
skb = bf - > bf_mpdu ;
2009-01-16 21:38:42 +05:30
tx_info = IEEE80211_SKB_CB ( skb ) ;
rates = tx_info - > control . rates ;
2009-02-04 08:10:19 +05:30
hdr = ( struct ieee80211_hdr * ) skb - > data ;
is_pspoll = ieee80211_is_pspoll ( hdr - > frame_control ) ;
2009-01-16 21:38:42 +05:30
/*
2009-01-30 14:29:28 +05:30
* We check if Short Preamble is needed for the CTS rate by
* checking the BSS ' s global flag .
* But for the rate series , IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used .
2009-01-16 21:38:42 +05:30
*/
2009-01-30 14:29:28 +05:30
if ( sc - > sc_flags & SC_OP_PREAMBLE_SHORT )
ctsrate = rt - > info [ tx_info - > control . rts_cts_rate_idx ] . ratecode |
rt - > info [ tx_info - > control . rts_cts_rate_idx ] . short_preamble ;
else
ctsrate = rt - > info [ tx_info - > control . rts_cts_rate_idx ] . ratecode ;
2009-01-16 21:38:42 +05:30
2009-01-30 14:29:28 +05:30
/*
* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive .
* Check the first rate in the series to decide whether RTS / CTS
* or CTS - to - self has to be used .
2009-01-16 21:38:42 +05:30
*/
2009-01-30 14:29:28 +05:30
if ( rates [ 0 ] . flags & IEEE80211_TX_RC_USE_CTS_PROTECT )
flags = ATH9K_TXDESC_CTSENA ;
else if ( rates [ 0 ] . flags & IEEE80211_TX_RC_USE_RTS_CTS )
flags = ATH9K_TXDESC_RTSENA ;
2009-01-16 21:38:42 +05:30
2009-01-30 14:29:28 +05:30
/* FIXME: Handle aggregation protection */
2009-02-09 13:27:03 +05:30
if ( sc - > config . ath_aggr_prot & &
2009-01-16 21:38:42 +05:30
( ! bf_isaggr ( bf ) | | ( bf_isaggr ( bf ) & & bf - > bf_al < 8192 ) ) ) {
flags = ATH9K_TXDESC_RTSENA ;
}
/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
2009-02-09 13:27:26 +05:30
if ( bf_isaggr ( bf ) & & ( bf - > bf_al > sc - > sc_ah - > caps . rts_aggr_limit ) )
2009-01-16 21:38:42 +05:30
flags & = ~ ( ATH9K_TXDESC_RTSENA ) ;
for ( i = 0 ; i < 4 ; i + + ) {
if ( ! rates [ i ] . count | | ( rates [ i ] . idx < 0 ) )
continue ;
rix = rates [ i ] . idx ;
series [ i ] . Tries = rates [ i ] . count ;
2009-02-09 13:27:03 +05:30
series [ i ] . ChSel = sc - > tx_chainmask ;
2009-01-16 21:38:42 +05:30
2009-01-30 14:29:28 +05:30
if ( rates [ i ] . flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE )
series [ i ] . Rate = rt - > info [ rix ] . ratecode |
rt - > info [ rix ] . short_preamble ;
else
series [ i ] . Rate = rt - > info [ rix ] . ratecode ;
if ( rates [ i ] . flags & IEEE80211_TX_RC_USE_RTS_CTS )
series [ i ] . RateFlags | = ATH9K_RATESERIES_RTS_CTS ;
if ( rates [ i ] . flags & IEEE80211_TX_RC_40_MHZ_WIDTH )
series [ i ] . RateFlags | = ATH9K_RATESERIES_2040 ;
if ( rates [ i ] . flags & IEEE80211_TX_RC_SHORT_GI )
series [ i ] . RateFlags | = ATH9K_RATESERIES_HALFGI ;
2009-01-16 21:38:42 +05:30
series [ i ] . PktDuration = ath_pkt_duration ( sc , rix , bf ,
( rates [ i ] . flags & IEEE80211_TX_RC_40_MHZ_WIDTH ) ! = 0 ,
( rates [ i ] . flags & IEEE80211_TX_RC_SHORT_GI ) ,
2009-01-30 14:29:28 +05:30
( rates [ i ] . flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ) ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
/* set dur_update_en for l-sig computation except for PS-Poll frames */
2009-01-30 14:29:28 +05:30
ath9k_hw_set11n_ratescenario ( sc - > sc_ah , bf - > bf_desc ,
bf - > bf_lastbf - > bf_desc ,
2009-02-04 08:10:19 +05:30
! is_pspoll , ctsrate ,
2009-01-30 14:29:28 +05:30
0 , series , 4 , flags ) ;
2008-08-04 00:16:41 -07:00
2009-02-09 13:27:03 +05:30
if ( sc - > config . ath_aggr_prot & & flags )
2009-01-30 14:29:28 +05:30
ath9k_hw_set11n_burstduration ( sc - > sc_ah , bf - > bf_desc , 8192 ) ;
2008-08-04 00:16:41 -07:00
}
2009-03-03 19:23:29 +02:00
static int ath_tx_setup_buffer ( struct ieee80211_hw * hw , struct ath_buf * bf ,
2008-11-18 09:10:42 +05:30
struct sk_buff * skb ,
2008-10-29 10:14:26 +05:30
struct ath_tx_control * txctl )
2008-08-04 00:16:41 -07:00
{
2009-03-03 19:23:29 +02:00
struct ath_wiphy * aphy = hw - > priv ;
struct ath_softc * sc = aphy - > sc ;
2008-10-29 10:14:26 +05:30
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2008-08-04 00:16:41 -07:00
struct ath_tx_info_priv * tx_info_priv ;
2008-10-29 10:14:26 +05:30
int hdrlen ;
__le16 fc ;
2008-08-22 17:31:33 +03:00
2008-12-03 03:35:30 -08:00
tx_info_priv = kzalloc ( sizeof ( * tx_info_priv ) , GFP_ATOMIC ) ;
if ( unlikely ( ! tx_info_priv ) )
return - ENOMEM ;
2008-11-18 09:07:30 +05:30
tx_info - > rate_driver_data [ 0 ] = tx_info_priv ;
2009-03-03 19:23:29 +02:00
tx_info_priv - > aphy = aphy ;
2009-03-03 19:23:31 +02:00
tx_info_priv - > frame_type = txctl - > frame_type ;
2008-10-29 10:14:26 +05:30
hdrlen = ieee80211_get_hdrlen_from_skb ( skb ) ;
fc = hdr - > frame_control ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:14:26 +05:30
ATH_TXBUF_RESET ( bf ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:14:26 +05:30
bf - > bf_frmlen = skb - > len + FCS_LEN - ( hdrlen & 3 ) ;
2008-08-11 14:03:34 +05:30
2009-03-09 09:31:57 +05:30
if ( conf_is_ht ( & sc - > hw - > conf ) & & ! is_pae ( skb ) )
2009-01-16 21:38:56 +05:30
bf - > bf_state . bf_type | = BUF_HT ;
2008-10-29 10:14:26 +05:30
bf - > bf_flags = setup_tx_flags ( sc , skb , txctl - > txq ) ;
bf - > bf_keytype = get_hw_crypto_keytype ( skb ) ;
if ( bf - > bf_keytype ! = ATH9K_KEY_TYPE_CLEAR ) {
bf - > bf_frmlen + = tx_info - > control . hw_key - > icv_len ;
bf - > bf_keyix = tx_info - > control . hw_key - > hw_key_idx ;
} else {
bf - > bf_keyix = ATH9K_TXKEYIX_INVALID ;
}
2008-12-22 16:31:58 +05:30
if ( ieee80211_is_data_qos ( fc ) & & ( sc - > sc_flags & SC_OP_TXAGGR ) )
2008-10-29 10:14:26 +05:30
assign_aggr_tid_seqno ( skb , bf ) ;
2008-08-04 00:16:41 -07:00
bf - > bf_mpdu = skb ;
2008-12-03 03:35:29 -08:00
2009-01-14 20:17:03 +01:00
bf - > bf_dmacontext = dma_map_single ( sc - > dev , skb - > data ,
skb - > len , DMA_TO_DEVICE ) ;
if ( unlikely ( dma_mapping_error ( sc - > dev , bf - > bf_dmacontext ) ) ) {
2008-12-03 03:35:29 -08:00
bf - > bf_mpdu = NULL ;
2009-04-13 21:56:34 +05:30
kfree ( tx_info_priv ) ;
tx_info - > rate_driver_data [ 0 ] = NULL ;
DPRINTF ( sc , ATH_DBG_FATAL , " dma_mapping_error() on TX \n " ) ;
2008-12-03 03:35:29 -08:00
return - ENOMEM ;
}
2008-10-29 10:14:26 +05:30
bf - > bf_buf_addr = bf - > bf_dmacontext ;
2008-12-03 03:35:29 -08:00
return 0 ;
2008-10-29 10:14:26 +05:30
}
/* FIXME: tx power */
static void ath_tx_start_dma ( struct ath_softc * sc , struct ath_buf * bf ,
struct ath_tx_control * txctl )
{
2009-03-30 15:28:36 +05:30
struct sk_buff * skb = bf - > bf_mpdu ;
2008-10-29 10:14:26 +05:30
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
2009-03-09 09:31:57 +05:30
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2008-10-29 10:14:26 +05:30
struct ath_node * an = NULL ;
struct list_head bf_head ;
struct ath_desc * ds ;
struct ath_atx_tid * tid ;
2009-02-09 13:27:12 +05:30
struct ath_hw * ah = sc - > sc_ah ;
2008-10-29 10:14:26 +05:30
int frm_type ;
2009-03-09 09:31:57 +05:30
__le16 fc ;
2008-10-29 10:14:26 +05:30
frm_type = get_hw_packet_type ( skb ) ;
2009-03-09 09:31:57 +05:30
fc = hdr - > frame_control ;
2008-10-29 10:14:26 +05:30
INIT_LIST_HEAD ( & bf_head ) ;
list_add_tail ( & bf - > list , & bf_head ) ;
2008-08-04 00:16:41 -07:00
ds = bf - > bf_desc ;
ds - > ds_link = 0 ;
ds - > ds_data = bf - > bf_buf_addr ;
2008-10-29 10:14:26 +05:30
ath9k_hw_set11n_txdesc ( ah , ds , bf - > bf_frmlen , frm_type , MAX_RATE_POWER ,
bf - > bf_keyix , bf - > bf_keytype , bf - > bf_flags ) ;
ath9k_hw_filltxdesc ( ah , ds ,
2008-11-18 09:10:42 +05:30
skb - > len , /* segment length */
true , /* first segment */
true , /* last segment */
ds ) ; /* first descriptor */
2008-08-04 00:16:41 -07:00
2008-10-29 10:14:26 +05:30
spin_lock_bh ( & txctl - > txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
2008-10-31 16:45:15 -04:00
if ( bf_isht ( bf ) & & ( sc - > sc_flags & SC_OP_TXAGGR ) & &
tx_info - > control . sta ) {
an = ( struct ath_node * ) tx_info - > control . sta - > drv_priv ;
tid = ATH_AN_2_TID ( an , bf - > bf_tidno ) ;
2009-03-09 09:31:57 +05:30
if ( ! ieee80211_is_data_qos ( fc ) ) {
ath_tx_send_normal ( sc , txctl - > txq , & bf_head ) ;
goto tx_done ;
}
2008-10-29 10:14:26 +05:30
if ( ath_aggr_query ( sc , an , bf - > bf_tidno ) ) {
2008-08-04 00:16:41 -07:00
/*
* Try aggregation if it ' s a unicast data frame
* and the destination is HT capable .
*/
2008-10-29 10:14:26 +05:30
ath_tx_send_ampdu ( sc , tid , & bf_head , txctl ) ;
2008-08-04 00:16:41 -07:00
} else {
/*
2008-10-29 10:14:26 +05:30
* Send this frame as regular when ADDBA
* exchange is neither complete nor pending .
2008-08-04 00:16:41 -07:00
*/
2009-03-09 09:31:57 +05:30
ath_tx_send_ht_normal ( sc , txctl - > txq ,
tid , & bf_head ) ;
2008-08-04 00:16:41 -07:00
}
} else {
2009-03-09 09:31:57 +05:30
ath_tx_send_normal ( sc , txctl - > txq , & bf_head ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-29 10:14:26 +05:30
2009-03-09 09:31:57 +05:30
tx_done :
2008-10-29 10:14:26 +05:30
spin_unlock_bh ( & txctl - > txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
}
2008-12-03 03:35:29 -08:00
/* Upon failure caller should free skb */
2009-03-03 19:23:29 +02:00
int ath_tx_start ( struct ieee80211_hw * hw , struct sk_buff * skb ,
2008-10-29 10:14:26 +05:30
struct ath_tx_control * txctl )
2008-08-04 00:16:41 -07:00
{
2009-03-03 19:23:29 +02:00
struct ath_wiphy * aphy = hw - > priv ;
struct ath_softc * sc = aphy - > sc ;
2008-10-29 10:14:26 +05:30
struct ath_buf * bf ;
2008-12-03 03:35:29 -08:00
int r ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:14:26 +05:30
bf = ath_tx_get_buffer ( sc ) ;
if ( ! bf ) {
2008-11-28 22:18:05 +05:30
DPRINTF ( sc , ATH_DBG_XMIT , " TX buffers are full \n " ) ;
2008-10-29 10:14:26 +05:30
return - 1 ;
}
2009-03-03 19:23:29 +02:00
r = ath_tx_setup_buffer ( hw , bf , skb , txctl ) ;
2008-12-03 03:35:29 -08:00
if ( unlikely ( r ) ) {
2008-12-03 03:35:30 -08:00
struct ath_txq * txq = txctl - > txq ;
2008-12-03 03:35:29 -08:00
DPRINTF ( sc , ATH_DBG_FATAL , " TX mem alloc failure \n " ) ;
2008-12-03 03:35:30 -08:00
/* upon ath_tx_processq() this TX queue will be resumed, we
* guarantee this will happen by knowing beforehand that
* we will at least have to run TX completionon one buffer
* on the queue */
spin_lock_bh ( & txq - > axq_lock ) ;
2009-02-17 15:36:33 +05:30
if ( sc - > tx . txq [ txq - > axq_qnum ] . axq_depth > 1 ) {
2008-12-03 03:35:30 -08:00
ieee80211_stop_queue ( sc - > hw ,
skb_get_queue_mapping ( skb ) ) ;
txq - > stopped = 1 ;
}
spin_unlock_bh ( & txq - > axq_lock ) ;
2008-12-07 21:44:03 +05:30
spin_lock_bh ( & sc - > tx . txbuflock ) ;
list_add_tail ( & bf - > list , & sc - > tx . txbuf ) ;
spin_unlock_bh ( & sc - > tx . txbuflock ) ;
2008-12-03 03:35:30 -08:00
2008-12-03 03:35:29 -08:00
return r ;
}
2008-11-18 09:10:42 +05:30
ath_tx_start_dma ( sc , bf , txctl ) ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:14:26 +05:30
return 0 ;
2008-08-04 00:16:41 -07:00
}
2009-03-03 19:23:29 +02:00
void ath_tx_cabq ( struct ieee80211_hw * hw , struct sk_buff * skb )
2008-08-04 00:16:41 -07:00
{
2009-03-03 19:23:29 +02:00
struct ath_wiphy * aphy = hw - > priv ;
struct ath_softc * sc = aphy - > sc ;
2009-01-16 21:38:42 +05:30
int hdrlen , padsize ;
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
struct ath_tx_control txctl ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
memset ( & txctl , 0 , sizeof ( struct ath_tx_control ) ) ;
2008-08-04 00:16:41 -07:00
/*
2009-01-16 21:38:42 +05:30
* As a temporary workaround , assign seq # here ; this will likely need
* to be cleaned up to work better with Beacon transmission and virtual
* BSSes .
2008-08-04 00:16:41 -07:00
*/
2009-01-16 21:38:42 +05:30
if ( info - > flags & IEEE80211_TX_CTL_ASSIGN_SEQ ) {
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
if ( info - > flags & IEEE80211_TX_CTL_FIRST_FRAGMENT )
sc - > tx . seq_no + = 0x10 ;
hdr - > seq_ctrl & = cpu_to_le16 ( IEEE80211_SCTL_FRAG ) ;
hdr - > seq_ctrl | = cpu_to_le16 ( sc - > tx . seq_no ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
/* Add the padding after the header if this is not already done */
hdrlen = ieee80211_get_hdrlen_from_skb ( skb ) ;
if ( hdrlen & 3 ) {
padsize = hdrlen % 4 ;
if ( skb_headroom ( skb ) < padsize ) {
DPRINTF ( sc , ATH_DBG_XMIT , " TX CABQ padding failed \n " ) ;
dev_kfree_skb_any ( skb ) ;
return ;
}
skb_push ( skb , padsize ) ;
memmove ( skb - > data , skb - > data + padsize , hdrlen ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
txctl . txq = sc - > beacon . cabq ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
DPRINTF ( sc , ATH_DBG_XMIT , " transmitting CABQ packet, skb: %p \n " , skb ) ;
2008-08-04 00:16:41 -07:00
2009-03-03 19:23:29 +02:00
if ( ath_tx_start ( hw , skb , & txctl ) ! = 0 ) {
2009-01-16 21:38:42 +05:30
DPRINTF ( sc , ATH_DBG_XMIT , " CABQ TX failed \n " ) ;
goto exit ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
return ;
exit :
dev_kfree_skb_any ( skb ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
/*****************/
/* TX Completion */
/*****************/
2008-10-29 10:14:26 +05:30
2009-01-16 21:38:42 +05:30
static void ath_tx_complete ( struct ath_softc * sc , struct sk_buff * skb ,
2009-03-20 15:27:50 +05:30
int tx_flags )
2008-10-29 10:14:26 +05:30
{
2009-01-16 21:38:42 +05:30
struct ieee80211_hw * hw = sc - > hw ;
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
struct ath_tx_info_priv * tx_info_priv = ATH_TX_INFO_PRIV ( tx_info ) ;
int hdrlen , padsize ;
2009-03-03 19:23:31 +02:00
int frame_type = ATH9K_NOT_INTERNAL ;
2008-10-29 10:14:26 +05:30
2009-01-16 21:38:42 +05:30
DPRINTF ( sc , ATH_DBG_XMIT , " TX complete: skb: %p \n " , skb ) ;
2008-10-29 10:14:26 +05:30
2009-03-03 19:23:31 +02:00
if ( tx_info_priv ) {
2009-03-03 19:23:29 +02:00
hw = tx_info_priv - > aphy - > hw ;
2009-03-03 19:23:31 +02:00
frame_type = tx_info_priv - > frame_type ;
}
2009-03-03 19:23:29 +02:00
2009-01-16 21:38:42 +05:30
if ( tx_info - > flags & IEEE80211_TX_CTL_NO_ACK | |
tx_info - > flags & IEEE80211_TX_STAT_TX_FILTERED ) {
kfree ( tx_info_priv ) ;
tx_info - > rate_driver_data [ 0 ] = NULL ;
}
2008-10-29 10:14:26 +05:30
2009-03-20 15:27:50 +05:30
if ( tx_flags & ATH_TX_BAR )
2009-01-16 21:38:42 +05:30
tx_info - > flags | = IEEE80211_TX_STAT_AMPDU_NO_BACK ;
2009-03-20 15:27:50 +05:30
if ( ! ( tx_flags & ( ATH_TX_ERROR | ATH_TX_XRETRY ) ) ) {
2009-01-16 21:38:42 +05:30
/* Frame was ACKed */
tx_info - > flags | = IEEE80211_TX_STAT_ACK ;
2008-10-29 10:14:26 +05:30
}
2009-01-16 21:38:42 +05:30
hdrlen = ieee80211_get_hdrlen_from_skb ( skb ) ;
padsize = hdrlen & 3 ;
if ( padsize & & hdrlen > = 24 ) {
/*
* Remove MAC header padding before giving the frame back to
* mac80211 .
*/
memmove ( skb - > data + padsize , skb - > data , hdrlen ) ;
skb_pull ( skb , padsize ) ;
}
2008-10-29 10:14:26 +05:30
2009-05-19 17:01:38 +03:00
if ( sc - > sc_flags & SC_OP_WAIT_FOR_TX_ACK ) {
sc - > sc_flags & = ~ SC_OP_WAIT_FOR_TX_ACK ;
DPRINTF ( sc , ATH_DBG_PS , " Going back to sleep after having "
" received TX status (0x%x) \n " ,
sc - > sc_flags & ( SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_CAB |
SC_OP_WAIT_FOR_PSPOLL_DATA |
SC_OP_WAIT_FOR_TX_ACK ) ) ;
}
2009-03-03 19:23:31 +02:00
if ( frame_type = = ATH9K_NOT_INTERNAL )
ieee80211_tx_status ( hw , skb ) ;
else
ath9k_tx_status ( hw , skb ) ;
2009-01-16 21:38:42 +05:30
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
static void ath_tx_complete_buf ( struct ath_softc * sc , struct ath_buf * bf ,
struct list_head * bf_q ,
int txok , int sendbar )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
struct sk_buff * skb = bf - > bf_mpdu ;
unsigned long flags ;
2009-03-20 15:27:50 +05:30
int tx_flags = 0 ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( sendbar )
2009-03-20 15:27:50 +05:30
tx_flags = ATH_TX_BAR ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( ! txok ) {
2009-03-20 15:27:50 +05:30
tx_flags | = ATH_TX_ERROR ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( bf_isxretried ( bf ) )
2009-03-20 15:27:50 +05:30
tx_flags | = ATH_TX_XRETRY ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
dma_unmap_single ( sc - > dev , bf - > bf_dmacontext , skb - > len , DMA_TO_DEVICE ) ;
2009-03-20 15:27:50 +05:30
ath_tx_complete ( sc , skb , tx_flags ) ;
2009-01-16 21:38:42 +05:30
/*
* Return the list of ath_buf of this mpdu to free queue
*/
spin_lock_irqsave ( & sc - > tx . txbuflock , flags ) ;
list_splice_tail_init ( bf_q , & sc - > tx . txbuf ) ;
spin_unlock_irqrestore ( & sc - > tx . txbuflock , flags ) ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
static int ath_tx_num_badfrms ( struct ath_softc * sc , struct ath_buf * bf ,
int txok )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
struct ath_buf * bf_last = bf - > bf_lastbf ;
struct ath_desc * ds = bf_last - > bf_desc ;
u16 seq_st = 0 ;
u32 ba [ WME_BA_BMP_SIZE > > 5 ] ;
int ba_index ;
int nbad = 0 ;
int isaggr = 0 ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( ds - > ds_txstat . ts_flags = = ATH9K_TX_SW_ABORTED )
return 0 ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
isaggr = bf_isaggr ( bf ) ;
if ( isaggr ) {
seq_st = ATH_DS_BA_SEQ ( ds ) ;
memcpy ( ba , ATH_DS_BA_BITMAP ( ds ) , WME_BA_BMP_SIZE > > 3 ) ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
while ( bf ) {
ba_index = ATH_BA_INDEX ( seq_st , bf - > bf_seqno ) ;
if ( ! txok | | ( isaggr & & ! ATH_BA_ISSET ( ba , ba_index ) ) )
nbad + + ;
bf = bf - > bf_next ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
return nbad ;
}
2008-08-04 00:16:41 -07:00
2009-03-13 08:56:09 +05:30
static void ath_tx_rc_status ( struct ath_buf * bf , struct ath_desc * ds ,
2009-03-20 15:27:49 +05:30
int nbad , int txok , bool update_rc )
2008-08-04 00:16:41 -07:00
{
2009-03-30 15:28:36 +05:30
struct sk_buff * skb = bf - > bf_mpdu ;
2009-02-04 08:10:19 +05:30
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2009-01-16 21:38:42 +05:30
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
struct ath_tx_info_priv * tx_info_priv = ATH_TX_INFO_PRIV ( tx_info ) ;
2009-03-20 15:27:49 +05:30
struct ieee80211_hw * hw = tx_info_priv - > aphy - > hw ;
u8 i , tx_rateindex ;
2008-08-04 00:16:41 -07:00
2009-03-13 08:56:09 +05:30
if ( txok )
tx_info - > status . ack_signal = ds - > ds_txstat . ts_rssi ;
2009-03-20 15:27:49 +05:30
tx_rateindex = ds - > ds_txstat . ts_rateindex ;
WARN_ON ( tx_rateindex > = hw - > max_rates ) ;
tx_info_priv - > update_rc = update_rc ;
2009-01-16 21:38:42 +05:30
if ( ds - > ds_txstat . ts_status & ATH9K_TXERR_FILT )
tx_info - > flags | = IEEE80211_TX_STAT_TX_FILTERED ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( ( ds - > ds_txstat . ts_status & ATH9K_TXERR_FILT ) = = 0 & &
2009-03-20 15:27:49 +05:30
( bf - > bf_flags & ATH9K_TXDESC_NOACK ) = = 0 & & update_rc ) {
2009-02-04 08:10:19 +05:30
if ( ieee80211_is_data ( hdr - > frame_control ) ) {
2009-01-16 21:38:42 +05:30
memcpy ( & tx_info_priv - > tx , & ds - > ds_txstat ,
sizeof ( tx_info_priv - > tx ) ) ;
tx_info_priv - > n_frames = bf - > bf_nframes ;
tx_info_priv - > n_bad_frames = nbad ;
}
2008-08-04 00:16:41 -07:00
}
2009-03-20 15:27:49 +05:30
for ( i = tx_rateindex + 1 ; i < hw - > max_rates ; i + + )
tx_info - > status . rates [ i ] . count = 0 ;
tx_info - > status . rates [ tx_rateindex ] . count = bf - > bf_retries + 1 ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:49 +05:30
static void ath_wake_mac80211_queue ( struct ath_softc * sc , struct ath_txq * txq )
{
int qnum ;
spin_lock_bh ( & txq - > axq_lock ) ;
if ( txq - > stopped & &
2009-02-17 15:36:33 +05:30
sc - > tx . txq [ txq - > axq_qnum ] . axq_depth < = ( ATH_TXBUF - 20 ) ) {
2009-01-16 21:38:49 +05:30
qnum = ath_get_mac80211_qnum ( txq - > axq_qnum , sc ) ;
if ( qnum ! = - 1 ) {
ieee80211_wake_queue ( sc - > hw , qnum ) ;
txq - > stopped = 0 ;
}
}
spin_unlock_bh ( & txq - > axq_lock ) ;
}
2009-01-16 21:38:42 +05:30
static void ath_tx_processq ( struct ath_softc * sc , struct ath_txq * txq )
2008-08-04 00:16:41 -07:00
{
2009-02-09 13:27:12 +05:30
struct ath_hw * ah = sc - > sc_ah ;
2009-01-16 21:38:42 +05:30
struct ath_buf * bf , * lastbf , * bf_held = NULL ;
2008-08-04 00:16:41 -07:00
struct list_head bf_head ;
2009-01-16 21:38:42 +05:30
struct ath_desc * ds ;
2009-03-18 20:22:00 +05:30
int txok ;
2009-01-16 21:38:42 +05:30
int status ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
DPRINTF ( sc , ATH_DBG_QUEUE , " tx queue %d (%x), link %p \n " ,
txq - > axq_qnum , ath9k_hw_gettxbuf ( sc - > sc_ah , txq - > axq_qnum ) ,
txq - > axq_link ) ;
2008-08-04 00:16:41 -07:00
for ( ; ; ) {
spin_lock_bh ( & txq - > axq_lock ) ;
if ( list_empty ( & txq - > axq_q ) ) {
txq - > axq_link = NULL ;
txq - > axq_linkbuf = NULL ;
spin_unlock_bh ( & txq - > axq_lock ) ;
break ;
}
bf = list_first_entry ( & txq - > axq_q , struct ath_buf , list ) ;
2009-01-16 21:38:42 +05:30
/*
* There is a race condition that a BH gets scheduled
* after sw writes TxE and before hw re - load the last
* descriptor to get the newly chained one .
* Software must keep the last DONE descriptor as a
* holding descriptor - software does so by marking
* it with the STALE flag .
*/
bf_held = NULL ;
2009-03-30 15:28:38 +05:30
if ( bf - > bf_stale ) {
2009-01-16 21:38:42 +05:30
bf_held = bf ;
if ( list_is_last ( & bf_held - > list , & txq - > axq_q ) ) {
2009-01-16 21:38:51 +05:30
txq - > axq_link = NULL ;
txq - > axq_linkbuf = NULL ;
spin_unlock_bh ( & txq - > axq_lock ) ;
/*
2009-01-16 21:38:42 +05:30
* The holding descriptor is the last
* descriptor in queue . It ' s safe to remove
* the last holding descriptor in BH context .
*/
2009-01-16 21:38:51 +05:30
spin_lock_bh ( & sc - > tx . txbuflock ) ;
list_move_tail ( & bf_held - > list , & sc - > tx . txbuf ) ;
spin_unlock_bh ( & sc - > tx . txbuflock ) ;
2009-01-16 21:38:42 +05:30
break ;
} else {
bf = list_entry ( bf_held - > list . next ,
2009-01-16 21:38:51 +05:30
struct ath_buf , list ) ;
2009-01-16 21:38:42 +05:30
}
2008-08-04 00:16:41 -07:00
}
lastbf = bf - > bf_lastbf ;
2009-01-16 21:38:42 +05:30
ds = lastbf - > bf_desc ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
status = ath9k_hw_txprocdesc ( ah , ds ) ;
if ( status = = - EINPROGRESS ) {
2008-08-04 00:16:41 -07:00
spin_unlock_bh ( & txq - > axq_lock ) ;
2009-01-16 21:38:42 +05:30
break ;
2008-08-04 00:16:41 -07:00
}
2009-01-16 21:38:42 +05:30
if ( bf - > bf_desc = = txq - > axq_lastdsWithCTS )
txq - > axq_lastdsWithCTS = NULL ;
if ( ds = = txq - > axq_gatingds )
txq - > axq_gatingds = NULL ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
/*
* Remove ath_buf ' s of the same transmit unit from txq ,
* however leave the last descriptor back as the holding
* descriptor for hw .
*/
2009-03-30 15:28:38 +05:30
lastbf - > bf_stale = true ;
2009-01-16 21:38:42 +05:30
INIT_LIST_HEAD ( & bf_head ) ;
if ( ! list_is_singular ( & lastbf - > list ) )
list_cut_position ( & bf_head ,
& txq - > axq_q , lastbf - > list . prev ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
txq - > axq_depth - - ;
if ( bf_isaggr ( bf ) )
txq - > axq_aggr_depth - - ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
txok = ( ds - > ds_txstat . ts_status = = 0 ) ;
spin_unlock_bh ( & txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( bf_held ) {
spin_lock_bh ( & sc - > tx . txbuflock ) ;
2009-01-16 21:38:51 +05:30
list_move_tail ( & bf_held - > list , & sc - > tx . txbuf ) ;
2009-01-16 21:38:42 +05:30
spin_unlock_bh ( & sc - > tx . txbuflock ) ;
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( ! bf_isampdu ( bf ) ) {
/*
* This frame is sent out as a single frame .
* Use hardware retry status for this frame .
*/
bf - > bf_retries = ds - > ds_txstat . ts_longretry ;
if ( ds - > ds_txstat . ts_status & ATH9K_TXERR_XRETRY )
bf - > bf_state . bf_type | = BUF_XRETRY ;
2009-03-20 15:27:49 +05:30
ath_tx_rc_status ( bf , ds , 0 , txok , true ) ;
2009-01-16 21:38:42 +05:30
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
if ( bf_isampdu ( bf ) )
2009-01-16 21:38:53 +05:30
ath_tx_complete_aggr ( sc , txq , bf , & bf_head , txok ) ;
2009-01-16 21:38:42 +05:30
else
ath_tx_complete_buf ( sc , bf , & bf_head , txok , 0 ) ;
2008-10-29 10:19:28 +05:30
2009-01-16 21:38:49 +05:30
ath_wake_mac80211_queue ( sc , txq ) ;
2008-10-29 10:19:28 +05:30
2009-01-16 21:38:49 +05:30
spin_lock_bh ( & txq - > axq_lock ) ;
2009-01-16 21:38:42 +05:30
if ( sc - > sc_flags & SC_OP_TXAGGR )
ath_txq_schedule ( sc , txq ) ;
spin_unlock_bh ( & txq - > axq_lock ) ;
2008-10-29 10:19:28 +05:30
}
}
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
void ath_tx_tasklet ( struct ath_softc * sc )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
int i ;
u32 qcumask = ( ( 1 < < ATH9K_NUM_TX_QUEUES ) - 1 ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
ath9k_hw_gettxintrtxqs ( sc - > sc_ah , & qcumask ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
for ( i = 0 ; i < ATH9K_NUM_TX_QUEUES ; i + + ) {
if ( ATH_TXQ_SETUP ( sc , i ) & & ( qcumask & ( 1 < < i ) ) )
ath_tx_processq ( sc , & sc - > tx . txq [ i ] ) ;
2008-08-04 00:16:41 -07:00
}
}
2009-01-16 21:38:42 +05:30
/*****************/
/* Init, Cleanup */
/*****************/
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
int ath_tx_init ( struct ath_softc * sc , int nbufs )
2008-08-04 00:16:41 -07:00
{
2009-01-16 21:38:42 +05:30
int error = 0 ;
2008-08-04 00:16:41 -07:00
2009-03-30 15:28:45 +05:30
spin_lock_init ( & sc - > tx . txbuflock ) ;
2008-08-04 00:16:41 -07:00
2009-03-30 15:28:45 +05:30
error = ath_descdma_setup ( sc , & sc - > tx . txdma , & sc - > tx . txbuf ,
" tx " , nbufs , 1 ) ;
if ( error ! = 0 ) {
DPRINTF ( sc , ATH_DBG_FATAL ,
" Failed to allocate tx descriptors: %d \n " , error ) ;
goto err ;
}
2008-08-04 00:16:41 -07:00
2009-03-30 15:28:45 +05:30
error = ath_descdma_setup ( sc , & sc - > beacon . bdma , & sc - > beacon . bbuf ,
" beacon " , ATH_BCBUF , 1 ) ;
if ( error ! = 0 ) {
DPRINTF ( sc , ATH_DBG_FATAL ,
" Failed to allocate beacon descriptors: %d \n " , error ) ;
goto err ;
}
2008-08-04 00:16:41 -07:00
2009-03-30 15:28:45 +05:30
err :
2009-01-16 21:38:42 +05:30
if ( error ! = 0 )
ath_tx_cleanup ( sc ) ;
2008-08-04 00:16:41 -07:00
2009-01-16 21:38:42 +05:30
return error ;
2008-08-04 00:16:41 -07:00
}
2009-03-30 15:28:45 +05:30
void ath_tx_cleanup ( struct ath_softc * sc )
2009-01-16 21:38:42 +05:30
{
if ( sc - > beacon . bdma . dd_desc_len ! = 0 )
ath_descdma_cleanup ( sc , & sc - > beacon . bdma , & sc - > beacon . bbuf ) ;
if ( sc - > tx . txdma . dd_desc_len ! = 0 )
ath_descdma_cleanup ( sc , & sc - > tx . txdma , & sc - > tx . txbuf ) ;
}
2008-08-04 00:16:41 -07:00
void ath_tx_node_init ( struct ath_softc * sc , struct ath_node * an )
{
2008-10-29 10:13:59 +05:30
struct ath_atx_tid * tid ;
struct ath_atx_ac * ac ;
int tidno , acno ;
2008-08-04 00:16:41 -07:00
2008-12-07 21:43:36 +05:30
for ( tidno = 0 , tid = & an - > tid [ tidno ] ;
2008-10-29 10:13:59 +05:30
tidno < WME_NUM_TID ;
tidno + + , tid + + ) {
tid - > an = an ;
tid - > tidno = tidno ;
tid - > seq_start = tid - > seq_next = 0 ;
tid - > baw_size = WME_MAX_BA ;
tid - > baw_head = tid - > baw_tail = 0 ;
tid - > sched = false ;
2009-01-16 21:38:42 +05:30
tid - > paused = false ;
2008-10-29 10:15:40 +05:30
tid - > state & = ~ AGGR_CLEANUP ;
2008-10-29 10:13:59 +05:30
INIT_LIST_HEAD ( & tid - > buf_q ) ;
acno = TID_TO_WME_AC ( tidno ) ;
2008-12-07 21:43:36 +05:30
tid - > ac = & an - > ac [ acno ] ;
2008-10-29 10:15:40 +05:30
tid - > state & = ~ AGGR_ADDBA_COMPLETE ;
tid - > state & = ~ AGGR_ADDBA_PROGRESS ;
tid - > addba_exchangeattempts = 0 ;
2008-10-29 10:13:59 +05:30
}
2008-08-04 00:16:41 -07:00
2008-12-07 21:43:36 +05:30
for ( acno = 0 , ac = & an - > ac [ acno ] ;
2008-10-29 10:13:59 +05:30
acno < WME_NUM_AC ; acno + + , ac + + ) {
ac - > sched = false ;
INIT_LIST_HEAD ( & ac - > tid_q ) ;
switch ( acno ) {
case WME_AC_BE :
ac - > qnum = ath_tx_get_qnum ( sc ,
ATH9K_TX_QUEUE_DATA , ATH9K_WME_AC_BE ) ;
break ;
case WME_AC_BK :
ac - > qnum = ath_tx_get_qnum ( sc ,
ATH9K_TX_QUEUE_DATA , ATH9K_WME_AC_BK ) ;
break ;
case WME_AC_VI :
ac - > qnum = ath_tx_get_qnum ( sc ,
ATH9K_TX_QUEUE_DATA , ATH9K_WME_AC_VI ) ;
break ;
case WME_AC_VO :
ac - > qnum = ath_tx_get_qnum ( sc ,
ATH9K_TX_QUEUE_DATA , ATH9K_WME_AC_VO ) ;
break ;
2008-08-04 00:16:41 -07:00
}
}
}
2008-10-29 10:13:31 +05:30
void ath_tx_node_cleanup ( struct ath_softc * sc , struct ath_node * an )
2008-08-04 00:16:41 -07:00
{
int i ;
struct ath_atx_ac * ac , * ac_tmp ;
struct ath_atx_tid * tid , * tid_tmp ;
struct ath_txq * txq ;
2009-01-16 21:38:42 +05:30
2008-08-04 00:16:41 -07:00
for ( i = 0 ; i < ATH9K_NUM_TX_QUEUES ; i + + ) {
if ( ATH_TXQ_SETUP ( sc , i ) ) {
2008-12-07 21:44:03 +05:30
txq = & sc - > tx . txq [ i ] ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:13:31 +05:30
spin_lock ( & txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
list_for_each_entry_safe ( ac ,
ac_tmp , & txq - > axq_acq , list ) {
tid = list_first_entry ( & ac - > tid_q ,
struct ath_atx_tid , list ) ;
if ( tid & & tid - > an ! = an )
continue ;
list_del ( & ac - > list ) ;
ac - > sched = false ;
list_for_each_entry_safe ( tid ,
tid_tmp , & ac - > tid_q , list ) {
list_del ( & tid - > list ) ;
tid - > sched = false ;
2008-10-29 10:13:31 +05:30
ath_tid_drain ( sc , txq , tid ) ;
2008-10-29 10:15:40 +05:30
tid - > state & = ~ AGGR_ADDBA_COMPLETE ;
2008-08-04 00:16:41 -07:00
tid - > addba_exchangeattempts = 0 ;
2008-10-29 10:15:40 +05:30
tid - > state & = ~ AGGR_CLEANUP ;
2008-08-04 00:16:41 -07:00
}
}
2008-10-29 10:13:31 +05:30
spin_unlock ( & txq - > axq_lock ) ;
2008-08-04 00:16:41 -07:00
}
}
}