Merge ath-next from ath.git
authorKalle Valo <kvalo@codeaurora.org>
Wed, 16 Dec 2015 14:28:20 +0000 (16:28 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Wed, 16 Dec 2015 14:28:20 +0000 (16:28 +0200)
Major changes:

ath9k

* add random number generator support (CONFIG_ATH9K_HWRNG)

25 files changed:
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/htc_mbox.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/channel.c
drivers/net/wireless/ath/ath9k/common-beacon.c
drivers/net/wireless/ath/ath9k/eeprom.c
drivers/net/wireless/ath/ath9k/eeprom.h
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/rng.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/wil6210/main.c
drivers/net/wireless/ath/wil6210/wmi.c

index 39fe4f3..2bdf540 100644 (file)
@@ -1139,7 +1139,7 @@ static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,
 {
        struct ath10k *ar = file->private_data;
        char buf[64];
-       u8 amsdu = 3, ampdu = 64;
+       u8 amsdu, ampdu;
        unsigned int len;
 
        mutex_lock(&ar->conf_mutex);
index bcb364d..b4bdeb0 100644 (file)
@@ -250,7 +250,8 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
        lockdep_assert_held(&ar->conf_mutex);
 
        if (WARN_ON(arvif->vif->type != NL80211_IFTYPE_AP &&
-                   arvif->vif->type != NL80211_IFTYPE_ADHOC))
+                   arvif->vif->type != NL80211_IFTYPE_ADHOC &&
+                   arvif->vif->type != NL80211_IFTYPE_MESH_POINT))
                return -EINVAL;
 
        spin_lock_bh(&ar->data_lock);
index 2a44d63..a7c3d29 100644 (file)
@@ -4312,34 +4312,58 @@ void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb)
        ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
 }
 
-static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
-                                    u32 num_units, u32 unit_len)
+static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id,
+                                 u32 num_units, u32 unit_len)
 {
        dma_addr_t paddr;
-       u32 pool_size;
+       u32 pool_size = 0;
        int idx = ar->wmi.num_mem_chunks;
+       void *vaddr = NULL;
 
-       pool_size = num_units * round_up(unit_len, 4);
+       if (ar->wmi.num_mem_chunks == ARRAY_SIZE(ar->wmi.mem_chunks))
+               return -ENOMEM;
 
-       if (!pool_size)
-               return -EINVAL;
+       while (!vaddr && num_units) {
+               pool_size = num_units * round_up(unit_len, 4);
+               if (!pool_size)
+                       return -EINVAL;
 
-       ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev,
-                                                          pool_size,
-                                                          &paddr,
-                                                          GFP_KERNEL);
-       if (!ar->wmi.mem_chunks[idx].vaddr) {
-               ath10k_warn(ar, "failed to allocate memory chunk\n");
-               return -ENOMEM;
+               vaddr = kzalloc(pool_size, GFP_KERNEL | __GFP_NOWARN);
+               if (!vaddr)
+                       num_units /= 2;
        }
 
-       memset(ar->wmi.mem_chunks[idx].vaddr, 0, pool_size);
+       if (!num_units)
+               return -ENOMEM;
+
+       paddr = dma_map_single(ar->dev, vaddr, pool_size, DMA_TO_DEVICE);
+       if (dma_mapping_error(ar->dev, paddr)) {
+               kfree(vaddr);
+               return -ENOMEM;
+       }
 
+       ar->wmi.mem_chunks[idx].vaddr = vaddr;
        ar->wmi.mem_chunks[idx].paddr = paddr;
        ar->wmi.mem_chunks[idx].len = pool_size;
        ar->wmi.mem_chunks[idx].req_id = req_id;
        ar->wmi.num_mem_chunks++;
 
+       return num_units;
+}
+
+static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
+                                    u32 num_units, u32 unit_len)
+{
+       int ret;
+
+       while (num_units) {
+               ret = ath10k_wmi_alloc_chunk(ar, req_id, num_units, unit_len);
+               if (ret < 0)
+                       return ret;
+
+               num_units -= ret;
+       }
+
        return 0;
 }
 
@@ -7717,10 +7741,11 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar)
 
        /* free the host memory chunks requested by firmware */
        for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
-               dma_free_coherent(ar->dev,
-                                 ar->wmi.mem_chunks[i].len,
-                                 ar->wmi.mem_chunks[i].vaddr,
-                                 ar->wmi.mem_chunks[i].paddr);
+               dma_unmap_single(ar->dev,
+                                ar->wmi.mem_chunks[i].paddr,
+                                ar->wmi.mem_chunks[i].len,
+                                DMA_TO_DEVICE);
+               kfree(ar->wmi.mem_chunks[i].vaddr);
        }
 
        ar->wmi.num_mem_chunks = 0;
