Merge tag 'ath-next-20240130' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath
authorKalle Valo <kvalo@kernel.org>
Wed, 31 Jan 2024 16:45:31 +0000 (18:45 +0200)
committerKalle Valo <kvalo@kernel.org>
Wed, 31 Jan 2024 16:45:31 +0000 (18:45 +0200)
ath.git patches for v6.9

We have new features for both ath11k and ath12k. ath12k is now under
heavy refactoring in preparation for MLO support.

Major changes:

ath12k

* refactoring in preparation for Multi-Link Operation (MLO) support

* 1024 Block Ack window size support

* provide firmware wmi logs via a trace event

ath11k

* 36 bit DMA mask support

* support 6 GHz station power modes: Low Power Indoor (LPI), Standard
  Power) SP and Very Low Power (VLP)

48 files changed:
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/coredump.h
drivers/net/wireless/ath/ath10k/htt.c
drivers/net/wireless/ath/ath10k/htt.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/wmi-tlv.c
drivers/net/wireless/ath/ath10k/wmi-tlv.h
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath11k/core.h
drivers/net/wireless/ath/ath11k/dp.c
drivers/net/wireless/ath/ath11k/dp_tx.c
drivers/net/wireless/ath/ath11k/hal.c
drivers/net/wireless/ath/ath11k/hal.h
drivers/net/wireless/ath/ath11k/hal_rx.c
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath11k/mac.h
drivers/net/wireless/ath/ath11k/mhi.c
drivers/net/wireless/ath/ath11k/pci.c
drivers/net/wireless/ath/ath11k/pci.h
drivers/net/wireless/ath/ath11k/reg.c
drivers/net/wireless/ath/ath11k/reg.h
drivers/net/wireless/ath/ath11k/testmode.c
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/ath/ath11k/wmi.h
drivers/net/wireless/ath/ath12k/core.c
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/dp.h
drivers/net/wireless/ath/ath12k/dp_mon.c
drivers/net/wireless/ath/ath12k/dp_rx.c
drivers/net/wireless/ath/ath12k/dp_tx.c
drivers/net/wireless/ath/ath12k/hal_desc.h
drivers/net/wireless/ath/ath12k/hal_rx.c
drivers/net/wireless/ath/ath12k/hw.c
drivers/net/wireless/ath/ath12k/hw.h
drivers/net/wireless/ath/ath12k/mac.c
drivers/net/wireless/ath/ath12k/mac.h
drivers/net/wireless/ath/ath12k/pci.c
drivers/net/wireless/ath/ath12k/qmi.c
drivers/net/wireless/ath/ath12k/qmi.h
drivers/net/wireless/ath/ath12k/reg.c
drivers/net/wireless/ath/ath12k/trace.h
drivers/net/wireless/ath/ath12k/wmi.c
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/antenna.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/reg_aic.h

index 0032f8aa892ffa2724ec40f45ca24e0435d2b254..9ce6f49ab2614e58baf88c75cff51159e40b6dad 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
  * Copyright (c) 2018-2019, 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.
  */
 
 #include <linux/module.h>
@@ -3613,7 +3613,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
        default:
                ath10k_err(ar, "unsupported core hardware revision %d\n",
                           hw_rev);
-               ret = -ENOTSUPP;
+               ret = -EOPNOTSUPP;
                goto err_free_mac;
        }
 
index e5ef0352e319c7416818b295fe6f64f3d5122bfe..8d274e0f374b6596544d169a02b84337bca8d137 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: ISC */
 /*
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _COREDUMP_H_
 
 /**
  * enum ath10k_fw_crash_dump_type - types of data in the dump file
- * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
+ * @ATH10K_FW_CRASH_DUMP_REGISTERS: Register crash dump in binary format
+ * @ATH10K_FW_CRASH_DUMP_CE_DATA: Copy Engine crash dump data
+ * @ATH10K_FW_CRASH_DUMP_RAM_DATA: RAM crash dump data, contains multiple
+ *                                struct ath10k_dump_ram_data_hdr
+ * @ATH10K_FW_CRASH_DUMP_MAX: Maximum enumeration
  */
 enum ath10k_fw_crash_dump_type {
        ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
index 907e1e13871acf3460cf4c11c16f8dd18d8e3582..dbaf262cd7c1eaf254dd14eca51532d7b662f8a1 100644 (file)
@@ -2,6 +2,7 @@
 /*
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/slab.h>
@@ -381,7 +382,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt)
            htt->target_version_major != 3) {
                ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n",
                           htt->target_version_major);
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
 
        return 0;
index 4a9270e2a4c882dfd5078ea2868d721ddbb52033..603f6de62b0a02f4f0d1ac64af46b635b001c2ee 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021, 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _HTT_H_
@@ -906,7 +906,7 @@ struct htt_data_tx_completion_ext {
        __le16 msdus_rssi[];
 } __packed;
 
-/**
+/*
  * @brief target -> host TX completion indication message definition
  *
  * @details
@@ -1474,15 +1474,19 @@ enum htt_q_depth_type {
 #define HTT_TX_Q_STATE_ENTRY_MULTIPLIER                0
 
 /**
- * htt_q_state_conf - part of htt_frag_desc_bank_cfg for host q state config
+ * struct htt_q_state_conf - part of htt_frag_desc_bank_cfg for host q state config
  *
  * Defines host q state format and behavior. See htt_q_state.
  *
+ * @paddr: Queue physical address
+ * @num_peers: Number of supported peers
+ * @num_tids: Number of supported TIDs
  * @record_size: Defines the size of each host q entry in bytes. In practice
  *     however firmware (at least 10.4.3-00191) ignores this host
  *     configuration value and uses hardcoded value of 1.
  * @record_multiplier: This is valid only when q depth type is MSDUs. It
  *     defines the exponent for the power of 2 multiplication.
+ * @pad: struct padding for 32-bit alignment
  */
 struct htt_q_state_conf {
        __le32 paddr;
@@ -1518,7 +1522,7 @@ struct htt_frag_desc_bank_cfg64 {
 #define HTT_TX_Q_STATE_ENTRY_EXP_LSB           6
 
 /**
- * htt_q_state - shared between host and firmware via DMA
+ * struct htt_q_state - shared between host and firmware via DMA
  *
  * This structure is used for the host to expose it's software queue state to
  * firmware so that its rate control can schedule fetch requests for optimized
index 090bcf148d0c75a4ce9abcecd1d8ee419acbd691..fc503db2fd8ed3fda007a6118dc1828a2986cd86 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
  * Copyright (c) 2018-2019, 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.
  */
 
 #include "mac.h"
@@ -4056,7 +4056,7 @@ static int ath10k_mac_tx(struct ath10k *ar,
                    !(skb_cb->flags & ATH10K_SKB_F_RAW_TX)) {
                        WARN_ON_ONCE(1);
                        ieee80211_free_txskb(hw, skb);
-                       return -ENOTSUPP;
+                       return -EOPNOTSUPP;
                }
        }
 
@@ -7065,7 +7065,7 @@ static int ath10k_mac_set_tid_config(struct ath10k *ar, struct ieee80211_sta *st
 
        if (sta) {
                if (!sta->wme)
-                       return -ENOTSUPP;
+                       return -EOPNOTSUPP;
 
                arsta = (struct ath10k_sta *)sta->drv_priv;
 
index 3de2de6d44bc9cf4e46105ab0714a4fd25aa9483..5c34b156b4ff49514be3a66bb2fda11a80202a52 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/pci.h>
@@ -889,7 +889,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
        if (WARN_ON_ONCE(!ar_pci->targ_cpu_to_ce_addr))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        return ar_pci->targ_cpu_to_ce_addr(ar, addr);
 }
@@ -2668,7 +2668,7 @@ static int ath10k_pci_safe_chip_reset(struct ath10k *ar)
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
        if (!ar_pci->pci_soft_reset)
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        return ar_pci->pci_soft_reset(ar);
 }
@@ -2808,7 +2808,7 @@ static int ath10k_pci_chip_reset(struct ath10k *ar)
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
        if (WARN_ON(!ar_pci->pci_hard_reset))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        return ar_pci->pci_hard_reset(ar);
 }
@@ -3594,7 +3594,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
                break;
        default:
                WARN_ON(1);
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
 
        ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, ATH10K_BUS_PCI,
index 6b6aa3c36744876df49180fb9955b02cff9a446b..aed97fd121babf6813afc0f50707b327310046c0 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
  * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 #include "core.h"
 #include "debug.h"
@@ -851,6 +852,10 @@ ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev(struct ath10k *ar, struct sk_buff *skb,
        }
 
        ev = tb[WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_EVENT];
+       if (!ev) {
+               kfree(tb);
+               return -EPROTO;
+       }
 
        arg->desc_id = ev->desc_id;
        arg->status = ev->status;
@@ -1347,7 +1352,7 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
            __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 ||
            __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 ||
            __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) {
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
 
        arg->min_tx_power = ev->hw_min_tx_power;
@@ -2119,9 +2124,9 @@ static int ath10k_wmi_tlv_op_get_vdev_subtype(struct ath10k *ar,
        case WMI_VDEV_SUBTYPE_MESH_11S:
                return WMI_TLV_VDEV_SUBTYPE_MESH_11S;
        case WMI_VDEV_SUBTYPE_MESH_NON_11S:
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
-       return -ENOTSUPP;
+       return -EOPNOTSUPP;
 }
 
 static struct sk_buff *
index 83a8f07a687f735f0edd46625074e92d473c3fea..8a2f87d0a3a3817b0e315402f90cf49cf022049a 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
  * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 #ifndef _WMI_TLV_H
 #define _WMI_TLV_H
@@ -2343,7 +2343,7 @@ struct wmi_tlv_adaptive_qcs {
 } __packed;
 
 /**
- * wmi_tlv_tx_pause_id - firmware tx queue pause reason types
+ * enum wmi_tlv_tx_pause_id - firmware tx queue pause reason types
  *
  * @WMI_TLV_TX_PAUSE_ID_MCC: used for by multi-channel firmware scheduler.
  *             Only vdev_map is valid.
index 88befe92f95dcc3490ebc607366bc62ef4d9898b..9e2f0a50aaea5d605d9eea1f3a3f715bfe8f30f6 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
  * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/skbuff.h>
@@ -6927,14 +6927,14 @@ void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
 }
 
 static void
-ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs,
+ath10k_wmi_put_start_scan_tlvs(u8 *tlvs,
                               const struct wmi_start_scan_arg *arg)
 {
        struct wmi_ie_data *ie;
        struct wmi_chan_list *channels;
        struct wmi_ssid_list *ssids;
        struct wmi_bssid_list *bssids;
-       void *ptr = tlvs->tlvs;
+       void *ptr = tlvs;
        int i;
 
        if (arg->n_channels) {
@@ -7012,7 +7012,7 @@ ath10k_wmi_op_gen_start_scan(struct ath10k *ar,
        cmd = (struct wmi_start_scan_cmd *)skb->data;
 
        ath10k_wmi_put_start_scan_common(&cmd->common, arg);
-       ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
+       ath10k_wmi_put_start_scan_tlvs(cmd->tlvs, arg);
 
        cmd->burst_duration_ms = __cpu_to_le32(0);
 
@@ -7041,7 +7041,7 @@ ath10k_wmi_10x_op_gen_start_scan(struct ath10k *ar,
        cmd = (struct wmi_10x_start_scan_cmd *)skb->data;
 
        ath10k_wmi_put_start_scan_common(&cmd->common, arg);
-       ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
+       ath10k_wmi_put_start_scan_tlvs(cmd->tlvs, arg);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi 10x start scan\n");
        return skb;
@@ -8733,9 +8733,9 @@ int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
                return WMI_VDEV_SUBTYPE_LEGACY_PROXY_STA;
        case WMI_VDEV_SUBTYPE_MESH_11S:
        case WMI_VDEV_SUBTYPE_MESH_NON_11S:
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
-       return -ENOTSUPP;
+       return -EOPNOTSUPP;
 }
 
 static int ath10k_wmi_10_2_4_op_get_vdev_subtype(struct ath10k *ar,
@@ -8755,9 +8755,9 @@ static int ath10k_wmi_10_2_4_op_get_vdev_subtype(struct ath10k *ar,
        case WMI_VDEV_SUBTYPE_MESH_11S:
                return WMI_VDEV_SUBTYPE_10_2_4_MESH_11S;
        case WMI_VDEV_SUBTYPE_MESH_NON_11S:
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
-       return -ENOTSUPP;
+       return -EOPNOTSUPP;
 }
 
 static int ath10k_wmi_10_4_op_get_vdev_subtype(struct ath10k *ar,
@@ -8779,7 +8779,7 @@ static int ath10k_wmi_10_4_op_get_vdev_subtype(struct ath10k *ar,
        case WMI_VDEV_SUBTYPE_MESH_NON_11S:
                return WMI_VDEV_SUBTYPE_10_4_MESH_NON_11S;
        }
-       return -ENOTSUPP;
+       return -EOPNOTSUPP;
 }
 
 static struct sk_buff *
@@ -8918,8 +8918,6 @@ ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar,
        if (!skb)
                return ERR_PTR(-ENOMEM);
 
-       memset(skb->data, 0, sizeof(*cmd));
-
        cmd = (struct wmi_10_4_tdls_peer_update_cmd *)skb->data;
        cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
        ether_addr_copy(cmd->peer_macaddr.addr, arg->addr);
index 9146df98fceeee9d8a6426e9724c35ebadc3bb46..2379501225a4aba43b7629d10eb5c2b18c044d30 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (c) 2005-2011 Atheros Communications Inc.
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
  * Copyright (c) 2018-2019, 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 _WMI_H_
@@ -3008,8 +3008,11 @@ enum wmi_coex_version {
  * @WMI_10_4_TDLS_UAPSD_SLEEP_STA: TDLS sleep sta support enable/disable
  * @WMI_10_4_TDLS_CONN_TRACKER_IN_HOST_MODE: TDLS connection tracker in host
  *     enable/disable
- * @WMI_10_4_TDLS_EXPLICIT_MODE_ONLY:Explicit TDLS mode enable/disable
+ * @WMI_10_4_TDLS_EXPLICIT_MODE_ONLY: Explicit TDLS mode enable/disable
  * @WMI_10_4_TX_DATA_ACK_RSSI: Enable DATA ACK RSSI if firmware is capable
+ * @WMI_10_4_EXT_PEER_TID_CONFIGS_SUPPORT:  Firmware supports Extended Peer
+ *     TID configuration for QoS related settings
+ * @WMI_10_4_REPORT_AIRTIME: Firmware supports transmit airtime reporting
  */
 enum wmi_10_4_feature_mask {
        WMI_10_4_LTEU_SUPPORT                   = BIT(0),
@@ -3069,7 +3072,10 @@ struct host_memory_chunk {
 struct wmi_host_mem_chunks {
        __le32 count;
        /* some fw revisions require at least 1 chunk regardless of count */
-       struct host_memory_chunk items[1];
+       union {
+               struct host_memory_chunk item;
+               DECLARE_FLEX_ARRAY(struct host_memory_chunk, items);
+       };
 } __packed;
 
 struct wmi_init_cmd {
@@ -3215,23 +3221,16 @@ struct wmi_start_scan_common {
        __le32 scan_ctrl_flags;
 } __packed;
 
-struct wmi_start_scan_tlvs {
-       /* TLV parameters. These includes channel list, ssid list, bssid list,
-        * extra ies.
-        */
-       u8 tlvs[0];
-} __packed;
-
 struct wmi_start_scan_cmd {
        struct wmi_start_scan_common common;
        __le32 burst_duration_ms;
-       struct wmi_start_scan_tlvs tlvs;
+       u8 tlvs[];
 } __packed;
 
 /* This is the definition from 10.X firmware branch */
 struct wmi_10x_start_scan_cmd {
        struct wmi_start_scan_common common;
-       struct wmi_start_scan_tlvs tlvs;
+       u8 tlvs[];
 } __packed;
 
 struct wmi_ssid_arg {
@@ -4260,13 +4259,6 @@ struct wmi_peer_sta_ps_state_chg_event {
        __le32 peer_ps_state;
 } __packed;
 
-struct wmi_pdev_chanlist_update_event {
-       /* number of channels */
-       __le32 num_chan;
-       /* array of channels */
-       struct wmi_channel channel_list[1];
-} __packed;
-
 #define WMI_MAX_DEBUG_MESG (sizeof(u32) * 32)
 
 struct wmi_debug_mesg_event {
@@ -5793,30 +5785,6 @@ struct wmi_bcn_prb_info {
        /* app IE */
 } __packed;
 
-struct wmi_bcn_tmpl_cmd {
-       /* unique id identifying the VDEV, generated by the caller */
-       __le32 vdev_id;
-       /* TIM IE offset from the beginning of the template. */
-       __le32 tim_ie_offset;
-       /* beacon probe capabilities and IEs */
-       struct wmi_bcn_prb_info bcn_prb_info;
-       /* beacon buffer length */
-       __le32 buf_len;
-       /* variable length data */
-       u8 data[1];
-} __packed;
-
-struct wmi_prb_tmpl_cmd {
-       /* unique id identifying the VDEV, generated by the caller */
-       __le32 vdev_id;
-       /* beacon probe capabilities and IEs */
-       struct wmi_bcn_prb_info bcn_prb_info;
-       /* beacon buffer length */
-       __le32 buf_len;
-       /* Variable length data */
-       u8 data[1];
-} __packed;
-
 enum wmi_sta_ps_mode {
        /* enable power save for the given STA VDEV */
        WMI_STA_PS_MODE_DISABLED = 0,
@@ -7197,7 +7165,13 @@ struct wmi_tdls_peer_capabilities {
        __le32 is_peer_responder;
        __le32 pref_offchan_num;
        __le32 pref_offchan_bw;
-       struct wmi_channel peer_chan_list[1];
+       union {
+               /* to match legacy implementation allocate room for
+                * at least one record even if peer_chan_len is 0
+                */
+               struct wmi_channel peer_chan_min_allocation;
+               DECLARE_FLEX_ARRAY(struct wmi_channel, peer_chan_list);
+       };
 } __packed;
 
 struct wmi_10_4_tdls_peer_update_cmd {
index 02e160d831bed13f3358034048ce5b03d36dc090..0b2d4a93d706e129f8eae67168a665daf63880eb 100644 (file)
@@ -314,6 +314,43 @@ struct ath11k_rekey_data {
        bool enable_offload;
 };
 
+/**
+ * struct ath11k_chan_power_info - TPE containing power info per channel chunk
+ * @chan_cfreq: channel center freq (MHz)
+ * e.g.
+ * channel 37/20 MHz,  it is 6135
+ * channel 37/40 MHz,  it is 6125
+ * channel 37/80 MHz,  it is 6145
+ * channel 37/160 MHz, it is 6185
+ * @tx_power: transmit power (dBm)
+ */
+struct ath11k_chan_power_info {
+       u16 chan_cfreq;
+       s8 tx_power;
+};
+
+/**
+ * struct ath11k_reg_tpc_power_info - regulatory TPC power info
+ * @is_psd_power: is PSD power or not
+ * @eirp_power: Maximum EIRP power (dBm), valid only if power is PSD
+ * @ap_power_type: type of power (SP/LPI/VLP)
+ * @num_pwr_levels: number of power levels
+ * @reg_max: Array of maximum TX power (dBm) per PSD value
+ * @ap_constraint_power: AP constraint power (dBm)
+ * @tpe: TPE values processed from TPE IE
+ * @chan_power_info: power info to send to firmware
+ */
+struct ath11k_reg_tpc_power_info {
+       bool is_psd_power;
+       u8 eirp_power;
+       enum wmi_reg_6ghz_ap_type ap_power_type;
+       u8 num_pwr_levels;
+       u8 reg_max[IEEE80211_MAX_NUM_PWR_LEVEL];
+       u8 ap_constraint_power;
+       s8 tpe[IEEE80211_MAX_NUM_PWR_LEVEL];
+       struct ath11k_chan_power_info chan_power_info[IEEE80211_MAX_NUM_PWR_LEVEL];
+};
+
 struct ath11k_vif {
        u32 vdev_id;
        enum wmi_vdev_type vdev_type;
@@ -368,6 +405,8 @@ struct ath11k_vif {
        struct ieee80211_chanctx_conf chanctx;
        struct ath11k_arp_ns_offload arp_ns_offload;
        struct ath11k_rekey_data rekey_data;
+
+       struct ath11k_reg_tpc_power_info reg_tpc_info;
 };
 
 struct ath11k_vif_iter {
@@ -735,6 +774,7 @@ struct ath11k {
        /* protected by conf_mutex */
        bool ps_state_enable;
        bool ps_timekeeper_enable;
+       s8 max_allowed_tx_power;
 };
 
 struct ath11k_band_cap {
@@ -918,6 +958,7 @@ struct ath11k_base {
         * This may or may not be used during the runtime
         */
        struct ieee80211_regdomain *new_regd[MAX_RADIOS];
+       struct cur_regulatory_info *reg_info_store;
 
        /* Current DFS Regulatory */
        enum ath11k_dfs_region dfs_region;
index 8975dc57ad77687218c53b602adf7a9f8be677f2..1a62407e5a9f23ec882a5c28c869904a055f8d21 100644 (file)
@@ -104,11 +104,14 @@ void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring)
        if (!ring->vaddr_unaligned)
                return;
 
-       if (ring->cached)
+       if (ring->cached) {
+               dma_unmap_single(ab->dev, ring->paddr_unaligned, ring->size,
+                                DMA_FROM_DEVICE);
                kfree(ring->vaddr_unaligned);
-       else
+       } else {
                dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned,
                                  ring->paddr_unaligned);
+       }
 
        ring->vaddr_unaligned = NULL;
 }
@@ -249,7 +252,18 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
 
                if (cached) {
                        ring->vaddr_unaligned = kzalloc(ring->size, GFP_KERNEL);
-                       ring->paddr_unaligned = virt_to_phys(ring->vaddr_unaligned);
+                       if (!ring->vaddr_unaligned)
+                               return -ENOMEM;
+
+                       ring->paddr_unaligned = dma_map_single(ab->dev,
+                                                              ring->vaddr_unaligned,
+                                                              ring->size,
+                                                              DMA_FROM_DEVICE);
+                       if (dma_mapping_error(ab->dev, ring->paddr_unaligned)) {
+                               kfree(ring->vaddr_unaligned);
+                               ring->vaddr_unaligned = NULL;
+                               return -ENOMEM;
+                       }
                }
        }
 
index c1072e66e3e8fd07f921466b014c271e08f5d3ba..272b1c35f98df2db0afbc9ff90b90796cfd289a9 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2018-2019 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.
  */
 
 #include "core.h"
@@ -103,7 +103,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
 
        if (unlikely(!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
                     !ieee80211_is_data(hdr->frame_control)))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1);
 
@@ -1018,7 +1018,7 @@ int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab)
        if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) {
                ath11k_err(ab, "unsupported htt major version %d supported version is %d\n",
                           dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR);
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
 
        return 0;
index c060c4b5c0cc3639745056b58c43a64f16cadf5c..f3d04568c221b6355b0da2f23bb850c9a01732bf 100644 (file)
@@ -626,15 +626,30 @@ u32 *ath11k_hal_srng_dst_peek(struct ath11k_base *ab, struct hal_srng *srng)
        return NULL;
 }
 
+static u32 *ath11k_hal_srng_dst_peek_with_dma(struct ath11k_base *ab,
+                                             struct hal_srng *srng, dma_addr_t *paddr)
+{
+       lockdep_assert_held(&srng->lock);
+
+       if (srng->u.dst_ring.tp != srng->u.dst_ring.cached_hp) {
+               *paddr = srng->ring_base_paddr +
+                         sizeof(*srng->ring_base_vaddr) * srng->u.dst_ring.tp;
+               return srng->ring_base_vaddr + srng->u.dst_ring.tp;
+       }
+
+       return NULL;
+}
+
 static void ath11k_hal_srng_prefetch_desc(struct ath11k_base *ab,
                                          struct hal_srng *srng)
 {
+       dma_addr_t desc_paddr;
        u32 *desc;
 
        /* prefetch only if desc is available */
-       desc = ath11k_hal_srng_dst_peek(ab, srng);
+       desc = ath11k_hal_srng_dst_peek_with_dma(ab, srng, &desc_paddr);
        if (likely(desc)) {
-               dma_sync_single_for_cpu(ab->dev, virt_to_phys(desc),
+               dma_sync_single_for_cpu(ab->dev, desc_paddr,
                                        (srng->entry_size * sizeof(u32)),
                                        DMA_FROM_DEVICE);
                prefetch(desc);
index 80447f488954a8fa0d78f28d6acde83250daa82d..65e8f244ebb971bfaddc7eea490da211adcdab0e 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
 /*
  * Copyright (c) 2018-2019 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.
  */
 
 #ifndef ATH11K_HAL_H
@@ -674,6 +674,7 @@ struct hal_srng_config {
  * @HAL_RX_BUF_RBM_SW1_BM: For Tx completion -- returned to host
  * @HAL_RX_BUF_RBM_SW2_BM: For Tx completion -- returned to host
  * @HAL_RX_BUF_RBM_SW3_BM: For Rx release -- returned to host
+ * @HAL_RX_BUF_RBM_SW4_BM: For Tx completion -- returned to host
  */
 
 enum hal_rx_buf_return_buf_manager {
index e758ee8e17c90459e48c750ea09c46eabc7ee630..8f7dd43dc1bd8ee7e9df4096ec1771d806e6b5f8 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2018-2019 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.
  */
 
 #include "debug.h"
@@ -246,7 +246,7 @@ int ath11k_hal_reo_cmd_send(struct ath11k_base *ab, struct hal_srng *srng,
        case HAL_REO_CMD_UNBLOCK_CACHE:
        case HAL_REO_CMD_FLUSH_TIMEOUT_LIST:
                ath11k_warn(ab, "Unsupported reo command %d\n", type);
-               ret = -ENOTSUPP;
+               ret = -EOPNOTSUPP;
                break;
        default:
                ath11k_warn(ab, "Unknown reo command %d\n", type);
index b13525bbbb8087acbdc15247a0a428a74fd5f8b9..bbf4d1f4d310c1f9b1a1355faeb6274499ca031c 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2018-2019 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.
  */
 
 #include <net/mac80211.h>
@@ -255,9 +255,6 @@ static const u32 ath11k_smps_map[] = {
        [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
 };
 
-static int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif);
-
 enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy)
 {
        enum nl80211_he_ru_alloc ret;
@@ -3397,6 +3394,18 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar,
        return 0;
 }
 
+static bool ath11k_mac_supports_station_tpc(struct ath11k *ar,
+                                           struct ath11k_vif *arvif,
+                                           const struct cfg80211_chan_def *chandef)
+{
+       return ath11k_wmi_supports_6ghz_cc_ext(ar) &&
+               test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map) &&
+               arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+               arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE &&
+               chandef->chan &&
+               chandef->chan->band == NL80211_BAND_6GHZ;
+}
+
 static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
                                           struct ieee80211_vif *vif,
                                           struct ieee80211_bss_conf *info,
@@ -3596,7 +3605,6 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_TXPOWER) {
                ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev_id %i txpower %d\n",
                           arvif->vdev_id, info->txpower);
-
                arvif->txpower = info->txpower;
                ath11k_mac_txpower_recalc(ar);
        }
@@ -4906,100 +4914,6 @@ static void ath11k_mac_dec_num_stations(struct ath11k_vif *arvif,
        ar->num_stations--;
 }
 
-static int ath11k_mac_station_add(struct ath11k *ar,
-                                 struct ieee80211_vif *vif,
-                                 struct ieee80211_sta *sta)
-{
-       struct ath11k_base *ab = ar->ab;
-       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
-       struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
-       struct peer_create_params peer_param;
-       int ret;
-
-       lockdep_assert_held(&ar->conf_mutex);
-
-       ret = ath11k_mac_inc_num_stations(arvif, sta);
-       if (ret) {
-               ath11k_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;
-               goto dec_num_station;
-       }
-
-       peer_param.vdev_id = arvif->vdev_id;
-       peer_param.peer_addr = sta->addr;
-       peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
-
-       ret = ath11k_peer_create(ar, arvif, sta, &peer_param);
-       if (ret) {
-               ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n",
-                           sta->addr, arvif->vdev_id);
-               goto free_rx_stats;
-       }
-
-       ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n",
-                  sta->addr, arvif->vdev_id);
-
-       if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) {
-               arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL);
-               if (!arsta->tx_stats) {
-                       ret = -ENOMEM;
-                       goto free_peer;
-               }
-       }
-
-       if (ieee80211_vif_is_mesh(vif)) {
-               ath11k_dbg(ab, ATH11K_DBG_MAC,
-                          "setting USE_4ADDR for mesh STA %pM\n", sta->addr);
-               ret = ath11k_wmi_set_peer_param(ar, sta->addr,
-                                               arvif->vdev_id,
-                                               WMI_PEER_USE_4ADDR, 1);
-               if (ret) {
-                       ath11k_warn(ab, "failed to set mesh STA %pM 4addr capability: %d\n",
-                                   sta->addr, ret);
-                       goto free_tx_stats;
-               }
-       }
-
-       ret = ath11k_dp_peer_setup(ar, arvif->vdev_id, sta->addr);
-       if (ret) {
-               ath11k_warn(ab, "failed to setup dp for peer %pM on vdev %i (%d)\n",
-                           sta->addr, arvif->vdev_id, ret);
-               goto free_tx_stats;
-       }
-
-       if (ab->hw_params.vdev_start_delay &&
-           !arvif->is_started &&
-           arvif->vdev_type != WMI_VDEV_TYPE_AP) {
-               ret = ath11k_start_vdev_delay(ar->hw, vif);
-               if (ret) {
-                       ath11k_warn(ab, "failed to delay vdev start: %d\n", ret);
-                       goto free_tx_stats;
-               }
-       }
-
-       ewma_avg_rssi_init(&arsta->avg_rssi);
-       return 0;
-
-free_tx_stats:
-       kfree(arsta->tx_stats);
-       arsta->tx_stats = NULL;
-free_peer:
-       ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
-free_rx_stats:
-       kfree(arsta->rx_stats);
-       arsta->rx_stats = NULL;
-dec_num_station:
-       ath11k_mac_dec_num_stations(arvif, sta);
-exit:
-       return ret;
-}
-
 static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar,
                                              struct ieee80211_sta *sta)
 {
@@ -5028,140 +4942,6 @@ static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar,
        return bw;
 }
 
-static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif,
-                                  struct ieee80211_sta *sta,
-                                  enum ieee80211_sta_state old_state,
-                                  enum ieee80211_sta_state new_state)
-{
-       struct ath11k *ar = hw->priv;
-       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
-       struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
-       struct ath11k_peer *peer;
-       int ret = 0;
-
-       /* cancel must be done outside the mutex to avoid deadlock */
-       if ((old_state == IEEE80211_STA_NONE &&
-            new_state == IEEE80211_STA_NOTEXIST)) {
-               cancel_work_sync(&arsta->update_wk);
-               cancel_work_sync(&arsta->set_4addr_wk);
-       }
-
-       mutex_lock(&ar->conf_mutex);
-
-       if (old_state == IEEE80211_STA_NOTEXIST &&
-           new_state == IEEE80211_STA_NONE) {
-               memset(arsta, 0, sizeof(*arsta));
-               arsta->arvif = arvif;
-               arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
-               INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk);
-               INIT_WORK(&arsta->set_4addr_wk, ath11k_sta_set_4addr_wk);
-
-               ret = ath11k_mac_station_add(ar, vif, sta);
-               if (ret)
-                       ath11k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n",
-                                   sta->addr, arvif->vdev_id);
-       } else if ((old_state == IEEE80211_STA_NONE &&
-                   new_state == IEEE80211_STA_NOTEXIST)) {
-               bool skip_peer_delete = ar->ab->hw_params.vdev_start_delay &&
-                       vif->type == NL80211_IFTYPE_STATION;
-
-               ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr);
-
-               if (!skip_peer_delete) {
-                       ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
-                       if (ret)
-                               ath11k_warn(ar->ab,
-                                           "Failed to delete peer: %pM for VDEV: %d\n",
-                                           sta->addr, arvif->vdev_id);
-                       else
-                               ath11k_dbg(ar->ab,
-                                          ATH11K_DBG_MAC,
-                                          "Removed peer: %pM for VDEV: %d\n",
-                                          sta->addr, arvif->vdev_id);
-               }
-
-               ath11k_mac_dec_num_stations(arvif, sta);
-               mutex_lock(&ar->ab->tbl_mtx_lock);
-               spin_lock_bh(&ar->ab->base_lock);
-               peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
-               if (skip_peer_delete && peer) {
-                       peer->sta = NULL;
-               } else if (peer && peer->sta == sta) {
-                       ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n",
-                                   vif->addr, arvif->vdev_id);
-                       ath11k_peer_rhash_delete(ar->ab, peer);
-                       peer->sta = NULL;
-                       list_del(&peer->list);
-                       kfree(peer);
-                       ar->num_peers--;
-               }
-               spin_unlock_bh(&ar->ab->base_lock);
-               mutex_unlock(&ar->ab->tbl_mtx_lock);
-
-               kfree(arsta->tx_stats);
-               arsta->tx_stats = NULL;
-
-               kfree(arsta->rx_stats);
-               arsta->rx_stats = NULL;
-       } else if (old_state == IEEE80211_STA_AUTH &&
-                  new_state == IEEE80211_STA_ASSOC &&
-                  (vif->type == NL80211_IFTYPE_AP ||
-                   vif->type == NL80211_IFTYPE_MESH_POINT ||
-                   vif->type == NL80211_IFTYPE_ADHOC)) {
-               ret = ath11k_station_assoc(ar, vif, sta, false);
-               if (ret)
-                       ath11k_warn(ar->ab, "Failed to associate station: %pM\n",
-                                   sta->addr);
-
-               spin_lock_bh(&ar->data_lock);
-               /* Set arsta bw and prev bw */
-               arsta->bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta);
-               arsta->bw_prev = arsta->bw;
-               spin_unlock_bh(&ar->data_lock);
-       } else if (old_state == IEEE80211_STA_ASSOC &&
-                  new_state == IEEE80211_STA_AUTHORIZED) {
-               spin_lock_bh(&ar->ab->base_lock);
-
-               peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
-               if (peer)
-                       peer->is_authorized = true;
-
-               spin_unlock_bh(&ar->ab->base_lock);
-
-               if (vif->type == NL80211_IFTYPE_STATION && arvif->is_up) {
-                       ret = ath11k_wmi_set_peer_param(ar, sta->addr,
-                                                       arvif->vdev_id,
-                                                       WMI_PEER_AUTHORIZE,
-                                                       1);
-                       if (ret)
-                               ath11k_warn(ar->ab, "Unable to authorize peer %pM vdev %d: %d\n",
-                                           sta->addr, arvif->vdev_id, ret);
-               }
-       } else if (old_state == IEEE80211_STA_AUTHORIZED &&
-                  new_state == IEEE80211_STA_ASSOC) {
-               spin_lock_bh(&ar->ab->base_lock);
-
-               peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
-               if (peer)
-                       peer->is_authorized = false;
-
-               spin_unlock_bh(&ar->ab->base_lock);
-       } else if (old_state == IEEE80211_STA_ASSOC &&
-                  new_state == IEEE80211_STA_AUTH &&
-                  (vif->type == NL80211_IFTYPE_AP ||
-                   vif->type == NL80211_IFTYPE_MESH_POINT ||
-                   vif->type == NL80211_IFTYPE_ADHOC)) {
-               ret = ath11k_station_disassoc(ar, vif, sta);
-               if (ret)
-                       ath11k_warn(ar->ab, "Failed to disassociate station: %pM\n",
-                                   sta->addr);
-       }
-
-       mutex_unlock(&ar->conf_mutex);
-       return ret;
-}
-
 static int ath11k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
                                       struct ieee80211_sta *sta)
