wifi: ath12k: Cache vdev configs before vdev create
authorSriram R <quic_srirrama@quicinc.com>
Tue, 9 Apr 2024 11:49:34 +0000 (14:49 +0300)
committerKalle Valo <quic_kvalo@quicinc.com>
Wed, 10 Apr 2024 14:12:15 +0000 (17:12 +0300)
Since the vdev create for a corresponding vif is deferred
until a channel is assigned, cache the information which
are received through mac80211 ops between add_interface()
and assign_vif_chanctx() and set them once the vdev is
created on one of the ath12k radios as the channel gets
assigned via assign_vif_chanctx().

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Co-developed-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240405194519.1337906-8-quic_ramess@quicinc.com
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/mac.c

index 44d5c96b1566ea87ddbd9c44be5476c9c8175488..4ad3628c714f88b9fc446a437638aab3ab01afe0 100644 (file)
@@ -214,6 +214,24 @@ enum ath12k_monitor_flags {
        ATH12K_FLAG_MONITOR_ENABLED,
 };
 
+struct ath12k_tx_conf {
+       bool changed;
+       u16 ac;
+       struct ieee80211_tx_queue_params tx_queue_params;
+};
+
+struct ath12k_key_conf {
+       bool changed;
+       enum set_key_cmd cmd;
+       struct ieee80211_key_conf *key;
+};
+
+struct ath12k_vif_cache {
+       struct ath12k_tx_conf tx_conf;
+       struct ath12k_key_conf key_conf;
+       u32 bss_conf_changed;
+};
+
 struct ath12k_vif {
        u32 vdev_id;
        enum wmi_vdev_type vdev_type;
@@ -268,6 +286,7 @@ struct ath12k_vif {
        u8 vdev_stats_id;
        u32 punct_bitmap;
        bool ps;
+       struct ath12k_vif_cache *cache;
 };
 
 struct ath12k_vif_iter {
index be36c7d133da51351ced5c252d032d582c963312..fed9ce490b379779015b4b2e8ca0e394123c5320 100644 (file)
@@ -3012,6 +3012,20 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
        }
 }
 
+static struct ath12k_vif_cache *ath12k_arvif_get_cache(struct ath12k_vif *arvif)
+{
+       if (!arvif->cache)
+               arvif->cache = kzalloc(sizeof(*arvif->cache), GFP_KERNEL);
+
+       return arvif->cache;
+}
+
+static void ath12k_arvif_put_cache(struct ath12k_vif *arvif)
+{
+       kfree(arvif->cache);
+       arvif->cache = NULL;
+}
+
 static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
                                           struct ieee80211_vif *vif,
                                           struct ieee80211_bss_conf *info,
@@ -3019,15 +3033,21 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct ath12k *ar;
        struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       struct ath12k_vif_cache *cache;
 
        ar = ath12k_get_ar_by_vif(hw, vif);
 
-       /* TODO if the vdev is not created on a certain radio,
+       /* if the vdev is not created on a certain radio,
         * cache the info to be updated later on vdev creation
         */
 
-       if (!ar)
+       if (!ar) {
+               cache = ath12k_arvif_get_cache(arvif);
+               if (!cache)
+                       return;
+               arvif->cache->bss_conf_changed |= changed;
                return;
+       }
 
        mutex_lock(&ar->conf_mutex);
 
@@ -3518,12 +3538,11 @@ static int ath12k_clear_peer_keys(struct ath12k_vif *arvif,
        return first_errno;
 }
 
-static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
-                                struct ieee80211_vif *vif, struct ieee80211_sta *sta,
-                                struct ieee80211_key_conf *key)
+static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd,
+                             struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+                             struct ieee80211_key_conf *key)
 {
-       struct ath12k *ar;
-       struct ath12k_base *ab;
+       struct ath12k_base *ab = ar->ab;
        struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
        struct ath12k_peer *peer;
        struct ath12k_sta *arsta;
@@ -3531,28 +3550,11 @@ static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        int ret = 0;
        u32 flags = 0;
 
-       /* BIP needs to be done in software */
-       if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
-           key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
-           key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
-           key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
-               return 1;
-
-       ar = ath12k_get_ar_by_vif(hw, vif);
-       if (!ar) {
-               WARN_ON_ONCE(1);
-               return -EINVAL;
-       }
-       ab = ar->ab;
+       lockdep_assert_held(&ar->conf_mutex);
 
-       if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags))
+       if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags))
                return 1;
 
-       if (key->keyidx > WMI_MAX_KEY_INDEX)
-               return -ENOSPC;
-
-       mutex_lock(&ar->conf_mutex);
-
        if (sta)
                peer_addr = sta->addr;
        else if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
@@ -3644,6 +3646,47 @@ static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        spin_unlock_bh(&ab->base_lock);
 
 exit:
+       return ret;
+}
+
+static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+                                struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+                                struct ieee80211_key_conf *key)
+{
+       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       struct ath12k_vif_cache *cache;
+       struct ath12k *ar;
+       int ret;
+
+       /* BIP needs to be done in software */
+       if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+           key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
+           key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
+           key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
+               return 1;
+
+       if (key->keyidx > WMI_MAX_KEY_INDEX)
+               return -ENOSPC;
+
+       ar = ath12k_get_ar_by_vif(hw, vif);
+       if (!ar) {
+               /* ar is expected to be valid when sta ptr is available */
+               if (sta) {
+                       WARN_ON_ONCE(1);
+                       return -EINVAL;
+               }
+
+               cache = ath12k_arvif_get_cache(arvif);
+               if (!cache)
+                       return -ENOSPC;
+               cache->key_conf.cmd = cmd;
+               cache->key_conf.key = key;
+               cache->key_conf.changed = true;
+               return 0;
+       }
+
+       mutex_lock(&ar->conf_mutex);
+       ret = ath12k_mac_set_key(ar, cmd, vif, sta, key);
        mutex_unlock(&ar->conf_mutex);
        return ret;
 }
@@ -4474,12 +4517,19 @@ static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw,
 {
        struct ath12k *ar;
        struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       struct ath12k_vif_cache *cache = arvif->cache;
        int ret;
 
        ar = ath12k_get_ar_by_vif(hw, vif);
        if (!ar) {
-               /* TODO cache the info and apply after vdev is created */
-               return -EINVAL;
+               /* cache the info and apply after vdev is created */
+               cache = ath12k_arvif_get_cache(arvif);
+               if (!cache)
+                       return -ENOSPC;
+               cache->tx_conf.changed = true;
+               cache->tx_conf.ac = ac;
+               cache->tx_conf.tx_queue_params = *params;
+               return 0;
        }
 
        mutex_lock(&ar->conf_mutex);
@@ -6122,6 +6172,43 @@ err:
        return ret;
 }
 
+static void ath12k_mac_vif_cache_flush(struct ath12k *ar,  struct ieee80211_vif *vif)
+{
+       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       struct ath12k_vif_cache *cache = arvif->cache;
+       struct ath12k_base *ab = ar->ab;
+
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (!cache)
+               return;
+
+       if (cache->tx_conf.changed) {
+               ret = ath12k_mac_conf_tx(arvif, 0, cache->tx_conf.ac,
+                                        &cache->tx_conf.tx_queue_params);
+               if (ret)
+                       ath12k_warn(ab,
+                                   "unable to apply tx config parameters to vdev %d\n",
+                                   ret);
+       }
+
+       if (cache->bss_conf_changed) {
+               ath12k_mac_bss_info_changed(ar, arvif, &vif->bss_conf,
+                                           cache->bss_conf_changed);
+       }
+
+       if (cache->key_conf.changed) {
+               ret = ath12k_mac_set_key(ar, cache->key_conf.cmd, vif, NULL,
+                                        cache->key_conf.key);
+               if (ret)
+                       ath12k_warn(ab, "unable to apply set key param to vdev %d ret %d\n",
+                                   arvif->vdev_id, ret);
+       }
+       ath12k_arvif_put_cache(arvif);
+}
+
 static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
                                                    struct ieee80211_vif *vif,
                                                    struct ieee80211_chanctx_conf *ctx)
@@ -6176,11 +6263,11 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
 
        ab = ar->ab;
 
-       if (arvif->is_created)
-               goto out;
-
        mutex_lock(&ar->conf_mutex);
 
+       if (arvif->is_created)
+               goto flush;
+
        if (vif->type == NL80211_IFTYPE_AP &&
            ar->num_peers > (ar->max_num_peers - 1)) {
                ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
@@ -6199,13 +6286,14 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
                goto unlock;
        }
 
-       /* TODO If the vdev is created during channel assign and not during
+flush:
+       /* If the vdev is created during channel assign and not during
         * add_interface(), Apply any parameters for the vdev which were received
         * after add_interface, corresponding to this vif.
         */
+       ath12k_mac_vif_cache_flush(ar, vif);
 unlock:
        mutex_unlock(&ar->conf_mutex);
-out:
        return arvif->ar;
 }
 
@@ -6314,6 +6402,7 @@ err_vdev_del:
        spin_unlock_bh(&ar->data_lock);
 
        ath12k_peer_cleanup(ar, arvif->vdev_id);
+       ath12k_arvif_put_cache(arvif);
 
        idr_for_each(&ar->txmgmt_idr,
                     ath12k_mac_vif_txmgmt_idr_remove, vif);
@@ -6340,8 +6429,13 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
        struct ath12k *ar;
        int ret;
 
-       if (!arvif->is_created)
+       if (!arvif->is_created) {
+               /* if we cached some config but never received assign chanctx,
+                * free the allocated cache.
+                */
+               ath12k_arvif_put_cache(arvif);
                return;
+       }
 
        ar = arvif->ar;
        ab = ar->ab;