diff options
author | Felix Fietkau <nbd@openwrt.org> | 2013-10-14 19:38:42 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2013-10-14 19:38:42 +0000 |
commit | f1ea6d3c2dc2b222abcf607d12f8889295718c54 (patch) | |
tree | 353d02183cc1639ae0a3858b476f66f7958fe4fa /package/kernel/mac80211/patches/300-pending_work.patch | |
parent | d21810a298abcfb9b957502f7e93063ac2cc057c (diff) | |
download | upstream-f1ea6d3c2dc2b222abcf607d12f8889295718c54.tar.gz upstream-f1ea6d3c2dc2b222abcf607d12f8889295718c54.tar.bz2 upstream-f1ea6d3c2dc2b222abcf607d12f8889295718c54.zip |
ath9k: add some more pending fixes / optimizations
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
SVN-Revision: 38398
Diffstat (limited to 'package/kernel/mac80211/patches/300-pending_work.patch')
-rw-r--r-- | package/kernel/mac80211/patches/300-pending_work.patch | 265 |
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) |