diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-03-15 14:16:48 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-03-15 14:16:48 -0400 |
commit | 106af2c99a5249b809aaed45b8353ac087821f4a (patch) | |
tree | b9d13cc35cfdc3b763408287b4e50daf32fda53b | |
parent | 0c0217b016ba8a970a6f6ab62ad0d858f39881ca (diff) | |
parent | 7d2c16befae67b901e6750b845661c1fdffd19f1 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
31 files changed, 596 insertions, 244 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index e6ff62e60a7..4d7f21ee111 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -943,6 +943,7 @@ ath5k_txq_setup(struct ath5k_softc *sc, | |||
943 | spin_lock_init(&txq->lock); | 943 | spin_lock_init(&txq->lock); |
944 | txq->setup = true; | 944 | txq->setup = true; |
945 | txq->txq_len = 0; | 945 | txq->txq_len = 0; |
946 | txq->txq_max = ATH5K_TXQ_LEN_MAX; | ||
946 | txq->txq_poll_mark = false; | 947 | txq->txq_poll_mark = false; |
947 | txq->txq_stuck = 0; | 948 | txq->txq_stuck = 0; |
948 | } | 949 | } |
@@ -1534,7 +1535,7 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1534 | goto drop_packet; | 1535 | goto drop_packet; |
1535 | } | 1536 | } |
1536 | 1537 | ||
1537 | if (txq->txq_len >= ATH5K_TXQ_LEN_MAX) | 1538 | if (txq->txq_len >= txq->txq_max) |
1538 | ieee80211_stop_queue(hw, txq->qnum); | 1539 | ieee80211_stop_queue(hw, txq->qnum); |
1539 | 1540 | ||
1540 | spin_lock_irqsave(&sc->txbuflock, flags); | 1541 | spin_lock_irqsave(&sc->txbuflock, flags); |
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 8d1df1fa235..978f1f4ac2f 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h | |||
@@ -86,6 +86,7 @@ struct ath5k_txq { | |||
86 | spinlock_t lock; /* lock on q and link */ | 86 | spinlock_t lock; /* lock on q and link */ |
87 | bool setup; | 87 | bool setup; |
88 | int txq_len; /* number of queued buffers */ | 88 | int txq_len; /* number of queued buffers */ |
89 | int txq_max; /* max allowed num of queued buffers */ | ||
89 | bool txq_poll_mark; | 90 | bool txq_poll_mark; |
90 | unsigned int txq_stuck; /* informational counter */ | 91 | unsigned int txq_stuck; /* informational counter */ |
91 | }; | 92 | }; |
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index c9b0b676add..9be29b728b1 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | |||
@@ -740,6 +740,47 @@ ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) | |||
740 | } | 740 | } |
741 | 741 | ||
742 | 742 | ||
743 | static void ath5k_get_ringparam(struct ieee80211_hw *hw, | ||
744 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) | ||
745 | { | ||
746 | struct ath5k_softc *sc = hw->priv; | ||
747 | |||
748 | *tx = sc->txqs[AR5K_TX_QUEUE_ID_DATA_MIN].txq_max; | ||
749 | |||
750 | *tx_max = ATH5K_TXQ_LEN_MAX; | ||
751 | *rx = *rx_max = ATH_RXBUF; | ||
752 | } | ||
753 | |||
754 | |||
755 | static int ath5k_set_ringparam(struct ieee80211_hw *hw, u32 tx, u32 rx) | ||
756 | { | ||
757 | struct ath5k_softc *sc = hw->priv; | ||
758 | u16 qnum; | ||
759 | |||
760 | /* only support setting tx ring size for now */ | ||
761 | if (rx != ATH_RXBUF) | ||
762 | return -EINVAL; | ||
763 | |||
764 | /* restrict tx ring size min/max */ | ||
765 | if (!tx || tx > ATH5K_TXQ_LEN_MAX) | ||
766 | return -EINVAL; | ||
767 | |||
768 | for (qnum = 0; qnum < ARRAY_SIZE(sc->txqs); qnum++) { | ||
769 | if (!sc->txqs[qnum].setup) | ||
770 | continue; | ||
771 | if (sc->txqs[qnum].qnum < AR5K_TX_QUEUE_ID_DATA_MIN || | ||
772 | sc->txqs[qnum].qnum > AR5K_TX_QUEUE_ID_DATA_MAX) | ||
773 | continue; | ||
774 | |||
775 | sc->txqs[qnum].txq_max = tx; | ||
776 | if (sc->txqs[qnum].txq_len >= sc->txqs[qnum].txq_max) | ||
777 | ieee80211_stop_queue(hw, sc->txqs[qnum].qnum); | ||
778 | } | ||
779 | |||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | |||
743 | const struct ieee80211_ops ath5k_hw_ops = { | 784 | const struct ieee80211_ops ath5k_hw_ops = { |
744 | .tx = ath5k_tx, | 785 | .tx = ath5k_tx, |
745 | .start = ath5k_start, | 786 | .start = ath5k_start, |
@@ -778,4 +819,6 @@ const struct ieee80211_ops ath5k_hw_ops = { | |||
778 | /* .napi_poll = not implemented */ | 819 | /* .napi_poll = not implemented */ |
779 | .set_antenna = ath5k_set_antenna, | 820 | .set_antenna = ath5k_set_antenna, |
780 | .get_antenna = ath5k_get_antenna, | 821 | .get_antenna = ath5k_get_antenna, |
822 | .set_ringparam = ath5k_set_ringparam, | ||
823 | .get_ringparam = ath5k_get_ringparam, | ||
781 | }; | 824 | }; |
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index eac4d8526fc..71cc0a3a29f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h | |||
@@ -667,6 +667,7 @@ static const u32 ar9485_1_0_pcie_phy_clkreq_enable_L1[][2] = { | |||
667 | 667 | ||
668 | static const u32 ar9485_1_0_soc_preamble[][2] = { | 668 | static const u32 ar9485_1_0_soc_preamble[][2] = { |
669 | /* Addr allmodes */ | 669 | /* Addr allmodes */ |
670 | {0x00004090, 0x00aa10aa}, | ||
670 | {0x000040a4, 0x00a0c9c9}, | 671 | {0x000040a4, 0x00a0c9c9}, |
671 | {0x00007048, 0x00000004}, | 672 | {0x00007048, 0x00000004}, |
672 | }; | 673 | }; |
@@ -1708,6 +1709,7 @@ static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = { | |||
1708 | static const u32 ar9485_1_1_soc_preamble[][2] = { | 1709 | static const u32 ar9485_1_1_soc_preamble[][2] = { |
1709 | /* Addr allmodes */ | 1710 | /* Addr allmodes */ |
1710 | {0x00004014, 0xba280400}, | 1711 | {0x00004014, 0xba280400}, |
1712 | {0x00004090, 0x00aa10aa}, | ||
1711 | {0x000040a4, 0x00a0c9c9}, | 1713 | {0x000040a4, 0x00a0c9c9}, |
1712 | {0x00007010, 0x00000022}, | 1714 | {0x00007010, 0x00000022}, |
1713 | {0x00007020, 0x00000000}, | 1715 | {0x00007020, 0x00000000}, |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index c718ab512a9..099bd4183ad 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -189,7 +189,6 @@ struct ath_txq { | |||
189 | u32 axq_ampdu_depth; | 189 | u32 axq_ampdu_depth; |
190 | bool stopped; | 190 | bool stopped; |
191 | bool axq_tx_inprogress; | 191 | bool axq_tx_inprogress; |
192 | bool txq_flush_inprogress; | ||
193 | struct list_head axq_acq; | 192 | struct list_head axq_acq; |
194 | struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; | 193 | struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; |
195 | struct list_head txq_fifo_pending; | 194 | struct list_head txq_fifo_pending; |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index a4bdfdb043e..6d2a545fc35 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -373,6 +373,7 @@ void ath_beacon_tasklet(unsigned long data) | |||
373 | ath_dbg(common, ATH_DBG_BSTUCK, | 373 | ath_dbg(common, ATH_DBG_BSTUCK, |
374 | "missed %u consecutive beacons\n", | 374 | "missed %u consecutive beacons\n", |
375 | sc->beacon.bmisscnt); | 375 | sc->beacon.bmisscnt); |
376 | ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); | ||
376 | ath9k_hw_bstuck_nfcal(ah); | 377 | ath9k_hw_bstuck_nfcal(ah); |
377 | } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { | 378 | } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { |
378 | ath_dbg(common, ATH_DBG_BSTUCK, | 379 | ath_dbg(common, ATH_DBG_BSTUCK, |
@@ -450,16 +451,6 @@ void ath_beacon_tasklet(unsigned long data) | |||
450 | sc->beacon.updateslot = OK; | 451 | sc->beacon.updateslot = OK; |
451 | } | 452 | } |
452 | if (bfaddr != 0) { | 453 | if (bfaddr != 0) { |
453 | /* | ||
454 | * Stop any current dma and put the new frame(s) on the queue. | ||
455 | * This should never fail since we check above that no frames | ||
456 | * are still pending on the queue. | ||
457 | */ | ||
458 | if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { | ||
459 | ath_err(common, "beacon queue %u did not stop?\n", | ||
460 | sc->beacon.beaconq); | ||
461 | } | ||
462 | |||
463 | /* NB: cabq traffic should already be queued and primed */ | 454 | /* NB: cabq traffic should already be queued and primed */ |
464 | ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); | 455 | ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); |
465 | ath9k_hw_txstart(ah, sc->beacon.beaconq); | 456 | ath9k_hw_txstart(ah, sc->beacon.beaconq); |
@@ -780,7 +771,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) | |||
780 | ah->imask &= ~ATH9K_INT_SWBA; | 771 | ah->imask &= ~ATH9K_INT_SWBA; |
781 | ath9k_hw_set_interrupts(ah, ah->imask); | 772 | ath9k_hw_set_interrupts(ah, ah->imask); |
782 | tasklet_kill(&sc->bcon_tasklet); | 773 | tasklet_kill(&sc->bcon_tasklet); |
783 | ath9k_hw_stoptxdma(ah, sc->beacon.beaconq); | 774 | ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); |
784 | } | 775 | } |
785 | ath9k_ps_restore(sc); | 776 | ath9k_ps_restore(sc); |
786 | } | 777 | } |
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index b4a92a4313f..8649581fa4d 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c | |||
@@ -262,7 +262,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) | |||
262 | * since 250us often results in NF load timeout and causes deaf | 262 | * since 250us often results in NF load timeout and causes deaf |
263 | * condition during stress testing 12/12/2009 | 263 | * condition during stress testing 12/12/2009 |
264 | */ | 264 | */ |
265 | for (j = 0; j < 1000; j++) { | 265 | for (j = 0; j < 10000; j++) { |
266 | if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & | 266 | if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & |
267 | AR_PHY_AGC_CONTROL_NF) == 0) | 267 | AR_PHY_AGC_CONTROL_NF) == 0) |
268 | break; | 268 | break; |
@@ -278,7 +278,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) | |||
278 | * here, the baseband nf cal will just be capped by our present | 278 | * here, the baseband nf cal will just be capped by our present |
279 | * noisefloor until the next calibration timer. | 279 | * noisefloor until the next calibration timer. |
280 | */ | 280 | */ |
281 | if (j == 1000) { | 281 | if (j == 10000) { |
282 | ath_dbg(common, ATH_DBG_ANY, | 282 | ath_dbg(common, ATH_DBG_ANY, |
283 | "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", | 283 | "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", |
284 | REG_READ(ah, AR_PHY_AGC_CONTROL)); | 284 | REG_READ(ah, AR_PHY_AGC_CONTROL)); |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9a3438174f8..338b07502f1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -701,7 +701,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, | |||
701 | AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); | 701 | AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); |
702 | 702 | ||
703 | REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); | 703 | REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); |
704 | udelay(100); | 704 | udelay(1000); |
705 | 705 | ||
706 | REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); | 706 | REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); |
707 | 707 | ||
@@ -713,7 +713,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, | |||
713 | REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, | 713 | REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, |
714 | AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); | 714 | AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); |
715 | REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); | 715 | REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); |
716 | udelay(110); | 716 | udelay(1000); |
717 | } | 717 | } |
718 | 718 | ||
719 | pll = ath9k_hw_compute_pll_control(ah, chan); | 719 | pll = ath9k_hw_compute_pll_control(ah, chan); |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ef79f4c876c..6650fd48415 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -95,9 +95,9 @@ | |||
95 | #define REG_READ_FIELD(_a, _r, _f) \ | 95 | #define REG_READ_FIELD(_a, _r, _f) \ |
96 | (((REG_READ(_a, _r) & _f) >> _f##_S)) | 96 | (((REG_READ(_a, _r) & _f) >> _f##_S)) |
97 | #define REG_SET_BIT(_a, _r, _f) \ | 97 | #define REG_SET_BIT(_a, _r, _f) \ |
98 | REG_WRITE(_a, _r, REG_READ(_a, _r) | _f) | 98 | REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f)) |
99 | #define REG_CLR_BIT(_a, _r, _f) \ | 99 | #define REG_CLR_BIT(_a, _r, _f) \ |
100 | REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f) | 100 | REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f)) |
101 | 101 | ||
102 | #define DO_DELAY(x) do { \ | 102 | #define DO_DELAY(x) do { \ |
103 | if ((++(x) % 64) == 0) \ | 103 | if ((++(x) % 64) == 0) \ |
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 5efc869d65f..562257ac52c 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
@@ -143,84 +143,59 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) | |||
143 | } | 143 | } |
144 | EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel); | 144 | EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel); |
145 | 145 | ||
146 | bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) | 146 | void ath9k_hw_abort_tx_dma(struct ath_hw *ah) |
147 | { | 147 | { |
148 | #define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */ | 148 | int i, q; |
149 | #define ATH9K_TIME_QUANTUM 100 /* usec */ | ||
150 | struct ath_common *common = ath9k_hw_common(ah); | ||
151 | struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
152 | struct ath9k_tx_queue_info *qi; | ||
153 | u32 tsfLow, j, wait; | ||
154 | u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM; | ||
155 | 149 | ||
156 | if (q >= pCap->total_queues) { | 150 | REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M); |
157 | ath_dbg(common, ATH_DBG_QUEUE, | ||
158 | "Stopping TX DMA, invalid queue: %u\n", q); | ||
159 | return false; | ||
160 | } | ||
161 | 151 | ||
162 | qi = &ah->txq[q]; | 152 | REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF); |
163 | if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { | 153 | REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); |
164 | ath_dbg(common, ATH_DBG_QUEUE, | 154 | REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF); |
165 | "Stopping TX DMA, inactive queue: %u\n", q); | ||
166 | return false; | ||
167 | } | ||
168 | 155 | ||
169 | REG_WRITE(ah, AR_Q_TXD, 1 << q); | 156 | for (q = 0; q < AR_NUM_QCU; q++) { |
157 | for (i = 0; i < 1000; i++) { | ||
158 | if (i) | ||
159 | udelay(5); | ||
170 | 160 | ||
171 | for (wait = wait_time; wait != 0; wait--) { | 161 | if (!ath9k_hw_numtxpending(ah, q)) |
172 | if (ath9k_hw_numtxpending(ah, q) == 0) | 162 | break; |
173 | break; | 163 | } |
174 | udelay(ATH9K_TIME_QUANTUM); | ||
175 | } | 164 | } |
176 | 165 | ||
177 | if (ath9k_hw_numtxpending(ah, q)) { | 166 | REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF); |
178 | ath_dbg(common, ATH_DBG_QUEUE, | 167 | REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); |
179 | "%s: Num of pending TX Frames %d on Q %d\n", | 168 | REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF); |
180 | __func__, ath9k_hw_numtxpending(ah, q), q); | ||
181 | |||
182 | for (j = 0; j < 2; j++) { | ||
183 | tsfLow = REG_READ(ah, AR_TSF_L32); | ||
184 | REG_WRITE(ah, AR_QUIET2, | ||
185 | SM(10, AR_QUIET2_QUIET_DUR)); | ||
186 | REG_WRITE(ah, AR_QUIET_PERIOD, 100); | ||
187 | REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10); | ||
188 | REG_SET_BIT(ah, AR_TIMER_MODE, | ||
189 | AR_QUIET_TIMER_EN); | ||
190 | |||
191 | if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10)) | ||
192 | break; | ||
193 | 169 | ||
194 | ath_dbg(common, ATH_DBG_QUEUE, | 170 | REG_WRITE(ah, AR_Q_TXD, 0); |
195 | "TSF has moved while trying to set quiet time TSF: 0x%08x\n", | 171 | } |
196 | tsfLow); | 172 | EXPORT_SYMBOL(ath9k_hw_abort_tx_dma); |
197 | } | ||
198 | 173 | ||
199 | REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); | 174 | bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q) |
175 | { | ||
176 | #define ATH9K_TX_STOP_DMA_TIMEOUT 1000 /* usec */ | ||
177 | #define ATH9K_TIME_QUANTUM 100 /* usec */ | ||
178 | int wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM; | ||
179 | int wait; | ||
200 | 180 | ||
201 | udelay(200); | 181 | REG_WRITE(ah, AR_Q_TXD, 1 << q); |
202 | REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); | ||
203 | 182 | ||
204 | wait = wait_time; | 183 | for (wait = wait_time; wait != 0; wait--) { |
205 | while (ath9k_hw_numtxpending(ah, q)) { | 184 | if (wait != wait_time) |
206 | if ((--wait) == 0) { | ||
207 | ath_err(common, | ||
208 | "Failed to stop TX DMA in 100 msec after killing last frame\n"); | ||
209 | break; | ||
210 | } | ||
211 | udelay(ATH9K_TIME_QUANTUM); | 185 | udelay(ATH9K_TIME_QUANTUM); |
212 | } | ||
213 | 186 | ||
214 | REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); | 187 | if (ath9k_hw_numtxpending(ah, q) == 0) |
188 | break; | ||
215 | } | 189 | } |
216 | 190 | ||
217 | REG_WRITE(ah, AR_Q_TXD, 0); | 191 | REG_WRITE(ah, AR_Q_TXD, 0); |
192 | |||
218 | return wait != 0; | 193 | return wait != 0; |
219 | 194 | ||
220 | #undef ATH9K_TX_STOP_DMA_TIMEOUT | 195 | #undef ATH9K_TX_STOP_DMA_TIMEOUT |
221 | #undef ATH9K_TIME_QUANTUM | 196 | #undef ATH9K_TIME_QUANTUM |
222 | } | 197 | } |
223 | EXPORT_SYMBOL(ath9k_hw_stoptxdma); | 198 | EXPORT_SYMBOL(ath9k_hw_stop_dma_queue); |
224 | 199 | ||
225 | void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) | 200 | void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs) |
226 | { | 201 | { |
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 04d58ae923b..b2b2ff852c3 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h | |||
@@ -676,7 +676,8 @@ void ath9k_hw_txstart(struct ath_hw *ah, u32 q); | |||
676 | void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds); | 676 | void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds); |
677 | u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); | 677 | u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); |
678 | bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); | 678 | bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); |
679 | bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); | 679 | bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q); |
680 | void ath9k_hw_abort_tx_dma(struct ath_hw *ah); | ||
680 | void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs); | 681 | void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs); |
681 | bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, | 682 | bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, |
682 | const struct ath9k_tx_queue_info *qinfo); | 683 | const struct ath9k_tx_queue_info *qinfo); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 2e228aada1a..115f162c617 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -2128,56 +2128,42 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) | |||
2128 | 2128 | ||
2129 | static void ath9k_flush(struct ieee80211_hw *hw, bool drop) | 2129 | static void ath9k_flush(struct ieee80211_hw *hw, bool drop) |
2130 | { | 2130 | { |
2131 | #define ATH_FLUSH_TIMEOUT 60 /* ms */ | ||
2132 | struct ath_softc *sc = hw->priv; | 2131 | struct ath_softc *sc = hw->priv; |
2133 | struct ath_txq *txq = NULL; | 2132 | int timeout = 200; /* ms */ |
2134 | struct ath_hw *ah = sc->sc_ah; | 2133 | int i, j; |
2135 | struct ath_common *common = ath9k_hw_common(ah); | ||
2136 | int i, j, npend = 0; | ||
2137 | 2134 | ||
2135 | ath9k_ps_wakeup(sc); | ||
2138 | mutex_lock(&sc->mutex); | 2136 | mutex_lock(&sc->mutex); |
2139 | 2137 | ||
2140 | cancel_delayed_work_sync(&sc->tx_complete_work); | 2138 | cancel_delayed_work_sync(&sc->tx_complete_work); |
2141 | 2139 | ||
2142 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { | 2140 | if (drop) |
2143 | if (!ATH_TXQ_SETUP(sc, i)) | 2141 | timeout = 1; |
2144 | continue; | ||
2145 | txq = &sc->tx.txq[i]; | ||
2146 | 2142 | ||
2147 | if (!drop) { | 2143 | for (j = 0; j < timeout; j++) { |
2148 | for (j = 0; j < ATH_FLUSH_TIMEOUT; j++) { | 2144 | int npend = 0; |
2149 | if (!ath9k_has_pending_frames(sc, txq)) | 2145 | |
2150 | break; | 2146 | if (j) |
2151 | usleep_range(1000, 2000); | 2147 | usleep_range(1000, 2000); |
2152 | } | ||
2153 | } | ||
2154 | 2148 | ||
2155 | if (drop || ath9k_has_pending_frames(sc, txq)) { | 2149 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { |
2156 | ath_dbg(common, ATH_DBG_QUEUE, "Drop frames from hw queue:%d\n", | 2150 | if (!ATH_TXQ_SETUP(sc, i)) |
2157 | txq->axq_qnum); | 2151 | continue; |
2158 | spin_lock_bh(&txq->axq_lock); | 2152 | |
2159 | txq->txq_flush_inprogress = true; | 2153 | npend += ath9k_has_pending_frames(sc, &sc->tx.txq[i]); |
2160 | spin_unlock_bh(&txq->axq_lock); | ||
2161 | |||
2162 | ath9k_ps_wakeup(sc); | ||
2163 | ath9k_hw_stoptxdma(ah, txq->axq_qnum); | ||
2164 | npend = ath9k_hw_numtxpending(ah, txq->axq_qnum); | ||
2165 | ath9k_ps_restore(sc); | ||
2166 | if (npend) | ||
2167 | break; | ||
2168 | |||
2169 | ath_draintxq(sc, txq, false); | ||
2170 | txq->txq_flush_inprogress = false; | ||
2171 | } | 2154 | } |
2155 | |||
2156 | if (!npend) | ||
2157 | goto out; | ||
2172 | } | 2158 | } |
2173 | 2159 | ||
2174 | if (npend) { | 2160 | if (!ath_drain_all_txq(sc, false)) |
2175 | ath_reset(sc, false); | 2161 | ath_reset(sc, false); |
2176 | txq->txq_flush_inprogress = false; | ||
2177 | } | ||
2178 | 2162 | ||
2163 | out: | ||
2179 | ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); | 2164 | ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); |
2180 | mutex_unlock(&sc->mutex); | 2165 | mutex_unlock(&sc->mutex); |
2166 | ath9k_ps_restore(sc); | ||
2181 | } | 2167 | } |
2182 | 2168 | ||
2183 | struct ieee80211_ops ath9k_ops = { | 2169 | struct ieee80211_ops ath9k_ops = { |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index cb559e345b8..a9c3f4672aa 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -413,9 +413,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | |||
413 | * mode interface or when in monitor mode. AP mode does not need this | 413 | * mode interface or when in monitor mode. AP mode does not need this |
414 | * since it receives all in-BSS frames anyway. | 414 | * since it receives all in-BSS frames anyway. |
415 | */ | 415 | */ |
416 | if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) && | 416 | if (sc->sc_ah->is_monitoring) |
417 | (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) || | ||
418 | (sc->sc_ah->is_monitoring)) | ||
419 | rfilt |= ATH9K_RX_FILTER_PROM; | 417 | rfilt |= ATH9K_RX_FILTER_PROM; |
420 | 418 | ||
421 | if (sc->rx.rxfilter & FIF_CONTROL) | 419 | if (sc->rx.rxfilter & FIF_CONTROL) |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index e16136d6179..ef22096d40c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -166,7 +166,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) | |||
166 | fi = get_frame_info(bf->bf_mpdu); | 166 | fi = get_frame_info(bf->bf_mpdu); |
167 | if (fi->retries) { | 167 | if (fi->retries) { |
168 | ath_tx_update_baw(sc, tid, fi->seqno); | 168 | ath_tx_update_baw(sc, tid, fi->seqno); |
169 | ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); | 169 | ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 1); |
170 | } else { | 170 | } else { |
171 | ath_tx_send_normal(sc, txq, NULL, &bf_head); | 171 | ath_tx_send_normal(sc, txq, NULL, &bf_head); |
172 | } | 172 | } |
@@ -1194,16 +1194,14 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) | |||
1194 | if (sc->sc_flags & SC_OP_INVALID) | 1194 | if (sc->sc_flags & SC_OP_INVALID) |
1195 | return true; | 1195 | return true; |
1196 | 1196 | ||
1197 | /* Stop beacon queue */ | 1197 | ath9k_hw_abort_tx_dma(ah); |
1198 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | ||
1199 | 1198 | ||
1200 | /* Stop data queues */ | 1199 | /* Check if any queue remains active */ |
1201 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { | 1200 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { |
1202 | if (ATH_TXQ_SETUP(sc, i)) { | 1201 | if (!ATH_TXQ_SETUP(sc, i)) |
1203 | txq = &sc->tx.txq[i]; | 1202 | continue; |
1204 | ath9k_hw_stoptxdma(ah, txq->axq_qnum); | 1203 | |
1205 | npend += ath9k_hw_numtxpending(ah, txq->axq_qnum); | 1204 | npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum); |
1206 | } | ||
1207 | } | 1205 | } |
1208 | 1206 | ||
1209 | if (npend) | 1207 | if (npend) |
@@ -2014,8 +2012,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2014 | spin_lock_bh(&txq->axq_lock); | 2012 | spin_lock_bh(&txq->axq_lock); |
2015 | if (list_empty(&txq->axq_q)) { | 2013 | if (list_empty(&txq->axq_q)) { |
2016 | txq->axq_link = NULL; | 2014 | txq->axq_link = NULL; |
2017 | if (sc->sc_flags & SC_OP_TXAGGR && | 2015 | if (sc->sc_flags & SC_OP_TXAGGR) |
2018 | !txq->txq_flush_inprogress) | ||
2019 | ath_txq_schedule(sc, txq); | 2016 | ath_txq_schedule(sc, txq); |
2020 | spin_unlock_bh(&txq->axq_lock); | 2017 | spin_unlock_bh(&txq->axq_lock); |
2021 | break; | 2018 | break; |
@@ -2096,7 +2093,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2096 | 2093 | ||
2097 | spin_lock_bh(&txq->axq_lock); | 2094 | spin_lock_bh(&txq->axq_lock); |
2098 | 2095 | ||
2099 | if (sc->sc_flags & SC_OP_TXAGGR && !txq->txq_flush_inprogress) | 2096 | if (sc->sc_flags & SC_OP_TXAGGR) |
2100 | ath_txq_schedule(sc, txq); | 2097 | ath_txq_schedule(sc, txq); |
2101 | spin_unlock_bh(&txq->axq_lock); | 2098 | spin_unlock_bh(&txq->axq_lock); |
2102 | } | 2099 | } |
@@ -2267,18 +2264,17 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) | |||
2267 | 2264 | ||
2268 | spin_lock_bh(&txq->axq_lock); | 2265 | spin_lock_bh(&txq->axq_lock); |
2269 | 2266 | ||
2270 | if (!txq->txq_flush_inprogress) { | 2267 | if (!list_empty(&txq->txq_fifo_pending)) { |
2271 | if (!list_empty(&txq->txq_fifo_pending)) { | 2268 | INIT_LIST_HEAD(&bf_head); |
2272 | INIT_LIST_HEAD(&bf_head); | 2269 | bf = list_first_entry(&txq->txq_fifo_pending, |
2273 | bf = list_first_entry(&txq->txq_fifo_pending, | 2270 | struct ath_buf, list); |
2274 | struct ath_buf, list); | 2271 | list_cut_position(&bf_head, |
2275 | list_cut_position(&bf_head, | 2272 | &txq->txq_fifo_pending, |
2276 | &txq->txq_fifo_pending, | 2273 | &bf->bf_lastbf->list); |
2277 | &bf->bf_lastbf->list); | 2274 | ath_tx_txqaddbuf(sc, txq, &bf_head); |
2278 | ath_tx_txqaddbuf(sc, txq, &bf_head); | 2275 | } else if (sc->sc_flags & SC_OP_TXAGGR) |
2279 | } else if (sc->sc_flags & SC_OP_TXAGGR) | 2276 | ath_txq_schedule(sc, txq); |
2280 | ath_txq_schedule(sc, txq); | 2277 | |
2281 | } | ||
2282 | spin_unlock_bh(&txq->axq_lock); | 2278 | spin_unlock_bh(&txq->axq_lock); |
2283 | } | 2279 | } |
2284 | } | 2280 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 25fccf9a300..2003c1d4295 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -1115,6 +1115,18 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, | |||
1115 | return added; | 1115 | return added; |
1116 | } | 1116 | } |
1117 | 1117 | ||
1118 | static int iwl_fill_offch_tx(struct iwl_priv *priv, void *data, size_t maxlen) | ||
1119 | { | ||
1120 | struct sk_buff *skb = priv->_agn.offchan_tx_skb; | ||
1121 | |||
1122 | if (skb->len < maxlen) | ||
1123 | maxlen = skb->len; | ||
1124 | |||
1125 | memcpy(data, skb->data, maxlen); | ||
1126 | |||
1127 | return maxlen; | ||
1128 | } | ||
1129 | |||
1118 | int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | 1130 | int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) |
1119 | { | 1131 | { |
1120 | struct iwl_host_cmd cmd = { | 1132 | struct iwl_host_cmd cmd = { |
@@ -1157,17 +1169,25 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1157 | scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; | 1169 | scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; |
1158 | scan->quiet_time = IWL_ACTIVE_QUIET_TIME; | 1170 | scan->quiet_time = IWL_ACTIVE_QUIET_TIME; |
1159 | 1171 | ||
1160 | if (iwl_is_any_associated(priv)) { | 1172 | if (priv->scan_type != IWL_SCAN_OFFCH_TX && |
1173 | iwl_is_any_associated(priv)) { | ||
1161 | u16 interval = 0; | 1174 | u16 interval = 0; |
1162 | u32 extra; | 1175 | u32 extra; |
1163 | u32 suspend_time = 100; | 1176 | u32 suspend_time = 100; |
1164 | u32 scan_suspend_time = 100; | 1177 | u32 scan_suspend_time = 100; |
1165 | 1178 | ||
1166 | IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); | 1179 | IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); |
1167 | if (priv->is_internal_short_scan) | 1180 | switch (priv->scan_type) { |
1181 | case IWL_SCAN_OFFCH_TX: | ||
1182 | WARN_ON(1); | ||
1183 | break; | ||
1184 | case IWL_SCAN_RADIO_RESET: | ||
1168 | interval = 0; | 1185 | interval = 0; |
1169 | else | 1186 | break; |
1187 | case IWL_SCAN_NORMAL: | ||
1170 | interval = vif->bss_conf.beacon_int; | 1188 | interval = vif->bss_conf.beacon_int; |
1189 | break; | ||
1190 | } | ||
1171 | 1191 | ||
1172 | scan->suspend_time = 0; | 1192 | scan->suspend_time = 0; |
1173 | scan->max_out_time = cpu_to_le32(200 * 1024); | 1193 | scan->max_out_time = cpu_to_le32(200 * 1024); |
@@ -1180,29 +1200,41 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1180 | scan->suspend_time = cpu_to_le32(scan_suspend_time); | 1200 | scan->suspend_time = cpu_to_le32(scan_suspend_time); |
1181 | IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", | 1201 | IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", |
1182 | scan_suspend_time, interval); | 1202 | scan_suspend_time, interval); |
1203 | } else if (priv->scan_type == IWL_SCAN_OFFCH_TX) { | ||
1204 | scan->suspend_time = 0; | ||
1205 | scan->max_out_time = | ||
1206 | cpu_to_le32(1024 * priv->_agn.offchan_tx_timeout); | ||
1183 | } | 1207 | } |
1184 | 1208 | ||
1185 | if (priv->is_internal_short_scan) { | 1209 | switch (priv->scan_type) { |
1210 | case IWL_SCAN_RADIO_RESET: | ||
1186 | IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); | 1211 | IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); |
1187 | } else if (priv->scan_request->n_ssids) { | 1212 | break; |
1188 | int i, p = 0; | 1213 | case IWL_SCAN_NORMAL: |
1189 | IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); | 1214 | if (priv->scan_request->n_ssids) { |
1190 | for (i = 0; i < priv->scan_request->n_ssids; i++) { | 1215 | int i, p = 0; |
1191 | /* always does wildcard anyway */ | 1216 | IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); |
1192 | if (!priv->scan_request->ssids[i].ssid_len) | 1217 | for (i = 0; i < priv->scan_request->n_ssids; i++) { |
1193 | continue; | 1218 | /* always does wildcard anyway */ |
1194 | scan->direct_scan[p].id = WLAN_EID_SSID; | 1219 | if (!priv->scan_request->ssids[i].ssid_len) |
1195 | scan->direct_scan[p].len = | 1220 | continue; |
1196 | priv->scan_request->ssids[i].ssid_len; | 1221 | scan->direct_scan[p].id = WLAN_EID_SSID; |
1197 | memcpy(scan->direct_scan[p].ssid, | 1222 | scan->direct_scan[p].len = |
1198 | priv->scan_request->ssids[i].ssid, | 1223 | priv->scan_request->ssids[i].ssid_len; |
1199 | priv->scan_request->ssids[i].ssid_len); | 1224 | memcpy(scan->direct_scan[p].ssid, |
1200 | n_probes++; | 1225 | priv->scan_request->ssids[i].ssid, |
1201 | p++; | 1226 | priv->scan_request->ssids[i].ssid_len); |
1202 | } | 1227 | n_probes++; |
1203 | is_active = true; | 1228 | p++; |
1204 | } else | 1229 | } |
1205 | IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); | 1230 | is_active = true; |
1231 | } else | ||
1232 | IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); | ||
1233 | break; | ||
1234 | case IWL_SCAN_OFFCH_TX: | ||
1235 | IWL_DEBUG_SCAN(priv, "Start offchannel TX scan.\n"); | ||
1236 | break; | ||
1237 | } | ||
1206 | 1238 | ||
1207 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; | 1239 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; |
1208 | scan->tx_cmd.sta_id = ctx->bcast_sta_id; | 1240 | scan->tx_cmd.sta_id = ctx->bcast_sta_id; |
@@ -1300,38 +1332,77 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
1300 | rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; | 1332 | rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; |
1301 | rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; | 1333 | rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; |
1302 | scan->rx_chain = cpu_to_le16(rx_chain); | 1334 | scan->rx_chain = cpu_to_le16(rx_chain); |
1303 | if (!priv->is_internal_short_scan) { | 1335 | switch (priv->scan_type) { |
1336 | case IWL_SCAN_NORMAL: | ||
1304 | cmd_len = iwl_fill_probe_req(priv, | 1337 | cmd_len = iwl_fill_probe_req(priv, |
1305 | (struct ieee80211_mgmt *)scan->data, | 1338 | (struct ieee80211_mgmt *)scan->data, |
1306 | vif->addr, | 1339 | vif->addr, |
1307 | priv->scan_request->ie, | 1340 | priv->scan_request->ie, |
1308 | priv->scan_request->ie_len, | 1341 | priv->scan_request->ie_len, |
1309 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); | 1342 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); |
1310 | } else { | 1343 | break; |
1344 | case IWL_SCAN_RADIO_RESET: | ||
1311 | /* use bcast addr, will not be transmitted but must be valid */ | 1345 | /* use bcast addr, will not be transmitted but must be valid */ |
1312 | cmd_len = iwl_fill_probe_req(priv, | 1346 | cmd_len = iwl_fill_probe_req(priv, |
1313 | (struct ieee80211_mgmt *)scan->data, | 1347 | (struct ieee80211_mgmt *)scan->data, |
1314 | iwl_bcast_addr, NULL, 0, | 1348 | iwl_bcast_addr, NULL, 0, |
1315 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); | 1349 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); |
1316 | 1350 | break; | |
1351 | case IWL_SCAN_OFFCH_TX: | ||
1352 | cmd_len = iwl_fill_offch_tx(priv, scan->data, | ||
1353 | IWL_MAX_SCAN_SIZE | ||
1354 | - sizeof(*scan) | ||
1355 | - sizeof(struct iwl_scan_channel)); | ||
1356 | scan->scan_flags |= IWL_SCAN_FLAGS_ACTION_FRAME_TX; | ||
1357 | break; | ||
1358 | default: | ||
1359 | BUG(); | ||
1317 | } | 1360 | } |
1318 | scan->tx_cmd.len = cpu_to_le16(cmd_len); | 1361 | scan->tx_cmd.len = cpu_to_le16(cmd_len); |
1319 | 1362 | ||
1320 | scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | | 1363 | scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | |
1321 | RXON_FILTER_BCON_AWARE_MSK); | 1364 | RXON_FILTER_BCON_AWARE_MSK); |
1322 | 1365 | ||
1323 | if (priv->is_internal_short_scan) { | 1366 | switch (priv->scan_type) { |
1367 | case IWL_SCAN_RADIO_RESET: | ||
1324 | scan->channel_count = | 1368 | scan->channel_count = |
1325 | iwl_get_single_channel_for_scan(priv, vif, band, | 1369 | iwl_get_single_channel_for_scan(priv, vif, band, |
1326 | (void *)&scan->data[le16_to_cpu( | 1370 | (void *)&scan->data[cmd_len]); |
1327 | scan->tx_cmd.len)]); | 1371 | break; |
1328 | } else { | 1372 | case IWL_SCAN_NORMAL: |
1329 | scan->channel_count = | 1373 | scan->channel_count = |
1330 | iwl_get_channels_for_scan(priv, vif, band, | 1374 | iwl_get_channels_for_scan(priv, vif, band, |
1331 | is_active, n_probes, | 1375 | is_active, n_probes, |
1332 | (void *)&scan->data[le16_to_cpu( | 1376 | (void *)&scan->data[cmd_len]); |
1333 | scan->tx_cmd.len)]); | 1377 | break; |
1378 | case IWL_SCAN_OFFCH_TX: { | ||
1379 | struct iwl_scan_channel *scan_ch; | ||
1380 | |||
1381 | scan->channel_count = 1; | ||
1382 | |||
1383 | scan_ch = (void *)&scan->data[cmd_len]; | ||
1384 | scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; | ||
1385 | scan_ch->channel = | ||
1386 | cpu_to_le16(priv->_agn.offchan_tx_chan->hw_value); | ||
1387 | scan_ch->active_dwell = | ||
1388 | cpu_to_le16(priv->_agn.offchan_tx_timeout); | ||
1389 | scan_ch->passive_dwell = 0; | ||
1390 | |||
1391 | /* Set txpower levels to defaults */ | ||
1392 | scan_ch->dsp_atten = 110; | ||
1393 | |||
1394 | /* NOTE: if we were doing 6Mb OFDM for scans we'd use | ||
1395 | * power level: | ||
1396 | * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; | ||
1397 | */ | ||
1398 | if (priv->_agn.offchan_tx_chan->band == IEEE80211_BAND_5GHZ) | ||
1399 | scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; | ||
1400 | else | ||
1401 | scan_ch->tx_gain = ((1 << 5) | (5 << 3)); | ||
1402 | } | ||
1403 | break; | ||
1334 | } | 1404 | } |
1405 | |||
1335 | if (scan->channel_count == 0) { | 1406 | if (scan->channel_count == 0) { |
1336 | IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); | 1407 | IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); |
1337 | return -EIO; | 1408 | return -EIO; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e0cd3e27a0d..581dc9f1027 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -2937,6 +2937,91 @@ static void iwl_bg_rx_replenish(struct work_struct *data) | |||
2937 | mutex_unlock(&priv->mutex); | 2937 | mutex_unlock(&priv->mutex); |
2938 | } | 2938 | } |
2939 | 2939 | ||
2940 | static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb, | ||
2941 | struct ieee80211_channel *chan, | ||
2942 | enum nl80211_channel_type channel_type, | ||
2943 | unsigned int wait) | ||
2944 | { | ||
2945 | struct iwl_priv *priv = hw->priv; | ||
2946 | int ret; | ||
2947 | |||
2948 | /* Not supported if we don't have PAN */ | ||
2949 | if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) { | ||
2950 | ret = -EOPNOTSUPP; | ||
2951 | goto free; | ||
2952 | } | ||
2953 | |||
2954 | /* Not supported on pre-P2P firmware */ | ||
2955 | if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & | ||
2956 | BIT(NL80211_IFTYPE_P2P_CLIENT))) { | ||
2957 | ret = -EOPNOTSUPP; | ||
2958 | goto free; | ||
2959 | } | ||
2960 | |||
2961 | mutex_lock(&priv->mutex); | ||
2962 | |||
2963 | if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) { | ||
2964 | /* | ||
2965 | * If the PAN context is free, use the normal | ||
2966 | * way of doing remain-on-channel offload + TX. | ||
2967 | */ | ||
2968 | ret = 1; | ||
2969 | goto out; | ||
2970 | } | ||
2971 | |||
2972 | /* TODO: queue up if scanning? */ | ||
2973 | if (test_bit(STATUS_SCANNING, &priv->status) || | ||
2974 | priv->_agn.offchan_tx_skb) { | ||
2975 | ret = -EBUSY; | ||
2976 | goto out; | ||
2977 | } | ||
2978 | |||
2979 | /* | ||
2980 | * max_scan_ie_len doesn't include the blank SSID or the header, | ||
2981 | * so need to add that again here. | ||
2982 | */ | ||
2983 | if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) { | ||
2984 | ret = -ENOBUFS; | ||
2985 | goto out; | ||
2986 | } | ||
2987 | |||
2988 | priv->_agn.offchan_tx_skb = skb; | ||
2989 | priv->_agn.offchan_tx_timeout = wait; | ||
2990 | priv->_agn.offchan_tx_chan = chan; | ||
2991 | |||
2992 | ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif, | ||
2993 | IWL_SCAN_OFFCH_TX, chan->band); | ||
2994 | if (ret) | ||
2995 | priv->_agn.offchan_tx_skb = NULL; | ||
2996 | out: | ||
2997 | mutex_unlock(&priv->mutex); | ||
2998 | free: | ||
2999 | if (ret < 0) | ||
3000 | kfree_skb(skb); | ||
3001 | |||
3002 | return ret; | ||
3003 | } | ||
3004 | |||
3005 | static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw) | ||
3006 | { | ||
3007 | struct iwl_priv *priv = hw->priv; | ||
3008 | int ret; | ||
3009 | |||
3010 | mutex_lock(&priv->mutex); | ||
3011 | |||
3012 | if (!priv->_agn.offchan_tx_skb) | ||
3013 | return -EINVAL; | ||
3014 | |||
3015 | priv->_agn.offchan_tx_skb = NULL; | ||
3016 | |||
3017 | ret = iwl_scan_cancel_timeout(priv, 200); | ||
3018 | if (ret) | ||
3019 | ret = -EIO; | ||
3020 | mutex_unlock(&priv->mutex); | ||
3021 | |||
3022 | return ret; | ||
3023 | } | ||
3024 | |||
2940 | /***************************************************************************** | 3025 | /***************************************************************************** |
2941 | * | 3026 | * |
2942 | * mac80211 entry point functions | 3027 | * mac80211 entry point functions |
@@ -3815,6 +3900,8 @@ struct ieee80211_ops iwlagn_hw_ops = { | |||
3815 | .tx_last_beacon = iwl_mac_tx_last_beacon, | 3900 | .tx_last_beacon = iwl_mac_tx_last_beacon, |
3816 | .remain_on_channel = iwl_mac_remain_on_channel, | 3901 | .remain_on_channel = iwl_mac_remain_on_channel, |
3817 | .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, | 3902 | .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, |
3903 | .offchannel_tx = iwl_mac_offchannel_tx, | ||
3904 | .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, | ||
3818 | }; | 3905 | }; |
3819 | 3906 | ||
3820 | static void iwl_hw_detect(struct iwl_priv *priv) | 3907 | static void iwl_hw_detect(struct iwl_priv *priv) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 03cfb74da2b..ca42ffa63ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -2964,9 +2964,15 @@ struct iwl3945_scan_cmd { | |||
2964 | u8 data[0]; | 2964 | u8 data[0]; |
2965 | } __packed; | 2965 | } __packed; |
2966 | 2966 | ||
2967 | enum iwl_scan_flags { | ||
2968 | /* BIT(0) currently unused */ | ||
2969 | IWL_SCAN_FLAGS_ACTION_FRAME_TX = BIT(1), | ||
2970 | /* bits 2-7 reserved */ | ||
2971 | }; | ||
2972 | |||
2967 | struct iwl_scan_cmd { | 2973 | struct iwl_scan_cmd { |
2968 | __le16 len; | 2974 | __le16 len; |
2969 | u8 reserved0; | 2975 | u8 scan_flags; /* scan flags: see enum iwl_scan_flags */ |
2970 | u8 channel_count; /* # channels in channel list */ | 2976 | u8 channel_count; /* # channels in channel list */ |
2971 | __le16 quiet_time; /* dwell only this # millisecs on quiet channel | 2977 | __le16 quiet_time; /* dwell only this # millisecs on quiet channel |
2972 | * (only for active scan) */ | 2978 | * (only for active scan) */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index af47750f898..b316d833d9a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -63,6 +63,8 @@ | |||
63 | #ifndef __iwl_core_h__ | 63 | #ifndef __iwl_core_h__ |
64 | #define __iwl_core_h__ | 64 | #define __iwl_core_h__ |
65 | 65 | ||
66 | #include "iwl-dev.h" | ||
67 | |||
66 | /************************ | 68 | /************************ |
67 | * forward declarations * | 69 | * forward declarations * |
68 | ************************/ | 70 | ************************/ |
@@ -551,6 +553,10 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, | |||
551 | struct ieee80211_vif *vif); | 553 | struct ieee80211_vif *vif); |
552 | void iwl_setup_scan_deferred_work(struct iwl_priv *priv); | 554 | void iwl_setup_scan_deferred_work(struct iwl_priv *priv); |
553 | void iwl_cancel_scan_deferred_work(struct iwl_priv *priv); | 555 | void iwl_cancel_scan_deferred_work(struct iwl_priv *priv); |
556 | int __must_check iwl_scan_initiate(struct iwl_priv *priv, | ||
557 | struct ieee80211_vif *vif, | ||
558 | enum iwl_scan_type scan_type, | ||
559 | enum ieee80211_band band); | ||
554 | 560 | ||
555 | /* For faster active scanning, scan will move to the next channel if fewer than | 561 | /* For faster active scanning, scan will move to the next channel if fewer than |
556 | * PLCP_QUIET_THRESH packets are heard on this channel within | 562 | * PLCP_QUIET_THRESH packets are heard on this channel within |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6a41deba686..68b953f2bdc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -1230,6 +1230,12 @@ struct iwl_rxon_context { | |||
1230 | } ht; | 1230 | } ht; |
1231 | }; | 1231 | }; |
1232 | 1232 | ||
1233 | enum iwl_scan_type { | ||
1234 | IWL_SCAN_NORMAL, | ||
1235 | IWL_SCAN_RADIO_RESET, | ||
1236 | IWL_SCAN_OFFCH_TX, | ||
1237 | }; | ||
1238 | |||
1233 | struct iwl_priv { | 1239 | struct iwl_priv { |
1234 | 1240 | ||
1235 | /* ieee device used by generic ieee processing code */ | 1241 | /* ieee device used by generic ieee processing code */ |
@@ -1290,7 +1296,7 @@ struct iwl_priv { | |||
1290 | enum ieee80211_band scan_band; | 1296 | enum ieee80211_band scan_band; |
1291 | struct cfg80211_scan_request *scan_request; | 1297 | struct cfg80211_scan_request *scan_request; |
1292 | struct ieee80211_vif *scan_vif; | 1298 | struct ieee80211_vif *scan_vif; |
1293 | bool is_internal_short_scan; | 1299 | enum iwl_scan_type scan_type; |
1294 | u8 scan_tx_ant[IEEE80211_NUM_BANDS]; | 1300 | u8 scan_tx_ant[IEEE80211_NUM_BANDS]; |
1295 | u8 mgmt_tx_ant; | 1301 | u8 mgmt_tx_ant; |
1296 | 1302 | ||
@@ -1504,6 +1510,10 @@ struct iwl_priv { | |||
1504 | struct delayed_work hw_roc_work; | 1510 | struct delayed_work hw_roc_work; |
1505 | enum nl80211_channel_type hw_roc_chantype; | 1511 | enum nl80211_channel_type hw_roc_chantype; |
1506 | int hw_roc_duration; | 1512 | int hw_roc_duration; |
1513 | |||
1514 | struct sk_buff *offchan_tx_skb; | ||
1515 | int offchan_tx_timeout; | ||
1516 | struct ieee80211_channel *offchan_tx_chan; | ||
1507 | } _agn; | 1517 | } _agn; |
1508 | #endif | 1518 | #endif |
1509 | }; | 1519 | }; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index faa6d34cb65..3a4d9e6b042 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -101,7 +101,7 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) | |||
101 | ieee80211_scan_completed(priv->hw, aborted); | 101 | ieee80211_scan_completed(priv->hw, aborted); |
102 | } | 102 | } |
103 | 103 | ||
104 | priv->is_internal_short_scan = false; | 104 | priv->scan_type = IWL_SCAN_NORMAL; |
105 | priv->scan_vif = NULL; | 105 | priv->scan_vif = NULL; |
106 | priv->scan_request = NULL; | 106 | priv->scan_request = NULL; |
107 | } | 107 | } |
@@ -339,10 +339,10 @@ void iwl_init_scan_params(struct iwl_priv *priv) | |||
339 | priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; | 339 | priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; |
340 | } | 340 | } |
341 | 341 | ||
342 | static int __must_check iwl_scan_initiate(struct iwl_priv *priv, | 342 | int __must_check iwl_scan_initiate(struct iwl_priv *priv, |
343 | struct ieee80211_vif *vif, | 343 | struct ieee80211_vif *vif, |
344 | bool internal, | 344 | enum iwl_scan_type scan_type, |
345 | enum ieee80211_band band) | 345 | enum ieee80211_band band) |
346 | { | 346 | { |
347 | int ret; | 347 | int ret; |
348 | 348 | ||
@@ -370,17 +370,19 @@ static int __must_check iwl_scan_initiate(struct iwl_priv *priv, | |||
370 | } | 370 | } |
371 | 371 | ||
372 | IWL_DEBUG_SCAN(priv, "Starting %sscan...\n", | 372 | IWL_DEBUG_SCAN(priv, "Starting %sscan...\n", |
373 | internal ? "internal short " : ""); | 373 | scan_type == IWL_SCAN_NORMAL ? "" : |
374 | scan_type == IWL_SCAN_OFFCH_TX ? "offchan TX " : | ||
375 | "internal short "); | ||
374 | 376 | ||
375 | set_bit(STATUS_SCANNING, &priv->status); | 377 | set_bit(STATUS_SCANNING, &priv->status); |
376 | priv->is_internal_short_scan = internal; | 378 | priv->scan_type = scan_type; |
377 | priv->scan_start = jiffies; | 379 | priv->scan_start = jiffies; |
378 | priv->scan_band = band; | 380 | priv->scan_band = band; |
379 | 381 | ||
380 | ret = priv->cfg->ops->utils->request_scan(priv, vif); | 382 | ret = priv->cfg->ops->utils->request_scan(priv, vif); |
381 | if (ret) { | 383 | if (ret) { |
382 | clear_bit(STATUS_SCANNING, &priv->status); | 384 | clear_bit(STATUS_SCANNING, &priv->status); |
383 | priv->is_internal_short_scan = false; | 385 | priv->scan_type = IWL_SCAN_NORMAL; |
384 | return ret; | 386 | return ret; |
385 | } | 387 | } |
386 | 388 | ||
@@ -405,7 +407,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, | |||
405 | mutex_lock(&priv->mutex); | 407 | mutex_lock(&priv->mutex); |
406 | 408 | ||
407 | if (test_bit(STATUS_SCANNING, &priv->status) && | 409 | if (test_bit(STATUS_SCANNING, &priv->status) && |
408 | !priv->is_internal_short_scan) { | 410 | priv->scan_type != IWL_SCAN_NORMAL) { |
409 | IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); | 411 | IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); |
410 | ret = -EAGAIN; | 412 | ret = -EAGAIN; |
411 | goto out_unlock; | 413 | goto out_unlock; |
@@ -419,11 +421,11 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, | |||
419 | * If an internal scan is in progress, just set | 421 | * If an internal scan is in progress, just set |
420 | * up the scan_request as per above. | 422 | * up the scan_request as per above. |
421 | */ | 423 | */ |
422 | if (priv->is_internal_short_scan) { | 424 | if (priv->scan_type != IWL_SCAN_NORMAL) { |
423 | IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n"); | 425 | IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n"); |
424 | ret = 0; | 426 | ret = 0; |
425 | } else | 427 | } else |
426 | ret = iwl_scan_initiate(priv, vif, false, | 428 | ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL, |
427 | req->channels[0]->band); | 429 | req->channels[0]->band); |
428 | 430 | ||
429 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 431 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
@@ -452,7 +454,7 @@ static void iwl_bg_start_internal_scan(struct work_struct *work) | |||
452 | 454 | ||
453 | mutex_lock(&priv->mutex); | 455 | mutex_lock(&priv->mutex); |
454 | 456 | ||
455 | if (priv->is_internal_short_scan == true) { | 457 | if (priv->scan_type == IWL_SCAN_RADIO_RESET) { |
456 | IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n"); | 458 | IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n"); |
457 | goto unlock; | 459 | goto unlock; |
458 | } | 460 | } |
@@ -462,7 +464,7 @@ static void iwl_bg_start_internal_scan(struct work_struct *work) | |||
462 | goto unlock; | 464 | goto unlock; |
463 | } | 465 | } |
464 | 466 | ||
465 | if (iwl_scan_initiate(priv, NULL, true, priv->band)) | 467 | if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band)) |
466 | IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n"); | 468 | IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n"); |
467 | unlock: | 469 | unlock: |
468 | mutex_unlock(&priv->mutex); | 470 | mutex_unlock(&priv->mutex); |
@@ -549,8 +551,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) | |||
549 | container_of(work, struct iwl_priv, scan_completed); | 551 | container_of(work, struct iwl_priv, scan_completed); |
550 | bool aborted; | 552 | bool aborted; |
551 | 553 | ||
552 | IWL_DEBUG_SCAN(priv, "Completed %sscan.\n", | 554 | IWL_DEBUG_SCAN(priv, "Completed scan.\n"); |
553 | priv->is_internal_short_scan ? "internal short " : ""); | ||
554 | 555 | ||
555 | cancel_delayed_work(&priv->scan_check); | 556 | cancel_delayed_work(&priv->scan_check); |
556 | 557 | ||
@@ -565,7 +566,13 @@ static void iwl_bg_scan_completed(struct work_struct *work) | |||
565 | goto out_settings; | 566 | goto out_settings; |
566 | } | 567 | } |
567 | 568 | ||
568 | if (priv->is_internal_short_scan && !aborted) { | 569 | if (priv->scan_type == IWL_SCAN_OFFCH_TX && priv->_agn.offchan_tx_skb) { |
570 | ieee80211_tx_status_irqsafe(priv->hw, | ||
571 | priv->_agn.offchan_tx_skb); | ||
572 | priv->_agn.offchan_tx_skb = NULL; | ||
573 | } | ||
574 | |||
575 | if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { | ||
569 | int err; | 576 | int err; |
570 | 577 | ||
571 | /* Check if mac80211 requested scan during our internal scan */ | 578 | /* Check if mac80211 requested scan during our internal scan */ |
@@ -573,7 +580,7 @@ static void iwl_bg_scan_completed(struct work_struct *work) | |||
573 | goto out_complete; | 580 | goto out_complete; |
574 | 581 | ||
575 | /* If so request a new scan */ | 582 | /* If so request a new scan */ |
576 | err = iwl_scan_initiate(priv, priv->scan_vif, false, | 583 | err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL, |
577 | priv->scan_request->channels[0]->band); | 584 | priv->scan_request->channels[0]->band); |
578 | if (err) { | 585 | if (err) { |
579 | IWL_DEBUG_SCAN(priv, | 586 | IWL_DEBUG_SCAN(priv, |
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index acf3bf63ee3..9d097b9c800 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c | |||
@@ -918,7 +918,6 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, | |||
918 | char *buf) | 918 | char *buf) |
919 | { | 919 | { |
920 | struct mrvl_mesh_defaults defs; | 920 | struct mrvl_mesh_defaults defs; |
921 | int maxlen; | ||
922 | int ret; | 921 | int ret; |
923 | 922 | ||
924 | ret = mesh_get_default_parameters(dev, &defs); | 923 | ret = mesh_get_default_parameters(dev, &defs); |
@@ -931,13 +930,11 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, | |||
931 | defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN; | 930 | defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN; |
932 | } | 931 | } |
933 | 932 | ||
934 | /* SSID not null terminated: reserve room for \0 + \n */ | 933 | memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len); |
935 | maxlen = defs.meshie.val.mesh_id_len + 2; | 934 | buf[defs.meshie.val.mesh_id_len] = '\n'; |
936 | maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE; | 935 | buf[defs.meshie.val.mesh_id_len + 1] = '\0'; |
937 | 936 | ||
938 | defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0'; | 937 | return defs.meshie.val.mesh_id_len + 1; |
939 | |||
940 | return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id); | ||
941 | } | 938 | } |
942 | 939 | ||
943 | /** | 940 | /** |
diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c index 9ba23ede51b..9cc514703d2 100644 --- a/drivers/net/wireless/wl1251/ps.c +++ b/drivers/net/wireless/wl1251/ps.c | |||
@@ -58,7 +58,6 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl) | |||
58 | unsigned long delay; | 58 | unsigned long delay; |
59 | 59 | ||
60 | if (wl->psm) { | 60 | if (wl->psm) { |
61 | cancel_delayed_work(&wl->elp_work); | ||
62 | delay = msecs_to_jiffies(ELP_ENTRY_DELAY); | 61 | delay = msecs_to_jiffies(ELP_ENTRY_DELAY); |
63 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); | 62 | ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay); |
64 | } | 63 | } |
@@ -69,6 +68,9 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) | |||
69 | unsigned long timeout, start; | 68 | unsigned long timeout, start; |
70 | u32 elp_reg; | 69 | u32 elp_reg; |
71 | 70 | ||
71 | if (delayed_work_pending(&wl->elp_work)) | ||
72 | cancel_delayed_work(&wl->elp_work); | ||
73 | |||
72 | if (!wl->elp) | 74 | if (!wl->elp) |
73 | return 0; | 75 | return 0; |
74 | 76 | ||
@@ -102,38 +104,6 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl) | |||
102 | return 0; | 104 | return 0; |
103 | } | 105 | } |
104 | 106 | ||
105 | static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable) | ||
106 | { | ||
107 | int ret; | ||
108 | |||
109 | if (enable) { | ||
110 | wl1251_debug(DEBUG_PSM, "sleep auth psm/elp"); | ||
111 | |||
112 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); | ||
113 | if (ret < 0) | ||
114 | return ret; | ||
115 | |||
116 | wl1251_ps_elp_sleep(wl); | ||
117 | } else { | ||
118 | wl1251_debug(DEBUG_PSM, "sleep auth cam"); | ||
119 | |||
120 | /* | ||
121 | * When the target is in ELP, we can only | ||
122 | * access the ELP control register. Thus, | ||
123 | * we have to wake the target up before | ||
124 | * changing the power authorization. | ||
125 | */ | ||
126 | |||
127 | wl1251_ps_elp_wakeup(wl); | ||
128 | |||
129 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); | ||
130 | if (ret < 0) | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) | 107 | int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) |
138 | { | 108 | { |
139 | int ret; | 109 | int ret; |
@@ -162,7 +132,7 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) | |||
162 | if (ret < 0) | 132 | if (ret < 0) |
163 | return ret; | 133 | return ret; |
164 | 134 | ||
165 | ret = wl1251_ps_set_elp(wl, true); | 135 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP); |
166 | if (ret < 0) | 136 | if (ret < 0) |
167 | return ret; | 137 | return ret; |
168 | 138 | ||
@@ -171,7 +141,8 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode) | |||
171 | case STATION_ACTIVE_MODE: | 141 | case STATION_ACTIVE_MODE: |
172 | default: | 142 | default: |
173 | wl1251_debug(DEBUG_PSM, "leaving psm"); | 143 | wl1251_debug(DEBUG_PSM, "leaving psm"); |
174 | ret = wl1251_ps_set_elp(wl, false); | 144 | |
145 | ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM); | ||
175 | if (ret < 0) | 146 | if (ret < 0) |
176 | return ret; | 147 | return ret; |
177 | 148 | ||
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1ac5786da14..60f7876b6da 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1197,6 +1197,10 @@ struct cfg80211_pmksa { | |||
1197 | * (also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX). | 1197 | * (also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX). |
1198 | * | 1198 | * |
1199 | * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant). | 1199 | * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant). |
1200 | * | ||
1201 | * @set_ringparam: Set tx and rx ring sizes. | ||
1202 | * | ||
1203 | * @get_ringparam: Get tx and rx ring current and maximum sizes. | ||
1200 | */ | 1204 | */ |
1201 | struct cfg80211_ops { | 1205 | struct cfg80211_ops { |
1202 | int (*suspend)(struct wiphy *wiphy); | 1206 | int (*suspend)(struct wiphy *wiphy); |
@@ -1364,6 +1368,10 @@ struct cfg80211_ops { | |||
1364 | 1368 | ||
1365 | int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); | 1369 | int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); |
1366 | int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant); | 1370 | int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant); |
1371 | |||
1372 | int (*set_ringparam)(struct wiphy *wiphy, u32 tx, u32 rx); | ||
1373 | void (*get_ringparam)(struct wiphy *wiphy, | ||
1374 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); | ||
1367 | }; | 1375 | }; |
1368 | 1376 | ||
1369 | /* | 1377 | /* |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2b072fa9939..8650e7bf2ed 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1804,6 +1804,10 @@ enum ieee80211_ampdu_mlme_action { | |||
1804 | * return value is 1, then the @remain_on_channel will be used with a | 1804 | * return value is 1, then the @remain_on_channel will be used with a |
1805 | * regular transmission (if supported.) | 1805 | * regular transmission (if supported.) |
1806 | * @offchannel_tx_cancel_wait: cancel wait associated with offchannel TX | 1806 | * @offchannel_tx_cancel_wait: cancel wait associated with offchannel TX |
1807 | * | ||
1808 | * @set_ringparam: Set tx and rx ring sizes. | ||
1809 | * | ||
1810 | * @get_ringparam: Get tx and rx ring current and maximum sizes. | ||
1807 | */ | 1811 | */ |
1808 | struct ieee80211_ops { | 1812 | struct ieee80211_ops { |
1809 | void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); | 1813 | void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); |
@@ -1888,6 +1892,9 @@ struct ieee80211_ops { | |||
1888 | enum nl80211_channel_type channel_type, | 1892 | enum nl80211_channel_type channel_type, |
1889 | unsigned int wait); | 1893 | unsigned int wait); |
1890 | int (*offchannel_tx_cancel_wait)(struct ieee80211_hw *hw); | 1894 | int (*offchannel_tx_cancel_wait)(struct ieee80211_hw *hw); |
1895 | int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx); | ||
1896 | void (*get_ringparam)(struct ieee80211_hw *hw, | ||
1897 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); | ||
1891 | }; | 1898 | }; |
1892 | 1899 | ||
1893 | /** | 1900 | /** |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7b701dcddb5..334213571ad 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -834,6 +834,10 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
834 | 834 | ||
835 | rcu_read_unlock(); | 835 | rcu_read_unlock(); |
836 | 836 | ||
837 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||
838 | params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
839 | ieee80211_recalc_ps(local, -1); | ||
840 | |||
837 | return 0; | 841 | return 0; |
838 | } | 842 | } |
839 | 843 | ||
@@ -2008,6 +2012,21 @@ static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) | |||
2008 | return drv_get_antenna(local, tx_ant, rx_ant); | 2012 | return drv_get_antenna(local, tx_ant, rx_ant); |
2009 | } | 2013 | } |
2010 | 2014 | ||
2015 | static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx) | ||
2016 | { | ||
2017 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
2018 | |||
2019 | return drv_set_ringparam(local, tx, rx); | ||
2020 | } | ||
2021 | |||
2022 | static void ieee80211_get_ringparam(struct wiphy *wiphy, | ||
2023 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) | ||
2024 | { | ||
2025 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
2026 | |||
2027 | drv_get_ringparam(local, tx, tx_max, rx, rx_max); | ||
2028 | } | ||
2029 | |||
2011 | struct cfg80211_ops mac80211_config_ops = { | 2030 | struct cfg80211_ops mac80211_config_ops = { |
2012 | .add_virtual_intf = ieee80211_add_iface, | 2031 | .add_virtual_intf = ieee80211_add_iface, |
2013 | .del_virtual_intf = ieee80211_del_iface, | 2032 | .del_virtual_intf = ieee80211_del_iface, |
@@ -2065,4 +2084,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2065 | .mgmt_frame_register = ieee80211_mgmt_frame_register, | 2084 | .mgmt_frame_register = ieee80211_mgmt_frame_register, |
2066 | .set_antenna = ieee80211_set_antenna, | 2085 | .set_antenna = ieee80211_set_antenna, |
2067 | .get_antenna = ieee80211_get_antenna, | 2086 | .get_antenna = ieee80211_get_antenna, |
2087 | .set_ringparam = ieee80211_set_ringparam, | ||
2088 | .get_ringparam = ieee80211_get_ringparam, | ||
2068 | }; | 2089 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 5b24740fc0b..889c3e93e0f 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -77,6 +77,9 @@ bool ieee80211_set_channel_type(struct ieee80211_local *local, | |||
77 | switch (tmp->vif.bss_conf.channel_type) { | 77 | switch (tmp->vif.bss_conf.channel_type) { |
78 | case NL80211_CHAN_NO_HT: | 78 | case NL80211_CHAN_NO_HT: |
79 | case NL80211_CHAN_HT20: | 79 | case NL80211_CHAN_HT20: |
80 | if (superchan > tmp->vif.bss_conf.channel_type) | ||
81 | break; | ||
82 | |||
80 | superchan = tmp->vif.bss_conf.channel_type; | 83 | superchan = tmp->vif.bss_conf.channel_type; |
81 | break; | 84 | break; |
82 | case NL80211_CHAN_HT40PLUS: | 85 | case NL80211_CHAN_HT40PLUS: |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 3729296f6f9..9c0d62bb0ea 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -526,4 +526,30 @@ static inline int drv_offchannel_tx_cancel_wait(struct ieee80211_local *local) | |||
526 | return ret; | 526 | return ret; |
527 | } | 527 | } |
528 | 528 | ||
529 | static inline int drv_set_ringparam(struct ieee80211_local *local, | ||
530 | u32 tx, u32 rx) | ||
531 | { | ||
532 | int ret = -ENOTSUPP; | ||
533 | |||
534 | might_sleep(); | ||
535 | |||
536 | trace_drv_set_ringparam(local, tx, rx); | ||
537 | if (local->ops->set_ringparam) | ||
538 | ret = local->ops->set_ringparam(&local->hw, tx, rx); | ||
539 | trace_drv_return_int(local, ret); | ||
540 | |||
541 | return ret; | ||
542 | } | ||
543 | |||
544 | static inline void drv_get_ringparam(struct ieee80211_local *local, | ||
545 | u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) | ||
546 | { | ||
547 | might_sleep(); | ||
548 | |||
549 | trace_drv_get_ringparam(local, tx, tx_max, rx, rx_max); | ||
550 | if (local->ops->get_ringparam) | ||
551 | local->ops->get_ringparam(&local->hw, tx, tx_max, rx, rx_max); | ||
552 | trace_drv_return_void(local); | ||
553 | } | ||
554 | |||
529 | #endif /* __MAC80211_DRIVER_OPS */ | 555 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 520fe244489..45aab80738e 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -912,6 +912,58 @@ TRACE_EVENT(drv_offchannel_tx, | |||
912 | ) | 912 | ) |
913 | ); | 913 | ); |
914 | 914 | ||
915 | TRACE_EVENT(drv_set_ringparam, | ||
916 | TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx), | ||
917 | |||
918 | TP_ARGS(local, tx, rx), | ||
919 | |||
920 | TP_STRUCT__entry( | ||
921 | LOCAL_ENTRY | ||
922 | __field(u32, tx) | ||
923 | __field(u32, rx) | ||
924 | ), | ||
925 | |||
926 | TP_fast_assign( | ||
927 | LOCAL_ASSIGN; | ||
928 | __entry->tx = tx; | ||
929 | __entry->rx = rx; | ||
930 | ), | ||
931 | |||
932 | TP_printk( | ||
933 | LOCAL_PR_FMT " tx:%d rx %d", | ||
934 | LOCAL_PR_ARG, __entry->tx, __entry->rx | ||
935 | ) | ||
936 | ); | ||
937 | |||
938 | TRACE_EVENT(drv_get_ringparam, | ||
939 | TP_PROTO(struct ieee80211_local *local, u32 *tx, u32 *tx_max, | ||
940 | u32 *rx, u32 *rx_max), | ||
941 | |||
942 | TP_ARGS(local, tx, tx_max, rx, rx_max), | ||
943 | |||
944 | TP_STRUCT__entry( | ||
945 | LOCAL_ENTRY | ||
946 | __field(u32, tx) | ||
947 | __field(u32, tx_max) | ||
948 | __field(u32, rx) | ||
949 | __field(u32, rx_max) | ||
950 | ), | ||
951 | |||
952 | TP_fast_assign( | ||
953 | LOCAL_ASSIGN; | ||
954 | __entry->tx = *tx; | ||
955 | __entry->tx_max = *tx_max; | ||
956 | __entry->rx = *rx; | ||
957 | __entry->rx_max = *rx_max; | ||
958 | ), | ||
959 | |||
960 | TP_printk( | ||
961 | LOCAL_PR_FMT " tx:%d tx_max %d rx %d rx_max %d", | ||
962 | LOCAL_PR_ARG, | ||
963 | __entry->tx, __entry->tx_max, __entry->rx, __entry->rx_max | ||
964 | ) | ||
965 | ); | ||
966 | |||
915 | DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait, | 967 | DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait, |
916 | TP_PROTO(struct ieee80211_local *local), | 968 | TP_PROTO(struct ieee80211_local *local), |
917 | TP_ARGS(local) | 969 | TP_ARGS(local) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index cc984bd861c..64d92d5a7f4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -613,6 +613,37 @@ static void ieee80211_change_ps(struct ieee80211_local *local) | |||
613 | } | 613 | } |
614 | } | 614 | } |
615 | 615 | ||
616 | static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | ||
617 | { | ||
618 | struct ieee80211_if_managed *mgd = &sdata->u.mgd; | ||
619 | struct sta_info *sta = NULL; | ||
620 | u32 sta_flags = 0; | ||
621 | |||
622 | if (!mgd->powersave) | ||
623 | return false; | ||
624 | |||
625 | if (!mgd->associated) | ||
626 | return false; | ||
627 | |||
628 | if (!mgd->associated->beacon_ies) | ||
629 | return false; | ||
630 | |||
631 | if (mgd->flags & (IEEE80211_STA_BEACON_POLL | | ||
632 | IEEE80211_STA_CONNECTION_POLL)) | ||
633 | return false; | ||
634 | |||
635 | rcu_read_lock(); | ||
636 | sta = sta_info_get(sdata, mgd->bssid); | ||
637 | if (sta) | ||
638 | sta_flags = get_sta_flags(sta); | ||
639 | rcu_read_unlock(); | ||
640 | |||
641 | if (!(sta_flags & WLAN_STA_AUTHORIZED)) | ||
642 | return false; | ||
643 | |||
644 | return true; | ||
645 | } | ||
646 | |||
616 | /* need to hold RTNL or interface lock */ | 647 | /* need to hold RTNL or interface lock */ |
617 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | 648 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) |
618 | { | 649 | { |
@@ -647,11 +678,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
647 | count++; | 678 | count++; |
648 | } | 679 | } |
649 | 680 | ||
650 | if (count == 1 && found->u.mgd.powersave && | 681 | if (count == 1 && ieee80211_powersave_allowed(found)) { |
651 | found->u.mgd.associated && | ||
652 | found->u.mgd.associated->beacon_ies && | ||
653 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | | ||
654 | IEEE80211_STA_CONNECTION_POLL))) { | ||
655 | struct ieee80211_conf *conf = &local->hw.conf; | 682 | struct ieee80211_conf *conf = &local->hw.conf; |
656 | s32 beaconint_us; | 683 | s32 beaconint_us; |
657 | 684 | ||
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index bce14fbfc3b..8212a8bebf0 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -598,19 +598,46 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
598 | sample = true; | 598 | sample = true; |
599 | minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, | 599 | minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx, |
600 | txrc, true, false); | 600 | txrc, true, false); |
601 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, | ||
602 | txrc, false, false); | ||
603 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 601 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
604 | } else { | 602 | } else { |
605 | minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, | 603 | minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate, |
606 | txrc, false, false); | 604 | txrc, false, false); |
607 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2, | ||
608 | txrc, false, true); | ||
609 | } | 605 | } |
610 | minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, !sample); | ||
611 | 606 | ||
612 | ar[3].count = 0; | 607 | if (mp->hw->max_rates >= 3) { |
613 | ar[3].idx = -1; | 608 | /* |
609 | * At least 3 tx rates supported, use | ||
610 | * sample_rate -> max_tp_rate -> max_prob_rate for sampling and | ||
611 | * max_tp_rate -> max_tp_rate2 -> max_prob_rate by default. | ||
612 | */ | ||
613 | if (sample_idx >= 0) | ||
614 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate, | ||
615 | txrc, false, false); | ||
616 | else | ||
617 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2, | ||
618 | txrc, false, true); | ||
619 | |||
620 | minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, | ||
621 | txrc, false, !sample); | ||
622 | |||
623 | ar[3].count = 0; | ||
624 | ar[3].idx = -1; | ||
625 | } else if (mp->hw->max_rates == 2) { | ||
626 | /* | ||
627 | * Only 2 tx rates supported, use | ||
628 | * sample_rate -> max_prob_rate for sampling and | ||
629 | * max_tp_rate -> max_prob_rate by default. | ||
630 | */ | ||
631 | minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_prob_rate, | ||
632 | txrc, false, !sample); | ||
633 | |||
634 | ar[2].count = 0; | ||
635 | ar[2].idx = -1; | ||
636 | } else { | ||
637 | /* Not using MRR, only use the first rate */ | ||
638 | ar[1].count = 0; | ||
639 | ar[1].idx = -1; | ||
640 | } | ||
614 | 641 | ||
615 | mi->total_packets++; | 642 | mi->total_packets++; |
616 | 643 | ||
diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c index ca4c825be93..9bde4d1d3e9 100644 --- a/net/wireless/ethtool.c +++ b/net/wireless/ethtool.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <linux/utsname.h> | 1 | #include <linux/utsname.h> |
2 | #include <net/cfg80211.h> | 2 | #include <net/cfg80211.h> |
3 | #include "core.h" | ||
3 | #include "ethtool.h" | 4 | #include "ethtool.h" |
4 | 5 | ||
5 | static void cfg80211_get_drvinfo(struct net_device *dev, | 6 | static void cfg80211_get_drvinfo(struct net_device *dev, |
@@ -37,9 +38,41 @@ static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |||
37 | regs->len = 0; | 38 | regs->len = 0; |
38 | } | 39 | } |
39 | 40 | ||
41 | static void cfg80211_get_ringparam(struct net_device *dev, | ||
42 | struct ethtool_ringparam *rp) | ||
43 | { | ||
44 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
45 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
46 | |||
47 | memset(rp, 0, sizeof(*rp)); | ||
48 | |||
49 | if (rdev->ops->get_ringparam) | ||
50 | rdev->ops->get_ringparam(wdev->wiphy, | ||
51 | &rp->tx_pending, &rp->tx_max_pending, | ||
52 | &rp->rx_pending, &rp->rx_max_pending); | ||
53 | } | ||
54 | |||
55 | static int cfg80211_set_ringparam(struct net_device *dev, | ||
56 | struct ethtool_ringparam *rp) | ||
57 | { | ||
58 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
59 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
60 | |||
61 | if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0) | ||
62 | return -EINVAL; | ||
63 | |||
64 | if (rdev->ops->set_ringparam) | ||
65 | return rdev->ops->set_ringparam(wdev->wiphy, | ||
66 | rp->tx_pending, rp->rx_pending); | ||
67 | |||
68 | return -ENOTSUPP; | ||
69 | } | ||
70 | |||
40 | const struct ethtool_ops cfg80211_ethtool_ops = { | 71 | const struct ethtool_ops cfg80211_ethtool_ops = { |
41 | .get_drvinfo = cfg80211_get_drvinfo, | 72 | .get_drvinfo = cfg80211_get_drvinfo, |
42 | .get_regs_len = cfg80211_get_regs_len, | 73 | .get_regs_len = cfg80211_get_regs_len, |
43 | .get_regs = cfg80211_get_regs, | 74 | .get_regs = cfg80211_get_regs, |
44 | .get_link = ethtool_op_get_link, | 75 | .get_link = ethtool_op_get_link, |
76 | .get_ringparam = cfg80211_get_ringparam, | ||
77 | .set_ringparam = cfg80211_set_ringparam, | ||
45 | }; | 78 | }; |