index 342563a..3d946d8 100644 (file)
@@ -767,7 +767,7 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
        if (info->flags & IEEE80211_TX_CTL_NO_ACK)
                flags |= AR5K_TXDESC_NOACK;
 
-       rc_flags = info->control.rates[0].flags;
+       rc_flags = bf->rates[0].flags;
 
        hw_rate = ath5k_get_rate_hw_value(ah->hw, info, bf, 0);
 
index 81ac8c5..7f3f94f 100644 (file)
@@ -3930,8 +3930,8 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
                ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
                ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
                ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff;
-               ar->hw.tx_ant = 2;
-               ar->hw.rx_ant = 2;
+               ar->hw.tx_ant = 0x3; /* mask, 2 antenna */
+               ar->hw.rx_ant = 0x3;
        } else {
                ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
                ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
index fffb65b..65c31da 100644 (file)
@@ -2222,8 +2222,9 @@ int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target,
        }
 
        if (status) {
-               ath6kl_err("failed to get pending recv messages: %d\n",
-                          status);
+               if (status != -ECANCELED)
+                       ath6kl_err("failed to get pending recv messages: %d\n",
+                                  status);
 
                /* cleanup any packets in sync completion queue */
                list_for_each_entry_safe(packets, tmp_pkt, &comp_pktq, list) {
index 6ae0734..da557dc 100644 (file)
@@ -954,8 +954,10 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
        snprintf(filename, sizeof(filename), "%s/%s", ar->hw.fw.dir, name);
 
        ret = request_firmware(&fw, filename, ar->dev);
-       if (ret)
+       if (ret) {
+               ath6kl_err("Failed request firmware, rv: %d\n", ret);
                return ret;
+       }
 
        data = fw->data;
        len = fw->size;
@@ -964,11 +966,15 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
        magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1;
 
        if (len < magic_len) {
+               ath6kl_err("Magic length is invalid, len: %zd  magic_len: %zd\n",
+                          len, magic_len);
                ret = -EINVAL;
                goto out;
        }
 
        if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) {
+               ath6kl_err("Magic is invalid, magic_len: %zd\n",
+                          magic_len);
                ret = -EINVAL;
                goto out;
        }
@@ -987,7 +993,12 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                len -= sizeof(*hdr);
                data += sizeof(*hdr);
 
+               ath6kl_dbg(ATH6KL_DBG_BOOT, "ie-id: %d  len: %zd (0x%zx)\n",
+                          ie_id, ie_len, ie_len);
+
                if (len < ie_len) {
+                       ath6kl_err("IE len is invalid, len: %zd  ie_len: %zd  ie-id: %d\n",
+                                  len, ie_len, ie_id);
                        ret = -EINVAL;
                        goto out;
                }
@@ -1008,6 +1019,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                        ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL);
 
                        if (ar->fw_otp == NULL) {
+                               ath6kl_err("fw_otp cannot be allocated\n");
                                ret = -ENOMEM;
                                goto out;
                        }
@@ -1025,6 +1037,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                        ar->fw = vmalloc(ie_len);
 
                        if (ar->fw == NULL) {
+                               ath6kl_err("fw storage cannot be allocated, len: %zd\n", ie_len);
                                ret = -ENOMEM;
                                goto out;
                        }
@@ -1039,6 +1052,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                        ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL);
 
                        if (ar->fw_patch == NULL) {
+                               ath6kl_err("fw_patch storage cannot be allocated, len: %zd\n", ie_len);
                                ret = -ENOMEM;
                                goto out;
                        }
index fee0cad..40fa915 100644 (file)
@@ -176,3 +176,14 @@ config ATH9K_HTC_DEBUGFS
        depends on ATH9K_HTC && DEBUG_FS
        ---help---
          Say Y, if you need access to ath9k_htc's statistics.
+
+config ATH9K_HWRNG
+       bool "Random number generator support"
+       depends on ATH9K && (HW_RANDOM = y || HW_RANDOM = ATH9K)
+       default y
+       ---help---
+         This option incorporates the ADC register output as a source of
+         randomness into Linux entropy pool (/dev/urandom and /dev/random)
+
+         Say Y, feeds the entropy directly from the WiFi driver to the input
+         pool.
index ecda613..76f9dc3 100644 (file)
@@ -15,6 +15,7 @@ ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
 ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o
 ath9k-$(CONFIG_ATH9K_TX99) += tx99.o
 ath9k-$(CONFIG_ATH9K_WOW) += wow.o
+ath9k-$(CONFIG_ATH9K_HWRNG) += rng.o
 
 ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
 
index b42f4a9..5294595 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/leds.h>
 #include <linux/completion.h>
 #include <linux/time.h>
+#include <linux/hw_random.h>
 
 #include "common.h"
 #include "debug.h"