@@ -6940,6 +6720,14 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
                                    ret);
        }
 
+       if (ath11k_wmi_supports_6ghz_cc_ext(ar)) {
+               struct cur_regulatory_info *reg_info;
+
+               reg_info = &ab->reg_info_store[ar->pdev_idx];
+               ath11k_dbg(ab, ATH11K_DBG_MAC, "interface added to change reg rules\n");
+               ath11k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_LPI_AP);
+       }
+
        mutex_unlock(&ar->conf_mutex);
 
        return 0;
@@ -7266,6 +7054,15 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif,
                return ret;
        }
 
+       /* TODO: For now we only set TPC power here. However when
+        * channel changes, say CSA, it should be updated again.
+        */
+       if (ath11k_mac_supports_station_tpc(ar, arvif, chandef)) {
+               ath11k_mac_fill_reg_tpc_info(ar, arvif->vif, &arvif->chanctx);
+               ath11k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id,
+                                                  &arvif->reg_tpc_info);
+       }
+
        if (!restart)
                ar->num_started_vdevs++;
 
@@ -7542,8 +7339,8 @@ unlock:
        mutex_unlock(&ar->conf_mutex);
 }
 
-static int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif)
+static int ath11k_mac_start_vdev_delay(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif)
 {
        struct ath11k *ar = hw->priv;
        struct ath11k_base *ab = ar->ab;
@@ -7589,52 +7386,550 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
        return 0;
 }
 
-static int
-ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
-                                struct ieee80211_vif *vif,
-                                struct ieee80211_bss_conf *link_conf,
-                                struct ieee80211_chanctx_conf *ctx)
+static int ath11k_mac_stop_vdev_early(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif)
 {
        struct ath11k *ar = hw->priv;
        struct ath11k_base *ab = ar->ab;
        struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
        int ret;
-       struct peer_create_params param;
-
-       mutex_lock(&ar->conf_mutex);
-
-       ath11k_dbg(ab, ATH11K_DBG_MAC,
-                  "chanctx assign ptr %p vdev_id %i\n",
-                  ctx, arvif->vdev_id);
 
-       /* for QCA6390 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 &&
-           !ath11k_peer_find_by_vdev_id(ab, arvif->vdev_id)) {
-               memcpy(&arvif->chanctx, ctx, sizeof(*ctx));
-               ret = 0;
-               goto out;
-       }
+       if (WARN_ON(!arvif->is_started))
+               return -EBUSY;
 
-       if (WARN_ON(arvif->is_started)) {
-               ret = -EBUSY;
-               goto out;
+       ret = ath11k_mac_vdev_stop(arvif);
+       if (ret) {
+               ath11k_warn(ab, "failed to stop vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
        }
 
-       if (ab->hw_params.vdev_start_delay &&
-           arvif->vdev_type != WMI_VDEV_TYPE_AP &&
-           arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
-               param.vdev_id = arvif->vdev_id;
-               param.peer_type = WMI_PEER_TYPE_DEFAULT;
-               param.peer_addr = ar->mac_addr;
+       arvif->is_started = false;
 
-               ret = ath11k_peer_create(ar, arvif, NULL, &param);
-               if (ret) {
-                       ath11k_warn(ab, "failed to create peer after vdev start delay: %d",
-                                   ret);
+       /* TODO: Setup ps and cts/rts protection */
+       return 0;
+}
+
+static u8 ath11k_mac_get_tpe_count(u8 txpwr_intrprt, u8 txpwr_cnt)
+{
+       switch (txpwr_intrprt) {
+       /* Refer "Table 9-276-Meaning of Maximum Transmit Power Count subfield
+        * if the Maximum Transmit Power Interpretation subfield is 0 or 2" of
+        * "IEEE Std 802.11ax 2021".
+        */
+       case IEEE80211_TPE_LOCAL_EIRP:
+       case IEEE80211_TPE_REG_CLIENT_EIRP:
+               txpwr_cnt = txpwr_cnt <= 3 ? txpwr_cnt : 3;
+               txpwr_cnt = txpwr_cnt + 1;
+               break;
+       /* Refer "Table 9-277-Meaning of Maximum Transmit Power Count subfield
+        * if Maximum Transmit Power Interpretation subfield is 1 or 3" of
+        * "IEEE Std 802.11ax 2021".
+        */
+       case IEEE80211_TPE_LOCAL_EIRP_PSD:
+       case IEEE80211_TPE_REG_CLIENT_EIRP_PSD:
+               txpwr_cnt = txpwr_cnt <= 4 ? txpwr_cnt : 4;
+               txpwr_cnt = txpwr_cnt ? (BIT(txpwr_cnt - 1)) : 1;
+               break;
+       }
+
+       return txpwr_cnt;
+}
+
+static u8 ath11k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def)
+{
+       if (chan_def->chan->flags & IEEE80211_CHAN_PSD) {
+               switch (chan_def->width) {
+               case NL80211_CHAN_WIDTH_20:
+                       return 1;
+               case NL80211_CHAN_WIDTH_40:
+                       return 2;
+               case NL80211_CHAN_WIDTH_80:
+                       return 4;
+               case NL80211_CHAN_WIDTH_80P80:
+               case NL80211_CHAN_WIDTH_160:
+                       return 8;
+               default:
+                       return 1;
+               }
+       } else {
+               switch (chan_def->width) {
+               case NL80211_CHAN_WIDTH_20:
+                       return 1;
+               case NL80211_CHAN_WIDTH_40:
+                       return 2;
+               case NL80211_CHAN_WIDTH_80:
+                       return 3;
+               case NL80211_CHAN_WIDTH_80P80:
+               case NL80211_CHAN_WIDTH_160:
+                       return 4;
+               default:
+                       return 1;
+               }
+       }
+}
+
+static u16 ath11k_mac_get_6ghz_start_frequency(struct cfg80211_chan_def *chan_def)
+{
+       u16 diff_seq;
+
+       /* It is to get the lowest channel number's center frequency of the chan.
+        * For example,
+        * bandwidth=40 MHz, center frequency is 5965, lowest channel is 1
+        * with center frequency 5955, its diff is 5965 - 5955 = 10.
+        * bandwidth=80 MHz, center frequency is 5985, lowest channel is 1
+        * with center frequency 5955, its diff is 5985 - 5955 = 30.
+        * bandwidth=160 MHz, center frequency is 6025, lowest channel is 1
+        * with center frequency 5955, its diff is 6025 - 5955 = 70.
+        */
+       switch (chan_def->width) {
+       case NL80211_CHAN_WIDTH_160:
+               diff_seq = 70;
+               break;
+       case NL80211_CHAN_WIDTH_80:
+       case NL80211_CHAN_WIDTH_80P80:
+               diff_seq = 30;
+               break;
+       case NL80211_CHAN_WIDTH_40:
+               diff_seq = 10;
+               break;
+       default:
+               diff_seq = 0;
+       }
+
+       return chan_def->center_freq1 - diff_seq;
+}
+
+static u16 ath11k_mac_get_seg_freq(struct cfg80211_chan_def *chan_def,
+                                  u16 start_seq, u8 seq)
+{
+       u16 seg_seq;
+
+       /* It is to get the center frequency of the specific bandwidth.
+        * start_seq means the lowest channel number's center frequency.
+        * seq 0/1/2/3 means 20 MHz/40 MHz/80 MHz/160 MHz&80P80.
+        * For example,
+        * lowest channel is 1, its center frequency 5955,
+        * center frequency is 5955 when bandwidth=20 MHz, its diff is 5955 - 5955 = 0.
+        * lowest channel is 1, its center frequency 5955,
+        * center frequency is 5965 when bandwidth=40 MHz, its diff is 5965 - 5955 = 10.
+        * lowest channel is 1, its center frequency 5955,
+        * center frequency is 5985 when bandwidth=80 MHz, its diff is 5985 - 5955 = 30.
+        * lowest channel is 1, its center frequency 5955,
+        * center frequency is 6025 when bandwidth=160 MHz, its diff is 6025 - 5955 = 70.
+        */
+       if (chan_def->width == NL80211_CHAN_WIDTH_80P80 && seq == 3)
+               return chan_def->center_freq2;
+
+       seg_seq = 10 * (BIT(seq) - 1);
+       return seg_seq + start_seq;
+}
+
+static void ath11k_mac_get_psd_channel(struct ath11k *ar,
+                                      u16 step_freq,
+                                      u16 *start_freq,
+                                      u16 *center_freq,
+                                      u8 i,
+                                      struct ieee80211_channel **temp_chan,
+                                      s8 *tx_power)
+{
+       /* It is to get the center frequency for each 20 MHz.
+        * For example, if the chan is 160 MHz and center frequency is 6025,
+        * then it include 8 channels, they are 1/5/9/13/17/21/25/29,
+        * channel number 1's center frequency is 5955, it is parameter start_freq.
+        * parameter i is the step of the 8 channels. i is 0~7 for the 8 channels.
+        * the channel 1/5/9/13/17/21/25/29 maps i=0/1/2/3/4/5/6/7,
+        * and maps its center frequency is 5955/5975/5995/6015/6035/6055/6075/6095,
+        * the gap is 20 for each channel, parameter step_freq means the gap.
+        * after get the center frequency of each channel, it is easy to find the
+        * struct ieee80211_channel of it and get the max_reg_power.
+        */
+       *center_freq = *start_freq + i * step_freq;
+       *temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
+       *tx_power = (*temp_chan)->max_reg_power;
+}
+
+static void ath11k_mac_get_eirp_power(struct ath11k *ar,
+                                     u16 *start_freq,
+                                     u16 *center_freq,
+                                     u8 i,
+                                     struct ieee80211_channel **temp_chan,
+                                     struct cfg80211_chan_def *def,
+                                     s8 *tx_power)
+{
+       /* It is to get the center frequency for 20 MHz/40 MHz/80 MHz/
+        * 160 MHz&80P80 bandwidth, and then plus 10 to the center frequency,
+        * it is the center frequency of a channel number.
+        * For example, when configured channel number is 1.
+        * center frequency is 5965 when bandwidth=40 MHz, after plus 10, it is 5975,
+        * then it is channel number 5.
+        * center frequency is 5985 when bandwidth=80 MHz, after plus 10, it is 5995,
+        * then it is channel number 9.
+        * center frequency is 6025 when bandwidth=160 MHz, after plus 10, it is 6035,
+        * then it is channel number 17.
+        * after get the center frequency of each channel, it is easy to find the
+        * struct ieee80211_channel of it and get the max_reg_power.
+        */
+       *center_freq = ath11k_mac_get_seg_freq(def, *start_freq, i);
+
+       /* For the 20 MHz, its center frequency is same with same channel */
+       if (i != 0)
+               *center_freq += 10;
+
+       *temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
+       *tx_power = (*temp_chan)->max_reg_power;
+}
+
+void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_chanctx_conf *ctx)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+       struct ath11k_reg_tpc_power_info *reg_tpc_info = &arvif->reg_tpc_info;
+       struct ieee80211_channel *chan, *temp_chan;
+       u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction;
+       bool is_psd_power = false, is_tpe_present = false;
+       s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL],
+               psd_power, tx_power, eirp_power;
+       u16 start_freq, center_freq;
+
+       chan = ctx->def.chan;
+       start_freq = ath11k_mac_get_6ghz_start_frequency(&ctx->def);
+       pwr_reduction = bss_conf->pwr_reduction;
+
+       if (arvif->reg_tpc_info.num_pwr_levels) {
+               is_tpe_present = true;
+               num_pwr_levels = arvif->reg_tpc_info.num_pwr_levels;
+       } else {
+               num_pwr_levels = ath11k_mac_get_num_pwr_levels(&ctx->def);
+       }
+
+       for (pwr_lvl_idx = 0; pwr_lvl_idx < num_pwr_levels; pwr_lvl_idx++) {
+               /* STA received TPE IE*/
+               if (is_tpe_present) {
+                       /* local power is PSD power*/
+                       if (chan->flags & IEEE80211_CHAN_PSD) {
+                               /* Connecting AP is psd power */
+                               if (reg_tpc_info->is_psd_power) {
+                                       is_psd_power = true;
+                                       ath11k_mac_get_psd_channel(ar, 20,
+                                                                  &start_freq,
+                                                                  &center_freq,
+                                                                  pwr_lvl_idx,
+                                                                  &temp_chan,
+                                                                  &tx_power);
+                                       psd_power = temp_chan->psd;
+                                       eirp_power = tx_power;
+                                       max_tx_power[pwr_lvl_idx] =
+                                               min_t(s8,
+                                                     psd_power,
+                                                     reg_tpc_info->tpe[pwr_lvl_idx]);
+                               /* Connecting AP is not psd power */
+                               } else {
+                                       ath11k_mac_get_eirp_power(ar,
+                                                                 &start_freq,
+                                                                 &center_freq,
+                                                                 pwr_lvl_idx,
+                                                                 &temp_chan,
+                                                                 &ctx->def,
+                                                                 &tx_power);
+                                       psd_power = temp_chan->psd;
+                                       /* convert psd power to EIRP power based
+                                        * on channel width
+                                        */
+                                       tx_power =
+                                               min_t(s8, tx_power,
+                                                     psd_power + 13 + pwr_lvl_idx * 3);
+                                       max_tx_power[pwr_lvl_idx] =
+                                               min_t(s8,
+                                                     tx_power,
+                                                     reg_tpc_info->tpe[pwr_lvl_idx]);
+                               }
+                       /* local power is not PSD power */
+                       } else {
+                               /* Connecting AP is psd power */
+                               if (reg_tpc_info->is_psd_power) {
+                                       is_psd_power = true;
+                                       ath11k_mac_get_psd_channel(ar, 20,
+                                                                  &start_freq,
+                                                                  &center_freq,
+                                                                  pwr_lvl_idx,
+                                                                  &temp_chan,
+                                                                  &tx_power);
+                                       eirp_power = tx_power;
+                                       max_tx_power[pwr_lvl_idx] =
+                                               reg_tpc_info->tpe[pwr_lvl_idx];
+                               /* Connecting AP is not psd power */
+                               } else {
+                                       ath11k_mac_get_eirp_power(ar,
+                                                                 &start_freq,
+                                                                 &center_freq,
+                                                                 pwr_lvl_idx,
+                                                                 &temp_chan,
+                                                                 &ctx->def,
+                                                                 &tx_power);
+                                       max_tx_power[pwr_lvl_idx] =
+                                               min_t(s8,
+                                                     tx_power,
+                                                     reg_tpc_info->tpe[pwr_lvl_idx]);
+                               }
+                       }
+               /* STA not received TPE IE */
+               } else {
+                       /* local power is PSD power*/
+                       if (chan->flags & IEEE80211_CHAN_PSD) {
+                               is_psd_power = true;
+                               ath11k_mac_get_psd_channel(ar, 20,
+                                                          &start_freq,
+                                                          &center_freq,
+                                                          pwr_lvl_idx,
+                                                          &temp_chan,
+                                                          &tx_power);
+                               psd_power = temp_chan->psd;
+                               eirp_power = tx_power;
+                               max_tx_power[pwr_lvl_idx] = psd_power;
+                       } else {
+                               ath11k_mac_get_eirp_power(ar,
+                                                         &start_freq,
+                                                         &center_freq,
+                                                         pwr_lvl_idx,
+                                                         &temp_chan,
+                                                         &ctx->def,
+                                                         &tx_power);
+                               max_tx_power[pwr_lvl_idx] = tx_power;
+                       }
+               }
+
+               if (is_psd_power) {
+                       /* If AP local power constraint is present */
+                       if (pwr_reduction)
+                               eirp_power = eirp_power - pwr_reduction;
+
+                       /* If firmware updated max tx power is non zero, then take
+                        * the min of firmware updated ap tx power
+                        * and max power derived from above mentioned parameters.
+                        */
+                       ath11k_dbg(ab, ATH11K_DBG_MAC,
+                                  "eirp power : %d firmware report power : %d\n",
+                                  eirp_power, ar->max_allowed_tx_power);
+                       /* Firmware reports lower max_allowed_tx_power during vdev
+                        * start response. In case of 6 GHz, firmware is not aware
+                        * of EIRP power unless driver sets EIRP power through WMI
+                        * TPC command. So radio which does not support idle power
+                        * save can set maximum calculated EIRP power directly to
+                        * firmware through TPC command without min comparison with
+                        * vdev start response's max_allowed_tx_power.
+                        */
+                       if (ar->max_allowed_tx_power && ab->hw_params.idle_ps)
+                               eirp_power = min_t(s8,
+                                                  eirp_power,
+                                                  ar->max_allowed_tx_power);
+               } else {
+                       /* If AP local power constraint is present */
+                       if (pwr_reduction)
+                               max_tx_power[pwr_lvl_idx] =
+                                       max_tx_power[pwr_lvl_idx] - pwr_reduction;
+                       /* If firmware updated max tx power is non zero, then take
+                        * the min of firmware updated ap tx power
+                        * and max power derived from above mentioned parameters.
+                        */
+                       if (ar->max_allowed_tx_power && ab->hw_params.idle_ps)
+                               max_tx_power[pwr_lvl_idx] =
+                                       min_t(s8,
+                                             max_tx_power[pwr_lvl_idx],
+                                             ar->max_allowed_tx_power);
+               }
+               reg_tpc_info->chan_power_info[pwr_lvl_idx].chan_cfreq = center_freq;
+               reg_tpc_info->chan_power_info[pwr_lvl_idx].tx_power =
+                       max_tx_power[pwr_lvl_idx];
+       }
+
+       reg_tpc_info->num_pwr_levels = num_pwr_levels;
+       reg_tpc_info->is_psd_power = is_psd_power;
+       reg_tpc_info->eirp_power = eirp_power;
+       reg_tpc_info->ap_power_type =
+               ath11k_reg_ap_pwr_convert(vif->bss_conf.power_type);
+}
+
+static void ath11k_mac_parse_tx_pwr_env(struct ath11k *ar,
+                                       struct ieee80211_vif *vif,
+                                       struct ieee80211_chanctx_conf *ctx)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+       struct ieee80211_tx_pwr_env *single_tpe;
+       enum wmi_reg_6ghz_client_type client_type;
+       struct cur_regulatory_info *reg_info;
+       int i;
+       u8 pwr_count, pwr_interpret, pwr_category;
+       u8 psd_index = 0, non_psd_index = 0, local_tpe_count = 0, reg_tpe_count = 0;
+       bool use_local_tpe, non_psd_set = false, psd_set = false;
+
+       reg_info = &ab->reg_info_store[ar->pdev_idx];
+       client_type = reg_info->client_type;
+
+       for (i = 0; i < bss_conf->tx_pwr_env_num; i++) {
+               single_tpe = &bss_conf->tx_pwr_env[i];
+               pwr_category = u8_get_bits(single_tpe->tx_power_info,
+                                          IEEE80211_TX_PWR_ENV_INFO_CATEGORY);
+               pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+                                           IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+
+               if (pwr_category == client_type) {
+                       if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP ||
+                           pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD)
+                               local_tpe_count++;
+                       else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP ||
+                                pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD)
+                               reg_tpe_count++;
+               }
+       }
+
+       if (!reg_tpe_count && !local_tpe_count) {
+               ath11k_warn(ab,
+                           "no transmit power envelope match client power type %d\n",
+                           client_type);
+               return;
+       } else if (!reg_tpe_count) {
+               use_local_tpe = true;
+       } else {
+               use_local_tpe = false;
+       }
+
+       for (i = 0; i < bss_conf->tx_pwr_env_num; i++) {
+               single_tpe = &bss_conf->tx_pwr_env[i];
+               pwr_category = u8_get_bits(single_tpe->tx_power_info,
+                                          IEEE80211_TX_PWR_ENV_INFO_CATEGORY);
+               pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+                                           IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+
+               if (pwr_category != client_type)
+                       continue;
+
+               /* get local transmit power envelope */
+               if (use_local_tpe) {
+                       if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP) {
+                               non_psd_index = i;
+                               non_psd_set = true;
+                       } else if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD) {
+                               psd_index = i;
+                               psd_set = true;
+                       }
+               /* get regulatory transmit power envelope */
+               } else {
+                       if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP) {
+                               non_psd_index = i;
+                               non_psd_set = true;
+                       } else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD) {
+                               psd_index = i;
+                               psd_set = true;
+                       }
+               }
+       }
+
+       if (non_psd_set && !psd_set) {
+               single_tpe = &bss_conf->tx_pwr_env[non_psd_index];
+               pwr_count = u8_get_bits(single_tpe->tx_power_info,
+                                       IEEE80211_TX_PWR_ENV_INFO_COUNT);
+               pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+                                           IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+               arvif->reg_tpc_info.is_psd_power = false;
+               arvif->reg_tpc_info.eirp_power = 0;
+
+               arvif->reg_tpc_info.num_pwr_levels =
+                       ath11k_mac_get_tpe_count(pwr_interpret, pwr_count);
+
+               for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) {
+                       ath11k_dbg(ab, ATH11K_DBG_MAC,
+                                  "non PSD power[%d] : %d\n",
+                                  i, single_tpe->tx_power[i]);
+                       arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2;
+               }
+       }
+
+       if (psd_set) {
+               single_tpe = &bss_conf->tx_pwr_env[psd_index];
+               pwr_count = u8_get_bits(single_tpe->tx_power_info,
+                                       IEEE80211_TX_PWR_ENV_INFO_COUNT);
+               pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+                                           IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+               arvif->reg_tpc_info.is_psd_power = true;
+
+               if (pwr_count == 0) {
+                       ath11k_dbg(ab, ATH11K_DBG_MAC,
+                                  "TPE PSD power : %d\n", single_tpe->tx_power[0]);
+                       arvif->reg_tpc_info.num_pwr_levels =
+                               ath11k_mac_get_num_pwr_levels(&ctx->def);
+
+                       for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++)
+                               arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[0] / 2;
+               } else {
+                       arvif->reg_tpc_info.num_pwr_levels =
+                               ath11k_mac_get_tpe_count(pwr_interpret, pwr_count);
+
+                       for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) {
+                               ath11k_dbg(ab, ATH11K_DBG_MAC,
+                                          "TPE PSD power[%d] : %d\n",
+                                          i, single_tpe->tx_power[i]);
+                               arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2;
+                       }
+               }
+       }
+}
+
+static int
+ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_bss_conf *link_conf,
+                                struct ieee80211_chanctx_conf *ctx)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       int ret;
+       struct cur_regulatory_info *reg_info;
+       enum ieee80211_ap_reg_power power_type;
+
+       mutex_lock(&ar->conf_mutex);
+
+       ath11k_dbg(ab, ATH11K_DBG_MAC,
+                  "chanctx assign ptr %p vdev_id %i\n",
+                  ctx, arvif->vdev_id);
+
+       if (ath11k_wmi_supports_6ghz_cc_ext(ar) &&
+           ctx->def.chan->band == NL80211_BAND_6GHZ &&
+           arvif->vdev_type == WMI_VDEV_TYPE_STA) {
+               reg_info = &ab->reg_info_store[ar->pdev_idx];
+               power_type = vif->bss_conf.power_type;
+
+               ath11k_dbg(ab, ATH11K_DBG_MAC, "chanctx power type %d\n", power_type);
+
+               if (power_type == IEEE80211_REG_UNSET_AP) {
+                       ret = -EINVAL;
                        goto out;
                }
+
+               ath11k_reg_handle_chan_list(ab, reg_info, power_type);
+               arvif->chanctx = *ctx;
+               ath11k_mac_parse_tx_pwr_env(ar, vif, ctx);
+       }
+
+       /* for QCA6390 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 &&
+           !ath11k_peer_find_by_vdev_id(ab, arvif->vdev_id)) {
+               memcpy(&arvif->chanctx, ctx, sizeof(*ctx));
+               ret = 0;
+               goto out;
+       }
+
+       if (WARN_ON(arvif->is_started)) {
+               ret = -EBUSY;
+               goto out;
        }
 
        if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
@@ -7649,15 +7944,17 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
                goto out;
        }
 
-       ret = ath11k_mac_vdev_start(arvif, ctx);
-       if (ret) {
-               ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n",
-                           arvif->vdev_id, vif->addr,
-                           ctx->def.chan->center_freq, ret);
-               goto out;
-       }
+       if (!arvif->is_started) {
+               ret = ath11k_mac_vdev_start(arvif, ctx);
+               if (ret) {
+                       ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n",
+                                   arvif->vdev_id, vif->addr,
+                                   ctx->def.chan->center_freq, ret);
+                       goto out;
+               }
 
-       arvif->is_started = true;
+               arvif->is_started = true;
+       }
 
        if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
            test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) {
@@ -7697,8 +7994,6 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
                   "chanctx unassign ptr %p vdev_id %i\n",
                   ctx, arvif->vdev_id);
 
-       WARN_ON(!arvif->is_started);
-
        if (ab->hw_params.vdev_start_delay &&
            arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
                spin_lock_bh(&ab->base_lock);
@@ -7722,24 +8017,13 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
                return;
        }
 
-       ret = ath11k_mac_vdev_stop(arvif);
-       if (ret)
-               ath11k_warn(ab, "failed to stop vdev %i: %d\n",
-                           arvif->vdev_id, ret);
-
-       arvif->is_started = false;
-
-       if (ab->hw_params.vdev_start_delay &&
-           arvif->vdev_type == WMI_VDEV_TYPE_STA) {
-               ret = ath11k_peer_delete(ar, arvif->vdev_id, arvif->bssid);
+       if (arvif->is_started) {
+               ret = ath11k_mac_vdev_stop(arvif);
                if (ret)
-                       ath11k_warn(ar->ab,
-                                   "failed to delete peer %pM for vdev %d: %d\n",
-                                   arvif->bssid, arvif->vdev_id, ret);
-               else
-                       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
-                                  "removed peer %pM  vdev %d after vdev stop\n",
-                                  arvif->bssid, arvif->vdev_id);
+                       ath11k_warn(ab, "failed to stop vdev %i: %d\n",
+                                   arvif->vdev_id, ret);
+
+               arvif->is_started = false;
        }
 
        if (ab->hw_params.vdev_start_delay &&
@@ -9097,6 +9381,252 @@ err_fallback:
        return 0;
 }
 
+static int ath11k_mac_station_add(struct ath11k *ar,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_sta *sta)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
+       struct peer_create_params peer_param;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ret = ath11k_mac_inc_num_stations(arvif, sta);
+       if (ret) {
+               ath11k_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;
+               goto dec_num_station;
+       }
+
+       peer_param.vdev_id = arvif->vdev_id;
+       peer_param.peer_addr = sta->addr;
+       peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
+
+       ret = ath11k_peer_create(ar, arvif, sta, &peer_param);
+       if (ret) {
+               ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n",
+                           sta->addr, arvif->vdev_id);
+               goto free_rx_stats;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n",
+                  sta->addr, arvif->vdev_id);
+
+       if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) {
+               arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL);
+               if (!arsta->tx_stats) {
+                       ret = -ENOMEM;
+                       goto free_peer;
+               }
+       }
+
+       if (ieee80211_vif_is_mesh(vif)) {
+               ath11k_dbg(ab, ATH11K_DBG_MAC,
+                          "setting USE_4ADDR for mesh STA %pM\n", sta->addr);
+               ret = ath11k_wmi_set_peer_param(ar, sta->addr,
+                                               arvif->vdev_id,
+                                               WMI_PEER_USE_4ADDR, 1);
+               if (ret) {
+                       ath11k_warn(ab, "failed to set mesh STA %pM 4addr capability: %d\n",
+                                   sta->addr, ret);
+                       goto free_tx_stats;
+               }
+       }
+
+       ret = ath11k_dp_peer_setup(ar, arvif->vdev_id, sta->addr);
+       if (ret) {
+               ath11k_warn(ab, "failed to setup dp for peer %pM on vdev %i (%d)\n",
+                           sta->addr, arvif->vdev_id, ret);
+               goto free_tx_stats;
+       }
+
+       if (ab->hw_params.vdev_start_delay &&
+           !arvif->is_started &&
+           arvif->vdev_type != WMI_VDEV_TYPE_AP) {
+               ret = ath11k_mac_start_vdev_delay(ar->hw, vif);
+               if (ret) {
+                       ath11k_warn(ab, "failed to delay vdev start: %d\n", ret);
+                       goto free_tx_stats;
+               }
+       }
+
+       ewma_avg_rssi_init(&arsta->avg_rssi);
+       return 0;
+
+free_tx_stats:
+       kfree(arsta->tx_stats);
+       arsta->tx_stats = NULL;
+free_peer:
+       ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
+free_rx_stats:
+       kfree(arsta->rx_stats);
+       arsta->rx_stats = NULL;
+dec_num_station:
+       ath11k_mac_dec_num_stations(arvif, sta);
+exit:
+       return ret;
+}
+
+static int ath11k_mac_station_remove(struct ath11k *ar,
+                                    struct ieee80211_vif *vif,
+                                    struct ieee80211_sta *sta)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
+       int ret;
+
+       if (ab->hw_params.vdev_start_delay &&
+           arvif->is_started &&
+           arvif->vdev_type != WMI_VDEV_TYPE_AP) {
+               ret = ath11k_mac_stop_vdev_early(ar->hw, vif);
+               if (ret) {
+                       ath11k_warn(ab, "failed to do early vdev stop: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr);
+
+       ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
+       if (ret)
+               ath11k_warn(ab, "Failed to delete peer: %pM for VDEV: %d\n",
+                           sta->addr, arvif->vdev_id);
+       else
+               ath11k_dbg(ab, ATH11K_DBG_MAC, "Removed peer: %pM for VDEV: %d\n",
+                          sta->addr, arvif->vdev_id);
+
+       ath11k_mac_dec_num_stations(arvif, sta);
+
+       kfree(arsta->tx_stats);
+       arsta->tx_stats = NULL;
+
+       kfree(arsta->rx_stats);
+       arsta->rx_stats = NULL;
+
+       return ret;
+}
+
+static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_sta *sta,
+                                  enum ieee80211_sta_state old_state,
+                                  enum ieee80211_sta_state new_state)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);
+       struct ath11k_peer *peer;
+       int ret = 0;
+
+       /* cancel must be done outside the mutex to avoid deadlock */
+       if ((old_state == IEEE80211_STA_NONE &&
+            new_state == IEEE80211_STA_NOTEXIST)) {
+               cancel_work_sync(&arsta->update_wk);
+               cancel_work_sync(&arsta->set_4addr_wk);
+       }
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (old_state == IEEE80211_STA_NOTEXIST &&
+           new_state == IEEE80211_STA_NONE) {
+               memset(arsta, 0, sizeof(*arsta));
+               arsta->arvif = arvif;
+               arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
+               INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk);
+               INIT_WORK(&arsta->set_4addr_wk, ath11k_sta_set_4addr_wk);
+
+               ret = ath11k_mac_station_add(ar, vif, sta);
+               if (ret)
+                       ath11k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n",
+                                   sta->addr, arvif->vdev_id);
+       } else if ((old_state == IEEE80211_STA_NONE &&
+                   new_state == IEEE80211_STA_NOTEXIST)) {
+               ret = ath11k_mac_station_remove(ar, vif, sta);
+               if (ret)
+                       ath11k_warn(ar->ab, "Failed to remove station: %pM for VDEV: %d\n",
+                                   sta->addr, arvif->vdev_id);
+
+               mutex_lock(&ar->ab->tbl_mtx_lock);
+               spin_lock_bh(&ar->ab->base_lock);
+               peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
+               if (peer && peer->sta == sta) {
+                       ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n",
+                                   vif->addr, arvif->vdev_id);
+                       ath11k_peer_rhash_delete(ar->ab, peer);
+                       peer->sta = NULL;
+                       list_del(&peer->list);
+                       kfree(peer);
+                       ar->num_peers--;
+               }
+               spin_unlock_bh(&ar->ab->base_lock);
+               mutex_unlock(&ar->ab->tbl_mtx_lock);
+       } else if (old_state == IEEE80211_STA_AUTH &&
+                  new_state == IEEE80211_STA_ASSOC &&
+                  (vif->type == NL80211_IFTYPE_AP ||
+                   vif->type == NL80211_IFTYPE_MESH_POINT ||
+                   vif->type == NL80211_IFTYPE_ADHOC)) {
+               ret = ath11k_station_assoc(ar, vif, sta, false);
+               if (ret)
+                       ath11k_warn(ar->ab, "Failed to associate station: %pM\n",
+                                   sta->addr);
+
+               spin_lock_bh(&ar->data_lock);
+               /* Set arsta bw and prev bw */
+               arsta->bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta);
+               arsta->bw_prev = arsta->bw;
+               spin_unlock_bh(&ar->data_lock);
+       } else if (old_state == IEEE80211_STA_ASSOC &&
+                  new_state == IEEE80211_STA_AUTHORIZED) {
+               spin_lock_bh(&ar->ab->base_lock);
+
+               peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
+               if (peer)
+                       peer->is_authorized = true;
+
+               spin_unlock_bh(&ar->ab->base_lock);
+
+               if (vif->type == NL80211_IFTYPE_STATION && arvif->is_up) {
+                       ret = ath11k_wmi_set_peer_param(ar, sta->addr,
+                                                       arvif->vdev_id,
+                                                       WMI_PEER_AUTHORIZE,
+                                                       1);
+                       if (ret)
+                               ath11k_warn(ar->ab, "Unable to authorize peer %pM vdev %d: %d\n",
+                                           sta->addr, arvif->vdev_id, ret);
+               }
+       } else if (old_state == IEEE80211_STA_AUTHORIZED &&
+                  new_state == IEEE80211_STA_ASSOC) {
+               spin_lock_bh(&ar->ab->base_lock);
+
+               peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
+               if (peer)
+                       peer->is_authorized = false;
+
+               spin_unlock_bh(&ar->ab->base_lock);
+       } else if (old_state == IEEE80211_STA_ASSOC &&
+                  new_state == IEEE80211_STA_AUTH &&
+                  (vif->type == NL80211_IFTYPE_AP ||
+                   vif->type == NL80211_IFTYPE_MESH_POINT ||
+                   vif->type == NL80211_IFTYPE_ADHOC)) {
+               ret = ath11k_station_disassoc(ar, vif, sta);
+               if (ret)
+                       ath11k_warn(ar->ab, "Failed to disassociate station: %pM\n",
+                                   sta->addr);
+       }
+
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
 static const struct ieee80211_ops ath11k_ops = {
        .tx                             = ath11k_mac_op_tx,
        .wake_tx_queue                  = ieee80211_handle_wake_tx_queue,
index 0dfdeed5177b88f74480ebf0e47d3055ba17e10c..f5800fbecff89e0a8e509cdbee005f3858d6b97a 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
 /*
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef ATH11K_MAC_H
@@ -176,4 +176,7 @@ int ath11k_mac_wait_tx_complete(struct ath11k *ar);
 int ath11k_mac_vif_set_keepalive(struct ath11k_vif *arvif,
                                 enum wmi_sta_keepalive_method method,
                                 u32 interval);
+void ath11k_mac_fill_reg_tpc_info(struct ath11k *ar,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_chanctx_conf *ctx);
 #endif
index 6835c14b82cc9570399698c4c4efd65a0a72b7bd..e6e69bb911036ee8b8f8e6fa6e4a91ea7959b8a8 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2020 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.
  */
 
 #include <linux/msi.h>
@@ -423,7 +423,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
                        goto free_controller;
        } else {
                mhi_ctrl->iova_start = 0;
-               mhi_ctrl->iova_stop = 0xFFFFFFFF;
+               mhi_ctrl->iova_stop = ab_pci->dma_mask;
        }
 
        mhi_ctrl->rddm_size = RDDM_DUMP_SIZE;
index 09e65c5e55c4a9add673fb720d656176366fa1ae..d667d5e06a66bc73f6da015e42b022e4a5230d28 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2019-2020 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.
  */
 
 #include <linux/module.h>
@@ -18,7 +18,8 @@
 #include "qmi.h"
 
 #define ATH11K_PCI_BAR_NUM             0
-#define ATH11K_PCI_DMA_MASK            32
+#define ATH11K_PCI_DMA_MASK            36
+#define ATH11K_PCI_COHERENT_DMA_MASK   32
 
 #define TCSR_SOC_HW_VERSION            0x0224
 #define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8)
@@ -526,14 +527,24 @@ static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev)
                goto disable_device;
        }
 
-       ret = dma_set_mask_and_coherent(&pdev->dev,
-                                       DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
+       ret = dma_set_mask(&pdev->dev,
+                          DMA_BIT_MASK(ATH11K_PCI_DMA_MASK));
        if (ret) {
                ath11k_err(ab, "failed to set pci dma mask to %d: %d\n",
                           ATH11K_PCI_DMA_MASK, ret);
                goto release_region;
        }
 
+       ab_pci->dma_mask = DMA_BIT_MASK(ATH11K_PCI_DMA_MASK);
+
+       ret = dma_set_coherent_mask(&pdev->dev,
+                                   DMA_BIT_MASK(ATH11K_PCI_COHERENT_DMA_MASK));
+       if (ret) {
+               ath11k_err(ab, "failed to set pci coherent dma mask to %d: %d\n",
+                          ATH11K_PCI_COHERENT_DMA_MASK, ret);
+               goto release_region;
+       }
+
        pci_set_master(pdev);
 
        ab->mem_len = pci_resource_len(pdev, ATH11K_PCI_BAR_NUM);
index e9a01f344ec6cd3ba1001d1cf1fd03c4417a8a7a..6be73333d90be6c090802ba55899e0546db256d2 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
 /*
  * Copyright (c) 2019-2020 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.
  */
 #ifndef _ATH11K_PCI_H
 #define _ATH11K_PCI_H
@@ -72,6 +72,7 @@ struct ath11k_pci {
        /* enum ath11k_pci_flags */
        unsigned long flags;
        u16 link_ctl;
+       u64 dma_mask;
 };
 
 static inline struct ath11k_pci *ath11k_pci_priv(struct ath11k_base *ab)
index b4fd4d2107c71fc64f3512f224514437d58325a9..737fcd450d4bdad3c654cd5c38e158f14ef0778a 100644 (file)
@@ -425,6 +425,11 @@ static void ath11k_reg_intersect_rules(struct ieee80211_reg_rule *rule1,
        /* Use the flags of both the rules */
        new_rule->flags = rule1->flags | rule2->flags;
 
+       if ((rule1->flags & NL80211_RRF_PSD) && (rule2->flags & NL80211_RRF_PSD))
+               new_rule->psd = min_t(s8, rule1->psd, rule2->psd);
+       else
+               new_rule->flags &= ~NL80211_RRF_PSD;
+
        /* To be safe, lts use the max cac timeout of both rules */
        new_rule->dfs_cac_ms = max_t(u32, rule1->dfs_cac_ms,
                                     rule2->dfs_cac_ms);
@@ -527,13 +532,14 @@ ath11k_reg_adjust_bw(u16 start_freq, u16 end_freq, u16 max_bw)
 static void
 ath11k_reg_update_rule(struct ieee80211_reg_rule *reg_rule, u32 start_freq,
                       u32 end_freq, u32 bw, u32 ant_gain, u32 reg_pwr,
-                      u32 reg_flags)
+                      s8 psd, u32 reg_flags)
 {
        reg_rule->freq_range.start_freq_khz = MHZ_TO_KHZ(start_freq);
        reg_rule->freq_range.end_freq_khz = MHZ_TO_KHZ(end_freq);
        reg_rule->freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw);
        reg_rule->power_rule.max_antenna_gain = DBI_TO_MBI(ant_gain);
        reg_rule->power_rule.max_eirp = DBM_TO_MBM(reg_pwr);
+       reg_rule->psd = psd;
        reg_rule->flags = reg_flags;
 }
 
@@ -563,7 +569,7 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab,
                                       reg_rule->start_freq,
                                       ETSI_WEATHER_RADAR_BAND_LOW, bw,
                                       reg_rule->ant_gain, reg_rule->reg_power,
-                                      flags);
+                                      reg_rule->psd_eirp, flags);
 
                ath11k_dbg(ab, ATH11K_DBG_REG,
                           "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
@@ -584,7 +590,7 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab,
 
                ath11k_reg_update_rule(regd->reg_rules + i, start_freq,
                                       end_freq, bw, reg_rule->ant_gain,
-                                      reg_rule->reg_power, flags);
+                                      reg_rule->reg_power, reg_rule->psd_eirp, flags);
 
                regd->reg_rules[i].dfs_cac_ms = ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT;
 
@@ -605,7 +611,7 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab,
                                       ETSI_WEATHER_RADAR_BAND_HIGH,
                                       reg_rule->end_freq, bw,
                                       reg_rule->ant_gain, reg_rule->reg_power,
-                                      flags);
+                                      reg_rule->psd_eirp, flags);
 
                ath11k_dbg(ab, ATH11K_DBG_REG,
                           "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
@@ -618,25 +624,68 @@ ath11k_reg_update_weather_radar_band(struct ath11k_base *ab,
        *rule_idx = i;
 }
 
+enum wmi_reg_6ghz_ap_type
+ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type)
+{
+       switch (power_type) {
+       case IEEE80211_REG_LPI_AP:
+               return WMI_REG_INDOOR_AP;
+       case IEEE80211_REG_SP_AP:
+               return WMI_REG_STANDARD_POWER_AP;
+       case IEEE80211_REG_VLP_AP:
+               return WMI_REG_VERY_LOW_POWER_AP;
+       default:
+               return WMI_REG_MAX_AP_TYPE;
+       }
+}
+
 struct ieee80211_regdomain *
 ath11k_reg_build_regd(struct ath11k_base *ab,
-                     struct cur_regulatory_info *reg_info, bool intersect)
+                     struct cur_regulatory_info *reg_info, bool intersect,
+                     enum wmi_vdev_type vdev_type,
+                     enum ieee80211_ap_reg_power power_type)
 {
        struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
-       struct cur_reg_rule *reg_rule;
+       struct cur_reg_rule *reg_rule, *reg_rule_6ghz;
        u8 i = 0, j = 0, k = 0;
        u8 num_rules;
        u16 max_bw;
-       u32 flags;
+       u32 flags, reg_6ghz_number, max_bw_6ghz;
        char alpha2[3];
 
        num_rules = reg_info->num_5ghz_reg_rules + reg_info->num_2ghz_reg_rules;
 
-       /* FIXME: Currently taking reg rules for 6 GHz only from Indoor AP mode list.
-        * This can be updated after complete 6 GHz regulatory support is added.
-        */
-       if (reg_info->is_ext_reg_event)
-               num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP];
+       if (reg_info->is_ext_reg_event) {
+               if (vdev_type == WMI_VDEV_TYPE_STA) {
+                       enum wmi_reg_6ghz_ap_type ap_type;
+
+                       ap_type = ath11k_reg_ap_pwr_convert(power_type);
+
+                       if (ap_type == WMI_REG_MAX_AP_TYPE)
+                               ap_type = WMI_REG_INDOOR_AP;
+
+                       reg_6ghz_number = reg_info->num_6ghz_rules_client
+                                       [ap_type][WMI_REG_DEFAULT_CLIENT];
+
+                       if (reg_6ghz_number == 0) {
+                               ap_type = WMI_REG_INDOOR_AP;
+                               reg_6ghz_number = reg_info->num_6ghz_rules_client
+                                               [ap_type][WMI_REG_DEFAULT_CLIENT];
+                       }
+
+                       reg_rule_6ghz = reg_info->reg_rules_6ghz_client_ptr
+                                       [ap_type][WMI_REG_DEFAULT_CLIENT];
+                       max_bw_6ghz = reg_info->max_bw_6ghz_client
+                                       [ap_type][WMI_REG_DEFAULT_CLIENT];
+               } else {
+                       reg_6ghz_number = reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP];
+                       reg_rule_6ghz =
+                               reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP];
+                       max_bw_6ghz = reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP];
+               }
+
+               num_rules += reg_6ghz_number;
+       }
 
        if (!num_rules)
                goto ret;
@@ -683,14 +732,13 @@ ath11k_reg_build_regd(struct ath11k_base *ab,
                         * per other BW rule flags we pass from here
                         */
                        flags = NL80211_RRF_AUTO_BW;
-               } else if (reg_info->is_ext_reg_event &&
-                          reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP] &&
-                          (k < reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP])) {
-                       reg_rule = reg_info->reg_rules_6ghz_ap_ptr[WMI_REG_INDOOR_AP] +
-                                  k++;
-                       max_bw = min_t(u16, reg_rule->max_bw,
-                                      reg_info->max_bw_6ghz_ap[WMI_REG_INDOOR_AP]);
+               } else if (reg_info->is_ext_reg_event && reg_6ghz_number &&
+                          k < reg_6ghz_number) {
+                       reg_rule = reg_rule_6ghz + k++;
+                       max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
                        flags = NL80211_RRF_AUTO_BW;
+                       if (reg_rule->psd_flag)
+                               flags |= NL80211_RRF_PSD;
                } else {
                        break;
                }
@@ -702,7 +750,7 @@ ath11k_reg_build_regd(struct ath11k_base *ab,
                                       reg_rule->start_freq,
                                       reg_rule->end_freq, max_bw,
                                       reg_rule->ant_gain, reg_rule->reg_power,
-                                      flags);
+                                      reg_rule->psd_eirp, flags);
 
                /* Update dfs cac timeout if the dfs domain is ETSI and the
                 * new rule covers weather radar band.
@@ -758,6 +806,159 @@ ret:
        return new_regd;
 }
 
+static bool ath11k_reg_is_world_alpha(char *alpha)
+{
+       if (alpha[0] == '0' && alpha[1] == '0')
+               return true;
+
+       if (alpha[0] == 'n' && alpha[1] == 'a')
+               return true;
+
+       return false;
+}
+
+static enum wmi_vdev_type ath11k_reg_get_ar_vdev_type(struct ath11k *ar)
+{
+       struct ath11k_vif *arvif;
+
+       /* Currently each struct ath11k maps to one struct ieee80211_hw/wiphy
+        * and one struct ieee80211_regdomain, so it could only store one group
+        * reg rules. It means multi-interface concurrency in the same ath11k is
+        * not support for the regdomain. So get the vdev type of the first entry
+        * now. After concurrency support for the regdomain, this should change.
+        */
+       arvif = list_first_entry_or_null(&ar->arvifs, struct ath11k_vif, list);
+       if (arvif)
+               return arvif->vdev_type;
+
+       return WMI_VDEV_TYPE_UNSPEC;
+}
+
+int ath11k_reg_handle_chan_list(struct ath11k_base *ab,
+                               struct cur_regulatory_info *reg_info,
+                               enum ieee80211_ap_reg_power power_type)
+{
+       struct ieee80211_regdomain *regd;
+       bool intersect = false;
+       int pdev_idx;
+       struct ath11k *ar;
+       enum wmi_vdev_type vdev_type;
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI, "event reg handle chan list");
+
+       if (reg_info->status_code != REG_SET_CC_STATUS_PASS) {
+               /* In case of failure to set the requested ctry,
+                * fw retains the current regd. We print a failure info
+                * and return from here.
+                */
+               ath11k_warn(ab, "Failed to set the requested Country regulatory setting\n");
+               return -EINVAL;
+       }
+
+       pdev_idx = reg_info->phy_id;
+
+       /* Avoid default reg rule updates sent during FW recovery if
+        * it is already available
+        */
+       spin_lock_bh(&ab->base_lock);
+       if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) &&
+           ab->default_regd[pdev_idx]) {
+               spin_unlock_bh(&ab->base_lock);
+               goto retfail;
+       }
+       spin_unlock_bh(&ab->base_lock);
+
+       if (pdev_idx >= ab->num_radios) {
+               /* Process the event for phy0 only if single_pdev_only
+                * is true. If pdev_idx is valid but not 0, discard the
+                * event. Otherwise, it goes to fallback. In either case
+                * ath11k_reg_reset_info() needs to be called to avoid
+                * memory leak issue.
+                */
+               ath11k_reg_reset_info(reg_info);
+
+               if (ab->hw_params.single_pdev_only &&
+                   pdev_idx < ab->hw_params.num_rxmda_per_pdev)
+                       return 0;
+               goto fallback;
+       }
+
+       /* Avoid multiple overwrites to default regd, during core
+        * stop-start after mac registration.
+        */
+       if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] &&
+           !memcmp((char *)ab->default_regd[pdev_idx]->alpha2,
+                   (char *)reg_info->alpha2, 2))
+               goto retfail;
+
+       /* Intersect new rules with default regd if a new country setting was
+        * requested, i.e a default regd was already set during initialization
+        * and the regd coming from this event has a valid country info.
+        */
+       if (ab->default_regd[pdev_idx] &&
+           !ath11k_reg_is_world_alpha((char *)
+               ab->default_regd[pdev_idx]->alpha2) &&
+           !ath11k_reg_is_world_alpha((char *)reg_info->alpha2))
+               intersect = true;
+
+       ar = ab->pdevs[pdev_idx].ar;
+       vdev_type = ath11k_reg_get_ar_vdev_type(ar);
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "wmi handle chan list power type %d vdev type %d intersect %d\n",
+                  power_type, vdev_type, intersect);
+
+       regd = ath11k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type);
+       if (!regd) {
+               ath11k_warn(ab, "failed to build regd from reg_info\n");
+               goto fallback;
+       }
+
+       if (power_type == IEEE80211_REG_UNSET_AP) {
+               ath11k_reg_reset_info(&ab->reg_info_store[pdev_idx]);
+               ab->reg_info_store[pdev_idx] = *reg_info;
+       }
+
+       spin_lock_bh(&ab->base_lock);
+       if (ab->default_regd[pdev_idx]) {
+               /* The initial rules from FW after WMI Init is to build
+                * the default regd. From then on, any rules updated for
+                * the pdev could be due to user reg changes.
+                * Free previously built regd before assigning the newly
+                * generated regd to ar. NULL pointer handling will be
+                * taken care by kfree itself.
+                */
+               ar = ab->pdevs[pdev_idx].ar;
+               kfree(ab->new_regd[pdev_idx]);
+               ab->new_regd[pdev_idx] = regd;
+               queue_work(ab->workqueue, &ar->regd_update_work);
+       } else {
+               /* This regd would be applied during mac registration and is
+                * held constant throughout for regd intersection purpose
+                */
+               ab->default_regd[pdev_idx] = regd;
+       }
+       ab->dfs_region = reg_info->dfs_region;
+       spin_unlock_bh(&ab->base_lock);
+
+       return 0;
+
+fallback:
+       /* Fallback to older reg (by sending previous country setting
+        * again if fw has succeeded and we failed to process here.
+        * The Regdomain should be uniform across driver and fw. Since the
+        * FW has processed the command and sent a success status, we expect
+        * this function to succeed as well. If it doesn't, CTRY needs to be
+        * reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent.
+        */
+       /* TODO: This is rare, but still should also be handled */
+       WARN_ON(1);
+
+retfail:
+
+       return -EINVAL;
+}
+
 void ath11k_regd_update_work(struct work_struct *work)
 {
        struct ath11k *ar = container_of(work, struct ath11k,
@@ -781,10 +982,36 @@ void ath11k_reg_init(struct ath11k *ar)
        ar->hw->wiphy->reg_notifier = ath11k_reg_notifier;
 }
 
+void ath11k_reg_reset_info(struct cur_regulatory_info *reg_info)
+{
+       int i, j;
+
+       if (!reg_info)
+               return;
+
+       kfree(reg_info->reg_rules_2ghz_ptr);
+       kfree(reg_info->reg_rules_5ghz_ptr);
+
+       for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
+               kfree(reg_info->reg_rules_6ghz_ap_ptr[i]);
+
+               for (j = 0; j < WMI_REG_MAX_CLIENT_TYPE; j++)
+                       kfree(reg_info->reg_rules_6ghz_client_ptr[i][j]);
+       }
+
+       memset(reg_info, 0, sizeof(*reg_info));
+}
+
 void ath11k_reg_free(struct ath11k_base *ab)
 {
        int i;
 
+       for (i = 0; i < ab->num_radios; i++)
+               ath11k_reg_reset_info(&ab->reg_info_store[i]);
+
+       kfree(ab->reg_info_store);
+       ab->reg_info_store = NULL;
+
        for (i = 0; i < ab->hw_params.max_radios; i++) {
                kfree(ab->default_regd[i]);
                kfree(ab->new_regd[i]);
index f28902f85e4196709a5d976303e36d1a008546af..64edb794260abcbe2d92eb4098d3b17712554ebe 100644 (file)
@@ -30,11 +30,20 @@ enum ath11k_dfs_region {
 
 /* ATH11K Regulatory API's */
 void ath11k_reg_init(struct ath11k *ar);
+void ath11k_reg_reset_info(struct cur_regulatory_info *reg_info);
 void ath11k_reg_free(struct ath11k_base *ab);
 void ath11k_regd_update_work(struct work_struct *work);
 struct ieee80211_regdomain *
 ath11k_reg_build_regd(struct ath11k_base *ab,
-                     struct cur_regulatory_info *reg_info, bool intersect);
+                     struct cur_regulatory_info *reg_info, bool intersect,
+                     enum wmi_vdev_type vdev_type,
+                     enum ieee80211_ap_reg_power power_type);
 int ath11k_regd_update(struct ath11k *ar);
 int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait);
+enum wmi_reg_6ghz_ap_type
+ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type);
+int ath11k_reg_handle_chan_list(struct ath11k_base *ab,
+                               struct cur_regulatory_info *reg_info,
+                               enum ieee80211_ap_reg_power power_type);
+
 #endif
