From: Felix Fietkau Date: Tue, 31 May 2011 23:07:29 +0000 (+0000) Subject: mac80211: update to wireless-testing 2011-05-27 X-Git-Tag: reboot~16640 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=41a169115b56cee08ba5ac0c85275c91b3193830;p=openwrt%2Fstaging%2Fnoltari.git mac80211: update to wireless-testing 2011-05-27 SVN-Revision: 27071 --- diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile index d531ecd46e..492fc976f0 100644 --- a/package/mac80211/Makefile +++ b/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) diff --git a/package/mac80211/patches/002-disable_rfkill.patch b/package/mac80211/patches/002-disable_rfkill.patch index 6105af96f3..f6350a6ba4 100644 --- a/package/mac80211/patches/002-disable_rfkill.patch +++ b/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 diff --git a/package/mac80211/patches/005-disable_ssb_build.patch b/package/mac80211/patches/005-disable_ssb_build.patch index 401b20f0d9..3a92f36c7e 100644 --- a/package/mac80211/patches/005-disable_ssb_build.patch +++ b/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 diff --git a/package/mac80211/patches/007-remove_misc_drivers.patch b/package/mac80211/patches/007-remove_misc_drivers.patch index d2cb2dc467..46081e29ea 100644 --- a/package/mac80211/patches/007-remove_misc_drivers.patch +++ b/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 diff --git a/package/mac80211/patches/011-no_sdio.patch b/package/mac80211/patches/011-no_sdio.patch index 984039efe3..e61d25e7ee 100644 --- a/package/mac80211/patches/011-no_sdio.patch +++ b/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 diff --git a/package/mac80211/patches/015-remove-rt2x00-options.patch b/package/mac80211/patches/015-remove-rt2x00-options.patch index db9126d35c..4ba8b76b47 100644 --- a/package/mac80211/patches/015-remove-rt2x00-options.patch +++ b/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 diff --git a/package/mac80211/patches/110-disable_usb_compat.patch b/package/mac80211/patches/110-disable_usb_compat.patch index 86467ebdbc..70683155a1 100644 --- a/package/mac80211/patches/110-disable_usb_compat.patch +++ b/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. diff --git a/package/mac80211/patches/300-pending_work.patch b/package/mac80211/patches/300-pending_work.patch index 15e6bd0dca..782f7d7877 100644 --- a/package/mac80211/patches/300-pending_work.patch +++ b/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); diff --git a/package/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch b/package/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch index 6d872e9059..6982671300 100644 --- a/package/mac80211/patches/410-ath9k_allow_adhoc_and_ap.patch +++ b/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); diff --git a/package/mac80211/patches/500-ath9k_eeprom_debugfs.patch b/package/mac80211/patches/500-ath9k_eeprom_debugfs.patch index fa330d0e7f..4aa83c734a 100644 --- a/package/mac80211/patches/500-ath9k_eeprom_debugfs.patch +++ b/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); diff --git a/package/mac80211/patches/511-ath9k_increase_bcbuf.patch b/package/mac80211/patches/511-ath9k_increase_bcbuf.patch index 3052c410fb..951e31d7db 100644 --- a/package/mac80211/patches/511-ath9k_increase_bcbuf.patch +++ b/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 diff --git a/package/mac80211/patches/521-mac80211_ht_change_rate_update.patch b/package/mac80211/patches/521-mac80211_ht_change_rate_update.patch new file mode 100644 index 0000000000..d2f1982339 --- /dev/null +++ b/package/mac80211/patches/521-mac80211_ht_change_rate_update.patch @@ -0,0 +1,35 @@ +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -239,7 +239,9 @@ void ieee80211_bss_info_change_notify(st + u32 changed) + { + struct ieee80211_local *local = sdata->local; ++ struct ieee80211_supported_band *sband; + static const u8 zero[ETH_ALEN] = { 0 }; ++ struct sta_info *sta; + + if (!changed) + return; +@@ -269,6 +271,22 @@ void ieee80211_bss_info_change_notify(st + + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: ++ if (!(changed & BSS_CHANGED_HT)) ++ break; ++ ++ sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; ++ rcu_read_lock(); ++ list_for_each_entry(sta, &local->sta_list, list) { ++ if (sta->sdata != sdata && ++ (!sdata->bss || sta->sdata->bss != sdata->bss)) ++ continue; ++ ++ rate_control_rate_update(local, sband, sta, ++ IEEE80211_RC_HT_CHANGED, ++ local->_oper_channel_type); ++ } ++ rcu_read_unlock(); ++ break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: diff --git a/package/mac80211/patches/530-ath9k_noise_dbm_fixup.patch b/package/mac80211/patches/530-ath9k_noise_dbm_fixup.patch new file mode 100644 index 0000000000..8f72207316 --- /dev/null +++ b/package/mac80211/patches/530-ath9k_noise_dbm_fixup.patch @@ -0,0 +1,99 @@ +--- a/drivers/net/wireless/ath/ath9k/calib.c ++++ b/drivers/net/wireless/ath/ath9k/calib.c +@@ -63,6 +63,19 @@ static s16 ath9k_hw_get_default_nf(struc + return ath9k_hw_get_nf_limits(ah, chan)->nominal; + } + ++s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) ++{ ++ s8 noise = ATH_DEFAULT_NOISE_FLOOR; ++ ++ if (chan && chan->noisefloor) { ++ s8 delta = chan->noisefloor - ++ ath9k_hw_get_default_nf(ah, chan); ++ if (delta > 0) ++ noise += delta; ++ } ++ return noise; ++} ++EXPORT_SYMBOL(ath9k_hw_getchan_noise); + + static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, + struct ath9k_hw_cal_data *cal, +@@ -378,6 +391,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, s + + if (!caldata) { + chan->noisefloor = nf; ++ ah->noise = ath9k_hw_getchan_noise(ah, chan); + return false; + } + +@@ -385,6 +399,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, s + caldata->nfcal_pending = false; + ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray); + chan->noisefloor = h[0].privNF; ++ ah->noise = ath9k_hw_getchan_noise(ah, chan); + return true; + } + +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -1344,6 +1344,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st + memset(caldata, 0, sizeof(*caldata)); + ath9k_init_nfcal_hist_buffer(ah, chan); + } ++ ah->noise = ath9k_hw_getchan_noise(ah, chan); + + if (bChannelChange && + (ah->chip_fullsleep != true) && +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -687,6 +687,7 @@ struct ath_hw { + enum nl80211_iftype opmode; + enum ath9k_power_mode power_mode; + ++ s8 noise; + struct ath9k_hw_cal_data *caldata; + struct ath9k_pacal_info pacal_info; + struct ar5416Stats stats; +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -163,7 +163,7 @@ static void ath_update_survey_nf(struct + + if (chan->noisefloor) { + survey->filled |= SURVEY_INFO_NOISE_DBM; +- survey->noise = chan->noisefloor; ++ survey->noise = ath9k_hw_getchan_noise(ah, chan); + } + } + +--- a/drivers/net/wireless/ath/ath9k/recv.c ++++ b/drivers/net/wireless/ath/ath9k/recv.c +@@ -985,6 +985,8 @@ static int ath9k_rx_skb_preprocess(struc + struct ieee80211_rx_status *rx_status, + bool *decrypt_error) + { ++ struct ath_hw *ah = common->ah; ++ + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + + /* +@@ -1005,7 +1007,7 @@ static int ath9k_rx_skb_preprocess(struc + + rx_status->band = hw->conf.channel->band; + rx_status->freq = hw->conf.channel->center_freq; +- rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; ++ rx_status->signal = ah->noise + rx_stats->rs_rssi; + rx_status->antenna = rx_stats->rs_antenna; + rx_status->flag |= RX_FLAG_MACTIME_MPDU; + +--- a/drivers/net/wireless/ath/ath9k/calib.h ++++ b/drivers/net/wireless/ath/ath9k/calib.h +@@ -108,6 +108,7 @@ void ath9k_init_nfcal_hist_buffer(struct + void ath9k_hw_bstuck_nfcal(struct ath_hw *ah); + void ath9k_hw_reset_calibration(struct ath_hw *ah, + struct ath9k_cal_list *currCal); ++s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); + + + #endif /* CALIB_H */ diff --git a/package/mac80211/patches/530-mac80211_remove_wds_sta_flag.patch b/package/mac80211/patches/530-mac80211_remove_wds_sta_flag.patch deleted file mode 100644 index 29c2fd7dad..0000000000 --- a/package/mac80211/patches/530-mac80211_remove_wds_sta_flag.patch +++ /dev/null @@ -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); - } diff --git a/package/mac80211/patches/531-mac80211_fix_iftype_wds.patch b/package/mac80211/patches/531-mac80211_fix_iftype_wds.patch deleted file mode 100644 index 98a8993236..0000000000 --- a/package/mac80211/patches/531-mac80211_fix_iftype_wds.patch +++ /dev/null @@ -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; diff --git a/package/mac80211/patches/532-mac80211_enable_iftype_wds_aggregation.patch b/package/mac80211/patches/532-mac80211_enable_iftype_wds_aggregation.patch deleted file mode 100644 index f981be4aa8..0000000000 --- a/package/mac80211/patches/532-mac80211_enable_iftype_wds_aggregation.patch +++ /dev/null @@ -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 */ diff --git a/package/mac80211/patches/540-ath9k_debugfs_show_xretry.patch b/package/mac80211/patches/540-ath9k_debugfs_show_xretry.patch deleted file mode 100644 index ca6ef3b0f2..0000000000 --- a/package/mac80211/patches/540-ath9k_debugfs_show_xretry.patch +++ /dev/null @@ -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; diff --git a/package/mac80211/patches/550-mac80211_ht_change_rate_update.patch b/package/mac80211/patches/550-mac80211_ht_change_rate_update.patch deleted file mode 100644 index d2f1982339..0000000000 --- a/package/mac80211/patches/550-mac80211_ht_change_rate_update.patch +++ /dev/null @@ -1,35 +0,0 @@ ---- a/net/mac80211/main.c -+++ b/net/mac80211/main.c -@@ -239,7 +239,9 @@ void ieee80211_bss_info_change_notify(st - u32 changed) - { - struct ieee80211_local *local = sdata->local; -+ struct ieee80211_supported_band *sband; - static const u8 zero[ETH_ALEN] = { 0 }; -+ struct sta_info *sta; - - if (!changed) - return; -@@ -269,6 +271,22 @@ void ieee80211_bss_info_change_notify(st - - switch (sdata->vif.type) { - case NL80211_IFTYPE_AP: -+ if (!(changed & BSS_CHANGED_HT)) -+ break; -+ -+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; -+ rcu_read_lock(); -+ list_for_each_entry(sta, &local->sta_list, list) { -+ if (sta->sdata != sdata && -+ (!sdata->bss || sta->sdata->bss != sdata->bss)) -+ continue; -+ -+ rate_control_rate_update(local, sband, sta, -+ IEEE80211_RC_HT_CHANGED, -+ local->_oper_channel_type); -+ } -+ rcu_read_unlock(); -+ break; - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_WDS: - case NL80211_IFTYPE_MESH_POINT: diff --git a/package/mac80211/patches/560-ath9k_noise_dbm_fixup.patch b/package/mac80211/patches/560-ath9k_noise_dbm_fixup.patch deleted file mode 100644 index 486e5d11ce..0000000000 --- a/package/mac80211/patches/560-ath9k_noise_dbm_fixup.patch +++ /dev/null @@ -1,99 +0,0 @@ ---- a/drivers/net/wireless/ath/ath9k/calib.c -+++ b/drivers/net/wireless/ath/ath9k/calib.c -@@ -63,6 +63,19 @@ static s16 ath9k_hw_get_default_nf(struc - return ath9k_hw_get_nf_limits(ah, chan)->nominal; - } - -+s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) -+{ -+ s8 noise = ATH_DEFAULT_NOISE_FLOOR; -+ -+ if (chan && chan->noisefloor) { -+ s8 delta = chan->noisefloor - -+ ath9k_hw_get_default_nf(ah, chan); -+ if (delta > 0) -+ noise += delta; -+ } -+ return noise; -+} -+EXPORT_SYMBOL(ath9k_hw_getchan_noise); - - static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, - struct ath9k_hw_cal_data *cal, -@@ -378,6 +391,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, s - - if (!caldata) { - chan->noisefloor = nf; -+ ah->noise = ath9k_hw_getchan_noise(ah, chan); - return false; - } - -@@ -385,6 +399,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, s - caldata->nfcal_pending = false; - ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray); - chan->noisefloor = h[0].privNF; -+ ah->noise = ath9k_hw_getchan_noise(ah, chan); - return true; - } - ---- a/drivers/net/wireless/ath/ath9k/hw.c -+++ b/drivers/net/wireless/ath/ath9k/hw.c -@@ -1344,6 +1344,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st - memset(caldata, 0, sizeof(*caldata)); - ath9k_init_nfcal_hist_buffer(ah, chan); - } -+ ah->noise = ath9k_hw_getchan_noise(ah, chan); - - if (bChannelChange && - (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 { - enum nl80211_iftype opmode; - enum ath9k_power_mode power_mode; - -+ s8 noise; - struct ath9k_hw_cal_data *caldata; - struct ath9k_pacal_info pacal_info; - 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 - - if (chan->noisefloor) { - survey->filled |= SURVEY_INFO_NOISE_DBM; -- survey->noise = chan->noisefloor; -+ survey->noise = ath9k_hw_getchan_noise(ah, chan); - } - } - ---- a/drivers/net/wireless/ath/ath9k/recv.c -+++ b/drivers/net/wireless/ath/ath9k/recv.c -@@ -985,6 +985,8 @@ static int ath9k_rx_skb_preprocess(struc - struct ieee80211_rx_status *rx_status, - bool *decrypt_error) - { -+ struct ath_hw *ah = common->ah; -+ - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - - /* -@@ -1005,7 +1007,7 @@ static int ath9k_rx_skb_preprocess(struc - - rx_status->band = hw->conf.channel->band; - rx_status->freq = hw->conf.channel->center_freq; -- rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; -+ rx_status->signal = ah->noise + rx_stats->rs_rssi; - rx_status->antenna = rx_stats->rs_antenna; - rx_status->flag |= RX_FLAG_MACTIME_MPDU; - ---- a/drivers/net/wireless/ath/ath9k/calib.h -+++ b/drivers/net/wireless/ath/ath9k/calib.h -@@ -108,6 +108,7 @@ void ath9k_init_nfcal_hist_buffer(struct - void ath9k_hw_bstuck_nfcal(struct ath_hw *ah); - void ath9k_hw_reset_calibration(struct ath_hw *ah, - struct ath9k_cal_list *currCal); -+s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); - - - #endif /* CALIB_H */ diff --git a/package/mac80211/patches/570-ath9k_fix_adhoc_beacons.patch b/package/mac80211/patches/570-ath9k_fix_adhoc_beacons.patch deleted file mode 100644 index d3eb764090..0000000000 --- a/package/mac80211/patches/570-ath9k_fix_adhoc_beacons.patch +++ /dev/null @@ -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) { diff --git a/package/mac80211/patches/571-ath9k_fix_adhoc_nexttbtt.patch b/package/mac80211/patches/571-ath9k_fix_adhoc_nexttbtt.patch deleted file mode 100644 index 544c7a9c9f..0000000000 --- a/package/mac80211/patches/571-ath9k_fix_adhoc_nexttbtt.patch +++ /dev/null @@ -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, diff --git a/package/mac80211/patches/572-ath9k_tx_last_beacon.patch b/package/mac80211/patches/572-ath9k_tx_last_beacon.patch deleted file mode 100644 index 8b2950d654..0000000000 --- a/package/mac80211/patches/572-ath9k_tx_last_beacon.patch +++ /dev/null @@ -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, - }; diff --git a/package/mac80211/patches/580-ath9k_tx_fifo_cleanup.patch b/package/mac80211/patches/580-ath9k_tx_fifo_cleanup.patch deleted file mode 100644 index b334bf1190..0000000000 --- a/package/mac80211/patches/580-ath9k_tx_fifo_cleanup.patch +++ /dev/null @@ -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]); diff --git a/package/mac80211/patches/581-ath9k_remove_get_desc_link.patch b/package/mac80211/patches/581-ath9k_remove_get_desc_link.patch deleted file mode 100644 index 5072842922..0000000000 --- a/package/mac80211/patches/581-ath9k_remove_get_desc_link.patch +++ /dev/null @@ -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, diff --git a/package/mac80211/patches/800-b43-gpio-mask-module-option.patch b/package/mac80211/patches/800-b43-gpio-mask-module-option.patch index dcbf6682fc..27a1ac104e 100644 --- a/package/mac80211/patches/800-b43-gpio-mask-module-option.patch +++ b/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 " diff --git a/package/mac80211/patches/810-b43_no_pio.patch b/package/mac80211/patches/810-b43_no_pio.patch index 5a48658cb5..5e55f771e5 100644 --- a/package/mac80211/patches/810-b43_no_pio.patch +++ b/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");