Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
authorKalle Valo <kvalo@codeaurora.org>
Mon, 11 Jan 2021 17:42:29 +0000 (19:42 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Mon, 11 Jan 2021 17:42:29 +0000 (19:42 +0200)
ath.git patches for v5.12. Major changes:

ath9k

* more robust encryption key cache management

14 files changed:
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath10k/ahb.c
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/sdio.c
drivers/net/wireless/ath/ath10k/snoc.c
drivers/net/wireless/ath/ath11k/dp_rx.c
drivers/net/wireless/ath/ath11k/pci.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/key.c

index 7a364eca46d642e25c69fc2275fce4077a113faa..f083fb9038c36384629631d0292a05152a6b17ce 100644 (file)
@@ -197,12 +197,13 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
 bool ath_is_mybeacon(struct ath_common *common, struct ieee80211_hdr *hdr);
 
 void ath_hw_setbssidmask(struct ath_common *common);
-void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key);
+void ath_key_delete(struct ath_common *common, u8 hw_key_idx);
 int ath_key_config(struct ath_common *common,
                          struct ieee80211_vif *vif,
                          struct ieee80211_sta *sta,
                          struct ieee80211_key_conf *key);
 bool ath_hw_keyreset(struct ath_common *common, u16 entry);
+bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac);
 void ath_hw_cycle_counters_update(struct ath_common *common);
 int32_t ath_hw_get_listen_time(struct ath_common *common);
 
index 05a61975c83f4bf26c04c8510f64d6dd5225769d..869524852fbaa3f29aca43e8d77cd3e7cf57bc00 100644 (file)
@@ -626,7 +626,7 @@ static int ath10k_ahb_hif_start(struct ath10k *ar)
 {
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif start\n");
 
-       napi_enable(&ar->napi);
+       ath10k_core_napi_enable(ar);
        ath10k_ce_enable_interrupts(ar);
        ath10k_pci_enable_legacy_irq(ar);
 
@@ -644,8 +644,7 @@ static void ath10k_ahb_hif_stop(struct ath10k *ar)
        ath10k_ahb_irq_disable(ar);
        synchronize_irq(ar_ahb->irq);
 
-       napi_synchronize(&ar->napi);
-       napi_disable(&ar->napi);
+       ath10k_core_napi_sync_disable(ar);
 
        ath10k_pci_flush(ar);
 }
index eeb6ff6aa2e1e80d9ecfcc37af43c073f960ce5f..a419ec7130f975996ff76e65633335f1d0141536 100644 (file)
@@ -2305,6 +2305,31 @@ void ath10k_core_start_recovery(struct ath10k *ar)
 }
 EXPORT_SYMBOL(ath10k_core_start_recovery);
 