index 43bb23265d3466af5a57aa9e07d910a0c3969ebe..302d66092b973d5d2cda5cc29c4a7bfa831902db 100644 (file)
@@ -198,7 +198,7 @@ static void ath11k_tm_wmi_event_segmented(struct ath11k_base *ab, u32 cmd_id,
        u16 length;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse ftm event tlv: %d\n", ret);
index 8a65fa04b48d98c6307632cd8c764e954ac0f60e..688ee20528a05d4f6955d2a4ccb62acbf0115c0c 100644 (file)
@@ -238,8 +238,8 @@ static int ath11k_wmi_tlv_parse(struct ath11k_base *ar, const void **tb,
                                   (void *)tb);
 }
 
-const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
-                                       size_t len, gfp_t gfp)
+const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab,
+                                       struct sk_buff *skb, gfp_t gfp)
 {
        const void **tb;
        int ret;
@@ -248,7 +248,7 @@ const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
        if (!tb)
                return ERR_PTR(-ENOMEM);
 
-       ret = ath11k_wmi_tlv_parse(ab, tb, ptr, len);
+       ret = ath11k_wmi_tlv_parse(ab, tb, skb->data, skb->len);
        if (ret) {
                kfree(tb);
                return ERR_PTR(ret);
@@ -2379,6 +2379,70 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
        return ret;
 }
 
+int ath11k_wmi_send_vdev_set_tpc_power(struct ath11k *ar,
+                                      u32 vdev_id,
+                                      struct ath11k_reg_tpc_power_info *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_vdev_set_tpc_power_cmd *cmd;
+       struct wmi_vdev_ch_power_info *ch;
+       struct sk_buff *skb;
+       struct wmi_tlv *tlv;
+       u8 *ptr;
+       int i, ret, len, array_len;
+
+       array_len = sizeof(*ch) * param->num_pwr_levels;
+       len = sizeof(*cmd) + TLV_HDR_SIZE + array_len;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
+       if (!skb)
+               return -ENOMEM;
+
+       ptr = skb->data;
+
+       cmd = (struct wmi_vdev_set_tpc_power_cmd *)ptr;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_SET_TPC_POWER_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       cmd->psd_power = param->is_psd_power;
+       cmd->eirp_power = param->eirp_power;
+       cmd->power_type_6ghz = param->ap_power_type;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "tpc vdev id %d is psd power %d eirp power %d 6 ghz power type %d\n",
+                  vdev_id, param->is_psd_power, param->eirp_power, param->ap_power_type);
+
+       ptr += sizeof(*cmd);
+       tlv = (struct wmi_tlv *)ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+                     FIELD_PREP(WMI_TLV_LEN, array_len);
+
+       ptr += TLV_HDR_SIZE;
+       ch = (struct wmi_vdev_ch_power_info *)ptr;
+
+       for (i = 0; i < param->num_pwr_levels; i++, ch++) {
+               ch->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                           WMI_TAG_VDEV_CH_POWER_INFO) |
+                               FIELD_PREP(WMI_TLV_LEN,
+                                          sizeof(*ch) - TLV_HDR_SIZE);
+
+               ch->chan_cfreq = param->chan_power_info[i].chan_cfreq;
+               ch->tx_power = param->chan_power_info[i].tx_power;
+
+               ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tpc chan freq %d TX power %d\n",
+                          ch->chan_cfreq, ch->tx_power);
+       }
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_SET_TPC_POWER_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_VDEV_SET_TPC_POWER_CMDID\n");
+               dev_kfree_skb(skb);
+               return ret;
+       }
+
+       return 0;
+}
+
 int ath11k_wmi_send_scan_stop_cmd(struct ath11k *ar,
                                  struct scan_cancel_param *param)
 {
@@ -3930,7 +3994,7 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk
        struct ath11k_vif *arvif;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -4749,6 +4813,14 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc,
                soc->pdevs[0].pdev_id = 0;
        }
 
+       if (!soc->reg_info_store) {
+               soc->reg_info_store = kcalloc(soc->num_radios,
+                                             sizeof(*soc->reg_info_store),
+                                             GFP_ATOMIC);
+               if (!soc->reg_info_store)
+                       return -ENOMEM;
+       }
+
        return 0;
 }
 
@@ -5003,7 +5075,7 @@ static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buf
        const struct wmi_vdev_start_resp_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5028,6 +5100,7 @@ static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buf
        vdev_rsp->mac_id = ev->mac_id;
        vdev_rsp->cfgd_tx_streams = ev->cfgd_tx_streams;
        vdev_rsp->cfgd_rx_streams = ev->cfgd_rx_streams;
+       vdev_rsp->max_allowed_tx_power = ev->max_allowed_tx_power;
 
        kfree(tb);
        return 0;
@@ -5102,7 +5175,7 @@ static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab,
 
        ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory channel list\n");
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5278,7 +5351,7 @@ static int ath11k_pull_reg_chan_list_ext_update_ev(struct ath11k_base *ab,
 
        ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory ext channel list\n");
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5634,7 +5707,7 @@ static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff *
        const struct wmi_peer_delete_resp_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5666,7 +5739,7 @@ static int ath11k_pull_vdev_del_resp_ev(struct ath11k_base *ab,
        const struct wmi_vdev_delete_resp_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5686,15 +5759,15 @@ static int ath11k_pull_vdev_del_resp_ev(struct ath11k_base *ab,
        return 0;
 }
 
-static int ath11k_pull_bcn_tx_status_ev(struct ath11k_base *ab, void *evt_buf,
-                                       u32 len, u32 *vdev_id,
-                                       u32 *tx_status)
+static int ath11k_pull_bcn_tx_status_ev(struct ath11k_base *ab,
+                                       struct sk_buff *skb,
+                                       u32 *vdev_id, u32 *tx_status)
 {
        const void **tb;
        const struct wmi_bcn_tx_status_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5722,7 +5795,7 @@ static int ath11k_pull_vdev_stopped_param_tlv(struct ath11k_base *ab, struct sk_
        const struct wmi_vdev_stopped_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5876,7 +5949,7 @@ static int ath11k_pull_mgmt_tx_compl_param_tlv(struct ath11k_base *ab,
        const struct wmi_mgmt_tx_compl_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6052,7 +6125,7 @@ static int ath11k_pull_scan_ev(struct ath11k_base *ab, struct sk_buff *skb,
        const struct wmi_scan_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6085,7 +6158,7 @@ static int ath11k_pull_peer_sta_kickout_ev(struct ath11k_base *ab, struct sk_buf
        const struct wmi_peer_sta_kickout_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6112,7 +6185,7 @@ static int ath11k_pull_roam_ev(struct ath11k_base *ab, struct sk_buff *skb,
        const struct wmi_roam_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6153,14 +6226,14 @@ exit:
        return idx;
 }
 
-static int ath11k_pull_chan_info_ev(struct ath11k_base *ab, u8 *evt_buf,
-                                   u32 len, struct wmi_chan_info_event *ch_info_ev)
+static int ath11k_pull_chan_info_ev(struct ath11k_base *ab, struct sk_buff *skb,
+                                   struct wmi_chan_info_event *ch_info_ev)
 {
        const void **tb;
        const struct wmi_chan_info_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6199,7 +6272,7 @@ ath11k_pull_pdev_bss_chan_info_ev(struct ath11k_base *ab, struct sk_buff *skb,
        const struct wmi_pdev_bss_chan_info_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6239,7 +6312,7 @@ ath11k_pull_vdev_install_key_compl_ev(struct ath11k_base *ab, struct sk_buff *sk
        const struct wmi_vdev_install_key_compl_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6270,7 +6343,7 @@ static int ath11k_pull_peer_assoc_conf_ev(struct ath11k_base *ab, struct sk_buff
        const struct wmi_peer_assoc_conf_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6995,7 +7068,7 @@ static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *s
        const void **tb;
        int ret, i;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -7060,32 +7133,15 @@ static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab,
                wake_up(&wmi->tx_ce_desc_wq);
 }
 
-static bool ath11k_reg_is_world_alpha(char *alpha)
-{
-       if (alpha[0] == '0' && alpha[1] == '0')
-               return true;
-
-       if (alpha[0] == 'n' && alpha[1] == 'a')
-               return true;
-
-       return false;
-}
-
-static int ath11k_reg_chan_list_event(struct ath11k_base *ab,
-                                     struct sk_buff *skb,
+static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb,
                                      enum wmi_reg_chan_list_cmd_type id)
 {
-       struct cur_regulatory_info *reg_info = NULL;
-       struct ieee80211_regdomain *regd = NULL;
-       bool intersect = false;
-       int ret = 0, pdev_idx, i, j;
-       struct ath11k *ar;
+       struct cur_regulatory_info *reg_info;
+       int ret;
 
        reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
-       if (!reg_info) {
-               ret = -ENOMEM;
-               goto fallback;
-       }
+       if (!reg_info)
+               return -ENOMEM;
 
        if (id == WMI_REG_CHAN_LIST_CC_ID)
                ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info);
@@ -7093,118 +7149,22 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab,
                ret = ath11k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info);
 
        if (ret) {
-               ath11k_warn(ab, "failed to extract regulatory info from received event\n");
-               goto fallback;
-       }
-
-       ath11k_dbg(ab, ATH11K_DBG_WMI, "event reg chan list id %d", id);
-
-       if (reg_info->status_code != REG_SET_CC_STATUS_PASS) {
-               /* In case of failure to set the requested ctry,
-                * fw retains the current regd. We print a failure info
-                * and return from here.
-                */
-               ath11k_warn(ab, "Failed to set the requested Country regulatory setting\n");
-               goto mem_free;
-       }
-
-       pdev_idx = reg_info->phy_id;
-
-       /* Avoid default reg rule updates sent during FW recovery if
-        * it is already available
-        */
-       spin_lock(&ab->base_lock);
-       if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags) &&
-           ab->default_regd[pdev_idx]) {
-               spin_unlock(&ab->base_lock);
+               ath11k_warn(ab, "failed to extract regulatory info\n");
                goto mem_free;
        }
-       spin_unlock(&ab->base_lock);
 
-       if (pdev_idx >= ab->num_radios) {
-               /* Process the event for phy0 only if single_pdev_only
-                * is true. If pdev_idx is valid but not 0, discard the
-                * event. Otherwise, it goes to fallback.
-                */
-               if (ab->hw_params.single_pdev_only &&
-                   pdev_idx < ab->hw_params.num_rxmda_per_pdev)
-                       goto mem_free;
-               else
-                       goto fallback;
-       }
-
-       /* Avoid multiple overwrites to default regd, during core
-        * stop-start after mac registration.
-        */
-       if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] &&
-           !memcmp((char *)ab->default_regd[pdev_idx]->alpha2,
-                   (char *)reg_info->alpha2, 2))
+       ret = ath11k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_UNSET_AP);
+       if (ret) {
+               ath11k_warn(ab, "failed to process regulatory info %d\n", ret);
                goto mem_free;
-
-       /* Intersect new rules with default regd if a new country setting was
-        * requested, i.e a default regd was already set during initialization
-        * and the regd coming from this event has a valid country info.
-        */
-       if (ab->default_regd[pdev_idx] &&
-           !ath11k_reg_is_world_alpha((char *)
-               ab->default_regd[pdev_idx]->alpha2) &&
-           !ath11k_reg_is_world_alpha((char *)reg_info->alpha2))
-               intersect = true;
-
-       regd = ath11k_reg_build_regd(ab, reg_info, intersect);
-       if (!regd) {
-               ath11k_warn(ab, "failed to build regd from reg_info\n");
-               goto fallback;
-       }
-
-       spin_lock(&ab->base_lock);
-       if (ab->default_regd[pdev_idx]) {
-               /* The initial rules from FW after WMI Init is to build
-                * the default regd. From then on, any rules updated for
-                * the pdev could be due to user reg changes.
-                * Free previously built regd before assigning the newly
-                * generated regd to ar. NULL pointer handling will be
-                * taken care by kfree itself.
-                */
-               ar = ab->pdevs[pdev_idx].ar;
-               kfree(ab->new_regd[pdev_idx]);
-               ab->new_regd[pdev_idx] = regd;
-               queue_work(ab->workqueue, &ar->regd_update_work);
-       } else {
-               /* This regd would be applied during mac registration and is
-                * held constant throughout for regd intersection purpose
-                */
-               ab->default_regd[pdev_idx] = regd;
        }
-       ab->dfs_region = reg_info->dfs_region;
-       spin_unlock(&ab->base_lock);
 
-       goto mem_free;
+       kfree(reg_info);
+       return 0;
 
-fallback:
-       /* Fallback to older reg (by sending previous country setting
-        * again if fw has succeeded and we failed to process here.
-        * The Regdomain should be uniform across driver and fw. Since the
-        * FW has processed the command and sent a success status, we expect
-        * this function to succeed as well. If it doesn't, CTRY needs to be
-        * reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent.
-        */
-       /* TODO: This is rare, but still should also be handled */
-       WARN_ON(1);
 mem_free:
-       if (reg_info) {
-               kfree(reg_info->reg_rules_2ghz_ptr);
-               kfree(reg_info->reg_rules_5ghz_ptr);
-               if (reg_info->is_ext_reg_event) {
-                       for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++)
-                               kfree(reg_info->reg_rules_6ghz_ap_ptr[i]);
-
-                       for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++)
-                               for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++)
-                                       kfree(reg_info->reg_rules_6ghz_client_ptr[j][i]);
-               }
-               kfree(reg_info);
-       }
+       ath11k_reg_reset_info(reg_info);
+       kfree(reg_info);
        return ret;
 }
 
@@ -7362,7 +7322,7 @@ static void ath11k_vdev_start_resp_event(struct ath11k_base *ab, struct sk_buff
        }
 
        ar->last_wmi_vdev_start_status = 0;
-
+       ar->max_allowed_tx_power = vdev_start_resp.max_allowed_tx_power;
        status = vdev_start_resp.status;
 
        if (WARN_ON_ONCE(status)) {
@@ -7384,8 +7344,7 @@ static void ath11k_bcn_tx_status_event(struct ath11k_base *ab, struct sk_buff *s
        struct ath11k_vif *arvif;
        u32 vdev_id, tx_status;
 
-       if (ath11k_pull_bcn_tx_status_ev(ab, skb->data, skb->len,
-                                        &vdev_id, &tx_status) != 0) {
+       if (ath11k_pull_bcn_tx_status_ev(ab, skb, &vdev_id, &tx_status) != 0) {
                ath11k_warn(ab, "failed to extract bcn tx status");
                return;
        }
@@ -7416,7 +7375,7 @@ static void ath11k_wmi_event_peer_sta_ps_state_chg(struct ath11k_base *ab,
        enum ath11k_wmi_peer_ps_state peer_previous_ps_state;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -7884,7 +7843,7 @@ static void ath11k_chan_info_event(struct ath11k_base *ab, struct sk_buff *skb)
        /* HW channel counters frequency value in hertz */
        u32 cc_freq_hz = ab->cc_freq_hz;
 
-       if (ath11k_pull_chan_info_ev(ab, skb->data, skb->len, &ch_info_ev) != 0) {
+       if (ath11k_pull_chan_info_ev(ab, skb, &ch_info_ev) != 0) {
                ath11k_warn(ab, "failed to extract chan info event");
                return;
        }
@@ -8216,7 +8175,7 @@ static void ath11k_pdev_ctl_failsafe_check_event(struct ath11k_base *ab,
        const struct wmi_pdev_ctl_failsafe_chk_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -8281,7 +8240,7 @@ ath11k_wmi_pdev_csa_switch_count_status_event(struct ath11k_base *ab,
        const u32 *vdev_ids;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -8315,7 +8274,7 @@ ath11k_wmi_pdev_dfs_radar_detected_event(struct ath11k_base *ab, struct sk_buff
        struct ath11k *ar;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -8369,7 +8328,7 @@ ath11k_wmi_pdev_temperature_event(struct ath11k_base *ab,
        const struct wmi_pdev_temperature_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -8409,7 +8368,7 @@ static void ath11k_fils_discovery_event(struct ath11k_base *ab,
        const struct wmi_fils_discovery_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab,
@@ -8441,7 +8400,7 @@ static void ath11k_probe_resp_tx_status_event(struct ath11k_base *ab,
        const struct wmi_probe_resp_tx_status_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab,
@@ -8567,7 +8526,7 @@ static void ath11k_wmi_twt_add_dialog_event(struct ath11k_base *ab,
        const struct wmi_twt_add_dialog_event *ev;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab,
@@ -8604,7 +8563,7 @@ static void ath11k_wmi_gtk_offload_status_event(struct ath11k_base *ab,
        u64    replay_ctr;
        int ret;
 
-       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -9793,3 +9752,9 @@ int ath11k_wmi_sta_keepalive(struct ath11k *ar,
 
        return ath11k_wmi_cmd_send(wmi, skb, WMI_STA_KEEPALIVE_CMDID);
 }
+
+bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar)
+{
+       return test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT,
+                       ar->ab->wmi_ab.svc_map) && ar->supports_6ghz;
+}
index ff0a9a92beeb037e775db0d5dcdbfc3b1d56aba0..6dcd147005708893d6dacb29f743622e03c0acfb 100644 (file)
@@ -15,6 +15,7 @@ struct ath11k;
 struct ath11k_fw_stats;
 struct ath11k_fw_dbglog;
 struct ath11k_vif;
+struct ath11k_reg_tpc_power_info;
 
 #define PSOC_HOST_MAX_NUM_SS (8)
 
@@ -327,6 +328,22 @@ enum wmi_tlv_cmd_id {
        WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID,
        WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID,
        WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID,
+       WMI_VDEV_SET_ARP_STAT_CMDID,
+       WMI_VDEV_GET_ARP_STAT_CMDID,
+       WMI_VDEV_GET_TX_POWER_CMDID,
+       WMI_VDEV_LIMIT_OFFCHAN_CMDID,
+       WMI_VDEV_SET_CUSTOM_SW_RETRY_TH_CMDID,
+       WMI_VDEV_CHAINMASK_CONFIG_CMDID,
+       WMI_VDEV_GET_BCN_RECEPTION_STATS_CMDID,
+       WMI_VDEV_GET_MWS_COEX_INFO_CMDID,
+       WMI_VDEV_DELETE_ALL_PEER_CMDID,
+       WMI_VDEV_BSS_MAX_IDLE_TIME_CMDID,
+       WMI_VDEV_AUDIO_SYNC_TRIGGER_CMDID,
+       WMI_VDEV_AUDIO_SYNC_QTIMER_CMDID,
+       WMI_VDEV_SET_PCL_CMDID,
+       WMI_VDEV_GET_BIG_DATA_CMDID,
+       WMI_VDEV_GET_BIG_DATA_P2_CMDID,
+       WMI_VDEV_SET_TPC_POWER_CMDID,
        WMI_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_PEER),
        WMI_PEER_DELETE_CMDID,
        WMI_PEER_FLUSH_TIDS_CMDID,
@@ -1880,6 +1897,8 @@ enum wmi_tlv_tag {
        WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
        WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
        WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
+       WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5,
+       WMI_TAG_VDEV_CH_POWER_INFO,
        WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8,
        WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD,
        WMI_TAG_MAX
@@ -2114,6 +2133,7 @@ enum wmi_tlv_service {
        /* The second 128 bits */
        WMI_MAX_EXT_SERVICE = 256,
        WMI_TLV_SERVICE_SCAN_CONFIG_PER_CHANNEL = 265,
+       WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT = 280,
        WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281,
        WMI_TLV_SERVICE_BIOS_SAR_SUPPORT = 326,
        WMI_TLV_SERVICE_SUPPORT_11D_FOR_HOST_SCAN = 357,
@@ -3168,6 +3188,41 @@ struct wlan_ssid {
        u8 ssid[WLAN_SSID_MAX_LEN];
 };
 
+struct wmi_vdev_ch_power_info {
+       u32 tlv_header;
+
+       /* Channel center frequency (MHz) */
+       u32 chan_cfreq;
+
+       /* Unit: dBm, either PSD/EIRP power for this frequency or
+        * incremental for non-PSD BW
+        */
+       u32 tx_power;
+} __packed;
+
+struct wmi_vdev_set_tpc_power_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+
+       /* Value: 0 or 1, is PSD power or not */
+       u32 psd_power;
+
+        /* Maximum EIRP power (dBm units), valid only if power is PSD */
+       u32 eirp_power;
+
+       /* Type: WMI_6GHZ_REG_TYPE, used for halphy CTL lookup */
+       u32 power_type_6ghz;
+
+       /* This fixed_param TLV is followed by the below TLVs:
+        * num_pwr_levels of wmi_vdev_ch_power_info
+        * For PSD power, it is the PSD/EIRP power of the frequency (20 MHz chunks).
+        * For non-PSD power, the power values are for 20, 40, and till
+        * BSS BW power levels.
+        * The num_pwr_levels will be checked by sw how many elements present
+        * in the variable-length array.
+        */
+} __packed;
+
 #define WMI_IE_BITMAP_SIZE             8
 
 /* prefix used by scan requestor ids on the host */
@@ -4119,6 +4174,7 @@ struct wmi_vdev_start_resp_event {
        };
        u32 cfgd_tx_streams;
        u32 cfgd_rx_streams;
+       s32 max_allowed_tx_power;
 } __packed;
 
 /* VDEV start response status codes */
@@ -4951,6 +5007,7 @@ struct ath11k_targ_cap {
 };
 
 enum wmi_vdev_type {
+       WMI_VDEV_TYPE_UNSPEC =  0,
        WMI_VDEV_TYPE_AP      = 1,
        WMI_VDEV_TYPE_STA     = 2,
        WMI_VDEV_TYPE_IBSS    = 3,
@@ -6295,8 +6352,8 @@ enum wmi_sta_keepalive_method {
 #define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT     30
 #define WMI_STA_KEEPALIVE_INTERVAL_DISABLE     0
 
-const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
-                                       size_t len, gfp_t gfp);
+const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab,
+                                       struct sk_buff *skb, gfp_t gfp);
 int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
                        u32 cmd_id);
 struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len);
@@ -6479,5 +6536,9 @@ int ath11k_wmi_pdev_set_bios_sar_table_param(struct ath11k *ar, const u8 *sar_va
 int ath11k_wmi_pdev_set_bios_geo_table_param(struct ath11k *ar);
 int ath11k_wmi_sta_keepalive(struct ath11k *ar,
                             const struct wmi_sta_keepalive_arg *arg);
+bool ath11k_wmi_supports_6ghz_cc_ext(struct ath11k *ar);
+int ath11k_wmi_send_vdev_set_tpc_power(struct ath11k *ar,
+                                      u32 vdev_id,
+                                      struct ath11k_reg_tpc_power_info *param);
 
 #endif
index 6c01b282fcd330a73c8b3c9635b135e65cd4abc0..1baad3302157caf0f551041e49c9e02c043574d8 100644 (file)
@@ -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.
  */
 
 #include <linux/module.h>
@@ -104,27 +104,66 @@ int ath12k_core_resume(struct ath12k_base *ab)
        return 0;
 }
 
-static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
-                                        size_t name_len)
+static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
+                                          size_t name_len, bool with_variant,
+                                          bool bus_type_mode)
 {
        /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */
        char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 };
 
-       if (ab->qmi.target.bdf_ext[0] != '\0')
+       if (with_variant && ab->qmi.target.bdf_ext[0] != '\0')
                scnprintf(variant, sizeof(variant), ",variant=%s",
                          ab->qmi.target.bdf_ext);
 
-       scnprintf(name, name_len,
-                 "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s",
-                 ath12k_bus_str(ab->hif.bus),
-                 ab->qmi.target.chip_id,
-                 ab->qmi.target.board_id, variant);
+       switch (ab->id.bdf_search) {
+       case ATH12K_BDF_SEARCH_BUS_AND_BOARD:
+               if (bus_type_mode)
+                       scnprintf(name, name_len,
+                                 "bus=%s",
+                                 ath12k_bus_str(ab->hif.bus));
+               else
+                       scnprintf(name, name_len,
+                                 "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s",
+                                 ath12k_bus_str(ab->hif.bus),
+                                 ab->id.vendor, ab->id.device,
+                                 ab->id.subsystem_vendor,
+                                 ab->id.subsystem_device,
+                                 ab->qmi.target.chip_id,
+                                 ab->qmi.target.board_id,
+                                 variant);
+               break;
+       default:
+               scnprintf(name, name_len,
+                         "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s",
+                         ath12k_bus_str(ab->hif.bus),
+                         ab->qmi.target.chip_id,
+                         ab->qmi.target.board_id, variant);
+               break;
+       }
 
        ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot using board name '%s'\n", name);
 
        return 0;
 }
 
+static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
+                                        size_t name_len)
+{
+       return __ath12k_core_create_board_name(ab, name, name_len, true, false);
+}
+
+static int ath12k_core_create_fallback_board_name(struct ath12k_base *ab, char *name,
+                                                 size_t name_len)
+{
+       return __ath12k_core_create_board_name(ab, name, name_len, false, false);
+}
+
+static int ath12k_core_create_bus_type_board_name(struct ath12k_base *ab, char *name,
+                                                 size_t name_len)
+{
+       return __ath12k_core_create_board_name(ab, name, name_len, false, true);
+}
+
 const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
                                                    const char *file)
 {
@@ -159,7 +198,9 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab,
                                         struct ath12k_board_data *bd,
                                         const void *buf, size_t buf_len,
                                         const char *boardname,
-                                        int bd_ie_type)
+                                        int ie_id,
+                                        int name_id,
+                                        int data_id)
 {
        const struct ath12k_fw_ie *hdr;
        bool name_match_found;
@@ -169,7 +210,7 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab,
 
        name_match_found = false;
 
-       /* go through ATH12K_BD_IE_BOARD_ elements */
+       /* go through ATH12K_BD_IE_BOARD_/ATH12K_BD_IE_REGDB_ elements */
        while (buf_len > sizeof(struct ath12k_fw_ie)) {
                hdr = buf;
                board_ie_id = le32_to_cpu(hdr->id);
@@ -180,48 +221,50 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab,
                buf += sizeof(*hdr);
 
                if (buf_len < ALIGN(board_ie_len, 4)) {
-                       ath12k_err(ab, "invalid ATH12K_BD_IE_BOARD length: %zu < %zu\n",
+                       ath12k_err(ab, "invalid %s length: %zu < %zu\n",
+                                  ath12k_bd_ie_type_str(ie_id),
                                   buf_len, ALIGN(board_ie_len, 4));
                        ret = -EINVAL;
                        goto out;
                }
 
-               switch (board_ie_id) {
-               case ATH12K_BD_IE_BOARD_NAME:
+               if (board_ie_id == name_id) {
                        ath12k_dbg_dump(ab, ATH12K_DBG_BOOT, "board name", "",
                                        board_ie_data, board_ie_len);
 
                        if (board_ie_len != strlen(boardname))
-                               break;
+                               goto next;
 
                        ret = memcmp(board_ie_data, boardname, strlen(boardname));
                        if (ret)
-                               break;
+                               goto next;
 
                        name_match_found = true;
                        ath12k_dbg(ab, ATH12K_DBG_BOOT,
-                                  "boot found match for name '%s'",
+                                  "boot found match %s for name '%s'",
+                                  ath12k_bd_ie_type_str(ie_id),
                                   boardname);
-                       break;
-               case ATH12K_BD_IE_BOARD_DATA:
+               } else if (board_ie_id == data_id) {
                        if (!name_match_found)
                                /* no match found */
-                               break;
+                               goto next;
 
                        ath12k_dbg(ab, ATH12K_DBG_BOOT,
-                                  "boot found board data for '%s'", boardname);
+                                  "boot found %s for '%s'",
+                                  ath12k_bd_ie_type_str(ie_id),
+                                  boardname);
 
                        bd->data = board_ie_data;
                        bd->len = board_ie_len;
 
                        ret = 0;
                        goto out;
-               default:
-                       ath12k_warn(ab, "unknown ATH12K_BD_IE_BOARD found: %d\n",
+               } else {
+                       ath12k_warn(ab, "unknown %s id found: %d\n",
+                                   ath12k_bd_ie_type_str(ie_id),
                                    board_ie_id);
-                       break;
                }
-
+next:
                /* jump over the padding */
                board_ie_len = ALIGN(board_ie_len, 4);
 
@@ -238,7 +281,10 @@ out:
 
 static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab,
                                              struct ath12k_board_data *bd,
-                                             const char *boardname)
+                                             const char *boardname,
+                                             int ie_id_match,
+                                             int name_id,
+                                             int data_id)
 {
        size_t len, magic_len;
        const u8 *data;
@@ -303,22 +349,23 @@ static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab,
                        goto err;
                }
 
-               switch (ie_id) {
-               case ATH12K_BD_IE_BOARD:
+               if (ie_id == ie_id_match) {
                        ret = ath12k_core_parse_bd_ie_board(ab, bd, data,
                                                            ie_len,
                                                            boardname,
-                                                           ATH12K_BD_IE_BOARD);
+                                                           ie_id_match,
+                                                           name_id,
+                                                           data_id);
                        if (ret == -ENOENT)
                                /* no match found, continue */
-                               break;
+                               goto next;
                        else if (ret)
                                /* there was an error, bail out */
                                goto err;
                        /* either found or error, so stop searching */
                        goto out;
                }
-
+next:
                /* jump over the padding */
                ie_len = ALIGN(ie_len, 4);
 
@@ -328,8 +375,9 @@ static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab,
 
 out:
        if (!bd->data || !bd->len) {
-               ath12k_err(ab,
-                          "failed to fetch board data for %s from %s\n",
+               ath12k_dbg(ab, ATH12K_DBG_BOOT,
+                          "failed to fetch %s for %s from %s\n",
+                          ath12k_bd_ie_type_str(ie_id_match),
                           boardname, filepath);
                ret = -ENODATA;
                goto err;
@@ -356,28 +404,56 @@ int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab,
        return 0;
 }
 
-#define BOARD_NAME_SIZE 100
+#define BOARD_NAME_SIZE 200
 int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd)
 {
-       char boardname[BOARD_NAME_SIZE];
+       char boardname[BOARD_NAME_SIZE], fallback_boardname[BOARD_NAME_SIZE];
+       char *filename, filepath[100];
        int bd_api;
        int ret;
 
-       ret = ath12k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE);
+       filename = ATH12K_BOARD_API2_FILE;
+
+       ret = ath12k_core_create_board_name(ab, boardname, sizeof(boardname));
        if (ret) {
                ath12k_err(ab, "failed to create board name: %d", ret);
                return ret;
        }
 
        bd_api = 2;
-       ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname);
+       ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname,
+                                                ATH12K_BD_IE_BOARD,
+                                                ATH12K_BD_IE_BOARD_NAME,
+                                                ATH12K_BD_IE_BOARD_DATA);
+       if (!ret)
+               goto success;
+
+       ret = ath12k_core_create_fallback_board_name(ab, fallback_boardname,
+                                                    sizeof(fallback_boardname));
+       if (ret) {
+               ath12k_err(ab, "failed to create fallback board name: %d", ret);
+               return ret;
+       }
+
+       ret = ath12k_core_fetch_board_data_api_n(ab, bd, fallback_boardname,
+                                                ATH12K_BD_IE_BOARD,
+                                                ATH12K_BD_IE_BOARD_NAME,
+                                                ATH12K_BD_IE_BOARD_DATA);
        if (!ret)
                goto success;
 
        bd_api = 1;
        ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_DEFAULT_BOARD_FILE);
        if (ret) {
-               ath12k_err(ab, "failed to fetch board-2.bin or board.bin from %s\n",
+               ath12k_core_create_firmware_path(ab, filename,
+                                                filepath, sizeof(filepath));
+               ath12k_err(ab, "failed to fetch board data for %s from %s\n",
+                          boardname, filepath);
+               if (memcmp(boardname, fallback_boardname, strlen(boardname)))
+                       ath12k_err(ab, "failed to fetch board data for %s from %s\n",
+                                  fallback_boardname, filepath);
+
+               ath12k_err(ab, "failed to fetch board.bin from %s\n",
                           ab->hw_params->fw.dir);
                return ret;
        }
@@ -387,6 +463,52 @@ success:
        return 0;
 }
 
+int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd)
+{
+       char boardname[BOARD_NAME_SIZE], default_boardname[BOARD_NAME_SIZE];
+       int ret;
+
+       ret = ath12k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE);
+       if (ret) {
+               ath12k_dbg(ab, ATH12K_DBG_BOOT,
+                          "failed to create board name for regdb: %d", ret);
+               goto exit;
+       }
+
+       ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname,
+                                                ATH12K_BD_IE_REGDB,
+                                                ATH12K_BD_IE_REGDB_NAME,
+                                                ATH12K_BD_IE_REGDB_DATA);
+       if (!ret)
+               goto exit;
+
+       ret = ath12k_core_create_bus_type_board_name(ab, default_boardname,
+                                                    BOARD_NAME_SIZE);
+       if (ret) {
+               ath12k_dbg(ab, ATH12K_DBG_BOOT,
+                          "failed to create default board name for regdb: %d", ret);
+               goto exit;
+       }
+
+       ret = ath12k_core_fetch_board_data_api_n(ab, bd, default_boardname,
+                                                ATH12K_BD_IE_REGDB,
+                                                ATH12K_BD_IE_REGDB_NAME,
+                                                ATH12K_BD_IE_REGDB_DATA);
+       if (!ret)
+               goto exit;
+
+       ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_REGDB_FILE_NAME);
+       if (ret)
+               ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to fetch %s from %s\n",
+                          ATH12K_REGDB_FILE_NAME, ab->hw_params->fw.dir);
+
+exit:
+       if (!ret)
+               ath12k_dbg(ab, ATH12K_DBG_BOOT, "fetched regdb\n");
+
+       return ret;
+}
+
 static void ath12k_core_stop(struct ath12k_base *ab)
 {
        if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
@@ -592,8 +714,6 @@ static int ath12k_core_start(struct ath12k_base *ab,
 
        ath12k_dp_cc_config(ab);
 
-       ath12k_dp_pdev_pre_alloc(ab);
-
        ret = ath12k_dp_rx_pdev_reo_setup(ab);
        if (ret) {
                ath12k_err(ab, "failed to initialize reo destination rings: %d\n", ret);
@@ -759,6 +879,7 @@ static void ath12k_rfkill_work(struct work_struct *work)
 {
        struct ath12k_base *ab = container_of(work, struct ath12k_base, rfkill_work);
        struct ath12k *ar;
+       struct ieee80211_hw *hw;
        bool rfkill_radio_on;
        int i;
 
@@ -771,8 +892,9 @@ static void ath12k_rfkill_work(struct work_struct *work)
                if (!ar)
                        continue;
 
+               hw = ath12k_ar_to_hw(ar);
                ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on);
-               wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on);
+               wiphy_rfkill_set_hw_state(hw->wiphy, !rfkill_radio_on);
        }
 }
 
