Kaynağa Gözat

mac80211: update to wireless-testing 2011-05-27

SVN-Revision: 27071
Felix Fietkau 15 yıl önce
ebeveyn
işleme
41a169115b
24 değiştirilmiş dosya ile 998 ekleme ve 1240 silme
  1. 2 2
      package/mac80211/Makefile
  2. 1 1
      package/mac80211/patches/002-disable_rfkill.patch
  3. 1 1
      package/mac80211/patches/005-disable_ssb_build.patch
  4. 3 3
      package/mac80211/patches/007-remove_misc_drivers.patch
  5. 1 1
      package/mac80211/patches/011-no_sdio.patch
  6. 1 1
      package/mac80211/patches/015-remove-rt2x00-options.patch
  7. 1 1
      package/mac80211/patches/110-disable_usb_compat.patch
  8. 976 82
      package/mac80211/patches/300-pending_work.patch
  9. 2 2
      package/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch
  10. 2 2
      package/mac80211/patches/500-ath9k_eeprom_debugfs.patch
  11. 1 1
      package/mac80211/patches/511-ath9k_increase_bcbuf.patch
  12. 0 0
      package/mac80211/patches/521-mac80211_ht_change_rate_update.patch
  13. 2 2
      package/mac80211/patches/530-ath9k_noise_dbm_fixup.patch
  14. 0 37
      package/mac80211/patches/530-mac80211_remove_wds_sta_flag.patch
  15. 0 160
      package/mac80211/patches/531-mac80211_fix_iftype_wds.patch
  16. 0 67
      package/mac80211/patches/532-mac80211_enable_iftype_wds_aggregation.patch
  17. 0 32
      package/mac80211/patches/540-ath9k_debugfs_show_xretry.patch
  18. 0 50
      package/mac80211/patches/570-ath9k_fix_adhoc_beacons.patch
  19. 0 11
      package/mac80211/patches/571-ath9k_fix_adhoc_nexttbtt.patch
  20. 0 111
      package/mac80211/patches/572-ath9k_tx_last_beacon.patch
  21. 0 598
      package/mac80211/patches/580-ath9k_tx_fifo_cleanup.patch
  22. 0 70
      package/mac80211/patches/581-ath9k_remove_get_desc_link.patch
  23. 4 4
      package/mac80211/patches/800-b43-gpio-mask-module-option.patch
  24. 1 1
      package/mac80211/patches/810-b43_no_pio.patch

+ 2 - 2
package/mac80211/Makefile

@@ -10,10 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk
 
 PKG_NAME:=mac80211
 
-PKG_VERSION:=2011-05-13
+PKG_VERSION:=2011-05-27
 PKG_RELEASE:=1
 PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources
-PKG_MD5SUM:=8670d18633dbd28b19168abe3ecd0357
+PKG_MD5SUM:=3a382b03333aff304dbe8ee94fce6b5a
 
 PKG_SOURCE:=compat-wireless-$(PKG_VERSION).tar.bz2
 PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)

+ 1 - 1
package/mac80211/patches/002-disable_rfkill.patch

@@ -9,7 +9,7 @@
  
  ifeq ($(CONFIG_MAC80211),y)
  $(error "ERROR: you have MAC80211 compiled into the kernel, CONFIG_MAC80211=y, as such you cannot replace its mac80211 driver. You need this set to CONFIG_MAC80211=m. If you are using Fedora upgrade your kernel as later version should this set as modular. For further information on Fedora see https://bugzilla.redhat.com/show_bug.cgi?id=470143. If you are using your own kernel recompile it and make mac80211 modular")
-@@ -617,10 +617,10 @@ endif #CONFIG_COMPAT_KERNEL_27
+@@ -622,10 +622,10 @@ endif #CONFIG_COMPAT_KERNEL_27
  # We need the backported rfkill module on kernel < 2.6.31.
  # In more recent kernel versions use the in kernel rfkill module.
  ifdef CONFIG_COMPAT_KERNEL_31

+ 1 - 1
package/mac80211/patches/005-disable_ssb_build.patch

@@ -51,7 +51,7 @@
  
  CONFIG_P54_PCI=m
  
-@@ -507,7 +505,6 @@ endif #CONFIG_SPI_MASTER end of SPI driv
+@@ -511,7 +509,6 @@ endif #CONFIG_SPI_MASTER end of SPI driv
  
  ifdef CONFIG_MMC
  

+ 3 - 3
package/mac80211/patches/007-remove_misc_drivers.patch

@@ -4,8 +4,8 @@
  endif #CONFIG_WIRELESS_EXT
  
  ifdef CONFIG_STAGING
--CONFIG_COMPAT_STAGING=y
-+# CONFIG_COMPAT_STAGING=y
+-CONFIG_COMPAT_STAGING=m
++# CONFIG_COMPAT_STAGING=m
  endif #CONFIG_STAGING
  
  # mac80211 test driver
@@ -28,7 +28,7 @@
  endif #CONFIG_COMPAT_KERNEL_27
  
  ifdef CONFIG_WIRELESS_EXT
-@@ -402,21 +402,21 @@ endif #CONFIG_COMPAT_KERNEL_29
+@@ -406,21 +406,21 @@ endif #CONFIG_COMPAT_KERNEL_29
  # Note: this depends on CONFIG_USB_NET_RNDIS_HOST and CONFIG_USB_NET_CDCETHER
  # it also requires new RNDIS_HOST and CDC_ETHER modules which we add
  ifdef CONFIG_COMPAT_KERNEL_29

+ 1 - 1
package/mac80211/patches/011-no_sdio.patch

@@ -1,6 +1,6 @@
 --- a/config.mk
 +++ b/config.mk
-@@ -488,7 +488,7 @@ endif #CONFIG_SPI_MASTER end of SPI driv
+@@ -492,7 +492,7 @@ endif #CONFIG_SPI_MASTER end of SPI driv
  
  ifdef CONFIG_MMC
  

+ 1 - 1
package/mac80211/patches/015-remove-rt2x00-options.patch

@@ -9,7 +9,7 @@
  CONFIG_RT2400PCI=m
  CONFIG_RT2500PCI=m
  ifdef CONFIG_CRC_CCITT
-@@ -437,7 +437,7 @@ CONFIG_RT2800USB_RT33XX=y
+@@ -441,7 +441,7 @@ CONFIG_RT2800USB_RT33XX=y
  # CONFIG_RT2800USB_RT53XX=y
  CONFIG_RT2800USB_UNKNOWN=y
  endif #CONFIG_CRC_CCITT

+ 1 - 1
package/mac80211/patches/110-disable_usb_compat.patch

@@ -33,7 +33,7 @@
  #endif
 --- a/config.mk
 +++ b/config.mk
-@@ -423,7 +423,7 @@ endif #CONFIG_COMPAT_KERNEL_29
+@@ -427,7 +427,7 @@ endif #CONFIG_COMPAT_KERNEL_29
  # This activates a threading fix for usb urb.
  # this is mainline commit: b3e670443b7fb8a2d29831b62b44a039c283e351
  # This fix will be included in some stable releases.

+ 976 - 82
package/mac80211/patches/300-pending_work.patch

@@ -1,93 +1,987 @@
---- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
-@@ -829,7 +829,7 @@ static bool ar9002_hw_init_cal(struct at
- 	if (AR_SREV_9271(ah)) {
- 		if (!ar9285_hw_cl_cal(ah, chan))
- 			return false;
--	} else if (AR_SREV_9285_12_OR_LATER(ah)) {
-+	} else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
- 		if (!ar9285_hw_clc(ah, chan))
- 			return false;
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -603,7 +603,6 @@ struct ath_hw_ops {
+ 				     int power_off);
+ 	void (*rx_enable)(struct ath_hw *ah);
+ 	void (*set_desc_link)(void *ds, u32 link);
+-	void (*get_desc_link)(void *ds, u32 **link);
+ 	bool (*calibrate)(struct ath_hw *ah,
+ 			  struct ath9k_channel *chan,
+ 			  u8 rxchainmask,
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -62,8 +62,6 @@ static bool ath9k_has_pending_frames(str
+ 
+ 	if (txq->axq_depth || !list_empty(&txq->axq_acq))
+ 		pending = true;
+-	else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+-		pending = !list_empty(&txq->txq_fifo_pending);
+ 
+ 	spin_unlock_bh(&txq->axq_lock);
+ 	return pending;
+--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+@@ -28,11 +28,6 @@ static void ar9002_hw_set_desc_link(void
+ 	((struct ath_desc*) ds)->ds_link = ds_link;
+ }
+ 
+-static void ar9002_hw_get_desc_link(void *ds, u32 **ds_link)
+-{
+-	*ds_link = &((struct ath_desc *)ds)->ds_link;
+-}
+-
+ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+ {
+ 	u32 isr = 0;
+@@ -437,7 +432,6 @@ void ar9002_hw_attach_mac_ops(struct ath
+ 
+ 	ops->rx_enable = ar9002_hw_rx_enable;
+ 	ops->set_desc_link = ar9002_hw_set_desc_link;
+-	ops->get_desc_link = ar9002_hw_get_desc_link;
+ 	ops->get_isr = ar9002_hw_get_isr;
+ 	ops->fill_txdesc = ar9002_hw_fill_txdesc;
+ 	ops->proc_txdesc = ar9002_hw_proc_txdesc;
+--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+@@ -43,13 +43,6 @@ static void ar9003_hw_set_desc_link(void
+ 	ads->ctl10 |= ar9003_calc_ptr_chksum(ads);
+ }
+ 
+-static void ar9003_hw_get_desc_link(void *ds, u32 **ds_link)
+-{
+-	struct ar9003_txc *ads = ds;
+-
+-	*ds_link = &ads->link;
+-}
+-
+ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+ {
+ 	u32 isr = 0;
+@@ -498,7 +491,6 @@ void ar9003_hw_attach_mac_ops(struct ath
+ 
+ 	ops->rx_enable = ar9003_hw_rx_enable;
+ 	ops->set_desc_link = ar9003_hw_set_desc_link;
+-	ops->get_desc_link = ar9003_hw_get_desc_link;
+ 	ops->get_isr = ar9003_hw_get_isr;
+ 	ops->fill_txdesc = ar9003_hw_fill_txdesc;
+ 	ops->proc_txdesc = ar9003_hw_proc_txdesc;
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -179,7 +179,7 @@ enum ATH_AGGR_STATUS {
+ struct ath_txq {
+ 	int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
+ 	u32 axq_qnum; /* ath9k hardware queue number */
+-	u32 *axq_link;
++	void *axq_link;
+ 	struct list_head axq_q;
+ 	spinlock_t axq_lock;
+ 	u32 axq_depth;
+@@ -188,7 +188,6 @@ struct ath_txq {
+ 	bool axq_tx_inprogress;
+ 	struct list_head axq_acq;
+ 	struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
+-	struct list_head txq_fifo_pending;
+ 	u8 txq_headidx;
+ 	u8 txq_tailidx;
+ 	int pending_frames;
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -550,6 +550,7 @@ static ssize_t read_file_xmit(struct fil
+ 
+ 	PR("MPDUs Queued:    ", queued);
+ 	PR("MPDUs Completed: ", completed);
++	PR("MPDUs XRetried:  ", xretries);
+ 	PR("Aggregates:      ", a_aggr);
+ 	PR("AMPDUs Queued HW:", a_queued_hw);
+ 	PR("AMPDUs Queued SW:", a_queued_sw);
+@@ -587,7 +588,6 @@ static ssize_t read_file_xmit(struct fil
+ 
+ 	PRQLE("axq_q empty:       ", axq_q);
+ 	PRQLE("axq_acq empty:     ", axq_acq);
+-	PRQLE("txq_fifo_pending:  ", txq_fifo_pending);
+ 	for (i = 0; i < ATH_TXFIFO_DEPTH; i++) {
+ 		snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
+ 		PRQLE(tmp, txq_fifo[i]);
+@@ -807,7 +807,10 @@ void ath_debug_stat_tx(struct ath_softc 
+ 		else
+ 			TX_STAT_INC(qnum, a_completed);
  	} else {
---- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
-@@ -1381,3 +1381,25 @@ void ar9003_hw_bb_watchdog_dbg_info(stru
- 		"==== BB update: done ====\n\n");
+-		TX_STAT_INC(qnum, completed);
++		if (bf_isxretried(bf))
++			TX_STAT_INC(qnum, xretries);
++		else
++			TX_STAT_INC(qnum, completed);
+ 	}
+ 
+ 	if (ts->ts_status & ATH9K_TXERR_FIFO)
+--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
++++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
+@@ -39,11 +39,6 @@ static inline void ath9k_hw_set_desc_lin
+ 	ath9k_hw_ops(ah)->set_desc_link(ds, link);
+ }
+ 
+-static inline void ath9k_hw_get_desc_link(struct ath_hw *ah, void *ds,
+-					  u32 **link)
+-{
+-	ath9k_hw_ops(ah)->get_desc_link(ds, link);
+-}
+ static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
+ 				      struct ath9k_channel *chan,
+ 				      u8 rxchainmask,
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -53,7 +53,7 @@ static void ath_tx_complete_buf(struct a
+ 				struct ath_txq *txq, struct list_head *bf_q,
+ 				struct ath_tx_status *ts, int txok, int sendbar);
+ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
+-			     struct list_head *head);
++			     struct list_head *head, bool internal);
+ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
+ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
+ 			     struct ath_tx_status *ts, int nframes, int nbad,
+@@ -377,8 +377,7 @@ static void ath_tx_complete_aggr(struct 
+ 			bf_next = bf->bf_next;
+ 
+ 			bf->bf_state.bf_type |= BUF_XRETRY;
+-			if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
+-			    !bf->bf_stale || bf_next != NULL)
++			if (!bf->bf_stale || bf_next != NULL)
+ 				list_move_tail(&bf->list, &bf_head);
+ 
+ 			ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
+@@ -463,20 +462,14 @@ static void ath_tx_complete_aggr(struct 
+ 			}
+ 		}
+ 
+-		if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
+-		    bf_next == NULL) {
+-			/*
+-			 * 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);
+-		} else {
+-			BUG_ON(list_empty(bf_q));
++		/*
++		 * Make sure the last desc is reclaimed if it
++		 * not a holding desc.
++		 */
++		if (!bf_last->bf_stale || bf_next != NULL)
+ 			list_move_tail(&bf->list, &bf_head);
+-		}
++		else
++			INIT_LIST_HEAD(&bf_head);
+ 
+ 		if (!txpending || (tid->state & AGGR_CLEANUP)) {
+ 			/*
+@@ -837,7 +830,7 @@ static void ath_tx_sched_aggr(struct ath
+ 			bf->bf_state.bf_type &= ~BUF_AGGR;
+ 			ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
+ 			ath_buf_set_rate(sc, bf, fi->framelen);
+-			ath_tx_txqaddbuf(sc, txq, &bf_q);
++			ath_tx_txqaddbuf(sc, txq, &bf_q, false);
+ 			continue;
+ 		}
+ 
+@@ -849,7 +842,7 @@ static void ath_tx_sched_aggr(struct ath
+ 		/* anchor last desc of aggregate */
+ 		ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
+ 
+-		ath_tx_txqaddbuf(sc, txq, &bf_q);
++		ath_tx_txqaddbuf(sc, txq, &bf_q, false);
+ 		TX_STAT_INC(txq->axq_qnum, a_aggr);
+ 
+ 	} while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
+@@ -1085,7 +1078,6 @@ struct ath_txq *ath_txq_setup(struct ath
+ 		txq->txq_headidx = txq->txq_tailidx = 0;
+ 		for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
+ 			INIT_LIST_HEAD(&txq->txq_fifo[i]);
+-		INIT_LIST_HEAD(&txq->txq_fifo_pending);
+ 	}
+ 	return &sc->tx.txq[axq_qnum];
+ }
+@@ -1155,13 +1147,8 @@ static bool bf_is_ampdu_not_probing(stru
+     return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+ }
+ 
+-/*
+- * 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)
++static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
++			       struct list_head *list, bool retry_tx)
+ {
+ 	struct ath_buf *bf, *lastbf;
+ 	struct list_head bf_head;
+@@ -1170,93 +1157,63 @@ void ath_draintxq(struct ath_softc *sc, 
+ 	memset(&ts, 0, sizeof(ts));
+ 	INIT_LIST_HEAD(&bf_head);
+ 
+-	for (;;) {
+-		spin_lock_bh(&txq->axq_lock);
++	while (!list_empty(list)) {
++		bf = list_first_entry(list, struct ath_buf, list);
+ 
+-		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+-			if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
+-				txq->txq_headidx = txq->txq_tailidx = 0;
+-				spin_unlock_bh(&txq->axq_lock);
+-				break;
+-			} else {
+-				bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
+-						      struct ath_buf, list);
+-			}
+-		} else {
+-			if (list_empty(&txq->axq_q)) {
+-				txq->axq_link = NULL;
+-				spin_unlock_bh(&txq->axq_lock);
+-				break;
+-			}
+-			bf = list_first_entry(&txq->axq_q, struct ath_buf,
+-					      list);
+-
+-			if (bf->bf_stale) {
+-				list_del(&bf->list);
+-				spin_unlock_bh(&txq->axq_lock);
++		if (bf->bf_stale) {
++			list_del(&bf->list);
+ 
+-				ath_tx_return_buffer(sc, bf);
+-				continue;
+-			}
++			ath_tx_return_buffer(sc, bf);
++			continue;
+ 		}
+ 
+ 		lastbf = bf->bf_lastbf;
+-
+-		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+-			list_cut_position(&bf_head,
+-					  &txq->txq_fifo[txq->txq_tailidx],
+-					  &lastbf->list);
+-			INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
+-		} else {
+-			/* remove ath_buf's of the same mpdu from txq */
+-			list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
+-		}
++		list_cut_position(&bf_head, list, &lastbf->list);
+ 
+ 		txq->axq_depth--;
+ 		if (bf_is_ampdu_not_probing(bf))
+ 			txq->axq_ampdu_depth--;
+-		spin_unlock_bh(&txq->axq_lock);
+ 
++		spin_unlock_bh(&txq->axq_lock);
+ 		if (bf_isampdu(bf))
+ 			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
+ 					     retry_tx);
+ 		else
+ 			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
++		spin_lock_bh(&txq->axq_lock);
+ 	}
++}
+ 
++/*
++ * 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)
++{
+ 	spin_lock_bh(&txq->axq_lock);
+-	txq->axq_tx_inprogress = false;
+-	spin_unlock_bh(&txq->axq_lock);
+-
+ 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+-		spin_lock_bh(&txq->axq_lock);
+-		while (!list_empty(&txq->txq_fifo_pending)) {
+-			bf = list_first_entry(&txq->txq_fifo_pending,
+-					      struct ath_buf, list);
+-			list_cut_position(&bf_head,
+-					  &txq->txq_fifo_pending,
+-					  &bf->bf_lastbf->list);
+-			spin_unlock_bh(&txq->axq_lock);
++		int idx = txq->txq_tailidx;
+ 
+-			if (bf_isampdu(bf))
+-				ath_tx_complete_aggr(sc, txq, bf, &bf_head,
+-						     &ts, 0, retry_tx);
+-			else
+-				ath_tx_complete_buf(sc, bf, txq, &bf_head,
+-						    &ts, 0, 0);
+-			spin_lock_bh(&txq->axq_lock);
++		while (!list_empty(&txq->txq_fifo[idx])) {
++			ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
++					   retry_tx);
++
++			INCR(idx, ATH_TXFIFO_DEPTH);
+ 		}
+-		spin_unlock_bh(&txq->axq_lock);
++		txq->txq_tailidx = idx;
+ 	}
+ 
++	txq->axq_link = NULL;
++	txq->axq_tx_inprogress = false;
++	ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
++
+ 	/* 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);
+-		}
+-	}
++	if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx)
++		ath_txq_drain_pending_buffers(sc, txq);
++
++	spin_unlock_bh(&txq->axq_lock);
  }
- EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);
+ 
+ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
+@@ -1370,11 +1327,13 @@ void ath_txq_schedule(struct ath_softc *
+  * assume the descriptors are already chained together by caller.
+  */
+ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
+-			     struct list_head *head)
++			     struct list_head *head, bool internal)
+ {
+ 	struct ath_hw *ah = sc->sc_ah;
+ 	struct ath_common *common = ath9k_hw_common(ah);
+-	struct ath_buf *bf;
++	struct ath_buf *bf, *bf_last;
++	bool puttxbuf = false;
++	bool edma;
+ 
+ 	/*
+ 	 * Insert the frame on the outbound list and
+@@ -1384,51 +1343,49 @@ static void ath_tx_txqaddbuf(struct ath_
+ 	if (list_empty(head))
+ 		return;
+ 
++	edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
+ 	bf = list_first_entry(head, struct ath_buf, list);
++	bf_last = list_entry(head->prev, struct ath_buf, list);
+ 
+ 	ath_dbg(common, ATH_DBG_QUEUE,
+ 		"qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
+ 
+-	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+-		if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
+-			list_splice_tail_init(head, &txq->txq_fifo_pending);
+-			return;
+-		}
+-		if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
+-			ath_dbg(common, ATH_DBG_XMIT,
+-				"Initializing tx fifo %d which is non-empty\n",
+-				txq->txq_headidx);
+-		INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
+-		list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
++	if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) {
++		list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]);
+ 		INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
+-		TX_STAT_INC(txq->axq_qnum, puttxbuf);
+-		ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
+-		ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
+-			txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
++		puttxbuf = true;
+ 	} else {
+ 		list_splice_tail_init(head, &txq->axq_q);
+ 
+-		if (txq->axq_link == NULL) {
+-			TX_STAT_INC(txq->axq_qnum, puttxbuf);
+-			ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
+-			ath_dbg(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;
++		if (txq->axq_link) {
++			ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr);
+ 			ath_dbg(common, ATH_DBG_XMIT,
+ 				"link[%u] (%p)=%llx (%p)\n",
+ 				txq->axq_qnum, txq->axq_link,
+ 				ito64(bf->bf_daddr), bf->bf_desc);
+-		}
+-		ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
+-				       &txq->axq_link);
++		} else if (!edma)
++			puttxbuf = true;
++
++		txq->axq_link = bf_last->bf_desc;
++	}
++
++	if (puttxbuf) {
++		TX_STAT_INC(txq->axq_qnum, puttxbuf);
++		ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
++		ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
++			txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
++	}
 +
-+void ar9003_hw_disable_phy_restart(struct ath_hw *ah)
++	if (!edma) {
+ 		TX_STAT_INC(txq->axq_qnum, txstart);
+ 		ath9k_hw_txstart(ah, txq->axq_qnum);
+ 	}
+-	txq->axq_depth++;
+-	if (bf_is_ampdu_not_probing(bf))
+-		txq->axq_ampdu_depth++;
++
++	if (!internal) {
++		txq->axq_depth++;
++		if (bf_is_ampdu_not_probing(bf))
++			txq->axq_ampdu_depth++;
++	}
+ }
+ 
+ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
+@@ -1470,7 +1427,7 @@ static void ath_tx_send_ampdu(struct ath
+ 	TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
+ 	bf->bf_lastbf = bf;
+ 	ath_buf_set_rate(sc, bf, fi->framelen);
+-	ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
++	ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
+ }
+ 
+ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
+@@ -1490,7 +1447,7 @@ static void ath_tx_send_normal(struct at
+ 	bf->bf_lastbf = bf;
+ 	fi = get_frame_info(bf->bf_mpdu);
+ 	ath_buf_set_rate(sc, bf, fi->framelen);
+-	ath_tx_txqaddbuf(sc, txq, bf_head);
++	ath_tx_txqaddbuf(sc, txq, bf_head, false);
+ 	TX_STAT_INC(txq->axq_qnum, queued);
+ }
+ 
+@@ -2077,6 +2034,38 @@ static void ath_tx_rc_status(struct ath_
+ 	tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
+ }
+ 
++static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
++				  struct ath_tx_status *ts, struct ath_buf *bf,
++				  struct list_head *bf_head)
 +{
-+	u32 val;
-+
-+	/* While receiving unsupported rate frame rx state machine
-+	 * gets into a state 0xb and if phy_restart happens in that
-+	 * state, BB would go hang. If RXSM is in 0xb state after
-+	 * first bb panic, ensure to disable the phy_restart.
-+	 */
-+	if (!((MS(ah->bb_watchdog_last_status,
-+		  AR_PHY_WATCHDOG_RX_OFDM_SM) == 0xb) ||
-+	    ah->bb_hang_rx_ofdm))
-+		return;
++	int txok;
++
++	txq->axq_depth--;
++	txok = !(ts->ts_status & ATH9K_TXERR_MASK);
++	txq->axq_tx_inprogress = false;
++	if (bf_is_ampdu_not_probing(bf))
++		txq->axq_ampdu_depth--;
 +
-+	ah->bb_hang_rx_ofdm = true;
-+	val = REG_READ(ah, AR_PHY_RESTART);
-+	val &= ~AR_PHY_RESTART_ENA;
++	spin_unlock_bh(&txq->axq_lock);
 +
-+	REG_WRITE(ah, AR_PHY_RESTART, val);
++	if (!bf_isampdu(bf)) {
++		/*
++		 * This frame is sent out as a single frame.
++		 * Use hardware retry status for this frame.
++		 */
++		if (ts->ts_status & ATH9K_TXERR_XRETRY)
++			bf->bf_state.bf_type |= BUF_XRETRY;
++		ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true);
++		ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0);
++	} else
++		ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
++
++	spin_lock_bh(&txq->axq_lock);
++
++	if (sc->sc_flags & SC_OP_TXAGGR)
++		ath_txq_schedule(sc, txq);
 +}
-+EXPORT_SYMBOL(ar9003_hw_disable_phy_restart);
---- a/drivers/net/wireless/ath/ath9k/hw.c
-+++ b/drivers/net/wireless/ath/ath9k/hw.c
-@@ -1555,9 +1555,12 @@ int ath9k_hw_reset(struct ath_hw *ah, st
- 	if (ah->btcoex_hw.enabled)
- 		ath9k_hw_btcoex_enable(ah);
- 
--	if (AR_SREV_9300_20_OR_LATER(ah))
-+	if (AR_SREV_9300_20_OR_LATER(ah)) {
- 		ar9003_hw_bb_watchdog_config(ah);
- 
-+		ar9003_hw_disable_phy_restart(ah);
-+	}
 +
- 	ath9k_hw_apply_gpio_override(ah);
+ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
+ {
+ 	struct ath_hw *ah = sc->sc_ah;
+@@ -2085,20 +2074,18 @@ static void ath_tx_processq(struct ath_s
+ 	struct list_head bf_head;
+ 	struct ath_desc *ds;
+ 	struct ath_tx_status ts;
+-	int txok;
+ 	int status;
  
- 	return 0;
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -842,6 +842,7 @@ struct ath_hw {
- 
- 	u32 bb_watchdog_last_status;
- 	u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
-+	u8 bb_hang_rx_ofdm; /* true if bb hang due to rx_ofdm */
- 
- 	unsigned int paprd_target_power;
- 	unsigned int paprd_training_power;
-@@ -990,6 +991,7 @@ void ar9002_hw_enable_wep_aggregation(st
- void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
- void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
- void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
-+void ar9003_hw_disable_phy_restart(struct ath_hw *ah);
- void ar9003_paprd_enable(struct ath_hw *ah, bool val);
- void ar9003_paprd_populate_single_table(struct ath_hw *ah,
- 					struct ath9k_hw_cal_data *caldata,
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -670,7 +670,8 @@ void ath9k_tasklet(unsigned long data)
- 	u32 status = sc->intrstatus;
- 	u32 rxmask;
- 
--	if (status & ATH9K_INT_FATAL) {
-+	if ((status & ATH9K_INT_FATAL) ||
-+	    (status & ATH9K_INT_BB_WATCHDOG)) {
- 		ath_reset(sc, true);
- 		return;
+ 	ath_dbg(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);
+ 
++	spin_lock_bh(&txq->axq_lock);
+ 	for (;;) {
+-		spin_lock_bh(&txq->axq_lock);
+ 		if (list_empty(&txq->axq_q)) {
+ 			txq->axq_link = NULL;
+ 			if (sc->sc_flags & SC_OP_TXAGGR)
+ 				ath_txq_schedule(sc, txq);
+-			spin_unlock_bh(&txq->axq_lock);
+ 			break;
+ 		}
+ 		bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
+@@ -2114,13 +2101,11 @@ static void ath_tx_processq(struct ath_s
+ 		bf_held = NULL;
+ 		if (bf->bf_stale) {
+ 			bf_held = bf;
+-			if (list_is_last(&bf_held->list, &txq->axq_q)) {
+-				spin_unlock_bh(&txq->axq_lock);
++			if (list_is_last(&bf_held->list, &txq->axq_q))
+ 				break;
+-			} else {
+-				bf = list_entry(bf_held->list.next,
+-						struct ath_buf, list);
+-			}
++
++			bf = list_entry(bf_held->list.next, struct ath_buf,
++					list);
+ 		}
+ 
+ 		lastbf = bf->bf_lastbf;
+@@ -2128,10 +2113,9 @@ static void ath_tx_processq(struct ath_s
+ 
+ 		memset(&ts, 0, sizeof(ts));
+ 		status = ath9k_hw_txprocdesc(ah, ds, &ts);
+-		if (status == -EINPROGRESS) {
+-			spin_unlock_bh(&txq->axq_lock);
++		if (status == -EINPROGRESS)
+ 			break;
+-		}
++
+ 		TX_STAT_INC(txq->axq_qnum, txprocdesc);
+ 
+ 		/*
+@@ -2145,42 +2129,14 @@ static void ath_tx_processq(struct ath_s
+ 			list_cut_position(&bf_head,
+ 				&txq->axq_q, lastbf->list.prev);
+ 
+-		txq->axq_depth--;
+-		txok = !(ts.ts_status & ATH9K_TXERR_MASK);
+-		txq->axq_tx_inprogress = false;
+-		if (bf_held)
++		if (bf_held) {
+ 			list_del(&bf_held->list);
+-
+-		if (bf_is_ampdu_not_probing(bf))
+-			txq->axq_ampdu_depth--;
+-
+-		spin_unlock_bh(&txq->axq_lock);
+-
+-		if (bf_held)
+ 			ath_tx_return_buffer(sc, bf_held);
+-
+-		if (!bf_isampdu(bf)) {
+-			/*
+-			 * This frame is sent out as a single frame.
+-			 * Use hardware retry status for this frame.
+-			 */
+-			if (ts.ts_status & ATH9K_TXERR_XRETRY)
+-				bf->bf_state.bf_type |= BUF_XRETRY;
+-			ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true);
+ 		}
+ 
+-		if (bf_isampdu(bf))
+-			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
+-					     true);
+-		else
+-			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
+-
+-		spin_lock_bh(&txq->axq_lock);
+-
+-		if (sc->sc_flags & SC_OP_TXAGGR)
+-			ath_txq_schedule(sc, txq);
+-		spin_unlock_bh(&txq->axq_lock);
++		ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
  	}
-@@ -737,6 +738,7 @@ irqreturn_t ath_isr(int irq, void *dev)
++	spin_unlock_bh(&txq->axq_lock);
+ }
+ 
+ static void ath_tx_complete_poll_work(struct work_struct *work)
+@@ -2237,17 +2193,16 @@ void ath_tx_tasklet(struct ath_softc *sc
+ 
+ void ath_tx_edma_tasklet(struct ath_softc *sc)
+ {
+-	struct ath_tx_status txs;
++	struct ath_tx_status ts;
+ 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ 	struct ath_hw *ah = sc->sc_ah;
+ 	struct ath_txq *txq;
+ 	struct ath_buf *bf, *lastbf;
+ 	struct list_head bf_head;
+ 	int status;
+-	int txok;
+ 
+ 	for (;;) {
+-		status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
++		status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
+ 		if (status == -EINPROGRESS)
+ 			break;
+ 		if (status == -EIO) {
+@@ -2257,12 +2212,13 @@ void ath_tx_edma_tasklet(struct ath_soft
+ 		}
+ 
+ 		/* Skip beacon completions */
+-		if (txs.qid == sc->beacon.beaconq)
++		if (ts.qid == sc->beacon.beaconq)
+ 			continue;
+ 
+-		txq = &sc->tx.txq[txs.qid];
++		txq = &sc->tx.txq[ts.qid];
+ 
+ 		spin_lock_bh(&txq->axq_lock);
++
+ 		if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
+ 			spin_unlock_bh(&txq->axq_lock);
+ 			return;
+@@ -2275,41 +2231,21 @@ void ath_tx_edma_tasklet(struct ath_soft
+ 		INIT_LIST_HEAD(&bf_head);
+ 		list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
+ 				  &lastbf->list);
+-		INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
+-		txq->axq_depth--;
+-		txq->axq_tx_inprogress = false;
+-		if (bf_is_ampdu_not_probing(bf))
+-			txq->axq_ampdu_depth--;
+-		spin_unlock_bh(&txq->axq_lock);
+ 
+-		txok = !(txs.ts_status & ATH9K_TXERR_MASK);
+-
+-		if (!bf_isampdu(bf)) {
+-			if (txs.ts_status & ATH9K_TXERR_XRETRY)
+-				bf->bf_state.bf_type |= BUF_XRETRY;
+-			ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true);
+-		}
+-
+-		if (bf_isampdu(bf))
+-			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
+-					     txok, true);
+-		else
+-			ath_tx_complete_buf(sc, bf, txq, &bf_head,
+-					    &txs, txok, 0);
++		if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
++			INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
+ 
+-		spin_lock_bh(&txq->axq_lock);
++			if (!list_empty(&txq->axq_q)) {
++				struct list_head bf_q;
+ 
+-		if (!list_empty(&txq->txq_fifo_pending)) {
+-			INIT_LIST_HEAD(&bf_head);
+-			bf = list_first_entry(&txq->txq_fifo_pending,
+-					      struct ath_buf, list);
+-			list_cut_position(&bf_head,
+-					  &txq->txq_fifo_pending,
+-					  &bf->bf_lastbf->list);
+-			ath_tx_txqaddbuf(sc, txq, &bf_head);
+-		} else if (sc->sc_flags & SC_OP_TXAGGR)
+-			ath_txq_schedule(sc, txq);
++				INIT_LIST_HEAD(&bf_q);
++				txq->axq_link = NULL;
++				list_splice_tail_init(&txq->axq_q, &bf_q);
++				ath_tx_txqaddbuf(sc, txq, &bf_q, true);
++			}
++		}
+ 
++		ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
+ 		spin_unlock_bh(&txq->axq_lock);
+ 	}
+ }
+--- a/net/mac80211/agg-rx.c
++++ b/net/mac80211/agg-rx.c
+@@ -161,6 +161,8 @@ static void ieee80211_send_addba_resp(st
+ 		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
+ 	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ 		memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
++	else if (sdata->vif.type == NL80211_IFTYPE_WDS)
++		memcpy(mgmt->bssid, da, ETH_ALEN);
+ 
+ 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ 					  IEEE80211_STYPE_ACTION);
+--- a/net/mac80211/agg-tx.c
++++ b/net/mac80211/agg-tx.c
+@@ -79,7 +79,8 @@ static void ieee80211_send_addba_request
+ 	memcpy(mgmt->da, da, ETH_ALEN);
+ 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+ 	if (sdata->vif.type == NL80211_IFTYPE_AP ||
+-	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
++	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
++	    sdata->vif.type == NL80211_IFTYPE_WDS)
+ 		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
+ 	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ 		memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
+@@ -388,7 +389,8 @@ int ieee80211_start_tx_ba_session(struct
+ 	 */
+ 	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ 	    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+-	    sdata->vif.type != NL80211_IFTYPE_AP)
++	    sdata->vif.type != NL80211_IFTYPE_AP &&
++	    sdata->vif.type != NL80211_IFTYPE_WDS)
+ 		return -EINVAL;
+ 
+ 	if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
+--- a/net/mac80211/debugfs_sta.c
++++ b/net/mac80211/debugfs_sta.c
+@@ -59,7 +59,7 @@ static ssize_t sta_flags_read(struct fil
+ 	char buf[100];
+ 	struct sta_info *sta = file->private_data;
+ 	u32 staflags = get_sta_flags(sta);
+-	int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
++	int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s",
+ 		staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
+ 		staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
+ 		staflags & WLAN_STA_PS_STA ? "PS (sta)\n" : "",
+@@ -67,7 +67,6 @@ static ssize_t sta_flags_read(struct fil
+ 		staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
+ 		staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
+ 		staflags & WLAN_STA_WME ? "WME\n" : "",
+-		staflags & WLAN_STA_WDS ? "WDS\n" : "",
+ 		staflags & WLAN_STA_MFP ? "MFP\n" : "");
+ 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+ }
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -178,7 +178,6 @@ static int ieee80211_do_open(struct net_
  {
- #define SCHED_INTR (				\
- 		ATH9K_INT_FATAL |		\
-+		ATH9K_INT_BB_WATCHDOG |		\
- 		ATH9K_INT_RXORN |		\
- 		ATH9K_INT_RXEOL |		\
- 		ATH9K_INT_RX |			\
+ 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ 	struct ieee80211_local *local = sdata->local;
+-	struct sta_info *sta;
+ 	u32 changed = 0;
+ 	int res;
+ 	u32 hw_reconf_flags = 0;
+@@ -290,27 +289,6 @@ static int ieee80211_do_open(struct net_
+ 
+ 	set_bit(SDATA_STATE_RUNNING, &sdata->state);
+ 
+-	if (sdata->vif.type == NL80211_IFTYPE_WDS) {
+-		/* Create STA entry for the WDS peer */
+-		sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
+-				     GFP_KERNEL);
+-		if (!sta) {
+-			res = -ENOMEM;
+-			goto err_del_interface;
+-		}
+-
+-		/* no locking required since STA is not live yet */
+-		sta->flags |= WLAN_STA_AUTHORIZED;
+-
+-		res = sta_info_insert(sta);
+-		if (res) {
+-			/* STA has been freed */
+-			goto err_del_interface;
+-		}
+-
+-		rate_control_rate_init(sta);
+-	}
+-
+ 	/*
+ 	 * set_multicast_list will be invoked by the networking core
+ 	 * which will check whether any increments here were done in
+@@ -344,8 +322,7 @@ static int ieee80211_do_open(struct net_
+ 	netif_tx_start_all_queues(dev);
+ 
+ 	return 0;
+- err_del_interface:
+-	drv_remove_interface(local, &sdata->vif);
++
+  err_stop:
+ 	if (!local->open_count)
+ 		drv_stop(local);
+@@ -718,6 +695,70 @@ static void ieee80211_if_setup(struct ne
+ 	dev->destructor = free_netdev;
+ }
+ 
++static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
++					 struct sk_buff *skb)
++{
++	struct ieee80211_local *local = sdata->local;
++	struct ieee80211_rx_status *rx_status;
++	struct ieee802_11_elems elems;
++	struct ieee80211_mgmt *mgmt;
++	struct sta_info *sta;
++	size_t baselen;
++	u32 rates = 0;
++	u16 stype;
++	bool new = false;
++	enum ieee80211_band band = local->hw.conf.channel->band;
++	struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
++
++	rx_status = IEEE80211_SKB_RXCB(skb);
++	mgmt = (struct ieee80211_mgmt *) skb->data;
++	stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
++
++	if (stype != IEEE80211_STYPE_BEACON)
++		return;
++
++	baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
++	if (baselen > skb->len)
++		return;
++
++	ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
++			       skb->len - baselen, &elems);
++
++	rates = ieee80211_sta_get_rates(local, &elems, band);
++
++	rcu_read_lock();
++
++	sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
++
++	if (!sta) {
++		rcu_read_unlock();
++		sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
++				     GFP_KERNEL);
++		if (!sta)
++			return;
++
++		new = true;
++	}
++
++	sta->last_rx = jiffies;
++	sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
++
++	if (elems.ht_cap_elem)
++		ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
++				elems.ht_cap_elem, &sta->sta.ht_cap);
++
++	if (elems.wmm_param)
++		set_sta_flags(sta, WLAN_STA_WME);
++
++	if (new) {
++		sta->flags = WLAN_STA_AUTHORIZED;
++		rate_control_rate_init(sta);
++		sta_info_insert_rcu(sta);
++	}
++
++	rcu_read_unlock();
++}
++
+ static void ieee80211_iface_work(struct work_struct *work)
+ {
+ 	struct ieee80211_sub_if_data *sdata =
+@@ -822,6 +863,9 @@ static void ieee80211_iface_work(struct 
+ 				break;
+ 			ieee80211_mesh_rx_queued_mgmt(sdata, skb);
+ 			break;
++		case NL80211_IFTYPE_WDS:
++			ieee80211_wds_rx_queued_mgmt(sdata, skb);
++			break;
+ 		default:
+ 			WARN(1, "frame for unexpected interface type");
+ 			break;
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2137,7 +2137,8 @@ ieee80211_rx_h_action(struct ieee80211_r
+ 		 */
+ 		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ 		    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+-		    sdata->vif.type != NL80211_IFTYPE_AP)
++		    sdata->vif.type != NL80211_IFTYPE_AP &&
++		    sdata->vif.type != NL80211_IFTYPE_WDS)
+ 			break;
+ 
+ 		/* verify action_code is present */
+@@ -2335,13 +2336,14 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
+ 
+ 	if (!ieee80211_vif_is_mesh(&sdata->vif) &&
+ 	    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+-	    sdata->vif.type != NL80211_IFTYPE_STATION)
++	    sdata->vif.type != NL80211_IFTYPE_STATION &&
++	    sdata->vif.type != NL80211_IFTYPE_WDS)
+ 		return RX_DROP_MONITOR;
+ 
+ 	switch (stype) {
+ 	case cpu_to_le16(IEEE80211_STYPE_BEACON):
+ 	case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
+-		/* process for all: mesh, mlme, ibss */
++		/* process for all: mesh, mlme, ibss, wds */
+ 		break;
+ 	case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+ 	case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+@@ -2680,10 +2682,16 @@ static int prepare_for_handlers(struct i
+ 		}
+ 		break;
+ 	case NL80211_IFTYPE_WDS:
+-		if (bssid || !ieee80211_is_data(hdr->frame_control))
+-			return 0;
+ 		if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
+ 			return 0;
++
++		if (ieee80211_is_data(hdr->frame_control) ||
++		    ieee80211_is_action(hdr->frame_control)) {
++			if (compare_ether_addr(sdata->vif.addr, hdr->addr1))
++				return 0;
++		} else if (!ieee80211_is_beacon(hdr->frame_control))
++			return 0;
++
+ 		break;
+ 	default:
+ 		/* should never get here */
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -31,7 +31,6 @@
+  *	frames.
+  * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
+  * @WLAN_STA_WME: Station is a QoS-STA.
+- * @WLAN_STA_WDS: Station is one of our WDS peers.
+  * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
+  *	IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
+  *	frame to this station is transmitted.
+@@ -54,7 +53,6 @@ enum ieee80211_sta_info_flags {
+ 	WLAN_STA_SHORT_PREAMBLE	= 1<<4,
+ 	WLAN_STA_ASSOC_AP	= 1<<5,
+ 	WLAN_STA_WME		= 1<<6,
+-	WLAN_STA_WDS		= 1<<7,
+ 	WLAN_STA_CLEAR_PS_FILT	= 1<<9,
+ 	WLAN_STA_MFP		= 1<<10,
+ 	WLAN_STA_BLOCK_BA	= 1<<11,
+--- a/drivers/net/wireless/ath/ath9k/debug.h
++++ b/drivers/net/wireless/ath/ath9k/debug.h
+@@ -116,6 +116,7 @@ struct ath_tx_stats {
+ 	u32 tx_bytes_all;
+ 	u32 queued;
+ 	u32 completed;
++	u32 xretries;
+ 	u32 a_aggr;
+ 	u32 a_queued_hw;
+ 	u32 a_queued_sw;
+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+@@ -4645,10 +4645,16 @@ static void ar9003_hw_set_power_per_rate
+ 	case 1:
+ 		break;
+ 	case 2:
+-		scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
++		if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
++			scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
++		else
++			scaledPower = 0;
+ 		break;
+ 	case 3:
+-		scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
++		if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
++			scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
++		else
++			scaledPower = 0;
+ 		break;
+ 	}
+ 
+--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
++++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+@@ -524,10 +524,16 @@ static void ath9k_hw_set_ar9287_power_pe
+ 	case 1:
+ 		break;
+ 	case 2:
+-		scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
++		if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
++			scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
++		else
++			scaledPower = 0;
+ 		break;
+ 	case 3:
+-		scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
++		if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
++			scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
++		else
++			scaledPower = 0;
+ 		break;
+ 	}
+ 	scaledPower = max((u16)0, scaledPower);

+ 2 - 2
package/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch

@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/main.c
 +++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1482,15 +1482,6 @@ static int ath9k_add_interface(struct ie
+@@ -1480,15 +1480,6 @@ static int ath9k_add_interface(struct ie
  		}
  	}
  
@@ -16,7 +16,7 @@
  	ath_dbg(common, ATH_DBG_CONFIG,
  		"Attach a VIF of type: %d\n", vif->type);
  
-@@ -1516,15 +1507,6 @@ static int ath9k_change_interface(struct
+@@ -1514,15 +1505,6 @@ static int ath9k_change_interface(struct
  	mutex_lock(&sc->mutex);
  	ath9k_ps_wakeup(sc);
  

+ 2 - 2
package/mac80211/patches/500-ath9k_eeprom_debugfs.patch

@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/debug.c
 +++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -1120,6 +1120,53 @@ static const struct file_operations fops
+@@ -1131,6 +1131,53 @@ static const struct file_operations fops
  	.llseek = default_llseek,/* read accesses f_pos */
  };
  
@@ -54,7 +54,7 @@
  int ath9k_init_debug(struct ath_hw *ah)
  {
  	struct ath_common *common = ath9k_hw_common(ah);
-@@ -1168,6 +1215,9 @@ int ath9k_init_debug(struct ath_hw *ah)
+@@ -1179,6 +1226,9 @@ int ath9k_init_debug(struct ath_hw *ah)
  	debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
  			   sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
  

+ 1 - 1
package/mac80211/patches/511-ath9k_increase_bcbuf.patch

@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -366,7 +366,7 @@ struct ath_vif {
+@@ -365,7 +365,7 @@ struct ath_vif {
   * number of beacon intervals, the game's up.
   */
  #define BSTUCK_THRESH           	9

+ 0 - 0
package/mac80211/patches/550-mac80211_ht_change_rate_update.patch → package/mac80211/patches/521-mac80211_ht_change_rate_update.patch


+ 2 - 2
package/mac80211/patches/560-ath9k_noise_dbm_fixup.patch → package/mac80211/patches/530-ath9k_noise_dbm_fixup.patch

@@ -48,7 +48,7 @@
  	    (ah->chip_fullsleep != true) &&
 --- a/drivers/net/wireless/ath/ath9k/hw.h
 +++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -688,6 +688,7 @@ struct ath_hw {
+@@ -687,6 +687,7 @@ struct ath_hw {
  	enum nl80211_iftype opmode;
  	enum ath9k_power_mode power_mode;
  
@@ -58,7 +58,7 @@
  	struct ar5416Stats stats;
 --- a/drivers/net/wireless/ath/ath9k/main.c
 +++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -165,7 +165,7 @@ static void ath_update_survey_nf(struct 
+@@ -163,7 +163,7 @@ static void ath_update_survey_nf(struct 
  
  	if (chan->noisefloor) {
  		survey->filled |= SURVEY_INFO_NOISE_DBM;

+ 0 - 37
package/mac80211/patches/530-mac80211_remove_wds_sta_flag.patch

@@ -1,37 +0,0 @@
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -31,7 +31,6 @@
-  *	frames.
-  * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
-  * @WLAN_STA_WME: Station is a QoS-STA.
-- * @WLAN_STA_WDS: Station is one of our WDS peers.
-  * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
-  *	IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
-  *	frame to this station is transmitted.
-@@ -54,7 +53,6 @@ enum ieee80211_sta_info_flags {
- 	WLAN_STA_SHORT_PREAMBLE	= 1<<4,
- 	WLAN_STA_ASSOC_AP	= 1<<5,
- 	WLAN_STA_WME		= 1<<6,
--	WLAN_STA_WDS		= 1<<7,
- 	WLAN_STA_CLEAR_PS_FILT	= 1<<9,
- 	WLAN_STA_MFP		= 1<<10,
- 	WLAN_STA_BLOCK_BA	= 1<<11,
---- a/net/mac80211/debugfs_sta.c
-+++ b/net/mac80211/debugfs_sta.c
-@@ -59,7 +59,7 @@ static ssize_t sta_flags_read(struct fil
- 	char buf[100];
- 	struct sta_info *sta = file->private_data;
- 	u32 staflags = get_sta_flags(sta);
--	int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
-+	int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s",
- 		staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
- 		staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
- 		staflags & WLAN_STA_PS_STA ? "PS (sta)\n" : "",
-@@ -67,7 +67,6 @@ static ssize_t sta_flags_read(struct fil
- 		staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
- 		staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
- 		staflags & WLAN_STA_WME ? "WME\n" : "",
--		staflags & WLAN_STA_WDS ? "WDS\n" : "",
- 		staflags & WLAN_STA_MFP ? "MFP\n" : "");
- 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
- }

+ 0 - 160
package/mac80211/patches/531-mac80211_fix_iftype_wds.patch

@@ -1,160 +0,0 @@
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2335,13 +2335,14 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
- 
- 	if (!ieee80211_vif_is_mesh(&sdata->vif) &&
- 	    sdata->vif.type != NL80211_IFTYPE_ADHOC &&
--	    sdata->vif.type != NL80211_IFTYPE_STATION)
-+	    sdata->vif.type != NL80211_IFTYPE_STATION &&
-+	    sdata->vif.type != NL80211_IFTYPE_WDS)
- 		return RX_DROP_MONITOR;
- 
- 	switch (stype) {
- 	case cpu_to_le16(IEEE80211_STYPE_BEACON):
- 	case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
--		/* process for all: mesh, mlme, ibss */
-+		/* process for all: mesh, mlme, ibss, wds */
- 		break;
- 	case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
- 	case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
-@@ -2680,7 +2681,10 @@ static int prepare_for_handlers(struct i
- 		}
- 		break;
- 	case NL80211_IFTYPE_WDS:
--		if (bssid || !ieee80211_is_data(hdr->frame_control))
-+		if (bssid) {
-+			if (!ieee80211_is_beacon(hdr->frame_control))
-+				return 0;
-+		} else if (!ieee80211_is_data(hdr->frame_control))
- 			return 0;
- 		if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
- 			return 0;
---- a/net/mac80211/iface.c
-+++ b/net/mac80211/iface.c
-@@ -178,7 +178,6 @@ static int ieee80211_do_open(struct net_
- {
- 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- 	struct ieee80211_local *local = sdata->local;
--	struct sta_info *sta;
- 	u32 changed = 0;
- 	int res;
- 	u32 hw_reconf_flags = 0;
-@@ -290,27 +289,6 @@ static int ieee80211_do_open(struct net_
- 
- 	set_bit(SDATA_STATE_RUNNING, &sdata->state);
- 
--	if (sdata->vif.type == NL80211_IFTYPE_WDS) {
--		/* Create STA entry for the WDS peer */
--		sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
--				     GFP_KERNEL);
--		if (!sta) {
--			res = -ENOMEM;
--			goto err_del_interface;
--		}
--
--		/* no locking required since STA is not live yet */
--		sta->flags |= WLAN_STA_AUTHORIZED;
--
--		res = sta_info_insert(sta);
--		if (res) {
--			/* STA has been freed */
--			goto err_del_interface;
--		}
--
--		rate_control_rate_init(sta);
--	}
--
- 	/*
- 	 * set_multicast_list will be invoked by the networking core
- 	 * which will check whether any increments here were done in
-@@ -344,8 +322,7 @@ static int ieee80211_do_open(struct net_
- 	netif_tx_start_all_queues(dev);
- 
- 	return 0;
-- err_del_interface:
--	drv_remove_interface(local, &sdata->vif);
-+
-  err_stop:
- 	if (!local->open_count)
- 		drv_stop(local);
-@@ -718,6 +695,70 @@ static void ieee80211_if_setup(struct ne
- 	dev->destructor = free_netdev;
- }
- 
-+static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
-+					 struct sk_buff *skb)
-+{
-+	struct ieee80211_local *local = sdata->local;
-+	struct ieee80211_rx_status *rx_status;
-+	struct ieee802_11_elems elems;
-+	struct ieee80211_mgmt *mgmt;
-+	struct sta_info *sta;
-+	size_t baselen;
-+	u32 rates = 0;
-+	u16 stype;
-+	bool new = false;
-+	enum ieee80211_band band = local->hw.conf.channel->band;
-+	struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
-+
-+	rx_status = IEEE80211_SKB_RXCB(skb);
-+	mgmt = (struct ieee80211_mgmt *) skb->data;
-+	stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
-+
-+	if (stype != IEEE80211_STYPE_BEACON)
-+		return;
-+
-+	baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
-+	if (baselen > skb->len)
-+		return;
-+
-+	ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
-+			       skb->len - baselen, &elems);
-+
-+	rates = ieee80211_sta_get_rates(local, &elems, band);
-+
-+	rcu_read_lock();
-+
-+	sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
-+
-+	if (!sta) {
-+		rcu_read_unlock();
-+		sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
-+				     GFP_KERNEL);
-+		if (!sta)
-+			return;
-+
-+		new = true;
-+	}
-+
-+	sta->last_rx = jiffies;
-+	sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
-+
-+	if (elems.ht_cap_elem)
-+		ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
-+				elems.ht_cap_elem, &sta->sta.ht_cap);
-+
-+	if (elems.wmm_param)
-+		set_sta_flags(sta, WLAN_STA_WME);
-+
-+	if (new) {
-+		sta->flags = WLAN_STA_AUTHORIZED;
-+		rate_control_rate_init(sta);
-+		sta_info_insert_rcu(sta);
-+	}
-+
-+	rcu_read_unlock();
-+}
-+
- static void ieee80211_iface_work(struct work_struct *work)
- {
- 	struct ieee80211_sub_if_data *sdata =
-@@ -822,6 +863,9 @@ static void ieee80211_iface_work(struct 
- 				break;
- 			ieee80211_mesh_rx_queued_mgmt(sdata, skb);
- 			break;
-+		case NL80211_IFTYPE_WDS:
-+			ieee80211_wds_rx_queued_mgmt(sdata, skb);
-+			break;
- 		default:
- 			WARN(1, "frame for unexpected interface type");
- 			break;

+ 0 - 67
package/mac80211/patches/532-mac80211_enable_iftype_wds_aggregation.patch

@@ -1,67 +0,0 @@
---- a/net/mac80211/agg-tx.c
-+++ b/net/mac80211/agg-tx.c
-@@ -79,7 +79,8 @@ static void ieee80211_send_addba_request
- 	memcpy(mgmt->da, da, ETH_ALEN);
- 	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
- 	if (sdata->vif.type == NL80211_IFTYPE_AP ||
--	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-+	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
-+		sdata->vif.type == NL80211_IFTYPE_WDS)
- 		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
- 	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
- 		memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
-@@ -388,7 +389,8 @@ int ieee80211_start_tx_ba_session(struct
- 	 */
- 	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- 	    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
--	    sdata->vif.type != NL80211_IFTYPE_AP)
-+	    sdata->vif.type != NL80211_IFTYPE_AP &&
-+	    sdata->vif.type != NL80211_IFTYPE_WDS)
- 		return -EINVAL;
- 
- 	if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
---- a/net/mac80211/agg-rx.c
-+++ b/net/mac80211/agg-rx.c
-@@ -161,6 +161,8 @@ static void ieee80211_send_addba_resp(st
- 		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
- 	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
- 		memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
-+	else if (sdata->vif.type == NL80211_IFTYPE_WDS)
-+		memcpy(mgmt->bssid, da, ETH_ALEN);
- 
- 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- 					  IEEE80211_STYPE_ACTION);
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2137,7 +2137,8 @@ ieee80211_rx_h_action(struct ieee80211_r
- 		 */
- 		if (sdata->vif.type != NL80211_IFTYPE_STATION &&
- 		    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
--		    sdata->vif.type != NL80211_IFTYPE_AP)
-+		    sdata->vif.type != NL80211_IFTYPE_AP &&
-+		    sdata->vif.type != NL80211_IFTYPE_WDS)
- 			break;
- 
- 		/* verify action_code is present */
-@@ -2681,13 +2682,16 @@ static int prepare_for_handlers(struct i
- 		}
- 		break;
- 	case NL80211_IFTYPE_WDS:
--		if (bssid) {
--			if (!ieee80211_is_beacon(hdr->frame_control))
--				return 0;
--		} else if (!ieee80211_is_data(hdr->frame_control))
--			return 0;
- 		if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
- 			return 0;
-+
-+		if (ieee80211_is_data(hdr->frame_control) ||
-+		    ieee80211_is_action(hdr->frame_control)) {
-+			if (compare_ether_addr(sdata->vif.addr, hdr->addr1))
-+				return 0;
-+		} else if (!ieee80211_is_beacon(hdr->frame_control))
-+			return 0;
-+
- 		break;
- 	default:
- 		/* should never get here */

+ 0 - 32
package/mac80211/patches/540-ath9k_debugfs_show_xretry.patch

@@ -1,32 +0,0 @@
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -548,6 +548,7 @@ static ssize_t read_file_xmit(struct fil
- 
- 	PR("MPDUs Queued:    ", queued);
- 	PR("MPDUs Completed: ", completed);
-+	PR("MPDUs XRetried:  ", xretries);
- 	PR("Aggregates:      ", a_aggr);
- 	PR("AMPDUs Queued HW:", a_queued_hw);
- 	PR("AMPDUs Queued SW:", a_queued_sw);
-@@ -803,7 +804,10 @@ void ath_debug_stat_tx(struct ath_softc 
- 		else
- 			TX_STAT_INC(qnum, a_completed);
- 	} else {
--		TX_STAT_INC(qnum, completed);
-+		if (bf_isxretried(bf))
-+			TX_STAT_INC(qnum, xretries);
-+		else
-+			TX_STAT_INC(qnum, completed);
- 	}
- 
- 	if (ts->ts_status & ATH9K_TXERR_FIFO)
---- a/drivers/net/wireless/ath/ath9k/debug.h
-+++ b/drivers/net/wireless/ath/ath9k/debug.h
-@@ -116,6 +116,7 @@ struct ath_tx_stats {
- 	u32 tx_bytes_all;
- 	u32 queued;
- 	u32 completed;
-+	u32 xretries;
- 	u32 a_aggr;
- 	u32 a_queued_hw;
- 	u32 a_queued_sw;

+ 0 - 50
package/mac80211/patches/570-ath9k_fix_adhoc_beacons.patch

@@ -1,50 +0,0 @@
---- a/drivers/net/wireless/ath/ath9k/beacon.c
-+++ b/drivers/net/wireless/ath/ath9k/beacon.c
-@@ -351,9 +351,7 @@ void ath_beacon_tasklet(unsigned long da
- 	struct ath_buf *bf = NULL;
- 	struct ieee80211_vif *vif;
- 	int slot;
--	u32 bfaddr, bc = 0, tsftu;
--	u64 tsf;
--	u16 intval;
-+	u32 bfaddr, bc = 0;
- 
- 	/*
- 	 * Check if the previous beacon has gone out.  If
-@@ -388,17 +386,27 @@ void ath_beacon_tasklet(unsigned long da
- 	 * on the tsf to safeguard against missing an swba.
- 	 */
- 
--	intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
- 
--	tsf = ath9k_hw_gettsf64(ah);
--	tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
--	tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
--	slot = (tsftu % (intval * ATH_BCBUF)) / intval;
--	vif = sc->beacon.bslot[slot];
-+	if (ah->opmode == NL80211_IFTYPE_AP) {
-+		u16 intval;
-+		u32 tsftu;
-+		u64 tsf;
-+
-+		intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
-+		tsf = ath9k_hw_gettsf64(ah);
-+		tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
-+		tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
-+		slot = (tsftu % (intval * ATH_BCBUF)) / intval;
-+		vif = sc->beacon.bslot[slot];
-+
-+		ath_dbg(common, ATH_DBG_BEACON,
-+			"slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
-+			slot, tsf, tsftu / ATH_BCBUF, intval, vif);
-+	} else {
-+		slot = 0;
-+		vif = sc->beacon.bslot[slot];
-+	}
- 
--	ath_dbg(common, ATH_DBG_BEACON,
--		"slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
--		slot, tsf, tsftu / ATH_BCBUF, intval, vif);
- 
- 	bfaddr = 0;
- 	if (vif) {

+ 0 - 11
package/mac80211/patches/571-ath9k_fix_adhoc_nexttbtt.patch

@@ -1,11 +0,0 @@
---- a/drivers/net/wireless/ath/ath9k/beacon.c
-+++ b/drivers/net/wireless/ath/ath9k/beacon.c
-@@ -654,7 +654,7 @@ static void ath_beacon_config_adhoc(stru
- 			delta = (tsf - sc->beacon.bc_tstamp);
- 		else
- 			delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp));
--		nexttbtt = tsf + roundup(delta, intval);
-+		nexttbtt = tsf + intval - (delta % intval);
- 	}
- 
- 	ath_dbg(common, ATH_DBG_BEACON,

+ 0 - 111
package/mac80211/patches/572-ath9k_tx_last_beacon.patch

@@ -1,111 +0,0 @@
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -397,6 +397,9 @@ struct ath_beacon {
- 	struct ath_descdma bdma;
- 	struct ath_txq *cabq;
- 	struct list_head bbuf;
-+
-+	bool tx_processed;
-+	bool tx_last;
- };
- 
- void ath_beacon_tasklet(unsigned long data);
---- a/drivers/net/wireless/ath/ath9k/beacon.c
-+++ b/drivers/net/wireless/ath/ath9k/beacon.c
-@@ -18,6 +18,12 @@
- 
- #define FUDGE 2
- 
-+static void ath9k_reset_beacon_status(struct ath_softc *sc)
-+{
-+	sc->beacon.tx_processed = false;
-+	sc->beacon.tx_last = false;
-+}
-+
- /*
-  *  This function will modify certain transmit queue properties depending on
-  *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
-@@ -72,6 +78,8 @@ static void ath_beacon_setup(struct ath_
- 	struct ieee80211_supported_band *sband;
- 	u8 rate = 0;
- 
-+	ath9k_reset_beacon_status(sc);
-+
- 	ds = bf->bf_desc;
- 	flags = ATH9K_TXDESC_NOACK;
- 
-@@ -134,6 +142,8 @@ static struct ath_buf *ath_beacon_genera
- 	struct ieee80211_tx_info *info;
- 	int cabq_depth;
- 
-+	ath9k_reset_beacon_status(sc);
-+
- 	avp = (void *)vif->drv_priv;
- 	cabq = sc->beacon.cabq;
- 
-@@ -644,6 +654,8 @@ static void ath_beacon_config_adhoc(stru
- 	struct ath_common *common = ath9k_hw_common(ah);
- 	u32 tsf, delta, intval, nexttbtt;
- 
-+	ath9k_reset_beacon_status(sc);
-+
- 	tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE);
- 	intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
- 
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -2316,6 +2316,48 @@ static bool ath9k_tx_frames_pending(stru
- 	return false;
- }
- 
-+int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
-+{
-+	struct ath_softc *sc = hw->priv;
-+	struct ath_hw *ah = sc->sc_ah;
-+	struct ieee80211_vif *vif;
-+	struct ath_vif *avp;
-+	struct ath_buf *bf;
-+	struct ath_tx_status ts;
-+	int status;
-+
-+	if (ah->opmode != NL80211_IFTYPE_ADHOC)
-+		return 0;
-+
-+	vif = sc->beacon.bslot[0];
-+	if (!vif)
-+		return 0;
-+
-+	avp = (void *)vif->drv_priv;
-+	if (!avp->is_bslot_active)
-+		return 0;
-+
-+	if (!sc->beacon.tx_processed) {
-+		tasklet_disable(&sc->bcon_tasklet);
-+
-+		bf = avp->av_bcbuf;
-+		if (!bf || !bf->bf_mpdu)
-+			goto skip;
-+
-+		status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts);
-+		if (status == -EINPROGRESS)
-+			goto skip;
-+
-+		sc->beacon.tx_processed = true;
-+		sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
-+
-+skip:
-+		tasklet_enable(&sc->bcon_tasklet);
-+	}
-+
-+	return sc->beacon.tx_last;
-+}
-+
- struct ieee80211_ops ath9k_ops = {
- 	.tx 		    = ath9k_tx,
- 	.start 		    = ath9k_start,
-@@ -2340,4 +2382,5 @@ struct ieee80211_ops ath9k_ops = {
- 	.set_coverage_class = ath9k_set_coverage_class,
- 	.flush		    = ath9k_flush,
- 	.tx_frames_pending  = ath9k_tx_frames_pending,
-+	.tx_last_beacon = ath9k_tx_last_beacon,
- };

+ 0 - 598
package/mac80211/patches/580-ath9k_tx_fifo_cleanup.patch

@@ -1,598 +0,0 @@
---- a/drivers/net/wireless/ath/ath9k/xmit.c
-+++ b/drivers/net/wireless/ath/ath9k/xmit.c
-@@ -53,7 +53,7 @@ static void ath_tx_complete_buf(struct a
- 				struct ath_txq *txq, struct list_head *bf_q,
- 				struct ath_tx_status *ts, int txok, int sendbar);
- static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
--			     struct list_head *head);
-+			     struct list_head *head, bool internal);
- static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
- static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
- 			     struct ath_tx_status *ts, int nframes, int nbad,
-@@ -377,8 +377,7 @@ static void ath_tx_complete_aggr(struct 
- 			bf_next = bf->bf_next;
- 
- 			bf->bf_state.bf_type |= BUF_XRETRY;
--			if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
--			    !bf->bf_stale || bf_next != NULL)
-+			if (!bf->bf_stale || bf_next != NULL)
- 				list_move_tail(&bf->list, &bf_head);
- 
- 			ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
-@@ -463,20 +462,14 @@ static void ath_tx_complete_aggr(struct 
- 			}
- 		}
- 
--		if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
--		    bf_next == NULL) {
--			/*
--			 * 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);
--		} else {
--			BUG_ON(list_empty(bf_q));
-+		/*
-+		 * Make sure the last desc is reclaimed if it
-+		 * not a holding desc.
-+		 */
-+		if (!bf_last->bf_stale || bf_next != NULL)
- 			list_move_tail(&bf->list, &bf_head);
--		}
-+		else
-+			INIT_LIST_HEAD(&bf_head);
- 
- 		if (!txpending || (tid->state & AGGR_CLEANUP)) {
- 			/*
-@@ -837,7 +830,7 @@ static void ath_tx_sched_aggr(struct ath
- 			bf->bf_state.bf_type &= ~BUF_AGGR;
- 			ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
- 			ath_buf_set_rate(sc, bf, fi->framelen);
--			ath_tx_txqaddbuf(sc, txq, &bf_q);
-+			ath_tx_txqaddbuf(sc, txq, &bf_q, false);
- 			continue;
- 		}
- 
-@@ -849,7 +842,7 @@ static void ath_tx_sched_aggr(struct ath
- 		/* anchor last desc of aggregate */
- 		ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
- 
--		ath_tx_txqaddbuf(sc, txq, &bf_q);
-+		ath_tx_txqaddbuf(sc, txq, &bf_q, false);
- 		TX_STAT_INC(txq->axq_qnum, a_aggr);
- 
- 	} while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
-@@ -1085,7 +1078,6 @@ struct ath_txq *ath_txq_setup(struct ath
- 		txq->txq_headidx = txq->txq_tailidx = 0;
- 		for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
- 			INIT_LIST_HEAD(&txq->txq_fifo[i]);
--		INIT_LIST_HEAD(&txq->txq_fifo_pending);
- 	}
- 	return &sc->tx.txq[axq_qnum];
- }
-@@ -1155,13 +1147,8 @@ static bool bf_is_ampdu_not_probing(stru
-     return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
- }
- 
--/*
-- * 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)
-+static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
-+			       struct list_head *list, bool retry_tx)
- {
- 	struct ath_buf *bf, *lastbf;
- 	struct list_head bf_head;
-@@ -1170,93 +1157,63 @@ void ath_draintxq(struct ath_softc *sc, 
- 	memset(&ts, 0, sizeof(ts));
- 	INIT_LIST_HEAD(&bf_head);
- 
--	for (;;) {
--		spin_lock_bh(&txq->axq_lock);
-+	while (!list_empty(list)) {
-+		bf = list_first_entry(list, struct ath_buf, list);
- 
--		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
--			if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
--				txq->txq_headidx = txq->txq_tailidx = 0;
--				spin_unlock_bh(&txq->axq_lock);
--				break;
--			} else {
--				bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
--						      struct ath_buf, list);
--			}
--		} else {
--			if (list_empty(&txq->axq_q)) {
--				txq->axq_link = NULL;
--				spin_unlock_bh(&txq->axq_lock);
--				break;
--			}
--			bf = list_first_entry(&txq->axq_q, struct ath_buf,
--					      list);
--
--			if (bf->bf_stale) {
--				list_del(&bf->list);
--				spin_unlock_bh(&txq->axq_lock);
-+		if (bf->bf_stale) {
-+			list_del(&bf->list);
- 
--				ath_tx_return_buffer(sc, bf);
--				continue;
--			}
-+			ath_tx_return_buffer(sc, bf);
-+			continue;
- 		}
- 
- 		lastbf = bf->bf_lastbf;
--
--		if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
--			list_cut_position(&bf_head,
--					  &txq->txq_fifo[txq->txq_tailidx],
--					  &lastbf->list);
--			INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
--		} else {
--			/* remove ath_buf's of the same mpdu from txq */
--			list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
--		}
-+		list_cut_position(&bf_head, list, &lastbf->list);
- 
- 		txq->axq_depth--;
- 		if (bf_is_ampdu_not_probing(bf))
- 			txq->axq_ampdu_depth--;
--		spin_unlock_bh(&txq->axq_lock);
- 
-+		spin_unlock_bh(&txq->axq_lock);
- 		if (bf_isampdu(bf))
- 			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
- 					     retry_tx);
- 		else
- 			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
-+		spin_lock_bh(&txq->axq_lock);
- 	}
-+}
- 
-+/*
-+ * 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)
-+{
- 	spin_lock_bh(&txq->axq_lock);
--	txq->axq_tx_inprogress = false;
--	spin_unlock_bh(&txq->axq_lock);
--
- 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
--		spin_lock_bh(&txq->axq_lock);
--		while (!list_empty(&txq->txq_fifo_pending)) {
--			bf = list_first_entry(&txq->txq_fifo_pending,
--					      struct ath_buf, list);
--			list_cut_position(&bf_head,
--					  &txq->txq_fifo_pending,
--					  &bf->bf_lastbf->list);
--			spin_unlock_bh(&txq->axq_lock);
-+		int idx = txq->txq_tailidx;
- 
--			if (bf_isampdu(bf))
--				ath_tx_complete_aggr(sc, txq, bf, &bf_head,
--						     &ts, 0, retry_tx);
--			else
--				ath_tx_complete_buf(sc, bf, txq, &bf_head,
--						    &ts, 0, 0);
--			spin_lock_bh(&txq->axq_lock);
-+		while (!list_empty(&txq->txq_fifo[idx])) {
-+			ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
-+					   retry_tx);
-+
-+			INCR(idx, ATH_TXFIFO_DEPTH);
- 		}
--		spin_unlock_bh(&txq->axq_lock);
-+		txq->txq_tailidx = idx;
- 	}
- 
-+	txq->axq_link = NULL;
-+	txq->axq_tx_inprogress = false;
-+	ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
-+
- 	/* 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);
--		}
--	}
-+	if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx)
-+		ath_txq_drain_pending_buffers(sc, txq);
-+
-+	spin_unlock_bh(&txq->axq_lock);
- }
- 
- bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
-@@ -1370,11 +1327,13 @@ void ath_txq_schedule(struct ath_softc *
-  * assume the descriptors are already chained together by caller.
-  */
- static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
--			     struct list_head *head)
-+			     struct list_head *head, bool internal)
- {
- 	struct ath_hw *ah = sc->sc_ah;
- 	struct ath_common *common = ath9k_hw_common(ah);
--	struct ath_buf *bf;
-+	struct ath_buf *bf, *bf_last;
-+	bool puttxbuf = false;
-+	bool edma;
- 
- 	/*
- 	 * Insert the frame on the outbound list and
-@@ -1384,51 +1343,49 @@ static void ath_tx_txqaddbuf(struct ath_
- 	if (list_empty(head))
- 		return;
- 
-+	edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
- 	bf = list_first_entry(head, struct ath_buf, list);
-+	bf_last = list_entry(head->prev, struct ath_buf, list);
- 
- 	ath_dbg(common, ATH_DBG_QUEUE,
- 		"qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
- 
--	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
--		if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
--			list_splice_tail_init(head, &txq->txq_fifo_pending);
--			return;
--		}
--		if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
--			ath_dbg(common, ATH_DBG_XMIT,
--				"Initializing tx fifo %d which is non-empty\n",
--				txq->txq_headidx);
--		INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
--		list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
-+	if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) {
-+		list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]);
- 		INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
--		TX_STAT_INC(txq->axq_qnum, puttxbuf);
--		ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
--		ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
--			txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
-+		puttxbuf = true;
- 	} else {
- 		list_splice_tail_init(head, &txq->axq_q);
- 
--		if (txq->axq_link == NULL) {
--			TX_STAT_INC(txq->axq_qnum, puttxbuf);
--			ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
--			ath_dbg(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;
-+		if (txq->axq_link) {
-+			ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr);
- 			ath_dbg(common, ATH_DBG_XMIT,
- 				"link[%u] (%p)=%llx (%p)\n",
- 				txq->axq_qnum, txq->axq_link,
- 				ito64(bf->bf_daddr), bf->bf_desc);
--		}
--		ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
--				       &txq->axq_link);
-+		} else if (!edma)
-+			puttxbuf = true;
-+
-+		txq->axq_link = bf_last->bf_desc;
-+	}
-+
-+	if (puttxbuf) {
-+		TX_STAT_INC(txq->axq_qnum, puttxbuf);
-+		ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
-+		ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
-+			txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
-+	}
-+
-+	if (!edma) {
- 		TX_STAT_INC(txq->axq_qnum, txstart);
- 		ath9k_hw_txstart(ah, txq->axq_qnum);
- 	}
--	txq->axq_depth++;
--	if (bf_is_ampdu_not_probing(bf))
--		txq->axq_ampdu_depth++;
-+
-+	if (!internal) {
-+		txq->axq_depth++;
-+		if (bf_is_ampdu_not_probing(bf))
-+			txq->axq_ampdu_depth++;
-+	}
- }
- 
- static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
-@@ -1470,7 +1427,7 @@ static void ath_tx_send_ampdu(struct ath
- 	TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
- 	bf->bf_lastbf = bf;
- 	ath_buf_set_rate(sc, bf, fi->framelen);
--	ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
-+	ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
- }
- 
- static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
-@@ -1490,7 +1447,7 @@ static void ath_tx_send_normal(struct at
- 	bf->bf_lastbf = bf;
- 	fi = get_frame_info(bf->bf_mpdu);
- 	ath_buf_set_rate(sc, bf, fi->framelen);
--	ath_tx_txqaddbuf(sc, txq, bf_head);
-+	ath_tx_txqaddbuf(sc, txq, bf_head, false);
- 	TX_STAT_INC(txq->axq_qnum, queued);
- }
- 
-@@ -2077,6 +2034,38 @@ static void ath_tx_rc_status(struct ath_
- 	tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
- }
- 
-+static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
-+				  struct ath_tx_status *ts, struct ath_buf *bf,
-+				  struct list_head *bf_head)
-+{
-+	int txok;
-+
-+	txq->axq_depth--;
-+	txok = !(ts->ts_status & ATH9K_TXERR_MASK);
-+	txq->axq_tx_inprogress = false;
-+	if (bf_is_ampdu_not_probing(bf))
-+		txq->axq_ampdu_depth--;
-+
-+	spin_unlock_bh(&txq->axq_lock);
-+
-+	if (!bf_isampdu(bf)) {
-+		/*
-+		 * This frame is sent out as a single frame.
-+		 * Use hardware retry status for this frame.
-+		 */
-+		if (ts->ts_status & ATH9K_TXERR_XRETRY)
-+			bf->bf_state.bf_type |= BUF_XRETRY;
-+		ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true);
-+		ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0);
-+	} else
-+		ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
-+
-+	spin_lock_bh(&txq->axq_lock);
-+
-+	if (sc->sc_flags & SC_OP_TXAGGR)
-+		ath_txq_schedule(sc, txq);
-+}
-+
- static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
- {
- 	struct ath_hw *ah = sc->sc_ah;
-@@ -2085,20 +2074,18 @@ static void ath_tx_processq(struct ath_s
- 	struct list_head bf_head;
- 	struct ath_desc *ds;
- 	struct ath_tx_status ts;
--	int txok;
- 	int status;
- 
- 	ath_dbg(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);
- 
-+	spin_lock_bh(&txq->axq_lock);
- 	for (;;) {
--		spin_lock_bh(&txq->axq_lock);
- 		if (list_empty(&txq->axq_q)) {
- 			txq->axq_link = NULL;
- 			if (sc->sc_flags & SC_OP_TXAGGR)
- 				ath_txq_schedule(sc, txq);
--			spin_unlock_bh(&txq->axq_lock);
- 			break;
- 		}
- 		bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
-@@ -2114,13 +2101,11 @@ static void ath_tx_processq(struct ath_s
- 		bf_held = NULL;
- 		if (bf->bf_stale) {
- 			bf_held = bf;
--			if (list_is_last(&bf_held->list, &txq->axq_q)) {
--				spin_unlock_bh(&txq->axq_lock);
-+			if (list_is_last(&bf_held->list, &txq->axq_q))
- 				break;
--			} else {
--				bf = list_entry(bf_held->list.next,
--						struct ath_buf, list);
--			}
-+
-+			bf = list_entry(bf_held->list.next, struct ath_buf,
-+					list);
- 		}
- 
- 		lastbf = bf->bf_lastbf;
-@@ -2128,10 +2113,9 @@ static void ath_tx_processq(struct ath_s
- 
- 		memset(&ts, 0, sizeof(ts));
- 		status = ath9k_hw_txprocdesc(ah, ds, &ts);
--		if (status == -EINPROGRESS) {
--			spin_unlock_bh(&txq->axq_lock);
-+		if (status == -EINPROGRESS)
- 			break;
--		}
-+
- 		TX_STAT_INC(txq->axq_qnum, txprocdesc);
- 
- 		/*
-@@ -2145,42 +2129,14 @@ static void ath_tx_processq(struct ath_s
- 			list_cut_position(&bf_head,
- 				&txq->axq_q, lastbf->list.prev);
- 
--		txq->axq_depth--;
--		txok = !(ts.ts_status & ATH9K_TXERR_MASK);
--		txq->axq_tx_inprogress = false;
--		if (bf_held)
-+		if (bf_held) {
- 			list_del(&bf_held->list);
--
--		if (bf_is_ampdu_not_probing(bf))
--			txq->axq_ampdu_depth--;
--
--		spin_unlock_bh(&txq->axq_lock);
--
--		if (bf_held)
- 			ath_tx_return_buffer(sc, bf_held);
--
--		if (!bf_isampdu(bf)) {
--			/*
--			 * This frame is sent out as a single frame.
--			 * Use hardware retry status for this frame.
--			 */
--			if (ts.ts_status & ATH9K_TXERR_XRETRY)
--				bf->bf_state.bf_type |= BUF_XRETRY;
--			ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true);
- 		}
- 
--		if (bf_isampdu(bf))
--			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
--					     true);
--		else
--			ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
--
--		spin_lock_bh(&txq->axq_lock);
--
--		if (sc->sc_flags & SC_OP_TXAGGR)
--			ath_txq_schedule(sc, txq);
--		spin_unlock_bh(&txq->axq_lock);
-+		ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
- 	}
-+	spin_unlock_bh(&txq->axq_lock);
- }
- 
- static void ath_tx_complete_poll_work(struct work_struct *work)
-@@ -2237,17 +2193,16 @@ void ath_tx_tasklet(struct ath_softc *sc
- 
- void ath_tx_edma_tasklet(struct ath_softc *sc)
- {
--	struct ath_tx_status txs;
-+	struct ath_tx_status ts;
- 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- 	struct ath_hw *ah = sc->sc_ah;
- 	struct ath_txq *txq;
- 	struct ath_buf *bf, *lastbf;
- 	struct list_head bf_head;
- 	int status;
--	int txok;
- 
- 	for (;;) {
--		status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
-+		status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
- 		if (status == -EINPROGRESS)
- 			break;
- 		if (status == -EIO) {
-@@ -2257,12 +2212,13 @@ void ath_tx_edma_tasklet(struct ath_soft
- 		}
- 
- 		/* Skip beacon completions */
--		if (txs.qid == sc->beacon.beaconq)
-+		if (ts.qid == sc->beacon.beaconq)
- 			continue;
- 
--		txq = &sc->tx.txq[txs.qid];
-+		txq = &sc->tx.txq[ts.qid];
- 
- 		spin_lock_bh(&txq->axq_lock);
-+
- 		if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
- 			spin_unlock_bh(&txq->axq_lock);
- 			return;
-@@ -2275,41 +2231,21 @@ void ath_tx_edma_tasklet(struct ath_soft
- 		INIT_LIST_HEAD(&bf_head);
- 		list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
- 				  &lastbf->list);
--		INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
--		txq->axq_depth--;
--		txq->axq_tx_inprogress = false;
--		if (bf_is_ampdu_not_probing(bf))
--			txq->axq_ampdu_depth--;
--		spin_unlock_bh(&txq->axq_lock);
- 
--		txok = !(txs.ts_status & ATH9K_TXERR_MASK);
--
--		if (!bf_isampdu(bf)) {
--			if (txs.ts_status & ATH9K_TXERR_XRETRY)
--				bf->bf_state.bf_type |= BUF_XRETRY;
--			ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true);
--		}
--
--		if (bf_isampdu(bf))
--			ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
--					     txok, true);
--		else
--			ath_tx_complete_buf(sc, bf, txq, &bf_head,
--					    &txs, txok, 0);
-+		if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
-+			INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
- 
--		spin_lock_bh(&txq->axq_lock);
-+			if (!list_empty(&txq->axq_q)) {
-+				struct list_head bf_q;
- 
--		if (!list_empty(&txq->txq_fifo_pending)) {
--			INIT_LIST_HEAD(&bf_head);
--			bf = list_first_entry(&txq->txq_fifo_pending,
--					      struct ath_buf, list);
--			list_cut_position(&bf_head,
--					  &txq->txq_fifo_pending,
--					  &bf->bf_lastbf->list);
--			ath_tx_txqaddbuf(sc, txq, &bf_head);
--		} else if (sc->sc_flags & SC_OP_TXAGGR)
--			ath_txq_schedule(sc, txq);
-+				INIT_LIST_HEAD(&bf_q);
-+				txq->axq_link = NULL;
-+				list_splice_tail_init(&txq->axq_q, &bf_q);
-+				ath_tx_txqaddbuf(sc, txq, &bf_q, true);
-+			}
-+		}
- 
-+		ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
- 		spin_unlock_bh(&txq->axq_lock);
- 	}
- }
---- a/drivers/net/wireless/ath/ath9k/ath9k.h
-+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -179,7 +179,7 @@ enum ATH_AGGR_STATUS {
- struct ath_txq {
- 	int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
- 	u32 axq_qnum; /* ath9k hardware queue number */
--	u32 *axq_link;
-+	void *axq_link;
- 	struct list_head axq_q;
- 	spinlock_t axq_lock;
- 	u32 axq_depth;
-@@ -188,7 +188,6 @@ struct ath_txq {
- 	bool axq_tx_inprogress;
- 	struct list_head axq_acq;
- 	struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
--	struct list_head txq_fifo_pending;
- 	u8 txq_headidx;
- 	u8 txq_tailidx;
- 	int pending_frames;
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -62,8 +62,6 @@ static bool ath9k_has_pending_frames(str
- 
- 	if (txq->axq_depth || !list_empty(&txq->axq_acq))
- 		pending = true;
--	else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
--		pending = !list_empty(&txq->txq_fifo_pending);
- 
- 	spin_unlock_bh(&txq->axq_lock);
- 	return pending;
---- a/drivers/net/wireless/ath/ath9k/debug.c
-+++ b/drivers/net/wireless/ath/ath9k/debug.c
-@@ -586,7 +586,6 @@ static ssize_t read_file_xmit(struct fil
- 
- 	PRQLE("axq_q empty:       ", axq_q);
- 	PRQLE("axq_acq empty:     ", axq_acq);
--	PRQLE("txq_fifo_pending:  ", txq_fifo_pending);
- 	for (i = 0; i < ATH_TXFIFO_DEPTH; i++) {
- 		snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
- 		PRQLE(tmp, txq_fifo[i]);

+ 0 - 70
package/mac80211/patches/581-ath9k_remove_get_desc_link.patch

@@ -1,70 +0,0 @@
---- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
-@@ -28,11 +28,6 @@ static void ar9002_hw_set_desc_link(void
- 	((struct ath_desc*) ds)->ds_link = ds_link;
- }
- 
--static void ar9002_hw_get_desc_link(void *ds, u32 **ds_link)
--{
--	*ds_link = &((struct ath_desc *)ds)->ds_link;
--}
--
- static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
- {
- 	u32 isr = 0;
-@@ -437,7 +432,6 @@ void ar9002_hw_attach_mac_ops(struct ath
- 
- 	ops->rx_enable = ar9002_hw_rx_enable;
- 	ops->set_desc_link = ar9002_hw_set_desc_link;
--	ops->get_desc_link = ar9002_hw_get_desc_link;
- 	ops->get_isr = ar9002_hw_get_isr;
- 	ops->fill_txdesc = ar9002_hw_fill_txdesc;
- 	ops->proc_txdesc = ar9002_hw_proc_txdesc;
---- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
-@@ -43,13 +43,6 @@ static void ar9003_hw_set_desc_link(void
- 	ads->ctl10 |= ar9003_calc_ptr_chksum(ads);
- }
- 
--static void ar9003_hw_get_desc_link(void *ds, u32 **ds_link)
--{
--	struct ar9003_txc *ads = ds;
--
--	*ds_link = &ads->link;
--}
--
- static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
- {
- 	u32 isr = 0;
-@@ -498,7 +491,6 @@ void ar9003_hw_attach_mac_ops(struct ath
- 
- 	ops->rx_enable = ar9003_hw_rx_enable;
- 	ops->set_desc_link = ar9003_hw_set_desc_link;
--	ops->get_desc_link = ar9003_hw_get_desc_link;
- 	ops->get_isr = ar9003_hw_get_isr;
- 	ops->fill_txdesc = ar9003_hw_fill_txdesc;
- 	ops->proc_txdesc = ar9003_hw_proc_txdesc;
---- a/drivers/net/wireless/ath/ath9k/hw-ops.h
-+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
-@@ -39,11 +39,6 @@ static inline void ath9k_hw_set_desc_lin
- 	ath9k_hw_ops(ah)->set_desc_link(ds, link);
- }
- 
--static inline void ath9k_hw_get_desc_link(struct ath_hw *ah, void *ds,
--					  u32 **link)
--{
--	ath9k_hw_ops(ah)->get_desc_link(ds, link);
--}
- static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
- 				      struct ath9k_channel *chan,
- 				      u8 rxchainmask,
---- a/drivers/net/wireless/ath/ath9k/hw.h
-+++ b/drivers/net/wireless/ath/ath9k/hw.h
-@@ -603,7 +603,6 @@ struct ath_hw_ops {
- 				     int power_off);
- 	void (*rx_enable)(struct ath_hw *ah);
- 	void (*set_desc_link)(void *ds, u32 link);
--	void (*get_desc_link)(void *ds, u32 **link);
- 	bool (*calibrate)(struct ath_hw *ah,
- 			  struct ath9k_channel *chan,
- 			  u8 rxchainmask,

+ 4 - 4
package/mac80211/patches/800-b43-gpio-mask-module-option.patch

@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/b43/b43.h
 +++ b/drivers/net/wireless/b43/b43.h
-@@ -718,6 +718,7 @@ struct b43_wldev {
+@@ -720,6 +720,7 @@ struct b43_wldev {
  	bool qos_enabled;		/* TRUE, if QoS is used. */
  	bool hwcrypto_enabled;		/* TRUE, if HW crypto acceleration is enabled. */
  	bool use_pio;			/* TRUE if next init should use PIO */
@@ -22,7 +22,7 @@
  static int modparam_bad_frames_preempt;
  module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
  MODULE_PARM_DESC(bad_frames_preempt,
-@@ -2543,10 +2548,10 @@ static int b43_gpio_init(struct b43_wlde
+@@ -2560,10 +2565,10 @@ static int b43_gpio_init(struct b43_wlde
  		    & ~B43_MACCTL_GPOUTSMSK);
  
  	b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK)
@@ -32,10 +32,10 @@
  	mask = 0x0000001F;
 -	set = 0x0000000F;
 +	set = modparam_gpiomask;
- 	if (dev->dev->bus->chip_id == 0x4301) {
+ 	if (dev->sdev->bus->chip_id == 0x4301) {
  		mask |= 0x0060;
  		set |= 0x0060;
-@@ -5078,10 +5083,10 @@ static void b43_print_driverinfo(void)
+@@ -5084,10 +5089,10 @@ static void b43_print_driverinfo(void)
  	feat_sdio = "S";
  #endif
  	printk(KERN_INFO "Broadcom 43xx driver loaded "

+ 1 - 1
package/mac80211/patches/810-b43_no_pio.patch

@@ -11,7 +11,7 @@
  b43-$(CONFIG_B43_PCMCIA)	+= pcmcia.o
 --- a/drivers/net/wireless/b43/main.c
 +++ b/drivers/net/wireless/b43/main.c
-@@ -1813,9 +1813,11 @@ static void b43_do_interrupt_thread(stru
+@@ -1819,9 +1819,11 @@ static void b43_do_interrupt_thread(stru
  			       dma_reason[4], dma_reason[5]);
  			b43err(dev->wl, "This device does not support DMA "
  			       "on your system. It will now be switched to PIO.\n");