diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
| -rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 354 | 
1 files changed, 216 insertions, 138 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 42551a48c8a..564c6cb1c2b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -70,6 +70,29 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,  static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,  			     int nbad, int txok, bool update_rc); +enum { +	MCS_DEFAULT, +	MCS_HT40, +	MCS_HT40_SGI, +}; + +static int ath_max_4ms_framelen[3][16] = { +	[MCS_DEFAULT] = { +		3216,  6434,  9650,  12868, 19304, 25740,  28956,  32180, +		6430,  12860, 19300, 25736, 38600, 51472,  57890,  64320, +	}, +	[MCS_HT40] = { +		6684,  13368, 20052, 26738, 40104, 53476,  60156,  66840, +		13360, 26720, 40080, 53440, 80160, 106880, 120240, 133600, +	}, +	[MCS_HT40_SGI] = { +		/* TODO: Only MCS 7 and 15 updated, recalculate the rest */ +		6684,  13368, 20052, 26738, 40104, 53476,  60156,  74200, +		13360, 26720, 40080, 53440, 80160, 106880, 120240, 148400, +	} +}; + +  /*********************/  /* Aggregation logic */  /*********************/ @@ -107,7 +130,7 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)  {  	struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; -	ASSERT(tid->paused > 0); +	BUG_ON(tid->paused <= 0);  	spin_lock_bh(&txq->axq_lock);  	tid->paused--; @@ -131,7 +154,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)  	struct list_head bf_head;  	INIT_LIST_HEAD(&bf_head); -	ASSERT(tid->paused > 0); +	BUG_ON(tid->paused <= 0);  	spin_lock_bh(&txq->axq_lock);  	tid->paused--; @@ -143,7 +166,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)  	while (!list_empty(&tid->buf_q)) {  		bf = list_first_entry(&tid->buf_q, struct ath_buf, list); -		ASSERT(!bf_isretried(bf)); +		BUG_ON(bf_isretried(bf));  		list_move_tail(&bf->list, &bf_head);  		ath_tx_send_ht_normal(sc, txq, tid, &bf_head);  	} @@ -178,7 +201,7 @@ static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,  	index  = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);  	cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); -	ASSERT(tid->tx_buf[cindex] == NULL); +	BUG_ON(tid->tx_buf[cindex] != NULL);  	tid->tx_buf[cindex] = bf;  	if (index >= ((tid->baw_tail - tid->baw_head) & @@ -251,6 +274,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)  	ATH_TXBUF_RESET(tbf); +	tbf->aphy = bf->aphy;  	tbf->bf_mpdu = bf->bf_mpdu;  	tbf->bf_buf_addr = bf->bf_buf_addr;  	*(tbf->bf_desc) = *(bf->bf_desc); @@ -267,7 +291,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,  	struct ath_node *an = NULL;  	struct sk_buff *skb;  	struct ieee80211_sta *sta; +	struct ieee80211_hw *hw;  	struct ieee80211_hdr *hdr; +	struct ieee80211_tx_info *tx_info;  	struct ath_atx_tid *tid = NULL;  	struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;  	struct ath_desc *ds = bf_last->bf_desc; @@ -280,9 +306,13 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,  	skb = bf->bf_mpdu;  	hdr = (struct ieee80211_hdr *)skb->data; +	tx_info = IEEE80211_SKB_CB(skb); +	hw = bf->aphy->hw; +  	rcu_read_lock(); -	sta = ieee80211_find_sta(sc->hw, hdr->addr1); +	/* XXX: use ieee80211_find_sta! */ +	sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);  	if (!sta) {  		rcu_read_unlock();  		return; @@ -358,7 +388,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,  			else  				INIT_LIST_HEAD(&bf_head);  		} else { -			ASSERT(!list_empty(bf_q)); +			BUG_ON(list_empty(bf_q));  			list_move_tail(&bf->list, &bf_head);  		} @@ -452,11 +482,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,  static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,  			   struct ath_atx_tid *tid)  { -	const struct ath_rate_table *rate_table = sc->cur_rate_table;  	struct sk_buff *skb;  	struct ieee80211_tx_info *tx_info;  	struct ieee80211_tx_rate *rates; -	struct ath_tx_info_priv *tx_info_priv;  	u32 max_4ms_framelen, frmlen;  	u16 aggr_limit, legacy = 0;  	int i; @@ -464,7 +492,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,  	skb = bf->bf_mpdu;  	tx_info = IEEE80211_SKB_CB(skb);  	rates = tx_info->control.rates; -	tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0];  	/*  	 * Find the lowest frame length among the rate series that will have a @@ -475,12 +502,20 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,  	for (i = 0; i < 4; i++) {  		if (rates[i].count) { -			if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) { +			int modeidx; +			if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {  				legacy = 1;  				break;  			} -			frmlen = rate_table->info[rates[i].idx].max_4ms_framelen; +			if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) +				modeidx = MCS_HT40_SGI; +			else if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) +				modeidx = MCS_HT40; +			else +				modeidx = MCS_DEFAULT; + +			frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];  			max_4ms_framelen = min(max_4ms_framelen, frmlen);  		}  	} @@ -518,12 +553,11 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,  static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,  				  struct ath_buf *bf, u16 frmlen)  { -	const struct ath_rate_table *rt = sc->cur_rate_table;  	struct sk_buff *skb = bf->bf_mpdu;  	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);  	u32 nsymbits, nsymbols;  	u16 minlen; -	u8 rc, flags, rix; +	u8 flags, rix;  	int width, half_gi, ndelim, mindelim;  	/* Select standard number of delimiters based on frame length alone */ @@ -553,7 +587,6 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,  	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; @@ -565,7 +598,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,  	if (nsymbols == 0)  		nsymbols = 1; -	nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; +	nsymbits = bits_per_symbol[rix][width];  	minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;  	if (frmlen < minlen) { @@ -694,7 +727,6 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,  		/* anchor last desc of aggregate */  		ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc); -		txq->axq_aggr_depth++;  		ath_tx_txqaddbuf(sc, txq, &bf_q);  		TX_STAT_INC(txq->axq_qnum, a_aggr); @@ -815,6 +847,7 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,  struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)  {  	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah);  	struct ath9k_tx_queue_info qi;  	int qnum; @@ -854,9 +887,9 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)  		return NULL;  	}  	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)); +		ath_print(common, 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;  	} @@ -869,8 +902,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)  		INIT_LIST_HEAD(&txq->axq_acq);  		spin_lock_init(&txq->axq_lock);  		txq->axq_depth = 0; -		txq->axq_aggr_depth = 0; -		txq->axq_linkbuf = NULL;  		txq->axq_tx_inprogress = false;  		sc->tx.txqsetup |= 1<<qnum;  	} @@ -884,9 +915,9 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)  	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)); +			ath_print(ath9k_hw_common(sc->sc_ah), 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]; @@ -906,18 +937,19 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)  struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)  {  	struct ath_txq *txq = NULL; +	u16 skb_queue = skb_get_queue_mapping(skb);  	int qnum; -	qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); +	qnum = ath_get_hal_qnum(skb_queue, sc);  	txq = &sc->tx.txq[qnum];  	spin_lock_bh(&txq->axq_lock);  	if (txq->axq_depth >= (ATH_TXBUF - 20)) { -		DPRINTF(sc, ATH_DBG_XMIT, -			"TX queue: %d is full, depth: %d\n", -			qnum, txq->axq_depth); -		ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); +		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT, +			  "TX queue: %d is full, depth: %d\n", +			  qnum, txq->axq_depth); +		ath_mac80211_stop_queue(sc, skb_queue);  		txq->stopped = 1;  		spin_unlock_bh(&txq->axq_lock);  		return NULL; @@ -945,7 +977,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum,  		return 0;  	} -	ASSERT(sc->tx.txq[qnum].axq_qnum == qnum); +	BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);  	ath9k_hw_get_txq_props(ah, qnum, &qi);  	qi.tqi_aifs = qinfo->tqi_aifs; @@ -955,8 +987,8 @@ int ath_txq_update(struct ath_softc *sc, int qnum,  	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); +		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, +			  "Unable to update hardware queue %u!\n", qnum);  		error = -EIO;  	} else {  		ath9k_hw_resettxqueue(ah, qnum); @@ -1004,7 +1036,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)  		if (list_empty(&txq->axq_q)) {  			txq->axq_link = NULL; -			txq->axq_linkbuf = NULL;  			spin_unlock_bh(&txq->axq_lock);  			break;  		} @@ -1055,6 +1086,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)  void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)  {  	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_txq *txq;  	int i, npend = 0; @@ -1076,14 +1108,15 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)  	if (npend) {  		int r; -		DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); +		ath_print(common, ATH_DBG_XMIT, +			  "Unable to stop TxDMA. Reset HAL!\n");  		spin_lock_bh(&sc->sc_resetlock);  		r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true);  		if (r) -			DPRINTF(sc, ATH_DBG_FATAL, -				"Unable to reset hardware; reset status %d\n", -				r); +			ath_print(common, ATH_DBG_FATAL, +				  "Unable to reset hardware; reset status %d\n", +				  r);  		spin_unlock_bh(&sc->sc_resetlock);  	} @@ -1147,8 +1180,8 @@ int ath_tx_setup(struct ath_softc *sc, int haltype)  	struct ath_txq *txq;  	if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { -		DPRINTF(sc, ATH_DBG_FATAL, -			"HAL AC %u out of range, max %zu!\n", +		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, +			  "HAL AC %u out of range, max %zu!\n",  			 haltype, ARRAY_SIZE(sc->tx.hwq_map));  		return 0;  	} @@ -1172,6 +1205,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,  			     struct list_head *head)  {  	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah);  	struct ath_buf *bf;  	/* @@ -1186,21 +1220,20 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,  	list_splice_tail_init(head, &txq->axq_q);  	txq->axq_depth++; -	txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); -	DPRINTF(sc, ATH_DBG_QUEUE, -		"qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); +	ath_print(common, ATH_DBG_QUEUE, +		  "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);  	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); +		ath_print(common, 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); +		ath_print(common, 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); @@ -1420,22 +1453,14 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,  static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,  			    int width, int half_gi, bool shortPreamble)  { -	const struct ath_rate_table *rate_table = sc->cur_rate_table;  	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]; +	nsymbits = bits_per_symbol[rix][width];  	nsymbols = (nbits + nsymbits - 1) / nsymbits;  	if (!half_gi) @@ -1444,7 +1469,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,  		duration = SYMBOL_TIME_HALFGI(nsymbols);  	/* addup duration for legacy/ht training and signal fields */ -	streams = HT_RC_2_STREAMS(rc); +	streams = HT_RC_2_STREAMS(rix);  	duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);  	return duration; @@ -1452,11 +1477,12 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,  static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)  { -	const struct ath_rate_table *rt = sc->cur_rate_table; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath9k_11n_rate_series series[4];  	struct sk_buff *skb;  	struct ieee80211_tx_info *tx_info;  	struct ieee80211_tx_rate *rates; +	const struct ieee80211_rate *rate;  	struct ieee80211_hdr *hdr;  	int i, flags = 0;  	u8 rix = 0, ctsrate = 0; @@ -1475,11 +1501,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)  	 * checking the BSS's global flag.  	 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.  	 */ +	rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info); +	ctsrate = rate->hw_value;  	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; +		ctsrate |= rate->hw_value_short;  	/*  	 * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. @@ -1502,18 +1527,15 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)  		flags &= ~(ATH9K_TXDESC_RTSENA);  	for (i = 0; i < 4; i++) { +		bool is_40, is_sgi, is_sp; +		int phy; +  		if (!rates[i].count || (rates[i].idx < 0))  			continue;  		rix = rates[i].idx;  		series[i].Tries = rates[i].count; -		series[i].ChSel = sc->tx_chainmask; - -		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; +		series[i].ChSel = common->tx_chainmask;  		if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)  			series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; @@ -1522,10 +1544,36 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)  		if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)  			series[i].RateFlags |= ATH9K_RATESERIES_HALFGI; -		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), -			 (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)); +		is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI); +		is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH); +		is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); + +		if (rates[i].flags & IEEE80211_TX_RC_MCS) { +			/* MCS rates */ +			series[i].Rate = rix | 0x80; +			series[i].PktDuration = ath_pkt_duration(sc, rix, bf, +				 is_40, is_sgi, is_sp); +			continue; +		} + +		/* legcay rates */ +		if ((tx_info->band == IEEE80211_BAND_2GHZ) && +		    !(rate->flags & IEEE80211_RATE_ERP_G)) +			phy = WLAN_RC_PHY_CCK; +		else +			phy = WLAN_RC_PHY_OFDM; + +		rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; +		series[i].Rate = rate->hw_value; +		if (rate->hw_value_short) { +			if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) +				series[i].Rate |= rate->hw_value_short; +		} else { +			is_sp = false; +		} + +		series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, +			phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);  	}  	/* set dur_update_en for l-sig computation except for PS-Poll frames */ @@ -1546,24 +1594,36 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,  	struct ath_softc *sc = aphy->sc;  	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; -	struct ath_tx_info_priv *tx_info_priv;  	int hdrlen;  	__le16 fc; +	int padpos, padsize; -	tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); -	if (unlikely(!tx_info_priv)) -		return -ENOMEM; -	tx_info->rate_driver_data[0] = tx_info_priv; -	tx_info_priv->aphy = aphy; -	tx_info_priv->frame_type = txctl->frame_type; +	tx_info->pad[0] = 0; +	switch (txctl->frame_type) { +	case ATH9K_NOT_INTERNAL: +		break; +	case ATH9K_INT_PAUSE: +		tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE; +		/* fall through */ +	case ATH9K_INT_UNPAUSE: +		tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL; +		break; +	}  	hdrlen = ieee80211_get_hdrlen_from_skb(skb);  	fc = hdr->frame_control;  	ATH_TXBUF_RESET(bf); -	bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); +	bf->aphy = aphy; +	bf->bf_frmlen = skb->len + FCS_LEN; +	/* Remove the padding size from bf_frmlen, if any */ +	padpos = ath9k_cmn_padpos(hdr->frame_control); +	padsize = padpos & 3; +	if (padsize && skb->len>padpos+padsize) { +		bf->bf_frmlen -= padsize; +	} -	if (conf_is_ht(&sc->hw->conf) && !is_pae(skb)) +	if (conf_is_ht(&hw->conf) && !is_pae(skb))  		bf->bf_state.bf_type |= BUF_HT;  	bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); @@ -1585,13 +1645,20 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,  					   skb->len, DMA_TO_DEVICE);  	if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {  		bf->bf_mpdu = NULL; -		kfree(tx_info_priv); -		tx_info->rate_driver_data[0] = NULL; -		DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on TX\n"); +		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, +			  "dma_mapping_error() on TX\n");  		return -ENOMEM;  	}  	bf->bf_buf_addr = bf->bf_dmacontext; + +	/* tag if this is a nullfunc frame to enable PS when AP acks it */ +	if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) { +		bf->bf_isnullfunc = true; +		sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; +	} else +		bf->bf_isnullfunc = false; +  	return 0;  } @@ -1669,12 +1736,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,  {  	struct ath_wiphy *aphy = hw->priv;  	struct ath_softc *sc = aphy->sc; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	struct ath_buf *bf;  	int r;  	bf = ath_tx_get_buffer(sc);  	if (!bf) { -		DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n"); +		ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");  		return -1;  	} @@ -1682,7 +1750,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,  	if (unlikely(r)) {  		struct ath_txq *txq = txctl->txq; -		DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); +		ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");  		/* upon ath_tx_processq() this TX queue will be resumed, we  		 * guarantee this will happen by knowing beforehand that @@ -1690,8 +1758,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,  		 * on the queue */  		spin_lock_bh(&txq->axq_lock);  		if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) { -			ieee80211_stop_queue(sc->hw, -				skb_get_queue_mapping(skb)); +			ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));  			txq->stopped = 1;  		}  		spin_unlock_bh(&txq->axq_lock); @@ -1712,6 +1779,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)  {  	struct ath_wiphy *aphy = hw->priv;  	struct ath_softc *sc = aphy->sc; +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	int hdrlen, padsize;  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  	struct ath_tx_control txctl; @@ -1736,7 +1804,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)  	if (hdrlen & 3) {  		padsize = hdrlen % 4;  		if (skb_headroom(skb) < padsize) { -			DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n"); +			ath_print(common, ATH_DBG_XMIT, +				  "TX CABQ padding failed\n");  			dev_kfree_skb_any(skb);  			return;  		} @@ -1746,10 +1815,11 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)  	txctl.txq = sc->beacon.cabq; -	DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); +	ath_print(common, ATH_DBG_XMIT, +		  "transmitting CABQ packet, skb: %p\n", skb);  	if (ath_tx_start(hw, skb, &txctl) != 0) { -		DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); +		ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");  		goto exit;  	} @@ -1763,26 +1833,17 @@ exit:  /*****************/  static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, -			    int tx_flags) +			    struct ath_wiphy *aphy, int tx_flags)  {  	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); +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	int hdrlen, padsize; -	int frame_type = ATH9K_NOT_INTERNAL; -	DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); +	ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); -	if (tx_info_priv) { -		hw = tx_info_priv->aphy->hw; -		frame_type = tx_info_priv->frame_type; -	} - -	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; -	} +	if (aphy) +		hw = aphy->hw;  	if (tx_flags & ATH_TX_BAR)  		tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; @@ -1805,18 +1866,19 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,  	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", +		ath_print(common, 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));  	} -	if (frame_type == ATH9K_NOT_INTERNAL) -		ieee80211_tx_status(hw, skb); -	else +	if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))  		ath9k_tx_status(hw, skb); +	else +		ieee80211_tx_status(hw, skb);  }  static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, @@ -1839,7 +1901,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,  	}  	dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); -	ath_tx_complete(sc, skb, tx_flags); +	ath_tx_complete(sc, skb, bf->aphy, tx_flags);  	ath_debug_stat_tx(sc, txq, bf);  	/* @@ -1887,8 +1949,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,  	struct sk_buff *skb = bf->bf_mpdu;  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); -	struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); -	struct ieee80211_hw *hw = tx_info_priv->aphy->hw; +	struct ieee80211_hw *hw = bf->aphy->hw;  	u8 i, tx_rateindex;  	if (txok) @@ -1897,22 +1958,29 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,  	tx_rateindex = ds->ds_txstat.ts_rateindex;  	WARN_ON(tx_rateindex >= hw->max_rates); -	tx_info_priv->update_rc = update_rc; +	if (update_rc) +		tx_info->pad[0] |= ATH_TX_INFO_UPDATE_RC;  	if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)  		tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;  	if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&  	    (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {  		if (ieee80211_is_data(hdr->frame_control)) { -			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; +			if (ds->ds_txstat.ts_flags & +			    (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN)) +				tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN; +			if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) || +			    (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO)) +				tx_info->pad[0] |= ATH_TX_INFO_XRETRY; +			tx_info->status.ampdu_len = bf->bf_nframes; +			tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;  		}  	} -	for (i = tx_rateindex + 1; i < hw->max_rates; i++) +	for (i = tx_rateindex + 1; i < hw->max_rates; i++) {  		tx_info->status.rates[i].count = 0; +		tx_info->status.rates[i].idx = -1; +	}  	tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;  } @@ -1926,7 +1994,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)  	    sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {  		qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);  		if (qnum != -1) { -			ieee80211_wake_queue(sc->hw, qnum); +			ath_mac80211_start_queue(sc, qnum);  			txq->stopped = 0;  		}  	} @@ -1936,21 +2004,21 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)  static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)  {  	struct ath_hw *ah = sc->sc_ah; +	struct ath_common *common = ath9k_hw_common(ah);  	struct ath_buf *bf, *lastbf, *bf_held = NULL;  	struct list_head bf_head;  	struct ath_desc *ds;  	int txok;  	int status; -	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); +	ath_print(common, 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);  	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;  		} @@ -1984,10 +2052,19 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)  			spin_unlock_bh(&txq->axq_lock);  			break;  		} -		if (bf->bf_desc == txq->axq_lastdsWithCTS) -			txq->axq_lastdsWithCTS = NULL; -		if (ds == txq->axq_gatingds) -			txq->axq_gatingds = NULL; + +		/* +		 * We now know the nullfunc frame has been ACKed so we +		 * can disable RX. +		 */ +		if (bf->bf_isnullfunc && +		    (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { +			if ((sc->sc_flags & SC_OP_PS_ENABLED)) { +				sc->ps_enabled = true; +				ath9k_hw_setrxabort(sc->sc_ah, 1); +			} else +				sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED; +		}  		/*  		 * Remove ath_buf's of the same transmit unit from txq, @@ -2001,9 +2078,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)  				&txq->axq_q, lastbf->list.prev);  		txq->axq_depth--; -		if (bf_isaggr(bf)) -			txq->axq_aggr_depth--; -  		txok = (ds->ds_txstat.ts_status == 0);  		txq->axq_tx_inprogress = false;  		spin_unlock_bh(&txq->axq_lock); @@ -2064,8 +2138,11 @@ static void ath_tx_complete_poll_work(struct work_struct *work)  		}  	if (needreset) { -		DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n"); +		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, +			  "tx hung, resetting the chip\n"); +		ath9k_ps_wakeup(sc);  		ath_reset(sc, false); +		ath9k_ps_restore(sc);  	}  	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, @@ -2093,6 +2170,7 @@ void ath_tx_tasklet(struct ath_softc *sc)  int ath_tx_init(struct ath_softc *sc, int nbufs)  { +	struct ath_common *common = ath9k_hw_common(sc->sc_ah);  	int error = 0;  	spin_lock_init(&sc->tx.txbuflock); @@ -2100,16 +2178,16 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)  	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); +		ath_print(common, ATH_DBG_FATAL, +			  "Failed to allocate tx descriptors: %d\n", error);  		goto err;  	}  	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); +		ath_print(common, ATH_DBG_FATAL, +			  "Failed to allocate beacon descriptors: %d\n", error);  		goto err;  	}  |