@@ -981,6 +982,7 @@ struct ath_softc {
        struct ath_offchannel offchannel;
        struct ath_chanctx *next_chan;
        struct completion go_beacon;
+       struct timespec last_event_time;
 #endif
 
        unsigned long driver_data;
@@ -1040,6 +1042,11 @@ struct ath_softc {
        u32 wow_intr_before_sleep;
        bool force_wow;
 #endif
+
+#ifdef CONFIG_ATH9K_HWRNG
+       u32 rng_last;
+       struct task_struct *rng_task;
+#endif
 };
 
 /********/
@@ -1062,6 +1069,22 @@ static inline int ath9k_tx99_send(struct ath_softc *sc,
 }
 #endif /* CONFIG_ATH9K_TX99 */
 
+/***************************/
+/* Random Number Generator */
+/***************************/
+#ifdef CONFIG_ATH9K_HWRNG
+void ath9k_rng_start(struct ath_softc *sc);
+void ath9k_rng_stop(struct ath_softc *sc);
+#else
+static inline void ath9k_rng_start(struct ath_softc *sc)
+{
+}
+
+static inline void ath9k_rng_stop(struct ath_softc *sc)
+{
+}
+#endif
+
 static inline void ath_read_cachesize(struct ath_common *common, int *csz)
 {
        common->bus_ops->read_cachesize(common, csz);
index f50a6bc..5cf0cd7 100644 (file)
@@ -148,7 +148,8 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
 
        ath_assign_seq(common, skb);
 
-       if (vif->p2p)
+       /* Always assign NOA attr when MCC enabled */
+       if (ath9k_is_chanctx_enabled())
                ath9k_beacon_add_noa(sc, avp, skb);
 
        bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
index 90f5773..50e614b 100644 (file)
@@ -226,6 +226,20 @@ static const char *chanctx_state_string(enum ath_chanctx_state state)
        }
 }
 
+static const u32 chanctx_event_delta(struct ath_softc *sc)
+{
+       u64 ms;
+       struct timespec ts, *old;
+
+       getrawmonotonic(&ts);
+       old = &sc->last_event_time;
+       ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+       ms -= old->tv_sec * 1000 + old->tv_nsec / 1000000;
+       sc->last_event_time = ts;
+
+       return (u32)ms;
+}
+
 void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -356,14 +370,16 @@ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_hw *ah = sc->sc_ah;
+       unsigned long timeout;
 
        ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
        tsf_time -= ath9k_hw_gettsf32(ah);