@@ -801,6 +923,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
 {
        struct ath12k *ar;
        struct ath12k_pdev *pdev;
+       struct ath12k_hw *ah;
        int i;
 
        spin_lock_bh(&ab->base_lock);
@@ -810,13 +933,20 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
        if (ab->is_reset)
                set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags);
 
+       for (i = 0; i < ab->num_hw; i++) {
+               if (!ab->ah[i])
+                       continue;
+
+               ah = ab->ah[i];
+               ieee80211_stop_queues(ah->hw);
+       }
+
        for (i = 0; i < ab->num_radios; i++) {
                pdev = &ab->pdevs[i];
                ar = pdev->ar;
                if (!ar || ar->state == ATH12K_STATE_OFF)
                        continue;
 
-               ieee80211_stop_queues(ar->hw);
                ath12k_mac_drain_tx(ar);
                complete(&ar->scan.started);
                complete(&ar->scan.completed);
@@ -856,7 +986,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
                case ATH12K_STATE_ON:
                        ar->state = ATH12K_STATE_RESTARTING;
                        ath12k_core_halt(ar);
-                       ieee80211_restart_hw(ar->hw);
+                       ieee80211_restart_hw(ath12k_ar_to_hw(ar));
                        break;
                case ATH12K_STATE_OFF:
                        ath12k_warn(ab,
@@ -1054,6 +1184,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
 
        ab->dev = dev;
        ab->hif.bus = bus;
+       ab->qmi.num_radios = U8_MAX;
 
        return ab;
 
index 8458dc292821a3bdbfcfcd92365dab0f3ef734b9..5c6c1e2eddb6c28751159c29ba8e7cc6bccb597d 100644 (file)
@@ -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_CORE_H
 #define ATH12K_RECONFIGURE_TIMEOUT_HZ          (10 * HZ)
 #define ATH12K_RECOVER_START_TIMEOUT_HZ                (20 * HZ)
 
+enum ath12k_bdf_search {
+       ATH12K_BDF_SEARCH_DEFAULT,
+       ATH12K_BDF_SEARCH_BUS_AND_BOARD,
+};
+
 enum wme_ac {
        WME_AC_BE,
        WME_AC_BK,
@@ -420,7 +425,7 @@ struct ath12k_sta {
 };
 
 #define ATH12K_MIN_5G_FREQ 4150
-#define ATH12K_MIN_6G_FREQ 5945
+#define ATH12K_MIN_6G_FREQ 5925
 #define ATH12K_MAX_6G_FREQ 7115
 #define ATH12K_NUM_CHANS 100
 #define ATH12K_MAX_5G_CHAN 173
@@ -468,7 +473,7 @@ struct ath12k_per_peer_tx_stats {
 struct ath12k {
        struct ath12k_base *ab;
        struct ath12k_pdev *pdev;
-       struct ieee80211_hw *hw;
+       struct ath12k_hw *ah;
        struct ath12k_wmi_pdev *wmi;
        struct ath12k_pdev_dp dp;
        u8 mac_addr[ETH_ALEN];
@@ -532,6 +537,7 @@ struct ath12k {
        /* pdev_idx starts from 0 whereas pdev->pdev_id starts with 1 */
        u8 pdev_idx;
        u8 lmac_id;
+       u8 hw_link_id;
 
        struct completion peer_assoc_done;
        struct completion peer_delete_done;
@@ -591,6 +597,13 @@ struct ath12k {
        int monitor_vdev_id;
 };
 
+struct ath12k_hw {
+       struct ieee80211_hw *hw;
+
+       u8 num_radio;
+       struct ath12k radio[] __aligned(sizeof(void *));
+};
+
 struct ath12k_band_cap {
        u32 phy_id;
        u32 max_bw_supported;
@@ -724,6 +737,16 @@ struct ath12k_base {
        u8 fw_pdev_count;
 
        struct ath12k_pdev __rcu *pdevs_active[MAX_RADIOS];
+
+       /* Holds information of wiphy (hw) registration.
+        *
+        * In Multi/Single Link Operation case, all pdevs are registered as
+        * a single wiphy. In other (legacy/Non-MLO) cases, each pdev is
+        * registered as separate wiphys.
+        */
+       struct ath12k_hw *ah[MAX_RADIOS];
+       u8 num_hw;
+
        struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS];
        unsigned long long free_vdev_map;
        unsigned long long free_vdev_stats_id_map;
@@ -793,10 +816,23 @@ struct ath12k_base {
        /* true means radio is on */
        bool rfkill_radio_on;
 
+       struct {
+               enum ath12k_bdf_search bdf_search;
+               u32 vendor;
+               u32 device;
+               u32 subsystem_vendor;
+               u32 subsystem_device;
+       } id;
+
        /* must be last */
        u8 drv_priv[] __aligned(sizeof(void *));
 };
 
+struct ath12k_pdev_map {
+       struct ath12k_base *ab;
+       u8 pdev_idx;
+};
+
 int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab);
 int ath12k_core_pre_init(struct ath12k_base *ab);
 int ath12k_core_init(struct ath12k_base *ath12k);
@@ -810,6 +846,7 @@ int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab,
 int ath12k_core_fetch_bdf(struct ath12k_base *ath12k,
                          struct ath12k_board_data *bd);
 void ath12k_core_free_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd);
+int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd);
 int ath12k_core_check_dt(struct ath12k_base *ath12k);
 int ath12k_core_check_smbios(struct ath12k_base *ab);
 void ath12k_core_halt(struct ath12k *ar);
@@ -882,4 +919,18 @@ static inline const char *ath12k_bus_str(enum ath12k_bus bus)
        return "unknown";
 }
 
+static inline struct ath12k_hw *ath12k_hw_to_ah(struct ieee80211_hw  *hw)
+{
+       return hw->priv;
+}
+
+static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah)
+{
+       return ah->radio;
+}
+
+static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar)
+{
+       return ar->ah->hw;
+}
 #endif /* _CORE_H_ */
index 1df3cdd461400aec42207118b5a113f5f83a876a..0a10cd36235619bab6c81198ad22a5297de97efa 100644 (file)
@@ -150,7 +150,7 @@ struct ath12k_pdev_dp {
 
 #define DP_RX_HASH_ENABLE      1 /* Enable hash based Rx steering */
 
-#define DP_BA_WIN_SZ_MAX       256
+#define DP_BA_WIN_SZ_MAX       1024
 
 #define DP_TCL_NUM_RING_MAX    4
 
@@ -170,6 +170,7 @@ struct ath12k_pdev_dp {
 #define DP_REO_CMD_RING_SIZE           128
 #define DP_REO_STATUS_RING_SIZE                2048
 #define DP_RXDMA_BUF_RING_SIZE         4096
+#define DP_RX_MAC_BUF_RING_SIZE                2048
 #define DP_RXDMA_REFILL_RING_SIZE      2048
 #define DP_RXDMA_ERR_DST_RING_SIZE     1024
 #define DP_RXDMA_MON_STATUS_RING_SIZE  1024
index be4b39f5fa800100b483dd24760457339583b8ee..2432ab605c85c266c610629e48886250082a6a1e 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2019-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.
  */
 
 #include "dp_mon.h"
@@ -1130,7 +1130,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct
            !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED))
                rx_status->flag |= RX_FLAG_8023;
 
-       ieee80211_rx_napi(ar->hw, pubsta, msdu, napi);
+       ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi);
 }
 
 static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, u32 mac_id,
index 1ee83f7659293e80f5a2df523f2a6d3db999c4ea..a31c24b548517193baab28788c9125a73cb18888 100644 (file)
@@ -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.
  */
 
 #include <linux/ieee80211.h>
@@ -2458,7 +2458,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
            !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED))
                rx_status->flag |= RX_FLAG_8023;
 
-       ieee80211_rx_napi(ar->hw, pubsta, msdu, napi);
+       ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi);
 }
 
 static int ath12k_dp_rx_process_msdu(struct ath12k *ar,
@@ -2844,7 +2844,7 @@ mic_fail:
        ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs);
        ath12k_dp_rx_h_undecap(ar, msdu, rx_desc,
                               HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
-       ieee80211_rx(ar->hw, msdu);
+       ieee80211_rx(ath12k_ar_to_hw(ar), msdu);
        return -EINVAL;
 }
 
@@ -4086,7 +4086,7 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab)
                        ret = ath12k_dp_srng_setup(ab,
                                                   &dp->rx_mac_buf_ring[i],
                                                   HAL_RXDMA_BUF, 1,
-                                                  i, 1024);
+                                                  i, DP_RX_MAC_BUF_RING_SIZE);
                        if (ret) {
                                ath12k_warn(ab, "failed to setup rx_mac_buf_ring %d\n",
                                            i);
index 62f9cdbb811c0264bad69f220ce5741c85a34d54..d4db94112debc3950c0885861e41541c43219214 100644 (file)
@@ -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.
  */
 
 #include "core.h"
@@ -151,7 +151,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif,
 
        if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
            !ieee80211_is_data(hdr->frame_control))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1);
 
@@ -401,7 +401,7 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab,
                }
        }
 
-       ieee80211_tx_status_skb(ar->hw, msdu);
+       ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu);
 }
 
 static void
@@ -498,7 +498,7 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar,
         * Might end up reporting it out-of-band from HTT stats.
         */
 
-       ieee80211_tx_status_skb(ar->hw, msdu);
+       ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu);
 
 exit:
        rcu_read_unlock();
@@ -837,7 +837,7 @@ int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab)
        if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) {
                ath12k_err(ab, "unsupported htt major version %d supported version is %d\n",
                           dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR);
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
 
        return 0;
index 6c17adc6d60b563f5c745a7be6f45c88991333d1..63340256d3f64ef20c7759d0d2958477315a9b26 100644 (file)
@@ -2500,13 +2500,13 @@ struct hal_rx_reo_queue {
 #define HAL_REO_UPD_RX_QUEUE_INFO1_PN_HANDLE_ENABLE            BIT(30)
 #define HAL_REO_UPD_RX_QUEUE_INFO1_IGNORE_AMPDU_FLG            BIT(31)
 
-#define HAL_REO_UPD_RX_QUEUE_INFO2_BA_WINDOW_SIZE              GENMASK(7, 0)
-#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_SIZE                     GENMASK(9, 8)
-#define HAL_REO_UPD_RX_QUEUE_INFO2_SVLD                                BIT(10)
-#define HAL_REO_UPD_RX_QUEUE_INFO2_SSN                         GENMASK(22, 11)
-#define HAL_REO_UPD_RX_QUEUE_INFO2_SEQ_2K_ERR                  BIT(23)
-#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR                      BIT(24)
-#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_VALID                    BIT(25)
+#define HAL_REO_UPD_RX_QUEUE_INFO2_BA_WINDOW_SIZE              GENMASK(9, 0)
+#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_SIZE                     GENMASK(11, 10)
+#define HAL_REO_UPD_RX_QUEUE_INFO2_SVLD                                BIT(12)
+#define HAL_REO_UPD_RX_QUEUE_INFO2_SSN                         GENMASK(24, 13)
+#define HAL_REO_UPD_RX_QUEUE_INFO2_SEQ_2K_ERR                  BIT(25)
+#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR                      BIT(26)
+#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_VALID                    BIT(27)
 
 struct hal_reo_update_rx_queue {
        struct hal_reo_cmd_hdr cmd;
@@ -2517,6 +2517,12 @@ struct hal_reo_update_rx_queue {
        __le32 pn[4];
 } __packed;
 
+struct hal_rx_reo_queue_1k {
+       struct hal_desc_header desc_hdr;
+       __le32 rx_bitmap_1023_288[23];
+       __le32 reserved[8];
+} __packed;
+
 #define HAL_REO_UNBLOCK_CACHE_INFO0_UNBLK_CACHE                BIT(0)
 #define HAL_REO_UNBLOCK_CACHE_INFO0_RESOURCE_IDX       GENMASK(2, 1)
 
index 4f25eb9f774538581d0bb9016294643d332d656b..f7c1aaa3b5d47fe766be8e83c3bdf714ba099c9a 100644 (file)
@@ -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.
  */
 
 #include "debug.h"
@@ -247,7 +247,7 @@ int ath12k_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng,
        case HAL_REO_CMD_UNBLOCK_CACHE:
        case HAL_REO_CMD_FLUSH_TIMEOUT_LIST:
                ath12k_warn(ab, "Unsupported reo command %d\n", type);
-               ret = -ENOTSUPP;
+               ret = -EOPNOTSUPP;
                break;
        default:
                ath12k_warn(ab, "Unknown reo command %d\n", type);
@@ -688,23 +688,28 @@ void ath12k_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab,
 
 u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid)
 {
-       u32 num_ext_desc;
+       u32 num_ext_desc, num_1k_desc = 0;
 
        if (ba_window_size <= 1) {
                if (tid != HAL_DESC_REO_NON_QOS_TID)
                        num_ext_desc = 1;
                else
                        num_ext_desc = 0;
+
        } else if (ba_window_size <= 105) {
                num_ext_desc = 1;
        } else if (ba_window_size <= 210) {
                num_ext_desc = 2;
-       } else {
+       } else if (ba_window_size <= 256) {
                num_ext_desc = 3;
+       } else {
+               num_ext_desc = 10;
+               num_1k_desc = 1;
        }
 
        return sizeof(struct hal_rx_reo_queue) +
-               (num_ext_desc * sizeof(struct hal_rx_reo_queue_ext));
+               (num_ext_desc * sizeof(struct hal_rx_reo_queue_ext)) +
+               (num_1k_desc * sizeof(struct hal_rx_reo_queue_1k));
 }
 
 void ath12k_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc,
index de60d988d8608f0ec2525d8bfb467886a7b099e8..cbb6e2b6d8264e577d4bbd81d664d6694d505121 100644 (file)
@@ -914,6 +914,9 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
                .rfkill_on_level = 0,
 
                .rddm_size = 0,
+
+               .def_num_link = 0,
+               .max_mlo_peer = 256,
        },
        {
                .name = "wcn7850 hw2.0",
@@ -978,6 +981,9 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
                .rfkill_on_level = 1,
 
                .rddm_size = 0x780000,
+
+               .def_num_link = 2,
+               .max_mlo_peer = 32,
        },
        {
                .name = "qcn9274 hw2.0",
@@ -1040,6 +1046,9 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
                .rfkill_on_level = 0,
 
                .rddm_size = 0,
+
+               .def_num_link = 0,
+               .max_mlo_peer = 256,
        },
 };
 
index d2622bfef94226447f7d0d4485238681c5307442..0c3b416ae150f45262ced488f6f7c2f9be41fb0e 100644 (file)
@@ -192,6 +192,9 @@ struct ath12k_hw_params {
        u32 rfkill_on_level;
 
        u32 rddm_size;
+
+       u8 def_num_link;
+       u16 max_mlo_peer;
 };
 
 struct ath12k_hw_ops {
@@ -242,10 +245,16 @@ enum ath12k_bd_ie_board_type {
        ATH12K_BD_IE_BOARD_DATA = 1,
 };
 
+enum ath12k_bd_ie_regdb_type {
+       ATH12K_BD_IE_REGDB_NAME = 0,
+       ATH12K_BD_IE_REGDB_DATA = 1,
+};
+
 enum ath12k_bd_ie_type {
        /* contains sub IEs of enum ath12k_bd_ie_board_type */
        ATH12K_BD_IE_BOARD = 0,
-       ATH12K_BD_IE_BOARD_EXT = 1,
+       /* contains sub IEs of enum ath12k_bd_ie_regdb_type */
+       ATH12K_BD_IE_REGDB = 1,
 };
 
 struct ath12k_hw_regs {
@@ -315,6 +324,18 @@ struct ath12k_hw_regs {
        u32 hal_reo_status_ring_base;
 };
 
+static inline const char *ath12k_bd_ie_type_str(enum ath12k_bd_ie_type type)
+{
+       switch (type) {
+       case ATH12K_BD_IE_BOARD:
+               return "board data";
+       case ATH12K_BD_IE_REGDB:
+               return "regdb data";
+       }
+
+       return "unknown";
+}
+
 int ath12k_hw_init(struct ath12k_base *ab);
 
 #endif
index 88cec54c6c2e64e02bd0af9d27ee6c92faa6a971..a27480a69b27325d50a0c2350c8ae82a2971e1e0 100644 (file)
@@ -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.
  */
 
 #include <net/mac80211.h>
@@ -241,8 +241,8 @@ static const u32 ath12k_smps_map[] = {
        [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
 };
 
-static int ath12k_start_vdev_delay(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif);
+static int ath12k_start_vdev_delay(struct ath12k *ar,
+                                  struct ath12k_vif *arvif);
 
 static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode)
 {
@@ -542,7 +542,7 @@ struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id)
        arvif_iter.vdev_id = vdev_id;
 
        flags = IEEE80211_IFACE_ITER_RESUME_ALL;
-       ieee80211_iterate_active_interfaces_atomic(ar->hw,
+       ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar),
                                                   flags,
                                                   ath12k_get_arvif_iter,
                                                   &arvif_iter);
@@ -1040,7 +1040,7 @@ static int ath12k_mac_monitor_start(struct ath12k *ar)
        if (ar->monitor_started)
                return 0;
 
-       ieee80211_iter_chan_contexts_atomic(ar->hw,
+       ieee80211_iter_chan_contexts_atomic(ath12k_ar_to_hw(ar),
                                            ath12k_mac_get_any_chandef_iter,
                                            &chandef);
        if (!chandef)
@@ -1083,9 +1083,9 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar)
        return ret;
 }
 
-static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed)
+static int ath12k_mac_config(struct ath12k *ar, u32 changed)
 {
-       struct ath12k *ar = hw->priv;
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
        struct ieee80211_conf *conf = &hw->conf;
        int ret = 0;
 
@@ -1122,11 +1122,27 @@ err_mon_del:
        return ret;
 }
 
+static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed)
+{
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+       int ret;
+
+       ar = ath12k_ah_to_ar(ah);
+
+       ret = ath12k_mac_config(ar, changed);
+       if (ret)
+               ath12k_warn(ar->ab, "failed to update config pdev idx %d: %d\n",
+                           ar->pdev_idx, ret);
+
+       return ret;
+}
+
 static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif)
 {
        struct ath12k *ar = arvif->ar;
        struct ath12k_base *ab = ar->ab;
-       struct ieee80211_hw *hw = ar->hw;
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
        struct ieee80211_vif *vif = arvif->vif;
        struct ieee80211_mutable_offsets offs = {};
        struct sk_buff *bcn;
@@ -1214,6 +1230,7 @@ static void ath12k_peer_assoc_h_basic(struct ath12k *ar,
                                      struct ath12k_wmi_peer_assoc_arg *arg)
 {
        struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
        u32 aid;
 
        lockdep_assert_held(&ar->conf_mutex);
@@ -1228,7 +1245,7 @@ static void ath12k_peer_assoc_h_basic(struct ath12k *ar,
        arg->peer_associd = aid;
        arg->auth_flag = true;
        /* TODO: STA WAR in ath10k for listen interval required? */
-       arg->peer_listen_intval = ar->hw->conf.listen_interval;
+       arg->peer_listen_intval = hw->conf.listen_interval;
        arg->peer_nss = 1;
        arg->peer_caps = vif->bss_conf.assoc_capability;
 }
@@ -1242,6 +1259,7 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar,
        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;
 
@@ -1250,7 +1268,7 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar,
        if (WARN_ON(ath12k_mac_vif_chan(vif, &def)))
                return;
 
-       bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0,
+       bss = cfg80211_get_bss(hw->wiphy, def.chan, info->bssid, NULL, 0,
                               IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
 
        if (arvif->rsnie_present || arvif->wpaie_present) {
@@ -1270,7 +1288,7 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar,
                                                ies->data,
                                                ies->len);
                rcu_read_unlock();
-               cfg80211_put_bss(ar->hw->wiphy, bss);
+               cfg80211_put_bss(hw->wiphy, bss);
        }
 
        /* FIXME: base on RSN IE/WPA IE is a correct idea? */
@@ -1304,6 +1322,7 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar,
        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);
        enum nl80211_band band;
        u32 ratemask;
        u8 rate;
@@ -1315,7 +1334,7 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar,
                return;
 
        band = def.chan->band;
-       sband = ar->hw->wiphy->bands[band];
+       sband = hw->wiphy->bands[band];
        ratemask = sta->deflink.supp_rates[band];
        ratemask &= arvif->bitrate_mask.control[band].legacy;
        rates = sband->bitrates;
@@ -2266,12 +2285,11 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif,
                                         ath12k_smps_map[smps]);
 }
 