+void ath10k_core_napi_enable(struct ath10k *ar)
+{
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (test_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags))
+               return;
+
+       napi_enable(&ar->napi);
+       set_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags);
+}
+EXPORT_SYMBOL(ath10k_core_napi_enable);
+
+void ath10k_core_napi_sync_disable(struct ath10k *ar)
+{
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (!test_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags))
+               return;
+
+       napi_synchronize(&ar->napi);
+       napi_disable(&ar->napi);
+       clear_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags);
+}
+EXPORT_SYMBOL(ath10k_core_napi_sync_disable);
+
 static void ath10k_core_restart(struct work_struct *work)
 {
        struct ath10k *ar = container_of(work, struct ath10k, restart_work);
index 51f7e960e2977a6241910c64498e63cb04263777..f4be6bfb253920233bfe8e7d4c1b89627d64bb0e 100644 (file)
@@ -868,6 +868,9 @@ enum ath10k_dev_flags {
 
        /* Indicates that ath10k device is during recovery process and not complete */
        ATH10K_FLAG_RESTARTING,
+
+       /* protected by conf_mutex */
+       ATH10K_FLAG_NAPI_ENABLED,
 };
 
 enum ath10k_cal_mode {
@@ -1308,6 +1311,8 @@ static inline bool ath10k_peer_stats_enabled(struct ath10k *ar)
 
 extern unsigned long ath10k_coredump_mask;
 
+void ath10k_core_napi_sync_disable(struct ath10k *ar);
+void ath10k_core_napi_enable(struct ath10k *ar);
 struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
                                  enum ath10k_bus bus,
                                  enum ath10k_hw_rev hw_rev,
index 2328df09875cede9e326408acfa8899c44eeed68..e7fde635e0eef81ffe10b4366bd37f998cf6f9d7 100644 (file)
@@ -1958,7 +1958,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
 
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
 
-       napi_enable(&ar->napi);
+       ath10k_core_napi_enable(ar);
 
        ath10k_pci_irq_enable(ar);
        ath10k_pci_rx_post(ar);
@@ -2075,8 +2075,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
 
        ath10k_pci_irq_disable(ar);
        ath10k_pci_irq_sync(ar);
-       napi_synchronize(&ar->napi);
-       napi_disable(&ar->napi);
+
+       ath10k_core_napi_sync_disable(ar);
+
        cancel_work_sync(&ar_pci->dump_work);
 
        /* Most likely the device has HTT Rx ring configured. The only way to
index c415090d1f37c2f8f602bf38428ad5df95265c07..b746052737e0bbc17d091389b58480b66392c723 100644 (file)
@@ -1859,7 +1859,7 @@ static int ath10k_sdio_hif_start(struct ath10k *ar)
        struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
        int ret;
 
-       napi_enable(&ar->napi);
+       ath10k_core_napi_enable(ar);
 
        /* Sleep 20 ms before HIF interrupts are disabled.
         * This will give target plenty of time to process the BMI done
@@ -1992,8 +1992,7 @@ static void ath10k_sdio_hif_stop(struct ath10k *ar)
 
        spin_unlock_bh(&ar_sdio->wr_async_lock);
 
-       napi_synchronize(&ar->napi);
-       napi_disable(&ar->napi);
+       ath10k_core_napi_sync_disable(ar);
 }
 
 #ifdef CONFIG_PM
index bf9a8cb713dc0ea50f7cf31c3333cef1f547984e..d66593f0950f84d7f1fe484cb72b18c0498e81fe 100644 (file)
@@ -915,8 +915,7 @@ static void ath10k_snoc_hif_stop(struct ath10k *ar)
        if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
                ath10k_snoc_irq_disable(ar);
 
-       napi_synchronize(&ar->napi);
-       napi_disable(&ar->napi);
+       ath10k_core_napi_sync_disable(ar);
        ath10k_snoc_buffer_cleanup(ar);
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
 }
@@ -926,7 +925,8 @@ static int ath10k_snoc_hif_start(struct ath10k *ar)
        struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
 
        bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX);
-       napi_enable(&ar->napi);
+
+       ath10k_core_napi_enable(ar);
        ath10k_snoc_irq_enable(ar);
        ath10k_snoc_rx_post(ar);
 
@@ -1003,6 +1003,39 @@ static int ath10k_snoc_wlan_enable(struct ath10k *ar,
                                       NULL);
 }
 
+static int ath10k_hw_power_on(struct ath10k *ar)
+{
+       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+       int ret;
+
+       ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n");
+
+       ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs);
+       if (ret)
+               return ret;
+
+       ret = clk_bulk_prepare_enable(ar_snoc->num_clks, ar_snoc->clks);
+       if (ret)
+               goto vreg_off;
+
+       return ret;
+
+vreg_off:
+       regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
+       return ret;
+}
+
+static int ath10k_hw_power_off(struct ath10k *ar)
+{
+       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+
+       ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n");
+
+       clk_bulk_disable_unprepare(ar_snoc->num_clks, ar_snoc->clks);
+
+       return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
+}
+
 static void ath10k_snoc_wlan_disable(struct ath10k *ar)
 {
        struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
@@ -1024,6 +1057,7 @@ static void ath10k_snoc_hif_power_down(struct ath10k *ar)
 
        ath10k_snoc_wlan_disable(ar);
        ath10k_ce_free_rri(ar);
+       ath10k_hw_power_off(ar);
 }
 
 static int ath10k_snoc_hif_power_up(struct ath10k *ar,
@@ -1034,10 +1068,16 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar,
        ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n",
                   __func__, ar->state);
 
+       ret = ath10k_hw_power_on(ar);
+       if (ret) {
+               ath10k_err(ar, "failed to power on device: %d\n", ret);
+               return ret;
+       }
+
        ret = ath10k_snoc_wlan_enable(ar, fw_mode);
        if (ret) {
                ath10k_err(ar, "failed to enable wcn3990: %d\n", ret);
-               return ret;
+               goto err_hw_power_off;
        }
 
        ath10k_ce_alloc_rri(ar);
@@ -1045,14 +1085,18 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar,
        ret = ath10k_snoc_init_pipes(ar);
        if (ret) {
                ath10k_err(ar, "failed to initialize CE: %d\n", ret);
-               goto err_wlan_enable;
+               goto err_free_rri;
        }
 
        return 0;
 
-err_wlan_enable:
+err_free_rri:
+       ath10k_ce_free_rri(ar);
        ath10k_snoc_wlan_disable(ar);
 
+err_hw_power_off:
+       ath10k_hw_power_off(ar);
+
        return ret;
 }
 
@@ -1369,39 +1413,6 @@ static void ath10k_snoc_release_resource(struct ath10k *ar)
                ath10k_ce_free_pipe(ar, i);
 }
 
-static int ath10k_hw_power_on(struct ath10k *ar)
-{
-       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
-       int ret;
-
-       ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n");
-
-       ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs);
-       if (ret)
-               return ret;
-
-       ret = clk_bulk_prepare_enable(ar_snoc->num_clks, ar_snoc->clks);
-       if (ret)
-               goto vreg_off;
-
-       return ret;
-
-vreg_off:
-       regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
-       return ret;
-}
-
-static int ath10k_hw_power_off(struct ath10k *ar)
-{
-       struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
-
-       ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n");
-
-       clk_bulk_disable_unprepare(ar_snoc->num_clks, ar_snoc->clks);
-
-       return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
-}
-
 static void ath10k_msa_dump_memory(struct ath10k *ar,
                                   struct ath10k_fw_crash_data *crash_data)
 {
@@ -1711,22 +1722,16 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
        if (ret)
                goto err_free_irq;
 
-       ret = ath10k_hw_power_on(ar);
-       if (ret) {
-               ath10k_err(ar, "failed to power on device: %d\n", ret);
-               goto err_free_irq;
-       }
-
        ret = ath10k_setup_msa_resources(ar, msa_size);
        if (ret) {
                ath10k_warn(ar, "failed to setup msa resources: %d\n", ret);
-               goto err_power_off;
+               goto err_free_irq;
        }
 
        ret = ath10k_fw_init(ar);
        if (ret) {
                ath10k_err(ar, "failed to initialize firmware: %d\n", ret);
-               goto err_power_off;
+               goto err_free_irq;
        }
 
        ret = ath10k_qmi_init(ar, msa_size);
@@ -1742,9 +1747,6 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
 err_fw_deinit:
        ath10k_fw_deinit(ar);
 
-err_power_off:
-       ath10k_hw_power_off(ar);
-
 err_free_irq:
        ath10k_snoc_free_irq(ar);
 
@@ -1772,7 +1774,6 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
        set_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags);
 
        ath10k_core_unregister(ar);
-       ath10k_hw_power_off(ar);
        ath10k_fw_deinit(ar);
        ath10k_snoc_free_irq(ar);
        ath10k_snoc_release_resource(ar);
index 920e5026a635fceabfa6f3e388f034dbe886d932..42328a06107b315e054ef07ed5ac50a97c5d6ed2 100644 (file)
@@ -1163,7 +1163,7 @@ int ath11k_dp_peer_rx_pn_replay_config(struct ath11k_vif *arvif,
                }
        }
 
-       spin_unlock_bh(&ar->ab->base_lock);
+       spin_unlock_bh(&ab->base_lock);
 
        return ret;
 }
index 20b415cd96c4aadaa233aed4cbabbae6996c4201..78478b2b3ba5766fd24e45cd396e7dae0addfc6c 100644 (file)
@@ -328,7 +328,7 @@ static void ath11k_pci_enable_ltssm(struct ath11k_base *ab)
        ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val);
 
        val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
-       val |= GCC_GCC_PCIE_HOT_RST_VAL | 0x10;
+       val |= GCC_GCC_PCIE_HOT_RST_VAL;
        ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val);
        val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST);
 
index 8f2719ff463c2e4cf03cb23c29a280753929e999..532eeac9e83e357e50b4656231ab40d542d2c838 100644 (file)
@@ -522,7 +522,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                }
                break;
        case DISABLE_KEY:
-               ath_key_delete(common, key);
+               ath_key_delete(common, key->hw_key_idx);
                break;
        default:
                ret = -EINVAL;
index 2b7832b1c80089796337fb37cce9d69294927c1b..72ef319feeda73d6c8f82b3d3db42f92561ef233 100644 (file)
@@ -1461,7 +1461,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
                }
                break;
        case DISABLE_KEY:
-               ath_key_delete(common, key);
+               ath_key_delete(common, key->hw_key_idx);
                break;
        default:
                ret = -EINVAL;
index 023599e10dd51812e0c904a3bb41be2530bf1770..b7b65b1c90e8fd0574a70fefa6a2928ee3ad68be 100644 (file)
@@ -820,6 +820,7 @@ struct ath_hw {
        struct ath9k_pacal_info pacal_info;
        struct ar5416Stats stats;
        struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
+       DECLARE_BITMAP(pending_del_keymap, ATH_KEYMAX);
 
        enum ath9k_int imask;
        u32 imrs2_reg;
index caebe3fd6869e0e11eca8e5696d44e1b42cfcf7f..45f6402478b50cf9b209ee5586b5f66c3a3c3fa7 100644 (file)
@@ -821,12 +821,80 @@ exit:
        ieee80211_free_txskb(hw, skb);
 }
 
+static bool ath9k_txq_list_has_key(struct list_head *txq_list, u32 keyix)
+{
+       struct ath_buf *bf;
+       struct ieee80211_tx_info *txinfo;
+       struct ath_frame_info *fi;
+
+       list_for_each_entry(bf, txq_list, list) {
+               if (bf->bf_state.stale || !bf->bf_mpdu)
+                       continue;
+
+               txinfo = IEEE80211_SKB_CB(bf->bf_mpdu);
+               fi = (struct ath_frame_info *)&txinfo->rate_driver_data[0];
+               if (fi->keyix == keyix)
+                       return true;
+       }
+
+       return false;
+}
+
+static bool ath9k_txq_has_key(struct ath_softc *sc, u32 keyix)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       int i;
+       struct ath_txq *txq;
+       bool key_in_use = false;
+
+       for (i = 0; !key_in_use && i < ATH9K_NUM_TX_QUEUES; i++) {
+               if (!ATH_TXQ_SETUP(sc, i))
+                       continue;
+               txq = &sc->tx.txq[i];
+               if (!txq->axq_depth)
+                       continue;
+               if (!ath9k_hw_numtxpending(ah, txq->axq_qnum))
+                       continue;
+
+               ath_txq_lock(sc, txq);
+               key_in_use = ath9k_txq_list_has_key(&txq->axq_q, keyix);
+               if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+                       int idx = txq->txq_tailidx;
+
+                       while (!key_in_use &&
+                              !list_empty(&txq->txq_fifo[idx])) {
+                               key_in_use = ath9k_txq_list_has_key(
+                                       &txq->txq_fifo[idx], keyix);
+                               INCR(idx, ATH_TXFIFO_DEPTH);
+                       }
+               }
+               ath_txq_unlock(sc, txq);
+       }
+
+       return key_in_use;
+}
+
+static void ath9k_pending_key_del(struct ath_softc *sc, u8 keyix)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (!test_bit(keyix, ah->pending_del_keymap) ||
+           ath9k_txq_has_key(sc, keyix))
+               return;
+
+       /* No more TXQ frames point to this key cache entry, so delete it. */
+       clear_bit(keyix, ah->pending_del_keymap);
+       ath_key_delete(common, keyix);
+}
+
 static void ath9k_stop(struct ieee80211_hw *hw)
 {
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        bool prev_idle;
+       int i;
 
        ath9k_deinit_channel_context(sc);
 
@@ -894,6 +962,14 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        spin_unlock_bh(&sc->sc_pcu_lock);
 
+       for (i = 0; i < ATH_KEYMAX; i++)
+               ath9k_pending_key_del(sc, i);
+
+       /* Clear key cache entries explicitly to get rid of any potentially
+        * remaining keys.
+        */
+       ath9k_cmn_init_crypto(sc->sc_ah);
+
        ath9k_ps_restore(sc);
 
        sc->ps_idle = prev_idle;
@@ -1538,12 +1614,11 @@ static void ath9k_del_ps_key(struct ath_softc *sc,
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_node *an = (struct ath_node *) sta->drv_priv;
-       struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
 
        if (!an->ps_key)
            return;
 
-       ath_key_delete(common, &ps_key);
+       ath_key_delete(common, an->ps_key);
        an->ps_key = 0;
        an->key_idx[0] = 0;
 }
@@ -1714,6 +1789,12 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
        if (sta)
                an = (struct ath_node *)sta->drv_priv;
 
+       /* Delete pending key cache entries if no more frames are pointing to
+        * them in TXQs.
+        */
+       for (i = 0; i < ATH_KEYMAX; i++)
+               ath9k_pending_key_del(sc, i);
+
        switch (cmd) {
        case SET_KEY:
                if (sta)
@@ -1743,7 +1824,15 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
                }
                break;
        case DISABLE_KEY:
-               ath_key_delete(common, key);
+               if (ath9k_txq_has_key(sc, key->hw_key_idx)) {
+                       /* Delay key cache entry deletion until there are no
+                        * remaining TXQ frames pointing to this entry.
+                        */
+                       set_bit(key->hw_key_idx, sc->sc_ah->pending_del_keymap);
+                       ath_hw_keysetmac(common, key->hw_key_idx, NULL);
+               } else {
+                       ath_key_delete(common, key->hw_key_idx);
+               }
                if (an) {
                        for (i = 0; i < ARRAY_SIZE(an->key_idx); i++) {
                                if (an->key_idx[i] != key->hw_key_idx)
index 1816b4e7dc26409352da12b166aac3108c4acd76..61b59a804e308d8358903d3f81950a85c97afdf0 100644 (file)
@@ -84,8 +84,7 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry)
 }
 EXPORT_SYMBOL(ath_hw_keyreset);
 
-static bool ath_hw_keysetmac(struct ath_common *common,
-                            u16 entry, const u8 *mac)
+bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac)
 {
        u32 macHi, macLo;
        u32 unicast_flag = AR_KEYTABLE_VALID;
@@ -125,6 +124,7 @@ static bool ath_hw_keysetmac(struct ath_common *common,
 
        return true;
 }
+EXPORT_SYMBOL(ath_hw_keysetmac);
 
 static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
                                      const struct ath_keyval *k,
@@ -581,29 +581,38 @@ EXPORT_SYMBOL(ath_key_config);
 /*
  * Delete Key.
  */
-void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
+void ath_key_delete(struct ath_common *common, u8 hw_key_idx)
 {
-       ath_hw_keyreset(common, key->hw_key_idx);
-       if (key->hw_key_idx < IEEE80211_WEP_NKID)
+       /* Leave CCMP and TKIP (main key) configured to avoid disabling
+        * encryption for potentially pending frames already in a TXQ with the
+        * keyix pointing to this key entry. Instead, only clear the MAC address
+        * to prevent RX processing from using this key cache entry.
+        */
+       if (test_bit(hw_key_idx, common->ccmp_keymap) ||
+           test_bit(hw_key_idx, common->tkip_keymap))
+               ath_hw_keysetmac(common, hw_key_idx, NULL);
+       else
+               ath_hw_keyreset(common, hw_key_idx);
+       if (hw_key_idx < IEEE80211_WEP_NKID)
                return;
 
-       clear_bit(key->hw_key_idx, common->keymap);
-       clear_bit(key->hw_key_idx, common->ccmp_keymap);
-       if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
+       clear_bit(hw_key_idx, common->keymap);
+       clear_bit(hw_key_idx, common->ccmp_keymap);
+       if (!test_bit(hw_key_idx, common->tkip_keymap))
                return;
 
-       clear_bit(key->hw_key_idx + 64, common->keymap);
+       clear_bit(hw_key_idx + 64, common->keymap);
 
-       clear_bit(key->hw_key_idx, common->tkip_keymap);
-       clear_bit(key->hw_key_idx + 64, common->tkip_keymap);
+       clear_bit(hw_key_idx, common->tkip_keymap);
+       clear_bit(hw_key_idx + 64, common->tkip_keymap);
 
        if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) {
-               ath_hw_keyreset(common, key->hw_key_idx + 32);
-               clear_bit(key->hw_key_idx + 32, common->keymap);
-               clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
+               ath_hw_keyreset(common, hw_key_idx + 32);
+               clear_bit(hw_key_idx + 32, common->keymap);
+               clear_bit(hw_key_idx + 64 + 32, common->keymap);
 
-               clear_bit(key->hw_key_idx + 32, common->tkip_keymap);
-               clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap);
+               clear_bit(hw_key_idx + 32, common->tkip_keymap);
+               clear_bit(hw_key_idx + 64 + 32, common->tkip_keymap);
        }
 }
 EXPORT_SYMBOL(ath_key_delete);