-       tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
-       mod_timer(&sc->sched.timer, jiffies + tsf_time);
+       timeout = msecs_to_jiffies(tsf_time / 1000) + 1;
+       mod_timer(&sc->sched.timer, jiffies + timeout);
 
        ath_dbg(common, CHAN_CTX,
-               "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
+               "Setup chanctx timer with timeout: %d (%d) ms\n",
+               tsf_time / 1000, jiffies_to_msecs(timeout));
 }
 
 static void ath_chanctx_handle_bmiss(struct ath_softc *sc,
@@ -403,7 +419,7 @@ static void ath_chanctx_offchannel_noa(struct ath_softc *sc,
        avp->offchannel_duration = sc->sched.offchannel_duration;
 
        ath_dbg(common, CHAN_CTX,
-               "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
+               "offchannel noa_duration: %d, noa_start: %u, noa_index: %d\n",
                avp->offchannel_duration,
                avp->offchannel_start,
                avp->noa_index);
@@ -443,7 +459,7 @@ static void ath_chanctx_set_periodic_noa(struct ath_softc *sc,
                avp->periodic_noa = true;
 
        ath_dbg(common, CHAN_CTX,
-               "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+               "noa_duration: %d, noa_start: %u, noa_index: %d, periodic: %d\n",
                avp->noa_duration,
                avp->noa_start,
                avp->noa_index,
@@ -464,7 +480,7 @@ static void ath_chanctx_set_oneshot_noa(struct ath_softc *sc,
        avp->noa_duration = duration + sc->sched.channel_switch_time;
 
        ath_dbg(common, CHAN_CTX,
-               "oneshot noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+               "oneshot noa_duration: %d, noa_start: %u, noa_index: %d, periodic: %d\n",
                avp->noa_duration,
                avp->noa_start,
                avp->noa_index,
@@ -487,10 +503,11 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
 
        spin_lock_bh(&sc->chan_lock);
 
-       ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s\n",
+       ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s, delta: %u ms\n",
                sc->cur_chan->chandef.center_freq1,
                chanctx_event_string(ev),
-               chanctx_state_string(sc->sched.state));
+               chanctx_state_string(sc->sched.state),
+               chanctx_event_delta(sc));
 
        switch (ev) {
        case ATH_CHANCTX_EVENT_BEACON_PREPARE:
@@ -1099,6 +1116,7 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
                        nullfunc->frame_control |=
                                cpu_to_le16(IEEE80211_FCTL_PM);
 
+               skb->priority = 7;
                skb_set_queue_mapping(skb, IEEE80211_AC_VO);
                if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
                        dev_kfree_skb_any(skb);
@@ -1401,8 +1419,9 @@ void ath9k_chanctx_wake_queues(struct ath_softc *sc, struct ath_chanctx *ctx)
 
 static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
 {
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_hw *ah = sc->sc_ah;
-       s32 tsf, target_tsf;
+       u32 tsf, target_tsf;
 
        if (!avp || !avp->noa.has_next_tsf)
                return;
@@ -1414,11 +1433,17 @@ static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
        target_tsf = avp->noa.next_tsf;
        if (!avp->noa.absent)
                target_tsf -= ATH_P2P_PS_STOP_TIME;
+       else
+               target_tsf += ATH_P2P_PS_STOP_TIME;
 
        if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
                target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
 
-       ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
+       ath_dbg(common, CHAN_CTX, "%s absent %d tsf 0x%08X next_tsf 0x%08X (%dms)\n",
+               __func__, avp->noa.absent, tsf, target_tsf,
+               (target_tsf - tsf) / 1000);
+
+       ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, target_tsf, 1000000);
 }
 
 static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
@@ -1433,6 +1458,10 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
                return;
 
        sc->p2p_ps_vif = avp;
+
+       if (sc->ps_flags & PS_BEACON_SYNC)
+               return;
+
        tsf = ath9k_hw_gettsf32(sc->sc_ah);
        ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
        ath9k_update_p2p_ps_timer(sc, avp);
@@ -1495,6 +1524,8 @@ void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
 
        noa->index = avp->noa_index;
        noa->oppps_ctwindow = ath9k_get_ctwin(sc, avp);
+       if (noa->oppps_ctwindow)
+               noa->oppps_ctwindow |= BIT(7);
 
        if (avp->noa_duration) {
                if (avp->periodic_noa) {
@@ -1536,6 +1567,8 @@ void ath9k_p2p_ps_timer(void *priv)
        tsf = ath9k_hw_gettsf32(sc->sc_ah);
        if (!avp->noa.absent)
                tsf += ATH_P2P_PS_STOP_TIME;
+       else
+               tsf -= ATH_P2P_PS_STOP_TIME;
 
        if (!avp->noa.has_next_tsf ||
            avp->noa.next_tsf - tsf > BIT(31))
@@ -1571,8 +1604,7 @@ void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
 
        spin_lock_bh(&sc->sc_pcu_lock);
        spin_lock_irqsave(&sc->sc_pm_lock, flags);
-       if (!(sc->ps_flags & PS_BEACON_SYNC))
-               ath9k_update_p2p_ps(sc, vif);
+       ath9k_update_p2p_ps(sc, vif);
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
        spin_unlock_bh(&sc->sc_pcu_lock);
 }
index 6ad4447..01d6d32 100644 (file)
 
 #define FUDGE 2
 
-/* Calculate the modulo of a 64 bit TSF snapshot with a TU divisor */
-static u32 ath9k_mod_tsf64_tu(u64 tsf, u32 div_tu)
-{
-       u32 tsf_mod, tsf_hi, tsf_lo, mod_hi, mod_lo;
-
-       tsf_mod = tsf & (BIT(10) - 1);
-       tsf_hi = tsf >> 32;
-       tsf_lo = ((u32) tsf) >> 10;
-
-       mod_hi = tsf_hi % div_tu;
-       mod_lo = ((mod_hi << 22) + tsf_lo) % div_tu;
-
-       return (mod_lo << 10) | tsf_mod;
-}
-
 static u32 ath9k_get_next_tbtt(struct ath_hw *ah, u64 tsf,
                               unsigned int interval)
 {
-       unsigned int offset;
+       unsigned int offset, divisor;
 
        tsf += TU_TO_USEC(FUDGE + ah->config.sw_beacon_response_time);
-       offset = ath9k_mod_tsf64_tu(tsf, interval);
+       divisor = TU_TO_USEC(interval);
+       div_u64_rem(tsf, divisor, &offset);
 
-       return (u32) tsf + TU_TO_USEC(interval) - offset;
+       return (u32) tsf + divisor - offset;
 }
 
 /*
index cc81482..f8c5065 100644 (file)
@@ -138,6 +138,80 @@ bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
        return ret;
 }
 
+int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
+{
+       u16 magic;
+       u16 *eepdata;
+       int i;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+               ath_err(common, "Reading Magic # failed\n");
+               return -EIO;
+       }
+
+       if (magic == AR5416_EEPROM_MAGIC) {
+               *swap_needed = false;
+       } else if (swab16(magic) == AR5416_EEPROM_MAGIC) {
+               if (ah->ah_flags & AH_NO_EEP_SWAP) {
+                       ath_info(common,
+                                "Ignoring endianness difference in EEPROM magic bytes.\n");
+
+                       *swap_needed = false;
+               } else {
+                       *swap_needed = true;
+               }
+       } else {
+               ath_err(common,
+                       "Invalid EEPROM Magic (0x%04x).\n", magic);
+               return -EINVAL;
+       }
+
+       eepdata = (u16 *)(&ah->eeprom);
+
+       if (*swap_needed) {
+               ath_dbg(common, EEPROM,
+                       "EEPROM Endianness is not native.. Changing.\n");
+
+               for (i = 0; i < size; i++)
+                       eepdata[i] = swab16(eepdata[i]);
+       }
+
+       return 0;
+}
+
+bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
+{
+       u32 i, sum = 0;
+       u16 *eepdata = (u16 *)(&ah->eeprom);
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       for (i = 0; i < size; i++)
+               sum ^= eepdata[i];
+
+       if (sum != 0xffff) {
+               ath_err(common, "Bad EEPROM checksum 0x%x\n", sum);
+               return false;
+       }
+
+       return true;
+}
+
+bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (ah->eep_ops->get_eeprom_ver(ah) != version ||
+           ah->eep_ops->get_eeprom_rev(ah) < minrev) {
+               ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n",
+                       ah->eep_ops->get_eeprom_ver(ah),
+                       ah->eep_ops->get_eeprom_rev(ah));
+               return -EINVAL;
+       }
+
+       return true;
+}
+
 void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
                             u8 *pVpdList, u16 numIntercepts,
                             u8 *pRetVpdList)
index 40d4f62..4465c65 100644 (file)
@@ -664,6 +664,9 @@ int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
 bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
                                    u16 *indexL, u16 *indexR);
 bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data);
+int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size);
+bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size);
+bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev);
 void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
                                  int eep_start_loc, int size);
 void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
index 4773da6..5da0826 100644 (file)
@@ -177,74 +177,30 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
 }
 #endif
 
-
-#undef SIZE_EEPROM_4K
-
 static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
 {
-#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
-       struct ath_common *common = ath9k_hw_common(ah);
        struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
-       u16 *eepdata, temp, magic, magic2;
-       u32 sum = 0, el;
-       bool need_swap = false;
-       int i, addr;
+       u32 el;
+       bool need_swap;
+       int i, err;
 
-
-       if (!ath9k_hw_use_flash(ah)) {
-               if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
-                                        &magic)) {
-                       ath_err(common, "Reading Magic # failed\n");
-                       return false;
-               }
-
-               ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
-
-               if (magic != AR5416_EEPROM_MAGIC) {
-                       magic2 = swab16(magic);
-
-                       if (magic2 == AR5416_EEPROM_MAGIC) {
-                               need_swap = true;
-                               eepdata = (u16 *) (&ah->eeprom);
-
-                               for (addr = 0; addr < EEPROM_4K_SIZE; addr++) {
-                                       temp = swab16(*eepdata);
-                                       *eepdata = temp;
-                                       eepdata++;
-                               }
-                       } else {
-                               ath_err(common,
-                                       "Invalid EEPROM Magic. Endianness mismatch.\n");
-                               return -EINVAL;
-                       }
-               }
-       }
-
-       ath_dbg(common, EEPROM, "need_swap = %s\n",
-               need_swap ? "True" : "False");
+       err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_4K);
+       if (err)
+               return err;
 
        if (need_swap)
-               el = swab16(ah->eeprom.map4k.baseEepHeader.length);
-       else
-               el = ah->eeprom.map4k.baseEepHeader.length;
-
-       if (el > sizeof(struct ar5416_eeprom_4k))
-               el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16);
+               el = swab16(eep->baseEepHeader.length);
        else
-               el = el / sizeof(u16);
+               el = eep->baseEepHeader.length;
 
-       eepdata = (u16 *)(&ah->eeprom);
-
-       for (i = 0; i < el; i++)
-               sum ^= *eepdata++;
+       el = min(el / sizeof(u16), SIZE_EEPROM_4K);
+       if (!ath9k_hw_nvram_validate_checksum(ah, el))
+               return -EINVAL;
 
        if (need_swap) {
                u32 integer;
                u16 word;
 
-               ath_dbg(common, EEPROM,
-                       "EEPROM Endianness is not native.. Changing\n");
-
                word = swab16(eep->baseEepHeader.length);
                eep->baseEepHeader.length = word;
 
@@ -283,17 +239,15 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
                }
        }
 
-       if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
-           ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
-               ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
-                       sum, ah->eep_ops->get_eeprom_ver(ah));
+       if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER,
+           AR5416_EEP_NO_BACK_VER))
                return -EINVAL;
-       }
 
        return 0;
-#undef EEPROM_4K_SIZE
 }
 
+#undef SIZE_EEPROM_4K
+
 static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
                                  enum eeprom_param param)
 {
index 6ca33df..1a019a3 100644 (file)
@@ -177,59 +177,24 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
 
 static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
 {
-       u32 sum = 0, el, integer;
-       u16 temp, word, magic, magic2, *eepdata;
-       int i, addr;
-       bool need_swap = false;
+       u32 el, integer;
+       u16 word;
+       int i, err;
+       bool need_swap;
        struct ar9287_eeprom *eep = &ah->eeprom.map9287;
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       if (!ath9k_hw_use_flash(ah)) {
-               if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
-                                        &magic)) {
-                       ath_err(common, "Reading Magic # failed\n");
-                       return false;
-               }
-
-               ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
-
-               if (magic != AR5416_EEPROM_MAGIC) {
-                       magic2 = swab16(magic);
-
-                       if (magic2 == AR5416_EEPROM_MAGIC) {
-                               need_swap = true;
-                               eepdata = (u16 *)(&ah->eeprom);
-
-                               for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
-                                       temp = swab16(*eepdata);
-                                       *eepdata = temp;
-                                       eepdata++;
-                               }
-                       } else {
-                               ath_err(common,
-                                       "Invalid EEPROM Magic. Endianness mismatch.\n");
-                               return -EINVAL;
-                       }
-               }
-       }
 
-       ath_dbg(common, EEPROM, "need_swap = %s\n",
-               need_swap ? "True" : "False");
+       err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_AR9287);
+       if (err)
+               return err;
 
        if (need_swap)
-               el = swab16(ah->eeprom.map9287.baseEepHeader.length);
-       else
-               el = ah->eeprom.map9287.baseEepHeader.length;
-
-       if (el > sizeof(struct ar9287_eeprom))
-               el = sizeof(struct ar9287_eeprom) / sizeof(u16);
+               el = swab16(eep->baseEepHeader.length);
        else
-               el = el / sizeof(u16);
-
-       eepdata = (u16 *)(&ah->eeprom);
+               el = eep->baseEepHeader.length;
 
-       for (i = 0; i < el; i++)
-               sum ^= *eepdata++;
+       el = min(el / sizeof(u16), SIZE_EEPROM_AR9287);
+       if (!ath9k_hw_nvram_validate_checksum(ah, el))
+               return -EINVAL;
 
        if (need_swap) {
                word = swab16(eep->baseEepHeader.length);
@@ -270,16 +235,15 @@ static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
                }
        }
 
-       if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER
-           || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
-               ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
-                       sum, ah->eep_ops->get_eeprom_ver(ah));
+       if (!ath9k_hw_nvram_check_version(ah, AR9287_EEP_VER,
+           AR5416_EEP_NO_BACK_VER))
                return -EINVAL;
-       }
 
        return 0;
 }
 
+#undef SIZE_EEPROM_AR9287
+
 static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
                                      enum eeprom_param param)
 {
index 056f516..959682f 100644 (file)
@@ -126,8 +126,6 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
                return __ath9k_hw_def_fill_eeprom(ah);
 }
 
-#undef SIZE_EEPROM_DEF
-
 #if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS)
 static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size,
                                       struct modal_eep_header *modal_hdr)
@@ -257,59 +255,31 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
 }
 #endif
 
-
 static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
 {
        struct ar5416_eeprom_def *eep = &ah->eeprom.def;
        struct ath_common *common = ath9k_hw_common(ah);
-       u16 *eepdata, temp, magic;
-       u32 sum = 0, el;
-       bool need_swap = false;
-       int i, addr, size;
-
-       if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
-               ath_err(common, "Reading Magic # failed\n");
-               return false;
-       }
-
-       if (swab16(magic) == AR5416_EEPROM_MAGIC &&
-           !(ah->ah_flags & AH_NO_EEP_SWAP)) {
-               size = sizeof(struct ar5416_eeprom_def);
-               need_swap = true;
-               eepdata = (u16 *) (&ah->eeprom);
-
-               for (addr = 0; addr < size / sizeof(u16); addr++) {
-                       temp = swab16(*eepdata);
-                       *eepdata = temp;
-                       eepdata++;
-               }
-       }
+       u32 el;
+       bool need_swap;
+       int i, err;
 
-       ath_dbg(common, EEPROM, "need_swap = %s\n",
-               need_swap ? "True" : "False");
+       err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_DEF);
+       if (err)
+               return err;
 
        if (need_swap)
-               el = swab16(ah->eeprom.def.baseEepHeader.length);
+               el = swab16(eep->baseEepHeader.length);
        else
-               el = ah->eeprom.def.baseEepHeader.length;
+               el = eep->baseEepHeader.length;
 
-       if (el > sizeof(struct ar5416_eeprom_def))
-               el = sizeof(struct ar5416_eeprom_def) / sizeof(u16);
-       else
-               el = el / sizeof(u16);
-
-       eepdata = (u16 *)(&ah->eeprom);
-
-       for (i = 0; i < el; i++)
-               sum ^= *eepdata++;
+       el = min(el / sizeof(u16), SIZE_EEPROM_DEF);
+       if (!ath9k_hw_nvram_validate_checksum(ah, el))
+               return -EINVAL;
 
        if (need_swap) {
                u32 integer, j;
                u16 word;
 
-               ath_dbg(common, EEPROM,
-                       "EEPROM Endianness is not native.. Changing.\n");
-
                word = swab16(eep->baseEepHeader.length);
                eep->baseEepHeader.length = word;
 
@@ -356,12 +326,9 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
                }
        }
 
-       if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
-           ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
-               ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
-                       sum, ah->eep_ops->get_eeprom_ver(ah));
+       if (!ath9k_hw_nvram_check_version(ah, AR5416_EEP_VER,
+           AR5416_EEP_NO_BACK_VER))
                return -EINVAL;
-       }
 
        /* Enable fixup for AR_AN_TOP2 if necessary */
        if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
@@ -376,6 +343,8 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
        return 0;
 }
 
+#undef SIZE_EEPROM_DEF
+
 static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
                                   enum eeprom_param param)
 {
index 41382f8..257f46e 100644 (file)
@@ -2299,10 +2299,10 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        else
                nextTbtt = bs->bs_nexttbtt;
 
-       ath_dbg(common, BEACON, "next DTIM %d\n", bs->bs_nextdtim);
-       ath_dbg(common, BEACON, "next beacon %d\n", nextTbtt);
-       ath_dbg(common, BEACON, "beacon period %d\n", beaconintval);
-       ath_dbg(common, BEACON, "DTIM period %d\n", dtimperiod);
+       ath_dbg(common, BEACON, "next DTIM %u\n", bs->bs_nextdtim);
+       ath_dbg(common, BEACON, "next beacon %u\n", nextTbtt);
+       ath_dbg(common, BEACON, "beacon period %u\n", beaconintval);
+       ath_dbg(common, BEACON, "DTIM period %u\n", dtimperiod);
 
        ENABLE_REGWRITE_BUFFER(ah);
 
@@ -2761,9 +2761,6 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
 
        ENABLE_REGWRITE_BUFFER(ah);
 
-       if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
-               bits |= ATH9K_RX_FILTER_CONTROL_WRAPPER;
-
        REG_WRITE(ah, AR_RX_FILTER, bits);
 
        phybits = 0;
index d184e68..c1b33fd 100644 (file)
@@ -739,6 +739,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
 
        ath9k_ps_restore(sc);
 
+       ath9k_rng_start(sc);
+
        return 0;
 }
 
@@ -828,6 +830,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        ath9k_deinit_channel_context(sc);
 
+       ath9k_rng_stop(sc);
+
        mutex_lock(&sc->mutex);
 
        ath_cancel_work(sc);
index 994daf6..32160fc 100644 (file)
@@ -424,6 +424,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
            AR_SREV_9561(sc->sc_ah))
                rfilt |= ATH9K_RX_FILTER_4ADDRESS;
 
+       if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah))
+               rfilt |= ATH9K_RX_FILTER_CONTROL_WRAPPER;
+
        if (ath9k_is_chanctx_enabled() &&
            test_bit(ATH_OP_SCANNING, &common->op_flags))
                rfilt |= ATH9K_RX_FILTER_BEACON;
diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c
new file mode 100644 (file)
index 0000000..c9cb2aa
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/hw_random.h>
+#include <linux/kthread.h>
+
+#include "ath9k.h"
+#include "hw.h"
+#include "ar9003_phy.h"
+
+#define ATH9K_RNG_BUF_SIZE     320
+#define ATH9K_RNG_ENTROPY(x)   (((x) * 8 * 320) >> 10) /* quality: 320/1024 */
+
+static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size)
+{
+       int i, j;
+       u32  v1, v2, rng_last = sc->rng_last;
+       struct ath_hw *ah = sc->sc_ah;
+
+       ath9k_ps_wakeup(sc);
+
+       REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1);
+       REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5);
+       REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0);
+
+       for (i = 0, j = 0; i < buf_size; i++) {
+               v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff;
+               v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff;
+
+               /* wait for data ready */
+               if (v1 && v2 && rng_last != v1 && v1 != v2 && v1 != 0xffff &&
+                   v2 != 0xffff)
+                       buf[j++] = (v1 << 16) | v2;
+
+               rng_last = v2;
+       }
+
+       ath9k_ps_restore(sc);
+
+       sc->rng_last = rng_last;
+
+       return j << 2;
+}
+
+static int ath9k_rng_kthread(void *data)
+{
+       int bytes_read;
+       struct ath_softc *sc = data;
+       u32 *rng_buf;
+
+       rng_buf = kmalloc_array(ATH9K_RNG_BUF_SIZE, sizeof(u32), GFP_KERNEL);
+       if (!rng_buf)
+               goto out;
+
+       while (!kthread_should_stop()) {
+               bytes_read = ath9k_rng_data_read(sc, rng_buf,
+                                                ATH9K_RNG_BUF_SIZE);
+               if (unlikely(!bytes_read)) {
+                       msleep_interruptible(10);
+                       continue;
+               }
+
+               /* sleep until entropy bits under write_wakeup_threshold */
+               add_hwgenerator_randomness((void *)rng_buf, bytes_read,
+                                          ATH9K_RNG_ENTROPY(bytes_read));
+       }
+
+       kfree(rng_buf);
+out:
+       sc->rng_task = NULL;
+
+       return 0;
+}
+
+void ath9k_rng_start(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+
+       if (sc->rng_task)
+               return;
+
+       if (!AR_SREV_9300_20_OR_LATER(ah))
+               return;
+
+       sc->rng_task = kthread_run(ath9k_rng_kthread, sc, "ath9k-hwrng");
+       if (IS_ERR(sc->rng_task))
+               sc->rng_task = NULL;
+}
+
+void ath9k_rng_stop(struct ath_softc *sc)
+{
+       if (sc->rng_task)
+               kthread_stop(sc->rng_task);
+}
index 3e3dac3..fe795fc 100644 (file)
@@ -1473,11 +1473,14 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
 int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
                      u16 tid, u16 *ssn)
 {
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_atx_tid *txtid;
        struct ath_txq *txq;
        struct ath_node *an;
        u8 density;
 
+       ath_dbg(common, XMIT, "%s called\n", __func__);
+
        an = (struct ath_node *)sta->drv_priv;
        txtid = ATH_AN_2_TID(an, tid);
        txq = txtid->txq;
@@ -1512,10 +1515,13 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 
 void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
 {
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_node *an = (struct ath_node *)sta->drv_priv;
        struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
        struct ath_txq *txq = txtid->txq;
 
+       ath_dbg(common, XMIT, "%s called\n", __func__);
+
        ath_txq_lock(sc, txq);
        txtid->active = false;
        ath_tx_flush_tid(sc, txtid);
@@ -1526,11 +1532,14 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
 void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
                       struct ath_node *an)
 {
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_atx_tid *tid;
        struct ath_txq *txq;
        bool buffered;
        int tidno;
 
+       ath_dbg(common, XMIT, "%s called\n", __func__);
+
        for (tidno = 0, tid = &an->tid[tidno];
             tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
 
@@ -1555,10 +1564,13 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
 
 void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
 {
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_atx_tid *tid;
        struct ath_txq *txq;
        int tidno;
 
+       ath_dbg(common, XMIT, "%s called\n", __func__);
+
        for (tidno = 0, tid = &an->tid[tidno];
             tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
 
@@ -1579,10 +1591,13 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
 void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
                        u16 tidno)
 {
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_atx_tid *tid;
        struct ath_node *an;
        struct ath_txq *txq;
 
+       ath_dbg(common, XMIT, "%s called\n", __func__);
+
        an = (struct ath_node *)sta->drv_priv;
        tid = ATH_AN_2_TID(an, tidno);
        txq = tid->txq;
@@ -2316,6 +2331,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        queue = ieee80211_is_data_present(hdr->frame_control);
 
+       /* If chanctx, queue all null frames while NOA could be there */
+       if (ath9k_is_chanctx_enabled() &&
+           ieee80211_is_nullfunc(hdr->frame_control) &&
+           !txctl->force_channel)
+               queue = true;
+
        /* Force queueing of all frames that belong to a virtual interface on
         * a different channel context, to ensure that they are sent on the
         * correct channel.
@@ -2894,7 +2915,7 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
                if (skb_headroom(skb) < padsize) {
                        ath_dbg(common, XMIT,
                                "tx99 padding failed\n");
-               return -EINVAL;
+                       return -EINVAL;
                }
 
                skb_push(skb, padsize);
index 48687f1..09b4dae 100644 (file)
@@ -781,8 +781,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
        wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
        wil_bcast_fini(wil);
 
-       /* prevent NAPI from being scheduled */
+       /* prevent NAPI from being scheduled and prevent wmi commands */
+       mutex_lock(&wil->wmi_mutex);
        bitmap_zero(wil->status, wil_status_last);
+       mutex_unlock(&wil->wmi_mutex);
 
        if (wil->scan_request) {
                wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
index 6ed26ba..e3ea74c 100644 (file)
@@ -228,6 +228,10 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
        wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
        /* wait till FW finish with previous command */
        for (retry = 5; retry > 0; retry--) {
+               if (!test_bit(wil_status_fwready, wil->status)) {
+                       wil_err(wil, "WMI: cannot send command while FW not ready\n");
+                       return -EAGAIN;
+               }
                r->tail = wil_r(wil, RGF_MBOX +
                                offsetof(struct wil6210_mbox_ctl, tx.tail));
                if (next_head != r->tail)