summaryrefslogtreecommitdiff
path: root/package/kernel/mac80211/patches/300-pending_work.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches/300-pending_work.patch')
-rw-r--r--package/kernel/mac80211/patches/300-pending_work.patch265
1 files changed, 222 insertions, 43 deletions
diff --git a/package/kernel/mac80211/patches/300-pending_work.patch b/package/kernel/mac80211/patches/300-pending_work.patch
index 91781f92fd..81f03c532e 100644
--- a/package/kernel/mac80211/patches/300-pending_work.patch
+++ b/package/kernel/mac80211/patches/300-pending_work.patch
@@ -1013,13 +1013,13 @@
+
+ if (!ath_tid_has_buffered(tid))
+ return false;
-+
-+ INIT_LIST_HEAD(&bf_q);
- ath_tx_fill_desc(sc, bf, txq, aggr_len);
- ath_tx_txqaddbuf(sc, txq, &bf_q, false);
- } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
- status != ATH_AGGR_BAW_CLOSED);
++ INIT_LIST_HEAD(&bf_q);
++
+ bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ if (!bf)
+ return false;
@@ -1193,7 +1193,17 @@
list_del(&bf->list);
ath_tx_return_buffer(sc, bf);
-@@ -1665,25 +1820,27 @@ void ath_tx_cleanupq(struct ath_softc *s
+@@ -1630,6 +1785,9 @@ bool ath_drain_all_txq(struct ath_softc
+ if (!ATH_TXQ_SETUP(sc, i))
+ continue;
+
++ if (!sc->tx.txq[i].axq_depth)
++ continue;
++
+ if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum))
+ npend |= BIT(i);
+ }
+@@ -1665,25 +1823,27 @@ void ath_tx_cleanupq(struct ath_softc *s
*/
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
{
@@ -1226,7 +1236,7 @@
tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
list);
list_del(&tid->list);
-@@ -1692,17 +1849,17 @@ void ath_txq_schedule(struct ath_softc *
+@@ -1692,17 +1852,17 @@ void ath_txq_schedule(struct ath_softc *
if (tid->paused)
continue;
@@ -1248,7 +1258,7 @@
break;
}
-@@ -1711,9 +1868,17 @@ void ath_txq_schedule(struct ath_softc *
+@@ -1711,9 +1871,17 @@ void ath_txq_schedule(struct ath_softc *
list_add_tail(&ac->list, &txq->axq_acq);
}
@@ -1268,7 +1278,7 @@
}
rcu_read_unlock();
-@@ -1787,74 +1952,28 @@ static void ath_tx_txqaddbuf(struct ath_
+@@ -1787,74 +1955,28 @@ static void ath_tx_txqaddbuf(struct ath_
if (bf_is_ampdu_not_probing(bf))
txq->axq_ampdu_depth++;
@@ -1352,7 +1362,7 @@
bf->bf_next = NULL;
bf->bf_lastbf = bf;
-@@ -1911,8 +2030,7 @@ u8 ath_txchainmask_reduction(struct ath_
+@@ -1911,8 +2033,7 @@ u8 ath_txchainmask_reduction(struct ath_
struct ath_hw *ah = sc->sc_ah;
struct ath9k_channel *curchan = ah->curchan;
@@ -1362,7 +1372,7 @@
(chainmask == 0x7) && (rate < 0x90))
return 0x3;
else if (AR_SREV_9462(ah) && ath9k_hw_btcoex_is_enabled(ah) &&
-@@ -1985,6 +2103,7 @@ static int ath_tx_prepare(struct ieee802
+@@ -1985,6 +2106,7 @@ static int ath_tx_prepare(struct ieee802
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = txctl->sta;
struct ieee80211_vif *vif = info->control.vif;
@@ -1370,7 +1380,7 @@
struct ath_softc *sc = hw->priv;
int frmlen = skb->len + FCS_LEN;
int padpos, padsize;
-@@ -1992,6 +2111,10 @@ static int ath_tx_prepare(struct ieee802
+@@ -1992,6 +2114,10 @@ static int ath_tx_prepare(struct ieee802
/* NOTE: sta can be NULL according to net/mac80211.h */
if (sta)
txctl->an = (struct ath_node *)sta->drv_priv;
@@ -1381,7 +1391,7 @@
if (info->control.hw_key)
frmlen += info->control.hw_key->icv_len;
-@@ -2041,7 +2164,6 @@ int ath_tx_start(struct ieee80211_hw *hw
+@@ -2041,7 +2167,6 @@ int ath_tx_start(struct ieee80211_hw *hw
struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf;
@@ -1389,7 +1399,7 @@
int q;
int ret;
-@@ -2069,27 +2191,31 @@ int ath_tx_start(struct ieee80211_hw *hw
+@@ -2069,27 +2194,31 @@ int ath_tx_start(struct ieee80211_hw *hw
ath_txq_unlock(sc, txq);
txq = sc->tx.uapsdq;
ath_txq_lock(sc, txq);
@@ -1432,7 +1442,7 @@
if (txctl->paprd)
dev_kfree_skb_any(skb);
else
-@@ -2142,7 +2268,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
+@@ -2142,7 +2271,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw
bf->bf_lastbf = bf;
ath_set_rates(vif, NULL, bf);
@@ -1441,7 +1451,7 @@
duration += info.rates[0].PktDuration;
if (bf_tail)
bf_tail->bf_next = bf;
-@@ -2189,7 +2315,7 @@ static void ath_tx_complete(struct ath_s
+@@ -2189,7 +2318,7 @@ static void ath_tx_complete(struct ath_s
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
@@ -1450,7 +1460,7 @@
unsigned long flags;
ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
-@@ -2225,21 +2351,7 @@ static void ath_tx_complete(struct ath_s
+@@ -2225,21 +2354,7 @@ static void ath_tx_complete(struct ath_s
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
__skb_queue_tail(&txq->complete_q, skb);
@@ -1473,7 +1483,7 @@
}
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
-@@ -2360,8 +2472,7 @@ static void ath_tx_processq(struct ath_s
+@@ -2360,8 +2475,7 @@ static void ath_tx_processq(struct ath_s
if (list_empty(&txq->axq_q)) {
txq->axq_link = NULL;
@@ -1483,7 +1493,7 @@
break;
}
bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
-@@ -2375,7 +2486,7 @@ static void ath_tx_processq(struct ath_s
+@@ -2375,7 +2489,7 @@ static void ath_tx_processq(struct ath_s
* it with the STALE flag.
*/
bf_held = NULL;
@@ -1492,7 +1502,7 @@
bf_held = bf;
if (list_is_last(&bf_held->list, &txq->axq_q))
break;
-@@ -2399,7 +2510,7 @@ static void ath_tx_processq(struct ath_s
+@@ -2399,7 +2513,7 @@ static void ath_tx_processq(struct ath_s
* however leave the last descriptor back as the holding
* descriptor for hw.
*/
@@ -1501,7 +1511,7 @@
INIT_LIST_HEAD(&bf_head);
if (!list_is_singular(&lastbf->list))
list_cut_position(&bf_head,
-@@ -2470,7 +2581,7 @@ void ath_tx_edma_tasklet(struct ath_soft
+@@ -2470,7 +2584,7 @@ void ath_tx_edma_tasklet(struct ath_soft
}
bf = list_first_entry(fifo_list, struct ath_buf, list);
@@ -1510,7 +1520,7 @@
list_del(&bf->list);
ath_tx_return_buffer(sc, bf);
bf = list_first_entry(fifo_list, struct ath_buf, list);
-@@ -2492,7 +2603,7 @@ void ath_tx_edma_tasklet(struct ath_soft
+@@ -2492,7 +2606,7 @@ void ath_tx_edma_tasklet(struct ath_soft
ath_tx_txqaddbuf(sc, txq, &bf_q, true);
}
} else {
@@ -1519,7 +1529,7 @@
if (bf != lastbf)
list_cut_position(&bf_head, fifo_list,
lastbf->list.prev);
-@@ -2583,6 +2694,7 @@ void ath_tx_node_init(struct ath_softc *
+@@ -2583,6 +2697,7 @@ void ath_tx_node_init(struct ath_softc *
tid->paused = false;
tid->active = false;
__skb_queue_head_init(&tid->buf_q);
@@ -1527,7 +1537,7 @@
acno = TID_TO_WME_AC(tidno);
tid->ac = &an->ac[acno];
}
-@@ -2590,6 +2702,7 @@ void ath_tx_node_init(struct ath_softc *
+@@ -2590,6 +2705,7 @@ void ath_tx_node_init(struct ath_softc *
for (acno = 0, ac = &an->ac[acno];
acno < IEEE80211_NUM_ACS; acno++, ac++) {
ac->sched = false;
@@ -1537,7 +1547,61 @@
}
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -173,8 +173,7 @@ static void ath_restart_work(struct ath_
+@@ -82,6 +82,22 @@ static bool ath9k_setpower(struct ath_so
+ return ret;
+ }
+
++void ath_ps_full_sleep(unsigned long data)
++{
++ struct ath_softc *sc = (struct ath_softc *) data;
++ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
++ bool reset;
++
++ spin_lock(&common->cc_lock);
++ ath_hw_cycle_counters_update(common);
++ spin_unlock(&common->cc_lock);
++
++ ath9k_hw_setrxabort(sc->sc_ah, 1);
++ ath9k_hw_stopdmarecv(sc->sc_ah, &reset);
++
++ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
++}
++
+ void ath9k_ps_wakeup(struct ath_softc *sc)
+ {
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+@@ -92,6 +108,7 @@ void ath9k_ps_wakeup(struct ath_softc *s
+ if (++sc->ps_usecount != 1)
+ goto unlock;
+
++ del_timer_sync(&sc->sleep_timer);
+ power_mode = sc->sc_ah->power_mode;
+ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+
+@@ -117,17 +134,17 @@ void ath9k_ps_restore(struct ath_softc *
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ enum ath9k_power_mode mode;
+ unsigned long flags;
+- bool reset;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (--sc->ps_usecount != 0)
+ goto unlock;
+
+ if (sc->ps_idle) {
+- ath9k_hw_setrxabort(sc->sc_ah, 1);
+- ath9k_hw_stopdmarecv(sc->sc_ah, &reset);
+- mode = ATH9K_PM_FULL_SLEEP;
+- } else if (sc->ps_enabled &&
++ mod_timer(&sc->sleep_timer, jiffies + HZ / 10);
++ goto unlock;
++ }
++
++ if (sc->ps_enabled &&
+ !(sc->ps_flags & (PS_WAIT_FOR_BEACON |
+ PS_WAIT_FOR_CAB |
+ PS_WAIT_FOR_PSPOLL_DATA |
+@@ -173,8 +190,7 @@ static void ath_restart_work(struct ath_
{
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
@@ -1547,7 +1611,7 @@
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
-@@ -209,6 +208,7 @@ static bool ath_complete_reset(struct at
+@@ -209,6 +225,7 @@ static bool ath_complete_reset(struct at
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
unsigned long flags;
@@ -1555,7 +1619,7 @@
if (ath_startrecv(sc) != 0) {
ath_err(common, "Unable to restart recv logic\n");
-@@ -236,10 +236,16 @@ static bool ath_complete_reset(struct at
+@@ -236,10 +253,16 @@ static bool ath_complete_reset(struct at
}
work:
ath_restart_work(sc);
@@ -1575,7 +1639,7 @@
ieee80211_wake_queues(sc->hw);
-@@ -306,17 +312,91 @@ out:
+@@ -306,17 +329,91 @@ out:
* by reseting the chip. To accomplish this we must first cleanup any pending
* DMA, then restart stuff.
*/
@@ -1670,7 +1734,16 @@
}
static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
-@@ -543,21 +623,10 @@ chip_reset:
+@@ -400,6 +497,8 @@ void ath9k_tasklet(unsigned long data)
+ ath_tx_edma_tasklet(sc);
+ else
+ ath_tx_tasklet(sc);
++
++ wake_up(&sc->tx_wait);
+ }
+
+ ath9k_btcoex_handle_interrupt(sc, status);
+@@ -543,21 +642,10 @@ chip_reset:
static int ath_reset(struct ath_softc *sc)
{
@@ -1693,7 +1766,7 @@
ath9k_ps_restore(sc);
return r;
-@@ -599,7 +668,7 @@ static int ath9k_start(struct ieee80211_
+@@ -599,7 +687,7 @@ static int ath9k_start(struct ieee80211_
ath9k_ps_wakeup(sc);
mutex_lock(&sc->mutex);
@@ -1702,7 +1775,7 @@
/* Reset SERDES registers */
ath9k_hw_configpcipowersave(ah, false);
-@@ -802,7 +871,7 @@ static void ath9k_stop(struct ieee80211_
+@@ -802,7 +890,7 @@ static void ath9k_stop(struct ieee80211_
}
if (!ah->curchan)
@@ -1711,7 +1784,7 @@
ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
ath9k_hw_phy_disable(ah);
-@@ -821,7 +890,7 @@ static void ath9k_stop(struct ieee80211_
+@@ -821,7 +909,7 @@ static void ath9k_stop(struct ieee80211_
ath_dbg(common, CONFIG, "Driver halt\n");
}
@@ -1720,7 +1793,7 @@
{
switch (type) {
case NL80211_IFTYPE_AP:
-@@ -966,6 +1035,8 @@ static int ath9k_add_interface(struct ie
+@@ -966,6 +1054,8 @@ static int ath9k_add_interface(struct ie
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
@@ -1729,7 +1802,7 @@
mutex_lock(&sc->mutex);
-@@ -979,6 +1050,12 @@ static int ath9k_add_interface(struct ie
+@@ -979,6 +1069,12 @@ static int ath9k_add_interface(struct ie
if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif);
@@ -1742,7 +1815,7 @@
mutex_unlock(&sc->mutex);
return 0;
}
-@@ -1016,6 +1093,7 @@ static void ath9k_remove_interface(struc
+@@ -1016,6 +1112,7 @@ static void ath9k_remove_interface(struc
{
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -1750,7 +1823,7 @@
ath_dbg(common, CONFIG, "Detach Interface\n");
-@@ -1030,6 +1108,8 @@ static void ath9k_remove_interface(struc
+@@ -1030,6 +1127,8 @@ static void ath9k_remove_interface(struc
ath9k_calculate_summary_state(hw, NULL);
ath9k_ps_restore(sc);
@@ -1759,7 +1832,7 @@
mutex_unlock(&sc->mutex);
}
-@@ -1192,83 +1272,12 @@ static int ath9k_config(struct ieee80211
+@@ -1192,83 +1291,12 @@ static int ath9k_config(struct ieee80211
}
if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
@@ -1844,7 +1917,7 @@
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
-@@ -1374,9 +1383,6 @@ static void ath9k_sta_notify(struct ieee
+@@ -1374,9 +1402,6 @@ static void ath9k_sta_notify(struct ieee
struct ath_softc *sc = hw->priv;
struct ath_node *an = (struct ath_node *) sta->drv_priv;
@@ -1854,7 +1927,70 @@
switch (cmd) {
case STA_NOTIFY_SLEEP:
an->sleeping = true;
-@@ -2094,7 +2100,7 @@ static void ath9k_wow_add_pattern(struct
+@@ -1772,13 +1797,31 @@ static void ath9k_set_coverage_class(str
+ mutex_unlock(&sc->mutex);
+ }
+
++static bool ath9k_has_tx_pending(struct ath_softc *sc)
++{
++ int i, npend;
++
++ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
++ if (!ATH_TXQ_SETUP(sc, i))
++ continue;
++
++ if (!sc->tx.txq[i].axq_depth)
++ continue;
++
++ npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
++ if (npend)
++ break;
++ }
++
++ return !!npend;
++}
++
+ static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+ {
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+- int timeout = 200; /* ms */
+- int i, j;
++ int timeout = HZ / 5; /* 200 ms */
+ bool drain_txq;
+
+ mutex_lock(&sc->mutex);
+@@ -1796,25 +1839,9 @@ static void ath9k_flush(struct ieee80211
+ return;
+ }
+
+- for (j = 0; j < timeout; j++) {
+- bool npend = false;
+-
+- if (j)
+- usleep_range(1000, 2000);
+-
+- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+- if (!ATH_TXQ_SETUP(sc, i))
+- continue;
+-
+- npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
+-
+- if (npend)
+- break;
+- }
+-
+- if (!npend)
+- break;
+- }
++ if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc),
++ timeout) > 0)
++ drop = false;
+
+ if (drop) {
+ ath9k_ps_wakeup(sc);
+@@ -2094,7 +2121,7 @@ static void ath9k_wow_add_pattern(struct
{
struct ath_hw *ah = sc->sc_ah;
struct ath9k_wow_pattern *wow_pattern = NULL;
@@ -3517,7 +3653,15 @@
int av_bslot;
bool primary_sta_vif;
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
-@@ -585,19 +588,14 @@ static inline void ath_fill_led_pin(stru
+@@ -459,6 +462,7 @@ void ath_check_ani(struct ath_softc *sc)
+ int ath_update_survey_stats(struct ath_softc *sc);
+ void ath_update_survey_nf(struct ath_softc *sc, int channel);
+ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
++void ath_ps_full_sleep(unsigned long data);
+
+ /**********/
+ /* BTCOEX */
+@@ -585,19 +589,14 @@ static inline void ath_fill_led_pin(stru
#define ATH_ANT_DIV_COMB_MAX_COUNT 100
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
@@ -3539,7 +3683,7 @@
struct ath_ant_comb {
u16 count;
u16 total_pkt_count;
-@@ -614,27 +612,36 @@ struct ath_ant_comb {
+@@ -614,27 +613,36 @@ struct ath_ant_comb {
int rssi_first;
int rssi_second;
int rssi_third;
@@ -3582,7 +3726,23 @@
/*
* Default cache line size, in bytes.
-@@ -926,7 +933,6 @@ void ath9k_deinit_device(struct ath_soft
+@@ -717,6 +725,7 @@ struct ath_softc {
+ struct work_struct hw_check_work;
+ struct work_struct hw_reset_work;
+ struct completion paprd_complete;
++ wait_queue_head_t tx_wait;
+
+ unsigned int hw_busy_count;
+ unsigned long sc_flags;
+@@ -753,6 +762,7 @@ struct ath_softc {
+ struct delayed_work tx_complete_work;
+ struct delayed_work hw_pll_work;
+ struct timer_list rx_poll_timer;
++ struct timer_list sleep_timer;
+
+ #ifdef CPTCFG_ATH9K_BTCOEX_SUPPORT
+ struct ath_btcoex btcoex;
+@@ -926,7 +936,6 @@ void ath9k_deinit_device(struct ath_soft
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath9k_reload_chainmask_settings(struct ath_softc *sc);
@@ -5453,15 +5613,18 @@
struct ath_common *common;
int ret = 0, i;
int csz = 0;
-@@ -600,6 +650,7 @@ static int ath9k_init_softc(u16 devid, s
+@@ -600,8 +650,10 @@ static int ath9k_init_softc(u16 devid, s
ah->reg_ops.rmw = ath9k_reg_rmw;
atomic_set(&ah->intr_ref_cnt, -1);
sc->sc_ah = ah;
+ pCap = &ah->caps;
sc->dfs_detector = dfs_pattern_detector_init(ah, NL80211_DFS_UNSET);
++ init_waitqueue_head(&sc->tx_wait);
-@@ -631,11 +682,15 @@ static int ath9k_init_softc(u16 devid, s
+ if (!pdata) {
+ ah->ah_flags |= AH_USE_EEPROM;
+@@ -631,11 +683,15 @@ static int ath9k_init_softc(u16 devid, s
ath9k_init_platform(sc);
/*
@@ -5481,7 +5644,15 @@
spin_lock_init(&common->cc_lock);
-@@ -710,13 +765,15 @@ static void ath9k_init_band_txpower(stru
+@@ -646,6 +702,7 @@ static int ath9k_init_softc(u16 devid, s
+ tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
+ (unsigned long)sc);
+
++ setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc);
+ INIT_WORK(&sc->hw_reset_work, ath_reset_work);
+ INIT_WORK(&sc->hw_check_work, ath_hw_check);
+ INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
+@@ -710,13 +767,15 @@ static void ath9k_init_band_txpower(stru
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
struct ath_hw *ah = sc->sc_ah;
@@ -5498,7 +5669,7 @@
ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true);
}
}
-@@ -802,7 +859,8 @@ void ath9k_set_hw_capab(struct ath_softc
+@@ -802,7 +861,8 @@ void ath9k_set_hw_capab(struct ath_softc
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
@@ -5508,6 +5679,14 @@
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+@@ -968,6 +1028,7 @@ static void ath9k_deinit_softc(struct at
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+
++ del_timer_sync(&sc->sleep_timer);
+ ath9k_hw_deinit(sc->sc_ah);
+ if (sc->dfs_detector != NULL)
+ sc->dfs_detector->exit(sc->dfs_detector);
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1878,7 +1878,8 @@ void *carl9170_alloc(size_t priv_size)