-static void ath12k_bss_assoc(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif,
+static void ath12k_bss_assoc(struct ath12k *ar,
+                            struct ath12k_vif *arvif,
                             struct ieee80211_bss_conf *bss_conf)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       struct ieee80211_vif *vif = arvif->vif;
        struct ath12k_wmi_peer_assoc_arg peer_arg;
        struct ieee80211_sta *ap_sta;
        struct ath12k_peer *peer;
@@ -2361,11 +2379,9 @@ static void ath12k_bss_assoc(struct ieee80211_hw *hw,
                            arvif->vdev_id, ret);
 }
 
-static void ath12k_bss_disassoc(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif)
+static void ath12k_bss_disassoc(struct ath12k *ar,
+                               struct ath12k_vif *arvif)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
        int ret;
 
        lockdep_assert_held(&ar->conf_mutex);
@@ -2413,6 +2429,7 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar,
                                         struct cfg80211_chan_def *def)
 {
        struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
        const struct ieee80211_supported_band *sband;
        u8 basic_rate_idx;
        int hw_rate_code;
@@ -2422,7 +2439,7 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar,
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       sband = ar->hw->wiphy->bands[def->chan->band];
+       sband = hw->wiphy->bands[def->chan->band];
        basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
        bitrate = sband->bitrates[basic_rate_idx].bitrate;
 
@@ -2449,6 +2466,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
                                     struct ieee80211_bss_conf *info)
 {
        struct ath12k *ar = arvif->ar;
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
        struct sk_buff *tmpl;
        int ret;
        u32 interval;
@@ -2457,7 +2475,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(ar->hw, arvif->vif);
+               tmpl = ieee80211_get_fils_discovery_tmpl(hw, arvif->vif);
                if (tmpl)
                        ret = ath12k_wmi_fils_discovery_tmpl(ar, arvif->vdev_id,
                                                             tmpl);
@@ -2465,7 +2483,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(ar->hw,
+               tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw,
                                                                 arvif->vif);
                if (tmpl)
                        ret = ath12k_wmi_probe_resp_tmpl(ar, arvif->vdev_id,
@@ -2491,13 +2509,12 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
        return ret;
 }
 
-static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
-                                          struct ieee80211_vif *vif,
-                                          struct ieee80211_bss_conf *info,
-                                          u64 changed)
+static void ath12k_mac_bss_info_changed(struct ath12k *ar,
+                                       struct ath12k_vif *arvif,
+                                       struct ieee80211_bss_conf *info,
+                                       u64 changed)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       struct ieee80211_vif *vif = arvif->vif;
        struct cfg80211_chan_def def;
        u32 param_id, param_value;
        enum nl80211_band band;
@@ -2510,7 +2527,7 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
        u8 rateidx;
        u32 rate;
 
-       mutex_lock(&ar->conf_mutex);
+       lockdep_assert_held(&ar->conf_mutex);
 
        if (changed & BSS_CHANGED_BEACON_INT) {
                arvif->beacon_interval = info->beacon_int;
@@ -2666,9 +2683,9 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changed & BSS_CHANGED_ASSOC) {
                if (vif->cfg.assoc)
-                       ath12k_bss_assoc(hw, vif, info);
+                       ath12k_bss_assoc(ar, arvif, info);
                else
-                       ath12k_bss_disassoc(hw, vif);
+                       ath12k_bss_disassoc(ar, arvif);
        }
 
        if (changed & BSS_CHANGED_TXPOWER) {
@@ -2770,12 +2787,30 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changed & BSS_CHANGED_EHT_PUNCTURING)
                arvif->punct_bitmap = info->eht_puncturing;
+}
+
+static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
+                                          struct ieee80211_vif *vif,
+                                          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);
+
+       ar = ath12k_ah_to_ar(ah);
+
+       mutex_lock(&ar->conf_mutex);
+
+       ath12k_mac_bss_info_changed(ar, arvif, info, changed);
 
        mutex_unlock(&ar->conf_mutex);
 }
 
 void __ath12k_mac_scan_finish(struct ath12k *ar)
 {
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
+
        lockdep_assert_held(&ar->data_lock);
 
        switch (ar->scan.state) {
@@ -2784,7 +2819,7 @@ void __ath12k_mac_scan_finish(struct ath12k *ar)
        case ATH12K_SCAN_RUNNING:
        case ATH12K_SCAN_ABORTING:
                if (ar->scan.is_roc && ar->scan.roc_notify)
-                       ieee80211_remain_on_channel_expired(ar->hw);
+                       ieee80211_remain_on_channel_expired(hw);
                fallthrough;
        case ATH12K_SCAN_STARTING:
                if (!ar->scan.is_roc) {
@@ -2795,7 +2830,7 @@ void __ath12k_mac_scan_finish(struct ath12k *ar)
                                            ATH12K_SCAN_STARTING)),
                        };
 
-                       ieee80211_scan_completed(ar->hw, &info);
+                       ieee80211_scan_completed(hw, &info);
                }
 
                ar->scan.state = ATH12K_SCAN_IDLE;
@@ -2940,13 +2975,16 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_scan_request *hw_req)
 {
-       struct ath12k *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
        struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
        struct cfg80211_scan_request *req = &hw_req->req;
        struct ath12k_wmi_scan_req_arg arg = {};
        int ret;
        int i;
 
+       ar = ath12k_ah_to_ar(ah);
+
        mutex_lock(&ar->conf_mutex);
 
        spin_lock_bh(&ar->data_lock);
@@ -3014,7 +3052,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
        }
 
        /* Add a margin to account for event/command processing */
-       ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+       ieee80211_queue_delayed_work(ath12k_ar_to_hw(ar), &ar->scan.timeout,
                                     msecs_to_jiffies(arg.max_scan_time +
                                                      ATH12K_MAC_SCAN_TIMEOUT_MSECS));
 
@@ -3025,13 +3063,17 @@ exit:
                kfree(arg.extraie.ptr);
 
        mutex_unlock(&ar->conf_mutex);
+
        return ret;
 }
 
 static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw,
                                         struct ieee80211_vif *vif)
 {
-       struct ath12k *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+
+       ar = ath12k_ah_to_ar(ah);
 
        mutex_lock(&ar->conf_mutex);
        ath12k_scan_abort(ar);
@@ -3159,8 +3201,9 @@ 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 *ar = hw->priv;
-       struct ath12k_base *ab = ar->ab;
+       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_peer *peer;
        struct ath12k_sta *arsta;
@@ -3175,6 +3218,9 @@ static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
            key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
                return 1;
 
+       ar = ath12k_ah_to_ar(ah);
+       ab = ar->ab;
+
        if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags))
                return 1;
 
@@ -3696,7 +3742,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) {
-               ret = ath12k_start_vdev_delay(ar->hw, vif);
+               ret = ath12k_start_vdev_delay(ar, arvif);
                if (ret) {
                        ath12k_warn(ab, "failed to delay vdev start: %d\n", ret);
                        goto free_peer;
@@ -3750,7 +3796,8 @@ 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 *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
        struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
        struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
        struct ath12k_peer *peer;
@@ -3761,6 +3808,8 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
             new_state == IEEE80211_STA_NOTEXIST))
                cancel_work_sync(&arsta->update_wk);
 
+       ar = ath12k_ah_to_ar(ah);
+
        mutex_lock(&ar->conf_mutex);
 
        if (old_state == IEEE80211_STA_NOTEXIST &&
@@ -3856,6 +3905,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
        }
 
        mutex_unlock(&ar->conf_mutex);
+
        return ret;
 }
 
@@ -3863,7 +3913,8 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
                                       struct ieee80211_sta *sta)
 {
-       struct ath12k *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
        struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
        int ret;
        s16 txpwr;
@@ -3879,6 +3930,8 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
        if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL)
                return -EINVAL;
 
+       ar = ath12k_ah_to_ar(ah);
+
        mutex_lock(&ar->conf_mutex);
 
        ret = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
@@ -3899,12 +3952,15 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
                                        struct ieee80211_sta *sta,
                                        u32 changed)
 {
-       struct ath12k *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
        struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta);
        struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
        struct ath12k_peer *peer;
        u32 bw, smps;
 
+       ar = ath12k_ah_to_ar(ah);
+
        spin_lock_bh(&ar->ab->base_lock);
 
        peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
@@ -3964,10 +4020,10 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
        ieee80211_queue_work(hw, &arsta->update_wk);
 }
 
-static int ath12k_conf_tx_uapsd(struct ath12k *ar, struct ieee80211_vif *vif,
+static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif,
                                u16 ac, bool enable)
 {
-       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       struct ath12k *ar = arvif->ar;
        u32 value;
        int ret;
 
@@ -4021,17 +4077,16 @@ exit:
        return ret;
 }
 
-static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw,
-                                struct ieee80211_vif *vif,
-                                unsigned int link_id, u16 ac,
-                                const struct ieee80211_tx_queue_params *params)
+static int ath12k_mac_conf_tx(struct ath12k_vif *arvif,
+                             unsigned int link_id, u16 ac,
+                             const struct ieee80211_tx_queue_params *params)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
        struct wmi_wmm_params_arg *p = NULL;
+       struct ath12k *ar = arvif->ar;
+       struct ath12k_base *ab = ar->ab;
        int ret;
 
-       mutex_lock(&ar->conf_mutex);
+       lockdep_assert_held(&ar->conf_mutex);
 
        switch (ac) {
        case IEEE80211_AC_VO:
@@ -4061,17 +4116,36 @@ static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw,
        ret = ath12k_wmi_send_wmm_update_cmd(ar, arvif->vdev_id,
                                             &arvif->wmm_params);
        if (ret) {
-               ath12k_warn(ar->ab, "failed to set wmm params: %d\n", ret);
+               ath12k_warn(ab, "pdev idx %d failed to set wmm params: %d\n",
+                           ar->pdev_idx, ret);
                goto exit;
        }
 
-       ret = ath12k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
-
+       ret = ath12k_conf_tx_uapsd(arvif, ac, params->uapsd);
        if (ret)
-               ath12k_warn(ar->ab, "failed to set sta uapsd: %d\n", ret);
+               ath12k_warn(ab, "pdev idx %d failed to set sta uapsd: %d\n",
+                           ar->pdev_idx, ret);
 
 exit:
+       return ret;
+}
+
+static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                unsigned int link_id, u16 ac,
+                                const struct ieee80211_tx_queue_params *params)
+{
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       int ret;
+
+       ar = ath12k_ah_to_ar(ah);
+
+       mutex_lock(&ar->conf_mutex);
+       ret = ath12k_mac_conf_tx(arvif, link_id, ac, params);
        mutex_unlock(&ar->conf_mutex);
+
        return ret;
 }
 
@@ -4782,7 +4856,7 @@ static void ath12k_mgmt_over_wmi_tx_drop(struct ath12k *ar, struct sk_buff *skb)
 {
        int num_mgmt;
 
-       ieee80211_free_txskb(ar->hw, skb);
+       ieee80211_free_txskb(ath12k_ar_to_hw(ar), skb);
 
        num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx);
 
@@ -4959,7 +5033,7 @@ static int ath12k_mac_mgmt_tx(struct ath12k *ar, struct sk_buff *skb,
 
        skb_queue_tail(q, skb);
        atomic_inc(&ar->num_pending_mgmt_tx);
-       ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
+       ieee80211_queue_work(ath12k_ar_to_hw(ar), &ar->wmi_mgmt_tx_work);
 
        return 0;
 }
@@ -4969,10 +5043,10 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw,
                             struct sk_buff *skb)
 {
        struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
-       struct ath12k *ar = hw->priv;
        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 *ar = arvif->ar;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ieee80211_key_conf *key = info->control.hw_key;
        u32 info_flags = info->flags;
@@ -5018,7 +5092,7 @@ void ath12k_mac_drain_tx(struct ath12k *ar)
 
 static int ath12k_mac_config_mon_status_default(struct ath12k *ar, bool enable)
 {
-       return -ENOTSUPP;
+       return -EOPNOTSUPP;
        /* TODO: Need to support new monitor mode */
 }
 
@@ -5044,14 +5118,12 @@ static void ath12k_mac_wait_reconfigure(struct ath12k_base *ab)
                                    ATH12K_RECONFIGURE_TIMEOUT_HZ);
 }
 
-static int ath12k_mac_op_start(struct ieee80211_hw *hw)
+static int ath12k_mac_start(struct ath12k *ar)
 {
-       struct ath12k *ar = hw->priv;
        struct ath12k_base *ab = ar->ab;
        struct ath12k_pdev *pdev = ar->pdev;
        int ret;
 
-       ath12k_mac_drain_tx(ar);
        mutex_lock(&ar->conf_mutex);
 
        switch (ar->state) {
@@ -5074,14 +5146,14 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
                                        1, pdev->pdev_id);
 
        if (ret) {
-               ath12k_err(ar->ab, "failed to enable PMF QOS: (%d\n", ret);
+               ath12k_err(ab, "failed to enable PMF QOS: (%d\n", ret);
                goto err;
        }
 
        ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 1,
                                        pdev->pdev_id);
        if (ret) {
-               ath12k_err(ar->ab, "failed to enable dynamic bw: %d\n", ret);
+               ath12k_err(ab, "failed to enable dynamic bw: %d\n", ret);
                goto err;
        }
 
@@ -5111,7 +5183,7 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
                                        1, pdev->pdev_id);
 
        if (ret) {
-               ath12k_err(ar->ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret);
+               ath12k_err(ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret);
                goto err;
        }
 
@@ -5130,14 +5202,14 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
         * such as rssi, rx_duration.
         */
        ret = ath12k_mac_config_mon_status_default(ar, true);
-       if (ret && (ret != -ENOTSUPP)) {
+       if (ret && (ret != -EOPNOTSUPP)) {
                ath12k_err(ab, "failed to configure monitor status ring with default rx_filter: (%d)\n",
                           ret);
                goto err;
        }
 
-       if (ret == -ENOTSUPP)
-               ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+       if (ret == -EOPNOTSUPP)
+               ath12k_dbg(ab, ATH12K_DBG_MAC,
                           "monitor status config is not yet supported");
 
        /* Configure the hash seed for hash based reo dest ring selection */
@@ -5159,7 +5231,6 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
                           &ab->pdevs[ar->pdev_idx]);
 
        return 0;
-
 err:
        ar->state = ATH12K_STATE_OFF;
        mutex_unlock(&ar->conf_mutex);
@@ -5167,6 +5238,25 @@ err:
        return ret;
 }
 
+static int ath12k_mac_op_start(struct ieee80211_hw *hw)
+{
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar = ath12k_ah_to_ar(ah);
+       struct ath12k_base *ab = ar->ab;
+       int ret;
+
+       ath12k_mac_drain_tx(ar);
+
+       ret = ath12k_mac_start(ar);
+       if (ret) {
+               ath12k_err(ab, "fail to start mac operations in pdev idx %d ret %d\n",
+                          ar->pdev_idx, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 int ath12k_mac_rfkill_config(struct ath12k *ar)
 {
        struct ath12k_base *ab = ar->ab;
@@ -5224,17 +5314,14 @@ int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable)
        return 0;
 }
 
-static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
+static void ath12k_mac_stop(struct ath12k *ar)
 {
-       struct ath12k *ar = hw->priv;
        struct htt_ppdu_stats_info *ppdu_stats, *tmp;
        int ret;
 
-       ath12k_mac_drain_tx(ar);
-
        mutex_lock(&ar->conf_mutex);
        ret = ath12k_mac_config_mon_status_default(ar, false);
-       if (ret && (ret != -ENOTSUPP))
+       if (ret && (ret != -EOPNOTSUPP))
                ath12k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n",
                           ret);
 
@@ -5260,6 +5347,16 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
        atomic_set(&ar->num_pending_mgmt_tx, 0);
 }
 
+static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
+{
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar = ath12k_ah_to_ar(ah);
+
+       ath12k_mac_drain_tx(ar);
+
+       ath12k_mac_stop(ar);
+}
+
 static u8
 ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif)
 {
@@ -5376,12 +5473,11 @@ static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar,
        return ret;
 }
 
-static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
-                                            struct ieee80211_vif *vif)
+static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif)
 {
-       struct ath12k *ar = hw->priv;
+       struct ieee80211_vif *vif = arvif->vif;
+       struct ath12k *ar = arvif->ar;
        struct ath12k_base *ab = ar->ab;
-       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
        u32 param_id, param_value;
        int ret;
 
@@ -5423,11 +5519,20 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
        }
 }
 
+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);
+
+       ath12k_mac_update_vif_offload(arvif);
+}
+
 static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_base *ab = ar->ab;
+       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_wmi_vdev_create_arg vdev_arg = {0};
        struct ath12k_wmi_peer_create_arg peer_param;
@@ -5439,6 +5544,9 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 
        vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
 
+       ar = ath12k_ah_to_ar(ah);
+       ab = ar->ab;
+
        mutex_lock(&ar->conf_mutex);
 
        if (vif->type == NL80211_IFTYPE_AP &&
@@ -5526,7 +5634,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
        list_add(&arvif->list, &ar->arvifs);
        spin_unlock_bh(&ar->data_lock);
 
-       ath12k_mac_op_update_vif_offload(hw, vif);
+       ath12k_mac_update_vif_offload(arvif);
 
        nss = hweight32(ar->cfg_tx_chainmask) ? : 1;
        ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
@@ -5685,12 +5793,16 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif
 static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
                                           struct ieee80211_vif *vif)
 {
-       struct ath12k *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
        struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
-       struct ath12k_base *ab = ar->ab;
+       struct ath12k_base *ab;
        unsigned long time_left;
        int ret;
 
+       ar = ath12k_ah_to_ar(ah);
+       ab = ar->ab;
+
        mutex_lock(&ar->conf_mutex);
 
        ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n",
@@ -5766,19 +5878,15 @@ err_vdev_del:
        FIF_PROBE_REQ |                         \
        FIF_FCSFAIL)
 
-static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw,
-                                          unsigned int changed_flags,
-                                          unsigned int *total_flags,
-                                          u64 multicast)
+static void ath12k_mac_configure_filter(struct ath12k *ar,
+                                       unsigned int total_flags)
 {
-       struct ath12k *ar = hw->priv;
        bool reset_flag;
        int ret;
 
-       mutex_lock(&ar->conf_mutex);
+       lockdep_assert_held(&ar->conf_mutex);
 
-       *total_flags &= SUPPORTED_FILTERS;
-       ar->filter_flags = *total_flags;
+       ar->filter_flags = total_flags;
 
        /* For monitor mode */
        reset_flag = !(ar->filter_flags & FIF_BCN_PRBRESP_PROMISC);
@@ -5793,16 +5901,36 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw,
                ath12k_warn(ar->ab,
                            "fail to set monitor filter: %d\n", ret);
        }
+
        ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
                   "total_flags:0x%x, reset_flag:%d\n",
-                  *total_flags, reset_flag);
+                  total_flags, reset_flag);
+}
+
+static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw,
+                                          unsigned int changed_flags,
+                                          unsigned int *total_flags,
+                                          u64 multicast)
+{
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+
+       ar = ath12k_ah_to_ar(ah);
+
+       mutex_lock(&ar->conf_mutex);
+
+       *total_flags &= SUPPORTED_FILTERS;
+       ath12k_mac_configure_filter(ar, *total_flags);
 
        mutex_unlock(&ar->conf_mutex);
 }
 
 static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
 {
-       struct ath12k *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+
+       ar = ath12k_ah_to_ar(ah);
 
        mutex_lock(&ar->conf_mutex);
 
@@ -5816,9 +5944,12 @@ static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *
 
 static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
 {
-       struct ath12k *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
        int ret;
 
+       ar = ath12k_ah_to_ar(ah);
+
        mutex_lock(&ar->conf_mutex);
        ret = __ath12k_set_antenna(ar, tx_ant, rx_ant);
        mutex_unlock(&ar->conf_mutex);
@@ -5826,14 +5957,13 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx
        return ret;
 }
 
-static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw,
-                                     struct ieee80211_vif *vif,
-                                     struct ieee80211_ampdu_params *params)
+static int ath12k_mac_ampdu_action(struct ath12k_vif *arvif,
+                                  struct ieee80211_ampdu_params *params)
 {
-       struct ath12k *ar = hw->priv;
+       struct ath12k *ar = arvif->ar;
        int ret = -EINVAL;
 
-       mutex_lock(&ar->conf_mutex);
+       lockdep_assert_held(&ar->conf_mutex);
 
        switch (params->action) {
        case IEEE80211_AMPDU_RX_START:
@@ -5854,16 +5984,40 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw,
                break;
        }
 
+       return ret;
+}
+
+static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif,
+                                     struct ieee80211_ampdu_params *params)
+{
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       int ret = -EINVAL;
+
+       ar = ath12k_ah_to_ar(ah);
+
+       mutex_lock(&ar->conf_mutex);
+       ret = ath12k_mac_ampdu_action(arvif, params);
        mutex_unlock(&ar->conf_mutex);
 
+       if (ret)
+               ath12k_warn(ar->ab, "pdev idx %d unable to perform ampdu action %d ret %d\n",
+                           ar->pdev_idx, params->action, ret);
+
        return ret;
 }
 
 static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw,
                                     struct ieee80211_chanctx_conf *ctx)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_base *ab = ar->ab;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+       struct ath12k_base *ab;
+
+       ar = ath12k_ah_to_ar(ah);
+       ab = ar->ab;
 
        ath12k_dbg(ab, ATH12K_DBG_MAC,
                   "mac chanctx add freq %u width %d ptr %pK\n",
@@ -5886,8 +6040,12 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw,
 static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
                                         struct ieee80211_chanctx_conf *ctx)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_base *ab = ar->ab;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+       struct ath12k_base *ab;
+
+       ar = ath12k_ah_to_ar(ah);
+       ab = ar->ab;
 
        ath12k_dbg(ab, ATH12K_DBG_MAC,
                   "mac chanctx remove freq %u width %d ptr %pK\n",
@@ -6266,7 +6424,7 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar,
                                  struct ieee80211_chanctx_conf *ctx)
 {
        struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx };
-       struct ieee80211_hw *hw = ar->hw;
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
 
        lockdep_assert_held(&ar->conf_mutex);
 
@@ -6295,8 +6453,12 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw,
                                         struct ieee80211_chanctx_conf *ctx,
                                         u32 changed)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_base *ab = ar->ab;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+       struct ath12k_base *ab;
+
+       ar = ath12k_ah_to_ar(ah);
+       ab = ar->ab;
 
        mutex_lock(&ar->conf_mutex);
 
@@ -6320,12 +6482,11 @@ unlock:
        mutex_unlock(&ar->conf_mutex);
 }
 
-static int ath12k_start_vdev_delay(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif)
+static int ath12k_start_vdev_delay(struct ath12k *ar,
+                                  struct ath12k_vif *arvif)
 {
-       struct ath12k *ar = hw->priv;
        struct ath12k_base *ab = ar->ab;
-       struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+       struct ieee80211_vif *vif = arvif->vif;
        int ret;
 
        if (WARN_ON(arvif->is_started))
@@ -6359,12 +6520,16 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
                                 struct ieee80211_bss_conf *link_conf,
                                 struct ieee80211_chanctx_conf *ctx)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_base *ab = ar->ab;
+       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);
        int ret;
        struct ath12k_wmi_peer_create_arg param;
 
+       ar = ath12k_ah_to_ar(ah);
+       ab = ar->ab;
+
        mutex_lock(&ar->conf_mutex);
 
        ath12k_dbg(ab, ATH12K_DBG_MAC,
@@ -6438,11 +6603,15 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
                                   struct ieee80211_bss_conf *link_conf,
                                   struct ieee80211_chanctx_conf *ctx)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_base *ab = ar->ab;
+       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);
        int ret;
 
+       ar = ath12k_ah_to_ar(ah);
+       ab = ar->ab;
+
        mutex_lock(&ar->conf_mutex);
 
        ath12k_dbg(ab, ATH12K_DBG_MAC,
@@ -6490,7 +6659,10 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
                                 int n_vifs,
                                 enum ieee80211_chanctx_switch_mode mode)
 {
-       struct ath12k *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+
+       ar = ath12k_ah_to_ar(ah);
 
        mutex_lock(&ar->conf_mutex);
 
@@ -6532,10 +6704,15 @@ ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value)
  */
 static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 {
-       struct ath12k *ar = hw->priv;
-       int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+       int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD, ret;
 
-       return ath12k_set_vdev_param_to_all_vifs(ar, param_id, value);
+       ar = ath12k_ah_to_ar(ah);
+
+       ret = ath12k_set_vdev_param_to_all_vifs(ar, param_id, value);
+
+       return ret;
 }
 
 static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
@@ -6553,15 +6730,10 @@ static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
        return -EOPNOTSUPP;
 }
 
-static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                               u32 queues, bool drop)
+static void ath12k_mac_flush(struct ath12k *ar)
 {
-       struct ath12k *ar = hw->priv;
        long time_left;
 
-       if (drop)
-               return;
-
        time_left = wait_event_timeout(ar->dp.tx_empty_waitq,
                                       (atomic_read(&ar->dp.num_tx_pending) == 0),
                                       ATH12K_FLUSH_TIMEOUT);
@@ -6576,6 +6748,18 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v
                            time_left);
 }
 
+static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                               u32 queues, bool drop)
+{
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar = ath12k_ah_to_ar(ah);
+
+       if (drop)
+               return;
+
+       ath12k_mac_flush(ar);
+}
+
 static int
 ath12k_mac_bitrate_mask_num_ht_rates(struct ath12k *ar,
                                     enum nl80211_band band,
@@ -6778,7 +6962,7 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data,
        arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
        spin_unlock_bh(&ar->data_lock);
 
-       ieee80211_queue_work(ar->hw, &arsta->update_wk);
+       ieee80211_queue_work(ath12k_ar_to_hw(ar), &arsta->update_wk);
 }
 
 static void ath12k_mac_disable_peer_fixed_rate(void *data,
@@ -6826,8 +7010,10 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
        ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC);
 
        sgi = mask->control[band].gi;
-       if (sgi == NL80211_TXRATE_FORCE_LGI)
-               return -EINVAL;
+       if (sgi == NL80211_TXRATE_FORCE_LGI) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        /* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it
         * requires passing at least one of used basic rates along with them.
@@ -6843,7 +7029,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
                if (ret) {
                        ath12k_warn(ar->ab, "failed to get single legacy rate for vdev %i: %d\n",
                                    arvif->vdev_id, ret);
-                       return ret;
+                       goto out;
                }
                ieee80211_iterate_stations_atomic(hw,
                                                  ath12k_mac_disable_peer_fixed_rate,
@@ -6888,7 +7074,8 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
                         */
                        ath12k_warn(ar->ab,
                                    "Setting more than one MCS Value in bitrate mask not supported\n");
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto out;
                }
 
                ieee80211_iterate_stations_atomic(hw,
@@ -6915,6 +7102,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 
        mutex_unlock(&ar->conf_mutex);
 
+out:
        return ret;
 }
 
@@ -6922,14 +7110,18 @@ static void
 ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
                                enum ieee80211_reconfig_type reconfig_type)
 {
-       struct ath12k *ar = hw->priv;
-       struct ath12k_base *ab = ar->ab;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
+       struct ath12k_base *ab;
        struct ath12k_vif *arvif;
        int recovery_count;
 
        if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
                return;
 
+       ar = ath12k_ah_to_ar(ah);
+       ab = ar->ab;
+
        mutex_lock(&ar->conf_mutex);
 
        if (ar->state == ATH12K_STATE_RESTARTED) {
@@ -7013,7 +7205,8 @@ ath12k_mac_update_bss_chan_survey(struct ath12k *ar,
 static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
                                    struct survey_info *survey)
 {
-       struct ath12k *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar;
        struct ieee80211_supported_band *sband;
        struct survey_info *ar_survey;
        int ret = 0;
@@ -7021,6 +7214,8 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
        if (idx >= ATH12K_NUM_CHANS)
                return -ENOENT;
 
+       ar = ath12k_ah_to_ar(ah);
+
        ar_survey = &ar->survey[idx];
 
        mutex_lock(&ar->conf_mutex);
@@ -7052,6 +7247,7 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
 
 exit:
        mutex_unlock(&ar->conf_mutex);
+
        return ret;
 }
 
@@ -7158,9 +7354,9 @@ static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band)
 }
 
 static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
-                                          u32 supported_bands)
+                                          u32 supported_bands,
+                                          struct ieee80211_supported_band *bands[])
 {
-       struct ieee80211_hw *hw = ar->hw;
        struct ieee80211_supported_band *band;
        struct ath12k_wmi_hal_reg_capabilities_ext_arg *reg_cap;
        void *channels;
@@ -7186,7 +7382,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
                band->channels = channels;
                band->n_bitrates = ath12k_g_rates_size;
                band->bitrates = ath12k_g_rates;
-               hw->wiphy->bands[NL80211_BAND_2GHZ] = band;
+               bands[NL80211_BAND_2GHZ] = band;
 
                if (ar->ab->hw_params->single_pdev_only) {
                        phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP);
@@ -7198,7 +7394,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
        }
 
        if (supported_bands & WMI_HOST_WLAN_5G_CAP) {
-               if (reg_cap->high_5ghz_chan >= ATH12K_MAX_6G_FREQ) {
+               if (reg_cap->high_5ghz_chan >= ATH12K_MIN_6G_FREQ) {
                        channels = kmemdup(ath12k_6ghz_channels,
                                           sizeof(ath12k_6ghz_channels), GFP_KERNEL);
                        if (!channels) {
@@ -7213,7 +7409,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
                        band->channels = channels;
                        band->n_bitrates = ath12k_a_rates_size;
                        band->bitrates = ath12k_a_rates;
-                       hw->wiphy->bands[NL80211_BAND_6GHZ] = band;
+                       bands[NL80211_BAND_6GHZ] = band;
                        ath12k_mac_update_ch_list(ar, band,
                                                  reg_cap->low_5ghz_chan,
                                                  reg_cap->high_5ghz_chan);
@@ -7235,7 +7431,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
                        band->channels = channels;
                        band->n_bitrates = ath12k_a_rates_size;
                        band->bitrates = ath12k_a_rates;
-                       hw->wiphy->bands[NL80211_BAND_5GHZ] = band;
+                       bands[NL80211_BAND_5GHZ] = band;
 
                        if (ar->ab->hw_params->single_pdev_only) {
                                phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP);
@@ -7251,20 +7447,44 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
        return 0;
 }
 
-static int ath12k_mac_setup_iface_combinations(struct ath12k *ar)
+static u16 ath12k_mac_get_ifmodes(struct ath12k_hw *ah)
 {
-       struct ath12k_base *ab = ar->ab;
-       struct ieee80211_hw *hw = ar->hw;
-       struct wiphy *wiphy = hw->wiphy;
+       struct ath12k *ar = ath12k_ah_to_ar(ah);
+       u16 interface_modes = U16_MAX;
+
+       interface_modes &= ar->ab->hw_params->interface_modes;
+
+       return interface_modes == U16_MAX ? 0 : interface_modes;
+}
+
+static bool ath12k_mac_is_iface_mode_enable(struct ath12k_hw *ah,
+                                           enum nl80211_iftype type)
+{
+       struct ath12k *ar = ath12k_ah_to_ar(ah);
+       u16 interface_modes, mode;
+       bool is_enable = true;
+
+       mode = BIT(type);
+
+       interface_modes = ar->ab->hw_params->interface_modes;
+       if (!(interface_modes & mode))
+               is_enable = false;
+
+       return is_enable;
+}
+
+static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah)
+{
+       struct wiphy *wiphy = ah->hw->wiphy;
        struct ieee80211_iface_combination *combinations;
        struct ieee80211_iface_limit *limits;
        int n_limits, max_interfaces;
        bool ap, mesh;
 
-       ap = ab->hw_params->interface_modes & BIT(NL80211_IFTYPE_AP);
+       ap = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_AP);
 
        mesh = IS_ENABLED(CONFIG_MAC80211_MESH) &&
-               ab->hw_params->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT);
+               ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_MESH_POINT);
 
        combinations = kzalloc(sizeof(*combinations), GFP_KERNEL);
        if (!combinations)
@@ -7349,21 +7569,27 @@ static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = {
        },
 };
 
-static void __ath12k_mac_unregister(struct ath12k *ar)
+static void ath12k_mac_cleanup_unregister(struct ath12k *ar)
 {
-       struct ieee80211_hw *hw = ar->hw;
-       struct wiphy *wiphy = hw->wiphy;
-
-       cancel_work_sync(&ar->regd_update_work);
-
-       ieee80211_unregister_hw(hw);
-
        idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar);
        idr_destroy(&ar->txmgmt_idr);
 
        kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
        kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels);
        kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
+}
+
+static void ath12k_mac_hw_unregister(struct ath12k_hw *ah)
+{
+       struct ieee80211_hw *hw = ah->hw;
+       struct wiphy *wiphy = hw->wiphy;
+       struct ath12k *ar = ath12k_ah_to_ar(ah);
+
+       cancel_work_sync(&ar->regd_update_work);
+
+       ieee80211_unregister_hw(hw);
+
+       ath12k_mac_cleanup_unregister(ar);
 
        kfree(wiphy->iface_combinations[0].limits);
        kfree(wiphy->iface_combinations);
@@ -7371,28 +7597,42 @@ static void __ath12k_mac_unregister(struct ath12k *ar)
        SET_IEEE80211_DEV(hw, NULL);
 }
 
-void ath12k_mac_unregister(struct ath12k_base *ab)
+static int ath12k_mac_setup_register(struct ath12k *ar,
+                                    u32 *ht_cap,
+                                    struct ieee80211_supported_band *bands[])
 {
-       struct ath12k *ar;
-       struct ath12k_pdev *pdev;
-       int i;
+       struct ath12k_pdev_cap *cap = &ar->pdev->cap;
+       int ret;
 
-       for (i = 0; i < ab->num_radios; i++) {
-               pdev = &ab->pdevs[i];
-               ar = pdev->ar;
-               if (!ar)
-                       continue;
+       init_waitqueue_head(&ar->txmgmt_empty_waitq);
+       idr_init(&ar->txmgmt_idr);
+       spin_lock_init(&ar->txmgmt_idr_lock);
 
-               __ath12k_mac_unregister(ar);
-       }
+       ath12k_pdev_caps_update(ar);
+
+       ret = ath12k_mac_setup_channels_rates(ar,
+                                             cap->supported_bands,
+                                             bands);
+       if (ret)
+               return ret;
+
+       ath12k_mac_setup_ht_vht_cap(ar, cap, ht_cap);
+       ath12k_mac_setup_sband_iftype_data(ar, cap);
+
+       ar->max_num_stations = TARGET_NUM_STATIONS;
+       ar->max_num_peers = TARGET_NUM_PEERS_PDEV;
+
+       return 0;
 }
 
-static int __ath12k_mac_register(struct ath12k *ar)
+static int ath12k_mac_hw_register(struct ath12k_hw *ah)
 {
-       struct ath12k_base *ab = ar->ab;
-       struct ieee80211_hw *hw = ar->hw;
+       struct ieee80211_hw *hw = ah->hw;
        struct wiphy *wiphy = hw->wiphy;
-       struct ath12k_pdev_cap *cap = &ar->pdev->cap;
+       struct ath12k *ar = ath12k_ah_to_ar(ah);
+       struct ath12k_base *ab = ar->ab;
+       struct ath12k_pdev *pdev;
+       struct ath12k_pdev_cap *cap;
        static const u32 cipher_suites[] = {
                WLAN_CIPHER_SUITE_TKIP,
                WLAN_CIPHER_SUITE_CCMP,
@@ -7407,30 +7647,34 @@ static int __ath12k_mac_register(struct ath12k *ar)
        int ret;
        u32 ht_cap = 0;
 
-       ath12k_pdev_caps_update(ar);
+       pdev = ar->pdev;
 
-       SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr);
-
-       SET_IEEE80211_DEV(hw, ab->dev);
+       if (ab->pdevs_macaddr_valid)
+               ether_addr_copy(ar->mac_addr, pdev->mac_addr);
+       else
+               ether_addr_copy(ar->mac_addr, ab->mac_addr);
 
-       ret = ath12k_mac_setup_channels_rates(ar,
-                                             cap->supported_bands);
+       ret = ath12k_mac_setup_register(ar, &ht_cap, hw->wiphy->bands);
        if (ret)
-               goto err;
+               goto out;
 
-       ath12k_mac_setup_ht_vht_cap(ar, cap, &ht_cap);
-       ath12k_mac_setup_sband_iftype_data(ar, cap);
+       wiphy->max_ap_assoc_sta = ar->max_num_stations;
 
-       ret = ath12k_mac_setup_iface_combinations(ar);
-       if (ret) {
-               ath12k_err(ar->ab, "failed to setup interface combinations: %d\n", ret);
-               goto err_free_channels;
-       }
+       cap = &pdev->cap;
 
        wiphy->available_antennas_rx = cap->rx_chain_mask;
        wiphy->available_antennas_tx = cap->tx_chain_mask;
 
-       wiphy->interface_modes = ab->hw_params->interface_modes;
+       SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr);
+       SET_IEEE80211_DEV(hw, ab->dev);
+
+       ret = ath12k_mac_setup_iface_combinations(ah);
+       if (ret) {
+               ath12k_err(ab, "failed to setup interface combinations: %d\n", ret);
+               goto err_cleanup_unregister;
+       }
+
+       wiphy->interface_modes = ath12k_mac_get_ifmodes(ah);
 
        if (wiphy->bands[NL80211_BAND_2GHZ] &&
            wiphy->bands[NL80211_BAND_5GHZ] &&
@@ -7483,15 +7727,10 @@ static int __ath12k_mac_register(struct ath12k *ar)
        wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
                                   NL80211_FEATURE_AP_SCAN;
 
-       ar->max_num_stations = TARGET_NUM_STATIONS;
-       ar->max_num_peers = TARGET_NUM_PEERS_PDEV;
-
-       wiphy->max_ap_assoc_sta = ar->max_num_stations;
-
        hw->queues = ATH12K_HW_MAX_QUEUES;
        wiphy->tx_queue_len = ATH12K_QUEUE_LEN;
        hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1;
-       hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
+       hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT;
 
        hw->vif_data_size = sizeof(struct ath12k_vif);
        hw->sta_data_size = sizeof(struct ath12k_sta);
@@ -7524,7 +7763,7 @@ static int __ath12k_mac_register(struct ath12k *ar)
 
        ret = ieee80211_register_hw(hw);
        if (ret) {
-               ath12k_err(ar->ab, "ieee80211 registration failed: %d\n", ret);
+               ath12k_err(ab, "ieee80211 registration failed: %d\n", ret);
                goto err_free_if_combs;
        }
 
@@ -7552,142 +7791,211 @@ err_free_if_combs:
        kfree(wiphy->iface_combinations[0].limits);
        kfree(wiphy->iface_combinations);
 
-err_free_channels:
-       kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
-       kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels);
-       kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
+err_cleanup_unregister:
+       ath12k_mac_cleanup_unregister(ar);
 
-err:
+out:
        SET_IEEE80211_DEV(hw, NULL);
+
        return ret;
 }
 
+static void ath12k_mac_setup(struct ath12k *ar)
+{
+       struct ath12k_base *ab = ar->ab;
+       struct ath12k_pdev *pdev = ar->pdev;
+       u8 pdev_idx = ar->pdev_idx;
+
+       ar->lmac_id = ath12k_hw_get_mac_from_pdev_id(ab->hw_params, pdev_idx);
+
+       ar->wmi = &ab->wmi_ab.wmi[pdev_idx];
+       /* FIXME: wmi[0] is already initialized during attach,
+        * Should we do this again?
+        */
+       ath12k_wmi_pdev_attach(ab, pdev_idx);
+
+       ar->cfg_tx_chainmask = pdev->cap.tx_chain_mask;
+       ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask;
+       ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask);
+       ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask);
+
+       spin_lock_init(&ar->data_lock);
+       INIT_LIST_HEAD(&ar->arvifs);
+       INIT_LIST_HEAD(&ar->ppdu_stats_info);
+       mutex_init(&ar->conf_mutex);
+       init_completion(&ar->vdev_setup_done);
+       init_completion(&ar->vdev_delete_done);
+       init_completion(&ar->peer_assoc_done);
+       init_completion(&ar->peer_delete_done);
+       init_completion(&ar->install_key_done);
+       init_completion(&ar->bss_survey_done);
+       init_completion(&ar->scan.started);
+       init_completion(&ar->scan.completed);
+
+       INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work);
+       INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work);
+
+       INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work);
+       skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
+       clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
+}
+
 int ath12k_mac_register(struct ath12k_base *ab)
 {
-       struct ath12k *ar;
-       struct ath12k_pdev *pdev;
+       struct ath12k_hw *ah;
        int i;
        int ret;
 
        if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))
                return 0;
 
-       for (i = 0; i < ab->num_radios; i++) {
-               pdev = &ab->pdevs[i];
-               ar = pdev->ar;
-               if (ab->pdevs_macaddr_valid) {
-                       ether_addr_copy(ar->mac_addr, pdev->mac_addr);
-               } else {
-                       ether_addr_copy(ar->mac_addr, ab->mac_addr);
-                       ar->mac_addr[4] += i;
-               }
-
-               ret = __ath12k_mac_register(ar);
-               if (ret)
-                       goto err_cleanup;
-
-               init_waitqueue_head(&ar->txmgmt_empty_waitq);
-               idr_init(&ar->txmgmt_idr);
-               spin_lock_init(&ar->txmgmt_idr_lock);
-       }
-
        /* Initialize channel counters frequency value in hertz */
        ab->cc_freq_hz = 320000;
        ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
 
+       for (i = 0; i < ab->num_hw; i++) {
+               ah = ab->ah[i];
+
+               ret = ath12k_mac_hw_register(ah);
+               if (ret)
+                       goto err;
+       }
+
        return 0;
 
-err_cleanup:
+err:
        for (i = i - 1; i >= 0; i--) {
-               pdev = &ab->pdevs[i];
-               ar = pdev->ar;
-               __ath12k_mac_unregister(ar);
+               ah = ab->ah[i];
+               if (!ah)
+                       continue;
+
+               ath12k_mac_hw_unregister(ah);
        }
 
        return ret;
 }
 
-int ath12k_mac_allocate(struct ath12k_base *ab)
+void ath12k_mac_unregister(struct ath12k_base *ab)
+{
+       struct ath12k_hw *ah;
+       int i;
+
+       for (i = ab->num_hw - 1; i >= 0; i--) {
+               ah = ab->ah[i];
+               if (!ah)
+                       continue;
+
+               ath12k_mac_hw_unregister(ah);
+       }
+}
+
+static void ath12k_mac_hw_destroy(struct ath12k_hw *ah)
+{
+       ieee80211_free_hw(ah->hw);
+}
+
+static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab,
+                                               struct ath12k_pdev_map *pdev_map,
+                                               u8 num_pdev_map)
 {
        struct ieee80211_hw *hw;
        struct ath12k *ar;
        struct ath12k_pdev *pdev;
-       int ret;
+       struct ath12k_hw *ah;
        int i;
+       u8 pdev_idx;
 
-       if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))
-               return 0;
+       hw = ieee80211_alloc_hw(struct_size(ah, radio, num_pdev_map),
+                               &ath12k_ops);
+       if (!hw)
+               return NULL;
 
-       for (i = 0; i < ab->num_radios; i++) {
-               pdev = &ab->pdevs[i];
-               hw = ieee80211_alloc_hw(sizeof(struct ath12k), &ath12k_ops);
-               if (!hw) {
-                       ath12k_warn(ab, "failed to allocate mac80211 hw device\n");
-                       ret = -ENOMEM;
-                       goto err_free_mac;
-               }
+       ah = ath12k_hw_to_ah(hw);
+       ah->hw = hw;
+       ah->num_radio = num_pdev_map;
+
+       for (i = 0; i < num_pdev_map; i++) {
+               ab = pdev_map[i].ab;
+               pdev_idx = pdev_map[i].pdev_idx;
+               pdev = &ab->pdevs[pdev_idx];
 
-               ar = hw->priv;
-               ar->hw = hw;
+               ar = ath12k_ah_to_ar(ah);
+               ar->ah = ah;
                ar->ab = ab;
+               ar->hw_link_id = i;
                ar->pdev = pdev;
-               ar->pdev_idx = i;
-               ar->lmac_id = ath12k_hw_get_mac_from_pdev_id(ab->hw_params, i);
-
-               ar->wmi = &ab->wmi_ab.wmi[i];
-               /* FIXME: wmi[0] is already initialized during attach,
-                * Should we do this again?
-                */
-               ath12k_wmi_pdev_attach(ab, i);
-
-               ar->cfg_tx_chainmask = pdev->cap.tx_chain_mask;
-               ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask;
-               ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask);
-               ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask);
-
+               ar->pdev_idx = pdev_idx;
                pdev->ar = ar;
-               spin_lock_init(&ar->data_lock);
-               INIT_LIST_HEAD(&ar->arvifs);
-               INIT_LIST_HEAD(&ar->ppdu_stats_info);
-               mutex_init(&ar->conf_mutex);
-               init_completion(&ar->vdev_setup_done);
-               init_completion(&ar->vdev_delete_done);
-               init_completion(&ar->peer_assoc_done);
-               init_completion(&ar->peer_delete_done);
-               init_completion(&ar->install_key_done);
-               init_completion(&ar->bss_survey_done);
-               init_completion(&ar->scan.started);
-               init_completion(&ar->scan.completed);
-
-               INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work);
-               INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work);
-
-               INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work);
-               skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
-               clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
-       }
-
-       return 0;
 
-err_free_mac:
-       ath12k_mac_destroy(ab);
+               ath12k_mac_setup(ar);
+       }
 
-       return ret;
+       return ah;
 }
 
 void ath12k_mac_destroy(struct ath12k_base *ab)
 {
-       struct ath12k *ar;
        struct ath12k_pdev *pdev;
        int i;
 
        for (i = 0; i < ab->num_radios; i++) {
                pdev = &ab->pdevs[i];
-               ar = pdev->ar;
-               if (!ar)
+               if (!pdev->ar)
                        continue;
 
-               ieee80211_free_hw(ar->hw);
                pdev->ar = NULL;
        }
+
+       for (i = 0; i < ab->num_hw; i++) {
+               if (!ab->ah[i])
+                       continue;
+
+               ath12k_mac_hw_destroy(ab->ah[i]);
+               ab->ah[i] = NULL;
+       }
+}
+
+int ath12k_mac_allocate(struct ath12k_base *ab)
+{
+       struct ath12k_hw *ah;
+       struct ath12k_pdev_map pdev_map[MAX_RADIOS];
+       int ret, i, j;
+       u8 radio_per_hw;
+
+       if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags))
+               return 0;
+
+       ab->num_hw = ab->num_radios;
+       radio_per_hw = 1;
+
+       for (i = 0; i < ab->num_hw; i++) {
+               for (j = 0; j < radio_per_hw; j++) {
+                       pdev_map[j].ab = ab;
+                       pdev_map[j].pdev_idx = (i * radio_per_hw) + j;
+               }
+
+               ah = ath12k_mac_hw_allocate(ab, pdev_map, radio_per_hw);
+               if (!ah) {
+                       ath12k_warn(ab, "failed to allocate mac80211 hw device for hw_idx %d\n",
+                                   i);
+                       goto err;
+               }
+
+               ab->ah[i] = ah;
+       }
+
+       ath12k_dp_pdev_pre_alloc(ab);
+
+       return 0;
+
+err:
+       for (i = i - 1; i >= 0; i--) {
+               if (!ab->ah[i])
+                       continue;
+
+               ath12k_mac_hw_destroy(ab->ah[i]);
+               ab->ah[i] = NULL;
+       }
+
+       return ret;
 }
index 7c63bb628adc1b664bb3a2df18d307b68a129c73..3f5e1be0dff9fbcfa4a75e0ada341be701e4c9f8 100644 (file)
@@ -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_MAC_H
@@ -12,6 +12,8 @@
 
 struct ath12k;
 struct ath12k_base;
+struct ath12k_hw;
+struct ath12k_pdev_map;
 
 struct ath12k_generic_iter {
        struct ath12k *ar;
index f0d2e2d8719c006a90ebd3656d29050f6854f4a4..76438b3afd55b51fad60a1bcddfc8b25d1d89122 100644 (file)
@@ -1310,6 +1310,15 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
                goto err_free_core;
        }
 
+       ath12k_dbg(ab, ATH12K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n",
+                  pdev->vendor, pdev->device,
+                  pdev->subsystem_vendor, pdev->subsystem_device);
+
+       ab->id.vendor = pdev->vendor;
+       ab->id.device = pdev->device;
+       ab->id.subsystem_vendor = pdev->subsystem_vendor;
+       ab->id.subsystem_device = pdev->subsystem_device;
+
        switch (pci_dev->device) {
        case QCN9274_DEVICE_ID:
                ab_pci->msi_config = &ath12k_msi_config[0];
@@ -1333,6 +1342,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
                }
                break;
        case WCN7850_DEVICE_ID:
+               ab->id.bdf_search = ATH12K_BDF_SEARCH_BUS_AND_BOARD;
                ab_pci->msi_config = &ath12k_msi_config[0];
                ab->static_window_map = false;
                ab_pci->pci_ops = &ath12k_pci_ops_wcn7850;
index 77a132f6bbd1be09c2d74f572bbd60ea526b603e..69f56400367cda1028cd208c7371f8d5f3a3904f 100644 (file)
@@ -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.
  */
 
 #include <linux/elf.h>
@@ -17,7 +17,7 @@
 #define PLATFORM_CAP_PCIE_GLOBAL_RESET 0x08
 #define ATH12K_QMI_MAX_CHUNK_SIZE      2097152
 
-static struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = {
+static const struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_1_BYTE,
                .elem_len       = 1,
@@ -61,7 +61,7 @@ static struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = {
        {
                .data_type      = QMI_OPT_FLAG,
                .elem_len       = 1,
@@ -511,7 +511,7 @@ static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = {
        {
                .data_type      = QMI_STRUCT,
                .elem_len       = 1,
@@ -528,7 +528,68 @@ static struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_phy_cap_req_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static const struct qmi_elem_info qmi_wlanfw_phy_cap_resp_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = 1,
+               .elem_size      = sizeof(struct qmi_response_type_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x02,
+               .offset         = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, resp),
+               .ei_array       = qmi_response_type_v01_ei,
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
+                                          num_phy_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
+                                          num_phy),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
+                                          board_id_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01,
+                                          board_id),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static const struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = {
        {
                .data_type      = QMI_OPT_FLAG,
                .elem_len       = 1,
@@ -753,7 +814,7 @@ static struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = {
        {
                .data_type      = QMI_STRUCT,
                .elem_len       = 1,
@@ -789,7 +850,7 @@ static struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_8_BYTE,
                .elem_len       = 1,
@@ -821,7 +882,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_4_BYTE,
                .elem_len       = 1,
@@ -863,7 +924,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = {
        {
                .data_type      = QMI_DATA_LEN,
                .elem_len       = 1,
@@ -890,7 +951,7 @@ static struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_8_BYTE,
                .elem_len       = 1,
@@ -930,7 +991,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = {
        {
                .data_type      = QMI_DATA_LEN,
                .elem_len       = 1,
@@ -957,7 +1018,7 @@ static struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = {
        {
                .data_type      = QMI_STRUCT,
                .elem_len       = 1,
@@ -975,7 +1036,7 @@ static struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = {
        {
                .data_type      = QMI_EOTI,
                .array_type     = NO_ARRAY,
@@ -983,7 +1044,7 @@ static struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_4_BYTE,
                .elem_len       = 1,
@@ -1009,7 +1070,7 @@ static struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_4_BYTE,
                .elem_len       = 1,
@@ -1026,7 +1087,7 @@ static struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_4_BYTE,
                .elem_len       = 1,
@@ -1042,7 +1103,7 @@ static struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_8_BYTE,
                .elem_len       = 1,
@@ -1068,7 +1129,7 @@ static struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_4_BYTE,
                .elem_len       = 1,
@@ -1094,7 +1155,7 @@ static struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = {
        {
                .data_type      = QMI_STRUCT,
                .elem_len       = 1,
@@ -1348,7 +1409,7 @@ static struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_1_BYTE,
                .elem_len       = 1,
@@ -1483,7 +1544,7 @@ static struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = {
        {
                .data_type      = QMI_STRUCT,
                .elem_len       = 1,
@@ -1501,7 +1562,7 @@ static struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_8_BYTE,
                .elem_len       = 1,
@@ -1525,7 +1586,7 @@ static struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = {
        {
                .data_type      = QMI_STRUCT,
                .elem_len       = 1,
@@ -1542,7 +1603,7 @@ static struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_4_BYTE,
                .elem_len       = 1,
@@ -1595,7 +1656,7 @@ static struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_4_BYTE,
                .elem_len       = 1,
@@ -1630,7 +1691,7 @@ static struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_2_BYTE,
                .elem_len       = 1,
@@ -1654,7 +1715,7 @@ static struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_4_BYTE,
                .elem_len       = 1,
@@ -1671,7 +1732,7 @@ static struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = {
        {
                .data_type      = QMI_UNSIGNED_4_BYTE,
                .elem_len       = 1,
@@ -1706,7 +1767,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = {
        {
                .data_type      = QMI_STRUCT,
                .elem_len       = 1,
@@ -1724,7 +1785,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = {
        {
                .data_type      = QMI_OPT_FLAG,
                .elem_len       = 1,
@@ -1862,7 +1923,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = {
        {
                .data_type      = QMI_STRUCT,
                .elem_len       = 1,
@@ -1879,22 +1940,78 @@ static struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = {
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = {
        {
                .data_type = QMI_EOTI,
                .array_type = NO_ARRAY,
        },
 };
 
-static struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = {
+static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = {
        {
                .data_type = QMI_EOTI,
                .array_type = NO_ARRAY,
        },
 };
 
-static void ath12k_host_cap_parse_mlo(struct qmi_wlanfw_host_cap_req_msg_v01 *req)
+static const struct qmi_elem_info qmi_wlanfw_wlan_ini_req_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01,
+                                          enable_fwlog_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01,
+                                          enable_fwlog),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static const struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = 1,
+               .elem_size      = sizeof(struct qmi_response_type_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x02,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_ini_resp_msg_v01,
+                                          resp),
+               .ei_array       = qmi_response_type_v01_ei,
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab,
+                                     struct qmi_wlanfw_host_cap_req_msg_v01 *req)
 {
+       struct wlfw_host_mlo_chip_info_s_v01 *info;
+       u8 hw_link_id = 0;
+       int i;
+
+       if (!ab->qmi.num_radios || ab->qmi.num_radios == U8_MAX) {
+               ath12k_dbg(ab, ATH12K_DBG_QMI,
+                          "skip QMI MLO cap due to invalid num_radio %d\n",
+                          ab->qmi.num_radios);
+               return;
+       }
+
        req->mlo_capable_valid = 1;
        req->mlo_capable = 1;
        req->mlo_chip_id_valid = 1;
@@ -1905,28 +2022,31 @@ static void ath12k_host_cap_parse_mlo(struct qmi_wlanfw_host_cap_req_msg_v01 *re
        /* Max peer number generally won't change for the same device
         * but needs to be synced with host driver.
         */
-       req->max_mlo_peer = 32;
+       req->max_mlo_peer = ab->hw_params->max_mlo_peer;
        req->mlo_num_chips_valid = 1;
        req->mlo_num_chips = 1;
+
+       info = &req->mlo_chip_info[0];
+       info->chip_id = 0;
+       info->num_local_links = ab->qmi.num_radios;
+
+       for (i = 0; i < info->num_local_links; i++) {
+               info->hw_link_id[i] = hw_link_id;
+               info->valid_mlo_link_id[i] = 1;
+
+               hw_link_id++;
+       }
+
        req->mlo_chip_info_valid = 1;
-       req->mlo_chip_info[0].chip_id = 0;
-       req->mlo_chip_info[0].num_local_links = 2;
-       req->mlo_chip_info[0].hw_link_id[0] = 0;
-       req->mlo_chip_info[0].hw_link_id[1] = 1;
-       req->mlo_chip_info[0].valid_mlo_link_id[0] = 1;
-       req->mlo_chip_info[0].valid_mlo_link_id[1] = 1;
 }
 
 static int ath12k_qmi_host_cap_send(struct ath12k_base *ab)
 {
-       struct qmi_wlanfw_host_cap_req_msg_v01 req;
-       struct qmi_wlanfw_host_cap_resp_msg_v01 resp;
-       struct qmi_txn txn = {};
+       struct qmi_wlanfw_host_cap_req_msg_v01 req = {};
+       struct qmi_wlanfw_host_cap_resp_msg_v01 resp = {};
+       struct qmi_txn txn;
        int ret = 0;
 
-       memset(&req, 0, sizeof(req));
-       memset(&resp, 0, sizeof(resp));
-
        req.num_clients_valid = 1;
        req.num_clients = 1;
        req.mem_cfg_mode = ab->qmi.target_mem_mode;
@@ -1963,10 +2083,10 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab)
                 */
                req.nm_modem |= SLEEP_CLOCK_SELECT_INTERNAL_BIT;
                req.nm_modem |= PLATFORM_CAP_PCIE_GLOBAL_RESET;
-
-               ath12k_host_cap_parse_mlo(&req);
        }
 
+       ath12k_host_cap_parse_mlo(ab, &req);
+
        ret = qmi_txn_init(&ab->qmi.handle, &txn,
                           qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp);
        if (ret < 0)
@@ -1977,6 +2097,7 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab)
                               QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_host_cap_req_msg_v01_ei, &req);
        if (ret < 0) {
+               qmi_txn_cancel(&txn);
                ath12k_warn(ab, "Failed to send host capability request,err = %d\n", ret);
                goto out;
        }
@@ -1996,6 +2117,59 @@ out:
        return ret;
 }
 
+static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab)
+{
+       struct qmi_wlanfw_phy_cap_req_msg_v01 req = {};
+       struct qmi_wlanfw_phy_cap_resp_msg_v01 resp = {};
+       struct qmi_txn txn;
+       int ret;
+
+       ret = qmi_txn_init(&ab->qmi.handle, &txn,
+                          qmi_wlanfw_phy_cap_resp_msg_v01_ei, &resp);
+       if (ret < 0)
+               goto out;
+
+       ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                              QMI_WLANFW_PHY_CAP_REQ_V01,
+                              QMI_WLANFW_PHY_CAP_REQ_MSG_V01_MAX_LEN,
+                              qmi_wlanfw_phy_cap_req_msg_v01_ei, &req);
+       if (ret < 0) {
+               qmi_txn_cancel(&txn);
+               ath12k_warn(ab, "failed to send phy capability request: %d\n", ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS));
+       if (ret < 0)
+               goto out;
+
+       if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!resp.num_phy_valid) {
+               ret = -ENODATA;
+               goto out;
+       }
+
+       ab->qmi.num_radios = resp.num_phy;
+
+       ath12k_dbg(ab, ATH12K_DBG_QMI, "phy capability resp valid %d num_phy %d valid %d board_id %d\n",
+                  resp.num_phy_valid, resp.num_phy,
+                  resp.board_id_valid, resp.board_id);
+
+       return;
+
+out:
+       /* If PHY capability not advertised then rely on default num link */
+       ab->qmi.num_radios = ab->hw_params->def_num_link;
+
+       ath12k_dbg(ab, ATH12K_DBG_QMI,
+                  "no valid response from PHY capability, choose default num_phy %d\n",
+                  ab->qmi.num_radios);
+}
+
 static int ath12k_qmi_fw_ind_register_send(struct ath12k_base *ab)
 {
        struct qmi_wlanfw_ind_register_req_msg_v01 *req;
@@ -2040,6 +2214,7 @@ static int ath12k_qmi_fw_ind_register_send(struct ath12k_base *ab)
                               QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_ind_register_req_msg_v01_ei, req);
        if (ret < 0) {
+               qmi_txn_cancel(&txn);
                ath12k_warn(ab, "Failed to send indication register request, err = %d\n",
                            ret);
                goto out;
@@ -2068,8 +2243,8 @@ resp_out:
 static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab)
 {
        struct qmi_wlanfw_respond_mem_req_msg_v01 *req;
-       struct qmi_wlanfw_respond_mem_resp_msg_v01 resp;
-       struct qmi_txn txn = {};
+       struct qmi_wlanfw_respond_mem_resp_msg_v01 resp = {};
+       struct qmi_txn txn;
        int ret = 0, i;
        bool delayed;
 
@@ -2077,8 +2252,6 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab)
        if (!req)
                return -ENOMEM;
 
-       memset(&resp, 0, sizeof(resp));
-
        /* Some targets by default request a block of big contiguous
         * DMA memory, it's hard to allocate from kernel. So host returns
         * failure to firmware and firmware then request multiple blocks of
@@ -2088,7 +2261,6 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab)
                delayed = true;
                ath12k_dbg(ab, ATH12K_DBG_QMI, "qmi delays mem_request %d\n",
                           ab->qmi.mem_seg_count);
-               memset(req, 0, sizeof(*req));
        } else {
                delayed = false;
                req->mem_seg_len = ab->qmi.mem_seg_count;
@@ -2114,6 +2286,7 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab)
                               QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_respond_mem_req_msg_v01_ei, req);
        if (ret < 0) {
+               qmi_txn_cancel(&txn);
                ath12k_warn(ab, "qmi failed to respond memory request, err = %d\n",
                            ret);
                goto out;
@@ -2208,17 +2381,14 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab)
 
 static int ath12k_qmi_request_target_cap(struct ath12k_base *ab)
 {
-       struct qmi_wlanfw_cap_req_msg_v01 req;
-       struct qmi_wlanfw_cap_resp_msg_v01 resp;
-       struct qmi_txn txn = {};
+       struct qmi_wlanfw_cap_req_msg_v01 req = {};
+       struct qmi_wlanfw_cap_resp_msg_v01 resp = {};
+       struct qmi_txn txn;
        unsigned int board_id = ATH12K_BOARD_ID_DEFAULT;
        int ret = 0;
        int r;
        int i;
 
-       memset(&req, 0, sizeof(req));
-       memset(&resp, 0, sizeof(resp));
-
        ret = qmi_txn_init(&ab->qmi.handle, &txn,
                           qmi_wlanfw_cap_resp_msg_v01_ei, &resp);
        if (ret < 0)
@@ -2229,6 +2399,7 @@ static int ath12k_qmi_request_target_cap(struct ath12k_base *ab)
                               QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_cap_req_msg_v01_ei, &req);
        if (ret < 0) {
+               qmi_txn_cancel(&txn);
                ath12k_warn(ab, "qmi failed to send target cap request, err = %d\n",
                            ret);
                goto out;
@@ -2310,8 +2481,8 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab,
                                           const u8 *data, u32 len, u8 type)
 {
        struct qmi_wlanfw_bdf_download_req_msg_v01 *req;
-       struct qmi_wlanfw_bdf_download_resp_msg_v01 resp;
-       struct qmi_txn txn = {};
+       struct qmi_wlanfw_bdf_download_resp_msg_v01 resp = {};
+       struct qmi_txn txn;
        const u8 *temp = data;
        int ret;
        u32 remaining = len;
@@ -2319,7 +2490,6 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab,
        req = kzalloc(sizeof(*req), GFP_KERNEL);
        if (!req)
                return -ENOMEM;
-       memset(&resp, 0, sizeof(resp));
 
        while (remaining) {
                req->valid = 1;
@@ -2423,8 +2593,7 @@ static int ath12k_qmi_load_bdf_qmi(struct ath12k_base *ab,
 
                break;
        case ATH12K_QMI_BDF_TYPE_REGDB:
-               ret = ath12k_core_fetch_board_data_api_1(ab, &bd,
-                                                        ATH12K_REGDB_FILE_NAME);
+               ret = ath12k_core_fetch_regdb(ab, &bd);
                if (ret) {
                        ath12k_warn(ab, "qmi failed to load regdb bin:\n");
                        goto out;
@@ -2546,14 +2715,11 @@ static void ath12k_qmi_m3_free(struct ath12k_base *ab)
 static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab)
 {
        struct m3_mem_region *m3_mem = &ab->qmi.m3_mem;
-       struct qmi_wlanfw_m3_info_req_msg_v01 req;
-       struct qmi_wlanfw_m3_info_resp_msg_v01 resp;
-       struct qmi_txn txn = {};
+       struct qmi_wlanfw_m3_info_req_msg_v01 req = {};
+       struct qmi_wlanfw_m3_info_resp_msg_v01 resp = {};
+       struct qmi_txn txn;
        int ret = 0;
 
-       memset(&req, 0, sizeof(req));
-       memset(&resp, 0, sizeof(resp));
-
        ret = ath12k_qmi_m3_load(ab);
        if (ret) {
                ath12k_err(ab, "failed to load m3 firmware: %d", ret);
@@ -2573,6 +2739,7 @@ static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab)
                               QMI_WLANFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN,
                               qmi_wlanfw_m3_info_req_msg_v01_ei, &req);
        if (ret < 0) {
+               qmi_txn_cancel(&txn);
                ath12k_warn(ab, "qmi failed to send M3 information request, err = %d\n",
                            ret);
                goto out;
@@ -2597,14 +2764,11 @@ out:
 static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab,
                                       u32 mode)
 {
-       struct qmi_wlanfw_wlan_mode_req_msg_v01 req;
-       struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp;
-       struct qmi_txn txn = {};
+       struct qmi_wlanfw_wlan_mode_req_msg_v01 req = {};
+       struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp = {};
+       struct qmi_txn txn;
        int ret = 0;
 
-       memset(&req, 0, sizeof(req));
-       memset(&resp, 0, sizeof(resp));
-
        req.mode = mode;
        req.hw_debug_valid = 1;
        req.hw_debug = 0;
@@ -2619,6 +2783,7 @@ static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab,
                               QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_wlan_mode_req_msg_v01_ei, &req);
        if (ret < 0) {
+               qmi_txn_cancel(&txn);
                ath12k_warn(ab, "qmi failed to send mode request, mode: %d, err = %d\n",
                            mode, ret);
                goto out;
@@ -2649,10 +2814,10 @@ out:
 static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab)
 {
        struct qmi_wlanfw_wlan_cfg_req_msg_v01 *req;
-       struct qmi_wlanfw_wlan_cfg_resp_msg_v01 resp;
+       struct qmi_wlanfw_wlan_cfg_resp_msg_v01 resp = {};
        struct ce_pipe_config *ce_cfg;
        struct service_to_pipe *svc_cfg;
-       struct qmi_txn txn = {};
+       struct qmi_txn txn;
        int ret = 0, pipe_num;
 
        ce_cfg  = (struct ce_pipe_config *)ab->qmi.ce_cfg.tgt_ce;
@@ -2662,8 +2827,6 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab)
        if (!req)
                return -ENOMEM;
 
-       memset(&resp, 0, sizeof(resp));
-
        req->host_version_valid = 1;
        strscpy(req->host_version, ATH12K_HOST_VERSION_STRING,
                sizeof(req->host_version));
@@ -2710,6 +2873,7 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab)
                               QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN,
                               qmi_wlanfw_wlan_cfg_req_msg_v01_ei, req);
        if (ret < 0) {
+               qmi_txn_cancel(&txn);
                ath12k_warn(ab, "qmi failed to send wlan config request, err = %d\n",
                            ret);
                goto out;
@@ -2733,6 +2897,49 @@ out:
        return ret;
 }
 
+static int ath12k_qmi_wlanfw_wlan_ini_send(struct ath12k_base *ab)
+{
+       struct qmi_wlanfw_wlan_ini_resp_msg_v01 resp = {};
+       struct qmi_wlanfw_wlan_ini_req_msg_v01 req = {};
+       struct qmi_txn txn;
+       int ret;
+
+       req.enable_fwlog_valid = true;
+       req.enable_fwlog = 1;
+
+       ret = qmi_txn_init(&ab->qmi.handle, &txn,
+                          qmi_wlanfw_wlan_ini_resp_msg_v01_ei, &resp);
+       if (ret < 0)
+               goto out;
+
+       ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                              ATH12K_QMI_WLANFW_WLAN_INI_REQ_V01,
+                              QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN,
+                              qmi_wlanfw_wlan_ini_req_msg_v01_ei, &req);
+       if (ret < 0) {
+               qmi_txn_cancel(&txn);
+               ath12k_warn(ab, "failed to send QMI wlan ini request: %d\n",
+                           ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS));
+       if (ret < 0) {
+               ath12k_warn(ab, "failed to receive QMI wlan ini request: %d\n", ret);
+               goto out;
+       }
+
+       if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+               ath12k_warn(ab, "QMI wlan ini response failure: %d %d\n",
+                           resp.resp.result, resp.resp.error);
+               ret = -EINVAL;
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
 void ath12k_qmi_firmware_stop(struct ath12k_base *ab)
 {
        int ret;
@@ -2749,6 +2956,12 @@ int ath12k_qmi_firmware_start(struct ath12k_base *ab,
 {
        int ret;
 
+       ret = ath12k_qmi_wlanfw_wlan_ini_send(ab);
+       if (ret < 0) {
+               ath12k_warn(ab, "qmi failed to send wlan fw ini: %d\n", ret);
+               return ret;
+       }
+
        ret = ath12k_qmi_wlanfw_wlan_cfg_send(ab);
        if (ret < 0) {
                ath12k_warn(ab, "qmi failed to send wlan cfg:%d\n", ret);
@@ -2792,6 +3005,8 @@ static int ath12k_qmi_event_server_arrive(struct ath12k_qmi *qmi)
        struct ath12k_base *ab = qmi->ab;
        int ret;
 
+       ath12k_qmi_phy_cap_send(ab);
+
        ret = ath12k_qmi_fw_ind_register_send(ab);
        if (ret < 0) {
                ath12k_warn(ab, "qmi failed to send FW indication QMI:%d\n", ret);
index e25bbaa125e83346e5cc7541aac196e89215a8ad..828ab2bf037df477e18b26d1493a2e2a73e57ef0 100644 (file)
@@ -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_QMI_H
@@ -141,6 +141,7 @@ struct ath12k_qmi {
        u32 target_mem_mode;
        bool target_mem_delayed;
        u8 cal_done;
+       u8 num_radios;
        struct target_info target;
        struct m3_mem_region m3_mem;
        unsigned int service_ins_id;
@@ -251,6 +252,22 @@ struct qmi_wlanfw_host_cap_resp_msg_v01 {
        struct qmi_response_type_v01 resp;
 };
 
+#define QMI_WLANFW_PHY_CAP_REQ_MSG_V01_MAX_LEN         0
+#define QMI_WLANFW_PHY_CAP_REQ_V01                     0x0057
+#define QMI_WLANFW_PHY_CAP_RESP_MSG_V01_MAX_LEN                18
+#define QMI_WLANFW_PHY_CAP_RESP_V01                    0x0057
+
+struct qmi_wlanfw_phy_cap_req_msg_v01 {
+};
+
+struct qmi_wlanfw_phy_cap_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+       u8 num_phy_valid;
+       u8 num_phy;
+       u8 board_id_valid;
+       u32 board_id;
+};
+
 #define QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN            54
 #define QMI_WLANFW_IND_REGISTER_REQ_V01                                0x0020
 #define QMI_WLANFW_IND_REGISTER_RESP_MSG_V01_MAX_LEN           18
@@ -559,6 +576,21 @@ struct qmi_wlanfw_wlan_cfg_resp_msg_v01 {
        struct qmi_response_type_v01 resp;
 };
 
+#define ATH12K_QMI_WLANFW_WLAN_INI_REQ_V01     0x002F
+#define ATH12K_QMI_WLANFW_WLAN_INI_RESP_V01    0x002F
+#define QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN                7
+#define QMI_WLANFW_WLAN_INI_RESP_MSG_V01_MAX_LEN       7
+
+struct qmi_wlanfw_wlan_ini_req_msg_v01 {
+       /* Must be set to true if enable_fwlog is being passed */
+       u8 enable_fwlog_valid;
+       u8 enable_fwlog;
+};
+
+struct qmi_wlanfw_wlan_ini_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+};
+
 int ath12k_qmi_firmware_start(struct ath12k_base *ab,
                              u32 mode);
 void ath12k_qmi_firmware_stop(struct ath12k_base *ab);
index f924bc13ccff5f1f85e47965084473b602319cab..f308e9a6ed551d932925550441394d05dd37bfdd 100644 (file)
@@ -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.
  */
 #include <linux/rtnetlink.h>
 #include "core.h"
@@ -48,7 +48,8 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct ath12k_wmi_init_country_arg arg;
-       struct ath12k *ar = hw->priv;
+       struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
+       struct ath12k *ar = ath12k_ah_to_ar(ah);
        int ret;
 
        ath12k_dbg(ar->ab, ATH12K_DBG_REG,
@@ -95,7 +96,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar)
        struct ieee80211_supported_band **bands;
        struct ath12k_wmi_scan_chan_list_arg *arg;
        struct ieee80211_channel *channel;
-       struct ieee80211_hw *hw = ar->hw;
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
        struct ath12k_wmi_channel_arg *ch;
        enum nl80211_band band;
        int num_channels = 0;
@@ -103,7 +104,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar)
 
        bands = hw->wiphy->bands;
        for (band = 0; band < NUM_NL80211_BANDS; band++) {
-               if (!bands[band])
+               if (!(ar->mac.sbands[band].channels && bands[band]))
                        continue;
 
                for (i = 0; i < bands[band]->n_channels; i++) {
@@ -129,7 +130,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar)
        ch = arg->channel;
 
        for (band = 0; band < NUM_NL80211_BANDS; band++) {
-               if (!bands[band])
+               if (!(ar->mac.sbands[band].channels && bands[band]))
                        continue;
 
                for (i = 0; i < bands[band]->n_channels; i++) {
@@ -199,7 +200,7 @@ static void ath12k_copy_regd(struct ieee80211_regdomain *regd_orig,
 
 int ath12k_regd_update(struct ath12k *ar, bool init)
 {
-       struct ieee80211_hw *hw = ar->hw;
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
        struct ieee80211_regdomain *regd, *regd_copy = NULL;
        int ret, regd_len, pdev_id;
        struct ath12k_base *ab;
index f72096684b7468403104af14a96776eeb966dd46..240737e1542d4e714de4bd05959e701ada51255a 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
 /*
  * Copyright (c) 2019-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.
  */
 
 #if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
@@ -140,6 +140,33 @@ TRACE_EVENT(ath12k_htt_rxdesc,
         )
 );
 
+TRACE_EVENT(ath12k_wmi_diag,
+           TP_PROTO(struct ath12k_base *ab, const void *data, size_t len),
+
+       TP_ARGS(ab, data, len),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(ab->dev))
+               __string(driver, dev_driver_string(ab->dev))
+               __field(u16, len)
+               __dynamic_array(u8, data, len)
+       ),
+
+       TP_fast_assign(
+               __assign_str(device, dev_name(ab->dev));
+               __assign_str(driver, dev_driver_string(ab->dev));
+               __entry->len = len;
+               memcpy(__get_dynamic_array(data), data, len);
+       ),
+
+       TP_printk(
+               "%s %s tlv diag len %d",
+               __get_str(driver),
+               __get_str(device),
+               __entry->len
+       )
+);
+
 #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
 
 /* we don't want to use include/trace/events */
index 11cc3005c0f983502c0392c52168b27d0a83c83e..2fa724e5851a90f767dc7ed8d3e48698cb60fbcb 100644 (file)
@@ -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.
  */
 #include <linux/skbuff.h>
 #include <linux/ctype.h>
@@ -359,8 +359,8 @@ static int ath12k_wmi_tlv_parse(struct ath12k_base *ar, const void **tb,
 }
 
 static const void **
-ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, const void *ptr,
-                          size_t len, gfp_t gfp)
+ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab,
+                          struct sk_buff *skb, gfp_t gfp)
 {
        const void **tb;
        int ret;
@@ -369,7 +369,7 @@ ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, const void *ptr,
        if (!tb)
                return ERR_PTR(-ENOMEM);
 
-       ret = ath12k_wmi_tlv_parse(ab, tb, ptr, len);
+       ret = ath12k_wmi_tlv_parse(ab, tb, skb->data, skb->len);
        if (ret) {
                kfree(tb);
                return ERR_PTR(ret);
@@ -4374,7 +4374,7 @@ static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buf
        const struct wmi_vdev_start_resp_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -4452,7 +4452,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 
        ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n");
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -4738,7 +4738,7 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff *
        const struct wmi_peer_delete_resp_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -4770,7 +4770,7 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab,
        const struct wmi_vdev_delete_resp_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -4790,15 +4790,15 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab,
        return 0;
 }
 
-static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, void *evt_buf,
-                                       u32 len, u32 *vdev_id,
-                                       u32 *tx_status)
+static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab,
+                                       struct sk_buff *skb,
+                                       u32 *vdev_id, u32 *tx_status)
 {
        const void **tb;
        const struct wmi_bcn_tx_status_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -4826,7 +4826,7 @@ static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_
        const struct wmi_vdev_stopped_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -4948,7 +4948,7 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id,
        if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status)
                info->flags |= IEEE80211_TX_STAT_ACK;
 
-       ieee80211_tx_status_irqsafe(ar->hw, msdu);
+       ieee80211_tx_status_irqsafe(ath12k_ar_to_hw(ar), msdu);
 
        num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx);
 
@@ -4970,7 +4970,7 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab,
        const struct wmi_mgmt_tx_compl_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5076,6 +5076,8 @@ static void ath12k_wmi_event_scan_bss_chan(struct ath12k *ar)
 
 static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq)
 {
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
+
        lockdep_assert_held(&ar->data_lock);
 
        switch (ar->scan.state) {
@@ -5087,7 +5089,7 @@ static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq)
                break;
        case ATH12K_SCAN_RUNNING:
        case ATH12K_SCAN_ABORTING:
-               ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
+               ar->scan_channel = ieee80211_get_channel(hw->wiphy, freq);
                break;
        }
 }
@@ -5141,7 +5143,7 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb,
        const struct wmi_scan_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5174,7 +5176,7 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf
        const struct wmi_peer_sta_kickout_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5201,7 +5203,7 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb,
        const struct wmi_roam_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5226,13 +5228,14 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb,
 static int freq_to_idx(struct ath12k *ar, int freq)
 {
        struct ieee80211_supported_band *sband;
+       struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
        int band, ch, idx = 0;
 
        for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
                if (!ar->mac.sbands[band].channels)
                        continue;
 
-               sband = ar->hw->wiphy->bands[band];
+               sband = hw->wiphy->bands[band];
                if (!sband)
                        continue;
 
@@ -5245,14 +5248,14 @@ exit:
        return idx;
 }
 
-static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, u8 *evt_buf,
-                                   u32 len, struct wmi_chan_info_event *ch_info_ev)
+static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
+                                   struct wmi_chan_info_event *ch_info_ev)
 {
        const void **tb;
        const struct wmi_chan_info_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5291,7 +5294,7 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
        const struct wmi_pdev_bss_chan_info_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5331,7 +5334,7 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk
        const struct wmi_vdev_install_key_compl_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5362,7 +5365,7 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff
        const struct wmi_peer_assoc_conf_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5384,13 +5387,13 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff
 }
 
 static int
-ath12k_pull_pdev_temp_ev(struct ath12k_base *ab, u8 *evt_buf,
-                        u32 len, const struct wmi_pdev_temperature_event *ev)
+ath12k_pull_pdev_temp_ev(struct ath12k_base *ab, struct sk_buff *skb,
+                        const struct wmi_pdev_temperature_event *ev)
 {
        const void **tb;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -5725,8 +5728,7 @@ static void ath12k_bcn_tx_status_event(struct ath12k_base *ab, struct sk_buff *s
 {
        u32 vdev_id, tx_status;
 
-       if (ath12k_pull_bcn_tx_status_ev(ab, skb->data, skb->len,
-                                        &vdev_id, &tx_status) != 0) {
+       if (ath12k_pull_bcn_tx_status_ev(ab, skb, &vdev_id, &tx_status) != 0) {
                ath12k_warn(ab, "failed to extract bcn tx status");
                return;
        }
@@ -5864,7 +5866,7 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)
                   status->freq, status->band, status->signal,
                   status->rate_idx);
 
-       ieee80211_rx_ni(ar->hw, skb);
+       ieee80211_rx_ni(ath12k_ar_to_hw(ar), skb);
 
 exit:
        rcu_read_unlock();
@@ -6037,7 +6039,7 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff
                goto exit;
        }
 
-       sta = ieee80211_find_sta_by_ifaddr(ar->hw,
+       sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
                                           arg.mac_addr, NULL);
        if (!sta) {
                ath12k_warn(ab, "Spurious quick kickout for STA %pM\n",
@@ -6110,7 +6112,7 @@ static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)
        /* HW channel counters frequency value in hertz */
        u32 cc_freq_hz = ab->cc_freq_hz;
 
-       if (ath12k_pull_chan_info_ev(ab, skb->data, skb->len, &ch_info_ev) != 0) {
+       if (ath12k_pull_chan_info_ev(ab, skb, &ch_info_ev) != 0) {
                ath12k_warn(ab, "failed to extract chan info event");
                return;
        }
@@ -6395,7 +6397,7 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab,
        const struct wmi_pdev_ctl_failsafe_chk_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6460,7 +6462,7 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab,
        const u32 *vdev_ids;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6494,7 +6496,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
        struct ath12k *ar;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6531,7 +6533,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
        if (ar->dfs_block_radar_events)
                ath12k_info(ab, "DFS Radar detected, but ignored as requested\n");
        else
-               ieee80211_radar_detected(ar->hw);
+               ieee80211_radar_detected(ath12k_ar_to_hw(ar));
 
 exit:
        rcu_read_unlock();
@@ -6546,7 +6548,7 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab,
        struct ath12k *ar;
        struct wmi_pdev_temperature_event ev = {0};
 
-       if (ath12k_pull_pdev_temp_ev(ab, skb->data, skb->len, &ev) != 0) {
+       if (ath12k_pull_pdev_temp_ev(ab, skb, &ev) != 0) {
                ath12k_warn(ab, "failed to extract pdev temperature event");
                return;
        }
@@ -6573,7 +6575,7 @@ static void ath12k_fils_discovery_event(struct ath12k_base *ab,
        const struct wmi_fils_discovery_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab,
@@ -6603,7 +6605,7 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
        const struct wmi_probe_resp_tx_status_event *ev;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab,
@@ -6635,7 +6637,7 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
        const void **tb;
        int ret;
 
-       tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
        if (IS_ERR(tb)) {
                ret = PTR_ERR(tb);
                ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
@@ -6662,6 +6664,12 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
        kfree(tb);
 }
 
+static void
+ath12k_wmi_diag_event(struct ath12k_base *ab, struct sk_buff *skb)
+{
+       trace_ath12k_wmi_diag(ab, skb->data, skb->len);
+}
+
 static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
 {
        struct wmi_cmd_hdr *cmd_hdr;
@@ -6772,6 +6780,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
        case WMI_VDEV_DELETE_RESP_EVENTID:
                ath12k_vdev_delete_resp_event(ab, skb);
                break;
+       case WMI_DIAG_EVENTID:
+               ath12k_wmi_diag_event(ab, skb);
+               break;
        /* TODO: Add remaining events */
        default:
                ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
index 9bfaadfa6c0099f73706f79f5d5eb51dad0d0d57..1a6697b6e3b41fd6de77cd09a875986733787cc1 100644 (file)
@@ -144,7 +144,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int ath_ahb_remove(struct platform_device *pdev)
+static void ath_ahb_remove(struct platform_device *pdev)
 {
        struct ieee80211_hw *hw = platform_get_drvdata(pdev);
 
@@ -155,13 +155,11 @@ static int ath_ahb_remove(struct platform_device *pdev)
                free_irq(sc->irq, sc);
                ieee80211_free_hw(sc->hw);
        }
-
-       return 0;
 }
 
 static struct platform_driver ath_ahb_driver = {
        .probe      = ath_ahb_probe,
-       .remove     = ath_ahb_remove,
+       .remove_new = ath_ahb_remove,
        .driver         = {
                .name   = "ath9k",
        },
index 988222cea9dfe760073e0312de65206343b65e50..acc84e6711b0e10dfcab53b02e0afaa5b077c1ff 100644 (file)
@@ -643,7 +643,7 @@ static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
                                conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
                                conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
                        } else if (antcomb->rssi_sub >
-                                  antcomb->rssi_lna1) {
+                                  antcomb->rssi_lna2) {
                                /* set to A-B */
                                conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
                                conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
index 57e2b4c89125e4bf95c87e9c99458772733b59e8..ad72a30b67c3b8afb468f6d21f79e949a5d1bae6 100644 (file)
 #define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN  0x0000000e
 #define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN_S 1
 
-#define AR_PHY_POWER_TX_RATE1   0x9934
-#define AR_PHY_POWER_TX_RATE2   0x9938
 #define AR_PHY_POWER_TX_RATE_MAX    0x993c
 #define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040
 #define PHY_AGC_CLR             0x10000000
 
 #define AR_PHY_TX_IQCAL_STATUS_B2_FAILED    0x00000001
 
-/*
- * AGC 3 Register Map
- */
-#define AR_AGC3_BASE   0xce00
-
-#define AR_PHY_RSSI_3            (AR_AGC3_BASE + 0x180)
-
 /* GLB Registers */
 #define AR_GLB_BASE    0x20000
 #define AR_GLB_GPIO_CONTROL    (AR_GLB_BASE)
index 955147ab48a2fae66cb9e54813ff534cf23a4cbd..f50994910eae0f9bfa51e7018d5c9805e83021a2 100644 (file)
 #ifndef REG_AIC_H
 #define REG_AIC_H
 
-#define AR_SM_BASE                              0xa200
-#define AR_SM1_BASE                             0xb200
-#define AR_AGC_BASE                             0x9e00
-
 #define AR_PHY_AIC_CTRL_0_B0                    (AR_SM_BASE + 0x4b0)
 #define AR_PHY_AIC_CTRL_1_B0                    (AR_SM_BASE + 0x4b4)
 #define AR_PHY_AIC_CTRL_2_B0                    (AR_SM_BASE + 0x4b8)