Search Linux Wireless

Re: [PATCH v4 1/3] wifi: ath12k: prepare vif data structure for MLO handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 6/17/2024 9:16 PM, Rameshkumar Sundaram wrote:
> From: Sriram R <quic_srirrama@xxxxxxxxxxx>
> 
> To prepare the driver for MLO support, split the driver vif
> data structure to scale for multiple links. This requires changing
> the use of arvif to per link and not per hw which can now
> comprise of multiple links.
> Also since most configurations from mac80211 are done per link, do refactoring
> of the driver functions to apply these configurations at link level.
> 
> Split ath12k_vif which is the driver private of ieee80211_vif to store
> link specific information as ath12k_link_vif. For default use cases
> the ath12k vif will have a preallocated link vif called deflink which will
> be used by non ML and the first link vif of ML vif.
> 
> With MLO Support to be added, remaining link vifs will be allocated during
> channel assignment where vdev create/start happens. These link vifs will be
> freed during interface down.
> 
>        		Current ath12k_vif(arvif) structure
> 
>              +---------------+      +---------------+     +---------------+
>              | ieee80211_vif |      | ieee80211_vif |     | ieee80211_vif |
>              | private data  |      | private data  |     | private data  |
>              |               |      |               |     |               |
>              |  ath12k_vif   |      |  ath12k_vif   |     |  ath12k_vif   |
>              |  (arvif)      |      |  (arvif)      |     |  (arvif)      |
>              |               |      |               |     |               |
>              |  +----------+ |      |  +----------+ |     |  +----------+ |
>              |  |*ar (2GHz)| |      |  |*ar (5GHz)| |     |  |*ar (2GHz)| |
>              |  +----------+ |      |  +----------+ |     |  +----------+ |
>              |               |      |               |     |               |
>              +---------------+      +---------------+     +---------------+
> 
>        	Proposed ath12k_vif(ahvif) containing ath12k_link_vif(s) (arvif)
>        	(deflink is preallocated member which is always the first link if
>        	 ieee80211_vif is MLD and is the only link otherwise)
> 
>        			+---------------------------------+
>        			|     ieee80211_vif               |
>        			|     private data                |
>        			|                                 |
>        			|   ath12k_vif(ahvif)             |
>        			|                                 |
>        			| +-------------------------------+
>        			| |ath12k_link_vif deflink (arvif)|
>        			| |        +---------------+      |
>        			| |        | *ar(2GHz)     |      |
>        			| +-------------------------------+
>        			| +-------------------------------+
>        			| |  ath12k_link_vif *link (arvif)|
>        			| |        +---------------+      |
>        			| |        | *ar(5GHz)     |      |
>        			| +-------------------------------+
>        			| +-------------------------------+
>        			| |  ath12k_link_vif *link (arvif)|
>        			| |        +---------------+      |
>        			| |        | *ar(6GHz)     |      |
>        			| +-------------------------------+
>        			|                                 |
>        			+---------------------------------+
> 
> To refactor existing ath12k_vif to make use of link vifs, following
> changes are made,
> 
>  1. ath12k_vif now called by variable name ahvif stores multiple
>  arvifs(ah12k_link_vif) and also has a back pointer to ieee80211_vif.
> 
>  2. In this patch set, only deflink is used to be on par with the
>  existing code. When MLO support is added the link id will be used to
>  fetch the arvif.
> 
>  3. For mac80211 ops which doesn't use specific link_id, the config or info
>  is common for the vif, hence apply the config to all link vifs.
>  The links_map in the ahvif, will be used to identify all the link vifs that
>  are setup.
> 
>  4. Change ath12k_vif_to_arvif() as ath12k_vif_to_ahvif() to fetch the
>  hw level vif. The link vif can be fetched from ahvif->link[], or the
>  deflink can be accessed via ahvif->deflink. API to access link
>  vif(arvif) by passing link_id can be introduced with MLO Support.
> 
>  5. The ieee80211_vif can be accessed from ahvif using ath12k_vif_to_vif()
> 
> Locking:
>  Currently modifications to members of arvif and arsta are protected by ar->conf_mutex
>  and it stays as such.
>  Now with these hw level structure (ahvif) being introduced, any modifications
>  to its members and link objects (i.e., arvifs[] which are dynamically allocated)
>  needs to be protected for writing and ah->conf_mutex is used for the same.
>  Also, atomic contexts(say WMI events and certain mac_ops) that we currently have in driver
>  will not(shouldn't be allowed) do any modifications but can read them and
>  rcu_read_lock() is used for the same.
> 
> 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@xxxxxxxxxxx>
> Co-developed-by: Rameshkumar Sundaram <quic_ramess@xxxxxxxxxxx>
> Signed-off-by: Rameshkumar Sundaram <quic_ramess@xxxxxxxxxxx>
> ---
>  drivers/net/wireless/ath/ath12k/core.h  |  69 ++-
>  drivers/net/wireless/ath/ath12k/dp.c    |  21 +-
>  drivers/net/wireless/ath/ath12k/dp.h    |   3 +-
>  drivers/net/wireless/ath/ath12k/dp_rx.c |   2 +-
>  drivers/net/wireless/ath/ath12k/dp_rx.h |   2 +-
>  drivers/net/wireless/ath/ath12k/dp_tx.c |   9 +-
>  drivers/net/wireless/ath/ath12k/dp_tx.h |   2 +-
>  drivers/net/wireless/ath/ath12k/mac.c   | 733 ++++++++++++++++--------
>  drivers/net/wireless/ath/ath12k/mac.h   |   9 +-
>  drivers/net/wireless/ath/ath12k/p2p.c   |  17 +-
>  drivers/net/wireless/ath/ath12k/p2p.h   |   2 +-
>  drivers/net/wireless/ath/ath12k/peer.c  |   7 +-
>  drivers/net/wireless/ath/ath12k/peer.h  |   4 +-
>  drivers/net/wireless/ath/ath12k/wmi.c   |  12 +-
>  14 files changed, 592 insertions(+), 300 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index b483899ca136..d47b6413aaad 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -229,10 +229,8 @@ struct ath12k_vif_cache {
>  	u32 bss_conf_changed;
>  };
>  
> -struct ath12k_vif {
> +struct ath12k_link_vif {
>  	u32 vdev_id;
> -	enum wmi_vdev_type vdev_type;
> -	enum wmi_vdev_subtype vdev_subtype;
>  	u32 beacon_interval;
>  	u32 dtim_period;
>  	u16 ast_hash;
> @@ -242,13 +240,38 @@ struct ath12k_vif {
>  	u8 search_type;
>  
>  	struct ath12k *ar;
> -	struct ieee80211_vif *vif;
>  
>  	int bank_id;
>  	u8 vdev_id_check_en;
>  
>  	struct wmi_wmm_params_all_arg wmm_params;
>  	struct list_head list;
> +
> +	bool is_created;
> +	bool is_started;
> +	bool is_up;
> +	u8 bssid[ETH_ALEN];
> +	struct cfg80211_bitrate_mask bitrate_mask;
> +	struct delayed_work connection_loss_work;
> +	int num_legacy_stations;
> +	int rtscts_prot_mode;
> +	int txpower;
> +	bool rsnie_present;
> +	bool wpaie_present;
> +	struct ieee80211_chanctx_conf chanctx;
> +	u8 vdev_stats_id;
> +	u32 punct_bitmap;
> +	u8 link_id;
> +	struct ath12k_vif *ahvif;
> +	struct ath12k_vif_cache *cache;
> +};
> +
> +struct ath12k_vif {
> +	enum wmi_vdev_type vdev_type;
> +	enum wmi_vdev_subtype vdev_subtype;
> +	struct ieee80211_vif *vif;
> +	struct ath12k_hw *ah;
> +
>  	union {
>  		struct {
>  			u32 uapsd;
> @@ -266,31 +289,21 @@ struct ath12k_vif {
>  		} ap;
>  	} u;
>  
> -	bool is_created;
> -	bool is_started;
> -	bool is_up;
>  	u32 aid;
> -	u8 bssid[ETH_ALEN];
> -	struct cfg80211_bitrate_mask bitrate_mask;
> -	struct delayed_work connection_loss_work;
> -	int num_legacy_stations;
> -	int rtscts_prot_mode;
> -	int txpower;
> -	bool rsnie_present;
> -	bool wpaie_present;
> -	struct ieee80211_chanctx_conf chanctx;
>  	u32 key_cipher;
>  	u8 tx_encap_type;
> -	u8 vdev_stats_id;
> -	u32 punct_bitmap;
>  	bool ps;
> -	struct ath12k_vif_cache *cache;
> +
> +	struct ath12k_link_vif deflink;
> +	struct ath12k_link_vif __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
> +	/* indicates bitmap of link vif created in FW */
> +	u16 links_map;
>  };
>  
>  struct ath12k_vif_iter {
>  	u32 vdev_id;
>  	struct ath12k *ar;
> -	struct ath12k_vif *arvif;
> +	struct ath12k_link_vif *arvif;
>  };
>  
>  #define HAL_AST_IDX_INVALID	0xFFFF
> @@ -426,7 +439,7 @@ struct ath12k_wbm_tx_stats {
>  };
>  
>  struct ath12k_sta {
> -	struct ath12k_vif *arvif;
> +	struct ath12k_link_vif *arvif;
>  
>  	/* the following are protected by ar->data_lock */
>  	u32 changed; /* IEEE80211_RC_* */
> @@ -543,7 +556,7 @@ struct ath12k {
>  	 */
>  	struct mutex conf_mutex;
>  	/* protects the radio specific data like debug stats, ppdu_stats_info stats,
> -	 * vdev_stop_status info, scan data, ath12k_sta info, ath12k_vif info,
> +	 * vdev_stop_status info, scan data, ath12k_sta info, ath12k_link_vif info,
>  	 * channel context data, survey info, test mode data.
>  	 */
>  	spinlock_t data_lock;
> @@ -639,6 +652,11 @@ struct ath12k_hw {
>  	enum ath12k_hw_state state;
>  	bool regd_updated;
>  	bool use_6ghz_regd;
> +
> +	/* To synchronize concurrent access of ahvif->link[]
> +	 * between mac80211 operations.
> +	 */
> +	struct mutex conf_mutex;
>  	u8 num_radio;
>  
>  	/* Keep last */
> @@ -995,7 +1013,7 @@ static inline struct ath12k_skb_rxcb *ATH12K_SKB_RXCB(struct sk_buff *skb)
>  	return (struct ath12k_skb_rxcb *)skb->cb;
>  }
>  
> -static inline struct ath12k_vif *ath12k_vif_to_arvif(struct ieee80211_vif *vif)
> +static inline struct ath12k_vif *ath12k_vif_to_ahvif(struct ieee80211_vif *vif)
>  {
>  	return (struct ath12k_vif *)vif->drv_priv;
>  }
> @@ -1005,6 +1023,11 @@ static inline struct ath12k_sta *ath12k_sta_to_arsta(struct ieee80211_sta *sta)
>  	return (struct ath12k_sta *)sta->drv_priv;
>  }
>  
> +static inline struct ieee80211_vif *ath12k_vif_to_vif(struct ath12k_vif *ahvif)
better naming as ath12k_ahvif_to_vif()?

> +{
> +	return container_of((void *)ahvif, struct ieee80211_vif, drv_priv);
> +}
> +
>  static inline struct ath12k *ath12k_ab_to_ar(struct ath12k_base *ab,
>  					     int mac_id)
>  {
> diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
> index 61aa78d8bd8c..30aac0dd5a80 100644
> --- a/drivers/net/wireless/ath/ath12k/dp.c
> +++ b/drivers/net/wireless/ath/ath12k/dp.c
> @@ -327,20 +327,22 @@ int ath12k_dp_srng_setup(struct ath12k_base *ab, struct dp_srng *ring,
>  }
>  
>  static
> -u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif *arvif)
> +u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab,
> +				      struct ath12k_link_vif *arvif)
>  {
>  	u32 bank_config = 0;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
>  
>  	/* Only valid for raw frames with HW crypto enabled.
>  	 * With SW crypto, mac80211 sets key per packet
>  	 */
> -	if (arvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
> +	if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
>  	    test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags))
>  		bank_config |=
> -			u32_encode_bits(ath12k_dp_tx_get_encrypt_type(arvif->key_cipher),
> +			u32_encode_bits(ath12k_dp_tx_get_encrypt_type(ahvif->key_cipher),
>  					HAL_TX_BANK_CONFIG_ENCRYPT_TYPE);
>  
> -	bank_config |= u32_encode_bits(arvif->tx_encap_type,
> +	bank_config |= u32_encode_bits(ahvif->tx_encap_type,
>  					HAL_TX_BANK_CONFIG_ENCAP_TYPE);
>  	bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_SRC_BUFFER_SWAP) |
>  			u32_encode_bits(0, HAL_TX_BANK_CONFIG_LINK_META_SWAP) |
> @@ -355,7 +357,7 @@ u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif
>  					HAL_TX_ADDRY_EN),
>  					HAL_TX_BANK_CONFIG_ADDRY_EN);
>  
> -	bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(arvif->vif) ? 3 : 0,
> +	bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(ahvif->vif) ? 3 : 0,
>  					HAL_TX_BANK_CONFIG_MESH_EN) |
>  			u32_encode_bits(arvif->vdev_id_check_en,
>  					HAL_TX_BANK_CONFIG_VDEV_ID_CHECK_EN);
> @@ -365,7 +367,8 @@ u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif
>  	return bank_config;
>  }
>  
> -static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab, struct ath12k_vif *arvif,
> +static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab,
> +					 struct ath12k_link_vif *arvif,
>  					 struct ath12k_dp *dp)
>  {
>  	int bank_id = DP_INVALID_BANK_ID;
> @@ -1099,9 +1102,9 @@ int ath12k_dp_htt_connect(struct ath12k_dp *dp)
>  	return 0;
>  }
>  
> -static void ath12k_dp_update_vdev_search(struct ath12k_vif *arvif)
> +static void ath12k_dp_update_vdev_search(struct ath12k_link_vif *arvif)
>  {
> -	switch (arvif->vdev_type) {
> +	switch (arvif->ahvif->vdev_type) {
>  	case WMI_VDEV_TYPE_STA:
>  		/* TODO: Verify the search type and flags since ast hash
>  		 * is not part of peer mapv3
> @@ -1120,7 +1123,7 @@ static void ath12k_dp_update_vdev_search(struct ath12k_vif *arvif)
>  	}
>  }
>  
> -void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif)
> +void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif)
>  {
>  	struct ath12k_base *ab = ar->ab;
>  
> diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
> index 742094545089..4161486e98ab 100644
> --- a/drivers/net/wireless/ath/ath12k/dp.h
> +++ b/drivers/net/wireless/ath/ath12k/dp.h
> @@ -16,6 +16,7 @@ struct ath12k_base;
>  struct ath12k_peer;
>  struct ath12k_dp;
>  struct ath12k_vif;
> +struct ath12k_link_vif;
>  struct hal_tcl_status_ring;
>  struct ath12k_ext_irq_grp;
>  
> @@ -1810,7 +1811,7 @@ int ath12k_dp_service_srng(struct ath12k_base *ab,
>  			   struct ath12k_ext_irq_grp *irq_grp,
>  			   int budget);
>  int ath12k_dp_htt_connect(struct ath12k_dp *dp);
> -void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif);
> +void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif);
>  void ath12k_dp_free(struct ath12k_base *ab);
>  int ath12k_dp_alloc(struct ath12k_base *ab);
>  void ath12k_dp_cc_config(struct ath12k_base *ab);
> diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
> index 54aea3c22311..781cb7af8cf0 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_rx.c
> +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
> @@ -1090,7 +1090,7 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar,
>  	return ret;
>  }
>  
> -int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_vif *arvif,
> +int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif,
>  				       const u8 *peer_addr,
>  				       enum set_key_cmd key_cmd,
>  				       struct ieee80211_key_conf *key)
> diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
> index 2ff421160181..8c1bccc4f0f0 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_rx.h
> +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
> @@ -88,7 +88,7 @@ int ath12k_dp_rx_ampdu_start(struct ath12k *ar,
>  			     struct ieee80211_ampdu_params *params);
>  int ath12k_dp_rx_ampdu_stop(struct ath12k *ar,
>  			    struct ieee80211_ampdu_params *params);
> -int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_vif *arvif,
> +int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif,
>  				       const u8 *peer_addr,
>  				       enum set_key_cmd key_cmd,
>  				       struct ieee80211_key_conf *key);
> diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
> index c4cfa7cf7cb9..fb5de5c2794d 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_tx.c
> +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
> @@ -10,7 +10,7 @@
>  #include "hw.h"
>  
>  static enum hal_tcl_encap_type
> -ath12k_dp_tx_get_encap_type(struct ath12k_vif *arvif, struct sk_buff *skb)
> +ath12k_dp_tx_get_encap_type(struct ath12k_link_vif *arvif, struct sk_buff *skb)
>  {
>  	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
>  	struct ath12k_base *ab = arvif->ar->ab;
> @@ -162,7 +162,7 @@ static int ath12k_dp_prepare_htt_metadata(struct sk_buff *skb)
>  	return 0;
>  }
>  
> -int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
> +int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
>  		 struct sk_buff *skb)
>  {
>  	struct ath12k_base *ab = ar->ab;
> @@ -176,6 +176,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
>  	struct sk_buff *skb_ext_desc;
>  	struct hal_srng *tcl_ring;
>  	struct ieee80211_hdr *hdr = (void *)skb->data;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
>  	struct dp_tx_ring *tx_ring;
>  	u8 pool_id;
>  	u8 hal_ring_id;
> @@ -219,7 +220,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
>  	ti.bank_id = arvif->bank_id;
>  	ti.meta_data_flags = arvif->tcl_metadata;
>  
> -	if (arvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
> +	if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
>  	    test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) {
>  		if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) {
>  			ti.encrypt_type =
> @@ -304,7 +305,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
>  	ti.desc_id = tx_desc->desc_id;
>  	ti.data_len = skb->len;
>  	skb_cb->paddr = ti.paddr;
> -	skb_cb->vif = arvif->vif;
> +	skb_cb->vif = ahvif->vif;
>  	skb_cb->ar = ar;
>  
>  	if (msdu_ext_desc) {
> diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.h b/drivers/net/wireless/ath/ath12k/dp_tx.h
> index 55ff8cc721e3..46dce23501f3 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_tx.h
> +++ b/drivers/net/wireless/ath/ath12k/dp_tx.h
> @@ -16,7 +16,7 @@ struct ath12k_dp_htt_wbm_tx_status {
>  };
>  
>  int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab);
> -int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
> +int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
>  		 struct sk_buff *skb);
>  void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id);
>  
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 2259ce22cc8b..8bd8efcc1264 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -247,7 +247,7 @@ static const u32 ath12k_smps_map[] = {
>  };
>  
>  static int ath12k_start_vdev_delay(struct ath12k *ar,
> -				   struct ath12k_vif *arvif);
> +				   struct ath12k_link_vif *arvif);
>  static void ath12k_mac_stop(struct ath12k *ar);
>  static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif);
>  static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif);
> @@ -536,18 +536,22 @@ static void ath12k_get_arvif_iter(void *data, u8 *mac,
>  				  struct ieee80211_vif *vif)
>  {
>  	struct ath12k_vif_iter *arvif_iter = data;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif = &ahvif->deflink;
>  
>  	if (arvif->vdev_id == arvif_iter->vdev_id &&
>  	    arvif->ar == arvif_iter->ar)
>  		arvif_iter->arvif = arvif;
>  }
>  
> -struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id)
> +struct ath12k_link_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id)
>  {
>  	struct ath12k_vif_iter arvif_iter = {};
>  	u32 flags;
>  
> +	/* To use the arvif returned, caller must have held rcu read lock.
> +	 */
> +	WARN_ON(!rcu_read_lock_any_held());
why rcu lock needed here? what needs protecting?

>  	arvif_iter.vdev_id = vdev_id;
>  	arvif_iter.ar = ar;
>  
> @@ -564,12 +568,12 @@ struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id)
>  	return arvif_iter.arvif;
>  }
>  
> -struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
> -						   u32 vdev_id)
> +struct ath12k_link_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
> +							u32 vdev_id)
>  {
>  	int i;
>  	struct ath12k_pdev *pdev;
> -	struct ath12k_vif *arvif;
> +	struct ath12k_link_vif *arvif;
>  
>  	for (i = 0; i < ab->num_radios; i++) {
>  		pdev = rcu_dereference(ab->pdevs_active[i]);
> @@ -655,7 +659,8 @@ static struct ath12k *ath12k_get_ar_by_ctx(struct ieee80211_hw *hw,
>  static struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw,
>  					   struct ieee80211_vif *vif)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif = &ahvif->deflink;
>  	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  
>  	/* If there is one pdev within ah, then we return
> @@ -691,7 +696,7 @@ static void ath12k_pdev_caps_update(struct ath12k *ar)
>  static int ath12k_mac_txpower_recalc(struct ath12k *ar)
>  {
>  	struct ath12k_pdev *pdev = ar->pdev;
> -	struct ath12k_vif *arvif;
> +	struct ath12k_link_vif *arvif;
>  	int ret, txpower = -1;
>  	u32 param;
>  
> @@ -745,7 +750,7 @@ static int ath12k_mac_txpower_recalc(struct ath12k *ar)
>  	return ret;
>  }
>  
> -static int ath12k_recalc_rtscts_prot(struct ath12k_vif *arvif)
> +static int ath12k_recalc_rtscts_prot(struct ath12k_link_vif *arvif)
>  {
>  	struct ath12k *ar = arvif->ar;
>  	u32 vdev_param, rts_cts;
> @@ -784,7 +789,7 @@ static int ath12k_recalc_rtscts_prot(struct ath12k_vif *arvif)
>  	return ret;
>  }
>  
> -static int ath12k_mac_set_kickout(struct ath12k_vif *arvif)
> +static int ath12k_mac_set_kickout(struct ath12k_link_vif *arvif)
>  {
>  	struct ath12k *ar = arvif->ar;
>  	u32 param;
> @@ -1147,8 +1152,9 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar)
>  	return ret;
>  }
>  
> -static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif)
> +static int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif)
>  {
> +	struct ath12k_vif *ahvif = arvif->ahvif;
>  	struct ath12k *ar = arvif->ar;
>  	int ret;
>  
> @@ -1174,7 +1180,7 @@ static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif)
>  
>  	ar->num_started_vdevs--;
>  	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n",
> -		   arvif->vif->addr, arvif->vdev_id);
> +		   ahvif->vif->addr, arvif->vdev_id);
>  
>  	if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) {
>  		clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags);
> @@ -1242,7 +1248,7 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed)
>  	return ret;
>  }
>  
> -static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_vif *arvif,
> +static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_link_vif *arvif,
>  				       struct sk_buff *bcn)
>  {
>  	struct ath12k *ar = arvif->ar;
> @@ -1299,7 +1305,7 @@ static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui,
>  	return 0;
>  }
>  
> -static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *bcn,
> +static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, struct sk_buff *bcn,
>  				     u8 bssid_index, bool *nontx_profile_found)
>  {
>  	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)bcn->data;
> @@ -1391,19 +1397,22 @@ static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *b
>  	}
>  }
>  
> -static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_vif *arvif)
> +static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_link_vif *arvif)
>  {
> -	struct ieee80211_bss_conf *bss_conf = &arvif->vif->bss_conf;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +	struct ieee80211_bss_conf *bss_conf = &ahvif->vif->bss_conf;
>  	struct ath12k_wmi_bcn_tmpl_ema_arg ema_args;
>  	struct ieee80211_ema_beacons *beacons;
> -	struct ath12k_vif *tx_arvif;
> +	struct ath12k_link_vif *tx_arvif;
>  	bool nontx_profile_found = false;
> +	struct ath12k_vif *tx_ahvif;
>  	int ret = 0;
>  	u8 i;
>  
> -	tx_arvif = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif);
> +	tx_ahvif = ath12k_vif_to_ahvif(ahvif->vif->mbssid_tx_vif);
> +	tx_arvif = &tx_ahvif->deflink;
>  	beacons = ieee80211_beacon_get_template_ema_list(ath12k_ar_to_hw(tx_arvif->ar),
> -							 tx_arvif->vif, 0);
> +							 tx_ahvif->vif, 0);
>  	if (!beacons || !beacons->cnt) {
>  		ath12k_warn(arvif->ar->ab,
>  			    "failed to get ema beacon templates from mac80211\n");
> @@ -1441,22 +1450,25 @@ static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_vif *arvif)
>  	return ret;
>  }
>  
> -static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif)
> +static int ath12k_mac_setup_bcn_tmpl(struct ath12k_link_vif *arvif)
>  {
> -	struct ath12k_vif *tx_arvif = arvif;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +	struct ieee80211_vif *vif = ath12k_vif_to_vif(ahvif);
> +	struct ath12k_link_vif *tx_arvif = arvif;
>  	struct ath12k *ar = arvif->ar;
>  	struct ath12k_base *ab = ar->ab;
> -	struct ieee80211_vif *vif = arvif->vif;
>  	struct ieee80211_mutable_offsets offs = {};
> +	struct ath12k_vif *tx_ahvif = ahvif;
>  	bool nontx_profile_found = false;
>  	struct sk_buff *bcn;
>  	int ret;
>  
> -	if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
> +	if (ahvif->vdev_type != WMI_VDEV_TYPE_AP)
>  		return 0;
>  
>  	if (vif->mbssid_tx_vif) {
> -		tx_arvif = ath12k_vif_to_arvif(vif->mbssid_tx_vif);
> +		tx_ahvif = ath12k_vif_to_ahvif(vif->mbssid_tx_vif);
> +		tx_arvif = &tx_ahvif->deflink;
>  		if (tx_arvif != arvif && arvif->is_up)
>  			return 0;
>  
> @@ -1464,7 +1476,7 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif)
>  			return ath12k_mac_setup_bcn_tmpl_ema(arvif);
>  	}
>  
> -	bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_arvif->vif,
> +	bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_ahvif->vif,
>  					    &offs, 0);
>  	if (!bcn) {
>  		ath12k_warn(ab, "failed to get beacon template from mac80211\n");
> @@ -1475,14 +1487,14 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif)
>  		ath12k_mac_set_arvif_ies(arvif, bcn, 0, NULL);
>  	} else {
>  		ath12k_mac_set_arvif_ies(arvif, bcn,
> -					 arvif->vif->bss_conf.bssid_index,
> +					 ahvif->vif->bss_conf.bssid_index,
>  					 &nontx_profile_found);
>  		if (!nontx_profile_found)
>  			ath12k_warn(ab,
>  				    "nontransmitted profile not found in beacon template\n");
>  	}
>  
> -	if (arvif->vif->type == NL80211_IFTYPE_AP && arvif->vif->p2p) {
> +	if (ahvif->vif->type == NL80211_IFTYPE_AP && ahvif->vif->p2p) {
>  		ret = ath12k_mac_setup_bcn_p2p_ie(arvif, bcn);
>  		if (ret) {
>  			ath12k_warn(ab, "failed to setup P2P GO bcn ie: %d\n",
> @@ -1516,10 +1528,11 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif)
>  	return ret;
>  }
>  
> -static void ath12k_control_beaconing(struct ath12k_vif *arvif,
> +static void ath12k_control_beaconing(struct ath12k_link_vif *arvif,
>  				     struct ieee80211_bss_conf *info)
>  {
>  	struct ath12k_wmi_vdev_up_params params = {};
> +	struct ath12k_vif *ahvif = arvif->ahvif;
>  	struct ath12k *ar = arvif->ar;
>  	int ret;
>  
> @@ -1543,15 +1556,19 @@ static void ath12k_control_beaconing(struct ath12k_vif *arvif,
>  		return;
>  	}
>  
> -	arvif->aid = 0;
> +	ahvif->aid = 0;
>  
>  	ether_addr_copy(arvif->bssid, info->bssid);
>  
>  	params.vdev_id = arvif->vdev_id;
> -	params.aid = arvif->aid;
> +	params.aid = ahvif->aid;
>  	params.bssid = arvif->bssid;
> -	if (arvif->vif->mbssid_tx_vif) {
> -		params.tx_bssid = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif)->bssid;
> +	if (ahvif->vif->mbssid_tx_vif) {
> +		struct ath12k_vif *tx_ahvif =
> +			ath12k_vif_to_ahvif(ahvif->vif->mbssid_tx_vif);
> +		struct ath12k_link_vif *tx_arvif = &tx_ahvif->deflink;
> +
> +		params.tx_bssid = tx_arvif->bssid;
>  		params.nontx_profile_idx = info->bssid_index;
>  		params.nontx_profile_cnt = 1 << info->bssid_indicator;
>  	}
> @@ -1572,7 +1589,8 @@ static void ath12k_mac_handle_beacon_iter(void *data, u8 *mac,
>  {
>  	struct sk_buff *skb = data;
>  	struct ieee80211_mgmt *mgmt = (void *)skb->data;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif = &ahvif->deflink;
>  
>  	if (vif->type != NL80211_IFTYPE_STATION)
>  		return;
> @@ -1595,7 +1613,8 @@ static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
>  					       struct ieee80211_vif *vif)
>  {
>  	u32 *vdev_id = data;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif = &ahvif->deflink;
>  	struct ath12k *ar = arvif->ar;
>  	struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
>  
> @@ -1626,9 +1645,9 @@ void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id)
>  
>  static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work)
>  {
> -	struct ath12k_vif *arvif = container_of(work, struct ath12k_vif,
> -						connection_loss_work.work);
> -	struct ieee80211_vif *vif = arvif->vif;
> +	struct ath12k_link_vif *arvif = container_of(work, struct ath12k_link_vif,
> +						     connection_loss_work.work);
> +	struct ieee80211_vif *vif = arvif->ahvif->vif;
>  
>  	if (!arvif->is_up)
>  		return;
> @@ -1641,12 +1660,15 @@ static void ath12k_peer_assoc_h_basic(struct ath12k *ar,
>  				      struct ieee80211_sta *sta,
>  				      struct ath12k_wmi_peer_assoc_arg *arg)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
> +	struct ath12k_link_vif *arvif;
>  	u32 aid;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
>  	if (vif->type == NL80211_IFTYPE_STATION)
>  		aid = vif->cfg.aid;
>  	else
> @@ -1667,16 +1689,19 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar,
>  				       struct ieee80211_sta *sta,
>  				       struct ath12k_wmi_peer_assoc_arg *arg)
>  {
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ieee80211_bss_conf *info = &vif->bss_conf;
> +	struct ath12k_link_vif *arvif;
>  	struct cfg80211_chan_def def;
>  	struct cfg80211_bss *bss;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>  	struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
>  	const u8 *rsnie = NULL;
>  	const u8 *wpaie = NULL;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
>  	if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
>  		return;
>  
> @@ -1729,19 +1754,22 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar,
>  				      struct ieee80211_sta *sta,
>  				      struct ath12k_wmi_peer_assoc_arg *arg)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates;
>  	struct cfg80211_chan_def def;
>  	const struct ieee80211_supported_band *sband;
>  	const struct ieee80211_rate *rates;
>  	struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
> +	struct ath12k_link_vif *arvif;
>  	enum nl80211_band band;
>  	u32 ratemask;
>  	u8 rate;
>  	int i;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
>  	if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
>  		return;
>  
> @@ -1792,8 +1820,9 @@ static void ath12k_peer_assoc_h_ht(struct ath12k *ar,
>  				   struct ieee80211_sta *sta,
>  				   struct ath12k_wmi_peer_assoc_arg *arg)
>  {
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	struct cfg80211_chan_def def;
>  	enum nl80211_band band;
>  	const u8 *ht_mcs_mask;
> @@ -1801,8 +1830,10 @@ static void ath12k_peer_assoc_h_ht(struct ath12k *ar,
>  	u8 max_nss;
>  	u32 stbc;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
>  	if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
>  		return;
>  
> @@ -1953,8 +1984,9 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar,
>  				    struct ieee80211_sta *sta,
>  				    struct ath12k_wmi_peer_assoc_arg *arg)
>  {
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	struct cfg80211_chan_def def;
>  	enum nl80211_band band;
>  	const u16 *vht_mcs_mask;
> @@ -1963,6 +1995,9 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar,
>  	u8 max_nss, vht_mcs;
>  	int i;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
> +	arvif = &ahvif->deflink;
> +
>  	if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
>  		return;
>  
> @@ -2300,9 +2335,9 @@ static void ath12k_peer_assoc_h_qos(struct ath12k *ar,
>  				    struct ieee80211_sta *sta,
>  				    struct ath12k_wmi_peer_assoc_arg *arg)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  
> -	switch (arvif->vdev_type) {
> +	switch (ahvif->vdev_type) {
>  	case WMI_VDEV_TYPE_AP:
>  		if (sta->wme) {
>  			/* TODO: Check WME vs QoS */
> @@ -2332,7 +2367,7 @@ static void ath12k_peer_assoc_h_qos(struct ath12k *ar,
>  }
>  
>  static int ath12k_peer_assoc_qos_ap(struct ath12k *ar,
> -				    struct ath12k_vif *arvif,
> +				    struct ath12k_link_vif *arvif,
>  				    struct ieee80211_sta *sta)
>  {
>  	struct ath12k_wmi_ap_ps_arg arg;
> @@ -2498,13 +2533,17 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar,
>  					struct ieee80211_sta *sta,
>  					struct ath12k_wmi_peer_assoc_arg *arg)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>  	struct cfg80211_chan_def def;
>  	enum nl80211_band band;
>  	const u8 *ht_mcs_mask;
>  	const u16 *vht_mcs_mask;
>  	enum wmi_phy_mode phymode = MODE_UNKNOWN;
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
> +
> +	arvif = &ahvif->deflink;
>  	if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
>  		return;
>  
> @@ -2643,13 +2682,17 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar,
>  				    struct ieee80211_sta *sta,
>  				    struct ath12k_wmi_peer_assoc_arg *arg)
>  {
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	const struct ieee80211_sta_eht_cap *eht_cap = &sta->deflink.eht_cap;
>  	const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
>  	const struct ieee80211_eht_mcs_nss_supp_20mhz_only *bw_20;
>  	const struct ieee80211_eht_mcs_nss_supp_bw *bw;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	u32 *rx_mcs, *tx_mcs;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
> +
> +	arvif = &ahvif->deflink;
>  	if (!sta->deflink.he_cap.has_he || !eht_cap->has_eht)
>  		return;
>  
> @@ -2749,7 +2792,7 @@ static void ath12k_peer_assoc_prepare(struct ath12k *ar,
>  	/* TODO: amsdu_disable req? */
>  }
>  
> -static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif,
> +static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_link_vif *arvif,
>  				  const u8 *addr,
>  				  const struct ieee80211_sta_ht_cap *ht_cap,
>  				  const struct ieee80211_he_6ghz_capa *he_6ghz_capa)
> @@ -2766,10 +2809,11 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif,
>  }
>  
>  static void ath12k_bss_assoc(struct ath12k *ar,
> -			     struct ath12k_vif *arvif,
> +			     struct ath12k_link_vif *arvif,
>  			     struct ieee80211_bss_conf *bss_conf)
>  {
> -	struct ieee80211_vif *vif = arvif->vif;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +	struct ieee80211_vif *vif = ath12k_vif_to_vif(ahvif);
>  	struct ath12k_wmi_vdev_up_params params = {};
>  	struct ath12k_wmi_peer_assoc_arg peer_arg;
>  	struct ieee80211_sta *ap_sta;
> @@ -2780,7 +2824,7 @@ static void ath12k_bss_assoc(struct ath12k *ar,
>  	lockdep_assert_held(&ar->conf_mutex);
>  
>  	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n",
> -		   arvif->vdev_id, arvif->bssid, arvif->aid);
> +		   arvif->vdev_id, arvif->bssid, ahvif->aid);
>  
>  	rcu_read_lock();
>  
> @@ -2820,11 +2864,11 @@ static void ath12k_bss_assoc(struct ath12k *ar,
>  
>  	WARN_ON(arvif->is_up);
>  
> -	arvif->aid = vif->cfg.aid;
> +	ahvif->aid = vif->cfg.aid;
>  	ether_addr_copy(arvif->bssid, bss_conf->bssid);
>  
>  	params.vdev_id = arvif->vdev_id;
> -	params.aid = arvif->aid;
> +	params.aid = ahvif->aid;
>  	params.bssid = arvif->bssid;
>  	ret = ath12k_wmi_vdev_up(ar, &params);
>  	if (ret) {
> @@ -2865,7 +2909,7 @@ static void ath12k_bss_assoc(struct ath12k *ar,
>  }
>  
>  static void ath12k_bss_disassoc(struct ath12k *ar,
> -				struct ath12k_vif *arvif)
> +				struct ath12k_link_vif *arvif)
>  {
>  	int ret;
>  
> @@ -2913,17 +2957,20 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar,
>  					 struct ieee80211_vif *vif,
>  					 struct cfg80211_chan_def *def)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
>  	const struct ieee80211_supported_band *sband;
> +	struct ath12k_link_vif *arvif;
>  	u8 basic_rate_idx;
>  	int hw_rate_code;
>  	u32 vdev_param;
>  	u16 bitrate;
>  	int ret;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
>  	sband = hw->wiphy->bands[def->chan->band];
>  	basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
>  	bitrate = sband->bitrates[basic_rate_idx].bitrate;
> @@ -2947,9 +2994,10 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar,
>  		ath12k_warn(ar->ab, "failed to set beacon tx rate %d\n", ret);
>  }
>  
> -static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
> +static int ath12k_mac_fils_discovery(struct ath12k_link_vif *arvif,
>  				     struct ieee80211_bss_conf *info)
>  {
> +	struct ieee80211_vif *vif = ath12k_vif_to_vif(arvif->ahvif);
>  	struct ath12k *ar = arvif->ar;
>  	struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
>  	struct sk_buff *tmpl;
> @@ -2960,7 +3008,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
>  	if (info->fils_discovery.max_interval) {
>  		interval = info->fils_discovery.max_interval;
>  
> -		tmpl = ieee80211_get_fils_discovery_tmpl(hw, arvif->vif);
> +		tmpl = ieee80211_get_fils_discovery_tmpl(hw, vif);
>  		if (tmpl)
>  			ret = ath12k_wmi_fils_discovery_tmpl(ar, arvif->vdev_id,
>  							     tmpl);
> @@ -2968,8 +3016,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
>  		unsol_bcast_probe_resp_enabled = 1;
>  		interval = info->unsol_bcast_probe_resp_interval;
>  
> -		tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw,
> -								 arvif->vif);
> +		tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
>  		if (tmpl)
>  			ret = ath12k_wmi_probe_resp_tmpl(ar, arvif->vdev_id,
>  							 tmpl);
> @@ -2994,10 +3041,10 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
>  	return ret;
>  }
>  
> -static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif)
> +static void ath12k_mac_vif_setup_ps(struct ath12k_link_vif *arvif)
>  {
>  	struct ath12k *ar = arvif->ar;
> -	struct ieee80211_vif *vif = arvif->vif;
> +	struct ieee80211_vif *vif = arvif->ahvif->vif;
>  	struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf;
>  	enum wmi_sta_powersave_param param;
>  	enum wmi_sta_ps_mode psmode;
> @@ -3010,7 +3057,7 @@ static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif)
>  	if (vif->type != NL80211_IFTYPE_STATION)
>  		return;
>  
> -	enable_ps = arvif->ps;
> +	enable_ps = arvif->ahvif->ps;
>  	if (enable_ps) {
>  		psmode = WMI_STA_PS_MODE_ENABLED;
>  		param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
> @@ -3042,11 +3089,12 @@ static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif)
>  }
>  
>  static void ath12k_mac_bss_info_changed(struct ath12k *ar,
> -					struct ath12k_vif *arvif,
> +					struct ath12k_link_vif *arvif,
>  					struct ieee80211_bss_conf *info,
>  					u64 changed)
>  {
> -	struct ieee80211_vif *vif = arvif->vif;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +	struct ieee80211_vif *vif = ath12k_vif_to_vif(ahvif);
>  	struct ieee80211_vif_cfg *vif_cfg = &vif->cfg;
>  	struct cfg80211_chan_def def;
>  	u32 param_id, param_value;
> @@ -3116,10 +3164,10 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
>  
>  	if (changed & BSS_CHANGED_SSID &&
>  	    vif->type == NL80211_IFTYPE_AP) {
> -		arvif->u.ap.ssid_len = vif->cfg.ssid_len;
> +		ahvif->u.ap.ssid_len = vif->cfg.ssid_len;
>  		if (vif->cfg.ssid_len)
> -			memcpy(arvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len);
> -		arvif->u.ap.hidden_ssid = info->hidden_ssid;
> +			memcpy(ahvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len);
> +		ahvif->u.ap.hidden_ssid = info->hidden_ssid;
>  	}
>  
>  	if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
> @@ -3230,7 +3278,7 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
>  	}
>  
>  	if (changed & BSS_CHANGED_MCAST_RATE &&
> -	    !ath12k_mac_vif_chan(arvif->vif, &def)) {
> +	    !ath12k_mac_vif_chan(vif, &def)) {
>  		band = def.chan->band;
>  		mcast_rate = vif->bss_conf.mcast_rate[band];
>  
> @@ -3274,7 +3322,7 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
>  	}
>  
>  	if (changed & BSS_CHANGED_BASIC_RATES &&
> -	    !ath12k_mac_vif_chan(arvif->vif, &def))
> +	    !ath12k_mac_vif_chan(vif, &def))
>  		ath12k_recalculate_mgmt_rate(ar, vif, &def);
>  
>  	if (changed & BSS_CHANGED_TWT) {
> @@ -3320,12 +3368,12 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
>  
>  	if (changed & BSS_CHANGED_PS &&
>  	    ar->ab->hw_params->supports_sta_ps) {
> -		arvif->ps = vif_cfg->ps;
> +		ahvif->ps = vif_cfg->ps;
>  		ath12k_mac_vif_setup_ps(arvif);
>  	}
>  }
>  
> -static struct ath12k_vif_cache *ath12k_arvif_get_cache(struct ath12k_vif *arvif)
> +static struct ath12k_vif_cache *ath12k_arvif_get_cache(struct ath12k_link_vif *arvif)
>  {
>  	if (!arvif->cache)
>  		arvif->cache = kzalloc(sizeof(*arvif->cache), GFP_KERNEL);
> @@ -3333,7 +3381,7 @@ static struct ath12k_vif_cache *ath12k_arvif_get_cache(struct ath12k_vif *arvif)
>  	return arvif->cache;
>  }
>  
> -static void ath12k_arvif_put_cache(struct ath12k_vif *arvif)
> +static void ath12k_arvif_put_cache(struct ath12k_link_vif *arvif)
>  {
>  	kfree(arvif->cache);
>  	arvif->cache = NULL;
> @@ -3344,10 +3392,17 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
>  					   struct ieee80211_bss_conf *info,
>  					   u64 changed)
>  {
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k_vif_cache *cache;
> +	struct ath12k_link_vif *arvif;
>  
> +	mutex_lock(&ah->conf_mutex);
> +	/* TODO use info->link_id and fetch corresponding ahvif->link[]
> +	 * with MLO support.
> +	 */
> +	arvif = &ahvif->deflink;
>  	ar = ath12k_get_ar_by_vif(hw, vif);
>  
>  	/* if the vdev is not created on a certain radio,
> @@ -3355,10 +3410,17 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
>  	 */
>  
>  	if (!ar) {
> +		/* TODO Once link vif is fetched based on link id from
> +		 * info, avoid using the deflink above and cache the link
> +		 * configs in ahvif per link.
> +		 */
>  		cache = ath12k_arvif_get_cache(arvif);
> -		if (!cache)
> +		if (!cache) {
> +			mutex_unlock(&ah->conf_mutex);
>  			return;
> +		}
>  		arvif->cache->bss_conf_changed |= changed;
> +		mutex_unlock(&ah->conf_mutex);
>  		return;
>  	}
>  
> @@ -3367,6 +3429,7 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
>  	ath12k_mac_bss_info_changed(ar, arvif, info, changed);
>  
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  }
>  
>  static struct ath12k*
> @@ -3575,13 +3638,17 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
>  {
>  	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar, *prev_ar;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	struct cfg80211_scan_request *req = &hw_req->req;
>  	struct ath12k_wmi_scan_req_arg arg = {};
>  	int ret;
>  	int i;
>  	bool create = true;
>  
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
> +
>  	if (ah->num_radio == 1) {
>  		WARN_ON(!arvif->is_created);
>  		ar = ath12k_ah_to_ar(ah, 0);
> @@ -3592,9 +3659,10 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
>  	 * requested in the hw_req, select the corresponding radio
>  	 */
>  	ar = ath12k_mac_select_scan_device(hw, vif, hw_req->req.channels[0]->center_freq);
> -	if (!ar)
> +	if (!ar) {
> +		mutex_unlock(&ah->conf_mutex);
>  		return -EINVAL;
> -
> +	}
>  	/* If the vif is already assigned to a specific vdev of an ar,
>  	 * check whether its already started, vdev which is started
>  	 * are not allowed to switch to a new radio.
> @@ -3605,11 +3673,15 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
>  	 * always on the same band for the vif
>  	 */
>  	if (arvif->is_created) {
> -		if (WARN_ON(!arvif->ar))
> +		if (WARN_ON(!arvif->ar)) {
> +			mutex_unlock(&ah->conf_mutex);
>  			return -EINVAL;
> +		}
>  
> -		if (ar != arvif->ar && arvif->is_started)
> +		if (ar != arvif->ar && arvif->is_started) {
> +			mutex_unlock(&ah->conf_mutex);
>  			return -EINVAL;
> +		}
>  
>  		if (ar != arvif->ar) {
>  			/* backup the previously used ar ptr, since the vdev delete
> @@ -3632,6 +3704,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
>  		mutex_unlock(&ar->conf_mutex);
>  		if (ret) {
>  			ath12k_warn(ar->ab, "unable to create scan vdev %d\n", ret);
> +			mutex_unlock(&ah->conf_mutex);
>  			return -EINVAL;
>  		}
>  	}
> @@ -3714,21 +3787,30 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
>  		kfree(arg.extraie.ptr);
>  
>  	mutex_unlock(&ar->conf_mutex);
> -
> +	mutex_unlock(&ah->conf_mutex);
>  	return ret;
>  }
>  
>  static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw,
>  					 struct ieee80211_vif *vif)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
> +	struct ath12k_link_vif *arvif;
>  	struct ath12k *ar;
>  
> -	if (!arvif->is_created)
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
> +
> +	if (!arvif->is_created) {
> +		mutex_unlock(&ah->conf_mutex);
>  		return;
> +	}
>  
>  	ar = arvif->ar;
>  
> +	mutex_unlock(&ah->conf_mutex);
> +
>  	mutex_lock(&ar->conf_mutex);
>  	ath12k_scan_abort(ar);
>  	mutex_unlock(&ar->conf_mutex);
> @@ -3736,7 +3818,7 @@ static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw,
>  	cancel_delayed_work_sync(&ar->scan.timeout);
>  }
>  
> -static int ath12k_install_key(struct ath12k_vif *arvif,
> +static int ath12k_install_key(struct ath12k_link_vif *arvif,
>  			      struct ieee80211_key_conf *key,
>  			      enum set_key_cmd cmd,
>  			      const u8 *macaddr, u32 flags)
> @@ -3751,6 +3833,8 @@ static int ath12k_install_key(struct ath12k_vif *arvif,
>  		.key_flags = flags,
>  		.macaddr = macaddr,
>  	};
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +	struct ieee80211_vif *vif = ath12k_vif_to_vif(ahvif);
>  
>  	lockdep_assert_held(&arvif->ar->conf_mutex);
>  
> @@ -3803,13 +3887,13 @@ static int ath12k_install_key(struct ath12k_vif *arvif,
>  	if (!wait_for_completion_timeout(&ar->install_key_done, 1 * HZ))
>  		return -ETIMEDOUT;
>  
> -	if (ether_addr_equal(macaddr, arvif->vif->addr))
> -		arvif->key_cipher = key->cipher;
> +	if (ether_addr_equal(macaddr, vif->addr))
> +		ahvif->key_cipher = key->cipher;
>  
>  	return ar->install_key_status ? -EINVAL : 0;
>  }
>  
> -static int ath12k_clear_peer_keys(struct ath12k_vif *arvif,
> +static int ath12k_clear_peer_keys(struct ath12k_link_vif *arvif,
>  				  const u8 *addr)
>  {
>  	struct ath12k *ar = arvif->ar;
> @@ -3855,22 +3939,25 @@ 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_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k_base *ab = ar->ab;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	struct ath12k_peer *peer;
>  	struct ath12k_sta *arsta;
>  	const u8 *peer_addr;
>  	int ret = 0;
>  	u32 flags = 0;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
>  	if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags))
>  		return 1;
>  
>  	if (sta)
>  		peer_addr = sta->addr;
> -	else if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
> +	else if (ahvif->vdev_type == WMI_VDEV_TYPE_STA)
>  		peer_addr = vif->bss_conf.bssid;
>  	else
>  		peer_addr = vif->addr;
> @@ -3966,41 +4053,60 @@ 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 *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
> +	struct ath12k_link_vif *arvif;
>  	struct ath12k_vif_cache *cache;
>  	struct ath12k *ar;
>  	int ret;
>  
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
>  	/* 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)
> +	    key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) {
> +		mutex_unlock(&ah->conf_mutex);
>  		return 1;
> +	}
>  
> -	if (key->keyidx > WMI_MAX_KEY_INDEX)
> +	if (key->keyidx > WMI_MAX_KEY_INDEX) {
> +		mutex_unlock(&ah->conf_mutex);
>  		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);
> +			mutex_unlock(&ah->conf_mutex);
>  			return -EINVAL;
>  		}
>  
>  		cache = ath12k_arvif_get_cache(arvif);
> -		if (!cache)
> +		if (!cache) {
> +			mutex_unlock(&ah->conf_mutex);
>  			return -ENOSPC;
> +		}
>  		cache->key_conf.cmd = cmd;
>  		cache->key_conf.key = key;
>  		cache->key_conf.changed = true;
> +		mutex_unlock(&ah->conf_mutex);
>  		return 0;
>  	}
>  
> +	/* Note: Currently only deflink of ahvif is used here, once MLO
> +	 * support is added the allocated links (i.e ahvif->links[])
> +	 * should be use based on link id passed from mac80211 and such link
> +	 * access needs to be protected with ah->conf_mutex.
> +	 */
> +
>  	mutex_lock(&ar->conf_mutex);
>  	ret = ath12k_mac_set_key(ar, cmd, vif, sta, key);
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  	return ret;
>  }
>  
> @@ -4019,7 +4125,7 @@ ath12k_mac_bitrate_mask_num_vht_rates(struct ath12k *ar,
>  }
>  
>  static int
> -ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_vif *arvif,
> +ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_link_vif *arvif,
>  				   struct ieee80211_sta *sta,
>  				   const struct cfg80211_bitrate_mask *mask,
>  				   enum nl80211_band band)
> @@ -4069,16 +4175,19 @@ static int ath12k_station_assoc(struct ath12k *ar,
>  				struct ieee80211_sta *sta,
>  				bool reassoc)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k_wmi_peer_assoc_arg peer_arg;
>  	int ret;
>  	struct cfg80211_chan_def def;
>  	enum nl80211_band band;
> +	struct ath12k_link_vif *arvif;
>  	struct cfg80211_bitrate_mask *mask;
>  	u8 num_vht_rates;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
>  	if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
>  		return -EPERM;
>  
> @@ -4152,11 +4261,14 @@ static int ath12k_station_disassoc(struct ath12k *ar,
>  				   struct ieee80211_vif *vif,
>  				   struct ieee80211_sta *sta)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	int ret;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
>  	if (!sta->wme) {
>  		arvif->num_legacy_stations--;
>  		ret = ath12k_recalc_rtscts_prot(arvif);
> @@ -4176,8 +4288,8 @@ static int ath12k_station_disassoc(struct ath12k *ar,
>  static void ath12k_sta_rc_update_wk(struct work_struct *wk)
>  {
>  	struct ath12k *ar;
> -	struct ath12k_vif *arvif;
>  	struct ath12k_sta *arsta;
> +	struct ath12k_link_vif *arvif;
>  	struct ieee80211_sta *sta;
>  	struct cfg80211_chan_def def;
>  	enum nl80211_band band;
> @@ -4188,13 +4300,15 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
>  	const struct cfg80211_bitrate_mask *mask;
>  	struct ath12k_wmi_peer_assoc_arg peer_arg;
>  	enum wmi_phy_mode peer_phymode;
> +	struct ieee80211_vif *vif;
>  
>  	arsta = container_of(wk, struct ath12k_sta, update_wk);
>  	sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
>  	arvif = arsta->arvif;
> +	vif = ath12k_vif_to_vif(arvif->ahvif);
>  	ar = arvif->ar;
>  
> -	if (WARN_ON(ath12k_mac_vif_chan(arvif->vif, &def)))
> +	if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
>  		return;
>  
>  	band = def.chan->band;
> @@ -4220,7 +4334,7 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
>  			   ath12k_mac_max_vht_nss(vht_mcs_mask)));
>  
>  	if (changed & IEEE80211_RC_BW_CHANGED) {
> -		ath12k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg);
> +		ath12k_peer_assoc_h_phymode(ar, vif, sta, &peer_arg);
>  		peer_phymode = peer_arg.peer_phymode;
>  
>  		if (bw > bw_prev) {
> @@ -4315,7 +4429,7 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
>  			 * is provided in the new bitrate mask we set the
>  			 * other rates using peer_assoc command.
>  			 */
> -			ath12k_peer_assoc_prepare(ar, arvif->vif, sta,
> +			ath12k_peer_assoc_prepare(ar, vif, sta,
>  						  &peer_arg, true);
>  
>  			err = ath12k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
> @@ -4332,14 +4446,14 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk)
>  	mutex_unlock(&ar->conf_mutex);
>  }
>  
> -static int ath12k_mac_inc_num_stations(struct ath12k_vif *arvif,
> +static int ath12k_mac_inc_num_stations(struct ath12k_link_vif *arvif,
>  				       struct ieee80211_sta *sta)
>  {
>  	struct ath12k *ar = arvif->ar;
>  
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> -	if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
> +	if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
>  		return 0;
>  
>  	if (ar->num_stations >= ar->max_num_stations)
> @@ -4350,14 +4464,14 @@ static int ath12k_mac_inc_num_stations(struct ath12k_vif *arvif,
>  	return 0;
>  }
>  
> -static void ath12k_mac_dec_num_stations(struct ath12k_vif *arvif,
> +static void ath12k_mac_dec_num_stations(struct ath12k_link_vif *arvif,
>  					struct ieee80211_sta *sta)
>  {
>  	struct ath12k *ar = arvif->ar;
>  
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> -	if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
> +	if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
>  		return;
>  
>  	ar->num_stations--;
> @@ -4368,20 +4482,22 @@ static int ath12k_mac_station_add(struct ath12k *ar,
>  				  struct ieee80211_sta *sta)
>  {
>  	struct ath12k_base *ab = ar->ab;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
>  	struct ath12k_wmi_peer_create_arg peer_param;
> +	struct ath12k_link_vif *arvif;
>  	int ret;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
>  	ret = ath12k_mac_inc_num_stations(arvif, sta);
>  	if (ret) {
>  		ath12k_warn(ab, "refusing to associate station: too many connected already (%d)\n",
>  			    ar->max_num_stations);
>  		goto exit;
>  	}
> -
>  	arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL);
>  	if (!arsta->rx_stats) {
>  		ret = -ENOMEM;
> @@ -4422,7 +4538,7 @@ static int ath12k_mac_station_add(struct ath12k *ar,
>  
>  	if (ab->hw_params->vdev_start_delay &&
>  	    !arvif->is_started &&
> -	    arvif->vdev_type != WMI_VDEV_TYPE_AP) {
> +	    arvif->ahvif->vdev_type != WMI_VDEV_TYPE_AP) {
>  		ret = ath12k_start_vdev_delay(ar, arvif);
>  		if (ret) {
>  			ath12k_warn(ab, "failed to delay vdev start: %d\n", ret);
> @@ -4477,12 +4593,17 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
>  				   enum ieee80211_sta_state old_state,
>  				   enum ieee80211_sta_state new_state)
>  {
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k *ar;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>  	struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
> +	struct ath12k_link_vif *arvif;
>  	struct ath12k_peer *peer;
>  	int ret = 0;
>  
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
> +
>  	/* cancel must be done outside the mutex to avoid deadlock */
>  	if ((old_state == IEEE80211_STA_NONE &&
>  	     new_state == IEEE80211_STA_NOTEXIST))
> @@ -4491,9 +4612,9 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
>  	ar = ath12k_get_ar_by_vif(hw, vif);
>  	if (!ar) {
>  		WARN_ON_ONCE(1);
> +		mutex_unlock(&ah->conf_mutex);
>  		return -EINVAL;
>  	}
> -
>  	mutex_lock(&ar->conf_mutex);
>  
>  	if (old_state == IEEE80211_STA_NOTEXIST &&
> @@ -4508,7 +4629,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
>  				    sta->addr, arvif->vdev_id);
>  	} else if ((old_state == IEEE80211_STA_NONE &&
>  		    new_state == IEEE80211_STA_NOTEXIST)) {
> -		if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
> +		if (ahvif->vdev_type == WMI_VDEV_TYPE_STA) {
>  			ath12k_bss_disassoc(ar, arvif);
>  			ret = ath12k_mac_vdev_stop(arvif);
>  			if (ret)
> @@ -4596,6 +4717,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
>  	}
>  
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  
>  	return ret;
>  }
> @@ -4606,20 +4728,28 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
>  {
>  	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	int ret;
>  	s16 txpwr;
>  
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
> +
>  	if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC) {
>  		txpwr = 0;
>  	} else {
>  		txpwr = sta->deflink.txpwr.power;
> -		if (!txpwr)
> +		if (!txpwr) {
> +			mutex_unlock(&ah->conf_mutex);
>  			return -EINVAL;
> +		}
>  	}
>  
> -	if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL)
> +	if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL) {
> +		mutex_unlock(&ah->conf_mutex);
>  		return -EINVAL;
> +	}
>  
>  	ar = ath12k_ah_to_ar(ah, 0);
>  
> @@ -4635,6 +4765,7 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
>  
>  out:
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  	return ret;
>  }
>  
> @@ -4645,7 +4776,8 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
>  {
>  	struct ath12k *ar;
>  	struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	struct ath12k_peer *peer;
>  	u32 bw, smps;
>  
> @@ -4655,11 +4787,14 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
>  		return;
>  	}
>  
> +	rcu_read_lock();
> +	arvif = &ahvif->deflink;
does ath12k_vif::deflink need rcu protect? note it is not declared as rcu*, and even mac80211 uses it without holding such lock. See
	ieee80211_mgd_auth() {
		struct ieee80211_link_data *link;
		...
		if()
			...
		else
			link = &sdata->deflink;

		...
	}

>  	spin_lock_bh(&ar->ab->base_lock);
>  
>  	peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
>  	if (!peer) {
>  		spin_unlock_bh(&ar->ab->base_lock);
> +		rcu_read_unlock();
>  		ath12k_warn(ar->ab, "mac sta rc update failed to find peer %pM on vdev %i\n",
>  			    sta->addr, arvif->vdev_id);
>  		return;
> @@ -4712,16 +4847,18 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
>  	spin_unlock_bh(&ar->data_lock);
>  
>  	ieee80211_queue_work(hw, &arsta->update_wk);
> +	rcu_read_unlock();
>  }
>  
> -static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif,
> +static int ath12k_conf_tx_uapsd(struct ath12k_link_vif *arvif,
>  				u16 ac, bool enable)
>  {
>  	struct ath12k *ar = arvif->ar;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
>  	u32 value;
>  	int ret;
>  
> -	if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
> +	if (ahvif->vdev_type != WMI_VDEV_TYPE_STA)
>  		return 0;
>  
>  	switch (ac) {
> @@ -4744,19 +4881,19 @@ static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif,
>  	}
>  
>  	if (enable)
> -		arvif->u.sta.uapsd |= value;
> +		ahvif->u.sta.uapsd |= value;
>  	else
> -		arvif->u.sta.uapsd &= ~value;
> +		ahvif->u.sta.uapsd &= ~value;
>  
>  	ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
>  					  WMI_STA_PS_PARAM_UAPSD,
> -					  arvif->u.sta.uapsd);
> +					  ahvif->u.sta.uapsd);
>  	if (ret) {
>  		ath12k_warn(ar->ab, "could not set uapsd params %d\n", ret);
>  		goto exit;
>  	}
>  
> -	if (arvif->u.sta.uapsd)
> +	if (ahvif->u.sta.uapsd)
>  		value = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD;
>  	else
>  		value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
> @@ -4771,7 +4908,7 @@ static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif,
>  	return ret;
>  }
>  
> -static int ath12k_mac_conf_tx(struct ath12k_vif *arvif,
> +static int ath12k_mac_conf_tx(struct ath12k_link_vif *arvif,
>  			      unsigned int link_id, u16 ac,
>  			      const struct ieee80211_tx_queue_params *params)
>  {
> @@ -4829,27 +4966,34 @@ static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw,
>  				 unsigned int link_id, u16 ac,
>  				 const struct ieee80211_tx_queue_params *params)
>  {
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
> +	struct ath12k_link_vif *arvif;
> +	struct ath12k_vif_cache *cache;
>  	struct ath12k *ar;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> -	struct ath12k_vif_cache *cache = arvif->cache;
>  	int ret;
>  
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
>  	ar = ath12k_get_ar_by_vif(hw, vif);
>  	if (!ar) {
>  		/* cache the info and apply after vdev is created */
>  		cache = ath12k_arvif_get_cache(arvif);
> -		if (!cache)
> +		if (!cache) {
> +			mutex_unlock(&ah->conf_mutex);
>  			return -ENOSPC;
> +		}
>  		cache->tx_conf.changed = true;
>  		cache->tx_conf.ac = ac;
>  		cache->tx_conf.tx_queue_params = *params;
> +		mutex_unlock(&ah->conf_mutex);
>  		return 0;
>  	}
>  
>  	mutex_lock(&ar->conf_mutex);
>  	ret = ath12k_mac_conf_tx(arvif, link_id, ac, params);
>  	mutex_unlock(&ar->conf_mutex);
> -
> +	mutex_unlock(&ah->conf_mutex);
>  	return ret;
>  }
>  
> @@ -4919,10 +5063,11 @@ ath12k_create_ht_cap(struct ath12k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask
>  	return ht_cap;
>  }
>  
> -static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif)
> +static int ath12k_mac_set_txbf_conf(struct ath12k_link_vif *arvif)
>  {
>  	u32 value = 0;
>  	struct ath12k *ar = arvif->ar;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
>  	int nsts;
>  	int sound_dim;
>  	u32 vht_cap = ar->pdev->cap.vht_cap;
> @@ -4950,7 +5095,7 @@ static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif)
>  		value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER;
>  
>  		if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) &&
> -		    arvif->vdev_type == WMI_VDEV_TYPE_AP)
> +		    ahvif->vdev_type == WMI_VDEV_TYPE_AP)
>  			value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER;
>  	}
>  
> @@ -4958,7 +5103,7 @@ static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif)
>  		value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE;
>  
>  		if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) &&
> -		    arvif->vdev_type == WMI_VDEV_TYPE_STA)
> +		    ahvif->vdev_type == WMI_VDEV_TYPE_STA)
>  			value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE;
>  	}
>  
> @@ -5619,7 +5764,7 @@ static int ath12k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
>  	return 0;
>  }
>  
> -static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_vif *arvif,
> +static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_link_vif *arvif,
>  				  struct sk_buff *skb)
>  {
>  	struct ath12k_base *ab = ar->ab;
> @@ -5687,7 +5832,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work)
>  {
>  	struct ath12k *ar = container_of(work, struct ath12k, wmi_mgmt_tx_work);
>  	struct ath12k_skb_cb *skb_cb;
> -	struct ath12k_vif *arvif;
> +	struct ath12k_vif *ahvif;
> +	struct ath12k_link_vif *arvif;
>  	struct sk_buff *skb;
>  	int ret;
>  
> @@ -5699,8 +5845,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work)
>  			continue;
>  		}
>  
> -		arvif = ath12k_vif_to_arvif(skb_cb->vif);
> -
> +		ahvif = ath12k_vif_to_ahvif(skb_cb->vif);
> +		arvif = &ahvif->deflink;
>  		if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) {
>  			ret = ath12k_mac_mgmt_tx_wmi(ar, arvif, skb);
>  			if (ret) {
> @@ -5755,18 +5901,18 @@ static void ath12k_mac_add_p2p_noa_ie(struct ath12k *ar,
>  				      struct sk_buff *skb,
>  				      bool is_prb_rsp)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  
>  	if (likely(!is_prb_rsp))
>  		return;
>  
>  	spin_lock_bh(&ar->data_lock);
>  
> -	if (arvif->u.ap.noa_data &&
> -	    !pskb_expand_head(skb, 0, arvif->u.ap.noa_len,
> +	if (ahvif->u.ap.noa_data &&
> +	    !pskb_expand_head(skb, 0, ahvif->u.ap.noa_len,
>  			      GFP_ATOMIC))
> -		skb_put_data(skb, arvif->u.ap.noa_data,
> -			     arvif->u.ap.noa_len);
> +		skb_put_data(skb, ahvif->u.ap.noa_data,
> +			     ahvif->u.ap.noa_len);
>  
>  	spin_unlock_bh(&ar->data_lock);
>  }
> @@ -5778,7 +5924,8 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw,
>  	struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
>  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
>  	struct ieee80211_vif *vif = info->control.vif;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif = &ahvif->deflink;
>  	struct ath12k *ar = arvif->ar;
>  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
>  	struct ieee80211_key_conf *key = info->control.hw_key;
> @@ -6131,7 +6278,7 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
>  }
>  
>  static u8
> -ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif)
> +ath12k_mac_get_vdev_stats_id(struct ath12k_link_vif *arvif)
>  {
>  	struct ath12k_base *ab = arvif->ar->ab;
>  	u8 vdev_stats_id = 0;
> @@ -6153,19 +6300,22 @@ ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif)
>  	return vdev_stats_id;
>  }
>  
> -static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_vif *arvif,
> +static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_link_vif *arvif,
>  					       u32 *flags, u32 *tx_vdev_id)
>  {
> -	struct ieee80211_vif *tx_vif = arvif->vif->mbssid_tx_vif;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +	struct ieee80211_vif *tx_vif = ahvif->vif->mbssid_tx_vif;
>  	struct ath12k *ar = arvif->ar;
> -	struct ath12k_vif *tx_arvif;
> +	struct ath12k_link_vif *tx_arvif;
> +	struct ath12k_vif *tx_ahvif;
>  
>  	if (!tx_vif)
>  		return 0;
>  
> -	tx_arvif = ath12k_vif_to_arvif(tx_vif);
> +	tx_ahvif = ath12k_vif_to_ahvif(tx_vif);
> +	tx_arvif = &tx_ahvif->deflink;
>  
> -	if (arvif->vif->bss_conf.nontransmitted) {
> +	if (ahvif->vif->bss_conf.nontransmitted) {
>  		if (ar->ah->hw->wiphy != ieee80211_vif_to_wdev(tx_vif)->wiphy)
>  			return -EINVAL;
>  
> @@ -6177,22 +6327,23 @@ static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_vif *arvif,
>  		return -EINVAL;
>  	}
>  
> -	if (arvif->vif->bss_conf.ema_ap)
> +	if (ahvif->vif->bss_conf.ema_ap)
>  		*flags |= WMI_VDEV_MBSSID_FLAGS_EMA_MODE;
>  
>  	return 0;
>  }
>  
> -static int ath12k_mac_setup_vdev_create_arg(struct ath12k_vif *arvif,
> +static int ath12k_mac_setup_vdev_create_arg(struct ath12k_link_vif *arvif,
>  					    struct ath12k_wmi_vdev_create_arg *arg)
>  {
>  	struct ath12k *ar = arvif->ar;
>  	struct ath12k_pdev *pdev = ar->pdev;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
>  	int ret;
>  
>  	arg->if_id = arvif->vdev_id;
> -	arg->type = arvif->vdev_type;
> -	arg->subtype = arvif->vdev_subtype;
> +	arg->type = ahvif->vdev_type;
> +	arg->subtype = ahvif->vdev_subtype;
>  	arg->pdev_id = pdev->pdev_id;
>  
>  	arg->mbssid_flags = WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP;
> @@ -6259,14 +6410,15 @@ ath12k_mac_prepare_he_mode(struct ath12k_pdev *pdev, u32 viftype)
>  }
>  
>  static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar,
> -					  struct ath12k_vif *arvif)
> +					  struct ath12k_link_vif *arvif)
>  {
>  	u32 param_id, param_value;
>  	struct ath12k_base *ab = ar->ab;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
>  	int ret;
>  
>  	param_id = WMI_VDEV_PARAM_SET_HEMU_MODE;
> -	param_value = ath12k_mac_prepare_he_mode(ar->pdev, arvif->vif->type);
> +	param_value = ath12k_mac_prepare_he_mode(ar->pdev, ahvif->vif->type);
>  	ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
>  					    param_id, param_value);
>  	if (ret) {
> @@ -6289,9 +6441,10 @@ static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar,
>  	return ret;
>  }
>  
> -static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif)
> +static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif)
>  {
> -	struct ieee80211_vif *vif = arvif->vif;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +	struct ieee80211_vif *vif = ath12k_vif_to_vif(ahvif);
>  	struct ath12k *ar = arvif->ar;
>  	struct ath12k_base *ab = ar->ab;
>  	u32 param_id, param_value;
> @@ -6304,14 +6457,14 @@ static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif)
>  					IEEE80211_OFFLOAD_DECAP_ENABLED);
>  
>  	if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
> -		arvif->tx_encap_type = ATH12K_HW_TXRX_ETHERNET;
> +		ahvif->tx_encap_type = ATH12K_HW_TXRX_ETHERNET;
>  	else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))
> -		arvif->tx_encap_type = ATH12K_HW_TXRX_RAW;
> +		ahvif->tx_encap_type = ATH12K_HW_TXRX_RAW;
>  	else
> -		arvif->tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI;
> +		ahvif->tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI;
>  
>  	ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
> -					    param_id, arvif->tx_encap_type);
> +					    param_id, ahvif->tx_encap_type);
>  	if (ret) {
>  		ath12k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
>  			    arvif->vdev_id, ret);
> @@ -6338,57 +6491,60 @@ static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif)
>  static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
>  					     struct ieee80211_vif *vif)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  
> -	ath12k_mac_update_vif_offload(arvif);
> +	ath12k_mac_update_vif_offload(&ahvif->deflink);
>  }
>  
> -static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
> +int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
>  {
>  	struct ath12k_hw *ah = ar->ah;
>  	struct ath12k_base *ab = ar->ab;
>  	struct ieee80211_hw *hw = ah->hw;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k_wmi_vdev_create_arg vdev_arg = {0};
>  	struct ath12k_wmi_peer_create_arg peer_param;
> +	struct ath12k_link_vif *arvif;
>  	u32 param_id, param_value;
>  	u16 nss;
>  	int i;
>  	int ret, vdev_id;
>  
> +	lockdep_assert_held(&ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
>  	arvif->ar = ar;
>  	vdev_id = __ffs64(ab->free_vdev_map);
>  	arvif->vdev_id = vdev_id;
> -	arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
> +	ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
>  
>  	switch (vif->type) {
>  	case NL80211_IFTYPE_UNSPECIFIED:
>  	case NL80211_IFTYPE_STATION:
> -		arvif->vdev_type = WMI_VDEV_TYPE_STA;
> +		ahvif->vdev_type = WMI_VDEV_TYPE_STA;
>  
>  		if (vif->p2p)
> -			arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT;
> +			ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT;
>  
>  		break;
>  	case NL80211_IFTYPE_MESH_POINT:
> -		arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S;
> +		ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S;
>  		fallthrough;
>  	case NL80211_IFTYPE_AP:
> -		arvif->vdev_type = WMI_VDEV_TYPE_AP;
> +		ahvif->vdev_type = WMI_VDEV_TYPE_AP;
>  
>  		if (vif->p2p)
> -			arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO;
> +			ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO;
>  
>  		break;
>  	case NL80211_IFTYPE_MONITOR:
> -		arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
> +		ahvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
>  		ar->monitor_vdev_id = vdev_id;
>  		break;
>  	case NL80211_IFTYPE_P2P_DEVICE:
> -		arvif->vdev_type = WMI_VDEV_TYPE_STA;
> -		arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
> +		ahvif->vdev_type = WMI_VDEV_TYPE_STA;
> +		ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
>  		break;
>  	default:
>  		WARN_ON(1);
> @@ -6396,7 +6552,7 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
>  	}
>  
>  	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev create id %d type %d subtype %d map %llx\n",
> -		   arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
> +		   arvif->vdev_id, ahvif->vdev_type, ahvif->vdev_subtype,
>  		   ab->free_vdev_map);
>  
>  	vif->cab_queue = arvif->vdev_id % (ATH12K_HW_MAX_QUEUES - 1);
> @@ -6439,7 +6595,7 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
>  		goto err_vdev_del;
>  	}
>  
> -	switch (arvif->vdev_type) {
> +	switch (ahvif->vdev_type) {
>  	case WMI_VDEV_TYPE_AP:
>  		peer_param.vdev_id = arvif->vdev_id;
>  		peer_param.peer_addr = vif->addr;
> @@ -6515,15 +6671,19 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
>  	}
>  
>  	ath12k_dp_vdev_tx_attach(ar, arvif);
> -
>  	if (vif->type != NL80211_IFTYPE_MONITOR && ar->monitor_conf_enabled)
>  		ath12k_mac_monitor_vdev_create(ar);
>  
>  	arvif->ar = ar;
> +	/* TODO use appropriate link id once MLO support is added.
> +	 */
> +	arvif->link_id = ATH12K_DEFAULT_LINK_ID;
> +	rcu_assign_pointer(ahvif->link[arvif->link_id], arvif);
> +	ahvif->links_map = BIT(arvif->link_id);
>  	return ret;
>  
>  err_peer_del:
> -	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
> +	if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
>  		reinit_completion(&ar->peer_delete_done);
>  
>  		ret = ath12k_wmi_send_peer_delete_cmd(ar, vif->addr,
> @@ -6559,16 +6719,19 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
>  	return ret;
>  }
>  
> -static void ath12k_mac_vif_cache_flush(struct ath12k *ar,  struct ieee80211_vif *vif)
> +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_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_vif_cache *cache;
>  	struct ath12k_base *ab = ar->ab;
> -
> +	struct ath12k_link_vif *arvif;
>  	int ret;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
>  
> +	arvif = &ahvif->deflink;
> +	cache = arvif->cache;
>  	if (!cache)
>  		return;
>  
> @@ -6600,12 +6763,16 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
>  						    struct ieee80211_vif *vif,
>  						    struct ieee80211_chanctx_conf *ctx)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	struct ath12k_hw *ah = hw->priv;
>  	struct ath12k *ar, *prev_ar;
>  	struct ath12k_base *ab;
>  	int ret;
>  
> +	lockdep_assert_held(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
> +
>  	if (ah->num_radio == 1)
>  		ar = ah->radio;
>  	else if (ctx)
> @@ -6687,12 +6854,18 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
>  static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>  				       struct ieee80211_vif *vif)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	int i;
>  
> -	memset(arvif, 0, sizeof(*arvif));
> +	mutex_lock(&ah->conf_mutex);
> +	memset(ahvif, 0, sizeof(*ahvif));
>  
> -	arvif->vif = vif;
> +	ahvif->ah = ah;
> +	ahvif->vif = vif;
> +	arvif = &ahvif->deflink;
> +	arvif->ahvif = ahvif;
>  
>  	INIT_LIST_HEAD(&arvif->list);
>  	INIT_DELAYED_WORK(&arvif->connection_loss_work,
> @@ -6719,6 +6892,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>  	 * vdev needs to be created
>  	 */
>  	ath12k_mac_assign_vif_to_vdev(hw, vif, NULL);
> +	mutex_unlock(&ah->conf_mutex);
>  	return 0;
>  }
>  
> @@ -6749,12 +6923,16 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif
>  
>  static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k_base *ab = ar->ab;
> +	struct ath12k_link_vif *arvif;
>  	unsigned long time_left;
>  	int ret;
>  
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
>  	lockdep_assert_held(&ar->conf_mutex);
> +
> +	arvif = &ahvif->deflink;
>  	reinit_completion(&ar->vdev_delete_done);
>  
>  	ret = ath12k_wmi_vdev_delete(ar, arvif->vdev_id);
> @@ -6775,7 +6953,7 @@ static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif)
>  	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
>  	ar->num_created_vdevs--;
>  
> -	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
> +	if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
>  		ar->monitor_vdev_id = -1;
>  		ar->monitor_vdev_created = false;
>  	} else if (ar->monitor_vdev_created && !ar->monitor_started) {
> @@ -6805,6 +6983,12 @@ static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif)
>  	/* TODO: recal traffic pause state based on the available vdevs */
>  	arvif->is_created = false;
>  	arvif->ar = NULL;
> +	if (arvif->link_id < IEEE80211_MLD_MAX_NUM_LINKS) {
> +		rcu_assign_pointer(ahvif->link[arvif->link_id], NULL);
> +		synchronize_rcu();
> +		ahvif->links_map &= ~(BIT(arvif->link_id));
> +		arvif->link_id = ATH12K_INVALID_LINK_ID;
> +	}
>  
>  	return ret;
>  }
> @@ -6812,16 +6996,21 @@ static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif)
>  static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
>  					   struct ieee80211_vif *vif)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
> +	struct ath12k_link_vif *arvif;
>  	struct ath12k_base *ab;
>  	struct ath12k *ar;
>  	int ret;
>  
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
>  	if (!arvif->is_created) {
>  		/* if we cached some config but never received assign chanctx,
>  		 * free the allocated cache.
>  		 */
>  		ath12k_arvif_put_cache(arvif);
> +		mutex_unlock(&ah->conf_mutex);
>  		return;
>  	}
>  
> @@ -6835,7 +7024,7 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
>  	ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n",
>  		   arvif->vdev_id);
>  
> -	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
> +	if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
>  		ret = ath12k_peer_delete(ar, arvif->vdev_id, vif->addr);
>  		if (ret)
>  			ath12k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n",
> @@ -6845,6 +7034,7 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
>  	ath12k_mac_vdev_delete(ar, vif);
>  
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  }
>  
>  /* FIXME: Has to be verified. */
> @@ -6936,7 +7126,7 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx
>  	return ret;
>  }
>  
> -static int ath12k_mac_ampdu_action(struct ath12k_vif *arvif,
> +static int ath12k_mac_ampdu_action(struct ath12k_link_vif *arvif,
>  				   struct ieee80211_ampdu_params *params)
>  {
>  	struct ath12k *ar = arvif->ar;
> @@ -6972,7 +7162,8 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw,
>  {
>  	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	int ret = -EINVAL;
>  
>  	ar = ath12k_get_ar_by_vif(hw, vif);
> @@ -6980,10 +7171,13 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw,
>  		return -EINVAL;
>  
>  	ar = ath12k_ah_to_ar(ah, 0);
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
>  
>  	mutex_lock(&ar->conf_mutex);
>  	ret = ath12k_mac_ampdu_action(arvif, params);
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  
>  	if (ret)
>  		ath12k_warn(ar->ab, "pdev idx %d unable to perform ampdu action %d ret %d\n",
> @@ -7114,7 +7308,7 @@ ath12k_mac_check_down_grade_phy_mode(struct ath12k *ar,
>  }
>  
>  static int
> -ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
> +ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif,
>  			      struct ieee80211_chanctx_conf *ctx,
>  			      bool restart)
>  {
> @@ -7122,7 +7316,8 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
>  	struct ath12k_base *ab = ar->ab;
>  	struct wmi_vdev_start_req_arg arg = {};
>  	const struct cfg80211_chan_def *chandef = &ctx->def;
> -	int he_support = arvif->vif->bss_conf.he_support;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +	int he_support = ahvif->vif->bss_conf.he_support;
>  	int ret;
>  
>  	lockdep_assert_held(&ar->conf_mutex);
> @@ -7141,7 +7336,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
>  
>  	arg.mode = ath12k_mac_check_down_grade_phy_mode(ar, arg.mode,
>  							chandef->chan->band,
> -							arvif->vif->type);
> +							ahvif->vif->type);
>  	arg.min_power = 0;
>  	arg.max_power = chandef->chan->max_power * 2;
>  	arg.max_reg_power = chandef->chan->max_reg_power * 2;
> @@ -7161,10 +7356,10 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
>  			return ret;
>  	}
>  
> -	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
> -		arg.ssid = arvif->u.ap.ssid;
> -		arg.ssid_len = arvif->u.ap.ssid_len;
> -		arg.hidden_ssid = arvif->u.ap.hidden_ssid;
> +	if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
> +		arg.ssid = ahvif->u.ap.ssid;
> +		arg.ssid_len = ahvif->u.ap.ssid_len;
> +		arg.hidden_ssid = ahvif->u.ap.hidden_ssid;
>  
>  		/* For now allow DFS for AP mode */
>  		arg.chan_radar = !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
> @@ -7211,7 +7406,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
>  
>  	ar->num_started_vdevs++;
>  	ath12k_dbg(ab, ATH12K_DBG_MAC,  "vdev %pM started, vdev_id %d\n",
> -		   arvif->vif->addr, arvif->vdev_id);
> +		   ahvif->vif->addr, arvif->vdev_id);
>  
>  	/* Enable CAC Flag in the driver by checking the channel DFS cac time,
>  	 * i.e dfs_cac_ms value which will be valid only for radar channels
> @@ -7220,7 +7415,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
>  	 * during CAC.
>  	 */
>  	/* TODO: Set the flag for other interface types as required */
> -	if (arvif->vdev_type == WMI_VDEV_TYPE_AP &&
> +	if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP &&
>  	    chandef->chan->dfs_cac_ms &&
>  	    chandef->chan->dfs_state == NL80211_DFS_USABLE) {
>  		set_bit(ATH12K_CAC_RUNNING, &ar->dev_flags);
> @@ -7237,13 +7432,13 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
>  	return 0;
>  }
>  
> -static int ath12k_mac_vdev_start(struct ath12k_vif *arvif,
> +static int ath12k_mac_vdev_start(struct ath12k_link_vif *arvif,
>  				 struct ieee80211_chanctx_conf *ctx)
>  {
>  	return ath12k_mac_vdev_start_restart(arvif, ctx, false);
>  }
>  
> -static int ath12k_mac_vdev_restart(struct ath12k_vif *arvif,
> +static int ath12k_mac_vdev_restart(struct ath12k_link_vif *arvif,
>  				   struct ieee80211_chanctx_conf *ctx)
>  {
>  	return ath12k_mac_vdev_start_restart(arvif, ctx, true);
> @@ -7261,8 +7456,12 @@ static void
>  ath12k_mac_change_chanctx_cnt_iter(void *data, u8 *mac,
>  				   struct ieee80211_vif *vif)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k_mac_change_chanctx_arg *arg = data;
> +	struct ath12k_link_vif *arvif;
> +
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
> +	arvif = &ahvif->deflink;
>  
>  	if (arvif->ar != arg->ar)
>  		return;
> @@ -7277,9 +7476,13 @@ static void
>  ath12k_mac_change_chanctx_fill_iter(void *data, u8 *mac,
>  				    struct ieee80211_vif *vif)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k_mac_change_chanctx_arg *arg = data;
>  	struct ieee80211_chanctx_conf *ctx;
> +	struct ath12k_link_vif *arvif;
> +
> +	lockdep_assert_held(&ahvif->ah->conf_mutex);
> +	arvif = &ahvif->deflink;
>  
>  	if (arvif->ar != arg->ar)
>  		return;
> @@ -7323,13 +7526,13 @@ static u32 ath12k_mac_nlwidth_to_wmiwidth(enum nl80211_chan_width width)
>  }
>  
>  static int ath12k_mac_update_peer_puncturing_width(struct ath12k *ar,
> -						   struct ath12k_vif *arvif,
> +						   struct ath12k_link_vif *arvif,
>  						   struct cfg80211_chan_def def)
>  {
>  	u32 param_id, param_value;
>  	int ret;
>  
> -	if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
> +	if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA)
>  		return 0;
>  
>  	param_id = WMI_PEER_CHWIDTH_PUNCTURE_20MHZ_BITMAP;
> @@ -7355,8 +7558,9 @@ ath12k_mac_update_vif_chan(struct ath12k *ar,
>  {
>  	struct ath12k_wmi_vdev_up_params params = {};
>  	struct ath12k_base *ab = ar->ab;
> +	struct ath12k_link_vif *arvif;
>  	struct ieee80211_vif *vif;
> -	struct ath12k_vif *arvif;
> +	struct ath12k_vif *ahvif;
>  	int ret;
>  	int i;
>  	bool monitor_vif = false;
> @@ -7365,7 +7569,8 @@ ath12k_mac_update_vif_chan(struct ath12k *ar,
>  
>  	for (i = 0; i < n_vifs; i++) {
>  		vif = vifs[i].vif;
> -		arvif = ath12k_vif_to_arvif(vif);
> +		ahvif = ath12k_vif_to_ahvif(vif);
> +		arvif = &ahvif->deflink;
>  
>  		if (vif->type == NL80211_IFTYPE_MONITOR)
>  			monitor_vif = true;
> @@ -7415,10 +7620,14 @@ ath12k_mac_update_vif_chan(struct ath12k *ar,
>  
>  		memset(&params, 0, sizeof(params));
>  		params.vdev_id = arvif->vdev_id;
> -		params.aid = arvif->aid;
> +		params.aid = ahvif->aid;
>  		params.bssid = arvif->bssid;
>  		if (vif->mbssid_tx_vif) {
> -			params.tx_bssid = ath12k_vif_to_arvif(vif->mbssid_tx_vif)->bssid;
> +			struct ath12k_vif *ahvif =
> +				ath12k_vif_to_ahvif(vif->mbssid_tx_vif);
> +			struct ath12k_link_vif *arvif = &ahvif->deflink;
> +
> +			params.tx_bssid = arvif->bssid;
>  			params.nontx_profile_idx = vif->bss_conf.bssid_index;
>  			params.nontx_profile_cnt = 1 << vif->bss_conf.bssid_indicator;
>  		}
> @@ -7481,12 +7690,16 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw,
>  					 struct ieee80211_chanctx_conf *ctx,
>  					 u32 changed)
>  {
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
>  	struct ath12k_base *ab;
>  
> +	mutex_lock(&ah->conf_mutex);
>  	ar = ath12k_get_ar_by_ctx(hw, ctx);
> -	if (!ar)
> +	if (!ar) {
> +		mutex_unlock(&ah->conf_mutex);
>  		return;
> +	}
>  
>  	ab = ar->ab;
>  
> @@ -7511,13 +7724,15 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw,
>  
>  unlock:
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  }
>  
>  static int ath12k_start_vdev_delay(struct ath12k *ar,
> -				   struct ath12k_vif *arvif)
> +				   struct ath12k_link_vif *arvif)
>  {
>  	struct ath12k_base *ab = ar->ab;
> -	struct ieee80211_vif *vif = arvif->vif;
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +	struct ieee80211_vif *vif = ath12k_vif_to_vif(arvif->ahvif);
>  	int ret;
>  
>  	if (WARN_ON(arvif->is_started))
> @@ -7531,7 +7746,7 @@ static int ath12k_start_vdev_delay(struct ath12k *ar,
>  		return ret;
>  	}
>  
> -	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
> +	if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
>  		ret = ath12k_monitor_vdev_up(ar, arvif->vdev_id);
>  		if (ret) {
>  			ath12k_warn(ab, "failed put monitor up: %d\n", ret);
> @@ -7551,17 +7766,22 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>  				 struct ieee80211_bss_conf *link_conf,
>  				 struct ieee80211_chanctx_conf *ctx)
>  {
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
>  	struct ath12k_base *ab;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	int ret;
>  
>  	/* For multi radio wiphy, the vdev was not created during add_interface
>  	 * create now since we have a channel ctx now to assign to a specific ar/fw
>  	 */
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
>  	ar = ath12k_mac_assign_vif_to_vdev(hw, vif, ctx);
>  	if (!ar) {
>  		WARN_ON(1);
> +		mutex_unlock(&ah->conf_mutex);
>  		return -EINVAL;
>  	}
>  
> @@ -7577,8 +7797,8 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>  
>  	/* for some targets bss peer must be created before vdev_start */
>  	if (ab->hw_params->vdev_start_delay &&
> -	    arvif->vdev_type != WMI_VDEV_TYPE_AP &&
> -	    arvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
> +	    ahvif->vdev_type != WMI_VDEV_TYPE_AP &&
> +	    ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
>  	    !ath12k_peer_exist_by_vdev_id(ab, arvif->vdev_id)) {
>  		memcpy(&arvif->chanctx, ctx, sizeof(*ctx));
>  		ret = 0;
> @@ -7590,7 +7810,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>  		goto out;
>  	}
>  
> -	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
> +	if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
>  		ret = ath12k_mac_monitor_start(ar);
>  		if (ret)
>  			goto out;
> @@ -7606,7 +7826,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>  		goto out;
>  	}
>  
> -	if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->monitor_vdev_created)
> +	if (ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->monitor_vdev_created)
>  		ath12k_mac_monitor_start(ar);
>  
>  	arvif->is_started = true;
> @@ -7615,6 +7835,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>  
>  out:
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  
>  	return ret;
>  }
> @@ -7625,11 +7846,15 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
>  				   struct ieee80211_bss_conf *link_conf,
>  				   struct ieee80211_chanctx_conf *ctx)
>  {
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
>  	struct ath12k_base *ab;
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_link_vif *arvif;
>  	int ret;
>  
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
>  	/* The vif is expected to be attached to an ar's VDEV.
>  	 * We leave the vif/vdev in this function as is
>  	 * and not delete the vdev symmetric to assign_vif_chanctx()
> @@ -7637,8 +7862,10 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
>  	 * remove_interface() or when there is a change in channel
>  	 * that moves the vif to a new ar
>  	 */
> -	if (!arvif->is_created)
> +	if (!arvif->is_created) {
> +		mutex_unlock(&ah->conf_mutex);
>  		return;
> +	}
>  
>  	ar = arvif->ar;
>  	ab = ar->ab;
> @@ -7651,18 +7878,19 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
>  
>  	WARN_ON(!arvif->is_started);
>  
> -	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
> +	if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
>  		ret = ath12k_mac_monitor_stop(ar);
>  		if (ret) {
>  			mutex_unlock(&ar->conf_mutex);
> +			mutex_unlock(&ah->conf_mutex);
>  			return;
>  		}
>  
>  		arvif->is_started = false;
>  	}
>  
> -	if (arvif->vdev_type != WMI_VDEV_TYPE_STA &&
> -	    arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
> +	if (ahvif->vdev_type != WMI_VDEV_TYPE_STA &&
> +	    ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
>  		ath12k_bss_disassoc(ar, arvif);
>  		ret = ath12k_mac_vdev_stop(arvif);
>  		if (ret)
> @@ -7671,11 +7899,12 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
>  	}
>  	arvif->is_started = false;
>  
> -	if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
> +	if (ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
>  	    ar->num_started_vdevs == 1 && ar->monitor_vdev_created)
>  		ath12k_mac_monitor_stop(ar);
>  
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  }
>  
>  static int
> @@ -7684,17 +7913,19 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
>  				 int n_vifs,
>  				 enum ieee80211_chanctx_switch_mode mode)
>  {
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
>  
>  	ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx);
>  	if (!ar)
>  		return -EINVAL;
> -
> +	mutex_lock(&ah->conf_mutex);
>  	mutex_lock(&ar->conf_mutex);
>  
>  	/* Switching channels across radio is not allowed */
>  	if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx)) {
>  		mutex_unlock(&ar->conf_mutex);
> +		mutex_unlock(&ah->conf_mutex);
>  		return -EINVAL;
>  	}
>  
> @@ -7702,8 +7933,8 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
>  		   "mac chanctx switch n_vifs %d mode %d\n",
>  		   n_vifs, mode);
>  	ath12k_mac_update_vif_chan(ar, vifs, n_vifs);
> -
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  
>  	return 0;
>  }
> @@ -7711,7 +7942,7 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
>  static int
>  ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value)
>  {
> -	struct ath12k_vif *arvif;
> +	struct ath12k_link_vif *arvif;
>  	int ret = 0;
>  
>  	mutex_lock(&ar->conf_mutex);
> @@ -7946,7 +8177,7 @@ ath12k_mac_get_single_legacy_rate(struct ath12k *ar,
>  	return 0;
>  }
>  
> -static int ath12k_mac_set_fixed_rate_params(struct ath12k_vif *arvif,
> +static int ath12k_mac_set_fixed_rate_params(struct ath12k_link_vif *arvif,
>  					    u32 rate, u8 nss, u8 sgi, u8 ldpc)
>  {
>  	struct ath12k *ar = arvif->ar;
> @@ -8025,7 +8256,7 @@ ath12k_mac_vht_mcs_range_present(struct ath12k *ar,
>  static void ath12k_mac_set_bitrate_mask_iter(void *data,
>  					     struct ieee80211_sta *sta)
>  {
> -	struct ath12k_vif *arvif = data;
> +	struct ath12k_link_vif *arvif = data;
>  	struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
>  	struct ath12k *ar = arvif->ar;
>  
> @@ -8042,8 +8273,8 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data,
>  static void ath12k_mac_disable_peer_fixed_rate(void *data,
>  					       struct ieee80211_sta *sta)
>  {
> +	struct ath12k_link_vif *arvif = data;
>  	struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
> -	struct ath12k_vif *arvif = data;
>  	struct ath12k *ar = arvif->ar;
>  	int ret;
>  
> @@ -8065,9 +8296,11 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
>  			       struct ieee80211_vif *vif,
>  			       const struct cfg80211_bitrate_mask *mask)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
> +	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
> +	struct ath12k_link_vif *arvif;
>  	struct cfg80211_chan_def def;
> -	struct ath12k *ar = arvif->ar;
> +	struct ath12k *ar;
>  	enum nl80211_band band;
>  	const u8 *ht_mcs_mask;
>  	const u16 *vht_mcs_mask;
> @@ -8079,8 +8312,13 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
>  	int ret;
>  	int num_rates;
>  
> -	if (ath12k_mac_vif_chan(vif, &def))
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
> +	ar = arvif->ar;
> +	if (ath12k_mac_vif_chan(vif, &def)) {
> +		mutex_unlock(&ah->conf_mutex);
>  		return -EPERM;
> +	}
>  
>  	band = def.chan->band;
>  	ht_mcs_mask = mask->control[band].ht_mcs;
> @@ -8181,6 +8419,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
>  	mutex_unlock(&ar->conf_mutex);
>  
>  out:
> +	mutex_unlock(&ah->conf_mutex);
>  	return ret;
>  }
>  
> @@ -8191,7 +8430,8 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
>  	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
>  	struct ath12k_base *ab;
> -	struct ath12k_vif *arvif;
> +	struct ath12k_vif *ahvif;
> +	struct ath12k_link_vif *arvif;
>  	int recovery_count, i;
>  
>  	if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
> @@ -8232,11 +8472,12 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
>  		}
>  
>  		list_for_each_entry(arvif, &ar->arvifs, list) {
> +			ahvif = arvif->ahvif;
>  			ath12k_dbg(ab, ATH12K_DBG_BOOT,
>  				   "reconfig cipher %d up %d vdev type %d\n",
> -				   arvif->key_cipher,
> +				   ahvif->key_cipher,
>  				   arvif->is_up,
> -				   arvif->vdev_type);
> +				   ahvif->vdev_type);
>  
>  			/* After trigger disconnect, then upper layer will
>  			 * trigger connect again, then the PN number of
> @@ -8244,9 +8485,9 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
>  			 * side, hence PN number mismatch will not happen.
>  			 */
>  			if (arvif->is_up &&
> -			    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
> -			    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
> -				ieee80211_hw_restart_disconnect(arvif->vif);
> +			    ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
> +			    ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
> +				ieee80211_hw_restart_disconnect(ahvif->vif);
>  
>  				ath12k_dbg(ab, ATH12K_DBG_BOOT,
>  					   "restart disconnect\n");
> @@ -8413,14 +8654,18 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
>  					   int duration,
>  					   enum ieee80211_roc_type type)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k_wmi_scan_req_arg arg;
> +	struct ath12k_link_vif *arvif;
>  	struct ath12k *ar, *prev_ar;
>  	u32 scan_time_msec;
>  	bool create = true;
>  	int ret;
>  
> +	mutex_lock(&ah->conf_mutex);
> +	arvif = &ahvif->deflink;
> +
>  	if (ah->num_radio == 1) {
>  		WARN_ON(!arvif->is_created);
>  		ar = ath12k_ah_to_ar(ah, 0);
> @@ -8428,8 +8673,10 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
>  	}
>  
>  	ar = ath12k_mac_select_scan_device(hw, vif, chan->center_freq);
> -	if (!ar)
> +	if (!ar) {
> +		mutex_unlock(&ah->conf_mutex);
>  		return -EINVAL;
> +	}
>  
>  	/* If the vif is already assigned to a specific vdev of an ar,
>  	 * check whether its already started, vdev which is started
> @@ -8441,11 +8688,15 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
>  	 * always on the same band for the vif
>  	 */
>  	if (arvif->is_created) {
> -		if (WARN_ON(!arvif->ar))
> +		if (WARN_ON(!arvif->ar)) {
> +			mutex_unlock(&ah->conf_mutex);
>  			return -EINVAL;
> +		}
>  
> -		if (ar != arvif->ar && arvif->is_started)
> +		if (ar != arvif->ar && arvif->is_started) {
> +			mutex_unlock(&ah->conf_mutex);
>  			return -EBUSY;
> +		}
>  
>  		if (ar != arvif->ar) {
>  			/* backup the previously used ar ptr, since the vdev delete
> @@ -8459,6 +8710,7 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
>  				ath12k_warn(prev_ar->ab,
>  					    "unable to delete scan vdev for roc: %d\n",
>  					    ret);
> +				mutex_unlock(&ah->conf_mutex);
>  				return ret;
>  			}
>  		} else {
> @@ -8473,6 +8725,7 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
>  		if (ret) {
>  			ath12k_warn(ar->ab, "unable to create scan vdev for roc: %d\n",
>  				    ret);
> +			mutex_unlock(&ah->conf_mutex);
>  			return -EINVAL;
>  		}
>  	}
> @@ -8555,6 +8808,7 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
>  	kfree(arg.chan_list);
>  exit:
>  	mutex_unlock(&ar->conf_mutex);
> +	mutex_unlock(&ah->conf_mutex);
>  
>  	return ret;
>  }
> @@ -9281,6 +9535,7 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab,
>  	ah->num_radio = num_pdev_map;
>  
>  	mutex_init(&ah->hw_mutex);
> +	mutex_init(&ah->conf_mutex);
>  
>  	for (i = 0; i < num_pdev_map; i++) {
>  		ab = pdev_map[i].ab;
> diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
> index 69fd282b9dd3..ef54349cb159 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.h
> +++ b/drivers/net/wireless/ath/ath12k/mac.h
> @@ -40,6 +40,9 @@ struct ath12k_generic_iter {
>  #define ATH12K_TX_POWER_MAX_VAL	70
>  #define ATH12K_TX_POWER_MIN_VAL	0
>  
> +#define ATH12K_DEFAULT_LINK_ID	0
> +#define ATH12K_INVALID_LINK_ID	255
> +
>  enum ath12k_supported_bw {
>  	ATH12K_BW_20    = 0,
>  	ATH12K_BW_40    = 1,
> @@ -64,9 +67,9 @@ u8 ath12k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
>  void __ath12k_mac_scan_finish(struct ath12k *ar);
>  void ath12k_mac_scan_finish(struct ath12k *ar);
>  
> -struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id);
> -struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
> -						   u32 vdev_id);
> +struct ath12k_link_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id);
> +struct ath12k_link_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
> +							u32 vdev_id);
>  struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id);
>  struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id);
>  
> diff --git a/drivers/net/wireless/ath/ath12k/p2p.c b/drivers/net/wireless/ath/ath12k/p2p.c
> index 3a851ee15b2f..84cccf7d91e7 100644
> --- a/drivers/net/wireless/ath/ath12k/p2p.c
> +++ b/drivers/net/wireless/ath/ath12k/p2p.c
> @@ -69,20 +69,20 @@ static size_t ath12k_p2p_noa_ie_len_compute(const struct ath12k_wmi_p2p_noa_info
>  	return len;
>  }
>  
> -static void ath12k_p2p_noa_ie_assign(struct ath12k_vif *arvif, void *ie,
> +static void ath12k_p2p_noa_ie_assign(struct ath12k_link_vif *arvif, void *ie,
>  				     size_t len)
>  {
>  	struct ath12k *ar = arvif->ar;
>  
>  	lockdep_assert_held(&ar->data_lock);
>  
> -	kfree(arvif->u.ap.noa_data);
> +	kfree(arvif->ahvif->u.ap.noa_data);
>  
> -	arvif->u.ap.noa_data = ie;
> -	arvif->u.ap.noa_len = len;
> +	arvif->ahvif->u.ap.noa_data = ie;
> +	arvif->ahvif->u.ap.noa_len = len;
>  }
>  
> -static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif,
> +static void __ath12k_p2p_noa_update(struct ath12k_link_vif *arvif,
>  				    const struct ath12k_wmi_p2p_noa_info *noa)
>  {
>  	struct ath12k *ar = arvif->ar;
> @@ -105,7 +105,7 @@ static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif,
>  	ath12k_p2p_noa_ie_assign(arvif, ie, len);
>  }
>  
> -void ath12k_p2p_noa_update(struct ath12k_vif *arvif,
> +void ath12k_p2p_noa_update(struct ath12k_link_vif *arvif,
>  			   const struct ath12k_wmi_p2p_noa_info *noa)
>  {
>  	struct ath12k *ar = arvif->ar;
> @@ -118,9 +118,12 @@ void ath12k_p2p_noa_update(struct ath12k_vif *arvif,
>  static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac,
>  					    struct ieee80211_vif *vif)
>  {
> -	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
>  	struct ath12k_p2p_noa_arg *arg = data;
> +	struct ath12k_link_vif *arvif;
>  
> +	WARN_ON(!rcu_read_lock_any_held());
> +	arvif = &ahvif->deflink;
same here.

>  	if (arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id)
>  		return;
>  
> diff --git a/drivers/net/wireless/ath/ath12k/p2p.h b/drivers/net/wireless/ath/ath12k/p2p.h
> index b2eec51a9900..03ee877e6d6b 100644
> --- a/drivers/net/wireless/ath/ath12k/p2p.h
> +++ b/drivers/net/wireless/ath/ath12k/p2p.h
> @@ -16,7 +16,7 @@ struct ath12k_p2p_noa_arg {
>  	const struct ath12k_wmi_p2p_noa_info *noa;
>  };
>  
> -void ath12k_p2p_noa_update(struct ath12k_vif *arvif,
> +void ath12k_p2p_noa_update(struct ath12k_link_vif *arvif,
>  			   const struct ath12k_wmi_p2p_noa_info *noa);
>  void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id,
>  				      const struct ath12k_wmi_p2p_noa_info *noa);
> diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
> index 19c0626fbff1..6481f100e6cc 100644
> --- a/drivers/net/wireless/ath/ath12k/peer.c
> +++ b/drivers/net/wireless/ath/ath12k/peer.c
> @@ -1,7 +1,7 @@
>  // SPDX-License-Identifier: BSD-3-Clause-Clear
>  /*
>   * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
> - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
>   */
>  
>  #include "core.h"
> @@ -261,10 +261,11 @@ static int ath12k_wait_for_peer_created(struct ath12k *ar, int vdev_id, const u8
>  	return ath12k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
>  }
>  
> -int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif,
> +int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
>  		       struct ieee80211_sta *sta,
>  		       struct ath12k_wmi_peer_create_arg *arg)
>  {
> +	struct ieee80211_vif *vif = ath12k_vif_to_vif(arvif->ahvif);
>  	struct ath12k_peer *peer;
>  	int ret;
>  
> @@ -326,7 +327,7 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif,
>  	peer->pdev_idx = ar->pdev_idx;
>  	peer->sta = sta;
>  
> -	if (arvif->vif->type == NL80211_IFTYPE_STATION) {
> +	if (vif->type == NL80211_IFTYPE_STATION) {
>  		arvif->ast_hash = peer->ast_hash;
>  		arvif->ast_idx = peer->hw_peer_id;
>  	}
> diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h
> index 7b3500b5c8c2..b955f0cdf598 100644
> --- a/drivers/net/wireless/ath/ath12k/peer.h
> +++ b/drivers/net/wireless/ath/ath12k/peer.h
> @@ -1,7 +1,7 @@
>  /* SPDX-License-Identifier: BSD-3-Clause-Clear */
>  /*
>   * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
> - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
> + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
>   */
>  
>  #ifndef ATH12K_PEER_H
> @@ -59,7 +59,7 @@ struct ath12k_peer *ath12k_peer_find_by_addr(struct ath12k_base *ab,
>  struct ath12k_peer *ath12k_peer_find_by_id(struct ath12k_base *ab, int peer_id);
>  void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id);
>  int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr);
> -int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif,
> +int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
>  		       struct ieee80211_sta *sta,
>  		       struct ath12k_wmi_peer_create_arg *arg);
>  int ath12k_wait_for_peer_delete_done(struct ath12k *ar, u32 vdev_id,
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index d6e1d1398cdb..ef02c90f63b8 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -6683,7 +6683,8 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab,
>  					  const u32 *vdev_ids)
>  {
>  	int i;
> -	struct ath12k_vif *arvif;
> +	struct ath12k_link_vif *arvif;
> +	struct ath12k_vif *ahvif;
>  
>  	/* Finish CSA once the switch count becomes NULL */
>  	if (ev->current_switch_count)
> @@ -6698,9 +6699,10 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab,
>  				    vdev_ids[i]);
>  			continue;
>  		}
> +		ahvif = arvif->ahvif;
>  
> -		if (arvif->is_up && arvif->vif->bss_conf.csa_active)
> -			ieee80211_csa_finish(arvif->vif, 0);
> +		if (arvif->is_up && ahvif->vif->bss_conf.csa_active)
> +			ieee80211_csa_finish(ahvif->vif, 0);
>  	}
>  	rcu_read_unlock();
>  }
> @@ -7252,13 +7254,13 @@ ath12k_wmi_send_unit_test_cmd(struct ath12k *ar,
>  
>  int ath12k_wmi_simulate_radar(struct ath12k *ar)
>  {
> -	struct ath12k_vif *arvif;
> +	struct ath12k_link_vif *arvif;
>  	u32 dfs_args[DFS_MAX_TEST_ARGS];
>  	struct wmi_unit_test_cmd wmi_ut;
>  	bool arvif_found = false;
>  
>  	list_for_each_entry(arvif, &ar->arvifs, list) {
> -		if (arvif->is_started && arvif->vdev_type == WMI_VDEV_TYPE_AP) {
> +		if (arvif->is_started && arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
>  			arvif_found = true;
>  			break;
>  		}




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux