Commit dc5771df authored by Kalle Valo's avatar Kalle Valo

Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git

ath.git patches for v5.12. Major changes:

ath9k

* more robust encryption key cache management
parents 73b7a604 abdcd4cb
......@@ -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);
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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,
......
......@@ -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
......
......@@ -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
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -821,12 +821,80 @@ static void ath9k_tx(struct ieee80211_hw *hw,
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)
......
......@@ -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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment