source "drivers/net/wireless/ath/wil6210/Kconfig"
 source "drivers/net/wireless/ath/ath10k/Kconfig"
 source "drivers/net/wireless/ath/wcn36xx/Kconfig"
+source "drivers/net/wireless/ath/ath11k/Kconfig"
 
 endif
 
 obj-$(CONFIG_WIL6210)          += wil6210/
 obj-$(CONFIG_ATH10K)           += ath10k/
 obj-$(CONFIG_WCN36XX)          += wcn36xx/
+obj-$(CONFIG_ATH11K)           += ath11k/
 
 obj-$(CONFIG_ATH_COMMON)       += ath.o
 
 
--- /dev/null
+# SPDX-License-Identifier: BSD-3-Clause-Clear
+config ATH11K
+       tristate "Qualcomm Technologies 802.11ax chipset support"
+       depends on MAC80211 && HAS_DMA
+       depends on REMOTEPROC
+       depends on ARCH_QCOM || COMPILE_TEST
+       select ATH_COMMON
+       select QCOM_QMI_HELPERS
+       ---help---
+         This module adds support for Qualcomm Technologies 802.11ax family of
+         chipsets.
+
+         If you choose to build a module, it'll be called ath11k.
+
+config ATH11K_DEBUG
+       bool "QCA ath11k debugging"
+       depends on ATH11K
+       ---help---
+         Enables debug support
+
+         If unsure, say Y to make it easier to debug problems.
+
+config ATH11K_DEBUGFS
+       bool "QCA ath11k debugfs support"
+       depends on ATH11K && DEBUG_FS
+       ---help---
+         Enable ath11k debugfs support
+
+         If unsure, say Y to make it easier to debug problems.
+
+config ATH11K_TRACING
+       bool "ath11k tracing support"
+       depends on ATH11K && EVENT_TRACING
+       ---help---
+         Select this to use ath11k tracing infrastructure.
 
--- /dev/null
+# SPDX-License-Identifier: BSD-3-Clause-Clear
+obj-$(CONFIG_ATH11K) += ath11k.o
+ath11k-y += core.o \
+           hal.o \
+           hal_tx.o \
+           hal_rx.o \
+           ahb.o \
+           wmi.o \
+           mac.o \
+           reg.o \
+           htc.o \
+           qmi.o \
+           dp.o  \
+           dp_tx.o \
+           dp_rx.o \
+           debug.o \
+           ce.o \
+           peer.o
+
+ath11k-$(CONFIG_ATH11K_DEBUGFS) += debug_htt_stats.o
+ath11k-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o
+ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o
+ath11k-$(CONFIG_ATH11K_TRACING) += trace.o
+
+# for tracing framework to find trace.h
+CFLAGS_trace.o := -I$(src)
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
+#include "ahb.h"
+#include "debug.h"
+#include <linux/remoteproc.h>
+
+static const struct of_device_id ath11k_ahb_of_match[] = {
+       /* TODO: Should we change the compatible string to something similar
+        * to one that ath10k uses?
+        */
+       { .compatible = "qcom,ipq8074-wifi",
+         .data = (void *)ATH11K_HW_IPQ8074,
+       },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
+
+/* Target firmware's Copy Engine configuration. */
+static const struct ce_pipe_config target_ce_config_wlan[] = {
+       /* CE0: host->target HTC control and raw streams */
+       {
+               .pipenum = __cpu_to_le32(0),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE1: target->host HTT + HTC control */
+       {
+               .pipenum = __cpu_to_le32(1),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE2: target->host WMI */
+       {
+               .pipenum = __cpu_to_le32(2),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE3: host->target WMI */
+       {
+               .pipenum = __cpu_to_le32(3),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE4: host->target HTT */
+       {
+               .pipenum = __cpu_to_le32(4),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(256),
+               .nbytes_max = __cpu_to_le32(256),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE5: target->host Pktlog */
+       {
+               .pipenum = __cpu_to_le32(5),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(0),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE6: Reserved for target autonomous hif_memcpy */
+       {
+               .pipenum = __cpu_to_le32(6),
+               .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(65535),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE7 used only by Host */
+       {
+               .pipenum = __cpu_to_le32(7),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE8 target->host used only by IPA */
+       {
+               .pipenum = __cpu_to_le32(8),
+               .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(65535),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE9 host->target HTT */
+       {
+               .pipenum = __cpu_to_le32(9),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE10 target->host HTT */
+       {
+               .pipenum = __cpu_to_le32(10),
+               .pipedir = __cpu_to_le32(PIPEDIR_INOUT_H2H),
+               .nentries = __cpu_to_le32(0),
+               .nbytes_max = __cpu_to_le32(0),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+
+       /* CE11 Not used */
+       {
+               .pipenum = __cpu_to_le32(0),
+               .pipedir = __cpu_to_le32(0),
+               .nentries = __cpu_to_le32(0),
+               .nbytes_max = __cpu_to_le32(0),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
+       },
+};
+
+/* Map from service/endpoint to Copy Engine.
+ * This table is derived from the CE_PCI TABLE, above.
+ * It is passed to the Target at startup for use by firmware.
+ */
+static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),  /* out = UL = host -> target */
+               .pipenum = __cpu_to_le32(3),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VO),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(2),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),  /* out = UL = host -> target */
+               .pipenum = __cpu_to_le32(3),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BK),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(2),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),  /* out = UL = host -> target */
+               .pipenum = __cpu_to_le32(3),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_BE),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(2),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),  /* out = UL = host -> target */
+               .pipenum = __cpu_to_le32(3),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_DATA_VI),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(2),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),  /* out = UL = host -> target */
+               .pipenum = __cpu_to_le32(3),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(2),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),  /* out = UL = host -> target */
+               .pipenum = __cpu_to_le32(7),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(2),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),  /* out = UL = host -> target */
+               .pipenum = __cpu_to_le32(9),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(2),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),  /* out = UL = host -> target */
+               .pipenum = __cpu_to_le32(0),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_RSVD_CTRL),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(1),
+       },
+       { /* not used */
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_TEST_RAW_STREAMS),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),  /* out = UL = host -> target */
+               .pipenum = __cpu_to_le32(0),
+       },
+       { /* not used */
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_TEST_RAW_STREAMS),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(1),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),  /* out = UL = host -> target */
+               .pipenum = __cpu_to_le32(4),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_HTT_DATA_MSG),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(1),
+       },
+       {
+               .service_id = __cpu_to_le32(ATH11K_HTC_SVC_ID_PKT_LOG),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),   /* in = DL = target -> host */
+               .pipenum = __cpu_to_le32(5),
+       },
+
+       /* (Additions here) */
+
+       { /* terminator entry */ }
+};
+
+#define ATH11K_IRQ_CE0_OFFSET 4
+
+static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
+       "misc-pulse1",
+       "misc-latch",
+       "sw-exception",
+       "watchdog",
+       "ce0",
+       "ce1",
+       "ce2",
+       "ce3",
+       "ce4",
+       "ce5",
+       "ce6",
+       "ce7",
+       "ce8",
+       "ce9",
+       "ce10",
+       "ce11",
+       "host2wbm-desc-feed",
+       "host2reo-re-injection",
+       "host2reo-command",
+       "host2rxdma-monitor-ring3",
+       "host2rxdma-monitor-ring2",
+       "host2rxdma-monitor-ring1",
+       "reo2ost-exception",
+       "wbm2host-rx-release",
+       "reo2host-status",
+       "reo2host-destination-ring4",
+       "reo2host-destination-ring3",
+       "reo2host-destination-ring2",
+       "reo2host-destination-ring1",
+       "rxdma2host-monitor-destination-mac3",
+       "rxdma2host-monitor-destination-mac2",
+       "rxdma2host-monitor-destination-mac1",
+       "ppdu-end-interrupts-mac3",
+       "ppdu-end-interrupts-mac2",
+       "ppdu-end-interrupts-mac1",
+       "rxdma2host-monitor-status-ring-mac3",
+       "rxdma2host-monitor-status-ring-mac2",
+       "rxdma2host-monitor-status-ring-mac1",
+       "host2rxdma-host-buf-ring-mac3",
+       "host2rxdma-host-buf-ring-mac2",
+       "host2rxdma-host-buf-ring-mac1",
+       "rxdma2host-destination-ring-mac3",
+       "rxdma2host-destination-ring-mac2",
+       "rxdma2host-destination-ring-mac1",
+       "host2tcl-input-ring4",
+       "host2tcl-input-ring3",
+       "host2tcl-input-ring2",
+       "host2tcl-input-ring1",
+       "wbm2host-tx-completions-ring3",
+       "wbm2host-tx-completions-ring2",
+       "wbm2host-tx-completions-ring1",
+       "tcl2host-status-ring",
+};
+
+#define ATH11K_TX_RING_MASK_0 0x1
+#define ATH11K_TX_RING_MASK_1 0x2
+#define ATH11K_TX_RING_MASK_2 0x4
+
+#define ATH11K_RX_RING_MASK_0 0x1
+#define ATH11K_RX_RING_MASK_1 0x2
+#define ATH11K_RX_RING_MASK_2 0x4
+#define ATH11K_RX_RING_MASK_3 0x8
+
+#define ATH11K_RX_ERR_RING_MASK_0 0x1
+
+#define ATH11K_RX_WBM_REL_RING_MASK_0 0x1
+
+#define ATH11K_REO_STATUS_RING_MASK_0 0x1
+
+#define ATH11K_RXDMA2HOST_RING_MASK_0 0x1
+#define ATH11K_RXDMA2HOST_RING_MASK_1 0x2
+#define ATH11K_RXDMA2HOST_RING_MASK_2 0x4
+
+#define ATH11K_HOST2RXDMA_RING_MASK_0 0x1
+#define ATH11K_HOST2RXDMA_RING_MASK_1 0x2
+#define ATH11K_HOST2RXDMA_RING_MASK_2 0x4
+
+#define ATH11K_RX_MON_STATUS_RING_MASK_0 0x1
+#define ATH11K_RX_MON_STATUS_RING_MASK_1 0x2
+#define ATH11K_RX_MON_STATUS_RING_MASK_2 0x4
+
+const u8 ath11k_tx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+       ATH11K_TX_RING_MASK_0,
+       ATH11K_TX_RING_MASK_1,
+       ATH11K_TX_RING_MASK_2,
+};
+
+const u8 rx_mon_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+       0, 0, 0, 0,
+       ATH11K_RX_MON_STATUS_RING_MASK_0,
+       ATH11K_RX_MON_STATUS_RING_MASK_1,
+       ATH11K_RX_MON_STATUS_RING_MASK_2,
+};
+
+const u8 ath11k_rx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+       0, 0, 0, 0, 0, 0, 0,
+       ATH11K_RX_RING_MASK_0,
+       ATH11K_RX_RING_MASK_1,
+       ATH11K_RX_RING_MASK_2,
+       ATH11K_RX_RING_MASK_3,
+};
+
+const u8 ath11k_rx_err_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+       ATH11K_RX_ERR_RING_MASK_0,
+};
+
+const u8 ath11k_rx_wbm_rel_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+       ATH11K_RX_WBM_REL_RING_MASK_0,
+};
+
+const u8 ath11k_reo_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+       ATH11K_REO_STATUS_RING_MASK_0,
+};
+
+const u8 ath11k_rxdma2host_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+       ATH11K_RXDMA2HOST_RING_MASK_0,
+       ATH11K_RXDMA2HOST_RING_MASK_1,
+       ATH11K_RXDMA2HOST_RING_MASK_2,
+};
+
+const u8 ath11k_host2rxdma_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX] = {
+       ATH11K_HOST2RXDMA_RING_MASK_0,
+       ATH11K_HOST2RXDMA_RING_MASK_1,
+       ATH11K_HOST2RXDMA_RING_MASK_2,
+};
+
+/* enum ext_irq_num - irq numbers that can be used by external modules
+ * like datapath
+ */
+enum ext_irq_num {
+       host2wbm_desc_feed = 16,
+       host2reo_re_injection,
+       host2reo_command,
+       host2rxdma_monitor_ring3,
+       host2rxdma_monitor_ring2,
+       host2rxdma_monitor_ring1,
+       reo2host_exception,
+       wbm2host_rx_release,
+       reo2host_status,
+       reo2host_destination_ring4,
+       reo2host_destination_ring3,
+       reo2host_destination_ring2,
+       reo2host_destination_ring1,
+       rxdma2host_monitor_destination_mac3,
+       rxdma2host_monitor_destination_mac2,
+       rxdma2host_monitor_destination_mac1,
+       ppdu_end_interrupts_mac3,
+       ppdu_end_interrupts_mac2,
+       ppdu_end_interrupts_mac1,
+       rxdma2host_monitor_status_ring_mac3,
+       rxdma2host_monitor_status_ring_mac2,
+       rxdma2host_monitor_status_ring_mac1,
+       host2rxdma_host_buf_ring_mac3,
+       host2rxdma_host_buf_ring_mac2,
+       host2rxdma_host_buf_ring_mac1,
+       rxdma2host_destination_ring_mac3,
+       rxdma2host_destination_ring_mac2,
+       rxdma2host_destination_ring_mac1,
+       host2tcl_input_ring4,
+       host2tcl_input_ring3,
+       host2tcl_input_ring2,
+       host2tcl_input_ring1,
+       wbm2host_tx_completions_ring3,
+       wbm2host_tx_completions_ring2,
+       wbm2host_tx_completions_ring1,
+       tcl2host_status_ring,
+};
+
+static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab)
+{
+       int i;
+
+       for (i = 0; i < CE_COUNT; i++) {
+               struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
+
+               if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
+                       continue;
+
+               tasklet_kill(&ce_pipe->intr_tq);
+       }
+}
+
+static void ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)
+{
+       int i;
+
+       for (i = 0; i < irq_grp->num_irq; i++)
+               disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+}
+
+static void __ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
+{
+       struct sk_buff *skb;
+       int i;
+
+       for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+               struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
+
+               ath11k_ahb_ext_grp_disable(irq_grp);
+
+               napi_synchronize(&irq_grp->napi);
+               napi_disable(&irq_grp->napi);
+
+               while ((skb = __skb_dequeue(&irq_grp->pending_q)))
+                       dev_kfree_skb_any(skb);
+       }
+}
+
+static void ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)
+{
+       int i;
+
+       for (i = 0; i < irq_grp->num_irq; i++)
+               enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
+}
+
+static void ath11k_ahb_setbit32(struct ath11k_base *ab, u8 bit, u32 offset)
+{
+       u32 val;
+
+       val = ath11k_ahb_read32(ab, offset);
+       ath11k_ahb_write32(ab, offset, val | BIT(bit));
+}
+
+static void ath11k_ahb_clearbit32(struct ath11k_base *ab, u8 bit, u32 offset)
+{
+       u32 val;
+
+       val = ath11k_ahb_read32(ab, offset);
+       ath11k_ahb_write32(ab, offset, val & ~BIT(bit));
+}
+
+static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
+{
+       const struct ce_pipe_config *ce_config;
+
+       ce_config = &target_ce_config_wlan[ce_id];
+       if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT)
+               ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
+
+       if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) {
+               ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
+               ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
+                                   CE_HOST_IE_3_ADDRESS);
+       }
+}
+
+static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
+{
+       const struct ce_pipe_config *ce_config;
+
+       ce_config = &target_ce_config_wlan[ce_id];
+       if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_OUT)
+               ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
+
+       if (__le32_to_cpu(ce_config->pipedir) & PIPEDIR_IN) {
+               ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
+               ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
+                                     CE_HOST_IE_3_ADDRESS);
+       }
+}
+
+static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab)
+{
+       int i;
+       int irq_idx;
+
+       for (i = 0; i < CE_COUNT; i++) {
+               if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
+                       continue;
+
+               irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
+               synchronize_irq(ab->irq_num[irq_idx]);
+       }
+}
+
+static void ath11k_ahb_sync_ext_irqs(struct ath11k_base *ab)
+{
+       int i, j;
+       int irq_idx;
+
+       for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+               struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
+
+               for (j = 0; j < irq_grp->num_irq; j++) {
+                       irq_idx = irq_grp->irqs[j];
+                       synchronize_irq(ab->irq_num[irq_idx]);
+               }
+       }
+}
+
+static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab)
+{
+       int i;
+
+       for (i = 0; i < CE_COUNT; i++) {
+               if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
+                       continue;
+               ath11k_ahb_ce_irq_enable(ab, i);
+       }
+}
+
+static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab)
+{
+       int i;
+
+       for (i = 0; i < CE_COUNT; i++) {
+               if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
+                       continue;
+               ath11k_ahb_ce_irq_disable(ab, i);
+       }
+}
+
+int ath11k_ahb_start(struct ath11k_base *ab)
+{
+       ath11k_ahb_ce_irqs_enable(ab);
+       ath11k_ce_rx_post_buf(ab);
+
+       return 0;
+}
+
+void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab)
+{
+       int i;
+
+       for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+               struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
+
+               napi_enable(&irq_grp->napi);
+               ath11k_ahb_ext_grp_enable(irq_grp);
+       }
+}
+
+void ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)
+{
+       __ath11k_ahb_ext_irq_disable(ab);
+       ath11k_ahb_sync_ext_irqs(ab);
+}
+
+void ath11k_ahb_stop(struct ath11k_base *ab)
+{
+       if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
+               ath11k_ahb_ce_irqs_disable(ab);
+       ath11k_ahb_sync_ce_irqs(ab);
+       ath11k_ahb_kill_tasklets(ab);
+       del_timer_sync(&ab->rx_replenish_retry);
+       ath11k_ce_cleanup_pipes(ab);
+}
+
+int ath11k_ahb_power_up(struct ath11k_base *ab)
+{
+       int ret;
+
+       ret = rproc_boot(ab->tgt_rproc);
+       if (ret)
+               ath11k_err(ab, "failed to boot the remote processor Q6\n");
+
+       return ret;
+}
+
+void ath11k_ahb_power_down(struct ath11k_base *ab)
+{
+       rproc_shutdown(ab->tgt_rproc);
+}
+
+static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
+{
+       struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
+
+       cfg->tgt_ce = (u8 *)target_ce_config_wlan;
+       cfg->tgt_ce_len = sizeof(target_ce_config_wlan);
+
+       cfg->svc_to_ce_map = (u8 *)target_service_to_ce_map_wlan;
+       cfg->svc_to_ce_map_len = sizeof(target_service_to_ce_map_wlan);
+}
+
+static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
+{
+       int i, j;
+
+       for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+               struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
+
+               for (j = 0; j < irq_grp->num_irq; j++)
+                       free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
+       }
+}
+
+static void ath11k_ahb_free_irq(struct ath11k_base *ab)
+{
+       int irq_idx;
+       int i;
+
+       for (i = 0; i < CE_COUNT; i++) {
+               if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
+                       continue;
+               irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
+               free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);
+       }
+
+       ath11k_ahb_free_ext_irq(ab);
+}
+
+static void ath11k_ahb_ce_tasklet(unsigned long data)
+{
+       struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data;
+
+       ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
+
+       ath11k_ahb_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
+}
+
+static irqreturn_t ath11k_ahb_ce_interrupt_handler(int irq, void *arg)
+{
+       struct ath11k_ce_pipe *ce_pipe = arg;
+
+       ath11k_ahb_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
+
+       tasklet_schedule(&ce_pipe->intr_tq);
+
+       return IRQ_HANDLED;
+}
+
+static int ath11k_ahb_ext_grp_napi_poll(struct napi_struct *napi, int budget)
+{
+       struct ath11k_ext_irq_grp *irq_grp = container_of(napi,
+                                               struct ath11k_ext_irq_grp,
+                                               napi);
+       struct ath11k_base *ab = irq_grp->ab;
+       int work_done;
+
+       work_done = ath11k_dp_service_srng(ab, irq_grp, budget);
+       if (work_done < budget) {
+               napi_complete_done(napi, work_done);
+               ath11k_ahb_ext_grp_enable(irq_grp);
+       }
+
+       if (work_done > budget)
+               work_done = budget;
+
+       return work_done;
+}
+
+static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg)
+{
+       struct ath11k_ext_irq_grp *irq_grp = arg;
+
+       ath11k_ahb_ext_grp_disable(irq_grp);
+
+       napi_schedule(&irq_grp->napi);
+
+       return IRQ_HANDLED;
+}
+
+static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab)
+{
+       int i, j;
+       int irq;
+       int ret;
+
+       for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
+               struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
+               u32 num_irq = 0;
+
+               irq_grp->ab = ab;
+               irq_grp->grp_id = i;
+               init_dummy_netdev(&irq_grp->napi_ndev);
+               netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
+                              ath11k_ahb_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
+               __skb_queue_head_init(&irq_grp->pending_q);
+
+               for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) {
+                       if (ath11k_tx_ring_mask[i] & BIT(j)) {
+                               irq_grp->irqs[num_irq++] =
+                                       wbm2host_tx_completions_ring1 - j;
+                       }
+
+                       if (ath11k_rx_ring_mask[i] & BIT(j)) {
+                               irq_grp->irqs[num_irq++] =
+                                       reo2host_destination_ring1 - j;
+                       }
+
+                       if (ath11k_rx_err_ring_mask[i] & BIT(j))
+                               irq_grp->irqs[num_irq++] = reo2host_exception;
+
+                       if (ath11k_rx_wbm_rel_ring_mask[i] & BIT(j))
+                               irq_grp->irqs[num_irq++] = wbm2host_rx_release;
+
+                       if (ath11k_reo_status_ring_mask[i] & BIT(j))
+                               irq_grp->irqs[num_irq++] = reo2host_status;
+
+                       if (j < MAX_RADIOS) {
+                               if (ath11k_rxdma2host_ring_mask[i] & BIT(j)) {
+                                       irq_grp->irqs[num_irq++] =
+                                               rxdma2host_destination_ring_mac1
+                                               - ath11k_core_get_hw_mac_id(ab, j);
+                               }
+
+                               if (ath11k_host2rxdma_ring_mask[i] & BIT(j)) {
+                                       irq_grp->irqs[num_irq++] =
+                                               host2rxdma_host_buf_ring_mac1
+                                               - ath11k_core_get_hw_mac_id(ab, j);
+                               }
+
+                               if (rx_mon_status_ring_mask[i] & BIT(j)) {
+                                       irq_grp->irqs[num_irq++] =
+                                               ppdu_end_interrupts_mac1 -
+                                               ath11k_core_get_hw_mac_id(ab, j);
+                                       irq_grp->irqs[num_irq++] =
+                                               rxdma2host_monitor_status_ring_mac1 -
+                                               ath11k_core_get_hw_mac_id(ab, j);
+                               }
+                       }
+               }
+               irq_grp->num_irq = num_irq;
+
+               for (j = 0; j < irq_grp->num_irq; j++) {
+                       int irq_idx = irq_grp->irqs[j];
+
+                       irq = platform_get_irq_byname(ab->pdev,
+                                                     irq_name[irq_idx]);
+                       ab->irq_num[irq_idx] = irq;
+                       irq_set_status_flags(irq, IRQ_NOAUTOEN);
+                       ret = request_irq(irq, ath11k_ahb_ext_interrupt_handler,
+                                         IRQF_TRIGGER_RISING,
+                                         irq_name[irq_idx], irq_grp);
+                       if (ret) {
+                               ath11k_err(ab, "failed request_irq for %d\n",
+                                          irq);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int ath11k_ahb_config_irq(struct ath11k_base *ab)
+{
+       int irq, irq_idx, i;
+       int ret;
+
+       /* Configure CE irqs */
+       for (i = 0; i < CE_COUNT; i++) {
+               struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
+
+               if (ath11k_ce_get_attr_flags(i) & CE_ATTR_DIS_INTR)
+                       continue;
+
+               irq_idx = ATH11K_IRQ_CE0_OFFSET + i;
+
+               tasklet_init(&ce_pipe->intr_tq, ath11k_ahb_ce_tasklet,
+                            (unsigned long)ce_pipe);
+               irq = platform_get_irq_byname(ab->pdev, irq_name[irq_idx]);
+               ret = request_irq(irq, ath11k_ahb_ce_interrupt_handler,
+                                 IRQF_TRIGGER_RISING, irq_name[irq_idx],
+                                 ce_pipe);
+               if (ret)
+                       return ret;
+
+               ab->irq_num[irq_idx] = irq;
+       }
+
+       /* Configure external interrupts */
+       ret = ath11k_ahb_ext_irq_config(ab);
+
+       return ret;
+}
+
+int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
+                                  u8 *ul_pipe, u8 *dl_pipe)
+{
+       const struct service_to_pipe *entry;
+       bool ul_set = false, dl_set = false;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
+               entry = &target_service_to_ce_map_wlan[i];
+
+               if (__le32_to_cpu(entry->service_id) != service_id)
+                       continue;
+
+               switch (__le32_to_cpu(entry->pipedir)) {
+               case PIPEDIR_NONE:
+                       break;
+               case PIPEDIR_IN:
+                       WARN_ON(dl_set);
+                       *dl_pipe = __le32_to_cpu(entry->pipenum);
+                       dl_set = true;
+                       break;
+               case PIPEDIR_OUT:
+                       WARN_ON(ul_set);
+                       *ul_pipe = __le32_to_cpu(entry->pipenum);
+                       ul_set = true;
+                       break;
+               case PIPEDIR_INOUT:
+                       WARN_ON(dl_set);
+                       WARN_ON(ul_set);
+                       *dl_pipe = __le32_to_cpu(entry->pipenum);
+                       *ul_pipe = __le32_to_cpu(entry->pipenum);
+                       dl_set = true;
+                       ul_set = true;
+                       break;
+               }
+       }
+
+       if (WARN_ON(!ul_set || !dl_set))
+               return -ENOENT;
+
+       return 0;
+}
+
+static int ath11k_ahb_probe(struct platform_device *pdev)
+{
+       struct ath11k_base *ab;
+       const struct of_device_id *of_id;
+       struct resource *mem_res;
+       void __iomem *mem;
+       int ret;
+
+       of_id = of_match_device(ath11k_ahb_of_match, &pdev->dev);
+       if (!of_id) {
+               dev_err(&pdev->dev, "failed to find matching device tree id\n");
+               return -EINVAL;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               dev_err(&pdev->dev, "failed to get IO memory resource\n");
+               return -ENXIO;
+       }
+
+       mem = devm_ioremap_resource(&pdev->dev, mem_res);
+       if (IS_ERR(mem)) {
+               dev_err(&pdev->dev, "ioremap error\n");
+               return PTR_ERR(mem);
+       }
+
+       ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(&pdev->dev, "failed to set 32-bit consistent dma\n");
+               return ret;
+       }
+
+       ab = ath11k_core_alloc(&pdev->dev);
+       if (!ab) {
+               dev_err(&pdev->dev, "failed to allocate ath11k base\n");
+               return -ENOMEM;
+       }
+
+       ab->pdev = pdev;
+       ab->hw_rev = (enum ath11k_hw_rev)of_id->data;
+       ab->mem = mem;
+       ab->mem_len = resource_size(mem_res);
+       platform_set_drvdata(pdev, ab);
+
+       ret = ath11k_hal_srng_init(ab);
+       if (ret)
+               goto err_core_free;
+
+       ret = ath11k_ce_alloc_pipes(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
+               goto err_hal_srng_deinit;
+       }
+
+       ath11k_ahb_init_qmi_ce_config(ab);
+
+       ret = ath11k_ahb_config_irq(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to configure irq: %d\n", ret);
+               goto err_ce_free;
+       }
+
+       ret = ath11k_core_init(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to init core: %d\n", ret);
+               goto err_ce_free;
+       }
+
+       return 0;
+
+err_ce_free:
+       ath11k_ce_free_pipes(ab);
+
+err_hal_srng_deinit:
+       ath11k_hal_srng_deinit(ab);
+
+err_core_free:
+       ath11k_core_free(ab);
+       platform_set_drvdata(pdev, NULL);
+
+       return ret;
+}
+
+static int ath11k_ahb_remove(struct platform_device *pdev)
+{
+       struct ath11k_base *ab = platform_get_drvdata(pdev);
+
+       reinit_completion(&ab->driver_recovery);
+
+       if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags))
+               wait_for_completion_timeout(&ab->driver_recovery,
+                                           ATH11K_AHB_RECOVERY_TIMEOUT);
+
+       set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
+       cancel_work_sync(&ab->restart_work);
+
+       ath11k_core_deinit(ab);
+       ath11k_ahb_free_irq(ab);
+
+       ath11k_hal_srng_deinit(ab);
+       ath11k_ce_free_pipes(ab);
+       ath11k_core_free(ab);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver ath11k_ahb_driver = {
+       .driver         = {
+               .name   = "ath11k",
+               .of_match_table = ath11k_ahb_of_match,
+       },
+       .probe  = ath11k_ahb_probe,
+       .remove = ath11k_ahb_remove,
+};
+
+int ath11k_ahb_init(void)
+{
+       return platform_driver_register(&ath11k_ahb_driver);
+}
+
+void ath11k_ahb_exit(void)
+{
+       platform_driver_unregister(&ath11k_ahb_driver);
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+#ifndef ATH11K_AHB_H
+#define ATH11K_AHB_H
+
+#include "core.h"
+
+#define ATH11K_AHB_RECOVERY_TIMEOUT (3 * HZ)
+struct ath11k_base;
+
+static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)
+{
+       return ioread32(ab->mem + offset);
+}
+
+static inline void ath11k_ahb_write32(struct ath11k_base *ab, u32 offset, u32 value)
+{
+       iowrite32(value, ab->mem + offset);
+}
+
+void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab);
+void ath11k_ahb_ext_irq_disable(struct ath11k_base *ab);
+int ath11k_ahb_start(struct ath11k_base *ab);
+void ath11k_ahb_stop(struct ath11k_base *ab);
+int ath11k_ahb_power_up(struct ath11k_base *ab);
+void ath11k_ahb_power_down(struct ath11k_base *ab);
+int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
+                                  u8 *ul_pipe, u8 *dl_pipe);
+
+int ath11k_ahb_init(void);
+void ath11k_ahb_exit(void);
+
+#endif
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include "dp_rx.h"
+#include "debug.h"
+
+static const struct ce_attr host_ce_config_wlan[] = {
+       /* CE0: host->target HTC control and raw streams */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 16,
+               .src_sz_max = 2048,
+               .dest_nentries = 0,
+       },
+
+       /* CE1: target->host HTT + HTC control */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 2048,
+               .dest_nentries = 512,
+               .recv_cb = ath11k_htc_rx_completion_handler,
+       },
+
+       /* CE2: target->host WMI */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 2048,
+               .dest_nentries = 512,
+               .recv_cb = ath11k_htc_rx_completion_handler,
+       },
+
+       /* CE3: host->target WMI (mac0) */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 32,
+               .src_sz_max = 2048,
+               .dest_nentries = 0,
+       },
+
+       /* CE4: host->target HTT */
+       {
+               .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
+               .src_nentries = 2048,
+               .src_sz_max = 256,
+               .dest_nentries = 0,
+       },
+
+       /* CE5: target->host pktlog */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 2048,
+               .dest_nentries = 512,
+               .recv_cb = ath11k_dp_htt_htc_t2h_msg_handler,
+       },
+
+       /* CE6: target autonomous hif_memcpy */
+       {
+               .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
+               .src_nentries = 0,
+               .src_sz_max = 0,
+               .dest_nentries = 0,
+       },
+
+       /* CE7: host->target WMI (mac1) */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 32,
+               .src_sz_max = 2048,
+               .dest_nentries = 0,
+       },
+
+       /* CE8: target autonomous hif_memcpy */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 0,
+               .dest_nentries = 0,
+       },
+
+       /* CE9: host->target WMI (mac2) */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 32,
+               .src_sz_max = 2048,
+               .dest_nentries = 0,
+       },
+
+       /* CE10: target->host HTT */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 2048,
+               .dest_nentries = 512,
+               .recv_cb = ath11k_htc_rx_completion_handler,
+       },
+
+       /* CE11: Not used */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 0,
+               .dest_nentries = 0,
+       },
+};
+
+static int ath11k_ce_rx_buf_enqueue_pipe(struct ath11k_ce_pipe *pipe,
+                                        struct sk_buff *skb, dma_addr_t paddr)
+{
+       struct ath11k_base *ab = pipe->ab;
+       struct ath11k_ce_ring *ring = pipe->dest_ring;
+       struct hal_srng *srng;
+       unsigned int write_index;
+       unsigned int nentries_mask = ring->nentries_mask;
+       u32 *desc;
+       int ret;
+
+       lockdep_assert_held(&ab->ce.ce_lock);
+
+       write_index = ring->write_index;
+
+       srng = &ab->hal.srng_list[ring->hal_ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       if (unlikely(ath11k_hal_srng_src_num_free(ab, srng, false) < 1)) {
+               ret = -ENOSPC;
+               goto exit;
+       }
+
+       desc = ath11k_hal_srng_src_get_next_entry(ab, srng);
+       if (!desc) {
+               ret = -ENOSPC;
+               goto exit;
+       }
+
+       ath11k_hal_ce_dst_set_desc(desc, paddr);
+
+       ring->skb[write_index] = skb;
+       write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
+       ring->write_index = write_index;
+
+       pipe->rx_buf_needed--;
+
+       ret = 0;
+exit:
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       return ret;
+}
+
+static int ath11k_ce_rx_post_pipe(struct ath11k_ce_pipe *pipe)
+{
+       struct ath11k_base *ab = pipe->ab;
+       struct sk_buff *skb;
+       dma_addr_t paddr;
+       int ret = 0;
+
+       if (!(pipe->dest_ring || pipe->status_ring))
+               return 0;
+
+       spin_lock_bh(&ab->ce.ce_lock);
+       while (pipe->rx_buf_needed) {
+               skb = dev_alloc_skb(pipe->buf_sz);
+               if (!skb) {
+                       ret = -ENOMEM;
+                       goto exit;
+               }
+
+               WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 4));
+
+               paddr = dma_map_single(ab->dev, skb->data,
+                                      skb->len + skb_tailroom(skb),
+                                      DMA_FROM_DEVICE);
+               if (unlikely(dma_mapping_error(ab->dev, paddr))) {
+                       ath11k_warn(ab, "failed to dma map ce rx buf\n");
+                       dev_kfree_skb_any(skb);
+                       ret = -EIO;
+                       goto exit;
+               }
+
+               ATH11K_SKB_RXCB(skb)->paddr = paddr;
+
+               ret = ath11k_ce_rx_buf_enqueue_pipe(pipe, skb, paddr);
+
+               if (ret) {
+                       ath11k_warn(ab, "failed to enqueue rx buf: %d\n", ret);
+                       dma_unmap_single(ab->dev, paddr,
+                                        skb->len + skb_tailroom(skb),
+                                        DMA_FROM_DEVICE);
+                       dev_kfree_skb_any(skb);
+                       goto exit;
+               }
+       }
+
+exit:
+       spin_unlock_bh(&ab->ce.ce_lock);
+       return ret;
+}
+
+static int ath11k_ce_completed_recv_next(struct ath11k_ce_pipe *pipe,
+                                        struct sk_buff **skb, int *nbytes)
+{
+       struct ath11k_base *ab = pipe->ab;
+       struct hal_srng *srng;
+       unsigned int sw_index;
+       unsigned int nentries_mask;
+       u32 *desc;
+       int ret = 0;
+
+       spin_lock_bh(&ab->ce.ce_lock);
+
+       sw_index = pipe->dest_ring->sw_index;
+       nentries_mask = pipe->dest_ring->nentries_mask;
+
+       srng = &ab->hal.srng_list[pipe->status_ring->hal_ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       desc = ath11k_hal_srng_dst_get_next_entry(ab, srng);
+       if (!desc) {
+               ret = -EIO;
+               goto err;
+       }
+
+       *nbytes = ath11k_hal_ce_dst_status_get_length(desc);
+       if (*nbytes == 0) {
+               ret = -EIO;
+               goto err;
+       }
+
+       *skb = pipe->dest_ring->skb[sw_index];
+       pipe->dest_ring->skb[sw_index] = NULL;
+
+       sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
+       pipe->dest_ring->sw_index = sw_index;
+
+       pipe->rx_buf_needed++;
+err:
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       spin_unlock_bh(&ab->ce.ce_lock);
+
+       return ret;
+}
+
+static void ath11k_ce_recv_process_cb(struct ath11k_ce_pipe *pipe)
+{
+       struct ath11k_base *ab = pipe->ab;
+       struct sk_buff *skb;
+       struct sk_buff_head list;
+       unsigned int nbytes, max_nbytes;
+       int ret;
+
+       __skb_queue_head_init(&list);
+       while (ath11k_ce_completed_recv_next(pipe, &skb, &nbytes) == 0) {
+               max_nbytes = skb->len + skb_tailroom(skb);
+               dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr,
+                                max_nbytes, DMA_FROM_DEVICE);
+
+               if (unlikely(max_nbytes < nbytes)) {
+                       ath11k_warn(ab, "rxed more than expected (nbytes %d, max %d)",
+                                   nbytes, max_nbytes);
+                       dev_kfree_skb_any(skb);
+                       continue;
+               }
+
+               skb_put(skb, nbytes);
+               __skb_queue_tail(&list, skb);
+       }
+
+       while ((skb = __skb_dequeue(&list))) {
+               ath11k_dbg(ab, ATH11K_DBG_AHB, "rx ce pipe %d len %d\n",
+                          pipe->pipe_num, skb->len);
+               pipe->recv_cb(ab, skb);
+       }
+
+       ret = ath11k_ce_rx_post_pipe(pipe);
+       if (ret && ret != -ENOSPC) {
+               ath11k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n",
+                           pipe->pipe_num, ret);
+               mod_timer(&ab->rx_replenish_retry,
+                         jiffies + ATH11K_CE_RX_POST_RETRY_JIFFIES);
+       }
+}
+
+static struct sk_buff *ath11k_ce_completed_send_next(struct ath11k_ce_pipe *pipe)
+{
+       struct ath11k_base *ab = pipe->ab;
+       struct hal_srng *srng;
+       unsigned int sw_index;
+       unsigned int nentries_mask;
+       struct sk_buff *skb;
+       u32 *desc;
+
+       spin_lock_bh(&ab->ce.ce_lock);
+
+       sw_index = pipe->src_ring->sw_index;
+       nentries_mask = pipe->src_ring->nentries_mask;
+
+       srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       desc = ath11k_hal_srng_src_reap_next(ab, srng);
+       if (!desc) {
+               skb = ERR_PTR(-EIO);
+               goto err_unlock;
+       }
+
+       skb = pipe->src_ring->skb[sw_index];
+
+       pipe->src_ring->skb[sw_index] = NULL;
+
+       sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
+       pipe->src_ring->sw_index = sw_index;
+
+err_unlock:
+       spin_unlock_bh(&srng->lock);
+
+       spin_unlock_bh(&ab->ce.ce_lock);
+
+       return skb;
+}
+
+static void ath11k_ce_send_done_cb(struct ath11k_ce_pipe *pipe)
+{
+       struct ath11k_base *ab = pipe->ab;
+       struct sk_buff *skb;
+
+       while (!IS_ERR(skb = ath11k_ce_completed_send_next(pipe))) {
+               if (!skb)
+                       continue;
+
+               dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr, skb->len,
+                                DMA_TO_DEVICE);
+               dev_kfree_skb_any(skb);
+       }
+}
+
+static int ath11k_ce_init_ring(struct ath11k_base *ab,
+                              struct ath11k_ce_ring *ce_ring,
+                              int ce_id, enum hal_ring_type type)
+{
+       struct hal_srng_params params = { 0 };
+       int ret;
+
+       params.ring_base_paddr = ce_ring->base_addr_ce_space;
+       params.ring_base_vaddr = ce_ring->base_addr_owner_space;
+       params.num_entries = ce_ring->nentries;
+
+       switch (type) {
+       case HAL_CE_SRC:
+               if (!(CE_ATTR_DIS_INTR & host_ce_config_wlan[ce_id].flags))
+                       params.intr_batch_cntr_thres_entries = 1;
+               break;
+       case HAL_CE_DST:
+               params.max_buffer_len = host_ce_config_wlan[ce_id].src_sz_max;
+               if (!(host_ce_config_wlan[ce_id].flags & CE_ATTR_DIS_INTR)) {
+                       params.intr_timer_thres_us = 1024;
+                       params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN;
+                       params.low_threshold = ce_ring->nentries - 3;
+               }
+               break;
+       case HAL_CE_DST_STATUS:
+               if (!(host_ce_config_wlan[ce_id].flags & CE_ATTR_DIS_INTR)) {
+                       params.intr_batch_cntr_thres_entries = 1;
+                       params.intr_timer_thres_us = 0x1000;
+               }
+               break;
+       default:
+               ath11k_warn(ab, "Invalid CE ring type %d\n", type);
+               return -EINVAL;
+       }
+
+       /* TODO: Init other params needed by HAL to init the ring */
+
+       ret = ath11k_hal_srng_setup(ab, type, ce_id, 0, ¶ms);
+       if (ret < 0) {
+               ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n",
+                           ret, ce_id);
+               return ret;
+       }
+       ce_ring->hal_ring_id = ret;
+
+       return 0;
+}
+
+static struct ath11k_ce_ring *
+ath11k_ce_alloc_ring(struct ath11k_base *ab, int nentries, int desc_sz)
+{
+       struct ath11k_ce_ring *ce_ring;
+       dma_addr_t base_addr;
+
+       ce_ring = kzalloc(struct_size(ce_ring, skb, nentries), GFP_KERNEL);
+       if (ce_ring == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       ce_ring->nentries = nentries;
+       ce_ring->nentries_mask = nentries - 1;
+
+       /* Legacy platforms that do not support cache
+        * coherent DMA are unsupported
+        */
+       ce_ring->base_addr_owner_space_unaligned =
+               dma_alloc_coherent(ab->dev,
+                                  nentries * desc_sz + CE_DESC_RING_ALIGN,
+                                  &base_addr, GFP_KERNEL);
+       if (!ce_ring->base_addr_owner_space_unaligned) {
+               kfree(ce_ring);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       ce_ring->base_addr_ce_space_unaligned = base_addr;
+
+       ce_ring->base_addr_owner_space = PTR_ALIGN(
+                       ce_ring->base_addr_owner_space_unaligned,
+                       CE_DESC_RING_ALIGN);
+       ce_ring->base_addr_ce_space = ALIGN(
+                       ce_ring->base_addr_ce_space_unaligned,
+                       CE_DESC_RING_ALIGN);
+
+       return ce_ring;
+}
+
+static int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id)
+{
+       struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id];
+       const struct ce_attr *attr = &host_ce_config_wlan[ce_id];
+       int nentries;
+       int desc_sz;
+
+       pipe->attr_flags = attr->flags;
+
+       if (attr->src_nentries) {
+               pipe->send_cb = ath11k_ce_send_done_cb;
+               nentries = roundup_pow_of_two(attr->src_nentries);
+               desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC);
+               pipe->src_ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz);
+               if (!pipe->src_ring)
+                       return -ENOMEM;
+       }
+
+       if (attr->dest_nentries) {
+               pipe->recv_cb = attr->recv_cb;
+               nentries = roundup_pow_of_two(attr->dest_nentries);
+               desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST);
+               pipe->dest_ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz);
+
+               if (!pipe->dest_ring)
+                       return -ENOMEM;
+
+               desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS);
+               pipe->status_ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz);
+               if (!pipe->status_ring)
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id)
+{
+       struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id];
+
+       if (pipe->send_cb)
+               pipe->send_cb(pipe);
+
+       if (pipe->recv_cb)
+               ath11k_ce_recv_process_cb(pipe);
+}
+
+void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id)
+{
+       struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id];
+
+       if ((pipe->attr_flags & CE_ATTR_DIS_INTR) && pipe->send_cb)
+               pipe->send_cb(pipe);
+}
+
+int ath11k_ce_send(struct ath11k_base *ab, struct sk_buff *skb, u8 pipe_id,
+                  u16 transfer_id)
+{
+       struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[pipe_id];
+       struct hal_srng *srng;
+       u32 *desc;
+       unsigned int write_index, sw_index;
+       unsigned int nentries_mask;
+       int ret = 0;
+       u8 byte_swap_data = 0;
+       int num_used;
+
+       /* Check if some entries could be regained by handling tx completion if
+        * the CE has interrupts disabled and the used entries is more than the
+        * defined usage threshold.
+        */
+       if (pipe->attr_flags & CE_ATTR_DIS_INTR) {
+               spin_lock_bh(&ab->ce.ce_lock);
+               write_index = pipe->src_ring->write_index;
+
+               sw_index = pipe->src_ring->sw_index;
+
+               if (write_index >= sw_index)
+                       num_used = write_index - sw_index;
+               else
+                       num_used = pipe->src_ring->nentries - sw_index +
+                                  write_index;
+
+               spin_unlock_bh(&ab->ce.ce_lock);
+
+               if (num_used > ATH11K_CE_USAGE_THRESHOLD)
+                       ath11k_ce_poll_send_completed(ab, pipe->pipe_num);
+       }
+
+       if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
+               return -ESHUTDOWN;
+
+       spin_lock_bh(&ab->ce.ce_lock);
+
+       write_index = pipe->src_ring->write_index;
+       nentries_mask = pipe->src_ring->nentries_mask;
+
+       srng = &ab->hal.srng_list[pipe->src_ring->hal_ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       if (unlikely(ath11k_hal_srng_src_num_free(ab, srng, false) < 1)) {
+               ath11k_hal_srng_access_end(ab, srng);
+               ret = -ENOBUFS;
+               goto err_unlock;
+       }
+
+       desc = ath11k_hal_srng_src_get_next_reaped(ab, srng);
+       if (!desc) {
+               ath11k_hal_srng_access_end(ab, srng);
+               ret = -ENOBUFS;
+               goto err_unlock;
+       }
+
+       if (pipe->attr_flags & CE_ATTR_BYTE_SWAP_DATA)
+               byte_swap_data = 1;
+
+       ath11k_hal_ce_src_set_desc(desc, ATH11K_SKB_CB(skb)->paddr,
+                                  skb->len, transfer_id, byte_swap_data);
+
+       pipe->src_ring->skb[write_index] = skb;
+       pipe->src_ring->write_index = CE_RING_IDX_INCR(nentries_mask,
+                                                      write_index);
+
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       spin_unlock_bh(&ab->ce.ce_lock);
+
+       return 0;
+
+err_unlock:
+       spin_unlock_bh(&srng->lock);
+
+       spin_unlock_bh(&ab->ce.ce_lock);
+
+       return ret;
+}
+
+static void ath11k_ce_rx_pipe_cleanup(struct ath11k_ce_pipe *pipe)
+{
+       struct ath11k_base *ab = pipe->ab;
+       struct ath11k_ce_ring *ring = pipe->dest_ring;
+       struct sk_buff *skb;
+       int i;
+
+       if (!(ring && pipe->buf_sz))
+               return;
+
+       for (i = 0; i < ring->nentries; i++) {
+               skb = ring->skb[i];
+               if (!skb)
+                       continue;
+
+               ring->skb[i] = NULL;
+               dma_unmap_single(ab->dev, ATH11K_SKB_RXCB(skb)->paddr,
+                                skb->len + skb_tailroom(skb), DMA_FROM_DEVICE);
+               dev_kfree_skb_any(skb);
+       }
+}
+
+void ath11k_ce_cleanup_pipes(struct ath11k_base *ab)
+{
+       struct ath11k_ce_pipe *pipe;
+       int pipe_num;
+
+       for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
+               pipe = &ab->ce.ce_pipe[pipe_num];
+               ath11k_ce_rx_pipe_cleanup(pipe);
+
+               /* Cleanup any src CE's which have interrupts disabled */
+               ath11k_ce_poll_send_completed(ab, pipe_num);
+
+               /* NOTE: Should we also clean up tx buffer in all pipes? */
+       }
+}
+
+void ath11k_ce_rx_post_buf(struct ath11k_base *ab)
+{
+       struct ath11k_ce_pipe *pipe;
+       int i;
+       int ret;
+
+       for (i = 0; i < CE_COUNT; i++) {
+               pipe = &ab->ce.ce_pipe[i];
+               ret = ath11k_ce_rx_post_pipe(pipe);
+               if (ret) {
+                       if (ret == -ENOSPC)
+                               continue;
+
+                       ath11k_warn(ab, "failed to post rx buf to pipe: %d err: %d\n",
+                                   i, ret);
+                       mod_timer(&ab->rx_replenish_retry,
+                                 jiffies + ATH11K_CE_RX_POST_RETRY_JIFFIES);
+
+                       return;
+               }
+       }
+}
+
+void ath11k_ce_rx_replenish_retry(struct timer_list *t)
+{
+       struct ath11k_base *ab = from_timer(ab, t, rx_replenish_retry);
+
+       ath11k_ce_rx_post_buf(ab);
+}
+
+int ath11k_ce_init_pipes(struct ath11k_base *ab)
+{
+       struct ath11k_ce_pipe *pipe;
+       int i;
+       int ret;
+
+       for (i = 0; i < CE_COUNT; i++) {
+               pipe = &ab->ce.ce_pipe[i];
+
+               if (pipe->src_ring) {
+                       ret = ath11k_ce_init_ring(ab, pipe->src_ring, i,
+                                                 HAL_CE_SRC);
+                       if (ret) {
+                               ath11k_warn(ab, "failed to init src ring: %d\n",
+                                           ret);
+                               /* Should we clear any partial init */
+                               return ret;
+                       }
+
+                       pipe->src_ring->write_index = 0;
+                       pipe->src_ring->sw_index = 0;
+               }
+
+               if (pipe->dest_ring) {
+                       ret = ath11k_ce_init_ring(ab, pipe->dest_ring, i,
+                                                 HAL_CE_DST);
+                       if (ret) {
+                               ath11k_warn(ab, "failed to init dest ring: %d\n",
+                                           ret);
+                               /* Should we clear any partial init */
+                               return ret;
+                       }
+
+                       pipe->rx_buf_needed = pipe->dest_ring->nentries ?
+                                             pipe->dest_ring->nentries - 2 : 0;
+
+                       pipe->dest_ring->write_index = 0;
+                       pipe->dest_ring->sw_index = 0;
+               }
+
+               if (pipe->status_ring) {
+                       ret = ath11k_ce_init_ring(ab, pipe->status_ring, i,
+                                                 HAL_CE_DST_STATUS);
+                       if (ret) {
+                               ath11k_warn(ab, "failed to init dest status ing: %d\n",
+                                           ret);
+                               /* Should we clear any partial init */
+                               return ret;
+                       }
+
+                       pipe->status_ring->write_index = 0;
+                       pipe->status_ring->sw_index = 0;
+               }
+       }
+
+       return 0;
+}
+
+void ath11k_ce_free_pipes(struct ath11k_base *ab)
+{
+       struct ath11k_ce_pipe *pipe;
+       int desc_sz;
+       int i;
+
+       for (i = 0; i < CE_COUNT; i++) {
+               pipe = &ab->ce.ce_pipe[i];
+
+               if (pipe->src_ring) {
+                       desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC);
+                       dma_free_coherent(ab->dev,
+                                         pipe->src_ring->nentries * desc_sz +
+                                         CE_DESC_RING_ALIGN,
+                                         pipe->src_ring->base_addr_owner_space,
+                                         pipe->src_ring->base_addr_ce_space);
+                       kfree(pipe->src_ring);
+                       pipe->src_ring = NULL;
+               }
+
+               if (pipe->dest_ring) {
+                       desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST);
+                       dma_free_coherent(ab->dev,
+                                         pipe->dest_ring->nentries * desc_sz +
+                                         CE_DESC_RING_ALIGN,
+                                         pipe->dest_ring->base_addr_owner_space,
+                                         pipe->dest_ring->base_addr_ce_space);
+                       kfree(pipe->dest_ring);
+                       pipe->dest_ring = NULL;
+               }
+
+               if (pipe->status_ring) {
+                       desc_sz =
+                         ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS);
+                       dma_free_coherent(ab->dev,
+                                         pipe->status_ring->nentries * desc_sz +
+                                         CE_DESC_RING_ALIGN,
+                                         pipe->status_ring->base_addr_owner_space,
+                                         pipe->status_ring->base_addr_ce_space);
+                       kfree(pipe->status_ring);
+                       pipe->status_ring = NULL;
+               }
+       }
+}
+
+int ath11k_ce_alloc_pipes(struct ath11k_base *ab)
+{
+       struct ath11k_ce_pipe *pipe;
+       int i;
+       int ret;
+       const struct ce_attr *attr;
+
+       spin_lock_init(&ab->ce.ce_lock);
+
+       for (i = 0; i < CE_COUNT; i++) {
+               attr = &host_ce_config_wlan[i];
+               pipe = &ab->ce.ce_pipe[i];
+               pipe->pipe_num = i;
+               pipe->ab = ab;
+               pipe->buf_sz = attr->src_sz_max;
+
+               ret = ath11k_ce_alloc_pipe(ab, i);
+               if (ret) {
+                       /* Free any parial successful allocation */
+                       ath11k_ce_free_pipes(ab);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/* For Big Endian Host, Copy Engine byte_swap is enabled
+ * When Copy Engine does byte_swap, need to byte swap again for the
+ * Host to get/put buffer content in the correct byte order
+ */
+void ath11k_ce_byte_swap(void *mem, u32 len)
+{
+       int i;
+
+       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
+               if (!mem)
+                       return;
+
+               for (i = 0; i < (len / 4); i++) {
+                       *(u32 *)mem = swab32(*(u32 *)mem);
+                       mem += 4;
+               }
+       }
+}
+
+int ath11k_ce_get_attr_flags(int ce_id)
+{
+       if (ce_id >= CE_COUNT)
+               return -EINVAL;
+
+       return host_ce_config_wlan[ce_id].flags;
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_CE_H
+#define ATH11K_CE_H
+
+#define CE_COUNT 12
+
+/* Byte swap data words */
+#define CE_ATTR_BYTE_SWAP_DATA 2
+
+/* no interrupt on copy completion */
+#define CE_ATTR_DIS_INTR               8
+
+/* Host software's Copy Engine configuration. */
+#ifdef __BIG_ENDIAN
+#define CE_ATTR_FLAGS CE_ATTR_BYTE_SWAP_DATA
+#else
+#define CE_ATTR_FLAGS 0
+#endif
+
+/* Threshold to poll for tx completion in case of Interrupt disabled CE's */
+#define ATH11K_CE_USAGE_THRESHOLD 32
+
+void ath11k_ce_byte_swap(void *mem, u32 len);
+
+/*
+ * Directions for interconnect pipe configuration.
+ * These definitions may be used during configuration and are shared
+ * between Host and Target.
+ *
+ * Pipe Directions are relative to the Host, so PIPEDIR_IN means
+ * "coming IN over air through Target to Host" as with a WiFi Rx operation.
+ * Conversely, PIPEDIR_OUT means "going OUT from Host through Target over air"
+ * as with a WiFi Tx operation. This is somewhat awkward for the "middle-man"
+ * Target since things that are "PIPEDIR_OUT" are coming IN to the Target
+ * over the interconnect.
+ */
+#define PIPEDIR_NONE           0
+#define PIPEDIR_IN             1 /* Target-->Host, WiFi Rx direction */
+#define PIPEDIR_OUT            2 /* Host->Target, WiFi Tx direction */
+#define PIPEDIR_INOUT          3 /* bidirectional */
+#define PIPEDIR_INOUT_H2H      4 /* bidirectional, host to host */
+
+/* CE address/mask */
+#define CE_HOST_IE_ADDRESS     0x00A1803C
+#define CE_HOST_IE_2_ADDRESS   0x00A18040
+#define CE_HOST_IE_3_ADDRESS   CE_HOST_IE_ADDRESS
+
+#define CE_HOST_IE_3_SHIFT     0xC
+
+#define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask))
+
+#define ATH11K_CE_RX_POST_RETRY_JIFFIES 50
+
+struct ath11k_base;
+
+/* Establish a mapping between a service/direction and a pipe. */
+struct service_to_pipe {
+       __le32 service_id;
+       __le32 pipedir;
+       __le32 pipenum;
+};
+
+/*
+ * Configuration information for a Copy Engine pipe.
+ * Passed from Host to Target during startup (one per CE).
+ *
+ * NOTE: Structure is shared between Host software and Target firmware!
+ */
+struct ce_pipe_config {
+       __le32 pipenum;
+       __le32 pipedir;
+       __le32 nentries;
+       __le32 nbytes_max;
+       __le32 flags;
+       __le32 reserved;
+};
+
+struct ce_attr {
+       /* CE_ATTR_* values */
+       unsigned int flags;
+
+       /* #entries in source ring - Must be a power of 2 */
+       unsigned int src_nentries;
+
+       /*
+        * Max source send size for this CE.
+        * This is also the minimum size of a destination buffer.
+        */
+       unsigned int src_sz_max;
+
+       /* #entries in destination ring - Must be a power of 2 */
+       unsigned int dest_nentries;
+
+       void (*recv_cb)(struct ath11k_base *, struct sk_buff *);
+};
+
+#define CE_DESC_RING_ALIGN 8
+
+struct ath11k_ce_ring {
+       /* Number of entries in this ring; must be power of 2 */
+       unsigned int nentries;
+       unsigned int nentries_mask;
+
+       /* For dest ring, this is the next index to be processed
+        * by software after it was/is received into.
+        *
+        * For src ring, this is the last descriptor that was sent
+        * and completion processed by software.
+        *
+        * Regardless of src or dest ring, this is an invariant
+        * (modulo ring size):
+        *     write index >= read index >= sw_index
+        */
+       unsigned int sw_index;
+       /* cached copy */
+       unsigned int write_index;
+
+       /* Start of DMA-coherent area reserved for descriptors */
+       /* Host address space */
+       void *base_addr_owner_space_unaligned;
+       /* CE address space */
+       u32 base_addr_ce_space_unaligned;
+
+       /* Actual start of descriptors.
+        * Aligned to descriptor-size boundary.
+        * Points into reserved DMA-coherent area, above.
+        */
+       /* Host address space */
+       void *base_addr_owner_space;
+
+       /* CE address space */
+       u32 base_addr_ce_space;
+
+       /* HAL ring id */
+       u32 hal_ring_id;
+
+       /* keep last */
+       struct sk_buff *skb[0];
+};
+
+struct ath11k_ce_pipe {
+       struct ath11k_base *ab;
+       u16 pipe_num;
+       unsigned int attr_flags;
+       unsigned int buf_sz;
+       unsigned int rx_buf_needed;
+
+       void (*send_cb)(struct ath11k_ce_pipe *);
+       void (*recv_cb)(struct ath11k_base *, struct sk_buff *);
+
+       struct tasklet_struct intr_tq;
+       struct ath11k_ce_ring *src_ring;
+       struct ath11k_ce_ring *dest_ring;
+       struct ath11k_ce_ring *status_ring;
+};
+
+struct ath11k_ce {
+       struct ath11k_ce_pipe ce_pipe[CE_COUNT];
+       /* Protects rings of all ce pipes */
+       spinlock_t ce_lock;
+};
+
+void ath11k_ce_cleanup_pipes(struct ath11k_base *ab);
+void ath11k_ce_rx_replenish_retry(struct timer_list *t);
+void ath11k_ce_per_engine_service(struct ath11k_base *ab, u16 ce_id);
+int ath11k_ce_send(struct ath11k_base *ab, struct sk_buff *skb, u8 pipe_id,
+                  u16 transfer_id);
+void ath11k_ce_rx_post_buf(struct ath11k_base *ab);
+int ath11k_ce_init_pipes(struct ath11k_base *ab);
+int ath11k_ce_alloc_pipes(struct ath11k_base *ab);
+void ath11k_ce_free_pipes(struct ath11k_base *ab);
+int ath11k_ce_get_attr_flags(int ce_id);
+void ath11k_ce_poll_send_completed(struct ath11k_base *ab, u8 pipe_id);
+#endif
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/remoteproc.h>
+#include <linux/firmware.h>
+#include "ahb.h"
+#include "core.h"
+#include "dp_tx.h"
+#include "debug.h"
+
+unsigned int ath11k_debug_mask;
+module_param_named(debug_mask, ath11k_debug_mask, uint, 0644);
+MODULE_PARM_DESC(debug_mask, "Debugging mask");
+
+static const struct ath11k_hw_params ath11k_hw_params = {
+       .name = "ipq8074",
+       .fw = {
+               .dir = IPQ8074_FW_DIR,
+               .board_size = IPQ8074_MAX_BOARD_DATA_SZ,
+               .cal_size =  IPQ8074_MAX_CAL_DATA_SZ,
+       },
+};
+
+/* Map from pdev index to hw mac index */
+u8 ath11k_core_get_hw_mac_id(struct ath11k_base *ab, int pdev_idx)
+{
+       switch (pdev_idx) {
+       case 0:
+               return 0;
+       case 1:
+               return 2;
+       case 2:
+               return 1;
+       default:
+               ath11k_warn(ab, "Invalid pdev idx %d\n", pdev_idx);
+               return ATH11K_INVALID_HW_MAC_ID;
+       }
+}
+
+static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name,
+                                        size_t name_len)
+{
+       /* Note: bus is fixed to ahb. When other bus type supported,
+        * make it to dynamic.
+        */
+       scnprintf(name, name_len,
+                 "bus=ahb,qmi-chip-id=%d,qmi-board-id=%d",
+                 ab->qmi.target.chip_id,
+                 ab->qmi.target.board_id);
+
+       ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot using board name '%s'\n", name);
+
+       return 0;
+}
+
+static const struct firmware *ath11k_fetch_fw_file(struct ath11k_base *ab,
+                                                  const char *dir,
+                                                  const char *file)
+{
+       char filename[100];
+       const struct firmware *fw;
+       int ret;
+
+       if (file == NULL)
+               return ERR_PTR(-ENOENT);
+
+       if (dir == NULL)
+               dir = ".";
+
+       snprintf(filename, sizeof(filename), "%s/%s", dir, file);
+       ret = firmware_request_nowarn(&fw, filename, ab->dev);
+       ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot fw request '%s': %d\n",
+                  filename, ret);
+
+       if (ret)
+               return ERR_PTR(ret);
+       ath11k_warn(ab, "Downloading BDF: %s, size: %zu\n",
+                   filename, fw->size);
+
+       return fw;
+}
+
+void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd)
+{
+       if (!IS_ERR(bd->fw))
+               release_firmware(bd->fw);
+
+       memset(bd, 0, sizeof(*bd));
+}
+
+static int ath11k_core_parse_bd_ie_board(struct ath11k_base *ab,
+                                        struct ath11k_board_data *bd,
+                                        const void *buf, size_t buf_len,
+                                        const char *boardname,
+                                        int bd_ie_type)
+{
+       const struct ath11k_fw_ie *hdr;
+       bool name_match_found;
+       int ret, board_ie_id;
+       size_t board_ie_len;
+       const void *board_ie_data;
+
+       name_match_found = false;
+
+       /* go through ATH11K_BD_IE_BOARD_ elements */
+       while (buf_len > sizeof(struct ath11k_fw_ie)) {
+               hdr = buf;
+               board_ie_id = le32_to_cpu(hdr->id);
+               board_ie_len = le32_to_cpu(hdr->len);
+               board_ie_data = hdr->data;
+
+               buf_len -= sizeof(*hdr);
+               buf += sizeof(*hdr);
+
+               if (buf_len < ALIGN(board_ie_len, 4)) {
+                       ath11k_err(ab, "invalid ATH11K_BD_IE_BOARD length: %zu < %zu\n",
+                                  buf_len, ALIGN(board_ie_len, 4));
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               switch (board_ie_id) {
+               case ATH11K_BD_IE_BOARD_NAME:
+                       ath11k_dbg_dump(ab, ATH11K_DBG_BOOT, "board name", "",
+                                       board_ie_data, board_ie_len);
+
+                       if (board_ie_len != strlen(boardname))
+                               break;
+
+                       ret = memcmp(board_ie_data, boardname, strlen(boardname));
+                       if (ret)
+                               break;
+
+                       name_match_found = true;
+                       ath11k_dbg(ab, ATH11K_DBG_BOOT,
+                                  "boot found match for name '%s'",
+                                  boardname);
+                       break;
+               case ATH11K_BD_IE_BOARD_DATA:
+                       if (!name_match_found)
+                               /* no match found */
+                               break;
+
+                       ath11k_dbg(ab, ATH11K_DBG_BOOT,
+                                  "boot found board data for '%s'", boardname);
+
+                       bd->data = board_ie_data;
+                       bd->len = board_ie_len;
+
+                       ret = 0;
+                       goto out;
+               default:
+                       ath11k_warn(ab, "unknown ATH11K_BD_IE_BOARD found: %d\n",
+                                   board_ie_id);
+                       break;
+               }
+
+               /* jump over the padding */
+               board_ie_len = ALIGN(board_ie_len, 4);
+
+               buf_len -= board_ie_len;
+               buf += board_ie_len;
+       }
+
+       /* no match found */
+       ret = -ENOENT;
+
+out:
+       return ret;
+}
+
+static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab,
+                                             struct ath11k_board_data *bd,
+                                             const char *boardname)
+{
+       size_t len, magic_len;
+       const u8 *data;
+       char *filename = ATH11K_BOARD_API2_FILE;
+       size_t ie_len;
+       struct ath11k_fw_ie *hdr;
+       int ret, ie_id;
+
+       if (!bd->fw)
+               bd->fw = ath11k_fetch_fw_file(ab,
+                                             ab->hw_params.fw.dir,
+                                             filename);
+       if (IS_ERR(bd->fw))
+               return PTR_ERR(bd->fw);
+
+       data = bd->fw->data;
+       len = bd->fw->size;
+
+       /* magic has extra null byte padded */
+       magic_len = strlen(ATH11K_BOARD_MAGIC) + 1;
+       if (len < magic_len) {
+               ath11k_err(ab, "failed to find magic value in %s/%s, file too short: %zu\n",
+                          ab->hw_params.fw.dir, filename, len);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       if (memcmp(data, ATH11K_BOARD_MAGIC, magic_len)) {
+               ath11k_err(ab, "found invalid board magic\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* magic is padded to 4 bytes */
+       magic_len = ALIGN(magic_len, 4);
+       if (len < magic_len) {
+               ath11k_err(ab, "failed: %s/%s too small to contain board data, len: %zu\n",
+                          ab->hw_params.fw.dir, filename, len);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       data += magic_len;
+       len -= magic_len;
+
+       while (len > sizeof(struct ath11k_fw_ie)) {
+               hdr = (struct ath11k_fw_ie *)data;
+               ie_id = le32_to_cpu(hdr->id);
+               ie_len = le32_to_cpu(hdr->len);
+
+               len -= sizeof(*hdr);
+               data = hdr->data;
+
+               if (len < ALIGN(ie_len, 4)) {
+                       ath11k_err(ab, "invalid length for board ie_id %d ie_len %zu len %zu\n",
+                                  ie_id, ie_len, len);
+                       return -EINVAL;
+               }
+
+               switch (ie_id) {
+               case ATH11K_BD_IE_BOARD:
+                       ret = ath11k_core_parse_bd_ie_board(ab, bd, data,
+                                                           ie_len,
+                                                           boardname,
+                                                           ATH11K_BD_IE_BOARD);
+                       if (ret == -ENOENT)
+                               /* no match found, continue */
+                               break;
+                       else if (ret)
+                               /* there was an error, bail out */
+                               goto err;
+                       /* either found or error, so stop searching */
+                       goto out;
+               }
+
+               /* jump over the padding */
+               ie_len = ALIGN(ie_len, 4);
+
+               len -= ie_len;
+               data += ie_len;
+       }
+
+out:
+       if (!bd->data || !bd->len) {
+               ath11k_err(ab,
+                          "failed to fetch board data for %s from %s/%s\n",
+                          boardname, ab->hw_params.fw.dir, filename);
+               ret = -ENODATA;
+               goto err;
+       }
+
+       return 0;
+
+err:
+       ath11k_core_free_bdf(ab, bd);
+       return ret;
+}
+
+static int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab,
+                                             struct ath11k_board_data *bd)
+{
+       bd->fw = ath11k_fetch_fw_file(ab,
+                                     ab->hw_params.fw.dir,
+                                     ATH11K_DEFAULT_BOARD_FILE);
+       if (IS_ERR(bd->fw))
+               return PTR_ERR(bd->fw);
+
+       bd->data = bd->fw->data;
+       bd->len = bd->fw->size;
+
+       return 0;
+}
+
+#define BOARD_NAME_SIZE 100
+int ath11k_core_fetch_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd)
+{
+       char boardname[BOARD_NAME_SIZE];
+       int ret;
+
+       ret = ath11k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE);
+       if (ret) {
+               ath11k_err(ab, "failed to create board name: %d", ret);
+               return ret;
+       }
+
+       ab->bd_api = 2;
+       ret = ath11k_core_fetch_board_data_api_n(ab, bd, boardname);
+       if (!ret)
+               goto success;
+
+       ab->bd_api = 1;
+       ret = ath11k_core_fetch_board_data_api_1(ab, bd);
+       if (ret) {
+               ath11k_err(ab, "failed to fetch board-2.bin or board.bin from %s\n",
+                          ab->hw_params.fw.dir);
+               return ret;
+       }
+
+success:
+       ath11k_dbg(ab, ATH11K_DBG_BOOT, "using board api %d\n", ab->bd_api);
+       return 0;
+}
+
+static void ath11k_core_stop(struct ath11k_base *ab)
+{
+       if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))
+               ath11k_qmi_firmware_stop(ab);
+       ath11k_ahb_stop(ab);
+       ath11k_wmi_detach(ab);
+
+       /* De-Init of components as needed */
+}
+
+static int ath11k_core_soc_create(struct ath11k_base *ab)
+{
+       int ret;
+
+       ret = ath11k_qmi_init_service(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to initialize qmi :%d\n", ret);
+               return ret;
+       }
+
+       ret = ath11k_debug_soc_create(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to create ath11k debugfs\n");
+               goto err_qmi_deinit;
+       }
+
+       ret = ath11k_ahb_power_up(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to power up :%d\n", ret);
+               goto err_debugfs_reg;
+       }
+
+       return 0;
+
+err_debugfs_reg:
+       ath11k_debug_soc_destroy(ab);
+err_qmi_deinit:
+       ath11k_qmi_deinit_service(ab);
+       return ret;
+}
+
+static void ath11k_core_soc_destroy(struct ath11k_base *ab)
+{
+       ath11k_debug_soc_destroy(ab);
+       ath11k_dp_free(ab);
+       ath11k_reg_free(ab);
+       ath11k_qmi_deinit_service(ab);
+}
+
+static int ath11k_core_pdev_create(struct ath11k_base *ab)
+{
+       int ret;
+
+       ret = ath11k_debug_pdev_create(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to create core pdev debugfs: %d\n", ret);
+               return ret;
+       }
+
+       ret = ath11k_mac_create(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to create new hw device with mac80211 :%d\n",
+                          ret);
+               goto err_pdev_debug;
+       }
+
+       ret = ath11k_dp_pdev_alloc(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to attach DP pdev: %d\n", ret);
+               goto err_mac_destroy;
+       }
+
+       return 0;
+
+err_mac_destroy:
+       ath11k_mac_destroy(ab);
+
+err_pdev_debug:
+       ath11k_debug_pdev_destroy(ab);
+
+       return ret;
+}
+
+static void ath11k_core_pdev_destroy(struct ath11k_base *ab)
+{
+       ath11k_mac_unregister(ab);
+       ath11k_ahb_ext_irq_disable(ab);
+       ath11k_dp_pdev_free(ab);
+       ath11k_debug_pdev_destroy(ab);
+}
+
+static int ath11k_core_start(struct ath11k_base *ab,
+                            enum ath11k_firmware_mode mode)
+{
+       int ret;
+
+       ret = ath11k_qmi_firmware_start(ab, mode);
+       if (ret) {
+               ath11k_err(ab, "failed to attach wmi: %d\n", ret);
+               return ret;
+       }
+
+       ret = ath11k_wmi_attach(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to attach wmi: %d\n", ret);
+               goto err_firmware_stop;
+       }
+
+       ret = ath11k_htc_init(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to init htc: %d\n", ret);
+               goto err_wmi_detach;
+       }
+
+       ret = ath11k_ahb_start(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to start HIF: %d\n", ret);
+               goto err_wmi_detach;
+       }
+
+       ret = ath11k_htc_wait_target(&ab->htc);
+       if (ret) {
+               ath11k_err(ab, "failed to connect to HTC: %d\n", ret);
+               goto err_hif_stop;
+       }
+
+       ret = ath11k_dp_htt_connect(&ab->dp);
+       if (ret) {
+               ath11k_err(ab, "failed to connect to HTT: %d\n", ret);
+               goto err_hif_stop;
+       }
+
+       ret = ath11k_wmi_connect(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to connect wmi: %d\n", ret);
+               goto err_hif_stop;
+       }
+
+       ret = ath11k_htc_start(&ab->htc);
+       if (ret) {
+               ath11k_err(ab, "failed to start HTC: %d\n", ret);
+               goto err_hif_stop;
+       }
+
+       ret = ath11k_wmi_wait_for_service_ready(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to receive wmi service ready event: %d\n",
+                          ret);
+               goto err_hif_stop;
+       }
+
+       ret = ath11k_wmi_cmd_init(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to send wmi init cmd: %d\n", ret);
+               goto err_hif_stop;
+       }
+
+       ret = ath11k_wmi_wait_for_unified_ready(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to receive wmi unified ready event: %d\n",
+                          ret);
+               goto err_hif_stop;
+       }
+
+       ret = ath11k_dp_tx_htt_h2t_ver_req_msg(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to send htt version request message: %d\n",
+                          ret);
+               goto err_hif_stop;
+       }
+
+       return 0;
+
+err_hif_stop:
+       ath11k_ahb_stop(ab);
+err_wmi_detach:
+       ath11k_wmi_detach(ab);
+err_firmware_stop:
+       ath11k_qmi_firmware_stop(ab);
+
+       return ret;
+}
+
+int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab)
+{
+       int ret;
+
+       ret = ath11k_ce_init_pipes(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to initialize CE: %d\n", ret);
+               return ret;
+       }
+
+       ret = ath11k_dp_alloc(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to init DP: %d\n", ret);
+               return ret;
+       }
+
+       mutex_lock(&ab->core_lock);
+       ret = ath11k_core_start(ab, ATH11K_FIRMWARE_MODE_NORMAL);
+       if (ret) {
+               ath11k_err(ab, "failed to start core: %d\n", ret);
+               goto err_dp_free;
+       }
+
+       ret = ath11k_core_pdev_create(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to create pdev core: %d\n", ret);
+               goto err_core_stop;
+       }
+       ath11k_ahb_ext_irq_enable(ab);
+       mutex_unlock(&ab->core_lock);
+
+       return 0;
+
+err_core_stop:
+       ath11k_core_stop(ab);
+err_dp_free:
+       ath11k_dp_free(ab);
+       return ret;
+}
+
+static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
+{
+       int ret;
+
+       mutex_lock(&ab->core_lock);
+       ath11k_ahb_ext_irq_disable(ab);
+       ath11k_dp_pdev_free(ab);
+       ath11k_ahb_stop(ab);
+       ath11k_wmi_detach(ab);
+       mutex_unlock(&ab->core_lock);
+
+       ath11k_dp_free(ab);
+       ath11k_hal_srng_deinit(ab);
+
+       ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
+
+       ret = ath11k_hal_srng_init(ab);
+       if (ret)
+               return ret;
+
+       clear_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags);
+
+       ret = ath11k_core_qmi_firmware_ready(ab);
+       if (ret)
+               goto err_hal_srng_deinit;
+
+       clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
+
+       return 0;
+
+err_hal_srng_deinit:
+       ath11k_hal_srng_deinit(ab);
+       return ret;
+}
+
+void ath11k_core_halt(struct ath11k *ar)
+{
+       struct ath11k_base *ab = ar->ab;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ar->num_created_vdevs = 0;
+
+       ath11k_mac_scan_finish(ar);
+       ath11k_mac_peer_cleanup_all(ar);
+       cancel_delayed_work_sync(&ar->scan.timeout);
+       cancel_work_sync(&ar->regd_update_work);
+
+       rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
+       synchronize_rcu();
+       INIT_LIST_HEAD(&ar->arvifs);
+       idr_init(&ar->txmgmt_idr);
+}
+
+static void ath11k_core_restart(struct work_struct *work)
+{
+       struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work);
+       struct ath11k *ar;
+       struct ath11k_pdev *pdev;
+       int i, ret = 0;
+
+       spin_lock_bh(&ab->base_lock);
+       ab->stats.fw_crash_counter++;
+       spin_unlock_bh(&ab->base_lock);
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = &ab->pdevs[i];
+               ar = pdev->ar;
+               if (!ar || ar->state == ATH11K_STATE_OFF)
+                       continue;
+
+               ieee80211_stop_queues(ar->hw);
+               ath11k_mac_drain_tx(ar);
+               complete(&ar->scan.started);
+               complete(&ar->scan.completed);
+               complete(&ar->peer_assoc_done);
+               complete(&ar->install_key_done);
+               complete(&ar->vdev_setup_done);
+               complete(&ar->bss_survey_done);
+
+               wake_up(&ar->dp.tx_empty_waitq);
+               idr_for_each(&ar->txmgmt_idr,
+                            ath11k_mac_tx_mgmt_pending_free, ar);
+               idr_destroy(&ar->txmgmt_idr);
+       }
+
+       wake_up(&ab->wmi_sc.tx_credits_wq);
+       wake_up(&ab->peer_mapping_wq);
+
+       ret = ath11k_core_reconfigure_on_crash(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to reconfigure driver on crash recovery\n");
+               return;
+       }
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = &ab->pdevs[i];
+               ar = pdev->ar;
+               if (!ar || ar->state == ATH11K_STATE_OFF)
+                       continue;
+
+               mutex_lock(&ar->conf_mutex);
+
+               switch (ar->state) {
+               case ATH11K_STATE_ON:
+                       ar->state = ATH11K_STATE_RESTARTING;
+                       ath11k_core_halt(ar);
+                       ieee80211_restart_hw(ar->hw);
+                       break;
+               case ATH11K_STATE_OFF:
+                       ath11k_warn(ab,
+                                   "cannot restart radio %d that hasn't been started\n",
+                                   i);
+                       break;
+               case ATH11K_STATE_RESTARTING:
+                       break;
+               case ATH11K_STATE_RESTARTED:
+                       ar->state = ATH11K_STATE_WEDGED;
+                       /* fall through */
+               case ATH11K_STATE_WEDGED:
+                       ath11k_warn(ab,
+                                   "device is wedged, will not restart radio %d\n", i);
+                       break;
+               }
+               mutex_unlock(&ar->conf_mutex);
+       }
+       complete(&ab->driver_recovery);
+}
+
+int ath11k_core_init(struct ath11k_base *ab)
+{
+       struct device *dev = ab->dev;
+       struct rproc *prproc;
+       phandle rproc_phandle;
+       int ret;
+
+       if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) {
+               ath11k_err(ab, "failed to get q6_rproc handle\n");
+               return -ENOENT;
+       }
+
+       prproc = rproc_get_by_phandle(rproc_phandle);
+       if (!prproc) {
+               ath11k_err(ab, "failed to get rproc\n");
+               return -EINVAL;
+       }
+       ab->tgt_rproc = prproc;
+       ab->hw_params = ath11k_hw_params;
+
+       ret = ath11k_core_soc_create(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to create soc core: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void ath11k_core_deinit(struct ath11k_base *ab)
+{
+       mutex_lock(&ab->core_lock);
+
+       ath11k_core_pdev_destroy(ab);
+       ath11k_core_stop(ab);
+
+       mutex_unlock(&ab->core_lock);
+
+       ath11k_ahb_power_down(ab);
+       ath11k_mac_destroy(ab);
+       ath11k_core_soc_destroy(ab);
+}
+
+void ath11k_core_free(struct ath11k_base *ab)
+{
+       kfree(ab);
+}
+
+struct ath11k_base *ath11k_core_alloc(struct device *dev)
+{
+       struct ath11k_base *ab;
+
+       ab = kzalloc(sizeof(*ab), GFP_KERNEL);
+       if (!ab)
+               return NULL;
+
+       init_completion(&ab->driver_recovery);
+
+       ab->workqueue = create_singlethread_workqueue("ath11k_wq");
+       if (!ab->workqueue)
+               goto err_sc_free;
+
+       mutex_init(&ab->core_lock);
+       spin_lock_init(&ab->base_lock);
+
+       INIT_LIST_HEAD(&ab->peers);
+       init_waitqueue_head(&ab->peer_mapping_wq);
+       init_waitqueue_head(&ab->wmi_sc.tx_credits_wq);
+       INIT_WORK(&ab->restart_work, ath11k_core_restart);
+       timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
+       ab->dev = dev;
+
+       return ab;
+
+err_sc_free:
+       kfree(ab);
+       return NULL;
+}
+
+static int __init ath11k_init(void)
+{
+       int ret;
+
+       ret = ath11k_ahb_init();
+       if (ret)
+               printk(KERN_ERR "failed to register ath11k ahb driver: %d\n",
+                      ret);
+       return ret;
+}
+module_init(ath11k_init);
+
+static void __exit ath11k_exit(void)
+{
+       ath11k_ahb_exit();
+}
+module_exit(ath11k_exit);
+
+MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax wireless chip");
+MODULE_LICENSE("Dual BSD/GPL");
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_CORE_H
+#define ATH11K_CORE_H
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/bitfield.h>
+#include "qmi.h"
+#include "htc.h"
+#include "wmi.h"
+#include "hal.h"
+#include "dp.h"
+#include "ce.h"
+#include "mac.h"
+#include "hw.h"
+#include "hal_rx.h"
+#include "reg.h"
+
+#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
+
+#define ATH11K_TX_MGMT_NUM_PENDING_MAX 512
+
+#define ATH11K_TX_MGMT_TARGET_MAX_SUPPORT_WMI 64
+
+/* Pending management packets threshold for dropping probe responses */
+#define ATH11K_PRB_RSP_DROP_THRESHOLD ((ATH11K_TX_MGMT_TARGET_MAX_SUPPORT_WMI * 3) / 4)
+
+#define ATH11K_INVALID_HW_MAC_ID       0xFF
+
+enum ath11k_supported_bw {
+       ATH11K_BW_20    = 0,
+       ATH11K_BW_40    = 1,
+       ATH11K_BW_80    = 2,
+       ATH11K_BW_160   = 3,
+};
+
+enum wme_ac {
+       WME_AC_BE,
+       WME_AC_BK,
+       WME_AC_VI,
+       WME_AC_VO,
+       WME_NUM_AC
+};
+
+#define ATH11K_HT_MCS_MAX      7
+#define ATH11K_VHT_MCS_MAX     9
+#define ATH11K_HE_MCS_MAX      11
+
+static inline enum wme_ac ath11k_tid_to_ac(u32 tid)
+{
+       return (((tid == 0) || (tid == 3)) ? WME_AC_BE :
+               ((tid == 1) || (tid == 2)) ? WME_AC_BK :
+               ((tid == 4) || (tid == 5)) ? WME_AC_VI :
+               WME_AC_VO);
+}
+
+struct ath11k_skb_cb {
+       dma_addr_t paddr;
+       u8 eid;
+       struct ath11k *ar;
+       struct ieee80211_vif *vif;
+} __packed;
+
+struct ath11k_skb_rxcb {
+       dma_addr_t paddr;
+       bool is_first_msdu;
+       bool is_last_msdu;
+       bool is_continuation;
+       struct hal_rx_desc *rx_desc;
+       u8 err_rel_src;
+       u8 err_code;
+       u8 mac_id;
+       u8 unmapped;
+};
+
+enum ath11k_hw_rev {
+       ATH11K_HW_IPQ8074,
+};
+
+enum ath11k_firmware_mode {
+       /* the default mode, standard 802.11 functionality */
+       ATH11K_FIRMWARE_MODE_NORMAL,
+
+       /* factory tests etc */
+       ATH11K_FIRMWARE_MODE_FTM,
+};
+
+#define ATH11K_IRQ_NUM_MAX 52
+#define ATH11K_EXT_IRQ_GRP_NUM_MAX 11
+#define ATH11K_EXT_IRQ_NUM_MAX 16
+
+extern const u8 ath11k_reo_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX];
+extern const u8 ath11k_tx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX];
+extern const u8 ath11k_rx_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX];
+extern const u8 ath11k_rx_err_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX];
+extern const u8 ath11k_rx_wbm_rel_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX];
+extern const u8 ath11k_rxdma2host_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX];
+extern const u8 ath11k_host2rxdma_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX];
+extern const u8 rx_mon_status_ring_mask[ATH11K_EXT_IRQ_GRP_NUM_MAX];
+
+struct ath11k_ext_irq_grp {
+       struct ath11k_base *ab;
+       u32 irqs[ATH11K_EXT_IRQ_NUM_MAX];
+       u32 num_irq;
+       u32 grp_id;
+       struct napi_struct napi;
+       struct net_device napi_ndev;
+       /* Queue of pending packets, not expected to be accessed concurrently
+        * to avoid locking overhead.
+        */
+       struct sk_buff_head pending_q;
+};
+
+#define HEHANDLE_CAP_PHYINFO_SIZE       3
+#define HECAP_PHYINFO_SIZE              9
+#define HECAP_MACINFO_SIZE              5
+#define HECAP_TXRX_MCS_NSS_SIZE         2
+#define HECAP_PPET16_PPET8_MAX_SIZE     25
+
+#define HE_PPET16_PPET8_SIZE            8
+
+/* 802.11ax PPE (PPDU packet Extension) threshold */
+struct he_ppe_threshold {
+       u32 numss_m1;
+       u32 ru_mask;
+       u32 ppet16_ppet8_ru3_ru0[HE_PPET16_PPET8_SIZE];
+};
+
+struct ath11k_he {
+       u8 hecap_macinfo[HECAP_MACINFO_SIZE];
+       u32 hecap_rxmcsnssmap;
+       u32 hecap_txmcsnssmap;
+       u32 hecap_phyinfo[HEHANDLE_CAP_PHYINFO_SIZE];
+       struct he_ppe_threshold   hecap_ppet;
+       u32 heop_param;
+};
+
+#define MAX_RADIOS 3
+
+enum {
+       WMI_HOST_TP_SCALE_MAX   = 0,
+       WMI_HOST_TP_SCALE_50    = 1,
+       WMI_HOST_TP_SCALE_25    = 2,
+       WMI_HOST_TP_SCALE_12    = 3,
+       WMI_HOST_TP_SCALE_MIN   = 4,
+       WMI_HOST_TP_SCALE_SIZE   = 5,
+};
+
+enum ath11k_scan_state {
+       ATH11K_SCAN_IDLE,
+       ATH11K_SCAN_STARTING,
+       ATH11K_SCAN_RUNNING,
+       ATH11K_SCAN_ABORTING,
+};
+
+enum ath11k_dev_flags {
+       ATH11K_CAC_RUNNING,
+       ATH11K_FLAG_CORE_REGISTERED,
+       ATH11K_FLAG_CRASH_FLUSH,
+       ATH11K_FLAG_RAW_MODE,
+       ATH11K_FLAG_HW_CRYPTO_DISABLED,
+       ATH11K_FLAG_BTCOEX,
+       ATH11K_FLAG_RECOVERY,
+       ATH11K_FLAG_UNREGISTERING,
+       ATH11K_FLAG_REGISTERED,
+};
+
+enum ath11k_monitor_flags {
+       ATH11K_FLAG_MONITOR_ENABLED,
+};
+
+struct ath11k_vif {
+       u32 vdev_id;
+       enum wmi_vdev_type vdev_type;
+       enum wmi_vdev_subtype vdev_subtype;
+       u32 beacon_interval;
+       u32 dtim_period;
+       u16 ast_hash;
+       u16 tcl_metadata;
+       u8 hal_addr_search_flags;
+       u8 search_type;
+
+       struct ath11k *ar;
+       struct ieee80211_vif *vif;
+
+       u16 tx_seq_no;
+       struct wmi_wmm_params_all_arg wmm_params;
+       struct list_head list;
+       union {
+               struct {
+                       u32 uapsd;
+               } sta;
+               struct {
+                       /* 127 stations; wmi limit */
+                       u8 tim_bitmap[16];
+                       u8 tim_len;
+                       u32 ssid_len;
+                       u8 ssid[IEEE80211_MAX_SSID_LEN];
+                       bool hidden_ssid;
+                       /* P2P_IE with NoA attribute for P2P_GO case */
+                       u32 noa_len;
+                       u8 *noa_data;
+               } ap;
+       } u;
+
+       bool is_started;
+       bool is_up;
+       u32 aid;
+       u8 bssid[ETH_ALEN];
+       struct cfg80211_bitrate_mask bitrate_mask;
+       int num_legacy_stations;
+       int rtscts_prot_mode;
+       int txpower;
+};
+
+struct ath11k_vif_iter {
+       u32 vdev_id;
+       struct ath11k_vif *arvif;
+};
+
+struct ath11k_rx_peer_stats {
+       u64 num_msdu;
+       u64 num_mpdu_fcs_ok;
+       u64 num_mpdu_fcs_err;
+       u64 tcp_msdu_count;
+       u64 udp_msdu_count;
+       u64 other_msdu_count;
+       u64 ampdu_msdu_count;
+       u64 non_ampdu_msdu_count;
+       u64 stbc_count;
+       u64 beamformed_count;
+       u64 mcs_count[HAL_RX_MAX_MCS + 1];
+       u64 nss_count[HAL_RX_MAX_NSS];
+       u64 bw_count[HAL_RX_BW_MAX];
+       u64 gi_count[HAL_RX_GI_MAX];
+       u64 coding_count[HAL_RX_SU_MU_CODING_MAX];
+       u64 tid_count[IEEE80211_NUM_TIDS + 1];
+       u64 pream_cnt[HAL_RX_PREAMBLE_MAX];
+       u64 reception_type[HAL_RX_RECEPTION_TYPE_MAX];
+       u64 rx_duration;
+};
+
+#define ATH11K_HE_MCS_NUM       12
+#define ATH11K_VHT_MCS_NUM      10
+#define ATH11K_BW_NUM           4
+#define ATH11K_NSS_NUM          4
+#define ATH11K_LEGACY_NUM       12
+#define ATH11K_GI_NUM           4
+#define ATH11K_HT_MCS_NUM       32
+
+enum ath11k_pkt_rx_err {
+       ATH11K_PKT_RX_ERR_FCS,
+       ATH11K_PKT_RX_ERR_TKIP,
+       ATH11K_PKT_RX_ERR_CRYPT,
+       ATH11K_PKT_RX_ERR_PEER_IDX_INVAL,
+       ATH11K_PKT_RX_ERR_MAX,
+};
+
+enum ath11k_ampdu_subfrm_num {
+       ATH11K_AMPDU_SUBFRM_NUM_10,
+       ATH11K_AMPDU_SUBFRM_NUM_20,
+       ATH11K_AMPDU_SUBFRM_NUM_30,
+       ATH11K_AMPDU_SUBFRM_NUM_40,
+       ATH11K_AMPDU_SUBFRM_NUM_50,
+       ATH11K_AMPDU_SUBFRM_NUM_60,
+       ATH11K_AMPDU_SUBFRM_NUM_MORE,
+       ATH11K_AMPDU_SUBFRM_NUM_MAX,
+};
+
+enum ath11k_amsdu_subfrm_num {
+       ATH11K_AMSDU_SUBFRM_NUM_1,
+       ATH11K_AMSDU_SUBFRM_NUM_2,
+       ATH11K_AMSDU_SUBFRM_NUM_3,
+       ATH11K_AMSDU_SUBFRM_NUM_4,
+       ATH11K_AMSDU_SUBFRM_NUM_MORE,
+       ATH11K_AMSDU_SUBFRM_NUM_MAX,
+};
+
+enum ath11k_counter_type {
+       ATH11K_COUNTER_TYPE_BYTES,
+       ATH11K_COUNTER_TYPE_PKTS,
+       ATH11K_COUNTER_TYPE_MAX,
+};
+
+enum ath11k_stats_type {
+       ATH11K_STATS_TYPE_SUCC,
+       ATH11K_STATS_TYPE_FAIL,
+       ATH11K_STATS_TYPE_RETRY,
+       ATH11K_STATS_TYPE_AMPDU,
+       ATH11K_STATS_TYPE_MAX,
+};
+
+struct ath11k_htt_data_stats {
+       u64 legacy[ATH11K_COUNTER_TYPE_MAX][ATH11K_LEGACY_NUM];
+       u64 ht[ATH11K_COUNTER_TYPE_MAX][ATH11K_HT_MCS_NUM];
+       u64 vht[ATH11K_COUNTER_TYPE_MAX][ATH11K_VHT_MCS_NUM];
+       u64 he[ATH11K_COUNTER_TYPE_MAX][ATH11K_HE_MCS_NUM];
+       u64 bw[ATH11K_COUNTER_TYPE_MAX][ATH11K_BW_NUM];
+       u64 nss[ATH11K_COUNTER_TYPE_MAX][ATH11K_NSS_NUM];
+       u64 gi[ATH11K_COUNTER_TYPE_MAX][ATH11K_GI_NUM];
+};
+
+struct ath11k_htt_tx_stats {
+       struct ath11k_htt_data_stats stats[ATH11K_STATS_TYPE_MAX];
+       u64 tx_duration;
+       u64 ba_fails;
+       u64 ack_fails;
+};
+
+struct ath11k_per_ppdu_tx_stats {
+       u16 succ_pkts;
+       u16 failed_pkts;
+       u16 retry_pkts;
+       u32 succ_bytes;
+       u32 failed_bytes;
+       u32 retry_bytes;
+};
+
+struct ath11k_sta {
+       struct ath11k_vif *arvif;
+
+       /* the following are protected by ar->data_lock */
+       u32 changed; /* IEEE80211_RC_* */
+       u32 bw;
+       u32 nss;
+       u32 smps;
+
+       struct work_struct update_wk;
+       struct ieee80211_tx_info tx_info;
+       struct rate_info txrate;
+       struct rate_info last_txrate;
+       u64 rx_duration;
+       u8 rssi_comb;
+       struct ath11k_htt_tx_stats *tx_stats;
+       struct ath11k_rx_peer_stats *rx_stats;
+};
+
+#define ATH11K_NUM_CHANS 41
+#define ATH11K_MAX_5G_CHAN 173
+
+enum ath11k_state {
+       ATH11K_STATE_OFF,
+       ATH11K_STATE_ON,
+       ATH11K_STATE_RESTARTING,
+       ATH11K_STATE_RESTARTED,
+       ATH11K_STATE_WEDGED,
+       /* Add other states as required */
+};
+
+/* Antenna noise floor */
+#define ATH11K_DEFAULT_NOISE_FLOOR -95
+
+struct ath11k_fw_stats {
+       struct dentry *debugfs_fwstats;
+       u32 pdev_id;
+       u32 stats_id;
+       struct list_head pdevs;
+       struct list_head vdevs;
+       struct list_head bcn;
+};
+
+struct ath11k_dbg_htt_stats {
+       u8 type;
+       u8 reset;
+       struct debug_htt_stats_req *stats_req;
+       /* protects shared stats req buffer */
+       spinlock_t lock;
+};
+
+struct ath11k_debug {
+       struct dentry *debugfs_pdev;
+       struct ath11k_dbg_htt_stats htt_stats;
+       u32 extd_tx_stats;
+       struct ath11k_fw_stats fw_stats;
+       struct completion fw_stats_complete;
+       bool fw_stats_done;
+       u32 extd_rx_stats;
+       u32 pktlog_filter;
+       u32 pktlog_mode;
+       u32 pktlog_peer_valid;
+       u8 pktlog_peer_addr[ETH_ALEN];
+};
+
+struct ath11k_per_peer_tx_stats {
+       u32 succ_bytes;
+       u32 retry_bytes;
+       u32 failed_bytes;
+       u16 succ_pkts;
+       u16 retry_pkts;
+       u16 failed_pkts;
+       u32 duration;
+       u8 ba_fails;
+       bool is_ampdu;
+};
+
+#define ATH11K_FLUSH_TIMEOUT (5 * HZ)
+
+struct ath11k_vdev_stop_status {
+       bool stop_in_progress;
+       u32  vdev_id;
+};
+
+struct ath11k {
+       struct ath11k_base *ab;
+       struct ath11k_pdev *pdev;
+       struct ieee80211_hw *hw;
+       struct ieee80211_ops *ops;
+       struct ath11k_pdev_wmi *wmi;
+       struct ath11k_pdev_dp dp;
+       u8 mac_addr[ETH_ALEN];
+       u32 ht_cap_info;
+       u32 vht_cap_info;
+       struct ath11k_he ar_he;
+       enum ath11k_state state;
+       struct {
+               struct completion started;
+               struct completion completed;
+               struct completion on_channel;
+               struct delayed_work timeout;
+               enum ath11k_scan_state state;
+               bool is_roc;
+               int vdev_id;
+               int roc_freq;
+               bool roc_notify;
+       } scan;
+
+       struct {
+               struct ieee80211_supported_band sbands[NUM_NL80211_BANDS];
+       } mac;
+       unsigned long dev_flags;
+       unsigned int filter_flags;
+       unsigned long monitor_flags;
+       u32 min_tx_power;
+       u32 max_tx_power;
+       u32 txpower_limit_2g;
+       u32 txpower_limit_5g;
+       u32 txpower_scale;
+       u32 power_scale;
+       u32 chan_tx_pwr;
+       u32 num_stations;
+       u32 max_num_stations;
+       bool monitor_present;
+       /* To synchronize concurrent synchronous mac80211 callback operations,
+        * concurrent debugfs configuration and concurrent FW statistics events.
+        */
+       struct mutex conf_mutex;
+       /* protects the radio specific data like debug stats, ppdu_stats_info stats,
+        * vdev_stop_status info, scan data, ath11k_sta info, ath11k_vif info,
+        * channel context data, survey info, test mode data.
+        */
+       spinlock_t data_lock;
+
+       struct list_head arvifs;
+       /* should never be NULL; needed for regular htt rx */
+       struct ieee80211_channel *rx_channel;
+
+       /* valid during scan; needed for mgmt rx during scan */
+       struct ieee80211_channel *scan_channel;
+
+       u8 cfg_tx_chainmask;
+       u8 cfg_rx_chainmask;
+       u8 num_rx_chains;
+       u8 num_tx_chains;
+       /* pdev_idx starts from 0 whereas pdev->pdev_id starts with 1 */
+       u8 pdev_idx;
+       u8 lmac_id;
+
+       struct completion peer_assoc_done;
+
+       int install_key_status;
+       struct completion install_key_done;
+
+       int last_wmi_vdev_start_status;
+       struct ath11k_vdev_stop_status vdev_stop_status;
+       struct completion vdev_setup_done;
+
+       int num_peers;
+       int max_num_peers;
+       u32 num_started_vdevs;
+       u32 num_created_vdevs;
+
+       struct idr txmgmt_idr;
+       /* protects txmgmt_idr data */
+       spinlock_t txmgmt_idr_lock;
+       atomic_t num_pending_mgmt_tx;
+
+       /* cycle count is reported twice for each visited channel during scan.
+        * access protected by data_lock
+        */
+       u32 survey_last_rx_clear_count;
+       u32 survey_last_cycle_count;
+
+       /* Channel info events are expected to come in pairs without and with
+        * COMPLETE flag set respectively for each channel visit during scan.
+        *
+        * However there are deviations from this rule. This flag is used to
+        * avoid reporting garbage data.
+        */
+       bool ch_info_can_report_survey;
+       struct survey_info survey[ATH11K_NUM_CHANS];
+       struct completion bss_survey_done;
+
+       struct work_struct regd_update_work;
+
+       struct work_struct wmi_mgmt_tx_work;
+       struct sk_buff_head wmi_mgmt_tx_queue;
+
+       struct ath11k_per_peer_tx_stats peer_tx_stats;
+       struct list_head ppdu_stats_info;
+       u32 ppdu_stat_list_depth;
+
+       struct ath11k_per_peer_tx_stats cached_stats;
+       u32 last_ppdu_id;
+       u32 cached_ppdu_id;
+#ifdef CONFIG_ATH11K_DEBUGFS
+       struct ath11k_debug debug;
+#endif
+       bool dfs_block_radar_events;
+};
+
+struct ath11k_band_cap {
+       u32 max_bw_supported;
+       u32 ht_cap_info;
+       u32 he_cap_info[2];
+       u32 he_mcs;
+       u32 he_cap_phy_info[PSOC_HOST_MAX_PHY_SIZE];
+       struct ath11k_ppe_threshold he_ppet;
+};
+
+struct ath11k_pdev_cap {
+       u32 supported_bands;
+       u32 ampdu_density;
+       u32 vht_cap;
+       u32 vht_mcs;
+       u32 he_mcs;
+       u32 tx_chain_mask;
+       u32 rx_chain_mask;
+       u32 tx_chain_mask_shift;
+       u32 rx_chain_mask_shift;
+       struct ath11k_band_cap band[NUM_NL80211_BANDS];
+};
+
+struct ath11k_pdev {
+       struct ath11k *ar;
+       u32 pdev_id;
+       struct ath11k_pdev_cap cap;
+       u8 mac_addr[ETH_ALEN];
+};
+
+struct ath11k_board_data {
+       const struct firmware *fw;
+       const void *data;
+       size_t len;
+};
+
+/* IPQ8074 HW channel counters frequency value in hertz */
+#define IPQ8074_CC_FREQ_HERTZ 320000
+
+struct ath11k_soc_dp_rx_stats {
+       u32 err_ring_pkts;
+       u32 invalid_rbm;
+       u32 rxdma_error[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX];
+       u32 reo_error[HAL_REO_DEST_RING_ERROR_CODE_MAX];
+       u32 hal_reo_error[DP_REO_DST_RING_MAX];
+};
+
+/* Master structure to hold the hw data which may be used in core module */
+struct ath11k_base {
+       enum ath11k_hw_rev hw_rev;
+       struct platform_device *pdev;
+       struct device *dev;
+       struct ath11k_qmi qmi;
+       struct ath11k_wmi_base wmi_sc;
+       struct completion fw_ready;
+       struct rproc *tgt_rproc;
+       int num_radios;
+       /* HW channel counters frequency value in hertz common to all MACs */
+       u32 cc_freq_hz;
+
+       struct ath11k_htc htc;
+
+       struct ath11k_dp dp;
+
+       void __iomem *mem;
+       unsigned long mem_len;
+
+       const struct ath11k_hif_ops *hif_ops;
+
+       struct ath11k_ce ce;
+       struct timer_list rx_replenish_retry;
+       struct ath11k_hal hal;
+       /* To synchronize core_start/core_stop */
+       struct mutex core_lock;
+       /* Protects data like peers */
+       spinlock_t base_lock;
+       struct ath11k_pdev pdevs[MAX_RADIOS];
+       struct ath11k_pdev __rcu *pdevs_active[MAX_RADIOS];
+       struct ath11k_hal_reg_capabilities_ext hal_reg_cap[MAX_RADIOS];
+       unsigned long long free_vdev_map;
+       struct list_head peers;
+       wait_queue_head_t peer_mapping_wq;
+       u8 mac_addr[ETH_ALEN];
+       bool wmi_ready;
+       u32 wlan_init_status;
+       int irq_num[ATH11K_IRQ_NUM_MAX];
+       struct ath11k_ext_irq_grp ext_irq_grp[ATH11K_EXT_IRQ_GRP_NUM_MAX];
+       struct napi_struct *napi;
+       struct ath11k_targ_cap target_caps;
+       u32 ext_service_bitmap[WMI_SERVICE_EXT_BM_SIZE];
+       bool pdevs_macaddr_valid;
+       int bd_api;
+       struct ath11k_hw_params hw_params;
+       const struct firmware *cal_file;
+
+       /* Below regd's are protected by ab->data_lock */
+       /* This is the regd set for every radio
+        * by the firmware during initializatin
+        */
+       struct ieee80211_regdomain *default_regd[MAX_RADIOS];
+       /* This regd is set during dynamic country setting
+        * This may or may not be used during the runtime
+        */
+       struct ieee80211_regdomain *new_regd[MAX_RADIOS];
+
+       /* Current DFS Regulatory */
+       enum ath11k_dfs_region dfs_region;
+#ifdef CONFIG_ATH11K_DEBUGFS
+       struct dentry *debugfs_soc;
+       struct dentry *debugfs_ath11k;
+#endif
+       struct ath11k_soc_dp_rx_stats soc_stats;
+
+       unsigned long dev_flags;
+       struct completion driver_recovery;
+       struct workqueue_struct *workqueue;
+       struct work_struct restart_work;
+       struct {
+               /* protected by data_lock */
+               u32 fw_crash_counter;
+       } stats;
+};
+
+struct ath11k_fw_stats_pdev {
+       struct list_head list;
+
+       /* PDEV stats */
+       s32 ch_noise_floor;
+       /* Cycles spent transmitting frames */
+       u32 tx_frame_count;
+       /* Cycles spent receiving frames */
+       u32 rx_frame_count;
+       /* Total channel busy time, evidently */
+       u32 rx_clear_count;
+       /* Total on-channel time */
+       u32 cycle_count;
+       u32 phy_err_count;
+       u32 chan_tx_power;
+       u32 ack_rx_bad;
+       u32 rts_bad;
+       u32 rts_good;
+       u32 fcs_bad;
+       u32 no_beacons;
+       u32 mib_int_count;
+
+       /* PDEV TX stats */
+       /* Num HTT cookies queued to dispatch list */
+       s32 comp_queued;
+       /* Num HTT cookies dispatched */
+       s32 comp_delivered;
+       /* Num MSDU queued to WAL */
+       s32 msdu_enqued;
+       /* Num MPDU queue to WAL */
+       s32 mpdu_enqued;
+       /* Num MSDUs dropped by WMM limit */
+       s32 wmm_drop;
+       /* Num Local frames queued */
+       s32 local_enqued;
+       /* Num Local frames done */
+       s32 local_freed;
+       /* Num queued to HW */
+       s32 hw_queued;
+       /* Num PPDU reaped from HW */
+       s32 hw_reaped;
+       /* Num underruns */
+       s32 underrun;
+       /* Num PPDUs cleaned up in TX abort */
+       s32 tx_abort;
+       /* Num MPDUs requed by SW */
+       s32 mpdus_requed;
+       /* excessive retries */
+       u32 tx_ko;
+       /* data hw rate code */
+       u32 data_rc;
+       /* Scheduler self triggers */
+       u32 self_triggers;
+       /* frames dropped due to excessive sw retries */
+       u32 sw_retry_failure;
+       /* illegal rate phy errors      */
+       u32 illgl_rate_phy_err;
+       /* wal pdev continuous xretry */
+       u32 pdev_cont_xretry;
+       /* wal pdev tx timeouts */
+       u32 pdev_tx_timeout;
+       /* wal pdev resets */
+       u32 pdev_resets;
+       /* frames dropped due to non-availability of stateless TIDs */
+       u32 stateless_tid_alloc_failure;
+       /* PhY/BB underrun */
+       u32 phy_underrun;
+       /* MPDU is more than txop limit */
+       u32 txop_ovf;
+
+       /* PDEV RX stats */
+       /* Cnts any change in ring routing mid-ppdu */
+       s32 mid_ppdu_route_change;
+       /* Total number of statuses processed */
+       s32 status_rcvd;
+       /* Extra frags on rings 0-3 */
+       s32 r0_frags;
+       s32 r1_frags;
+       s32 r2_frags;
+       s32 r3_frags;
+       /* MSDUs / MPDUs delivered to HTT */
+       s32 htt_msdus;
+       s32 htt_mpdus;
+       /* MSDUs / MPDUs delivered to local stack */
+       s32 loc_msdus;
+       s32 loc_mpdus;
+       /* AMSDUs that have more MSDUs than the status ring size */
+       s32 oversize_amsdu;
+       /* Number of PHY errors */
+       s32 phy_errs;
+       /* Number of PHY errors drops */
+       s32 phy_err_drop;
+       /* Number of mpdu errors - FCS, MIC, ENC etc. */
+       s32 mpdu_errs;
+};
+
+struct ath11k_fw_stats_vdev {
+       struct list_head list;
+
+       u32 vdev_id;
+       u32 beacon_snr;
+       u32 data_snr;
+       u32 num_tx_frames[WLAN_MAX_AC];
+       u32 num_rx_frames;
+       u32 num_tx_frames_retries[WLAN_MAX_AC];
+       u32 num_tx_frames_failures[WLAN_MAX_AC];
+       u32 num_rts_fail;
+       u32 num_rts_success;
+       u32 num_rx_err;
+       u32 num_rx_discard;
+       u32 num_tx_not_acked;
+       u32 tx_rate_history[MAX_TX_RATE_VALUES];
+       u32 beacon_rssi_history[MAX_TX_RATE_VALUES];
+};
+
+struct ath11k_fw_stats_bcn {
+       struct list_head list;
+
+       u32 vdev_id;
+       u32 tx_bcn_succ_cnt;
+       u32 tx_bcn_outage_cnt;
+};
+
+void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id);
+void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
+                          u8 *mac_addr, u16 ast_hash);
+struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
+                                    const u8 *addr);
+struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
+                                            const u8 *addr);
+struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab, int peer_id);
+int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab);
+int ath11k_core_init(struct ath11k_base *ath11k);
+void ath11k_core_deinit(struct ath11k_base *ath11k);
+struct ath11k_base *ath11k_core_alloc(struct device *dev);
+void ath11k_core_free(struct ath11k_base *ath11k);
+int ath11k_core_fetch_bdf(struct ath11k_base *ath11k,
+                         struct ath11k_board_data *bd);
+void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd);
+
+void ath11k_core_halt(struct ath11k *ar);
+u8 ath11k_core_get_hw_mac_id(struct ath11k_base *ab, int pdev_idx);
+
+static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state)
+{
+       switch (state) {
+       case ATH11K_SCAN_IDLE:
+               return "idle";
+       case ATH11K_SCAN_STARTING:
+               return "starting";
+       case ATH11K_SCAN_RUNNING:
+               return "running";
+       case ATH11K_SCAN_ABORTING:
+               return "aborting";
+       }
+
+       return "unknown";
+}
+
+static inline struct ath11k_skb_cb *ATH11K_SKB_CB(struct sk_buff *skb)
+{
+       return (struct ath11k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data;
+}
+
+static inline struct ath11k_skb_rxcb *ATH11K_SKB_RXCB(struct sk_buff *skb)
+{
+       BUILD_BUG_ON(sizeof(struct ath11k_skb_rxcb) > sizeof(skb->cb));
+       return (struct ath11k_skb_rxcb *)skb->cb;
+}
+
+static inline struct ath11k_vif *ath11k_vif_to_arvif(struct ieee80211_vif *vif)
+{
+       return (struct ath11k_vif *)vif->drv_priv;
+}
+
+#endif /* _CORE_H_ */
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/vmalloc.h>
+#include "core.h"
+#include "debug.h"
+#include "wmi.h"
+#include "hal_rx.h"
+#include "dp_tx.h"
+#include "debug_htt_stats.h"
+#include "peer.h"
+
+void ath11k_info(struct ath11k_base *ab, const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+       dev_info(ab->dev, "%pV", &vaf);
+       /* TODO: Trace the log */
+       va_end(args);
+}
+
+void ath11k_err(struct ath11k_base *ab, const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+       dev_err(ab->dev, "%pV", &vaf);
+       /* TODO: Trace the log */
+       va_end(args);
+}
+
+void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+       dev_warn_ratelimited(ab->dev, "%pV", &vaf);
+       /* TODO: Trace the log */
+       va_end(args);
+}
+
+#ifdef CONFIG_ATH11K_DEBUG
+void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask,
+                 const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+
+       vaf.fmt = fmt;
+       vaf.va = &args;
+
+       if (ath11k_debug_mask & mask)
+               dev_printk(KERN_DEBUG, ab->dev, "%pV", &vaf);
+
+       /* TODO: trace log */
+
+       va_end(args);
+}
+
+void ath11k_dbg_dump(struct ath11k_base *ab,
+                    enum ath11k_debug_mask mask,
+                    const char *msg, const char *prefix,
+                    const void *buf, size_t len)
+{
+       char linebuf[256];
+       size_t linebuflen;
+       const void *ptr;
+
+       if (ath11k_debug_mask & mask) {
+               if (msg)
+                       __ath11k_dbg(ab, mask, "%s\n", msg);
+
+               for (ptr = buf; (ptr - buf) < len; ptr += 16) {
+                       linebuflen = 0;
+                       linebuflen += scnprintf(linebuf + linebuflen,
+                                               sizeof(linebuf) - linebuflen,
+                                               "%s%08x: ",
+                                               (prefix ? prefix : ""),
+                                               (unsigned int)(ptr - buf));
+                       hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,
+                                          linebuf + linebuflen,
+                                          sizeof(linebuf) - linebuflen, true);
+                       dev_printk(KERN_DEBUG, ab->dev, "%s\n", linebuf);
+               }
+       }
+}
+
+#endif
+
+#ifdef CONFIG_ATH11K_DEBUGFS
+static void ath11k_fw_stats_pdevs_free(struct list_head *head)
+{
+       struct ath11k_fw_stats_pdev *i, *tmp;
+
+       list_for_each_entry_safe(i, tmp, head, list) {
+               list_del(&i->list);
+               kfree(i);
+       }
+}
+
+static void ath11k_fw_stats_vdevs_free(struct list_head *head)
+{
+       struct ath11k_fw_stats_vdev *i, *tmp;
+
+       list_for_each_entry_safe(i, tmp, head, list) {
+               list_del(&i->list);
+               kfree(i);
+       }
+}
+
+static void ath11k_fw_stats_bcn_free(struct list_head *head)
+{
+       struct ath11k_fw_stats_bcn *i, *tmp;
+
+       list_for_each_entry_safe(i, tmp, head, list) {
+               list_del(&i->list);
+               kfree(i);
+       }
+}
+
+static void ath11k_debug_fw_stats_reset(struct ath11k *ar)
+{
+       spin_lock_bh(&ar->data_lock);
+       ar->debug.fw_stats_done = false;
+       ath11k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
+       ath11k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
+       spin_unlock_bh(&ar->data_lock);
+}
+
+void ath11k_debug_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct ath11k_fw_stats stats = {};
+       struct ath11k *ar;
+       struct ath11k_pdev *pdev;
+       bool is_end;
+       static unsigned int num_vdev, num_bcn;
+       size_t total_vdevs_started = 0;
+       int i, ret;
+
+       INIT_LIST_HEAD(&stats.pdevs);
+       INIT_LIST_HEAD(&stats.vdevs);
+       INIT_LIST_HEAD(&stats.bcn);
+
+       ret = ath11k_wmi_pull_fw_stats(ab, skb, &stats);
+       if (ret) {
+               ath11k_warn(ab, "failed to pull fw stats: %d\n", ret);
+               goto free;
+       }
+
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
+       if (!ar) {
+               rcu_read_unlock();
+               ath11k_warn(ab, "failed to get ar for pdev_id %d: %d\n",
+                           stats.pdev_id, ret);
+               goto free;
+       }
+
+       spin_lock_bh(&ar->data_lock);
+
+       if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
+               list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
+               ar->debug.fw_stats_done = true;
+               goto complete;
+       }
+
+       if (stats.stats_id == WMI_REQUEST_VDEV_STAT) {
+               if (list_empty(&stats.vdevs)) {
+                       ath11k_warn(ab, "empty vdev stats");
+                       goto complete;
+               }
+               /* FW sends all the active VDEV stats irrespective of PDEV,
+                * hence limit until the count of all VDEVs started
+                */
+               for (i = 0; i < ab->num_radios; i++) {
+                       pdev = rcu_dereference(ab->pdevs_active[i]);
+                       if (pdev && pdev->ar)
+                               total_vdevs_started += ar->num_started_vdevs;
+               }
+
+               is_end = ((++num_vdev) == total_vdevs_started ? true : false);
+
+               list_splice_tail_init(&stats.vdevs,
+                                     &ar->debug.fw_stats.vdevs);
+
+               if (is_end) {
+                       ar->debug.fw_stats_done = true;
+                       num_vdev = 0;
+               }
+               goto complete;
+       }
+
+       if (stats.stats_id == WMI_REQUEST_BCN_STAT) {
+               if (list_empty(&stats.bcn)) {
+                       ath11k_warn(ab, "empty bcn stats");
+                       goto complete;
+               }
+               /* Mark end until we reached the count of all started VDEVs
+                * within the PDEV
+                */
+               is_end = ((++num_bcn) == ar->num_started_vdevs ? true : false);
+
+               list_splice_tail_init(&stats.bcn,
+                                     &ar->debug.fw_stats.bcn);
+
+               if (is_end) {
+                       ar->debug.fw_stats_done = true;
+                       num_bcn = 0;
+               }
+       }
+complete:
+       complete(&ar->debug.fw_stats_complete);
+       rcu_read_unlock();
+       spin_unlock_bh(&ar->data_lock);
+
+free:
+       ath11k_fw_stats_pdevs_free(&stats.pdevs);
+       ath11k_fw_stats_vdevs_free(&stats.vdevs);
+       ath11k_fw_stats_bcn_free(&stats.bcn);
+}
+
+static int ath11k_debug_fw_stats_request(struct ath11k *ar,
+                                        struct stats_request_params *req_param)
+{
+       struct ath11k_base *ab = ar->ab;
+       unsigned long timeout, time_left;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       /* FW stats can get split when exceeding the stats data buffer limit.
+        * In that case, since there is no end marking for the back-to-back
+        * received 'update stats' event, we keep a 3 seconds timeout in case,
+        * fw_stats_done is not marked yet
+        */
+       timeout = jiffies + msecs_to_jiffies(3 * HZ);
+
+       ath11k_debug_fw_stats_reset(ar);
+
+       reinit_completion(&ar->debug.fw_stats_complete);
+
+       ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
+
+       if (ret) {
+               ath11k_warn(ab, "could not request fw stats (%d)\n",
+                           ret);
+               return ret;
+       }
+
+       time_left =
+       wait_for_completion_timeout(&ar->debug.fw_stats_complete,
+                                   1 * HZ);
+       if (!time_left)
+               return -ETIMEDOUT;
+
+       for (;;) {
+               if (time_after(jiffies, timeout))
+                       break;
+
+               spin_lock_bh(&ar->data_lock);
+               if (ar->debug.fw_stats_done) {
+                       spin_unlock_bh(&ar->data_lock);
+                       break;
+               }
+               spin_unlock_bh(&ar->data_lock);
+       }
+       return 0;
+}
+
+static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
+{
+       struct ath11k *ar = inode->i_private;
+       struct ath11k_base *ab = ar->ab;
+       struct stats_request_params req_param;
+       void *buf = NULL;
+       int ret;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH11K_STATE_ON) {
+               ret = -ENETDOWN;
+               goto err_unlock;
+       }
+
+       buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto err_unlock;
+       }
+
+       req_param.pdev_id = ar->pdev->pdev_id;
+       req_param.vdev_id = 0;
+       req_param.stats_id = WMI_REQUEST_PDEV_STAT;
+
+       ret = ath11k_debug_fw_stats_request(ar, &req_param);
+       if (ret) {
+               ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
+               goto err_free;
+       }
+
+       ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+                                buf);
+
+       file->private_data = buf;
+
+       mutex_unlock(&ar->conf_mutex);
+       return 0;
+
+err_free:
+       vfree(buf);
+
+err_unlock:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static int ath11k_release_pdev_stats(struct inode *inode, struct file *file)
+{
+       vfree(file->private_data);
+
+       return 0;
+}
+
+static ssize_t ath11k_read_pdev_stats(struct file *file,
+                                     char __user *user_buf,
+                                     size_t count, loff_t *ppos)
+{
+       const char *buf = file->private_data;
+       size_t len = strlen(buf);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_pdev_stats = {
+       .open = ath11k_open_pdev_stats,
+       .release = ath11k_release_pdev_stats,
+       .read = ath11k_read_pdev_stats,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
+{
+       struct ath11k *ar = inode->i_private;
+       struct stats_request_params req_param;
+       void *buf = NULL;
+       int ret;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH11K_STATE_ON) {
+               ret = -ENETDOWN;
+               goto err_unlock;
+       }
+
+       buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto err_unlock;
+       }
+
+       req_param.pdev_id = ar->pdev->pdev_id;
+       /* VDEV stats is always sent for all active VDEVs from FW */
+       req_param.vdev_id = 0;
+       req_param.stats_id = WMI_REQUEST_VDEV_STAT;
+
+       ret = ath11k_debug_fw_stats_request(ar, &req_param);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
+               goto err_free;
+       }
+
+       ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+                                buf);
+
+       file->private_data = buf;
+
+       mutex_unlock(&ar->conf_mutex);
+       return 0;
+
+err_free:
+       vfree(buf);
+
+err_unlock:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static int ath11k_release_vdev_stats(struct inode *inode, struct file *file)
+{
+       vfree(file->private_data);
+
+       return 0;
+}
+
+static ssize_t ath11k_read_vdev_stats(struct file *file,
+                                     char __user *user_buf,
+                                     size_t count, loff_t *ppos)
+{
+       const char *buf = file->private_data;
+       size_t len = strlen(buf);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_vdev_stats = {
+       .open = ath11k_open_vdev_stats,
+       .release = ath11k_release_vdev_stats,
+       .read = ath11k_read_vdev_stats,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)
+{
+       struct ath11k *ar = inode->i_private;
+       struct ath11k_vif *arvif;
+       struct stats_request_params req_param;
+       void *buf = NULL;
+       int ret;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH11K_STATE_ON) {
+               ret = -ENETDOWN;
+               goto err_unlock;
+       }
+
+       buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto err_unlock;
+       }
+
+       req_param.stats_id = WMI_REQUEST_BCN_STAT;
+       req_param.pdev_id = ar->pdev->pdev_id;
+
+       /* loop all active VDEVs for bcn stats */
+       list_for_each_entry(arvif, &ar->arvifs, list) {
+               if (!arvif->is_up)
+                       continue;
+
+               req_param.vdev_id = arvif->vdev_id;
+               ret = ath11k_debug_fw_stats_request(ar, &req_param);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
+                       goto err_free;
+               }
+       }
+
+       ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+                                buf);
+
+       /* since beacon stats request is looped for all active VDEVs, saved fw
+        * stats is not freed for each request until done for all active VDEVs
+        */
+       spin_lock_bh(&ar->data_lock);
+       ath11k_fw_stats_bcn_free(&ar->debug.fw_stats.bcn);
+       spin_unlock_bh(&ar->data_lock);
+
+       file->private_data = buf;
+
+       mutex_unlock(&ar->conf_mutex);
+       return 0;
+
+err_free:
+       vfree(buf);
+
+err_unlock:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static int ath11k_release_bcn_stats(struct inode *inode, struct file *file)
+{
+       vfree(file->private_data);
+
+       return 0;
+}
+
+static ssize_t ath11k_read_bcn_stats(struct file *file,
+                                    char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       const char *buf = file->private_data;
+       size_t len = strlen(buf);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_bcn_stats = {
+       .open = ath11k_open_bcn_stats,
+       .release = ath11k_release_bcn_stats,
+       .read = ath11k_read_bcn_stats,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
+                                            char __user *user_buf,
+                                            size_t count, loff_t *ppos)
+{
+       const char buf[] =
+               "To simulate firmware crash write one of the keywords to this file:\n"
+               "`assert` - this will send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n"
+               "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+/* Simulate firmware crash:
+ * 'soft': Call wmi command causing firmware hang. This firmware hang is
+ * recoverable by warm firmware reset.
+ * 'hard': Force firmware crash by setting any vdev parameter for not allowed
+ * vdev id. This is hard firmware crash because it is recoverable only by cold
+ * firmware reset.
+ */
+static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
+                                             const char __user *user_buf,
+                                             size_t count, loff_t *ppos)
+{
+       struct ath11k_base *ab = file->private_data;
+       struct ath11k_pdev *pdev;
+       struct ath11k *ar = ab->pdevs[0].ar;
+       char buf[32] = {0};
+       ssize_t rc;
+       int i, ret, radioup;
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = &ab->pdevs[i];
+               ar = pdev->ar;
+               if (ar && ar->state == ATH11K_STATE_ON) {
+                       radioup = 1;
+                       break;
+               }
+       }
+       /* filter partial writes and invalid commands */
+       if (*ppos != 0 || count >= sizeof(buf) || count == 0)
+               return -EINVAL;
+
+       rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
+       if (rc < 0)
+               return rc;
+
+       /* drop the possible '\n' from the end */
+       if (buf[*ppos - 1] == '\n')
+               buf[*ppos - 1] = '\0';
+
+       if (radioup == 0) {
+               ret = -ENETDOWN;
+               goto exit;
+       }
+
+       if (!strcmp(buf, "assert")) {
+               ath11k_info(ab, "simulating firmware assert crash\n");
+               ret = ath11k_wmi_force_fw_hang_cmd(ar,
+                                                  ATH11K_WMI_FW_HANG_ASSERT_TYPE,
+                                                  ATH11K_WMI_FW_HANG_DELAY);
+       } else {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       if (ret) {
+               ath11k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
+               goto exit;
+       }
+
+       ret = count;
+
+exit:
+       return ret;
+}
+
+static const struct file_operations fops_simulate_fw_crash = {
+       .read = ath11k_read_simulate_fw_crash,
+       .write = ath11k_write_simulate_fw_crash,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_write_enable_extd_tx_stats(struct file *file,
+                                                const char __user *ubuf,
+                                                size_t count, loff_t *ppos)
+{
+       struct ath11k *ar = file->private_data;
+       u32 filter;
+       int ret;
+
+       if (kstrtouint_from_user(ubuf, count, 0, &filter))
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH11K_STATE_ON) {
+               ret = -ENETDOWN;
+               goto out;
+       }
+
+       if (filter == ar->debug.extd_tx_stats) {
+               ret = count;
+               goto out;
+       }
+
+       ar->debug.extd_tx_stats = filter;
+       ret = count;
+
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file,
+                                               char __user *ubuf,
+                                               size_t count, loff_t *ppos)
+
+{
+       char buf[32] = {0};
+       struct ath11k *ar = file->private_data;
+       int len = 0;
+
+       mutex_lock(&ar->conf_mutex);
+       len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
+                       ar->debug.extd_tx_stats);
+       mutex_unlock(&ar->conf_mutex);
+
+       return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_extd_tx_stats = {
+       .read = ath11k_read_enable_extd_tx_stats,
+       .write = ath11k_write_enable_extd_tx_stats,
+       .open = simple_open
+};
+
+static ssize_t ath11k_write_extd_rx_stats(struct file *file,
+                                         const char __user *ubuf,
+                                         size_t count, loff_t *ppos)
+{
+       struct ath11k *ar = file->private_data;
+       struct htt_rx_ring_tlv_filter tlv_filter = {0};
+       u32 enable, rx_filter = 0, ring_id;
+       int ret;
+
+       if (kstrtouint_from_user(ubuf, count, 0, &enable))
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH11K_STATE_ON) {
+               ret = -ENETDOWN;
+               goto exit;
+       }
+
+       if (enable > 1) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       if (enable == ar->debug.extd_rx_stats) {
+               ret = count;
+               goto exit;
+       }
+
+       if (enable) {
+               rx_filter =  HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
+               rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
+               rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
+               rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
+               rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
+               rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
+
+               tlv_filter.rx_filter = rx_filter;
+               tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
+               tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
+               tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
+               tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
+                       HTT_RX_FP_DATA_FILTER_FLASG3;
+       } else {
+               tlv_filter = ath11k_mac_mon_status_filter_default;
+       }
+
+       ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id;
+       ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
+                                              HAL_RXDMA_MONITOR_STATUS,
+                                              DP_RX_BUFFER_SIZE, &tlv_filter);
+
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set rx filter for moniter status ring\n");
+               goto exit;
+       }
+
+       ar->debug.extd_rx_stats = enable;
+       ret = count;
+exit:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static ssize_t ath11k_read_extd_rx_stats(struct file *file,
+                                        char __user *ubuf,
+                                        size_t count, loff_t *ppos)
+{
+       struct ath11k *ar = file->private_data;
+       char buf[32];
+       int len = 0;
+
+       mutex_lock(&ar->conf_mutex);
+       len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+                       ar->debug.extd_rx_stats);
+       mutex_unlock(&ar->conf_mutex);
+
+       return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_extd_rx_stats = {
+       .read = ath11k_read_extd_rx_stats,
+       .write = ath11k_write_extd_rx_stats,
+       .open = simple_open,
+};
+
+static ssize_t ath11k_debug_dump_soc_rx_stats(struct file *file,
+                                             char __user *user_buf,
+                                             size_t count, loff_t *ppos)
+{
+       struct ath11k_base *ab = file->private_data;
+       struct ath11k_soc_dp_rx_stats *soc_stats = &ab->soc_stats;
+       int len = 0, i, retval;
+       const int size = 4096;
+       static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
+                       "Overflow", "MPDU len", "FCS", "Decrypt", "TKIP MIC",
+                       "Unencrypt", "MSDU len", "MSDU limit", "WiFi parse",
+                       "AMSDU parse", "SA timeout", "DA timeout",
+                       "Flow timeout", "Flush req"};
+       static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
+                       "Desc addr zero", "Desc inval", "AMPDU in non BA",
+                       "Non BA dup", "BA dup", "Frame 2k jump", "BAR 2k jump",
+                       "Frame OOR", "BAR OOR", "No BA session",
+                       "Frame SN equal SSN", "PN check fail", "2k err",
+                       "PN err", "Desc blocked"};
+
+       char *buf;
+
+       buf = kzalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       len += scnprintf(buf + len, size - len, "SOC RX STATS:\n\n");
+       len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
+                        soc_stats->err_ring_pkts);
+       len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
+                        soc_stats->invalid_rbm);
+       len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
+       for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
+               len += scnprintf(buf + len, size - len, "%s: %u\n",
+                                rxdma_err[i], soc_stats->rxdma_error[i]);
+
+       len += scnprintf(buf + len, size - len, "\nREO errors:\n");
+       for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
+               len += scnprintf(buf + len, size - len, "%s: %u\n",
+                                reo_err[i], soc_stats->reo_error[i]);
+
+       len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
+       len += scnprintf(buf + len, size - len,
+                        "ring0: %u\nring1: %u\nring2: %u\nring3: %u\n",
+                        soc_stats->hal_reo_error[0],
+                        soc_stats->hal_reo_error[1],
+                        soc_stats->hal_reo_error[2],
+                        soc_stats->hal_reo_error[3]);
+
+       if (len > size)
+               len = size;
+       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+
+       return retval;
+}
+
+static const struct file_operations fops_soc_rx_stats = {
+       .read = ath11k_debug_dump_soc_rx_stats,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+int ath11k_debug_pdev_create(struct ath11k_base *ab)
+{
+       ab->debugfs_soc = debugfs_create_dir(ab->hw_params.name, ab->debugfs_ath11k);
+
+       if (IS_ERR_OR_NULL(ab->debugfs_soc)) {
+               if (IS_ERR(ab->debugfs_soc))
+                       return PTR_ERR(ab->debugfs_soc);
+               return -ENOMEM;
+       }
+
+       debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
+                           &fops_simulate_fw_crash);
+
+       debugfs_create_file("soc_rx_stats", 0600, ab->debugfs_soc, ab,
+                           &fops_soc_rx_stats);
+
+       return 0;
+}
+
+void ath11k_debug_pdev_destroy(struct ath11k_base *ab)
+{
+       debugfs_remove_recursive(ab->debugfs_ath11k);
+       ab->debugfs_ath11k = NULL;
+}
+
+int ath11k_debug_soc_create(struct ath11k_base *ab)
+{
+       ab->debugfs_ath11k = debugfs_create_dir("ath11k", NULL);
+
+       if (IS_ERR_OR_NULL(ab->debugfs_ath11k)) {
+               if (IS_ERR(ab->debugfs_ath11k))
+                       return PTR_ERR(ab->debugfs_ath11k);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void ath11k_debug_soc_destroy(struct ath11k_base *ab)
+{
+       debugfs_remove_recursive(ab->debugfs_soc);
+       ab->debugfs_soc = NULL;
+}
+
+void ath11k_debug_fw_stats_init(struct ath11k *ar)
+{
+       struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
+                                                       ar->debug.debugfs_pdev);
+
+       ar->debug.fw_stats.debugfs_fwstats = fwstats_dir;
+
+       /* all stats debugfs files created are under "fw_stats" directory
+        * created per PDEV
+        */
+       debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
+                           &fops_pdev_stats);
+       debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
+                           &fops_vdev_stats);
+       debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
+                           &fops_bcn_stats);
+
+       INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
+       INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
+       INIT_LIST_HEAD(&ar->debug.fw_stats.bcn);
+
+       init_completion(&ar->debug.fw_stats_complete);
+}
+
+static ssize_t ath11k_write_pktlog_filter(struct file *file,
+                                         const char __user *ubuf,
+                                         size_t count, loff_t *ppos)
+{
+       struct ath11k *ar = file->private_data;
+       struct htt_rx_ring_tlv_filter tlv_filter = {0};
+       u32 rx_filter = 0, ring_id, filter, mode;
+       u8 buf[128] = {0};
+       int ret;
+       ssize_t rc;
+
+       mutex_lock(&ar->conf_mutex);
+       if (ar->state != ATH11K_STATE_ON) {
+               ret = -ENETDOWN;
+               goto out;
+       }
+
+       rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
+       if (rc < 0) {
+               ret = rc;
+               goto out;
+       }
+       buf[rc] = '\0';
+
+       ret = sscanf(buf, "0x%x %u", &filter, &mode);
+       if (ret != 2) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (filter) {
+               ret = ath11k_wmi_pdev_pktlog_enable(ar, filter);
+               if (ret) {
+                       ath11k_warn(ar->ab,
+                                   "failed to enable pktlog filter %x: %d\n",
+                                   ar->debug.pktlog_filter, ret);
+                       goto out;
+               }
+       } else {
+               ret = ath11k_wmi_pdev_pktlog_disable(ar);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to disable pktlog: %d\n", ret);
+                       goto out;
+               }
+       }
+
+#define HTT_RX_FILTER_TLV_LITE_MODE \
+                       (HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
+                       HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
+                       HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
+                       HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
+                       HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE | \
+                       HTT_RX_FILTER_TLV_FLAGS_MPDU_START)
+
+       if (mode == ATH11K_PKTLOG_MODE_FULL) {
+               rx_filter = HTT_RX_FILTER_TLV_LITE_MODE |
+                           HTT_RX_FILTER_TLV_FLAGS_MSDU_START |
+                           HTT_RX_FILTER_TLV_FLAGS_MSDU_END |
+                           HTT_RX_FILTER_TLV_FLAGS_MPDU_END |
+                           HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER |
+                           HTT_RX_FILTER_TLV_FLAGS_ATTENTION;
+       } else if (mode == ATH11K_PKTLOG_MODE_LITE) {
+               rx_filter = HTT_RX_FILTER_TLV_LITE_MODE;
+       }
+
+       tlv_filter.rx_filter = rx_filter;
+       if (rx_filter) {
+               tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
+               tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
+               tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
+               tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
+                                              HTT_RX_FP_DATA_FILTER_FLASG3;
+       }
+
+       ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id;
+       ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
+                                              HAL_RXDMA_MONITOR_STATUS,
+                                              DP_RX_BUFFER_SIZE, &tlv_filter);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set rx filter for moniter status ring\n");
+               goto out;
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n",
+                  filter, ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite"));
+
+       ar->debug.pktlog_filter = filter;
+       ar->debug.pktlog_mode = mode;
+       ret = count;
+
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static ssize_t ath11k_read_pktlog_filter(struct file *file,
+                                        char __user *ubuf,
+                                        size_t count, loff_t *ppos)
+
+{
+       char buf[32] = {0};
+       struct ath11k *ar = file->private_data;
+       int len = 0;
+
+       mutex_lock(&ar->conf_mutex);
+       len = scnprintf(buf, sizeof(buf) - len, "%08x %08x\n",
+                       ar->debug.pktlog_filter,
+                       ar->debug.pktlog_mode);
+       mutex_unlock(&ar->conf_mutex);
+
+       return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_pktlog_filter = {
+       .read = ath11k_read_pktlog_filter,
+       .write = ath11k_write_pktlog_filter,
+       .open = simple_open
+};
+
+static ssize_t ath11k_write_simulate_radar(struct file *file,
+                                          const char __user *user_buf,
+                                          size_t count, loff_t *ppos)
+{
+       struct ath11k *ar = file->private_data;
+       int ret;
+
+       ret = ath11k_wmi_simulate_radar(ar);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static const struct file_operations fops_simulate_radar = {
+       .write = ath11k_write_simulate_radar,
+       .open = simple_open
+};
+
+int ath11k_debug_register(struct ath11k *ar)
+{
+       struct ath11k_base *ab = ar->ab;
+       char pdev_name[5];
+       char buf[100] = {0};
+
+       snprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
+
+       ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
+
+       if (IS_ERR_OR_NULL(ar->debug.debugfs_pdev)) {
+               if (IS_ERR(ar->debug.debugfs_pdev))
+                       return PTR_ERR(ar->debug.debugfs_pdev);
+
+               return -ENOMEM;
+       }
+
+       /* Create a symlink under ieee80211/phy* */
+       snprintf(buf, 100, "../../ath11k/%pd2", ar->debug.debugfs_pdev);
+       debugfs_create_symlink("ath11k", ar->hw->wiphy->debugfsdir, buf);
+
+       ath11k_debug_htt_stats_init(ar);
+
+       ath11k_debug_fw_stats_init(ar);
+
+       debugfs_create_file("ext_tx_stats", 0644,
+                           ar->debug.debugfs_pdev, ar,
+                           &fops_extd_tx_stats);
+       debugfs_create_file("ext_rx_stats", 0644,
+                           ar->debug.debugfs_pdev, ar,
+                           &fops_extd_rx_stats);
+       debugfs_create_file("pktlog_filter", 0644,
+                           ar->debug.debugfs_pdev, ar,
+                           &fops_pktlog_filter);
+
+       if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {
+               debugfs_create_file("dfs_simulate_radar", 0200,
+                                   ar->debug.debugfs_pdev, ar,
+                                   &fops_simulate_radar);
+               debugfs_create_bool("dfs_block_radar_events", 0200,
+                                   ar->debug.debugfs_pdev,
+                                   &ar->dfs_block_radar_events);
+       }
+
+       return 0;
+}
+
+void ath11k_debug_unregister(struct ath11k *ar)
+{
+}
+#endif /* CONFIG_ATH11K_DEBUGFS */
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _ATH11K_DEBUG_H_
+#define _ATH11K_DEBUG_H_
+
+#include "hal_tx.h"
+#include "trace.h"
+
+enum ath11k_debug_mask {
+       ATH11K_DBG_AHB          = 0x00000001,
+       ATH11K_DBG_WMI          = 0x00000002,
+       ATH11K_DBG_HTC          = 0x00000004,
+       ATH11K_DBG_DP_HTT       = 0x00000008,
+       ATH11K_DBG_MAC          = 0x00000010,
+       ATH11K_DBG_BOOT         = 0x00000020,
+       ATH11K_DBG_QMI          = 0x00000040,
+       ATH11K_DBG_DATA         = 0x00000080,
+       ATH11K_DBG_MGMT         = 0x00000100,
+       ATH11K_DBG_REG          = 0x00000200,
+       ATH11K_DBG_TESTMODE     = 0x00000400,
+       ATH11k_DBG_HAL          = 0x00000800,
+       ATH11K_DBG_ANY          = 0xffffffff,
+};
+
+/* htt_dbg_ext_stats_type */
+enum ath11k_dbg_htt_ext_stats_type {
+       ATH11K_DBG_HTT_EXT_STATS_RESET                      =  0,
+       ATH11K_DBG_HTT_EXT_STATS_PDEV_TX                    =  1,
+       ATH11K_DBG_HTT_EXT_STATS_PDEV_RX                    =  2,
+       ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_HWQ                =  3,
+       ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED              =  4,
+       ATH11K_DBG_HTT_EXT_STATS_PDEV_ERROR                 =  5,
+       ATH11K_DBG_HTT_EXT_STATS_PDEV_TQM                   =  6,
+       ATH11K_DBG_HTT_EXT_STATS_TQM_CMDQ                   =  7,
+       ATH11K_DBG_HTT_EXT_STATS_TX_DE_INFO                 =  8,
+       ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_RATE               =  9,
+       ATH11K_DBG_HTT_EXT_STATS_PDEV_RX_RATE               =  10,
+       ATH11K_DBG_HTT_EXT_STATS_PEER_INFO                  =  11,
+       ATH11K_DBG_HTT_EXT_STATS_TX_SELFGEN_INFO            =  12,
+       ATH11K_DBG_HTT_EXT_STATS_TX_MU_HWQ                  =  13,
+       ATH11K_DBG_HTT_EXT_STATS_RING_IF_INFO               =  14,
+       ATH11K_DBG_HTT_EXT_STATS_SRNG_INFO                  =  15,
+       ATH11K_DBG_HTT_EXT_STATS_SFM_INFO                   =  16,
+       ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_MU                 =  17,
+       ATH11K_DBG_HTT_EXT_STATS_ACTIVE_PEERS_LIST          =  18,
+       ATH11K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS             =  19,
+       ATH11K_DBG_HTT_EXT_STATS_TWT_SESSIONS               =  20,
+       ATH11K_DBG_HTT_EXT_STATS_REO_RESOURCE_STATS         =  21,
+       ATH11K_DBG_HTT_EXT_STATS_TX_SOUNDING_INFO           =  22,
+
+       /* keep this last */
+       ATH11K_DBG_HTT_NUM_EXT_STATS,
+};
+
+struct debug_htt_stats_req {
+       bool done;
+       u8 pdev_id;
+       u8 type;
+       u8 peer_addr[ETH_ALEN];
+       struct completion cmpln;
+       u32 buf_len;
+       u8 buf[0];
+};
+
+#define ATH11K_HTT_STATS_BUF_SIZE (1024 * 512)
+
+#define ATH11K_FW_STATS_BUF_SIZE (1024 * 1024)
+
+#define ATH11K_HTT_PKTLOG_MAX_SIZE 2048
+
+enum ath11k_pktlog_filter {
+       ATH11K_PKTLOG_RX                = 0x000000001,
+       ATH11K_PKTLOG_TX                = 0x000000002,
+       ATH11K_PKTLOG_RCFIND            = 0x000000004,
+       ATH11K_PKTLOG_RCUPDATE          = 0x000000008,
+       ATH11K_PKTLOG_EVENT_SMART_ANT   = 0x000000020,
+       ATH11K_PKTLOG_EVENT_SW          = 0x000000040,
+       ATH11K_PKTLOG_ANY               = 0x00000006f,
+};
+
+enum ath11k_pktlog_mode {
+       ATH11K_PKTLOG_MODE_LITE = 1,
+       ATH11K_PKTLOG_MODE_FULL = 2,
+};
+
+enum ath11k_pktlog_enum {
+       ATH11K_PKTLOG_TYPE_TX_CTRL      = 1,
+       ATH11K_PKTLOG_TYPE_TX_STAT      = 2,
+       ATH11K_PKTLOG_TYPE_TX_MSDU_ID   = 3,
+       ATH11K_PKTLOG_TYPE_RX_STAT      = 5,
+       ATH11K_PKTLOG_TYPE_RC_FIND      = 6,
+       ATH11K_PKTLOG_TYPE_RC_UPDATE    = 7,
+       ATH11K_PKTLOG_TYPE_TX_VIRT_ADDR = 8,
+       ATH11K_PKTLOG_TYPE_RX_CBF       = 10,
+       ATH11K_PKTLOG_TYPE_RX_STATBUF   = 22,
+       ATH11K_PKTLOG_TYPE_PPDU_STATS   = 23,
+       ATH11K_PKTLOG_TYPE_LITE_RX      = 24,
+};
+
+__printf(2, 3) void ath11k_info(struct ath11k_base *ab, const char *fmt, ...);
+__printf(2, 3) void ath11k_err(struct ath11k_base *ab, const char *fmt, ...);
+__printf(2, 3) void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...);
+
+extern unsigned int ath11k_debug_mask;
+
+#ifdef CONFIG_ATH11K_DEBUG
+__printf(3, 4) void __ath11k_dbg(struct ath11k_base *ab,
+                                enum ath11k_debug_mask mask,
+                                const char *fmt, ...);
+void ath11k_dbg_dump(struct ath11k_base *ab,
+                    enum ath11k_debug_mask mask,
+                    const char *msg, const char *prefix,
+                    const void *buf, size_t len);
+#else /* CONFIG_ATH11K_DEBUG */
+static inline int __ath11k_dbg(struct ath11k_base *ab,
+                              enum ath11k_debug_mask dbg_mask,
+                              const char *fmt, ...)
+{
+       return 0;
+}
+
+static inline void ath11k_dbg_dump(struct ath11k_base *ab,
+                                  enum ath11k_debug_mask mask,
+                                  const char *msg, const char *prefix,
+                                  const void *buf, size_t len)
+{
+}
+#endif /* CONFIG_ATH11K_DEBUG */
+
+#ifdef CONFIG_ATH11K_DEBUGFS
+int ath11k_debug_soc_create(struct ath11k_base *ab);
+void ath11k_debug_soc_destroy(struct ath11k_base *ab);
+int ath11k_debug_pdev_create(struct ath11k_base *ab);
+void ath11k_debug_pdev_destroy(struct ath11k_base *ab);
+int ath11k_debug_register(struct ath11k *ar);
+void ath11k_debug_unregister(struct ath11k *ar);
+void ath11k_dbg_htt_ext_stats_handler(struct ath11k_base *ab,
+                                     struct sk_buff *skb);
+void ath11k_debug_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb);
+
+void ath11k_debug_fw_stats_init(struct ath11k *ar);
+int ath11k_dbg_htt_stats_req(struct ath11k *ar);
+
+static inline bool ath11k_debug_is_pktlog_lite_mode_enabled(struct ath11k *ar)
+{
+       return (ar->debug.pktlog_mode == ATH11K_PKTLOG_MODE_LITE);
+}
+
+static inline bool ath11k_debug_is_pktlog_rx_stats_enabled(struct ath11k *ar)
+{
+       return (!ar->debug.pktlog_peer_valid && ar->debug.pktlog_mode);
+}
+
+static inline bool ath11k_debug_is_pktlog_peer_valid(struct ath11k *ar, u8 *addr)
+{
+       return (ar->debug.pktlog_peer_valid && ar->debug.pktlog_mode &&
+               ether_addr_equal(addr, ar->debug.pktlog_peer_addr));
+}
+
+static inline int ath11k_debug_is_extd_tx_stats_enabled(struct ath11k *ar)
+{
+       return ar->debug.extd_tx_stats;
+}
+
+static inline int ath11k_debug_is_extd_rx_stats_enabled(struct ath11k *ar)
+{
+       return ar->debug.extd_rx_stats;
+}
+#else
+static inline int ath11k_debug_soc_create(struct ath11k_base *ab)
+{
+       return 0;
+}
+
+static inline void ath11k_debug_soc_destroy(struct ath11k_base *ab)
+{
+}
+
+static inline int ath11k_debug_pdev_create(struct ath11k_base *ab)
+{
+       return 0;
+}
+
+static inline void ath11k_debug_pdev_destroy(struct ath11k_base *ab)
+{
+}
+
+static inline int ath11k_debug_register(struct ath11k *ar)
+{
+       return 0;
+}
+
+static inline void ath11k_debug_unregister(struct ath11k *ar)
+{
+}
+
+static inline void ath11k_dbg_htt_ext_stats_handler(struct ath11k_base *ab,
+                                                   struct sk_buff *skb)
+{
+}
+
+static inline void ath11k_debug_fw_stats_process(struct ath11k_base *ab,
+                                                struct sk_buff *skb)
+{
+}
+
+static inline void ath11k_debug_fw_stats_init(struct ath11k *ar)
+{
+}
+
+static inline int ath11k_debug_is_extd_tx_stats_enabled(struct ath11k *ar)
+{
+       return 0;
+}
+
+static inline int ath11k_debug_is_extd_rx_stats_enabled(struct ath11k *ar)
+{
+       return 0;
+}
+
+static inline int ath11k_dbg_htt_stats_req(struct ath11k *ar)
+{
+       return 0;
+}
+
+static inline bool ath11k_debug_is_pktlog_lite_mode_enabled(struct ath11k *ar)
+{
+       return false;
+}
+
+static inline bool ath11k_debug_is_pktlog_rx_stats_enabled(struct ath11k *ar)
+{
+       return false;
+}
+
+static inline bool ath11k_debug_is_pktlog_peer_valid(struct ath11k *ar, u8 *addr)
+{
+       return false;
+}
+#endif /* CONFIG_ATH11K_DEBUGFS */
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                           struct ieee80211_sta *sta, struct dentry *dir);
+void
+ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
+                                   struct ath11k_per_peer_tx_stats *peer_stats,
+                                   u8 legacy_rate_idx);
+void ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar,
+                                              struct sk_buff *msdu,
+                                              struct hal_tx_status *ts);
+#else /* !CONFIG_MAC80211_DEBUGFS */
+static inline void
+ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
+                                   struct ath11k_per_peer_tx_stats *peer_stats,
+                                   u8 legacy_rate_idx)
+{
+}
+
+static inline void
+ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar,
+                                         struct sk_buff *msdu,
+                                         struct hal_tx_status *ts)
+{
+}
+
+#endif /* CONFIG_MAC80211_DEBUGFS*/
+
+#define ath11k_dbg(ar, dbg_mask, fmt, ...)                     \
+do {                                                           \
+       if (ath11k_debug_mask & dbg_mask)                       \
+               __ath11k_dbg(ar, dbg_mask, fmt, ##__VA_ARGS__); \
+} while (0)
+
+#endif /* _ATH11K_DEBUG_H_ */
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/vmalloc.h>
+#include "core.h"
+#include "dp_tx.h"
+#include "dp_rx.h"
+#include "debug.h"
+#include "debug_htt_stats.h"
+
+#define HTT_DBG_OUT(buf, len, fmt, ...) \
+                       scnprintf(buf, len, fmt "\n", ##__VA_ARGS__)
+
+#define HTT_MAX_STRING_LEN 256
+#define HTT_MAX_PRINT_CHAR_PER_ELEM 15
+
+#define HTT_TLV_HDR_LEN 4
+
+#define ARRAY_TO_STRING(out, arr, len)                                                 \
+       do {                                                                            \
+               int index = 0; u8 i;                                                    \
+               for (i = 0; i < len; i++) {                                             \
+                       index += snprintf(out + index, HTT_MAX_STRING_LEN - index,      \
+                                         " %u:%u,", i, arr[i]);                        \
+                       if (index < 0 || index >= HTT_MAX_STRING_LEN)                   \
+                               break;                                                  \
+               }                                                                       \
+       } while (0)
+
+static inline void htt_print_stats_string_tlv(const void *tag_buf,
+                                             u16 tag_len,
+                                             struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_stats_string_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       u8  i;
+       u16 index = 0;
+       char data[HTT_MAX_STRING_LEN] = {0};
+
+       tag_len = tag_len >> 2;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_STATS_STRING_TLV:");
+
+       for (i = 0; i < tag_len; i++) {
+               index += snprintf(&data[index],
+                               HTT_MAX_STRING_LEN - index,
+                               "%.*s", 4, (char *)&(htt_stats_buf->data[i]));
+               if (index >= HTT_MAX_STRING_LEN)
+                       break;
+       }
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "data = %s\n", data);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_tx_pdev_stats_cmn_tlv(const void *tag_buf,
+                                                  struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_stats_cmn_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_CMN_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_queued = %u",
+                          htt_stats_buf->hw_queued);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_reaped = %u",
+                          htt_stats_buf->hw_reaped);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "underrun = %u",
+                          htt_stats_buf->underrun);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_paused = %u",
+                          htt_stats_buf->hw_paused);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_flush = %u",
+                          htt_stats_buf->hw_flush);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_filt = %u",
+                          htt_stats_buf->hw_filt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort = %u",
+                          htt_stats_buf->tx_abort);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_requeued = %u",
+                          htt_stats_buf->mpdu_requed);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_xretry = %u",
+                          htt_stats_buf->tx_xretry);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "data_rc = %u",
+                          htt_stats_buf->data_rc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_dropped_xretry = %u",
+                          htt_stats_buf->mpdu_dropped_xretry);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "illegal_rate_phy_err = %u",
+                          htt_stats_buf->illgl_rate_phy_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "cont_xretry = %u",
+                          htt_stats_buf->cont_xretry);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_timeout = %u",
+                          htt_stats_buf->tx_timeout);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_resets = %u",
+                          htt_stats_buf->pdev_resets);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_underrun = %u",
+                          htt_stats_buf->phy_underrun);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "txop_ovf = %u",
+                          htt_stats_buf->txop_ovf);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_posted = %u",
+                          htt_stats_buf->seq_posted);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_failed_queueing = %u",
+                          htt_stats_buf->seq_failed_queueing);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_completed = %u",
+                          htt_stats_buf->seq_completed);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_restarted = %u",
+                          htt_stats_buf->seq_restarted);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_seq_posted = %u",
+                          htt_stats_buf->mu_seq_posted);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_switch_hw_paused = %u",
+                          htt_stats_buf->seq_switch_hw_paused);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "next_seq_posted_dsr = %u",
+                          htt_stats_buf->next_seq_posted_dsr);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_posted_isr = %u",
+                          htt_stats_buf->seq_posted_isr);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "seq_ctrl_cached = %u",
+                          htt_stats_buf->seq_ctrl_cached);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_count_tqm = %u",
+                          htt_stats_buf->mpdu_count_tqm);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_count_tqm = %u",
+                          htt_stats_buf->msdu_count_tqm);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_removed_tqm = %u",
+                          htt_stats_buf->mpdu_removed_tqm);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_removed_tqm = %u",
+                          htt_stats_buf->msdu_removed_tqm);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_sw_flush = %u",
+                          htt_stats_buf->mpdus_sw_flush);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_hw_filter = %u",
+                          htt_stats_buf->mpdus_hw_filter);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_truncated = %u",
+                          htt_stats_buf->mpdus_truncated);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_ack_failed = %u",
+                          htt_stats_buf->mpdus_ack_failed);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_expired = %u",
+                          htt_stats_buf->mpdus_expired);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_seq_hw_retry = %u",
+                          htt_stats_buf->mpdus_seq_hw_retry);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_tlv_proc = %u",
+                          htt_stats_buf->ack_tlv_proc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "coex_abort_mpdu_cnt_valid = %u",
+                          htt_stats_buf->coex_abort_mpdu_cnt_valid);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "coex_abort_mpdu_cnt = %u",
+                          htt_stats_buf->coex_abort_mpdu_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_total_ppdus_tried_ota = %u",
+                          htt_stats_buf->num_total_ppdus_tried_ota);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_tried_ota = %u",
+                          htt_stats_buf->num_data_ppdus_tried_ota);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "local_ctrl_mgmt_enqued = %u",
+                          htt_stats_buf->local_ctrl_mgmt_enqued);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "local_ctrl_mgmt_freed = %u",
+                          htt_stats_buf->local_ctrl_mgmt_freed);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "local_data_enqued = %u",
+                          htt_stats_buf->local_data_enqued);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "local_data_freed = %u",
+                          htt_stats_buf->local_data_freed);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_tried = %u",
+                          htt_stats_buf->mpdu_tried);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "isr_wait_seq_posted = %u",
+                          htt_stats_buf->isr_wait_seq_posted);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_active_dur_us_low = %u",
+                          htt_stats_buf->tx_active_dur_us_low);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_active_dur_us_high = %u\n",
+                          htt_stats_buf->tx_active_dur_us_high);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_pdev_stats_urrn_tlv_v(const void *tag_buf,
+                                  u16 tag_len,
+                                  struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_stats_urrn_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char urrn_stats[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_URRN_STATS);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_URRN_TLV_V:");
+
+       ARRAY_TO_STRING(urrn_stats, htt_stats_buf->urrn_stats, num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "urrn_stats = %s\n", urrn_stats);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_pdev_stats_flush_tlv_v(const void *tag_buf,
+                                   u16 tag_len,
+                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_stats_flush_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char flush_errs[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_FLUSH_REASON_STATS);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_FLUSH_TLV_V:");
+
+       ARRAY_TO_STRING(flush_errs, htt_stats_buf->flush_errs, num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_errs = %s\n", flush_errs);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_pdev_stats_sifs_tlv_v(const void *tag_buf,
+                                  u16 tag_len,
+                                  struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_stats_sifs_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char sifs_status[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_SIFS_BURST_STATS);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_SIFS_TLV_V:");
+
+       ARRAY_TO_STRING(sifs_status, htt_stats_buf->sifs_status, num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sifs_status = %s\n",
+                          sifs_status);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_pdev_stats_phy_err_tlv_v(const void *tag_buf,
+                                     u16 tag_len,
+                                     struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_stats_phy_err_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char phy_errs[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_PHY_ERR_STATS);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_STATS_PHY_ERR_TLV_V:");
+
+       ARRAY_TO_STRING(phy_errs, htt_stats_buf->phy_errs, num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_errs = %s\n", phy_errs);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_pdev_stats_sifs_hist_tlv_v(const void *tag_buf,
+                                       u16 tag_len,
+                                       struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_stats_sifs_hist_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char sifs_hist_status[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_MAX_SIFS_BURST_HIST_STATS);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_PDEV_STATS_SIFS_HIST_TLV_V:");
+
+       ARRAY_TO_STRING(sifs_hist_status, htt_stats_buf->sifs_hist_status, num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sifs_hist_status = %s\n",
+                          sifs_hist_status);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_pdev_stats_tx_ppdu_stats_tlv_v(const void *tag_buf,
+                                           struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_stats_tx_ppdu_stats_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_PDEV_STATS_TX_PPDU_STATS_TLV_V:");
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_legacy_su = %u",
+                          htt_stats_buf->num_data_ppdus_legacy_su);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ac_su = %u",
+                          htt_stats_buf->num_data_ppdus_ac_su);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ax_su = %u",
+                          htt_stats_buf->num_data_ppdus_ax_su);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ac_su_txbf = %u",
+                          htt_stats_buf->num_data_ppdus_ac_su_txbf);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_data_ppdus_ax_su_txbf = %u\n",
+                          htt_stats_buf->num_data_ppdus_ax_su_txbf);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_pdev_stats_tried_mpdu_cnt_hist_tlv_v(const void *tag_buf,
+                                                 u16 tag_len,
+                                                 struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_stats_tried_mpdu_cnt_hist_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char tried_mpdu_cnt_hist[HTT_MAX_STRING_LEN] = {0};
+       u32  num_elements = ((tag_len - sizeof(htt_stats_buf->hist_bin_size)) >> 2);
+       u32  required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_PDEV_STATS_TRIED_MPDU_CNT_HIST_TLV_V:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u",
+                          htt_stats_buf->hist_bin_size);
+
+       if (required_buffer_size < HTT_MAX_STRING_LEN) {
+               ARRAY_TO_STRING(tried_mpdu_cnt_hist,
+                               htt_stats_buf->tried_mpdu_cnt_hist,
+                               num_elements);
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "tried_mpdu_cnt_hist = %s\n",
+                                  tried_mpdu_cnt_hist);
+       } else {
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "INSUFFICIENT PRINT BUFFER\n");
+       }
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_hw_stats_intr_misc_tlv(const void *tag_buf,
+                                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_hw_stats_intr_misc_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char hw_intr_name[HTT_STATS_MAX_HW_INTR_NAME_LEN + 1] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_INTR_MISC_TLV:");
+       memcpy(hw_intr_name, &(htt_stats_buf->hw_intr_name[0]),
+              HTT_STATS_MAX_HW_INTR_NAME_LEN);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_intr_name = %s ", hw_intr_name);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mask = %u",
+                          htt_stats_buf->mask);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u\n",
+                          htt_stats_buf->count);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_hw_stats_wd_timeout_tlv(const void *tag_buf,
+                                 struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_hw_stats_wd_timeout_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char hw_module_name[HTT_STATS_MAX_HW_MODULE_NAME_LEN + 1] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_WD_TIMEOUT_TLV:");
+       memcpy(hw_module_name, &(htt_stats_buf->hw_module_name[0]),
+              HTT_STATS_MAX_HW_MODULE_NAME_LEN);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_module_name = %s ",
+                          hw_module_name);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u",
+                          htt_stats_buf->count);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_hw_stats_pdev_errs_tlv(const void *tag_buf,
+                                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_hw_stats_pdev_errs_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_PDEV_ERRS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort = %u",
+                          htt_stats_buf->tx_abort);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort_fail_count = %u",
+                          htt_stats_buf->tx_abort_fail_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_abort = %u",
+                          htt_stats_buf->rx_abort);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_abort_fail_count = %u",
+                          htt_stats_buf->rx_abort_fail_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "warm_reset = %u",
+                          htt_stats_buf->warm_reset);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "cold_reset = %u",
+                          htt_stats_buf->cold_reset);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_flush = %u",
+                          htt_stats_buf->tx_flush);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_glb_reset = %u",
+                          htt_stats_buf->tx_glb_reset);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_txq_reset = %u",
+                          htt_stats_buf->tx_txq_reset);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_timeout_reset = %u\n",
+                          htt_stats_buf->rx_timeout_reset);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_msdu_flow_stats_tlv(const void *tag_buf,
+                                                struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_msdu_flow_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_MSDU_FLOW_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_update_timestamp = %u",
+                          htt_stats_buf->last_update_timestamp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_add_timestamp = %u",
+                          htt_stats_buf->last_add_timestamp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_remove_timestamp = %u",
+                          htt_stats_buf->last_remove_timestamp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "total_processed_msdu_count = %u",
+                          htt_stats_buf->total_processed_msdu_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "cur_msdu_count_in_flowq = %u",
+                          htt_stats_buf->cur_msdu_count_in_flowq);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u",
+                          htt_stats_buf->sw_peer_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_flow_no = %u",
+                          htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u",
+                          (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0xF0000) >>
+                          16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "drop_rule = %u",
+                          (htt_stats_buf->tx_flow_no__tid_num__drop_rule & 0x100000) >>
+                          20);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_cycle_enqueue_count = %u",
+                          htt_stats_buf->last_cycle_enqueue_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_cycle_dequeue_count = %u",
+                          htt_stats_buf->last_cycle_dequeue_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_cycle_drop_count = %u",
+                          htt_stats_buf->last_cycle_drop_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "current_drop_th = %u\n",
+                          htt_stats_buf->current_drop_th);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_tx_tid_stats_tlv(const void *tag_buf,
+                                             struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_tid_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char tid_name[MAX_HTT_TID_NAME + 1] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TID_STATS_TLV:");
+       memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_name = %s ", tid_name);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u",
+                          htt_stats_buf->sw_peer_id__tid_num & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u",
+                          (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_sched_pending = %u",
+                          htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_ppdu_in_hwq = %u",
+                          (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq &
+                          0xFF00) >> 8);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_flags = 0x%x",
+                          htt_stats_buf->tid_flags);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_queued = %u",
+                          htt_stats_buf->hw_queued);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hw_reaped = %u",
+                          htt_stats_buf->hw_reaped);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdus_hw_filter = %u",
+                          htt_stats_buf->mpdus_hw_filter);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_bytes = %u",
+                          htt_stats_buf->qdepth_bytes);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_msdu = %u",
+                          htt_stats_buf->qdepth_num_msdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_mpdu = %u",
+                          htt_stats_buf->qdepth_num_mpdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_scheduled_tsmp = %u",
+                          htt_stats_buf->last_scheduled_tsmp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "pause_module_id = %u",
+                          htt_stats_buf->pause_module_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "block_module_id = %u\n",
+                          htt_stats_buf->block_module_id);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_tx_tid_stats_v1_tlv(const void *tag_buf,
+                                                struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_tid_stats_v1_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char tid_name[MAX_HTT_TID_NAME + 1] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TID_STATS_V1_TLV:");
+       memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_name = %s ", tid_name);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u",
+                          htt_stats_buf->sw_peer_id__tid_num & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u",
+                          (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_sched_pending = %u",
+                          htt_stats_buf->num_sched_pending__num_ppdu_in_hwq & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_ppdu_in_hwq = %u",
+                          (htt_stats_buf->num_sched_pending__num_ppdu_in_hwq &
+                          0xFF00) >> 8);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_flags = 0x%x",
+                          htt_stats_buf->tid_flags);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "max_qdepth_bytes = %u",
+                          htt_stats_buf->max_qdepth_bytes);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "max_qdepth_n_msdus = %u",
+                          htt_stats_buf->max_qdepth_n_msdus);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rsvd = %u",
+                          htt_stats_buf->rsvd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_bytes = %u",
+                          htt_stats_buf->qdepth_bytes);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_msdu = %u",
+                          htt_stats_buf->qdepth_num_msdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qdepth_num_mpdu = %u",
+                          htt_stats_buf->qdepth_num_mpdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_scheduled_tsmp = %u",
+                          htt_stats_buf->last_scheduled_tsmp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "pause_module_id = %u",
+                          htt_stats_buf->pause_module_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "block_module_id = %u",
+                          htt_stats_buf->block_module_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "allow_n_flags = 0x%x",
+                          htt_stats_buf->allow_n_flags);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sendn_frms_allowed = %u\n",
+                          htt_stats_buf->sendn_frms_allowed);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_rx_tid_stats_tlv(const void *tag_buf,
+                                             struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_tid_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char tid_name[MAX_HTT_TID_NAME + 1] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_TID_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u",
+                          htt_stats_buf->sw_peer_id__tid_num & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_num = %u",
+                          (htt_stats_buf->sw_peer_id__tid_num & 0xFFFF0000) >> 16);
+       memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tid_name = %s ", tid_name);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "dup_in_reorder = %u",
+                          htt_stats_buf->dup_in_reorder);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "dup_past_outside_window = %u",
+                          htt_stats_buf->dup_past_outside_window);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "dup_past_within_window = %u",
+                          htt_stats_buf->dup_past_within_window);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rxdesc_err_decrypt = %u\n",
+                          htt_stats_buf->rxdesc_err_decrypt);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_counter_tlv(const void *tag_buf,
+                                        struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_counter_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char counter_name[HTT_MAX_STRING_LEN] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_COUNTER_TLV:");
+
+       ARRAY_TO_STRING(counter_name,
+                       htt_stats_buf->counter_name,
+                       HTT_MAX_COUNTER_NAME);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "counter_name = %s ", counter_name);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "count = %u\n",
+                          htt_stats_buf->count);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_peer_stats_cmn_tlv(const void *tag_buf,
+                                               struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_peer_stats_cmn_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PEER_STATS_CMN_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ppdu_cnt = %u",
+                          htt_stats_buf->ppdu_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_cnt = %u",
+                          htt_stats_buf->mpdu_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_cnt = %u",
+                          htt_stats_buf->msdu_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "pause_bitmap = %u",
+                          htt_stats_buf->pause_bitmap);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "block_bitmap = %u",
+                          htt_stats_buf->block_bitmap);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_rssi = %d",
+                          htt_stats_buf->rssi);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueued_count = %llu",
+                          htt_stats_buf->peer_enqueued_count_low |
+                          ((u64)htt_stats_buf->peer_enqueued_count_high << 32));
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "dequeued_count = %llu",
+                          htt_stats_buf->peer_dequeued_count_low |
+                          ((u64)htt_stats_buf->peer_dequeued_count_high << 32));
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "dropped_count = %llu",
+                          htt_stats_buf->peer_dropped_count_low |
+                          ((u64)htt_stats_buf->peer_dropped_count_high << 32));
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "transmitted_ppdu_bytes = %llu",
+                          htt_stats_buf->ppdu_transmitted_bytes_low |
+                          ((u64)htt_stats_buf->ppdu_transmitted_bytes_high << 32));
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ttl_removed_count = %u",
+                          htt_stats_buf->peer_ttl_removed_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "inactive_time = %u\n",
+                          htt_stats_buf->inactive_time);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_peer_details_tlv(const void *tag_buf,
+                                             struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_peer_details_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PEER_DETAILS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "peer_type = %u",
+                          htt_stats_buf->peer_type);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sw_peer_id = %u",
+                          htt_stats_buf->sw_peer_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "vdev_id = %u",
+                          htt_stats_buf->vdev_pdev_ast_idx & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_id = %u",
+                          (htt_stats_buf->vdev_pdev_ast_idx & 0xFF00) >> 8);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ast_idx = %u",
+                          (htt_stats_buf->vdev_pdev_ast_idx & 0xFFFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "mac_addr = %02x:%02x:%02x:%02x:%02x:%02x",
+                          htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF,
+                          (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF00) >> 8,
+                          (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF0000) >> 16,
+                          (htt_stats_buf->mac_addr.mac_addr_l32 & 0xFF000000) >> 24,
+                          (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF),
+                          (htt_stats_buf->mac_addr.mac_addr_h16 & 0xFF00) >> 8);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "peer_flags = 0x%x",
+                          htt_stats_buf->peer_flags);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qpeer_flags = 0x%x\n",
+                          htt_stats_buf->qpeer_flags);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_tx_peer_rate_stats_tlv(const void *tag_buf,
+                                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_peer_rate_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char str_buf[HTT_MAX_STRING_LEN] = {0};
+       char *tx_gi[HTT_TX_PEER_STATS_NUM_GI_COUNTERS];
+       u8 j;
+
+       for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++)
+               tx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PEER_RATE_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_ldpc = %u",
+                          htt_stats_buf->tx_ldpc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u",
+                          htt_stats_buf->rts_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_rssi = %u",
+                          htt_stats_buf->ack_rssi);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_mcs,
+                       HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mcs = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_su_mcs,
+                       HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_su_mcs = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_mu_mcs,
+                       HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mu_mcs = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf,
+                       htt_stats_buf->tx_nss,
+                       HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_nss = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf,
+                       htt_stats_buf->tx_bw,
+                       HTT_TX_PDEV_STATS_NUM_BW_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_bw = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_stbc,
+                       HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_stbc = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_pream,
+                       HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_pream = %s ", str_buf);
+
+       for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++) {
+               ARRAY_TO_STRING(tx_gi[j],
+                               htt_stats_buf->tx_gi[j],
+                               HTT_TX_PEER_STATS_NUM_MCS_COUNTERS);
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_gi[%u] = %s ",
+                               j, tx_gi[j]);
+       }
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf,
+                       htt_stats_buf->tx_dcm,
+                       HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_dcm = %s\n", str_buf);
+
+       for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++)
+               kfree(tx_gi[j]);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_rx_peer_rate_stats_tlv(const void *tag_buf,
+                                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_peer_rate_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       u8 j;
+       char *rssi_chain[HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS];
+       char *rx_gi[HTT_RX_PEER_STATS_NUM_GI_COUNTERS];
+       char str_buf[HTT_MAX_STRING_LEN] = {0};
+
+       for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++)
+               rssi_chain[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC);
+
+       for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++)
+               rx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PEER_RATE_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "nsts = %u",
+                          htt_stats_buf->nsts);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ldpc = %u",
+                          htt_stats_buf->rx_ldpc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u",
+                          htt_stats_buf->rts_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_mgmt = %u",
+                          htt_stats_buf->rssi_mgmt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_data = %u",
+                          htt_stats_buf->rssi_data);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_comb = %u",
+                          htt_stats_buf->rssi_comb);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_mcs,
+                       HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_mcs = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_nss,
+                       HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_nss = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_dcm,
+                       HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_dcm = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_stbc,
+                       HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_stbc = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_bw,
+                       HTT_RX_PDEV_STATS_NUM_BW_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_bw = %s ", str_buf);
+
+       for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++) {
+               ARRAY_TO_STRING(rssi_chain[j], htt_stats_buf->rssi_chain[j],
+                               HTT_RX_PEER_STATS_NUM_BW_COUNTERS);
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_chain[%u] = %s ",
+                                  j, rssi_chain[j]);
+       }
+
+       for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++) {
+               ARRAY_TO_STRING(rx_gi[j], htt_stats_buf->rx_gi[j],
+                               HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS);
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_gi[%u] = %s ",
+                               j, rx_gi[j]);
+       }
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_pream,
+                       HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_pream = %s\n", str_buf);
+
+       for (j = 0; j < HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS; j++)
+               kfree(rssi_chain[j]);
+
+       for (j = 0; j < HTT_RX_PEER_STATS_NUM_GI_COUNTERS; j++)
+               kfree(rx_gi[j]);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_hwq_mu_mimo_sch_stats_tlv(const void *tag_buf,
+                                      struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_hwq_mu_mimo_sch_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_SCH_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_posted = %u",
+                          htt_stats_buf->mu_mimo_sch_posted);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_failed = %u",
+                          htt_stats_buf->mu_mimo_sch_failed);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n",
+                          htt_stats_buf->mu_mimo_ppdu_posted);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_hwq_mu_mimo_mpdu_stats_tlv(const void *tag_buf,
+                                       struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_hwq_mu_mimo_mpdu_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_HWQ_MU_MIMO_MPDU_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_queued_usr = %u",
+                          htt_stats_buf->mu_mimo_mpdus_queued_usr);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_tried_usr = %u",
+                          htt_stats_buf->mu_mimo_mpdus_tried_usr);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_failed_usr = %u",
+                          htt_stats_buf->mu_mimo_mpdus_failed_usr);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdus_requeued_usr = %u",
+                          htt_stats_buf->mu_mimo_mpdus_requeued_usr);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_err_no_ba_usr = %u",
+                          htt_stats_buf->mu_mimo_err_no_ba_usr);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_mpdu_underrun_usr = %u",
+                          htt_stats_buf->mu_mimo_mpdu_underrun_usr);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_ampdu_underrun_usr = %u\n",
+                          htt_stats_buf->mu_mimo_ampdu_underrun_usr);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_hwq_mu_mimo_cmn_stats_tlv(const void *tag_buf,
+                                      struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_hwq_mu_mimo_cmn_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_MU_MIMO_CMN_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__hwq_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hwq_id = %u\n",
+                          (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_hwq_stats_cmn_tlv(const void *tag_buf, struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_hwq_stats_cmn_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       /* TODO: HKDBG */
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_STATS_CMN_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__hwq_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hwq_id = %u",
+                          (htt_stats_buf->mac_id__hwq_id__word & 0xFF00) >> 8);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "xretry = %u",
+                          htt_stats_buf->xretry);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "underrun_cnt = %u",
+                          htt_stats_buf->underrun_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_cnt = %u",
+                          htt_stats_buf->flush_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "filt_cnt = %u",
+                          htt_stats_buf->filt_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "null_mpdu_bmap = %u",
+                          htt_stats_buf->null_mpdu_bmap);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "user_ack_failure = %u",
+                          htt_stats_buf->user_ack_failure);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_tlv_proc = %u",
+                          htt_stats_buf->ack_tlv_proc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_id_proc = %u",
+                          htt_stats_buf->sched_id_proc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "null_mpdu_tx_count = %u",
+                          htt_stats_buf->null_mpdu_tx_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_bmap_not_recvd = %u",
+                          htt_stats_buf->mpdu_bmap_not_recvd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_bar = %u",
+                          htt_stats_buf->num_bar);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rts = %u",
+                          htt_stats_buf->rts);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "cts2self = %u",
+                          htt_stats_buf->cts2self);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qos_null = %u",
+                          htt_stats_buf->qos_null);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_tried_cnt = %u",
+                          htt_stats_buf->mpdu_tried_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_queued_cnt = %u",
+                          htt_stats_buf->mpdu_queued_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_ack_fail_cnt = %u",
+                          htt_stats_buf->mpdu_ack_fail_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_filt_cnt = %u",
+                          htt_stats_buf->mpdu_filt_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "false_mpdu_ack_count = %u",
+                          htt_stats_buf->false_mpdu_ack_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "txq_timeout = %u\n",
+                          htt_stats_buf->txq_timeout);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_hwq_difs_latency_stats_tlv_v(const void *tag_buf,
+                                         u16 tag_len,
+                                         struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_hwq_difs_latency_stats_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       u16 data_len = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_DIFS_LATENCY_BINS);
+       char difs_latency_hist[HTT_MAX_STRING_LEN] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_HWQ_DIFS_LATENCY_STATS_TLV_V:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hist_intvl = %u",
+                       htt_stats_buf->hist_intvl);
+
+       ARRAY_TO_STRING(difs_latency_hist, htt_stats_buf->difs_latency_hist,
+                       data_len);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "difs_latency_hist = %s\n",
+                       difs_latency_hist);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_hwq_cmd_result_stats_tlv_v(const void *tag_buf,
+                                       u16 tag_len,
+                                       struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_hwq_cmd_result_stats_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       u16 data_len;
+       char cmd_result[HTT_MAX_STRING_LEN] = {0};
+
+       data_len = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_CMD_RESULT_STATS);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_HWQ_CMD_RESULT_STATS_TLV_V:");
+
+       ARRAY_TO_STRING(cmd_result, htt_stats_buf->cmd_result, data_len);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "cmd_result = %s\n", cmd_result);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_hwq_cmd_stall_stats_tlv_v(const void *tag_buf,
+                                      u16 tag_len,
+                                      struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_hwq_cmd_stall_stats_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       u16 num_elems;
+       char cmd_stall_status[HTT_MAX_STRING_LEN] = {0};
+
+       num_elems = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_CMD_STALL_STATS);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_HWQ_CMD_STALL_STATS_TLV_V:");
+
+       ARRAY_TO_STRING(cmd_stall_status, htt_stats_buf->cmd_stall_status, num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "cmd_stall_status = %s\n",
+                          cmd_stall_status);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_hwq_fes_result_stats_tlv_v(const void *tag_buf,
+                                       u16 tag_len,
+                                       struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_hwq_fes_result_stats_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       u16 num_elems;
+       char fes_result[HTT_MAX_STRING_LEN] = {0};
+
+       num_elems = min_t(u16, (tag_len >> 2), HTT_TX_HWQ_MAX_FES_RESULT_STATS);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_HWQ_FES_RESULT_STATS_TLV_V:");
+
+       ARRAY_TO_STRING(fes_result, htt_stats_buf->fes_result, num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fes_result = %s\n", fes_result);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_hwq_tried_mpdu_cnt_hist_tlv_v(const void *tag_buf,
+                                          u16 tag_len,
+                                          struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_hwq_tried_mpdu_cnt_hist_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char tried_mpdu_cnt_hist[HTT_MAX_STRING_LEN] = {0};
+       u32  num_elements = ((tag_len -
+                           sizeof(htt_stats_buf->hist_bin_size)) >> 2);
+       u32  required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_HWQ_TRIED_MPDU_CNT_HIST_TLV_V:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "TRIED_MPDU_CNT_HIST_BIN_SIZE : %u",
+                          htt_stats_buf->hist_bin_size);
+
+       if (required_buffer_size < HTT_MAX_STRING_LEN) {
+               ARRAY_TO_STRING(tried_mpdu_cnt_hist,
+                               htt_stats_buf->tried_mpdu_cnt_hist,
+                               num_elements);
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "tried_mpdu_cnt_hist = %s\n",
+                                  tried_mpdu_cnt_hist);
+       } else {
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "INSUFFICIENT PRINT BUFFER ");
+       }
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_hwq_txop_used_cnt_hist_tlv_v(const void *tag_buf,
+                                         u16 tag_len,
+                                         struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_hwq_txop_used_cnt_hist_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char txop_used_cnt_hist[HTT_MAX_STRING_LEN] = {0};
+       u32 num_elements = tag_len >> 2;
+       u32  required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_HWQ_TXOP_USED_CNT_HIST_TLV_V:");
+
+       if (required_buffer_size < HTT_MAX_STRING_LEN) {
+               ARRAY_TO_STRING(txop_used_cnt_hist,
+                               htt_stats_buf->txop_used_cnt_hist,
+                               num_elements);
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "txop_used_cnt_hist = %s\n",
+                                  txop_used_cnt_hist);
+       } else {
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "INSUFFICIENT PRINT BUFFER ");
+       }
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_tx_sounding_stats_tlv(const void *tag_buf,
+                                                  struct debug_htt_stats_req *stats_req)
+{
+       s32 i;
+       const struct htt_tx_sounding_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       const u32 *cbf_20 = htt_stats_buf->cbf_20;
+       const u32 *cbf_40 = htt_stats_buf->cbf_40;
+       const u32 *cbf_80 = htt_stats_buf->cbf_80;
+       const u32 *cbf_160 = htt_stats_buf->cbf_160;
+
+       if (htt_stats_buf->tx_sounding_mode == HTT_TX_AC_SOUNDING_MODE) {
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "\nHTT_TX_AC_SOUNDING_STATS_TLV:\n");
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ac_cbf_20 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u ",
+                                  cbf_20[HTT_IMPLICIT_TXBF_STEER_STATS],
+                                  cbf_20[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS],
+                                  cbf_20[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS],
+                                  cbf_20[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS],
+                                  cbf_20[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]);
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ac_cbf_40 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u",
+                                  cbf_40[HTT_IMPLICIT_TXBF_STEER_STATS],
+                                  cbf_40[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS],
+                                  cbf_40[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS],
+                                  cbf_40[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS],
+                                  cbf_40[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]);
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ac_cbf_80 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u",
+                                  cbf_80[HTT_IMPLICIT_TXBF_STEER_STATS],
+                                  cbf_80[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS],
+                                  cbf_80[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS],
+                                  cbf_80[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS],
+                                  cbf_80[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]);
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ac_cbf_160 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u",
+                                  cbf_160[HTT_IMPLICIT_TXBF_STEER_STATS],
+                                  cbf_160[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS],
+                                  cbf_160[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS],
+                                  cbf_160[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS],
+                                  cbf_160[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]);
+
+               for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS; i++) {
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "Sounding User %u = 20MHz: %u, 40MHz : %u, 80MHz: %u, 160MHz: %u ",
+                                          i,
+                                          htt_stats_buf->sounding[0],
+                                          htt_stats_buf->sounding[1],
+                                          htt_stats_buf->sounding[2],
+                                          htt_stats_buf->sounding[3]);
+               }
+       } else if (htt_stats_buf->tx_sounding_mode == HTT_TX_AX_SOUNDING_MODE) {
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "\nHTT_TX_AX_SOUNDING_STATS_TLV:\n");
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ax_cbf_20 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u ",
+                                  cbf_20[HTT_IMPLICIT_TXBF_STEER_STATS],
+                                  cbf_20[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS],
+                                  cbf_20[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS],
+                                  cbf_20[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS],
+                                  cbf_20[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]);
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ax_cbf_40 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u",
+                                  cbf_40[HTT_IMPLICIT_TXBF_STEER_STATS],
+                                  cbf_40[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS],
+                                  cbf_40[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS],
+                                  cbf_40[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS],
+                                  cbf_40[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]);
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ax_cbf_80 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u",
+                                  cbf_80[HTT_IMPLICIT_TXBF_STEER_STATS],
+                                  cbf_80[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS],
+                                  cbf_80[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS],
+                                  cbf_80[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS],
+                                  cbf_80[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]);
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ax_cbf_160 = IBF : %u, SU_SIFS : %u, SU_RBO : %u, MU_SIFS : %u, MU_RBO : %u",
+                                  cbf_160[HTT_IMPLICIT_TXBF_STEER_STATS],
+                                  cbf_160[HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS],
+                                  cbf_160[HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS],
+                                  cbf_160[HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS],
+                                  cbf_160[HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS]);
+
+               for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS; i++) {
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "Sounding User %u = 20MHz: %u, 40MHz : %u, 80MHz: %u, 160MHz: %u ",
+                                          i,
+                                          htt_stats_buf->sounding[0],
+                                          htt_stats_buf->sounding[1],
+                                          htt_stats_buf->sounding[2],
+                                          htt_stats_buf->sounding[3]);
+               }
+       }
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_selfgen_cmn_stats_tlv(const void *tag_buf,
+                                  struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_selfgen_cmn_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_CMN_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "su_bar = %u",
+                          htt_stats_buf->su_bar);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rts = %u",
+                          htt_stats_buf->rts);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "cts2self = %u",
+                          htt_stats_buf->cts2self);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qos_null = %u",
+                          htt_stats_buf->qos_null);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_1 = %u",
+                          htt_stats_buf->delayed_bar_1);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_2 = %u",
+                          htt_stats_buf->delayed_bar_2);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_3 = %u",
+                          htt_stats_buf->delayed_bar_3);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_4 = %u",
+                          htt_stats_buf->delayed_bar_4);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_5 = %u",
+                          htt_stats_buf->delayed_bar_5);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_6 = %u",
+                          htt_stats_buf->delayed_bar_6);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "delayed_bar_7 = %u\n",
+                          htt_stats_buf->delayed_bar_7);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_selfgen_ac_stats_tlv(const void *tag_buf,
+                                 struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_selfgen_ac_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndpa = %u",
+                          htt_stats_buf->ac_su_ndpa);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndp = %u",
+                          htt_stats_buf->ac_su_ndp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndpa = %u",
+                          htt_stats_buf->ac_mu_mimo_ndpa);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndp = %u",
+                          htt_stats_buf->ac_mu_mimo_ndp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brpoll_1 = %u",
+                          htt_stats_buf->ac_mu_mimo_brpoll_1);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brpoll_2 = %u",
+                          htt_stats_buf->ac_mu_mimo_brpoll_2);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brpoll_3 = %u\n",
+                          htt_stats_buf->ac_mu_mimo_brpoll_3);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_selfgen_ax_stats_tlv(const void *tag_buf,
+                                 struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_selfgen_ax_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndpa = %u",
+                          htt_stats_buf->ax_su_ndpa);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndp = %u",
+                          htt_stats_buf->ax_su_ndp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndpa = %u",
+                          htt_stats_buf->ax_mu_mimo_ndpa);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndp = %u",
+                          htt_stats_buf->ax_mu_mimo_ndp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_1 = %u",
+                          htt_stats_buf->ax_mu_mimo_brpoll_1);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_2 = %u",
+                          htt_stats_buf->ax_mu_mimo_brpoll_2);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_3 = %u",
+                          htt_stats_buf->ax_mu_mimo_brpoll_3);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_4 = %u",
+                          htt_stats_buf->ax_mu_mimo_brpoll_4);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_5 = %u",
+                          htt_stats_buf->ax_mu_mimo_brpoll_5);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_6 = %u",
+                          htt_stats_buf->ax_mu_mimo_brpoll_6);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brpoll_7 = %u",
+                          htt_stats_buf->ax_mu_mimo_brpoll_7);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_basic_trigger = %u",
+                          htt_stats_buf->ax_basic_trigger);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_bsr_trigger = %u",
+                          htt_stats_buf->ax_bsr_trigger);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_bar_trigger = %u",
+                          htt_stats_buf->ax_mu_bar_trigger);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_rts_trigger = %u\n",
+                          htt_stats_buf->ax_mu_rts_trigger);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_selfgen_ac_err_stats_tlv(const void *tag_buf,
+                                     struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_selfgen_ac_err_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_ERR_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndp_err = %u",
+                          htt_stats_buf->ac_su_ndp_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_su_ndpa_err = %u",
+                          htt_stats_buf->ac_su_ndpa_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndpa_err = %u",
+                          htt_stats_buf->ac_mu_mimo_ndpa_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_ndp_err = %u",
+                          htt_stats_buf->ac_mu_mimo_ndp_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brp1_err = %u",
+                          htt_stats_buf->ac_mu_mimo_brp1_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brp2_err = %u",
+                          htt_stats_buf->ac_mu_mimo_brp2_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_brp3_err = %u\n",
+                          htt_stats_buf->ac_mu_mimo_brp3_err);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_selfgen_ax_err_stats_tlv(const void *tag_buf,
+                                     struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_selfgen_ax_err_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_ERR_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndp_err = %u",
+                          htt_stats_buf->ax_su_ndp_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_su_ndpa_err = %u",
+                          htt_stats_buf->ax_su_ndpa_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndpa_err = %u",
+                          htt_stats_buf->ax_mu_mimo_ndpa_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_ndp_err = %u",
+                          htt_stats_buf->ax_mu_mimo_ndp_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp1_err = %u",
+                          htt_stats_buf->ax_mu_mimo_brp1_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp2_err = %u",
+                          htt_stats_buf->ax_mu_mimo_brp2_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp3_err = %u",
+                          htt_stats_buf->ax_mu_mimo_brp3_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp4_err = %u",
+                          htt_stats_buf->ax_mu_mimo_brp4_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp5_err = %u",
+                          htt_stats_buf->ax_mu_mimo_brp5_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp6_err = %u",
+                          htt_stats_buf->ax_mu_mimo_brp6_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_brp7_err = %u",
+                          htt_stats_buf->ax_mu_mimo_brp7_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_basic_trigger_err = %u",
+                          htt_stats_buf->ax_basic_trigger_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_bsr_trigger_err = %u",
+                          htt_stats_buf->ax_bsr_trigger_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_bar_trigger_err = %u",
+                          htt_stats_buf->ax_mu_bar_trigger_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_rts_trigger_err = %u\n",
+                          htt_stats_buf->ax_mu_rts_trigger_err);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_pdev_mu_mimo_sch_stats_tlv(const void *tag_buf,
+                                       struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_mu_mimo_sch_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       u8 i;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_PDEV_MU_MIMO_SCH_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_posted = %u",
+                          htt_stats_buf->mu_mimo_sch_posted);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_sch_failed = %u",
+                          htt_stats_buf->mu_mimo_sch_failed);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n",
+                          htt_stats_buf->mu_mimo_ppdu_posted);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "11ac MU_MIMO SCH STATS:");
+
+       for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS; i++)
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ac_mu_mimo_sch_nusers_%u = %u",
+                                  i, htt_stats_buf->ac_mu_mimo_sch_nusers[i]);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "\n11ax MU_MIMO SCH STATS:");
+
+       for (i = 0; i < HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS; i++)
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ax_mu_mimo_sch_nusers_%u = %u",
+                                  i, htt_stats_buf->ax_mu_mimo_sch_nusers[i]);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "\n11ax OFDMA SCH STATS:");
+
+       for (i = 0; i < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS; i++)
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ax_ofdma_sch_nusers_%u = %u",
+                                  i, htt_stats_buf->ax_ofdma_sch_nusers[i]);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_pdev_mu_mimo_mpdu_stats_tlv(const void *tag_buf,
+                                        struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_mpdu_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       if (htt_stats_buf->tx_sched_mode == HTT_STATS_TX_SCHED_MODE_MU_MIMO_AC) {
+               if (!htt_stats_buf->user_index)
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "HTT_TX_PDEV_MU_MIMO_AC_MPDU_STATS:\n");
+
+               if (htt_stats_buf->user_index <
+                   HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS) {
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ac_mu_mimo_mpdus_queued_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_queued_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ac_mu_mimo_mpdus_tried_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_tried_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ac_mu_mimo_mpdus_failed_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_failed_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ac_mu_mimo_mpdus_requeued_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_requeued_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ac_mu_mimo_err_no_ba_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->err_no_ba_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ac_mu_mimo_mpdu_underrun_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdu_underrun_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ac_mu_mimo_ampdu_underrun_usr_%u = %u\n",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->ampdu_underrun_usr);
+               }
+       }
+
+       if (htt_stats_buf->tx_sched_mode == HTT_STATS_TX_SCHED_MODE_MU_MIMO_AX) {
+               if (!htt_stats_buf->user_index)
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "HTT_TX_PDEV_MU_MIMO_AX_MPDU_STATS:\n");
+
+               if (htt_stats_buf->user_index <
+                   HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS) {
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_mimo_mpdus_queued_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_queued_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_mimo_mpdus_tried_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_tried_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_mimo_mpdus_failed_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_failed_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_mimo_mpdus_requeued_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_requeued_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_mimo_err_no_ba_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->err_no_ba_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_mimo_mpdu_underrun_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdu_underrun_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_mimo_ampdu_underrun_usr_%u = %u\n",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->ampdu_underrun_usr);
+               }
+       }
+
+       if (htt_stats_buf->tx_sched_mode == HTT_STATS_TX_SCHED_MODE_MU_OFDMA_AX) {
+               if (!htt_stats_buf->user_index)
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "HTT_TX_PDEV_AX_MU_OFDMA_MPDU_STATS:\n");
+
+               if (htt_stats_buf->user_index < HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS) {
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_ofdma_mpdus_queued_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_queued_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_ofdma_mpdus_tried_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_tried_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_ofdma_mpdus_failed_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_failed_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_ofdma_mpdus_requeued_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdus_requeued_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_ofdma_err_no_ba_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->err_no_ba_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_ofdma_mpdu_underrun_usr_%u = %u",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->mpdu_underrun_usr);
+                       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                          "ax_mu_ofdma_ampdu_underrun_usr_%u = %u\n",
+                                          htt_stats_buf->user_index,
+                                          htt_stats_buf->ampdu_underrun_usr);
+               }
+       }
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_sched_txq_cmd_posted_tlv_v(const void *tag_buf,
+                                    u16 tag_len,
+                                    struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_sched_txq_cmd_posted_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char sched_cmd_posted[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elements = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_SCHED_TX_MODE_MAX);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_POSTED_TLV_V:");
+
+       ARRAY_TO_STRING(sched_cmd_posted, htt_stats_buf->sched_cmd_posted,
+                       num_elements);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_posted = %s\n",
+                          sched_cmd_posted);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_sched_txq_cmd_reaped_tlv_v(const void *tag_buf,
+                                    u16 tag_len,
+                                    struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_sched_txq_cmd_reaped_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char sched_cmd_reaped[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elements = min_t(u16, (tag_len >> 2), HTT_TX_PDEV_SCHED_TX_MODE_MAX);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SCHED_TXQ_CMD_REAPED_TLV_V:");
+
+       ARRAY_TO_STRING(sched_cmd_reaped, htt_stats_buf->sched_cmd_reaped,
+                       num_elements);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_reaped = %s\n",
+                          sched_cmd_reaped);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_sched_txq_sched_order_su_tlv_v(const void *tag_buf,
+                                        u16 tag_len,
+                                        struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_sched_txq_sched_order_su_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char sched_order_su[HTT_MAX_STRING_LEN] = {0};
+       /* each entry is u32, i.e. 4 bytes */
+       u32 sched_order_su_num_entries =
+               min_t(u32, (tag_len >> 2), HTT_TX_PDEV_NUM_SCHED_ORDER_LOG);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_SCHED_TXQ_SCHED_ORDER_SU_TLV_V:");
+
+       ARRAY_TO_STRING(sched_order_su, htt_stats_buf->sched_order_su,
+                       sched_order_su_num_entries);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_order_su = %s\n",
+                          sched_order_su);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_sched_txq_sched_ineligibility_tlv_v(const void *tag_buf,
+                                             u16 tag_len,
+                                             struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_sched_txq_sched_ineligibility_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char sched_ineligibility[HTT_MAX_STRING_LEN] = {0};
+       /* each entry is u32, i.e. 4 bytes */
+       u32 sched_ineligibility_num_entries = tag_len >> 2;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_SCHED_TXQ_SCHED_INELIGIBILITY_V:");
+
+       ARRAY_TO_STRING(sched_ineligibility, htt_stats_buf->sched_ineligibility,
+                       sched_ineligibility_num_entries);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_ineligibility = %s\n",
+                          sched_ineligibility);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_pdev_stats_sched_per_txq_tlv(const void *tag_buf,
+                                         struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_stats_sched_per_txq_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_PDEV_STATS_SCHED_PER_TXQ_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__txq_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "txq_id = %u",
+                          (htt_stats_buf->mac_id__txq_id__word & 0xFF00) >> 8);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_policy = %u",
+                          htt_stats_buf->sched_policy);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "last_sched_cmd_posted_timestamp = %u",
+                          htt_stats_buf->last_sched_cmd_posted_timestamp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "last_sched_cmd_compl_timestamp = %u",
+                          htt_stats_buf->last_sched_cmd_compl_timestamp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_2_tac_lwm_count = %u",
+                          htt_stats_buf->sched_2_tac_lwm_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_2_tac_ring_full = %u",
+                          htt_stats_buf->sched_2_tac_ring_full);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmd_post_failure = %u",
+                          htt_stats_buf->sched_cmd_post_failure);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_active_tids = %u",
+                          htt_stats_buf->num_active_tids);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_ps_schedules = %u",
+                          htt_stats_buf->num_ps_schedules);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_cmds_pending = %u",
+                          htt_stats_buf->sched_cmds_pending);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tid_register = %u",
+                          htt_stats_buf->num_tid_register);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tid_unregister = %u",
+                          htt_stats_buf->num_tid_unregister);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_qstats_queried = %u",
+                          htt_stats_buf->num_qstats_queried);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qstats_update_pending = %u",
+                          htt_stats_buf->qstats_update_pending);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_qstats_query_timestamp = %u",
+                          htt_stats_buf->last_qstats_query_timestamp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tqm_cmdq_full = %u",
+                          htt_stats_buf->num_tqm_cmdq_full);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_de_sched_algo_trigger = %u",
+                          htt_stats_buf->num_de_sched_algo_trigger);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_rt_sched_algo_trigger = %u",
+                          htt_stats_buf->num_rt_sched_algo_trigger);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tqm_sched_algo_trigger = %u",
+                          htt_stats_buf->num_tqm_sched_algo_trigger);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_sched = %u\n",
+                          htt_stats_buf->notify_sched);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "dur_based_sendn_term = %u\n",
+                          htt_stats_buf->dur_based_sendn_term);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_stats_tx_sched_cmn_tlv(const void *tag_buf,
+                                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_stats_tx_sched_cmn_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_STATS_TX_SCHED_CMN_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "current_timestamp = %u\n",
+                          htt_stats_buf->current_timestamp);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_tqm_gen_mpdu_stats_tlv_v(const void *tag_buf,
+                                     u16 tag_len,
+                                     struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_tqm_gen_mpdu_stats_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char gen_mpdu_end_reason[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elements = min_t(u16, (tag_len >> 2),
+                                HTT_TX_TQM_MAX_LIST_MPDU_END_REASON);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_GEN_MPDU_STATS_TLV_V:");
+
+       ARRAY_TO_STRING(gen_mpdu_end_reason, htt_stats_buf->gen_mpdu_end_reason,
+                       num_elements);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_end_reason = %s\n",
+                          gen_mpdu_end_reason);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_tqm_list_mpdu_stats_tlv_v(const void *tag_buf,
+                                      u16 tag_len,
+                                      struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_tqm_list_mpdu_stats_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char list_mpdu_end_reason[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_TX_TQM_MAX_LIST_MPDU_END_REASON);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_TQM_LIST_MPDU_STATS_TLV_V:");
+
+       ARRAY_TO_STRING(list_mpdu_end_reason, htt_stats_buf->list_mpdu_end_reason,
+                       num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_end_reason = %s\n",
+                          list_mpdu_end_reason);
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_tqm_list_mpdu_cnt_tlv_v(const void *tag_buf,
+                                    u16 tag_len,
+                                    struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_tqm_list_mpdu_cnt_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char list_mpdu_cnt_hist[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2),
+                             HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_LIST_MPDU_CNT_TLV_V:");
+
+       ARRAY_TO_STRING(list_mpdu_cnt_hist, htt_stats_buf->list_mpdu_cnt_hist,
+                       num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_cnt_hist = %s\n",
+                          list_mpdu_cnt_hist);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_tqm_pdev_stats_tlv_v(const void *tag_buf,
+                                 struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_tqm_pdev_stats_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_PDEV_STATS_TLV_V:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_count = %u",
+                          htt_stats_buf->msdu_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_count = %u",
+                          htt_stats_buf->mpdu_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu = %u",
+                          htt_stats_buf->remove_msdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu = %u",
+                          htt_stats_buf->remove_mpdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_ttl = %u",
+                          htt_stats_buf->remove_msdu_ttl);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "send_bar = %u",
+                          htt_stats_buf->send_bar);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "bar_sync = %u",
+                          htt_stats_buf->bar_sync);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_mpdu = %u",
+                          htt_stats_buf->notify_mpdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sync_cmd = %u",
+                          htt_stats_buf->sync_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "write_cmd = %u",
+                          htt_stats_buf->write_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_trigger = %u",
+                          htt_stats_buf->hwsch_trigger);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_tlv_proc = %u",
+                          htt_stats_buf->ack_tlv_proc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_cmd = %u",
+                          htt_stats_buf->gen_mpdu_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_list_cmd = %u",
+                          htt_stats_buf->gen_list_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu_cmd = %u",
+                          htt_stats_buf->remove_mpdu_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu_tried_cmd = %u",
+                          htt_stats_buf->remove_mpdu_tried_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u",
+                          htt_stats_buf->mpdu_queue_stats_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_head_info_cmd = %u",
+                          htt_stats_buf->mpdu_head_info_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u",
+                          htt_stats_buf->msdu_flow_stats_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_cmd = %u",
+                          htt_stats_buf->remove_msdu_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_ttl_cmd = %u",
+                          htt_stats_buf->remove_msdu_ttl_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_cache_cmd = %u",
+                          htt_stats_buf->flush_cache_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "update_mpduq_cmd = %u",
+                          htt_stats_buf->update_mpduq_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueue = %u",
+                          htt_stats_buf->enqueue);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueue_notify = %u",
+                          htt_stats_buf->enqueue_notify);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_mpdu_at_head = %u",
+                          htt_stats_buf->notify_mpdu_at_head);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "notify_mpdu_state_valid = %u",
+                          htt_stats_buf->notify_mpdu_state_valid);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_udp_notify1 = %u",
+                          htt_stats_buf->sched_udp_notify1);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_udp_notify2 = %u",
+                          htt_stats_buf->sched_udp_notify2);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_nonudp_notify1 = %u",
+                          htt_stats_buf->sched_nonudp_notify1);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sched_nonudp_notify2 = %u\n",
+                          htt_stats_buf->sched_nonudp_notify2);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_tx_tqm_cmn_stats_tlv(const void *tag_buf,
+                                                 struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_tqm_cmn_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_CMN_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "max_cmdq_id = %u",
+                          htt_stats_buf->max_cmdq_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "list_mpdu_cnt_hist_intvl = %u",
+                          htt_stats_buf->list_mpdu_cnt_hist_intvl);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "add_msdu = %u",
+                          htt_stats_buf->add_msdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "q_empty = %u",
+                          htt_stats_buf->q_empty);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "q_not_empty = %u",
+                          htt_stats_buf->q_not_empty);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "drop_notification = %u",
+                          htt_stats_buf->drop_notification);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "desc_threshold = %u\n",
+                          htt_stats_buf->desc_threshold);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_tx_tqm_error_stats_tlv(const void *tag_buf,
+                                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_tqm_error_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_ERROR_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "q_empty_failure = %u",
+                          htt_stats_buf->q_empty_failure);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "q_not_empty_failure = %u",
+                          htt_stats_buf->q_not_empty_failure);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "add_msdu_failure = %u\n",
+                          htt_stats_buf->add_msdu_failure);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_tx_tqm_cmdq_status_tlv(const void *tag_buf,
+                                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_tqm_cmdq_status_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_TQM_CMDQ_STATUS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__cmdq_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "cmdq_id = %u\n",
+                          (htt_stats_buf->mac_id__cmdq_id__word & 0xFF00) >> 8);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sync_cmd = %u",
+                          htt_stats_buf->sync_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "write_cmd = %u",
+                          htt_stats_buf->write_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "gen_mpdu_cmd = %u",
+                          htt_stats_buf->gen_mpdu_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_queue_stats_cmd = %u",
+                          htt_stats_buf->mpdu_queue_stats_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_head_info_cmd = %u",
+                          htt_stats_buf->mpdu_head_info_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "msdu_flow_stats_cmd = %u",
+                          htt_stats_buf->msdu_flow_stats_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_mpdu_cmd = %u",
+                          htt_stats_buf->remove_mpdu_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "remove_msdu_cmd = %u",
+                          htt_stats_buf->remove_msdu_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "flush_cache_cmd = %u",
+                          htt_stats_buf->flush_cache_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "update_mpduq_cmd = %u",
+                          htt_stats_buf->update_mpduq_cmd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "update_msduq_cmd = %u\n",
+                          htt_stats_buf->update_msduq_cmd);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_de_eapol_packets_stats_tlv(const void *tag_buf,
+                                       struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_de_eapol_packets_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_DE_EAPOL_PACKETS_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "m1_packets = %u",
+                          htt_stats_buf->m1_packets);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "m2_packets = %u",
+                          htt_stats_buf->m2_packets);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "m3_packets = %u",
+                          htt_stats_buf->m3_packets);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "m4_packets = %u",
+                          htt_stats_buf->m4_packets);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "g1_packets = %u",
+                          htt_stats_buf->g1_packets);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "g2_packets = %u\n",
+                          htt_stats_buf->g2_packets);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_de_classify_failed_stats_tlv(const void *tag_buf,
+                                         struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_de_classify_failed_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_DE_CLASSIFY_FAILED_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ap_bss_peer_not_found = %u",
+                          htt_stats_buf->ap_bss_peer_not_found);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ap_bcast_mcast_no_peer = %u",
+                          htt_stats_buf->ap_bcast_mcast_no_peer);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sta_delete_in_progress = %u",
+                          htt_stats_buf->sta_delete_in_progress);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ibss_no_bss_peer = %u",
+                          htt_stats_buf->ibss_no_bss_peer);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_vdev_type = %u",
+                          htt_stats_buf->invalid_vdev_type);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_ast_peer_entry = %u",
+                          htt_stats_buf->invalid_ast_peer_entry);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "peer_entry_invalid = %u",
+                          htt_stats_buf->peer_entry_invalid);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ethertype_not_ip = %u",
+                          htt_stats_buf->ethertype_not_ip);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "eapol_lookup_failed = %u",
+                          htt_stats_buf->eapol_lookup_failed);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qpeer_not_allow_data = %u",
+                          htt_stats_buf->qpeer_not_allow_data);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_tid_override = %u",
+                          htt_stats_buf->fse_tid_override);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ipv6_jumbogram_zero_length = %u",
+                          htt_stats_buf->ipv6_jumbogram_zero_length);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "qos_to_non_qos_in_prog = %u\n",
+                          htt_stats_buf->qos_to_non_qos_in_prog);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_de_classify_stats_tlv(const void *tag_buf,
+                                  struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_de_classify_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_DE_CLASSIFY_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "arp_packets = %u",
+                          htt_stats_buf->arp_packets);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "igmp_packets = %u",
+                          htt_stats_buf->igmp_packets);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "dhcp_packets = %u",
+                          htt_stats_buf->dhcp_packets);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "host_inspected = %u",
+                          htt_stats_buf->host_inspected);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_included = %u",
+                          htt_stats_buf->htt_included);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_mcs = %u",
+                          htt_stats_buf->htt_valid_mcs);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_nss = %u",
+                          htt_stats_buf->htt_valid_nss);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_preamble_type = %u",
+                          htt_stats_buf->htt_valid_preamble_type);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_chainmask = %u",
+                          htt_stats_buf->htt_valid_chainmask);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_guard_interval = %u",
+                          htt_stats_buf->htt_valid_guard_interval);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_retries = %u",
+                          htt_stats_buf->htt_valid_retries);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_bw_info = %u",
+                          htt_stats_buf->htt_valid_bw_info);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_power = %u",
+                          htt_stats_buf->htt_valid_power);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_key_flags = 0x%x",
+                          htt_stats_buf->htt_valid_key_flags);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_valid_no_encryption = %u",
+                          htt_stats_buf->htt_valid_no_encryption);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_entry_count = %u",
+                          htt_stats_buf->fse_entry_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_priority_be = %u",
+                          htt_stats_buf->fse_priority_be);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_priority_high = %u",
+                          htt_stats_buf->fse_priority_high);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_priority_low = %u",
+                          htt_stats_buf->fse_priority_low);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_be = %u",
+                          htt_stats_buf->fse_traffic_ptrn_be);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_over_sub = %u",
+                          htt_stats_buf->fse_traffic_ptrn_over_sub);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_bursty = %u",
+                          htt_stats_buf->fse_traffic_ptrn_bursty);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_interactive = %u",
+                          htt_stats_buf->fse_traffic_ptrn_interactive);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_traffic_ptrn_periodic = %u",
+                          htt_stats_buf->fse_traffic_ptrn_periodic);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_hwqueue_alloc = %u",
+                          htt_stats_buf->fse_hwqueue_alloc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_hwqueue_created = %u",
+                          htt_stats_buf->fse_hwqueue_created);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_hwqueue_send_to_host = %u",
+                          htt_stats_buf->fse_hwqueue_send_to_host);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mcast_entry = %u",
+                          htt_stats_buf->mcast_entry);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "bcast_entry = %u",
+                          htt_stats_buf->bcast_entry);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_update_peer_cache = %u",
+                          htt_stats_buf->htt_update_peer_cache);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "htt_learning_frame = %u",
+                          htt_stats_buf->htt_learning_frame);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fse_invalid_peer = %u",
+                          htt_stats_buf->fse_invalid_peer);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mec_notify = %u\n",
+                          htt_stats_buf->mec_notify);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_de_classify_status_stats_tlv(const void *tag_buf,
+                                         struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_de_classify_status_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_DE_CLASSIFY_STATUS_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "eok = %u",
+                          htt_stats_buf->eok);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "classify_done = %u",
+                          htt_stats_buf->classify_done);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "lookup_failed = %u",
+                          htt_stats_buf->lookup_failed);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host_dhcp = %u",
+                          htt_stats_buf->send_host_dhcp);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host_mcast = %u",
+                          htt_stats_buf->send_host_mcast);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host_unknown_dest = %u",
+                          htt_stats_buf->send_host_unknown_dest);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "send_host = %u",
+                          htt_stats_buf->send_host);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "status_invalid = %u\n",
+                          htt_stats_buf->status_invalid);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_de_enqueue_packets_stats_tlv(const void *tag_buf,
+                                         struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_de_enqueue_packets_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_DE_ENQUEUE_PACKETS_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "enqueued_pkts = %u",
+                       htt_stats_buf->enqueued_pkts);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "to_tqm = %u",
+                       htt_stats_buf->to_tqm);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "to_tqm_bypass = %u\n",
+                       htt_stats_buf->to_tqm_bypass);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_de_enqueue_discard_stats_tlv(const void *tag_buf,
+                                         struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_de_enqueue_discard_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_DE_ENQUEUE_DISCARD_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "discarded_pkts = %u",
+                          htt_stats_buf->discarded_pkts);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "local_frames = %u",
+                          htt_stats_buf->local_frames);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "is_ext_msdu = %u\n",
+                          htt_stats_buf->is_ext_msdu);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_tx_de_compl_stats_tlv(const void *tag_buf,
+                                                  struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_de_compl_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_DE_COMPL_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tcl_dummy_frame = %u",
+                          htt_stats_buf->tcl_dummy_frame);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tqm_dummy_frame = %u",
+                          htt_stats_buf->tqm_dummy_frame);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tqm_notify_frame = %u",
+                          htt_stats_buf->tqm_notify_frame);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw2wbm_enq = %u",
+                          htt_stats_buf->fw2wbm_enq);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tqm_bypass_frame = %u\n",
+                          htt_stats_buf->tqm_bypass_frame);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_de_fw2wbm_ring_full_hist_tlv(const void *tag_buf,
+                                         u16 tag_len,
+                                         struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_de_fw2wbm_ring_full_hist_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char fw2wbm_ring_full_hist[HTT_MAX_STRING_LEN] = {0};
+       u16  num_elements = tag_len >> 2;
+       u32  required_buffer_size = HTT_MAX_PRINT_CHAR_PER_ELEM * num_elements;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_TX_DE_FW2WBM_RING_FULL_HIST_TLV");
+
+       if (required_buffer_size < HTT_MAX_STRING_LEN) {
+               ARRAY_TO_STRING(fw2wbm_ring_full_hist,
+                               htt_stats_buf->fw2wbm_ring_full_hist,
+                               num_elements);
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "fw2wbm_ring_full_hist = %s\n",
+                                  fw2wbm_ring_full_hist);
+       } else {
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "INSUFFICIENT PRINT BUFFER ");
+       }
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_tx_de_cmn_stats_tlv(const void *tag_buf, struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_de_cmn_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_DE_CMN_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tcl2fw_entry_count = %u",
+                          htt_stats_buf->tcl2fw_entry_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "not_to_fw = %u",
+                          htt_stats_buf->not_to_fw);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_pdev_vdev_peer = %u",
+                          htt_stats_buf->invalid_pdev_vdev_peer);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tcl_res_invalid_addrx = %u",
+                          htt_stats_buf->tcl_res_invalid_addrx);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm2fw_entry_count = %u",
+                          htt_stats_buf->wbm2fw_entry_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "invalid_pdev = %u\n",
+                          htt_stats_buf->invalid_pdev);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_ring_if_stats_tlv(const void *tag_buf,
+                                              struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_ring_if_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char low_wm_hit_count[HTT_MAX_STRING_LEN] = {0};
+       char high_wm_hit_count[HTT_MAX_STRING_LEN] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RING_IF_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "base_addr = %u",
+                          htt_stats_buf->base_addr);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "elem_size = %u",
+                          htt_stats_buf->elem_size);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_elems = %u",
+                          htt_stats_buf->num_elems__prefetch_tail_idx & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "prefetch_tail_idx = %u",
+                          (htt_stats_buf->num_elems__prefetch_tail_idx &
+                          0xFFFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "head_idx = %u",
+                          htt_stats_buf->head_idx__tail_idx & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tail_idx = %u",
+                          (htt_stats_buf->head_idx__tail_idx & 0xFFFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "shadow_head_idx = %u",
+                          htt_stats_buf->shadow_head_idx__shadow_tail_idx & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "shadow_tail_idx = %u",
+                          (htt_stats_buf->shadow_head_idx__shadow_tail_idx &
+                          0xFFFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_tail_incr = %u",
+                          htt_stats_buf->num_tail_incr);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "lwm_thresh = %u",
+                          htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hwm_thresh = %u",
+                          (htt_stats_buf->lwm_thresh__hwm_thresh & 0xFFFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "overrun_hit_count = %u",
+                          htt_stats_buf->overrun_hit_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "underrun_hit_count = %u",
+                          htt_stats_buf->underrun_hit_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "prod_blockwait_count = %u",
+                          htt_stats_buf->prod_blockwait_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "cons_blockwait_count = %u",
+                          htt_stats_buf->cons_blockwait_count);
+
+       ARRAY_TO_STRING(low_wm_hit_count, htt_stats_buf->low_wm_hit_count,
+                       HTT_STATS_LOW_WM_BINS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "low_wm_hit_count = %s ",
+                          low_wm_hit_count);
+
+       ARRAY_TO_STRING(high_wm_hit_count, htt_stats_buf->high_wm_hit_count,
+                       HTT_STATS_HIGH_WM_BINS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "high_wm_hit_count = %s\n",
+                          high_wm_hit_count);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_ring_if_cmn_tlv(const void *tag_buf,
+                                            struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_ring_if_cmn_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RING_IF_CMN_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u\n",
+                          htt_stats_buf->num_records);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_sfm_client_user_tlv_v(const void *tag_buf,
+                                                  u16 tag_len,
+                                                  struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_sfm_client_user_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char dwords_used_by_user_n[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = tag_len >> 2;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV_V:");
+
+       ARRAY_TO_STRING(dwords_used_by_user_n,
+                       htt_stats_buf->dwords_used_by_user_n,
+                       num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "dwords_used_by_user_n = %s\n",
+                          dwords_used_by_user_n);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_sfm_client_tlv(const void *tag_buf,
+                                           struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_sfm_client_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CLIENT_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "client_id = %u",
+                          htt_stats_buf->client_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_min = %u",
+                          htt_stats_buf->buf_min);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_max = %u",
+                          htt_stats_buf->buf_max);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_busy = %u",
+                          htt_stats_buf->buf_busy);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_alloc = %u",
+                          htt_stats_buf->buf_alloc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_avail = %u",
+                          htt_stats_buf->buf_avail);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_users = %u\n",
+                          htt_stats_buf->num_users);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_sfm_cmn_tlv(const void *tag_buf,
+                                        struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_sfm_cmn_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SFM_CMN_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "buf_total = %u",
+                          htt_stats_buf->buf_total);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mem_empty = %u",
+                          htt_stats_buf->mem_empty);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "deallocate_bufs = %u",
+                          htt_stats_buf->deallocate_bufs);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u\n",
+                          htt_stats_buf->num_records);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_sring_stats_tlv(const void *tag_buf,
+                                            struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_sring_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SRING_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ring_id = %u",
+                          (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF00) >> 8);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "arena = %u",
+                          (htt_stats_buf->mac_id__ring_id__arena__ep & 0xFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ep = %u",
+                          (htt_stats_buf->mac_id__ring_id__arena__ep & 0x1000000) >> 24);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "base_addr_lsb = 0x%x",
+                          htt_stats_buf->base_addr_lsb);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "base_addr_msb = 0x%x",
+                          htt_stats_buf->base_addr_msb);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ring_size = %u",
+                          htt_stats_buf->ring_size);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "elem_size = %u",
+                          htt_stats_buf->elem_size);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_avail_words = %u",
+                          htt_stats_buf->num_avail_words__num_valid_words & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_valid_words = %u",
+                          (htt_stats_buf->num_avail_words__num_valid_words &
+                          0xFFFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "head_ptr = %u",
+                          htt_stats_buf->head_ptr__tail_ptr & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tail_ptr = %u",
+                          (htt_stats_buf->head_ptr__tail_ptr & 0xFFFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "consumer_empty = %u",
+                          htt_stats_buf->consumer_empty__producer_full & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "producer_full = %u",
+                          (htt_stats_buf->consumer_empty__producer_full &
+                          0xFFFF0000) >> 16);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "prefetch_count = %u",
+                          htt_stats_buf->prefetch_count__internal_tail_ptr & 0xFFFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "internal_tail_ptr = %u\n",
+                          (htt_stats_buf->prefetch_count__internal_tail_ptr &
+                          0xFFFF0000) >> 16);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_sring_cmn_tlv(const void *tag_buf,
+                                          struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_sring_cmn_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_SRING_CMN_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u\n",
+                          htt_stats_buf->num_records);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_tx_pdev_rate_stats_tlv(const void *tag_buf,
+                                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_tx_pdev_rate_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       u8 j;
+       char str_buf[HTT_MAX_STRING_LEN] = {0};
+       char *tx_gi[HTT_TX_PEER_STATS_NUM_GI_COUNTERS];
+
+       for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++)
+               tx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_TX_PDEV_RATE_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_ldpc = %u",
+                          htt_stats_buf->tx_ldpc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_ldpc = %u",
+                          htt_stats_buf->ac_mu_mimo_tx_ldpc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_ldpc = %u",
+                          htt_stats_buf->ax_mu_mimo_tx_ldpc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_ldpc = %u",
+                          htt_stats_buf->ofdma_tx_ldpc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u",
+                          htt_stats_buf->rts_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_success = %u",
+                          htt_stats_buf->rts_success);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ack_rssi = %u",
+                          htt_stats_buf->ack_rssi);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "Legacy CCK Rates: 1 Mbps: %u, 2 Mbps: %u, 5.5 Mbps: %u, 11 Mbps: %u",
+                          htt_stats_buf->tx_legacy_cck_rate[0],
+                          htt_stats_buf->tx_legacy_cck_rate[1],
+                          htt_stats_buf->tx_legacy_cck_rate[2],
+                          htt_stats_buf->tx_legacy_cck_rate[3]);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "Legacy OFDM Rates: 6 Mbps: %u, 9 Mbps: %u, 12 Mbps: %u, 18 Mbps: %u\n"
+                          "                   24 Mbps: %u, 36 Mbps: %u, 48 Mbps: %u, 54 Mbps: %u",
+                          htt_stats_buf->tx_legacy_ofdm_rate[0],
+                          htt_stats_buf->tx_legacy_ofdm_rate[1],
+                          htt_stats_buf->tx_legacy_ofdm_rate[2],
+                          htt_stats_buf->tx_legacy_ofdm_rate[3],
+                          htt_stats_buf->tx_legacy_ofdm_rate[4],
+                          htt_stats_buf->tx_legacy_ofdm_rate[5],
+                          htt_stats_buf->tx_legacy_ofdm_rate[6],
+                          htt_stats_buf->tx_legacy_ofdm_rate[7]);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_mcs,
+                       HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_mcs = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->ac_mu_mimo_tx_mcs,
+                       HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_mcs = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->ax_mu_mimo_tx_mcs,
+                       HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_mcs = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->ofdma_tx_mcs,
+                       HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_mcs = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_nss,
+                       HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_nss = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->ac_mu_mimo_tx_nss,
+                       HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_nss = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->ax_mu_mimo_tx_nss,
+                       HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_nss = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->ofdma_tx_nss,
+                       HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_nss = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_bw,
+                       HTT_TX_PDEV_STATS_NUM_BW_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_bw = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->ac_mu_mimo_tx_bw,
+                       HTT_TX_PDEV_STATS_NUM_BW_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ac_mu_mimo_tx_bw = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->ax_mu_mimo_tx_bw,
+                       HTT_TX_PDEV_STATS_NUM_BW_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ax_mu_mimo_tx_bw = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->ofdma_tx_bw,
+                       HTT_TX_PDEV_STATS_NUM_BW_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_bw = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_stbc,
+                       HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_stbc = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_pream,
+                       HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_pream = %s ", str_buf);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HE LTF: 1x: %u, 2x: %u, 4x: %u",
+                          htt_stats_buf->tx_he_ltf[1],
+                          htt_stats_buf->tx_he_ltf[2],
+                          htt_stats_buf->tx_he_ltf[3]);
+
+       /* SU GI Stats */
+       for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) {
+               ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->tx_gi[j],
+                               HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_gi[%u] = %s ",
+                                  j, tx_gi[j]);
+       }
+
+       /* AC MU-MIMO GI Stats */
+       for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) {
+               ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->ac_mu_mimo_tx_gi[j],
+                               HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ac_mu_mimo_tx_gi[%u] = %s ",
+                                  j, tx_gi[j]);
+       }
+
+       /* AX MU-MIMO GI Stats */
+       for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) {
+               ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->ax_mu_mimo_tx_gi[j],
+                               HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "ax_mu_mimo_tx_gi[%u] = %s ",
+                                  j, tx_gi[j]);
+       }
+
+       /* DL OFDMA GI Stats */
+       for (j = 0; j < HTT_TX_PDEV_STATS_NUM_GI_COUNTERS; j++) {
+               ARRAY_TO_STRING(tx_gi[j], htt_stats_buf->ofdma_tx_gi[j],
+                               HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS);
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "ofdma_tx_gi[%u] = %s ",
+                                  j, tx_gi[j]);
+       }
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->tx_dcm,
+                       HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_dcm = %s\n", str_buf);
+
+       for (j = 0; j < HTT_TX_PEER_STATS_NUM_GI_COUNTERS; j++)
+               kfree(tx_gi[j]);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_rx_pdev_rate_stats_tlv(const void *tag_buf,
+                                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_pdev_rate_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       u8 j;
+       char *rssi_chain[HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS];
+       char *rx_gi[HTT_RX_PDEV_STATS_NUM_GI_COUNTERS];
+       char str_buf[HTT_MAX_STRING_LEN] = {0};
+
+       for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++)
+               rssi_chain[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC);
+
+       for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++)
+               rx_gi[j] = kmalloc(HTT_MAX_STRING_LEN, GFP_ATOMIC);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_RATE_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "nsts = %u",
+                          htt_stats_buf->nsts);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ldpc = %u",
+                          htt_stats_buf->rx_ldpc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rts_cnt = %u",
+                          htt_stats_buf->rts_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_mgmt = %u",
+                          htt_stats_buf->rssi_mgmt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_data = %u",
+                          htt_stats_buf->rssi_data);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_comb = %u",
+                          htt_stats_buf->rssi_comb);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_in_dbm = %d",
+                          htt_stats_buf->rssi_in_dbm);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_mcs,
+                       HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_mcs = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_nss,
+                       HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_nss = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_dcm,
+                       HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_dcm = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_stbc,
+                       HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_stbc = %s ", str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_bw,
+                       HTT_RX_PDEV_STATS_NUM_BW_COUNTERS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_bw = %s ", str_buf);
+
+       for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++) {
+               ARRAY_TO_STRING(rssi_chain[j], htt_stats_buf->rssi_chain[j],
+                               HTT_RX_PDEV_STATS_NUM_BW_COUNTERS);
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "rssi_chain[%u] = %s ",
+                                  j, rssi_chain[j]);
+       }
+
+       for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++) {
+               ARRAY_TO_STRING(rx_gi[j], htt_stats_buf->rx_gi[j],
+                               HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS);
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_gi[%u] = %s ",
+                                  j, rx_gi[j]);
+       }
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_pream,
+                       HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_pream = %s", str_buf);
+
+       for (j = 0; j < HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS; j++)
+               kfree(rssi_chain[j]);
+
+       for (j = 0; j < HTT_RX_PDEV_STATS_NUM_GI_COUNTERS; j++)
+               kfree(rx_gi[j]);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_su_ext = %u",
+                          htt_stats_buf->rx_11ax_su_ext);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ac_mumimo = %u",
+                          htt_stats_buf->rx_11ac_mumimo);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_mumimo = %u",
+                          htt_stats_buf->rx_11ax_mumimo);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_11ax_ofdma = %u",
+                          htt_stats_buf->rx_11ax_ofdma);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "txbf = %u",
+                          htt_stats_buf->txbf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_legacy_cck_rate,
+                       HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_legacy_cck_rate = %s ",
+                          str_buf);
+
+       memset(str_buf, 0x0, HTT_MAX_STRING_LEN);
+       ARRAY_TO_STRING(str_buf, htt_stats_buf->rx_legacy_ofdm_rate,
+                       HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_legacy_ofdm_rate = %s ",
+                          str_buf);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_active_dur_us_low = %u",
+                          htt_stats_buf->rx_active_dur_us_low);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_active_dur_us_high = %u\n",
+                          htt_stats_buf->rx_active_dur_us_high);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_rx_soc_fw_stats_tlv(const void *tag_buf,
+                                                struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_soc_fw_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_SOC_FW_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_reo_ring_data_msdu = %u",
+                          htt_stats_buf->fw_reo_ring_data_msdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_to_host_data_msdu_bcmc = %u",
+                          htt_stats_buf->fw_to_host_data_msdu_bcmc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_to_host_data_msdu_uc = %u",
+                          htt_stats_buf->fw_to_host_data_msdu_uc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "ofld_remote_data_buf_recycle_cnt = %u",
+                          htt_stats_buf->ofld_remote_data_buf_recycle_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "ofld_remote_free_buf_indication_cnt = %u",
+                          htt_stats_buf->ofld_remote_free_buf_indication_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "ofld_buf_to_host_data_msdu_uc = %u",
+                          htt_stats_buf->ofld_buf_to_host_data_msdu_uc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "reo_fw_ring_to_host_data_msdu_uc = %u",
+                          htt_stats_buf->reo_fw_ring_to_host_data_msdu_uc);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm_sw_ring_reap = %u",
+                          htt_stats_buf->wbm_sw_ring_reap);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm_forward_to_host_cnt = %u",
+                          htt_stats_buf->wbm_forward_to_host_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "wbm_target_recycle_cnt = %u",
+                          htt_stats_buf->wbm_target_recycle_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "target_refill_ring_recycle_cnt = %u",
+                          htt_stats_buf->target_refill_ring_recycle_cnt);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_rx_soc_fw_refill_ring_empty_tlv_v(const void *tag_buf,
+                                           u16 tag_len,
+                                           struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_soc_fw_refill_ring_empty_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char refill_ring_empty_cnt[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_REFILL_MAX_RING);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_RX_SOC_FW_REFILL_RING_EMPTY_TLV_V:");
+
+       ARRAY_TO_STRING(refill_ring_empty_cnt,
+                       htt_stats_buf->refill_ring_empty_cnt,
+                       num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "refill_ring_empty_cnt = %s\n",
+                          refill_ring_empty_cnt);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_rx_soc_fw_refill_ring_num_rxdma_err_tlv_v(const void *tag_buf,
+                                                   u16 tag_len,
+                                                   struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_soc_fw_refill_ring_num_rxdma_err_tlv_v *htt_stats_buf =
+               tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char rxdma_err_cnt[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_RXDMA_MAX_ERR_CODE);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_RX_SOC_FW_REFILL_RING_NUM_RXDMA_ERR_TLV_V:");
+
+       ARRAY_TO_STRING(rxdma_err_cnt,
+                       htt_stats_buf->rxdma_err,
+                       num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rxdma_err = %s\n",
+                          rxdma_err_cnt);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_rx_soc_fw_refill_ring_num_reo_err_tlv_v(const void *tag_buf,
+                                                 u16 tag_len,
+                                                 struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_soc_fw_refill_ring_num_reo_err_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char reo_err_cnt[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_REO_MAX_ERR_CODE);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_RX_SOC_FW_REFILL_RING_NUM_REO_ERR_TLV_V:");
+
+       ARRAY_TO_STRING(reo_err_cnt,
+                       htt_stats_buf->reo_err,
+                       num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "reo_err = %s\n",
+                          reo_err_cnt);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_rx_reo_debug_stats_tlv_v(const void *tag_buf,
+                                  struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_reo_resource_stats_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_REO_RESOURCE_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sample_id = %u",
+                          htt_stats_buf->sample_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "total_max = %u",
+                          htt_stats_buf->total_max);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "total_avg = %u",
+                          htt_stats_buf->total_avg);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "total_sample = %u",
+                          htt_stats_buf->total_sample);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "non_zeros_avg = %u",
+                          htt_stats_buf->non_zeros_avg);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "non_zeros_sample = %u",
+                          htt_stats_buf->non_zeros_sample);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_max = %u",
+                          htt_stats_buf->last_non_zeros_max);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_min %u",
+                          htt_stats_buf->last_non_zeros_min);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_avg %u",
+                          htt_stats_buf->last_non_zeros_avg);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_non_zeros_sample %u\n",
+                          htt_stats_buf->last_non_zeros_sample);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_rx_soc_fw_refill_ring_num_refill_tlv_v(const void *tag_buf,
+                                                u16 tag_len,
+                                                struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_soc_fw_refill_ring_num_refill_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char refill_ring_num_refill[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_REFILL_MAX_RING);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_RX_SOC_FW_REFILL_RING_NUM_REFILL_TLV_V:");
+
+       ARRAY_TO_STRING(refill_ring_num_refill,
+                       htt_stats_buf->refill_ring_num_refill,
+                       num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "refill_ring_num_refill = %s\n",
+                          refill_ring_num_refill);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_rx_pdev_fw_stats_tlv(const void *tag_buf,
+                                                 struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_pdev_fw_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char fw_ring_mgmt_subtype[HTT_MAX_STRING_LEN] = {0};
+       char fw_ring_ctrl_subtype[HTT_MAX_STRING_LEN] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ppdu_recvd = %u",
+                          htt_stats_buf->ppdu_recvd);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_cnt_fcs_ok = %u",
+                          htt_stats_buf->mpdu_cnt_fcs_ok);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_cnt_fcs_err = %u",
+                          htt_stats_buf->mpdu_cnt_fcs_err);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tcp_msdu_cnt = %u",
+                          htt_stats_buf->tcp_msdu_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tcp_ack_msdu_cnt = %u",
+                          htt_stats_buf->tcp_ack_msdu_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "udp_msdu_cnt = %u",
+                          htt_stats_buf->udp_msdu_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "other_msdu_cnt = %u",
+                          htt_stats_buf->other_msdu_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_ind = %u",
+                          htt_stats_buf->fw_ring_mpdu_ind);
+
+       ARRAY_TO_STRING(fw_ring_mgmt_subtype,
+                       htt_stats_buf->fw_ring_mgmt_subtype,
+                       HTT_STATS_SUBTYPE_MAX);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mgmt_subtype = %s ",
+                          fw_ring_mgmt_subtype);
+
+       ARRAY_TO_STRING(fw_ring_ctrl_subtype,
+                       htt_stats_buf->fw_ring_ctrl_subtype,
+                       HTT_STATS_SUBTYPE_MAX);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_ctrl_subtype = %s ",
+                          fw_ring_ctrl_subtype);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mcast_data_msdu = %u",
+                          htt_stats_buf->fw_ring_mcast_data_msdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_bcast_data_msdu = %u",
+                          htt_stats_buf->fw_ring_bcast_data_msdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_ucast_data_msdu = %u",
+                          htt_stats_buf->fw_ring_ucast_data_msdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_null_data_msdu = %u",
+                          htt_stats_buf->fw_ring_null_data_msdu);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_drop = %u",
+                          htt_stats_buf->fw_ring_mpdu_drop);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "ofld_local_data_ind_cnt = %u",
+                          htt_stats_buf->ofld_local_data_ind_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "ofld_local_data_buf_recycle_cnt = %u",
+                          htt_stats_buf->ofld_local_data_buf_recycle_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "drx_local_data_ind_cnt = %u",
+                          htt_stats_buf->drx_local_data_ind_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "drx_local_data_buf_recycle_cnt = %u",
+                          htt_stats_buf->drx_local_data_buf_recycle_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "local_nondata_ind_cnt = %u",
+                          htt_stats_buf->local_nondata_ind_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "local_nondata_buf_recycle_cnt = %u",
+                          htt_stats_buf->local_nondata_buf_recycle_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_status_buf_ring_refill_cnt = %u",
+                          htt_stats_buf->fw_status_buf_ring_refill_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_status_buf_ring_empty_cnt = %u",
+                          htt_stats_buf->fw_status_buf_ring_empty_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_pkt_buf_ring_refill_cnt = %u",
+                          htt_stats_buf->fw_pkt_buf_ring_refill_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_pkt_buf_ring_empty_cnt = %u",
+                          htt_stats_buf->fw_pkt_buf_ring_empty_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_link_buf_ring_refill_cnt = %u",
+                          htt_stats_buf->fw_link_buf_ring_refill_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_link_buf_ring_empty_cnt = %u",
+                          htt_stats_buf->fw_link_buf_ring_empty_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "host_pkt_buf_ring_refill_cnt = %u",
+                          htt_stats_buf->host_pkt_buf_ring_refill_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "host_pkt_buf_ring_empty_cnt = %u",
+                          htt_stats_buf->host_pkt_buf_ring_empty_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_pkt_buf_ring_refill_cnt = %u",
+                          htt_stats_buf->mon_pkt_buf_ring_refill_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_pkt_buf_ring_empty_cnt = %u",
+                          htt_stats_buf->mon_pkt_buf_ring_empty_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "mon_status_buf_ring_refill_cnt = %u",
+                          htt_stats_buf->mon_status_buf_ring_refill_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_status_buf_ring_empty_cnt = %u",
+                          htt_stats_buf->mon_status_buf_ring_empty_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_desc_buf_ring_refill_cnt = %u",
+                          htt_stats_buf->mon_desc_buf_ring_refill_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_desc_buf_ring_empty_cnt = %u",
+                          htt_stats_buf->mon_desc_buf_ring_empty_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_dest_ring_update_cnt = %u",
+                          htt_stats_buf->mon_dest_ring_update_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mon_dest_ring_full_cnt = %u",
+                          htt_stats_buf->mon_dest_ring_full_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_suspend_cnt = %u",
+                          htt_stats_buf->rx_suspend_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_suspend_fail_cnt = %u",
+                          htt_stats_buf->rx_suspend_fail_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_resume_cnt = %u",
+                          htt_stats_buf->rx_resume_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_resume_fail_cnt = %u",
+                          htt_stats_buf->rx_resume_fail_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ring_switch_cnt = %u",
+                          htt_stats_buf->rx_ring_switch_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_ring_restore_cnt = %u",
+                          htt_stats_buf->rx_ring_restore_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_flush_cnt = %u",
+                          htt_stats_buf->rx_flush_cnt);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "rx_recovery_reset_cnt = %u\n",
+                          htt_stats_buf->rx_recovery_reset_cnt);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_rx_pdev_fw_ring_mpdu_err_tlv_v(const void *tag_buf,
+                                        struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_pdev_fw_ring_mpdu_err_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char fw_ring_mpdu_err[HTT_MAX_STRING_LEN] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_RX_PDEV_FW_RING_MPDU_ERR_TLV_V:");
+
+       ARRAY_TO_STRING(fw_ring_mpdu_err,
+                       htt_stats_buf->fw_ring_mpdu_err,
+                       HTT_RX_STATS_RXDMA_MAX_ERR);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_ring_mpdu_err = %s\n",
+                          fw_ring_mpdu_err);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_rx_pdev_fw_mpdu_drop_tlv_v(const void *tag_buf,
+                                    u16 tag_len,
+                                    struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_pdev_fw_mpdu_drop_tlv_v *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char fw_mpdu_drop[HTT_MAX_STRING_LEN] = {0};
+       u16 num_elems = min_t(u16, (tag_len >> 2), HTT_RX_STATS_FW_DROP_REASON_MAX);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_MPDU_DROP_TLV_V:");
+
+       ARRAY_TO_STRING(fw_mpdu_drop,
+                       htt_stats_buf->fw_mpdu_drop,
+                       num_elems);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "fw_mpdu_drop = %s\n", fw_mpdu_drop);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_rx_pdev_fw_stats_phy_err_tlv(const void *tag_buf,
+                                      struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_rx_pdev_fw_stats_phy_err_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       char phy_errs[HTT_MAX_STRING_LEN] = {0};
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_PHY_ERR_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id__word = %u",
+                          htt_stats_buf->mac_id__word);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "tota_phy_err_nct = %u",
+                          htt_stats_buf->total_phy_err_cnt);
+
+       ARRAY_TO_STRING(phy_errs,
+                       htt_stats_buf->phy_err,
+                       HTT_STATS_PHY_ERR_MAX);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "phy_errs = %s\n", phy_errs);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_pdev_cca_stats_hist_tlv(const void *tag_buf,
+                                 struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_pdev_cca_stats_hist_v1_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "\nHTT_PDEV_CCA_STATS_HIST_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "chan_num = %u",
+                          htt_stats_buf->chan_num);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_records = %u",
+                          htt_stats_buf->num_records);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "valid_cca_counters_bitmap = 0x%x",
+                          htt_stats_buf->valid_cca_counters_bitmap);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "collection_interval = %u\n",
+                          htt_stats_buf->collection_interval);
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HTT_PDEV_STATS_CCA_COUNTERS_TLV:(in usec)");
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "|  tx_frame|   rx_frame|   rx_clear| my_rx_frame|        cnt| med_rx_idle| med_tx_idle_global|   cca_obss|");
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_pdev_stats_cca_counters_tlv(const void *tag_buf,
+                                     struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_pdev_stats_cca_counters_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "|%10u| %10u| %10u| %11u| %10u| %11u| %18u| %10u|",
+                          htt_stats_buf->tx_frame_usec,
+                          htt_stats_buf->rx_frame_usec,
+                          htt_stats_buf->rx_clear_usec,
+                          htt_stats_buf->my_rx_frame_usec,
+                          htt_stats_buf->usec_cnt,
+                          htt_stats_buf->med_rx_idle_usec,
+                          htt_stats_buf->med_tx_idle_global_usec,
+                          htt_stats_buf->cca_obss_usec);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_print_hw_stats_whal_tx_tlv(const void *tag_buf,
+                                                 struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_hw_stats_whal_tx_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_HW_STATS_WHAL_TX_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id = %u",
+                          htt_stats_buf->mac_id__word & 0xFF);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "last_unpause_ppdu_id = %u",
+                          htt_stats_buf->last_unpause_ppdu_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_unpause_wait_tqm_write = %u",
+                          htt_stats_buf->hwsch_unpause_wait_tqm_write);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_dummy_tlv_skipped = %u",
+                          htt_stats_buf->hwsch_dummy_tlv_skipped);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "hwsch_misaligned_offset_received = %u",
+                          htt_stats_buf->hwsch_misaligned_offset_received);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_reset_count = %u",
+                          htt_stats_buf->hwsch_reset_count);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_dev_reset_war = %u",
+                          htt_stats_buf->hwsch_dev_reset_war);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_delayed_pause = %u",
+                          htt_stats_buf->hwsch_delayed_pause);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "hwsch_long_delayed_pause = %u",
+                          htt_stats_buf->hwsch_long_delayed_pause);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sch_rx_ppdu_no_response = %u",
+                          htt_stats_buf->sch_rx_ppdu_no_response);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sch_selfgen_response = %u",
+                          htt_stats_buf->sch_selfgen_response);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sch_rx_sifs_resp_trigger= %u\n",
+                          htt_stats_buf->sch_rx_sifs_resp_trigger);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_pdev_stats_twt_sessions_tlv(const void *tag_buf,
+                                     struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_pdev_stats_twt_sessions_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PDEV_STATS_TWT_SESSIONS_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "pdev_id = %u",
+                          htt_stats_buf->pdev_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "num_sessions = %u\n",
+                          htt_stats_buf->num_sessions);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_pdev_stats_twt_session_tlv(const void *tag_buf,
+                                    struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_pdev_stats_twt_session_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_PDEV_STATS_TWT_SESSION_TLV:");
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "vdev_id = %u",
+                          htt_stats_buf->vdev_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "peer_mac = %02x:%02x:%02x:%02x:%02x:%02x",
+                          htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF,
+                          (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF00) >> 8,
+                          (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF0000) >> 16,
+                          (htt_stats_buf->peer_mac.mac_addr_l32 & 0xFF000000) >> 24,
+                          (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF),
+                          (htt_stats_buf->peer_mac.mac_addr_h16 & 0xFF00) >> 8);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "flow_id_flags = %u",
+                          htt_stats_buf->flow_id_flags);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "dialog_id = %u",
+                          htt_stats_buf->dialog_id);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "wake_dura_us = %u",
+                          htt_stats_buf->wake_dura_us);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "wake_intvl_us = %u",
+                          htt_stats_buf->wake_intvl_us);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "sp_offset_us = %u\n",
+                          htt_stats_buf->sp_offset_us);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void
+htt_print_pdev_obss_pd_stats_tlv_v(const void *tag_buf,
+                                  struct debug_htt_stats_req *stats_req)
+{
+       const struct htt_pdev_obss_pd_stats_tlv *htt_stats_buf = tag_buf;
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "OBSS Tx success PPDU = %u",
+                          htt_stats_buf->num_obss_tx_ppdu_success);
+       len += HTT_DBG_OUT(buf + len, buf_len - len, "OBSS Tx failures PPDU = %u\n",
+                          htt_stats_buf->num_obss_tx_ppdu_failure);
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static inline void htt_htt_stats_debug_dump(const u32 *tag_buf,
+                                           struct debug_htt_stats_req *stats_req)
+{
+       u8 *buf = stats_req->buf;
+       u32 len = stats_req->buf_len;
+       u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE;
+       u32 tlv_len = 0, i = 0, word_len = 0;
+
+       tlv_len  = FIELD_GET(HTT_TLV_LEN, *tag_buf) + HTT_TLV_HDR_LEN;
+       word_len = (tlv_len % 4) == 0 ? (tlv_len / 4) : ((tlv_len / 4) + 1);
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "============================================");
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "HKDBG TLV DUMP: (tag_len=%u bytes, words=%u)",
+                          tlv_len, word_len);
+
+       for (i = 0; i + 3 < word_len; i += 4) {
+               len += HTT_DBG_OUT(buf + len, buf_len - len,
+                                  "0x%08x 0x%08x 0x%08x 0x%08x",
+                                  tag_buf[i], tag_buf[i + 1],
+                                  tag_buf[i + 2], tag_buf[i + 3]);
+       }
+
+       if (i + 3 == word_len) {
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "0x%08x 0x%08x 0x%08x ",
+                               tag_buf[i], tag_buf[i + 1], tag_buf[i + 2]);
+       } else if (i + 2 == word_len) {
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "0x%08x 0x%08x ",
+                               tag_buf[i], tag_buf[i + 1]);
+       } else if (i + 1 == word_len) {
+               len += HTT_DBG_OUT(buf + len, buf_len - len, "0x%08x ",
+                               tag_buf[i]);
+       }
+       len += HTT_DBG_OUT(buf + len, buf_len - len,
+                          "============================================");
+
+       if (len >= buf_len)
+               buf[buf_len - 1] = 0;
+       else
+               buf[len] = 0;
+
+       stats_req->buf_len = len;
+}
+
+static int ath11k_dbg_htt_ext_stats_parse(struct ath11k_base *ab,
+                                         u16 tag, u16 len, const void *tag_buf,
+                                         void *user_data)
+{
+       struct debug_htt_stats_req *stats_req = user_data;
+
+       switch (tag) {
+       case HTT_STATS_TX_PDEV_CMN_TAG:
+               htt_print_tx_pdev_stats_cmn_tlv(tag_buf, stats_req);
+               break;
+       case HTT_STATS_TX_PDEV_UNDERRUN_TAG:
+               htt_print_tx_pdev_stats_urrn_tlv_v(tag_buf, len, stats_req);
+               break;
+       case HTT_STATS_TX_PDEV_SIFS_TAG:
+               htt_print_tx_pdev_stats_sifs_tlv_v(tag_buf, len, stats_req);
+               break;
+       case HTT_STATS_TX_PDEV_FLUSH_TAG:
+               htt_print_tx_pdev_stats_flush_tlv_v(tag_buf, len, stats_req);
+               break;
+       case HTT_STATS_TX_PDEV_PHY_ERR_TAG:
+               htt_print_tx_pdev_stats_phy_err_tlv_v(tag_buf, len, stats_req);
+               break;
+       case HTT_STATS_TX_PDEV_SIFS_HIST_TAG:
+               htt_print_tx_pdev_stats_sifs_hist_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_PDEV_TX_PPDU_STATS_TAG:
+               htt_print_tx_pdev_stats_tx_ppdu_stats_tlv_v(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_PDEV_TRIED_MPDU_CNT_HIST_TAG:
+               htt_print_tx_pdev_stats_tried_mpdu_cnt_hist_tlv_v(tag_buf, len,
+                                                                 stats_req);
+               break;
+
+       case HTT_STATS_STRING_TAG:
+               htt_print_stats_string_tlv(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_HWQ_CMN_TAG:
+               htt_print_tx_hwq_stats_cmn_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_HWQ_DIFS_LATENCY_TAG:
+               htt_print_tx_hwq_difs_latency_stats_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_HWQ_CMD_RESULT_TAG:
+               htt_print_tx_hwq_cmd_result_stats_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_HWQ_CMD_STALL_TAG:
+               htt_print_tx_hwq_cmd_stall_stats_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_HWQ_FES_STATUS_TAG:
+               htt_print_tx_hwq_fes_result_stats_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_HWQ_TRIED_MPDU_CNT_HIST_TAG:
+               htt_print_tx_hwq_tried_mpdu_cnt_hist_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_HWQ_TXOP_USED_CNT_HIST_TAG:
+               htt_print_tx_hwq_txop_used_cnt_hist_tlv_v(tag_buf, len, stats_req);
+               break;
+       case HTT_STATS_TX_TQM_GEN_MPDU_TAG:
+               htt_print_tx_tqm_gen_mpdu_stats_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_TQM_LIST_MPDU_TAG:
+               htt_print_tx_tqm_list_mpdu_stats_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_TQM_LIST_MPDU_CNT_TAG:
+               htt_print_tx_tqm_list_mpdu_cnt_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_TQM_CMN_TAG:
+               htt_print_tx_tqm_cmn_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_TQM_PDEV_TAG:
+               htt_print_tx_tqm_pdev_stats_tlv_v(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_TQM_CMDQ_STATUS_TAG:
+               htt_print_tx_tqm_cmdq_status_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_DE_EAPOL_PACKETS_TAG:
+               htt_print_tx_de_eapol_packets_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_DE_CLASSIFY_FAILED_TAG:
+               htt_print_tx_de_classify_failed_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_DE_CLASSIFY_STATS_TAG:
+               htt_print_tx_de_classify_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_DE_CLASSIFY_STATUS_TAG:
+               htt_print_tx_de_classify_status_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_DE_ENQUEUE_PACKETS_TAG:
+               htt_print_tx_de_enqueue_packets_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_DE_ENQUEUE_DISCARD_TAG:
+               htt_print_tx_de_enqueue_discard_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_DE_FW2WBM_RING_FULL_HIST_TAG:
+               htt_print_tx_de_fw2wbm_ring_full_hist_tlv(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_TX_DE_CMN_TAG:
+               htt_print_tx_de_cmn_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_RING_IF_TAG:
+               htt_print_ring_if_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG:
+               htt_print_tx_pdev_mu_mimo_sch_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_SFM_CMN_TAG:
+               htt_print_sfm_cmn_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_SRING_STATS_TAG:
+               htt_print_sring_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_RX_PDEV_FW_STATS_TAG:
+               htt_print_rx_pdev_fw_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_RX_PDEV_FW_RING_MPDU_ERR_TAG:
+               htt_print_rx_pdev_fw_ring_mpdu_err_tlv_v(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_RX_PDEV_FW_MPDU_DROP_TAG:
+               htt_print_rx_pdev_fw_mpdu_drop_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_RX_SOC_FW_STATS_TAG:
+               htt_print_rx_soc_fw_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_RX_SOC_FW_REFILL_RING_EMPTY_TAG:
+               htt_print_rx_soc_fw_refill_ring_empty_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_RX_SOC_FW_REFILL_RING_NUM_REFILL_TAG:
+               htt_print_rx_soc_fw_refill_ring_num_refill_tlv_v(
+                               tag_buf, len, stats_req);
+               break;
+       case HTT_STATS_RX_REFILL_RXDMA_ERR_TAG:
+               htt_print_rx_soc_fw_refill_ring_num_rxdma_err_tlv_v(
+                               tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_RX_REFILL_REO_ERR_TAG:
+               htt_print_rx_soc_fw_refill_ring_num_reo_err_tlv_v(
+                               tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_RX_REO_RESOURCE_STATS_TAG:
+               htt_print_rx_reo_debug_stats_tlv_v(
+                               tag_buf, stats_req);
+               break;
+       case HTT_STATS_RX_PDEV_FW_STATS_PHY_ERR_TAG:
+               htt_print_rx_pdev_fw_stats_phy_err_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_PDEV_RATE_STATS_TAG:
+               htt_print_tx_pdev_rate_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_RX_PDEV_RATE_STATS_TAG:
+               htt_print_rx_pdev_rate_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_PDEV_SCHEDULER_TXQ_STATS_TAG:
+               htt_print_tx_pdev_stats_sched_per_txq_tlv(tag_buf, stats_req);
+               break;
+       case HTT_STATS_TX_SCHED_CMN_TAG:
+               htt_print_stats_tx_sched_cmn_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_PDEV_MPDU_STATS_TAG:
+               htt_print_tx_pdev_mu_mimo_mpdu_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_SCHED_TXQ_CMD_POSTED_TAG:
+               htt_print_sched_txq_cmd_posted_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_RING_IF_CMN_TAG:
+               htt_print_ring_if_cmn_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_SFM_CLIENT_USER_TAG:
+               htt_print_sfm_client_user_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_SFM_CLIENT_TAG:
+               htt_print_sfm_client_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_TQM_ERROR_STATS_TAG:
+               htt_print_tx_tqm_error_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_SCHED_TXQ_CMD_REAPED_TAG:
+               htt_print_sched_txq_cmd_reaped_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_SRING_CMN_TAG:
+               htt_print_sring_cmn_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_SOUNDING_STATS_TAG:
+               htt_print_tx_sounding_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_SELFGEN_AC_ERR_STATS_TAG:
+               htt_print_tx_selfgen_ac_err_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_SELFGEN_CMN_STATS_TAG:
+               htt_print_tx_selfgen_cmn_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_SELFGEN_AC_STATS_TAG:
+               htt_print_tx_selfgen_ac_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_SELFGEN_AX_STATS_TAG:
+               htt_print_tx_selfgen_ax_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_SELFGEN_AX_ERR_STATS_TAG:
+               htt_print_tx_selfgen_ax_err_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_HWQ_MUMIMO_SCH_STATS_TAG:
+               htt_print_tx_hwq_mu_mimo_sch_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_HWQ_MUMIMO_MPDU_STATS_TAG:
+               htt_print_tx_hwq_mu_mimo_mpdu_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_HWQ_MUMIMO_CMN_STATS_TAG:
+               htt_print_tx_hwq_mu_mimo_cmn_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_HW_INTR_MISC_TAG:
+               htt_print_hw_stats_intr_misc_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_HW_WD_TIMEOUT_TAG:
+               htt_print_hw_stats_wd_timeout_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_HW_PDEV_ERRS_TAG:
+               htt_print_hw_stats_pdev_errs_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_COUNTER_NAME_TAG:
+               htt_print_counter_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_TID_DETAILS_TAG:
+               htt_print_tx_tid_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_TID_DETAILS_V1_TAG:
+               htt_print_tx_tid_stats_v1_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_RX_TID_DETAILS_TAG:
+               htt_print_rx_tid_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_PEER_STATS_CMN_TAG:
+               htt_print_peer_stats_cmn_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_PEER_DETAILS_TAG:
+               htt_print_peer_details_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_PEER_MSDU_FLOWQ_TAG:
+               htt_print_msdu_flow_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_PEER_TX_RATE_STATS_TAG:
+               htt_print_tx_peer_rate_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_PEER_RX_RATE_STATS_TAG:
+               htt_print_rx_peer_rate_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_TX_DE_COMPL_STATS_TAG:
+               htt_print_tx_de_compl_stats_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_PDEV_CCA_1SEC_HIST_TAG:
+       case HTT_STATS_PDEV_CCA_100MSEC_HIST_TAG:
+       case HTT_STATS_PDEV_CCA_STAT_CUMULATIVE_TAG:
+               htt_print_pdev_cca_stats_hist_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_PDEV_CCA_COUNTERS_TAG:
+               htt_print_pdev_stats_cca_counters_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_WHAL_TX_TAG:
+               htt_print_hw_stats_whal_tx_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_PDEV_TWT_SESSIONS_TAG:
+               htt_print_pdev_stats_twt_sessions_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_PDEV_TWT_SESSION_TAG:
+               htt_print_pdev_stats_twt_session_tlv(tag_buf, stats_req);
+               break;
+
+       case HTT_STATS_SCHED_TXQ_SCHED_ORDER_SU_TAG:
+               htt_print_sched_txq_sched_order_su_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_SCHED_TXQ_SCHED_INELIGIBILITY_TAG:
+               htt_print_sched_txq_sched_ineligibility_tlv_v(tag_buf, len, stats_req);
+               break;
+
+       case HTT_STATS_PDEV_OBSS_PD_TAG:
+               htt_print_pdev_obss_pd_stats_tlv_v(tag_buf, stats_req);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+void ath11k_dbg_htt_ext_stats_handler(struct ath11k_base *ab,
+                                     struct sk_buff *skb)
+{
+       struct ath11k_htt_extd_stats_msg *msg;
+       struct debug_htt_stats_req *stats_req;
+       struct ath11k *ar;
+       u32 len;
+       u64 cookie;
+       int ret;
+       u8 pdev_id;
+
+       msg = (struct ath11k_htt_extd_stats_msg *)skb->data;
+       cookie = msg->cookie;
+
+       if (FIELD_GET(HTT_STATS_COOKIE_MSB, cookie) != HTT_STATS_MAGIC_VALUE) {
+               ath11k_warn(ab, "received invalid htt ext stats event\n");
+               return;
+       }
+
+       pdev_id = FIELD_GET(HTT_STATS_COOKIE_LSB, cookie);
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_pdev_id(ab, pdev_id);
+       rcu_read_unlock();
+       if (!ar) {
+               ath11k_warn(ab, "failed to get ar for pdev_id %d\n", pdev_id);
+               return;
+       }
+
+       stats_req = ar->debug.htt_stats.stats_req;
+       if (!stats_req)
+               return;
+
+       spin_lock_bh(&ar->debug.htt_stats.lock);
+       if (stats_req->done) {
+               spin_unlock_bh(&ar->debug.htt_stats.lock);
+               return;
+       }
+       stats_req->done = true;
+       spin_unlock_bh(&ar->debug.htt_stats.lock);
+
+       len = FIELD_GET(HTT_T2H_EXT_STATS_INFO1_LENGTH, msg->info1);
+       ret = ath11k_dp_htt_tlv_iter(ab, msg->data, len,
+                                    ath11k_dbg_htt_ext_stats_parse,
+                                    stats_req);
+       if (ret)
+               ath11k_warn(ab, "Failed to parse tlv %d\n", ret);
+
+       complete(&stats_req->cmpln);
+}
+
+static ssize_t ath11k_read_htt_stats_type(struct file *file,
+                                         char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct ath11k *ar = file->private_data;
+       char buf[32];
+       size_t len;
+
+       len = scnprintf(buf, sizeof(buf), "%u\n", ar->debug.htt_stats.type);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath11k_write_htt_stats_type(struct file *file,
+                                          const char __user *user_buf,
+                                          size_t count, loff_t *ppos)
+{
+       struct ath11k *ar = file->private_data;
+       u8 type;
+       int ret;
+
+       ret = kstrtou8_from_user(user_buf, count, 0, &type);
+       if (ret)
+               return ret;
+
+       if (type >= ATH11K_DBG_HTT_NUM_EXT_STATS)
+               return -E2BIG;
+
+       if (type == ATH11K_DBG_HTT_EXT_STATS_RESET ||
+           type == ATH11K_DBG_HTT_EXT_STATS_PEER_INFO)
+               return -EPERM;
+
+       ar->debug.htt_stats.type = type;
+
+       ret = count;
+
+       return ret;
+}
+
+static const struct file_operations fops_htt_stats_type = {
+       .read = ath11k_read_htt_stats_type,
+       .write = ath11k_write_htt_stats_type,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static int ath11k_prep_htt_stats_cfg_params(struct ath11k *ar, u8 type,
+                                           const u8 *mac_addr,
+                                           struct htt_ext_stats_cfg_params *cfg_params)
+{
+       if (!cfg_params)
+               return -EINVAL;
+
+       switch (type) {
+       case ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_HWQ:
+       case ATH11K_DBG_HTT_EXT_STATS_TX_MU_HWQ:
+               cfg_params->cfg0 = HTT_STAT_DEFAULT_CFG0_ALL_HWQS;
+               break;
+       case ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED:
+               cfg_params->cfg0 = HTT_STAT_DEFAULT_CFG0_ALL_TXQS;
+               break;
+       case ATH11K_DBG_HTT_EXT_STATS_TQM_CMDQ:
+               cfg_params->cfg0 = HTT_STAT_DEFAULT_CFG0_ALL_CMDQS;
+               break;
+       case ATH11K_DBG_HTT_EXT_STATS_PEER_INFO:
+               cfg_params->cfg0 = HTT_STAT_PEER_INFO_MAC_ADDR;
+               cfg_params->cfg0 |= FIELD_PREP(GENMASK(15, 1),
+                                       HTT_PEER_STATS_REQ_MODE_FLUSH_TQM);
+               cfg_params->cfg1 = HTT_STAT_DEFAULT_PEER_REQ_TYPE;
+               cfg_params->cfg2 |= FIELD_PREP(GENMASK(7, 0), mac_addr[0]);
+               cfg_params->cfg2 |= FIELD_PREP(GENMASK(15, 8), mac_addr[1]);
+               cfg_params->cfg2 |= FIELD_PREP(GENMASK(23, 16), mac_addr[2]);
+               cfg_params->cfg2 |= FIELD_PREP(GENMASK(31, 24), mac_addr[3]);
+               cfg_params->cfg3 |= FIELD_PREP(GENMASK(7, 0), mac_addr[4]);
+               cfg_params->cfg3 |= FIELD_PREP(GENMASK(15, 8), mac_addr[5]);
+               break;
+       case ATH11K_DBG_HTT_EXT_STATS_RING_IF_INFO:
+       case ATH11K_DBG_HTT_EXT_STATS_SRNG_INFO:
+               cfg_params->cfg0 = HTT_STAT_DEFAULT_CFG0_ALL_RINGS;
+               break;
+       case ATH11K_DBG_HTT_EXT_STATS_ACTIVE_PEERS_LIST:
+               cfg_params->cfg0 = HTT_STAT_DEFAULT_CFG0_ACTIVE_PEERS;
+               break;
+       case ATH11K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS:
+               cfg_params->cfg0 = HTT_STAT_DEFAULT_CFG0_CCA_CUMULATIVE;
+               break;
+       case ATH11K_DBG_HTT_EXT_STATS_TX_SOUNDING_INFO:
+               cfg_params->cfg0 = HTT_STAT_DEFAULT_CFG0_ACTIVE_VDEVS;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+int ath11k_dbg_htt_stats_req(struct ath11k *ar)
+{
+       struct debug_htt_stats_req *stats_req = ar->debug.htt_stats.stats_req;
+       u8 type = stats_req->type;
+       u64 cookie = 0;
+       int ret, pdev_id = ar->pdev->pdev_id;
+       struct htt_ext_stats_cfg_params cfg_params = { 0 };
+
+       init_completion(&stats_req->cmpln);
+
+       stats_req->done = false;
+       stats_req->pdev_id = pdev_id;
+
+       cookie = FIELD_PREP(HTT_STATS_COOKIE_MSB, HTT_STATS_MAGIC_VALUE) |
+                FIELD_PREP(HTT_STATS_COOKIE_LSB, pdev_id);
+
+       ret = ath11k_prep_htt_stats_cfg_params(ar, type, stats_req->peer_addr,
+                                              &cfg_params);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set htt stats cfg params: %d\n", ret);
+               return ret;
+       }
+
+       ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar, type, &cfg_params, cookie);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send htt stats request: %d\n", ret);
+               mutex_unlock(&ar->conf_mutex);
+               return ret;
+       }
+
+       while (!wait_for_completion_timeout(&stats_req->cmpln, 3 * HZ)) {
+               spin_lock_bh(&ar->debug.htt_stats.lock);
+               if (!stats_req->done) {
+                       stats_req->done = true;
+                       spin_unlock_bh(&ar->debug.htt_stats.lock);
+                       ath11k_warn(ar->ab, "stats request timed out\n");
+                       return -ETIMEDOUT;
+               }
+               spin_unlock_bh(&ar->debug.htt_stats.lock);
+       }
+
+       return 0;
+}
+
+static int ath11k_open_htt_stats(struct inode *inode, struct file *file)
+{
+       struct ath11k *ar = inode->i_private;
+       struct debug_htt_stats_req *stats_req;
+       u8 type = ar->debug.htt_stats.type;
+       int ret;
+
+       if (type == ATH11K_DBG_HTT_EXT_STATS_RESET)
+               return -EPERM;
+
+       stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
+       if (!stats_req)
+               return -ENOMEM;
+
+       mutex_lock(&ar->conf_mutex);
+       ar->debug.htt_stats.stats_req = stats_req;
+       stats_req->type = type;
+       ret = ath11k_dbg_htt_stats_req(ar);
+       mutex_unlock(&ar->conf_mutex);
+       if (ret < 0)
+               goto out;
+
+       file->private_data = stats_req;
+       return 0;
+out:
+       vfree(stats_req);
+       return ret;
+}
+
+static int ath11k_release_htt_stats(struct inode *inode, struct file *file)
+{
+       vfree(file->private_data);
+       return 0;
+}
+
+static ssize_t ath11k_read_htt_stats(struct file *file,
+                                    char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct debug_htt_stats_req *stats_req = file->private_data;
+       char *buf;
+       u32 length = 0;
+
+       buf = stats_req->buf;
+       length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, length);
+}
+
+static const struct file_operations fops_dump_htt_stats = {
+       .open = ath11k_open_htt_stats,
+       .release = ath11k_release_htt_stats,
+       .read = ath11k_read_htt_stats,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_read_htt_stats_reset(struct file *file,
+                                          char __user *user_buf,
+                                          size_t count, loff_t *ppos)
+{
+       struct ath11k *ar = file->private_data;
+       char buf[32];
+       size_t len;
+
+       len = scnprintf(buf, sizeof(buf), "%u\n", ar->debug.htt_stats.reset);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath11k_write_htt_stats_reset(struct file *file,
+                                           const char __user *user_buf,
+                                           size_t count, loff_t *ppos)
+{
+       struct ath11k *ar = file->private_data;
+       u8 type;
+       struct htt_ext_stats_cfg_params cfg_params = { 0 };
+       int ret;
+
+       ret = kstrtou8_from_user(user_buf, count, 0, &type);
+       if (ret)
+               return ret;
+
+       if (type >= ATH11K_DBG_HTT_NUM_EXT_STATS ||
+           type == ATH11K_DBG_HTT_EXT_STATS_RESET)
+               return -E2BIG;
+
+       mutex_lock(&ar->conf_mutex);
+       cfg_params.cfg0 = HTT_STAT_DEFAULT_RESET_START_OFFSET;
+       cfg_params.cfg1 = 1 << (cfg_params.cfg0 + type);
+       ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar,
+                                                ATH11K_DBG_HTT_EXT_STATS_RESET,
+                                                &cfg_params,
+                                                0ULL);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send htt stats request: %d\n", ret);
+               mutex_unlock(&ar->conf_mutex);
+               return ret;
+       }
+
+       ar->debug.htt_stats.reset = type;
+       mutex_unlock(&ar->conf_mutex);
+
+       ret = count;
+
+       return ret;
+}
+
+static const struct file_operations fops_htt_stats_reset = {
+       .read = ath11k_read_htt_stats_reset,
+       .write = ath11k_write_htt_stats_reset,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+void ath11k_debug_htt_stats_init(struct ath11k *ar)
+{
+       spin_lock_init(&ar->debug.htt_stats.lock);
+       debugfs_create_file("htt_stats_type", 0600, ar->debug.debugfs_pdev,
+                           ar, &fops_htt_stats_type);
+       debugfs_create_file("htt_stats", 0400, ar->debug.debugfs_pdev,
+                           ar, &fops_dump_htt_stats);
+       debugfs_create_file("htt_stats_reset", 0600, ar->debug.debugfs_pdev,
+                           ar, &fops_htt_stats_reset);
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef DEBUG_HTT_STATS_H
+#define DEBUG_HTT_STATS_H
+
+#define HTT_STATS_COOKIE_LSB    GENMASK_ULL(31, 0)
+#define HTT_STATS_COOKIE_MSB    GENMASK_ULL(63, 32)
+#define HTT_STATS_MAGIC_VALUE   0xF0F0F0F0
+
+enum htt_tlv_tag_t {
+       HTT_STATS_TX_PDEV_CMN_TAG                           = 0,
+       HTT_STATS_TX_PDEV_UNDERRUN_TAG                      = 1,
+       HTT_STATS_TX_PDEV_SIFS_TAG                          = 2,
+       HTT_STATS_TX_PDEV_FLUSH_TAG                         = 3,
+       HTT_STATS_TX_PDEV_PHY_ERR_TAG                       = 4,
+       HTT_STATS_STRING_TAG                                = 5,
+       HTT_STATS_TX_HWQ_CMN_TAG                            = 6,
+       HTT_STATS_TX_HWQ_DIFS_LATENCY_TAG                   = 7,
+       HTT_STATS_TX_HWQ_CMD_RESULT_TAG                     = 8,
+       HTT_STATS_TX_HWQ_CMD_STALL_TAG                      = 9,
+       HTT_STATS_TX_HWQ_FES_STATUS_TAG                     = 10,
+       HTT_STATS_TX_TQM_GEN_MPDU_TAG                       = 11,
+       HTT_STATS_TX_TQM_LIST_MPDU_TAG                      = 12,
+       HTT_STATS_TX_TQM_LIST_MPDU_CNT_TAG                  = 13,
+       HTT_STATS_TX_TQM_CMN_TAG                            = 14,
+       HTT_STATS_TX_TQM_PDEV_TAG                           = 15,
+       HTT_STATS_TX_TQM_CMDQ_STATUS_TAG                    = 16,
+       HTT_STATS_TX_DE_EAPOL_PACKETS_TAG                   = 17,
+       HTT_STATS_TX_DE_CLASSIFY_FAILED_TAG                 = 18,
+       HTT_STATS_TX_DE_CLASSIFY_STATS_TAG                  = 19,
+       HTT_STATS_TX_DE_CLASSIFY_STATUS_TAG                 = 20,
+       HTT_STATS_TX_DE_ENQUEUE_PACKETS_TAG                 = 21,
+       HTT_STATS_TX_DE_ENQUEUE_DISCARD_TAG                 = 22,
+       HTT_STATS_TX_DE_CMN_TAG                             = 23,
+       HTT_STATS_RING_IF_TAG                               = 24,
+       HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG                 = 25,
+       HTT_STATS_SFM_CMN_TAG                               = 26,
+       HTT_STATS_SRING_STATS_TAG                           = 27,
+       HTT_STATS_RX_PDEV_FW_STATS_TAG                      = 28,
+       HTT_STATS_RX_PDEV_FW_RING_MPDU_ERR_TAG              = 29,
+       HTT_STATS_RX_PDEV_FW_MPDU_DROP_TAG                  = 30,
+       HTT_STATS_RX_SOC_FW_STATS_TAG                       = 31,
+       HTT_STATS_RX_SOC_FW_REFILL_RING_EMPTY_TAG           = 32,
+       HTT_STATS_RX_SOC_FW_REFILL_RING_NUM_REFILL_TAG      = 33,
+       HTT_STATS_TX_PDEV_RATE_STATS_TAG                    = 34,
+       HTT_STATS_RX_PDEV_RATE_STATS_TAG                    = 35,
+       HTT_STATS_TX_PDEV_SCHEDULER_TXQ_STATS_TAG           = 36,
+       HTT_STATS_TX_SCHED_CMN_TAG                          = 37,
+       HTT_STATS_TX_PDEV_MUMIMO_MPDU_STATS_TAG             = 38,
+       HTT_STATS_SCHED_TXQ_CMD_POSTED_TAG                  = 39,
+       HTT_STATS_RING_IF_CMN_TAG                           = 40,
+       HTT_STATS_SFM_CLIENT_USER_TAG                       = 41,
+       HTT_STATS_SFM_CLIENT_TAG                            = 42,
+       HTT_STATS_TX_TQM_ERROR_STATS_TAG                    = 43,
+       HTT_STATS_SCHED_TXQ_CMD_REAPED_TAG                  = 44,
+       HTT_STATS_SRING_CMN_TAG                             = 45,
+       HTT_STATS_TX_SELFGEN_AC_ERR_STATS_TAG               = 46,
+       HTT_STATS_TX_SELFGEN_CMN_STATS_TAG                  = 47,
+       HTT_STATS_TX_SELFGEN_AC_STATS_TAG                   = 48,
+       HTT_STATS_TX_SELFGEN_AX_STATS_TAG                   = 49,
+       HTT_STATS_TX_SELFGEN_AX_ERR_STATS_TAG               = 50,
+       HTT_STATS_TX_HWQ_MUMIMO_SCH_STATS_TAG               = 51,
+       HTT_STATS_TX_HWQ_MUMIMO_MPDU_STATS_TAG              = 52,
+       HTT_STATS_TX_HWQ_MUMIMO_CMN_STATS_TAG               = 53,
+       HTT_STATS_HW_INTR_MISC_TAG                          = 54,
+       HTT_STATS_HW_WD_TIMEOUT_TAG                         = 55,
+       HTT_STATS_HW_PDEV_ERRS_TAG                          = 56,
+       HTT_STATS_COUNTER_NAME_TAG                          = 57,
+       HTT_STATS_TX_TID_DETAILS_TAG                        = 58,
+       HTT_STATS_RX_TID_DETAILS_TAG                        = 59,
+       HTT_STATS_PEER_STATS_CMN_TAG                        = 60,
+       HTT_STATS_PEER_DETAILS_TAG                          = 61,
+       HTT_STATS_PEER_TX_RATE_STATS_TAG                    = 62,
+       HTT_STATS_PEER_RX_RATE_STATS_TAG                    = 63,
+       HTT_STATS_PEER_MSDU_FLOWQ_TAG                       = 64,
+       HTT_STATS_TX_DE_COMPL_STATS_TAG                     = 65,
+       HTT_STATS_WHAL_TX_TAG                               = 66,
+       HTT_STATS_TX_PDEV_SIFS_HIST_TAG                     = 67,
+       HTT_STATS_RX_PDEV_FW_STATS_PHY_ERR_TAG              = 68,
+       HTT_STATS_TX_TID_DETAILS_V1_TAG                     = 69,
+       HTT_STATS_PDEV_CCA_1SEC_HIST_TAG                    = 70,
+       HTT_STATS_PDEV_CCA_100MSEC_HIST_TAG                 = 71,
+       HTT_STATS_PDEV_CCA_STAT_CUMULATIVE_TAG              = 72,
+       HTT_STATS_PDEV_CCA_COUNTERS_TAG                     = 73,
+       HTT_STATS_TX_PDEV_MPDU_STATS_TAG                    = 74,
+       HTT_STATS_PDEV_TWT_SESSIONS_TAG                     = 75,
+       HTT_STATS_PDEV_TWT_SESSION_TAG                      = 76,
+       HTT_STATS_RX_REFILL_RXDMA_ERR_TAG                   = 77,
+       HTT_STATS_RX_REFILL_REO_ERR_TAG                     = 78,
+       HTT_STATS_RX_REO_RESOURCE_STATS_TAG                 = 79,
+       HTT_STATS_TX_SOUNDING_STATS_TAG                     = 80,
+       HTT_STATS_TX_PDEV_TX_PPDU_STATS_TAG                 = 81,
+       HTT_STATS_TX_PDEV_TRIED_MPDU_CNT_HIST_TAG           = 82,
+       HTT_STATS_TX_HWQ_TRIED_MPDU_CNT_HIST_TAG            = 83,
+       HTT_STATS_TX_HWQ_TXOP_USED_CNT_HIST_TAG             = 84,
+       HTT_STATS_TX_DE_FW2WBM_RING_FULL_HIST_TAG           = 85,
+       HTT_STATS_SCHED_TXQ_SCHED_ORDER_SU_TAG              = 86,
+       HTT_STATS_SCHED_TXQ_SCHED_INELIGIBILITY_TAG         = 87,
+       HTT_STATS_PDEV_OBSS_PD_TAG                          = 88,
+
+       HTT_STATS_MAX_TAG,
+};
+
+#define HTT_STATS_MAX_STRING_SZ32            4
+#define HTT_STATS_MACID_INVALID              0xff
+#define HTT_TX_HWQ_MAX_DIFS_LATENCY_BINS     10
+#define HTT_TX_HWQ_MAX_CMD_RESULT_STATS      13
+#define HTT_TX_HWQ_MAX_CMD_STALL_STATS       5
+#define HTT_TX_HWQ_MAX_FES_RESULT_STATS      10
+
+enum htt_tx_pdev_underrun_enum {
+       HTT_STATS_TX_PDEV_NO_DATA_UNDERRUN           = 0,
+       HTT_STATS_TX_PDEV_DATA_UNDERRUN_BETWEEN_MPDU = 1,
+       HTT_STATS_TX_PDEV_DATA_UNDERRUN_WITHIN_MPDU  = 2,
+       HTT_TX_PDEV_MAX_URRN_STATS                   = 3,
+};
+
+#define HTT_TX_PDEV_MAX_FLUSH_REASON_STATS     71
+#define HTT_TX_PDEV_MAX_SIFS_BURST_STATS       9
+#define HTT_TX_PDEV_MAX_SIFS_BURST_HIST_STATS  10
+#define HTT_TX_PDEV_MAX_PHY_ERR_STATS          18
+#define HTT_TX_PDEV_SCHED_TX_MODE_MAX          4
+#define HTT_TX_PDEV_NUM_SCHED_ORDER_LOG        20
+
+#define HTT_RX_STATS_REFILL_MAX_RING         4
+#define HTT_RX_STATS_RXDMA_MAX_ERR           16
+#define HTT_RX_STATS_FW_DROP_REASON_MAX      16
+
+/* Bytes stored in little endian order */
+/* Length should be multiple of DWORD */
+struct htt_stats_string_tlv {
+       u32 data[0]; /* Can be variable length */
+} __packed;
+
+/* == TX PDEV STATS == */
+struct htt_tx_pdev_stats_cmn_tlv {
+       u32 mac_id__word;
+       u32 hw_queued;
+       u32 hw_reaped;
+       u32 underrun;
+       u32 hw_paused;
+       u32 hw_flush;
+       u32 hw_filt;
+       u32 tx_abort;
+       u32 mpdu_requed;
+       u32 tx_xretry;
+       u32 data_rc;
+       u32 mpdu_dropped_xretry;
+       u32 illgl_rate_phy_err;
+       u32 cont_xretry;
+       u32 tx_timeout;
+       u32 pdev_resets;
+       u32 phy_underrun;
+       u32 txop_ovf;
+       u32 seq_posted;
+       u32 seq_failed_queueing;
+       u32 seq_completed;
+       u32 seq_restarted;
+       u32 mu_seq_posted;
+       u32 seq_switch_hw_paused;
+       u32 next_seq_posted_dsr;
+       u32 seq_posted_isr;
+       u32 seq_ctrl_cached;
+       u32 mpdu_count_tqm;
+       u32 msdu_count_tqm;
+       u32 mpdu_removed_tqm;
+       u32 msdu_removed_tqm;
+       u32 mpdus_sw_flush;
+       u32 mpdus_hw_filter;
+       u32 mpdus_truncated;
+       u32 mpdus_ack_failed;
+       u32 mpdus_expired;
+       u32 mpdus_seq_hw_retry;
+       u32 ack_tlv_proc;
+       u32 coex_abort_mpdu_cnt_valid;
+       u32 coex_abort_mpdu_cnt;
+       u32 num_total_ppdus_tried_ota;
+       u32 num_data_ppdus_tried_ota;
+       u32 local_ctrl_mgmt_enqued;
+       u32 local_ctrl_mgmt_freed;
+       u32 local_data_enqued;
+       u32 local_data_freed;
+       u32 mpdu_tried;
+       u32 isr_wait_seq_posted;
+
+       u32 tx_active_dur_us_low;
+       u32 tx_active_dur_us_high;
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_pdev_stats_urrn_tlv_v {
+       u32 urrn_stats[0]; /* HTT_TX_PDEV_MAX_URRN_STATS */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_pdev_stats_flush_tlv_v {
+       u32 flush_errs[0]; /* HTT_TX_PDEV_MAX_FLUSH_REASON_STATS */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_pdev_stats_sifs_tlv_v {
+       u32 sifs_status[0]; /* HTT_TX_PDEV_MAX_SIFS_BURST_STATS */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_pdev_stats_phy_err_tlv_v {
+       u32  phy_errs[0]; /* HTT_TX_PDEV_MAX_PHY_ERR_STATS */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_pdev_stats_sifs_hist_tlv_v {
+       u32 sifs_hist_status[0]; /* HTT_TX_PDEV_SIFS_BURST_HIST_STATS */
+};
+
+struct htt_tx_pdev_stats_tx_ppdu_stats_tlv_v {
+       u32 num_data_ppdus_legacy_su;
+       u32 num_data_ppdus_ac_su;
+       u32 num_data_ppdus_ax_su;
+       u32 num_data_ppdus_ac_su_txbf;
+       u32 num_data_ppdus_ax_su_txbf;
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size .
+ *
+ *  Tried_mpdu_cnt_hist is the histogram of MPDUs tries per HWQ.
+ *  The tries here is the count of the  MPDUS within a PPDU that the
+ *  HW had attempted to transmit on  air, for the HWSCH Schedule
+ *  command submitted by FW.It is not the retry attempts.
+ *  The histogram bins are  0-29, 30-59, 60-89 and so on. The are
+ *   10 bins in this histogram. They are defined in FW using the
+ *  following macros
+ *  #define WAL_MAX_TRIED_MPDU_CNT_HISTOGRAM 9
+ *  #define WAL_TRIED_MPDU_CNT_HISTOGRAM_INTERVAL 30
+ */
+struct htt_tx_pdev_stats_tried_mpdu_cnt_hist_tlv_v {
+       u32 hist_bin_size;
+       u32 tried_mpdu_cnt_hist[0]; /* HTT_TX_PDEV_TRIED_MPDU_CNT_HIST */
+};
+
+/* == SOC ERROR STATS == */
+
+/* =============== PDEV ERROR STATS ============== */
+#define HTT_STATS_MAX_HW_INTR_NAME_LEN 8
+struct htt_hw_stats_intr_misc_tlv {
+       /* Stored as little endian */
+       u8 hw_intr_name[HTT_STATS_MAX_HW_INTR_NAME_LEN];
+       u32 mask;
+       u32 count;
+};
+
+#define HTT_STATS_MAX_HW_MODULE_NAME_LEN 8
+struct htt_hw_stats_wd_timeout_tlv {
+       /* Stored as little endian */
+       u8 hw_module_name[HTT_STATS_MAX_HW_MODULE_NAME_LEN];
+       u32 count;
+};
+
+struct htt_hw_stats_pdev_errs_tlv {
+       u32    mac_id__word; /* BIT [ 7 :  0] : mac_id */
+       u32    tx_abort;
+       u32    tx_abort_fail_count;
+       u32    rx_abort;
+       u32    rx_abort_fail_count;
+       u32    warm_reset;
+       u32    cold_reset;
+       u32    tx_flush;
+       u32    tx_glb_reset;
+       u32    tx_txq_reset;
+       u32    rx_timeout_reset;
+};
+
+struct htt_hw_stats_whal_tx_tlv {
+       u32 mac_id__word;
+       u32 last_unpause_ppdu_id;
+       u32 hwsch_unpause_wait_tqm_write;
+       u32 hwsch_dummy_tlv_skipped;
+       u32 hwsch_misaligned_offset_received;
+       u32 hwsch_reset_count;
+       u32 hwsch_dev_reset_war;
+       u32 hwsch_delayed_pause;
+       u32 hwsch_long_delayed_pause;
+       u32 sch_rx_ppdu_no_response;
+       u32 sch_selfgen_response;
+       u32 sch_rx_sifs_resp_trigger;
+};
+
+/* ============ PEER STATS ============ */
+struct htt_msdu_flow_stats_tlv {
+       u32 last_update_timestamp;
+       u32 last_add_timestamp;
+       u32 last_remove_timestamp;
+       u32 total_processed_msdu_count;
+       u32 cur_msdu_count_in_flowq;
+       u32 sw_peer_id;
+       u32 tx_flow_no__tid_num__drop_rule;
+       u32 last_cycle_enqueue_count;
+       u32 last_cycle_dequeue_count;
+       u32 last_cycle_drop_count;
+       u32 current_drop_th;
+};
+
+#define MAX_HTT_TID_NAME 8
+
+/* Tidq stats */
+struct htt_tx_tid_stats_tlv {
+       /* Stored as little endian */
+       u8     tid_name[MAX_HTT_TID_NAME];
+       u32 sw_peer_id__tid_num;
+       u32 num_sched_pending__num_ppdu_in_hwq;
+       u32 tid_flags;
+       u32 hw_queued;
+       u32 hw_reaped;
+       u32 mpdus_hw_filter;
+
+       u32 qdepth_bytes;
+       u32 qdepth_num_msdu;
+       u32 qdepth_num_mpdu;
+       u32 last_scheduled_tsmp;
+       u32 pause_module_id;
+       u32 block_module_id;
+       u32 tid_tx_airtime;
+};
+
+/* Tidq stats */
+struct htt_tx_tid_stats_v1_tlv {
+       /* Stored as little endian */
+       u8 tid_name[MAX_HTT_TID_NAME];
+       u32 sw_peer_id__tid_num;
+       u32 num_sched_pending__num_ppdu_in_hwq;
+       u32 tid_flags;
+       u32 max_qdepth_bytes;
+       u32 max_qdepth_n_msdus;
+       u32 rsvd;
+
+       u32 qdepth_bytes;
+       u32 qdepth_num_msdu;
+       u32 qdepth_num_mpdu;
+       u32 last_scheduled_tsmp;
+       u32 pause_module_id;
+       u32 block_module_id;
+       u32 tid_tx_airtime;
+       u32 allow_n_flags;
+       u32 sendn_frms_allowed;
+};
+
+struct htt_rx_tid_stats_tlv {
+       u32 sw_peer_id__tid_num;
+       u8 tid_name[MAX_HTT_TID_NAME];
+       u32 dup_in_reorder;
+       u32 dup_past_outside_window;
+       u32 dup_past_within_window;
+       u32 rxdesc_err_decrypt;
+       u32 tid_rx_airtime;
+};
+
+#define HTT_MAX_COUNTER_NAME 8
+struct htt_counter_tlv {
+       u8 counter_name[HTT_MAX_COUNTER_NAME];
+       u32 count;
+};
+
+struct htt_peer_stats_cmn_tlv {
+       u32 ppdu_cnt;
+       u32 mpdu_cnt;
+       u32 msdu_cnt;
+       u32 pause_bitmap;
+       u32 block_bitmap;
+       u32 current_timestamp;
+       u32 peer_tx_airtime;
+       u32 peer_rx_airtime;
+       s32 rssi;
+       u32 peer_enqueued_count_low;
+       u32 peer_enqueued_count_high;
+       u32 peer_dequeued_count_low;
+       u32 peer_dequeued_count_high;
+       u32 peer_dropped_count_low;
+       u32 peer_dropped_count_high;
+       u32 ppdu_transmitted_bytes_low;
+       u32 ppdu_transmitted_bytes_high;
+       u32 peer_ttl_removed_count;
+       u32 inactive_time;
+};
+
+struct htt_peer_details_tlv {
+       u32 peer_type;
+       u32 sw_peer_id;
+       u32 vdev_pdev_ast_idx;
+       struct htt_mac_addr mac_addr;
+       u32 peer_flags;
+       u32 qpeer_flags;
+};
+
+enum htt_stats_param_type {
+       HTT_STATS_PREAM_OFDM,
+       HTT_STATS_PREAM_CCK,
+       HTT_STATS_PREAM_HT,
+       HTT_STATS_PREAM_VHT,
+       HTT_STATS_PREAM_HE,
+       HTT_STATS_PREAM_RSVD,
+       HTT_STATS_PREAM_RSVD1,
+
+       HTT_STATS_PREAM_COUNT,
+};
+
+#define HTT_TX_PEER_STATS_NUM_MCS_COUNTERS        12
+#define HTT_TX_PEER_STATS_NUM_GI_COUNTERS          4
+#define HTT_TX_PEER_STATS_NUM_DCM_COUNTERS         5
+#define HTT_TX_PEER_STATS_NUM_BW_COUNTERS          4
+#define HTT_TX_PEER_STATS_NUM_SPATIAL_STREAMS      8
+#define HTT_TX_PEER_STATS_NUM_PREAMBLE_TYPES       HTT_STATS_PREAM_COUNT
+
+struct htt_tx_peer_rate_stats_tlv {
+       u32 tx_ldpc;
+       u32 rts_cnt;
+       u32 ack_rssi;
+
+       u32 tx_mcs[HTT_TX_PEER_STATS_NUM_MCS_COUNTERS];
+       u32 tx_su_mcs[HTT_TX_PEER_STATS_NUM_MCS_COUNTERS];
+       u32 tx_mu_mcs[HTT_TX_PEER_STATS_NUM_MCS_COUNTERS];
+       /* element 0,1, ...7 -> NSS 1,2, ...8 */
+       u32 tx_nss[HTT_TX_PEER_STATS_NUM_SPATIAL_STREAMS];
+       /* element 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160 and 80+80 MHz */
+       u32 tx_bw[HTT_TX_PEER_STATS_NUM_BW_COUNTERS];
+       u32 tx_stbc[HTT_TX_PEER_STATS_NUM_MCS_COUNTERS];
+       u32 tx_pream[HTT_TX_PEER_STATS_NUM_PREAMBLE_TYPES];
+
+       /* Counters to track number of tx packets in each GI
+        * (400us, 800us, 1600us & 3200us) in each mcs (0-11)
+        */
+       u32 tx_gi[HTT_TX_PEER_STATS_NUM_GI_COUNTERS][HTT_TX_PEER_STATS_NUM_MCS_COUNTERS];
+
+       /* Counters to track packets in dcm mcs (MCS 0, 1, 3, 4) */
+       u32 tx_dcm[HTT_TX_PEER_STATS_NUM_DCM_COUNTERS];
+
+};
+
+#define HTT_RX_PEER_STATS_NUM_MCS_COUNTERS        12
+#define HTT_RX_PEER_STATS_NUM_GI_COUNTERS          4
+#define HTT_RX_PEER_STATS_NUM_DCM_COUNTERS         5
+#define HTT_RX_PEER_STATS_NUM_BW_COUNTERS          4
+#define HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS      8
+#define HTT_RX_PEER_STATS_NUM_PREAMBLE_TYPES       HTT_STATS_PREAM_COUNT
+
+struct htt_rx_peer_rate_stats_tlv {
+       u32 nsts;
+
+       /* Number of rx ldpc packets */
+       u32 rx_ldpc;
+       /* Number of rx rts packets */
+       u32 rts_cnt;
+
+       u32 rssi_mgmt; /* units = dB above noise floor */
+       u32 rssi_data; /* units = dB above noise floor */
+       u32 rssi_comb; /* units = dB above noise floor */
+       u32 rx_mcs[HTT_RX_PEER_STATS_NUM_MCS_COUNTERS];
+       /* element 0,1, ...7 -> NSS 1,2, ...8 */
+       u32 rx_nss[HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS];
+       u32 rx_dcm[HTT_RX_PEER_STATS_NUM_DCM_COUNTERS];
+       u32 rx_stbc[HTT_RX_PEER_STATS_NUM_MCS_COUNTERS];
+       /* element 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160 and 80+80 MHz */
+       u32 rx_bw[HTT_RX_PEER_STATS_NUM_BW_COUNTERS];
+       u32 rx_pream[HTT_RX_PEER_STATS_NUM_PREAMBLE_TYPES];
+       /* units = dB above noise floor */
+       u8 rssi_chain[HTT_RX_PEER_STATS_NUM_SPATIAL_STREAMS]
+                    [HTT_RX_PEER_STATS_NUM_BW_COUNTERS];
+
+       /* Counters to track number of rx packets in each GI in each mcs (0-11) */
+       u32 rx_gi[HTT_RX_PEER_STATS_NUM_GI_COUNTERS]
+                [HTT_RX_PEER_STATS_NUM_MCS_COUNTERS];
+};
+
+enum htt_peer_stats_req_mode {
+       HTT_PEER_STATS_REQ_MODE_NO_QUERY,
+       HTT_PEER_STATS_REQ_MODE_QUERY_TQM,
+       HTT_PEER_STATS_REQ_MODE_FLUSH_TQM,
+};
+
+enum htt_peer_stats_tlv_enum {
+       HTT_PEER_STATS_CMN_TLV       = 0,
+       HTT_PEER_DETAILS_TLV         = 1,
+       HTT_TX_PEER_RATE_STATS_TLV   = 2,
+       HTT_RX_PEER_RATE_STATS_TLV   = 3,
+       HTT_TX_TID_STATS_TLV         = 4,
+       HTT_RX_TID_STATS_TLV         = 5,
+       HTT_MSDU_FLOW_STATS_TLV      = 6,
+
+       HTT_PEER_STATS_MAX_TLV       = 31,
+};
+
+/* =========== MUMIMO HWQ stats =========== */
+/* MU MIMO stats per hwQ */
+struct htt_tx_hwq_mu_mimo_sch_stats_tlv {
+       u32 mu_mimo_sch_posted;
+       u32 mu_mimo_sch_failed;
+       u32 mu_mimo_ppdu_posted;
+};
+
+struct htt_tx_hwq_mu_mimo_mpdu_stats_tlv {
+       u32 mu_mimo_mpdus_queued_usr;
+       u32 mu_mimo_mpdus_tried_usr;
+       u32 mu_mimo_mpdus_failed_usr;
+       u32 mu_mimo_mpdus_requeued_usr;
+       u32 mu_mimo_err_no_ba_usr;
+       u32 mu_mimo_mpdu_underrun_usr;
+       u32 mu_mimo_ampdu_underrun_usr;
+};
+
+struct htt_tx_hwq_mu_mimo_cmn_stats_tlv {
+       u32 mac_id__hwq_id__word;
+};
+
+/* == TX HWQ STATS == */
+struct htt_tx_hwq_stats_cmn_tlv {
+       u32 mac_id__hwq_id__word;
+
+       /* PPDU level stats */
+       u32 xretry;
+       u32 underrun_cnt;
+       u32 flush_cnt;
+       u32 filt_cnt;
+       u32 null_mpdu_bmap;
+       u32 user_ack_failure;
+       u32 ack_tlv_proc;
+       u32 sched_id_proc;
+       u32 null_mpdu_tx_count;
+       u32 mpdu_bmap_not_recvd;
+
+       /* Selfgen stats per hwQ */
+       u32 num_bar;
+       u32 rts;
+       u32 cts2self;
+       u32 qos_null;
+
+       /* MPDU level stats */
+       u32 mpdu_tried_cnt;
+       u32 mpdu_queued_cnt;
+       u32 mpdu_ack_fail_cnt;
+       u32 mpdu_filt_cnt;
+       u32 false_mpdu_ack_count;
+
+       u32 txq_timeout;
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_hwq_difs_latency_stats_tlv_v {
+       u32 hist_intvl;
+       /* histogram of ppdu post to hwsch - > cmd status received */
+       u32 difs_latency_hist[0]; /* HTT_TX_HWQ_MAX_DIFS_LATENCY_BINS */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_hwq_cmd_result_stats_tlv_v {
+       /* Histogram of sched cmd result */
+       u32 cmd_result[0]; /* HTT_TX_HWQ_MAX_CMD_RESULT_STATS */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_hwq_cmd_stall_stats_tlv_v {
+       /* Histogram of various pause conitions */
+       u32 cmd_stall_status[0]; /* HTT_TX_HWQ_MAX_CMD_STALL_STATS */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_hwq_fes_result_stats_tlv_v {
+       /* Histogram of number of user fes result */
+       u32 fes_result[0]; /* HTT_TX_HWQ_MAX_FES_RESULT_STATS */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size
+ *
+ *  The hwq_tried_mpdu_cnt_hist is a  histogram of MPDUs tries per HWQ.
+ *  The tries here is the count of the  MPDUS within a PPDU that the HW
+ *  had attempted to transmit on  air, for the HWSCH Schedule command
+ *  submitted by FW in this HWQ .It is not the retry attempts. The
+ *  histogram bins are  0-29, 30-59, 60-89 and so on. The are 10 bins
+ *  in this histogram.
+ *  they are defined in FW using the following macros
+ *  #define WAL_MAX_TRIED_MPDU_CNT_HISTOGRAM 9
+ *  #define WAL_TRIED_MPDU_CNT_HISTOGRAM_INTERVAL 30
+ */
+struct htt_tx_hwq_tried_mpdu_cnt_hist_tlv_v {
+       u32 hist_bin_size;
+       /* Histogram of number of mpdus on tried mpdu */
+       u32 tried_mpdu_cnt_hist[0]; /* HTT_TX_HWQ_TRIED_MPDU_CNT_HIST */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size
+ *
+ * The txop_used_cnt_hist is the histogram of txop per burst. After
+ * completing the burst, we identify the txop used in the burst and
+ * incr the corresponding bin.
+ * Each bin represents 1ms & we have 10 bins in this histogram.
+ * they are deined in FW using the following macros
+ * #define WAL_MAX_TXOP_USED_CNT_HISTOGRAM 10
+ * #define WAL_TXOP_USED_HISTOGRAM_INTERVAL 1000 ( 1 ms )
+ */
+struct htt_tx_hwq_txop_used_cnt_hist_tlv_v {
+       /* Histogram of txop used cnt */
+       u32 txop_used_cnt_hist[0]; /* HTT_TX_HWQ_TXOP_USED_CNT_HIST */
+};
+
+/* == TX SELFGEN STATS == */
+struct htt_tx_selfgen_cmn_stats_tlv {
+       u32 mac_id__word;
+       u32 su_bar;
+       u32 rts;
+       u32 cts2self;
+       u32 qos_null;
+       u32 delayed_bar_1; /* MU user 1 */
+       u32 delayed_bar_2; /* MU user 2 */
+       u32 delayed_bar_3; /* MU user 3 */
+       u32 delayed_bar_4; /* MU user 4 */
+       u32 delayed_bar_5; /* MU user 5 */
+       u32 delayed_bar_6; /* MU user 6 */
+       u32 delayed_bar_7; /* MU user 7 */
+};
+
+struct htt_tx_selfgen_ac_stats_tlv {
+       /* 11AC */
+       u32 ac_su_ndpa;
+       u32 ac_su_ndp;
+       u32 ac_mu_mimo_ndpa;
+       u32 ac_mu_mimo_ndp;
+       u32 ac_mu_mimo_brpoll_1; /* MU user 1 */
+       u32 ac_mu_mimo_brpoll_2; /* MU user 2 */
+       u32 ac_mu_mimo_brpoll_3; /* MU user 3 */
+};
+
+struct htt_tx_selfgen_ax_stats_tlv {
+       /* 11AX */
+       u32 ax_su_ndpa;
+       u32 ax_su_ndp;
+       u32 ax_mu_mimo_ndpa;
+       u32 ax_mu_mimo_ndp;
+       u32 ax_mu_mimo_brpoll_1; /* MU user 1 */
+       u32 ax_mu_mimo_brpoll_2; /* MU user 2 */
+       u32 ax_mu_mimo_brpoll_3; /* MU user 3 */
+       u32 ax_mu_mimo_brpoll_4; /* MU user 4 */
+       u32 ax_mu_mimo_brpoll_5; /* MU user 5 */
+       u32 ax_mu_mimo_brpoll_6; /* MU user 6 */
+       u32 ax_mu_mimo_brpoll_7; /* MU user 7 */
+       u32 ax_basic_trigger;
+       u32 ax_bsr_trigger;
+       u32 ax_mu_bar_trigger;
+       u32 ax_mu_rts_trigger;
+};
+
+struct htt_tx_selfgen_ac_err_stats_tlv {
+       /* 11AC error stats */
+       u32 ac_su_ndp_err;
+       u32 ac_su_ndpa_err;
+       u32 ac_mu_mimo_ndpa_err;
+       u32 ac_mu_mimo_ndp_err;
+       u32 ac_mu_mimo_brp1_err;
+       u32 ac_mu_mimo_brp2_err;
+       u32 ac_mu_mimo_brp3_err;
+};
+
+struct htt_tx_selfgen_ax_err_stats_tlv {
+       /* 11AX error stats */
+       u32 ax_su_ndp_err;
+       u32 ax_su_ndpa_err;
+       u32 ax_mu_mimo_ndpa_err;
+       u32 ax_mu_mimo_ndp_err;
+       u32 ax_mu_mimo_brp1_err;
+       u32 ax_mu_mimo_brp2_err;
+       u32 ax_mu_mimo_brp3_err;
+       u32 ax_mu_mimo_brp4_err;
+       u32 ax_mu_mimo_brp5_err;
+       u32 ax_mu_mimo_brp6_err;
+       u32 ax_mu_mimo_brp7_err;
+       u32 ax_basic_trigger_err;
+       u32 ax_bsr_trigger_err;
+       u32 ax_mu_bar_trigger_err;
+       u32 ax_mu_rts_trigger_err;
+};
+
+/* == TX MU STATS == */
+#define HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS 4
+#define HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS 8
+#define HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS    74
+
+struct htt_tx_pdev_mu_mimo_sch_stats_tlv {
+       /* mu-mimo sw sched cmd stats */
+       u32 mu_mimo_sch_posted;
+       u32 mu_mimo_sch_failed;
+       /* MU PPDU stats per hwQ */
+       u32 mu_mimo_ppdu_posted;
+       /*
+        * Counts the number of users in each transmission of
+        * the given TX mode.
+        *
+        * Index is the number of users - 1.
+        */
+       u32 ac_mu_mimo_sch_nusers[HTT_TX_PDEV_STATS_NUM_AC_MUMIMO_USER_STATS];
+       u32 ax_mu_mimo_sch_nusers[HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS];
+       u32 ax_ofdma_sch_nusers[HTT_TX_PDEV_STATS_NUM_OFDMA_USER_STATS];
+};
+
+struct htt_tx_pdev_mu_mimo_mpdu_stats_tlv {
+       u32 mu_mimo_mpdus_queued_usr;
+       u32 mu_mimo_mpdus_tried_usr;
+       u32 mu_mimo_mpdus_failed_usr;
+       u32 mu_mimo_mpdus_requeued_usr;
+       u32 mu_mimo_err_no_ba_usr;
+       u32 mu_mimo_mpdu_underrun_usr;
+       u32 mu_mimo_ampdu_underrun_usr;
+
+       u32 ax_mu_mimo_mpdus_queued_usr;
+       u32 ax_mu_mimo_mpdus_tried_usr;
+       u32 ax_mu_mimo_mpdus_failed_usr;
+       u32 ax_mu_mimo_mpdus_requeued_usr;
+       u32 ax_mu_mimo_err_no_ba_usr;
+       u32 ax_mu_mimo_mpdu_underrun_usr;
+       u32 ax_mu_mimo_ampdu_underrun_usr;
+
+       u32 ax_ofdma_mpdus_queued_usr;
+       u32 ax_ofdma_mpdus_tried_usr;
+       u32 ax_ofdma_mpdus_failed_usr;
+       u32 ax_ofdma_mpdus_requeued_usr;
+       u32 ax_ofdma_err_no_ba_usr;
+       u32 ax_ofdma_mpdu_underrun_usr;
+       u32 ax_ofdma_ampdu_underrun_usr;
+};
+
+#define HTT_STATS_TX_SCHED_MODE_MU_MIMO_AC  1
+#define HTT_STATS_TX_SCHED_MODE_MU_MIMO_AX  2
+#define HTT_STATS_TX_SCHED_MODE_MU_OFDMA_AX 3
+
+struct htt_tx_pdev_mpdu_stats_tlv {
+       /* mpdu level stats */
+       u32 mpdus_queued_usr;
+       u32 mpdus_tried_usr;
+       u32 mpdus_failed_usr;
+       u32 mpdus_requeued_usr;
+       u32 err_no_ba_usr;
+       u32 mpdu_underrun_usr;
+       u32 ampdu_underrun_usr;
+       u32 user_index;
+       u32 tx_sched_mode; /* HTT_STATS_TX_SCHED_MODE_xxx */
+};
+
+/* == TX SCHED STATS == */
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_sched_txq_cmd_posted_tlv_v {
+       u32 sched_cmd_posted[0]; /* HTT_TX_PDEV_SCHED_TX_MODE_MAX */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_sched_txq_cmd_reaped_tlv_v {
+       u32 sched_cmd_reaped[0]; /* HTT_TX_PDEV_SCHED_TX_MODE_MAX */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_sched_txq_sched_order_su_tlv_v {
+       u32 sched_order_su[0]; /* HTT_TX_PDEV_NUM_SCHED_ORDER_LOG */
+};
+
+enum htt_sched_txq_sched_ineligibility_tlv_enum {
+       HTT_SCHED_TID_SKIP_SCHED_MASK_DISABLED = 0,
+       HTT_SCHED_TID_SKIP_NOTIFY_MPDU,
+       HTT_SCHED_TID_SKIP_MPDU_STATE_INVALID,
+       HTT_SCHED_TID_SKIP_SCHED_DISABLED,
+       HTT_SCHED_TID_SKIP_TQM_BYPASS_CMD_PENDING,
+       HTT_SCHED_TID_SKIP_SECOND_SU_SCHEDULE,
+
+       HTT_SCHED_TID_SKIP_CMD_SLOT_NOT_AVAIL,
+       HTT_SCHED_TID_SKIP_NO_ENQ,
+       HTT_SCHED_TID_SKIP_LOW_ENQ,
+       HTT_SCHED_TID_SKIP_PAUSED,
+       HTT_SCHED_TID_SKIP_UL,
+       HTT_SCHED_TID_REMOVE_PAUSED,
+       HTT_SCHED_TID_REMOVE_NO_ENQ,
+       HTT_SCHED_TID_REMOVE_UL,
+       HTT_SCHED_TID_QUERY,
+       HTT_SCHED_TID_SU_ONLY,
+       HTT_SCHED_TID_ELIGIBLE,
+       HTT_SCHED_INELIGIBILITY_MAX,
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_sched_txq_sched_ineligibility_tlv_v {
+       /* indexed by htt_sched_txq_sched_ineligibility_tlv_enum */
+       u32 sched_ineligibility[0];
+};
+
+struct htt_tx_pdev_stats_sched_per_txq_tlv {
+       u32 mac_id__txq_id__word;
+       u32 sched_policy;
+       u32 last_sched_cmd_posted_timestamp;
+       u32 last_sched_cmd_compl_timestamp;
+       u32 sched_2_tac_lwm_count;
+       u32 sched_2_tac_ring_full;
+       u32 sched_cmd_post_failure;
+       u32 num_active_tids;
+       u32 num_ps_schedules;
+       u32 sched_cmds_pending;
+       u32 num_tid_register;
+       u32 num_tid_unregister;
+       u32 num_qstats_queried;
+       u32 qstats_update_pending;
+       u32 last_qstats_query_timestamp;
+       u32 num_tqm_cmdq_full;
+       u32 num_de_sched_algo_trigger;
+       u32 num_rt_sched_algo_trigger;
+       u32 num_tqm_sched_algo_trigger;
+       u32 notify_sched;
+       u32 dur_based_sendn_term;
+};
+
+struct htt_stats_tx_sched_cmn_tlv {
+       /* BIT [ 7 :  0]   :- mac_id
+        * BIT [31 :  8]   :- reserved
+        */
+       u32 mac_id__word;
+       /* Current timestamp */
+       u32 current_timestamp;
+};
+
+/* == TQM STATS == */
+#define HTT_TX_TQM_MAX_GEN_MPDU_END_REASON          16
+#define HTT_TX_TQM_MAX_LIST_MPDU_END_REASON         16
+#define HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS 16
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_tqm_gen_mpdu_stats_tlv_v {
+       u32 gen_mpdu_end_reason[0]; /* HTT_TX_TQM_MAX_GEN_MPDU_END_REASON */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_tqm_list_mpdu_stats_tlv_v {
+       u32 list_mpdu_end_reason[0]; /* HTT_TX_TQM_MAX_LIST_MPDU_END_REASON */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_tx_tqm_list_mpdu_cnt_tlv_v {
+       u32 list_mpdu_cnt_hist[0];
+                       /* HTT_TX_TQM_MAX_LIST_MPDU_CNT_HISTOGRAM_BINS */
+};
+
+struct htt_tx_tqm_pdev_stats_tlv_v {
+       u32 msdu_count;
+       u32 mpdu_count;
+       u32 remove_msdu;
+       u32 remove_mpdu;
+       u32 remove_msdu_ttl;
+       u32 send_bar;
+       u32 bar_sync;
+       u32 notify_mpdu;
+       u32 sync_cmd;
+       u32 write_cmd;
+       u32 hwsch_trigger;
+       u32 ack_tlv_proc;
+       u32 gen_mpdu_cmd;
+       u32 gen_list_cmd;
+       u32 remove_mpdu_cmd;
+       u32 remove_mpdu_tried_cmd;
+       u32 mpdu_queue_stats_cmd;
+       u32 mpdu_head_info_cmd;
+       u32 msdu_flow_stats_cmd;
+       u32 remove_msdu_cmd;
+       u32 remove_msdu_ttl_cmd;
+       u32 flush_cache_cmd;
+       u32 update_mpduq_cmd;
+       u32 enqueue;
+       u32 enqueue_notify;
+       u32 notify_mpdu_at_head;
+       u32 notify_mpdu_state_valid;
+       /*
+        * On receiving TQM_FLOW_NOT_EMPTY_STATUS from TQM, (on MSDUs being enqueued
+        * the flow is non empty), if the number of MSDUs is greater than the threshold,
+        * notify is incremented. UDP_THRESH counters are for UDP MSDUs, and NONUDP are
+        * for non-UDP MSDUs.
+        * MSDUQ_SWNOTIFY_UDP_THRESH1 threshold    - sched_udp_notify1 is incremented
+        * MSDUQ_SWNOTIFY_UDP_THRESH2 threshold    - sched_udp_notify2 is incremented
+        * MSDUQ_SWNOTIFY_NONUDP_THRESH1 threshold - sched_nonudp_notify1 is incremented
+        * MSDUQ_SWNOTIFY_NONUDP_THRESH2 threshold - sched_nonudp_notify2 is incremented
+        *
+        * Notify signifies that we trigger the scheduler.
+        */
+       u32 sched_udp_notify1;
+       u32 sched_udp_notify2;
+       u32 sched_nonudp_notify1;
+       u32 sched_nonudp_notify2;
+};
+
+struct htt_tx_tqm_cmn_stats_tlv {
+       u32 mac_id__word;
+       u32 max_cmdq_id;
+       u32 list_mpdu_cnt_hist_intvl;
+
+       /* Global stats */
+       u32 add_msdu;
+       u32 q_empty;
+       u32 q_not_empty;
+       u32 drop_notification;
+       u32 desc_threshold;
+};
+
+struct htt_tx_tqm_error_stats_tlv {
+       /* Error stats */
+       u32 q_empty_failure;
+       u32 q_not_empty_failure;
+       u32 add_msdu_failure;
+};
+
+/* == TQM CMDQ stats == */
+struct htt_tx_tqm_cmdq_status_tlv {
+       u32 mac_id__cmdq_id__word;
+       u32 sync_cmd;
+       u32 write_cmd;
+       u32 gen_mpdu_cmd;
+       u32 mpdu_queue_stats_cmd;
+       u32 mpdu_head_info_cmd;
+       u32 msdu_flow_stats_cmd;
+       u32 remove_mpdu_cmd;
+       u32 remove_msdu_cmd;
+       u32 flush_cache_cmd;
+       u32 update_mpduq_cmd;
+       u32 update_msduq_cmd;
+};
+
+/* == TX-DE STATS == */
+/* Structures for tx de stats */
+struct htt_tx_de_eapol_packets_stats_tlv {
+       u32 m1_packets;
+       u32 m2_packets;
+       u32 m3_packets;
+       u32 m4_packets;
+       u32 g1_packets;
+       u32 g2_packets;
+};
+
+struct htt_tx_de_classify_failed_stats_tlv {
+       u32 ap_bss_peer_not_found;
+       u32 ap_bcast_mcast_no_peer;
+       u32 sta_delete_in_progress;
+       u32 ibss_no_bss_peer;
+       u32 invalid_vdev_type;
+       u32 invalid_ast_peer_entry;
+       u32 peer_entry_invalid;
+       u32 ethertype_not_ip;
+       u32 eapol_lookup_failed;
+       u32 qpeer_not_allow_data;
+       u32 fse_tid_override;
+       u32 ipv6_jumbogram_zero_length;
+       u32 qos_to_non_qos_in_prog;
+};
+
+struct htt_tx_de_classify_stats_tlv {
+       u32 arp_packets;
+       u32 igmp_packets;
+       u32 dhcp_packets;
+       u32 host_inspected;
+       u32 htt_included;
+       u32 htt_valid_mcs;
+       u32 htt_valid_nss;
+       u32 htt_valid_preamble_type;
+       u32 htt_valid_chainmask;
+       u32 htt_valid_guard_interval;
+       u32 htt_valid_retries;
+       u32 htt_valid_bw_info;
+       u32 htt_valid_power;
+       u32 htt_valid_key_flags;
+       u32 htt_valid_no_encryption;
+       u32 fse_entry_count;
+       u32 fse_priority_be;
+       u32 fse_priority_high;
+       u32 fse_priority_low;
+       u32 fse_traffic_ptrn_be;
+       u32 fse_traffic_ptrn_over_sub;
+       u32 fse_traffic_ptrn_bursty;
+       u32 fse_traffic_ptrn_interactive;
+       u32 fse_traffic_ptrn_periodic;
+       u32 fse_hwqueue_alloc;
+       u32 fse_hwqueue_created;
+       u32 fse_hwqueue_send_to_host;
+       u32 mcast_entry;
+       u32 bcast_entry;
+       u32 htt_update_peer_cache;
+       u32 htt_learning_frame;
+       u32 fse_invalid_peer;
+       /*
+        * mec_notify is HTT TX WBM multicast echo check notification
+        * from firmware to host.  FW sends SA addresses to host for all
+        * multicast/broadcast packets received on STA side.
+        */
+       u32    mec_notify;
+};
+
+struct htt_tx_de_classify_status_stats_tlv {
+       u32 eok;
+       u32 classify_done;
+       u32 lookup_failed;
+       u32 send_host_dhcp;
+       u32 send_host_mcast;
+       u32 send_host_unknown_dest;
+       u32 send_host;
+       u32 status_invalid;
+};
+
+struct htt_tx_de_enqueue_packets_stats_tlv {
+       u32 enqueued_pkts;
+       u32 to_tqm;
+       u32 to_tqm_bypass;
+};
+
+struct htt_tx_de_enqueue_discard_stats_tlv {
+       u32 discarded_pkts;
+       u32 local_frames;
+       u32 is_ext_msdu;
+};
+
+struct htt_tx_de_compl_stats_tlv {
+       u32 tcl_dummy_frame;
+       u32 tqm_dummy_frame;
+       u32 tqm_notify_frame;
+       u32 fw2wbm_enq;
+       u32 tqm_bypass_frame;
+};
+
+/*
+ *  The htt_tx_de_fw2wbm_ring_full_hist_tlv is a histogram of time we waited
+ *  for the fw2wbm ring buffer.  we are requesting a buffer in FW2WBM release
+ *  ring,which may fail, due to non availability of buffer. Hence we sleep for
+ *  200us & again request for it. This is a histogram of time we wait, with
+ *  bin of 200ms & there are 10 bin (2 seconds max)
+ *  They are defined by the following macros in FW
+ *  #define ENTRIES_PER_BIN_COUNT 1000  // per bin 1000 * 200us = 200ms
+ *  #define RING_FULL_BIN_ENTRIES (WAL_TX_DE_FW2WBM_ALLOC_TIMEOUT_COUNT /
+ *                               ENTRIES_PER_BIN_COUNT)
+ */
+struct htt_tx_de_fw2wbm_ring_full_hist_tlv {
+       u32 fw2wbm_ring_full_hist[0];
+};
+
+struct htt_tx_de_cmn_stats_tlv {
+       u32   mac_id__word;
+
+       /* Global Stats */
+       u32   tcl2fw_entry_count;
+       u32   not_to_fw;
+       u32   invalid_pdev_vdev_peer;
+       u32   tcl_res_invalid_addrx;
+       u32   wbm2fw_entry_count;
+       u32   invalid_pdev;
+};
+
+/* == RING-IF STATS == */
+#define HTT_STATS_LOW_WM_BINS      5
+#define HTT_STATS_HIGH_WM_BINS     5
+
+struct htt_ring_if_stats_tlv {
+       u32 base_addr; /* DWORD aligned base memory address of the ring */
+       u32 elem_size;
+       u32 num_elems__prefetch_tail_idx;
+       u32 head_idx__tail_idx;
+       u32 shadow_head_idx__shadow_tail_idx;
+       u32 num_tail_incr;
+       u32 lwm_thresh__hwm_thresh;
+       u32 overrun_hit_count;
+       u32 underrun_hit_count;
+       u32 prod_blockwait_count;
+       u32 cons_blockwait_count;
+       u32 low_wm_hit_count[HTT_STATS_LOW_WM_BINS];
+       u32 high_wm_hit_count[HTT_STATS_HIGH_WM_BINS];
+};
+
+struct htt_ring_if_cmn_tlv {
+       u32 mac_id__word;
+       u32 num_records;
+};
+
+/* == SFM STATS == */
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_sfm_client_user_tlv_v {
+       /* Number of DWORDS used per user and per client */
+       u32 dwords_used_by_user_n[0];
+};
+
+struct htt_sfm_client_tlv {
+       /* Client ID */
+       u32 client_id;
+       /* Minimum number of buffers */
+       u32 buf_min;
+       /* Maximum number of buffers */
+       u32 buf_max;
+       /* Number of Busy buffers */
+       u32 buf_busy;
+       /* Number of Allocated buffers */
+       u32 buf_alloc;
+       /* Number of Available/Usable buffers */
+       u32 buf_avail;
+       /* Number of users */
+       u32 num_users;
+};
+
+struct htt_sfm_cmn_tlv {
+       u32 mac_id__word;
+       /* Indicates the total number of 128 byte buffers
+        * in the CMEM that are available for buffer sharing
+        */
+       u32 buf_total;
+       /* Indicates for certain client or all the clients
+        * there is no dowrd saved in SFM, refer to SFM_R1_MEM_EMPTY
+        */
+       u32 mem_empty;
+       /* DEALLOCATE_BUFFERS, refer to register SFM_R0_DEALLOCATE_BUFFERS */
+       u32 deallocate_bufs;
+       /* Number of Records */
+       u32 num_records;
+};
+
+/* == SRNG STATS == */
+struct htt_sring_stats_tlv {
+       u32 mac_id__ring_id__arena__ep;
+       u32 base_addr_lsb; /* DWORD aligned base memory address of the ring */
+       u32 base_addr_msb;
+       u32 ring_size;
+       u32 elem_size;
+
+       u32 num_avail_words__num_valid_words;
+       u32 head_ptr__tail_ptr;
+       u32 consumer_empty__producer_full;
+       u32 prefetch_count__internal_tail_ptr;
+};
+
+struct htt_sring_cmn_tlv {
+       u32 num_records;
+};
+
+/* == PDEV TX RATE CTRL STATS == */
+#define HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS        12
+#define HTT_TX_PDEV_STATS_NUM_GI_COUNTERS          4
+#define HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS         5
+#define HTT_TX_PDEV_STATS_NUM_BW_COUNTERS          4
+#define HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS      8
+#define HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES       HTT_STATS_PREAM_COUNT
+#define HTT_TX_PDEV_STATS_NUM_LEGACY_CCK_STATS     4
+#define HTT_TX_PDEV_STATS_NUM_LEGACY_OFDM_STATS    8
+#define HTT_TX_PDEV_STATS_NUM_LTF                  4
+
+#define HTT_TX_NUM_OF_SOUNDING_STATS_WORDS \
+       (HTT_TX_PDEV_STATS_NUM_BW_COUNTERS * \
+        HTT_TX_PDEV_STATS_NUM_AX_MUMIMO_USER_STATS)
+
+struct htt_tx_pdev_rate_stats_tlv {
+       u32 mac_id__word;
+       u32 tx_ldpc;
+       u32 rts_cnt;
+       /* RSSI value of last ack packet (units = dB above noise floor) */
+       u32 ack_rssi;
+
+       u32 tx_mcs[HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+
+       u32 tx_su_mcs[HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+       u32 tx_mu_mcs[HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+
+       /* element 0,1, ...7 -> NSS 1,2, ...8 */
+       u32 tx_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS];
+       /* element 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160 and 80+80 MHz */
+       u32 tx_bw[HTT_TX_PDEV_STATS_NUM_BW_COUNTERS];
+       u32 tx_stbc[HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+       u32 tx_pream[HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES];
+
+       /* Counters to track number of tx packets
+        * in each GI (400us, 800us, 1600us & 3200us) in each mcs (0-11)
+        */
+       u32 tx_gi[HTT_TX_PDEV_STATS_NUM_GI_COUNTERS][HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+
+       /* Counters to track packets in dcm mcs (MCS 0, 1, 3, 4) */
+       u32 tx_dcm[HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS];
+       /* Number of CTS-acknowledged RTS packets */
+       u32 rts_success;
+
+       /*
+        * Counters for legacy 11a and 11b transmissions.
+        *
+        * The index corresponds to:
+        *
+        * CCK: 0: 1 Mbps, 1: 2 Mbps, 2: 5.5 Mbps, 3: 11 Mbps
+        *
+        * OFDM: 0: 6 Mbps, 1: 9 Mbps, 2: 12 Mbps, 3: 18 Mbps,
+        *       4: 24 Mbps, 5: 36 Mbps, 6: 48 Mbps, 7: 54 Mbps
+        */
+       u32 tx_legacy_cck_rate[HTT_TX_PDEV_STATS_NUM_LEGACY_CCK_STATS];
+       u32 tx_legacy_ofdm_rate[HTT_TX_PDEV_STATS_NUM_LEGACY_OFDM_STATS];
+
+       u32 ac_mu_mimo_tx_ldpc;
+       u32 ax_mu_mimo_tx_ldpc;
+       u32 ofdma_tx_ldpc;
+
+       /*
+        * Counters for 11ax HE LTF selection during TX.
+        *
+        * The index corresponds to:
+        *
+        * 0: unused, 1: 1x LTF, 2: 2x LTF, 3: 4x LTF
+        */
+       u32 tx_he_ltf[HTT_TX_PDEV_STATS_NUM_LTF];
+
+       u32 ac_mu_mimo_tx_mcs[HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+       u32 ax_mu_mimo_tx_mcs[HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+       u32 ofdma_tx_mcs[HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+
+       u32 ac_mu_mimo_tx_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS];
+       u32 ax_mu_mimo_tx_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS];
+       u32 ofdma_tx_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS];
+
+       u32 ac_mu_mimo_tx_bw[HTT_TX_PDEV_STATS_NUM_BW_COUNTERS];
+       u32 ax_mu_mimo_tx_bw[HTT_TX_PDEV_STATS_NUM_BW_COUNTERS];
+       u32 ofdma_tx_bw[HTT_TX_PDEV_STATS_NUM_BW_COUNTERS];
+
+       u32 ac_mu_mimo_tx_gi[HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
+                           [HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+       u32 ax_mu_mimo_tx_gi[HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
+                           [HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+       u32 ofdma_tx_gi[HTT_TX_PDEV_STATS_NUM_GI_COUNTERS]
+                      [HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS];
+};
+
+/* == PDEV RX RATE CTRL STATS == */
+#define HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS     4
+#define HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS    8
+#define HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS        12
+#define HTT_RX_PDEV_STATS_NUM_GI_COUNTERS          4
+#define HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS         5
+#define HTT_RX_PDEV_STATS_NUM_BW_COUNTERS          4
+#define HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS      8
+#define HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES       HTT_STATS_PREAM_COUNT
+
+struct htt_rx_pdev_rate_stats_tlv {
+       u32 mac_id__word;
+       u32 nsts;
+
+       u32 rx_ldpc;
+       u32 rts_cnt;
+
+       u32 rssi_mgmt; /* units = dB above noise floor */
+       u32 rssi_data; /* units = dB above noise floor */
+       u32 rssi_comb; /* units = dB above noise floor */
+       u32 rx_mcs[HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
+       /* element 0,1, ...7 -> NSS 1,2, ...8 */
+       u32 rx_nss[HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS];
+       u32 rx_dcm[HTT_RX_PDEV_STATS_NUM_DCM_COUNTERS];
+       u32 rx_stbc[HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
+       /* element 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160 and 80+80 MHz */
+       u32 rx_bw[HTT_RX_PDEV_STATS_NUM_BW_COUNTERS];
+       u32 rx_pream[HTT_RX_PDEV_STATS_NUM_PREAMBLE_TYPES];
+       u8 rssi_chain[HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS]
+                    [HTT_RX_PDEV_STATS_NUM_BW_COUNTERS];
+                                       /* units = dB above noise floor */
+
+       /* Counters to track number of rx packets
+        * in each GI in each mcs (0-11)
+        */
+       u32 rx_gi[HTT_RX_PDEV_STATS_NUM_GI_COUNTERS][HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS];
+       s32 rssi_in_dbm; /* rx Signal Strength value in dBm unit */
+
+       u32 rx_11ax_su_ext;
+       u32 rx_11ac_mumimo;
+       u32 rx_11ax_mumimo;
+       u32 rx_11ax_ofdma;
+       u32 txbf;
+       u32 rx_legacy_cck_rate[HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS];
+       u32 rx_legacy_ofdm_rate[HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS];
+       u32 rx_active_dur_us_low;
+       u32 rx_active_dur_us_high;
+};
+
+/* == RX PDEV/SOC STATS == */
+struct htt_rx_soc_fw_stats_tlv {
+       u32 fw_reo_ring_data_msdu;
+       u32 fw_to_host_data_msdu_bcmc;
+       u32 fw_to_host_data_msdu_uc;
+       u32 ofld_remote_data_buf_recycle_cnt;
+       u32 ofld_remote_free_buf_indication_cnt;
+
+       u32 ofld_buf_to_host_data_msdu_uc;
+       u32 reo_fw_ring_to_host_data_msdu_uc;
+
+       u32 wbm_sw_ring_reap;
+       u32 wbm_forward_to_host_cnt;
+       u32 wbm_target_recycle_cnt;
+
+       u32 target_refill_ring_recycle_cnt;
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_rx_soc_fw_refill_ring_empty_tlv_v {
+       u32 refill_ring_empty_cnt[0]; /* HTT_RX_STATS_REFILL_MAX_RING */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_rx_soc_fw_refill_ring_num_refill_tlv_v {
+       u32 refill_ring_num_refill[0]; /* HTT_RX_STATS_REFILL_MAX_RING */
+};
+
+/* RXDMA error code from WBM released packets */
+enum htt_rx_rxdma_error_code_enum {
+       HTT_RX_RXDMA_OVERFLOW_ERR                           = 0,
+       HTT_RX_RXDMA_MPDU_LENGTH_ERR                        = 1,
+       HTT_RX_RXDMA_FCS_ERR                                = 2,
+       HTT_RX_RXDMA_DECRYPT_ERR                            = 3,
+       HTT_RX_RXDMA_TKIP_MIC_ERR                           = 4,
+       HTT_RX_RXDMA_UNECRYPTED_ERR                         = 5,
+       HTT_RX_RXDMA_MSDU_LEN_ERR                           = 6,
+       HTT_RX_RXDMA_MSDU_LIMIT_ERR                         = 7,
+       HTT_RX_RXDMA_WIFI_PARSE_ERR                         = 8,
+       HTT_RX_RXDMA_AMSDU_PARSE_ERR                        = 9,
+       HTT_RX_RXDMA_SA_TIMEOUT_ERR                         = 10,
+       HTT_RX_RXDMA_DA_TIMEOUT_ERR                         = 11,
+       HTT_RX_RXDMA_FLOW_TIMEOUT_ERR                       = 12,
+       HTT_RX_RXDMA_FLUSH_REQUEST                          = 13,
+       HTT_RX_RXDMA_ERR_CODE_RVSD0                         = 14,
+       HTT_RX_RXDMA_ERR_CODE_RVSD1                         = 15,
+
+       /* This MAX_ERR_CODE should not be used in any host/target messages,
+        * so that even though it is defined within a host/target interface
+        * definition header file, it isn't actually part of the host/target
+        * interface, and thus can be modified.
+        */
+       HTT_RX_RXDMA_MAX_ERR_CODE
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_rx_soc_fw_refill_ring_num_rxdma_err_tlv_v {
+       u32 rxdma_err[0]; /* HTT_RX_RXDMA_MAX_ERR_CODE */
+};
+
+/* REO error code from WBM released packets */
+enum htt_rx_reo_error_code_enum {
+       HTT_RX_REO_QUEUE_DESC_ADDR_ZERO                     = 0,
+       HTT_RX_REO_QUEUE_DESC_NOT_VALID                     = 1,
+       HTT_RX_AMPDU_IN_NON_BA                              = 2,
+       HTT_RX_NON_BA_DUPLICATE                             = 3,
+       HTT_RX_BA_DUPLICATE                                 = 4,
+       HTT_RX_REGULAR_FRAME_2K_JUMP                        = 5,
+       HTT_RX_BAR_FRAME_2K_JUMP                            = 6,
+       HTT_RX_REGULAR_FRAME_OOR                            = 7,
+       HTT_RX_BAR_FRAME_OOR                                = 8,
+       HTT_RX_BAR_FRAME_NO_BA_SESSION                      = 9,
+       HTT_RX_BAR_FRAME_SN_EQUALS_SSN                      = 10,
+       HTT_RX_PN_CHECK_FAILED                              = 11,
+       HTT_RX_2K_ERROR_HANDLING_FLAG_SET                   = 12,
+       HTT_RX_PN_ERROR_HANDLING_FLAG_SET                   = 13,
+       HTT_RX_QUEUE_DESCRIPTOR_BLOCKED_SET                 = 14,
+       HTT_RX_REO_ERR_CODE_RVSD                            = 15,
+
+       /* This MAX_ERR_CODE should not be used in any host/target messages,
+        * so that even though it is defined within a host/target interface
+        * definition header file, it isn't actually part of the host/target
+        * interface, and thus can be modified.
+        */
+       HTT_RX_REO_MAX_ERR_CODE
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_rx_soc_fw_refill_ring_num_reo_err_tlv_v {
+       u32 reo_err[0]; /* HTT_RX_REO_MAX_ERR_CODE */
+};
+
+/* == RX PDEV STATS == */
+#define HTT_STATS_SUBTYPE_MAX     16
+
+struct htt_rx_pdev_fw_stats_tlv {
+       u32 mac_id__word;
+       u32 ppdu_recvd;
+       u32 mpdu_cnt_fcs_ok;
+       u32 mpdu_cnt_fcs_err;
+       u32 tcp_msdu_cnt;
+       u32 tcp_ack_msdu_cnt;
+       u32 udp_msdu_cnt;
+       u32 other_msdu_cnt;
+       u32 fw_ring_mpdu_ind;
+       u32 fw_ring_mgmt_subtype[HTT_STATS_SUBTYPE_MAX];
+       u32 fw_ring_ctrl_subtype[HTT_STATS_SUBTYPE_MAX];
+       u32 fw_ring_mcast_data_msdu;
+       u32 fw_ring_bcast_data_msdu;
+       u32 fw_ring_ucast_data_msdu;
+       u32 fw_ring_null_data_msdu;
+       u32 fw_ring_mpdu_drop;
+       u32 ofld_local_data_ind_cnt;
+       u32 ofld_local_data_buf_recycle_cnt;
+       u32 drx_local_data_ind_cnt;
+       u32 drx_local_data_buf_recycle_cnt;
+       u32 local_nondata_ind_cnt;
+       u32 local_nondata_buf_recycle_cnt;
+
+       u32 fw_status_buf_ring_refill_cnt;
+       u32 fw_status_buf_ring_empty_cnt;
+       u32 fw_pkt_buf_ring_refill_cnt;
+       u32 fw_pkt_buf_ring_empty_cnt;
+       u32 fw_link_buf_ring_refill_cnt;
+       u32 fw_link_buf_ring_empty_cnt;
+
+       u32 host_pkt_buf_ring_refill_cnt;
+       u32 host_pkt_buf_ring_empty_cnt;
+       u32 mon_pkt_buf_ring_refill_cnt;
+       u32 mon_pkt_buf_ring_empty_cnt;
+       u32 mon_status_buf_ring_refill_cnt;
+       u32 mon_status_buf_ring_empty_cnt;
+       u32 mon_desc_buf_ring_refill_cnt;
+       u32 mon_desc_buf_ring_empty_cnt;
+       u32 mon_dest_ring_update_cnt;
+       u32 mon_dest_ring_full_cnt;
+
+       u32 rx_suspend_cnt;
+       u32 rx_suspend_fail_cnt;
+       u32 rx_resume_cnt;
+       u32 rx_resume_fail_cnt;
+       u32 rx_ring_switch_cnt;
+       u32 rx_ring_restore_cnt;
+       u32 rx_flush_cnt;
+       u32 rx_recovery_reset_cnt;
+};
+
+#define HTT_STATS_PHY_ERR_MAX 43
+
+struct htt_rx_pdev_fw_stats_phy_err_tlv {
+       u32 mac_id__word;
+       u32 total_phy_err_cnt;
+       /* Counts of different types of phy errs
+        * The mapping of PHY error types to phy_err array elements is HW dependent.
+        * The only currently-supported mapping is shown below:
+        *
+        * 0 phyrx_err_phy_off Reception aborted due to receiving a PHY_OFF TLV
+        * 1 phyrx_err_synth_off
+        * 2 phyrx_err_ofdma_timing
+        * 3 phyrx_err_ofdma_signal_parity
+        * 4 phyrx_err_ofdma_rate_illegal
+        * 5 phyrx_err_ofdma_length_illegal
+        * 6 phyrx_err_ofdma_restart
+        * 7 phyrx_err_ofdma_service
+        * 8 phyrx_err_ppdu_ofdma_power_drop
+        * 9 phyrx_err_cck_blokker
+        * 10 phyrx_err_cck_timing
+        * 11 phyrx_err_cck_header_crc
+        * 12 phyrx_err_cck_rate_illegal
+        * 13 phyrx_err_cck_length_illegal
+        * 14 phyrx_err_cck_restart
+        * 15 phyrx_err_cck_service
+        * 16 phyrx_err_cck_power_drop
+        * 17 phyrx_err_ht_crc_err
+        * 18 phyrx_err_ht_length_illegal
+        * 19 phyrx_err_ht_rate_illegal
+        * 20 phyrx_err_ht_zlf
+        * 21 phyrx_err_false_radar_ext
+        * 22 phyrx_err_green_field
+        * 23 phyrx_err_bw_gt_dyn_bw
+        * 24 phyrx_err_leg_ht_mismatch
+        * 25 phyrx_err_vht_crc_error
+        * 26 phyrx_err_vht_siga_unsupported
+        * 27 phyrx_err_vht_lsig_len_invalid
+        * 28 phyrx_err_vht_ndp_or_zlf
+        * 29 phyrx_err_vht_nsym_lt_zero
+        * 30 phyrx_err_vht_rx_extra_symbol_mismatch
+        * 31 phyrx_err_vht_rx_skip_group_id0
+        * 32 phyrx_err_vht_rx_skip_group_id1to62
+        * 33 phyrx_err_vht_rx_skip_group_id63
+        * 34 phyrx_err_ofdm_ldpc_decoder_disabled
+        * 35 phyrx_err_defer_nap
+        * 36 phyrx_err_fdomain_timeout
+        * 37 phyrx_err_lsig_rel_check
+        * 38 phyrx_err_bt_collision
+        * 39 phyrx_err_unsupported_mu_feedback
+        * 40 phyrx_err_ppdu_tx_interrupt_rx
+        * 41 phyrx_err_unsupported_cbf
+        * 42 phyrx_err_other
+        */
+       u32 phy_err[HTT_STATS_PHY_ERR_MAX];
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_rx_pdev_fw_ring_mpdu_err_tlv_v {
+       /* Num error MPDU for each RxDMA error type  */
+       u32 fw_ring_mpdu_err[0]; /* HTT_RX_STATS_RXDMA_MAX_ERR */
+};
+
+/* NOTE: Variable length TLV, use length spec to infer array size */
+struct htt_rx_pdev_fw_mpdu_drop_tlv_v {
+       /* Num MPDU dropped  */
+       u32 fw_mpdu_drop[0]; /* HTT_RX_STATS_FW_DROP_REASON_MAX */
+};
+
+#define HTT_PDEV_CCA_STATS_TX_FRAME_INFO_PRESENT               (0x1)
+#define HTT_PDEV_CCA_STATS_RX_FRAME_INFO_PRESENT               (0x2)
+#define HTT_PDEV_CCA_STATS_RX_CLEAR_INFO_PRESENT               (0x4)
+#define HTT_PDEV_CCA_STATS_MY_RX_FRAME_INFO_PRESENT            (0x8)
+#define HTT_PDEV_CCA_STATS_USEC_CNT_INFO_PRESENT              (0x10)
+#define HTT_PDEV_CCA_STATS_MED_RX_IDLE_INFO_PRESENT           (0x20)
+#define HTT_PDEV_CCA_STATS_MED_TX_IDLE_GLOBAL_INFO_PRESENT    (0x40)
+#define HTT_PDEV_CCA_STATS_CCA_OBBS_USEC_INFO_PRESENT         (0x80)
+
+struct htt_pdev_stats_cca_counters_tlv {
+       /* Below values are obtained from the HW Cycles counter registers */
+       u32 tx_frame_usec;
+       u32 rx_frame_usec;
+       u32 rx_clear_usec;
+       u32 my_rx_frame_usec;
+       u32 usec_cnt;
+       u32 med_rx_idle_usec;
+       u32 med_tx_idle_global_usec;
+       u32 cca_obss_usec;
+};
+
+struct htt_pdev_cca_stats_hist_v1_tlv {
+       u32    chan_num;
+       /* num of CCA records (Num of htt_pdev_stats_cca_counters_tlv)*/
+       u32    num_records;
+       u32    valid_cca_counters_bitmap;
+       u32    collection_interval;
+
+       /* This will be followed by an array which contains the CCA stats
+        * collected in the last N intervals,
+        * if the indication is for last N intervals CCA stats.
+        * Then the pdev_cca_stats[0] element contains the oldest CCA stats
+        * and pdev_cca_stats[N-1] will have the most recent CCA stats.
+        * htt_pdev_stats_cca_counters_tlv cca_hist_tlv[1];
+        */
+};
+
+struct htt_pdev_stats_twt_session_tlv {
+       u32 vdev_id;
+       struct htt_mac_addr peer_mac;
+       u32 flow_id_flags;
+
+       /* TWT_DIALOG_ID_UNAVAILABLE is used
+        * when TWT session is not initiated by host
+        */
+       u32 dialog_id;
+       u32 wake_dura_us;
+       u32 wake_intvl_us;
+       u32 sp_offset_us;
+};
+
+struct htt_pdev_stats_twt_sessions_tlv {
+       u32 pdev_id;
+       u32 num_sessions;
+       struct htt_pdev_stats_twt_session_tlv twt_session[0];
+};
+
+enum htt_rx_reo_resource_sample_id_enum {
+       /* Global link descriptor queued in REO */
+       HTT_RX_REO_RESOURCE_GLOBAL_LINK_DESC_COUNT_0           = 0,
+       HTT_RX_REO_RESOURCE_GLOBAL_LINK_DESC_COUNT_1           = 1,
+       HTT_RX_REO_RESOURCE_GLOBAL_LINK_DESC_COUNT_2           = 2,
+       /*Number of queue descriptors of this aging group */
+       HTT_RX_REO_RESOURCE_BUFFERS_USED_AC0                   = 3,
+       HTT_RX_REO_RESOURCE_BUFFERS_USED_AC1                   = 4,
+       HTT_RX_REO_RESOURCE_BUFFERS_USED_AC2                   = 5,
+       HTT_RX_REO_RESOURCE_BUFFERS_USED_AC3                   = 6,
+       /* Total number of MSDUs buffered in AC */
+       HTT_RX_REO_RESOURCE_AGING_NUM_QUEUES_AC0               = 7,
+       HTT_RX_REO_RESOURCE_AGING_NUM_QUEUES_AC1               = 8,
+       HTT_RX_REO_RESOURCE_AGING_NUM_QUEUES_AC2               = 9,
+       HTT_RX_REO_RESOURCE_AGING_NUM_QUEUES_AC3               = 10,
+
+       HTT_RX_REO_RESOURCE_STATS_MAX                          = 16
+};
+
+struct htt_rx_reo_resource_stats_tlv_v {
+       /* Variable based on the Number of records. HTT_RX_REO_RESOURCE_STATS_MAX */
+       u32 sample_id;
+       u32 total_max;
+       u32 total_avg;
+       u32 total_sample;
+       u32 non_zeros_avg;
+       u32 non_zeros_sample;
+       u32 last_non_zeros_max;
+       u32 last_non_zeros_min;
+       u32 last_non_zeros_avg;
+       u32 last_non_zeros_sample;
+};
+
+/* == TX SOUNDING STATS == */
+
+enum htt_txbf_sound_steer_modes {
+       HTT_IMPLICIT_TXBF_STEER_STATS                = 0,
+       HTT_EXPLICIT_TXBF_SU_SIFS_STEER_STATS        = 1,
+       HTT_EXPLICIT_TXBF_SU_RBO_STEER_STATS         = 2,
+       HTT_EXPLICIT_TXBF_MU_SIFS_STEER_STATS        = 3,
+       HTT_EXPLICIT_TXBF_MU_RBO_STEER_STATS         = 4,
+       HTT_TXBF_MAX_NUM_OF_MODES                    = 5
+};
+
+enum htt_stats_sounding_tx_mode {
+       HTT_TX_AC_SOUNDING_MODE                      = 0,
+       HTT_TX_AX_SOUNDING_MODE                      = 1,
+};
+
+struct htt_tx_sounding_stats_tlv {
+       u32 tx_sounding_mode; /* HTT_TX_XX_SOUNDING_MODE */
+       /* Counts number of soundings for all steering modes in each bw */
+       u32 cbf_20[HTT_TXBF_MAX_NUM_OF_MODES];
+       u32 cbf_40[HTT_TXBF_MAX_NUM_OF_MODES];
+       u32 cbf_80[HTT_TXBF_MAX_NUM_OF_MODES];
+       u32 cbf_160[HTT_TXBF_MAX_NUM_OF_MODES];
+       /*
+        * The sounding array is a 2-D array stored as an 1-D array of
+        * u32. The stats for a particular user/bw combination is
+        * referenced with the following:
+        *
+        *          sounding[(user* max_bw) + bw]
+        *
+        * ... where max_bw == 4 for 160mhz
+        */
+       u32 sounding[HTT_TX_NUM_OF_SOUNDING_STATS_WORDS];
+};
+
+struct htt_pdev_obss_pd_stats_tlv {
+       u32        num_obss_tx_ppdu_success;
+       u32        num_obss_tx_ppdu_failure;
+};
+
+void ath11k_debug_htt_stats_init(struct ath11k *ar);
+#endif
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/vmalloc.h>
+
+#include "core.h"
+#include "peer.h"
+#include "debug.h"
+
+void
+ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
+                                   struct ath11k_per_peer_tx_stats *peer_stats,
+                                   u8 legacy_rate_idx)
+{
+       struct rate_info *txrate = &arsta->txrate;
+       struct ath11k_htt_tx_stats *tx_stats;
+       int gi, mcs, bw, nss;
+
+       if (!arsta->tx_stats)
+               return;
+
+       tx_stats = arsta->tx_stats;
+       gi = FIELD_GET(RATE_INFO_FLAGS_SHORT_GI, arsta->txrate.flags);
+       mcs = txrate->mcs;
+       bw = txrate->bw;
+       nss = txrate->nss - 1;
+
+#define STATS_OP_FMT(name) tx_stats->stats[ATH11K_STATS_TYPE_##name]
+
+       if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
+               STATS_OP_FMT(SUCC).he[0][mcs] += peer_stats->succ_bytes;
+               STATS_OP_FMT(SUCC).he[1][mcs] += peer_stats->succ_pkts;
+               STATS_OP_FMT(FAIL).he[0][mcs] += peer_stats->failed_bytes;
+               STATS_OP_FMT(FAIL).he[1][mcs] += peer_stats->failed_pkts;
+               STATS_OP_FMT(RETRY).he[0][mcs] += peer_stats->retry_bytes;
+               STATS_OP_FMT(RETRY).he[1][mcs] += peer_stats->retry_pkts;
+       } else if (txrate->flags & RATE_INFO_FLAGS_VHT_MCS) {
+               STATS_OP_FMT(SUCC).vht[0][mcs] += peer_stats->succ_bytes;
+               STATS_OP_FMT(SUCC).vht[1][mcs] += peer_stats->succ_pkts;
+               STATS_OP_FMT(FAIL).vht[0][mcs] += peer_stats->failed_bytes;
+               STATS_OP_FMT(FAIL).vht[1][mcs] += peer_stats->failed_pkts;
+               STATS_OP_FMT(RETRY).vht[0][mcs] += peer_stats->retry_bytes;
+               STATS_OP_FMT(RETRY).vht[1][mcs] += peer_stats->retry_pkts;
+       } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
+               STATS_OP_FMT(SUCC).ht[0][mcs] += peer_stats->succ_bytes;
+               STATS_OP_FMT(SUCC).ht[1][mcs] += peer_stats->succ_pkts;
+               STATS_OP_FMT(FAIL).ht[0][mcs] += peer_stats->failed_bytes;
+               STATS_OP_FMT(FAIL).ht[1][mcs] += peer_stats->failed_pkts;
+               STATS_OP_FMT(RETRY).ht[0][mcs] += peer_stats->retry_bytes;
+               STATS_OP_FMT(RETRY).ht[1][mcs] += peer_stats->retry_pkts;
+       } else {
+               mcs = legacy_rate_idx;
+
+               STATS_OP_FMT(SUCC).legacy[0][mcs] += peer_stats->succ_bytes;
+               STATS_OP_FMT(SUCC).legacy[1][mcs] += peer_stats->succ_pkts;
+               STATS_OP_FMT(FAIL).legacy[0][mcs] += peer_stats->failed_bytes;
+               STATS_OP_FMT(FAIL).legacy[1][mcs] += peer_stats->failed_pkts;
+               STATS_OP_FMT(RETRY).legacy[0][mcs] += peer_stats->retry_bytes;
+               STATS_OP_FMT(RETRY).legacy[1][mcs] += peer_stats->retry_pkts;
+       }
+
+       if (peer_stats->is_ampdu) {
+               tx_stats->ba_fails += peer_stats->ba_fails;
+
+               if (txrate->flags & RATE_INFO_FLAGS_HE_MCS) {
+                       STATS_OP_FMT(AMPDU).he[0][mcs] +=
+                       peer_stats->succ_bytes + peer_stats->retry_bytes;
+                       STATS_OP_FMT(AMPDU).he[1][mcs] +=
+                       peer_stats->succ_pkts + peer_stats->retry_pkts;
+               } else if (txrate->flags & RATE_INFO_FLAGS_MCS) {
+                       STATS_OP_FMT(AMPDU).ht[0][mcs] +=
+                       peer_stats->succ_bytes + peer_stats->retry_bytes;
+                       STATS_OP_FMT(AMPDU).ht[1][mcs] +=
+                       peer_stats->succ_pkts + peer_stats->retry_pkts;
+               } else {
+                       STATS_OP_FMT(AMPDU).vht[0][mcs] +=
+                       peer_stats->succ_bytes + peer_stats->retry_bytes;
+                       STATS_OP_FMT(AMPDU).vht[1][mcs] +=
+                       peer_stats->succ_pkts + peer_stats->retry_pkts;
+               }
+               STATS_OP_FMT(AMPDU).bw[0][bw] +=
+                       peer_stats->succ_bytes + peer_stats->retry_bytes;
+               STATS_OP_FMT(AMPDU).nss[0][nss] +=
+                       peer_stats->succ_bytes + peer_stats->retry_bytes;
+               STATS_OP_FMT(AMPDU).gi[0][gi] +=
+                       peer_stats->succ_bytes + peer_stats->retry_bytes;
+               STATS_OP_FMT(AMPDU).bw[1][bw] +=
+                       peer_stats->succ_pkts + peer_stats->retry_pkts;
+               STATS_OP_FMT(AMPDU).nss[1][nss] +=
+                       peer_stats->succ_pkts + peer_stats->retry_pkts;
+               STATS_OP_FMT(AMPDU).gi[1][gi] +=
+                       peer_stats->succ_pkts + peer_stats->retry_pkts;
+       } else {
+               tx_stats->ack_fails += peer_stats->ba_fails;
+       }
+
+       STATS_OP_FMT(SUCC).bw[0][bw] += peer_stats->succ_bytes;
+       STATS_OP_FMT(SUCC).nss[0][nss] += peer_stats->succ_bytes;
+       STATS_OP_FMT(SUCC).gi[0][gi] += peer_stats->succ_bytes;
+
+       STATS_OP_FMT(SUCC).bw[1][bw] += peer_stats->succ_pkts;
+       STATS_OP_FMT(SUCC).nss[1][nss] += peer_stats->succ_pkts;
+       STATS_OP_FMT(SUCC).gi[1][gi] += peer_stats->succ_pkts;
+
+       STATS_OP_FMT(FAIL).bw[0][bw] += peer_stats->failed_bytes;
+       STATS_OP_FMT(FAIL).nss[0][nss] += peer_stats->failed_bytes;
+       STATS_OP_FMT(FAIL).gi[0][gi] += peer_stats->failed_bytes;
+
+       STATS_OP_FMT(FAIL).bw[1][bw] += peer_stats->failed_pkts;
+       STATS_OP_FMT(FAIL).nss[1][nss] += peer_stats->failed_pkts;
+       STATS_OP_FMT(FAIL).gi[1][gi] += peer_stats->failed_pkts;
+
+       STATS_OP_FMT(RETRY).bw[0][bw] += peer_stats->retry_bytes;
+       STATS_OP_FMT(RETRY).nss[0][nss] += peer_stats->retry_bytes;
+       STATS_OP_FMT(RETRY).gi[0][gi] += peer_stats->retry_bytes;
+
+       STATS_OP_FMT(RETRY).bw[1][bw] += peer_stats->retry_pkts;
+       STATS_OP_FMT(RETRY).nss[1][nss] += peer_stats->retry_pkts;
+       STATS_OP_FMT(RETRY).gi[1][gi] += peer_stats->retry_pkts;
+
+       tx_stats->tx_duration += peer_stats->duration;
+}
+
+void ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar,
+                                              struct sk_buff *msdu,
+                                              struct hal_tx_status *ts)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
+       struct ath11k_peer *peer;
+       struct ath11k_sta *arsta;
+       struct ieee80211_sta *sta;
+       u16 rate;
+       u8 rate_idx;
+       int ret;
+
+       rcu_read_lock();
+       spin_lock_bh(&ab->base_lock);
+       peer = ath11k_peer_find_by_id(ab, ts->peer_id);
+       if (!peer || !peer->sta) {
+               ath11k_warn(ab, "failed to find the peer\n");
+               spin_unlock_bh(&ab->base_lock);
+               rcu_read_unlock();
+               return;
+       }
+
+       sta = peer->sta;
+       arsta = (struct ath11k_sta *)sta->drv_priv;
+
+       memset(&arsta->txrate, 0, sizeof(arsta->txrate));
+
+       if (ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A ||
+           ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) {
+               ret = ath11k_mac_hw_ratecode_to_legacy_rate(ts->mcs,
+                                                           ts->pkt_type,
+                                                           &rate_idx,
+                                                           &rate);
+               if (ret < 0) {
+                       spin_unlock_bh(&ab->base_lock);
+                       rcu_read_unlock();
+                       return;
+               }
+               arsta->txrate.legacy = rate;
+       } else if (ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) {
+               if (ts->mcs > 7) {
+                       ath11k_warn(ab, "Invalid HT mcs index %d\n", ts->mcs);
+                       spin_unlock_bh(&ab->base_lock);
+                       rcu_read_unlock();
+                       return;
+               }
+
+               arsta->txrate.mcs = ts->mcs + 8 * (arsta->last_txrate.nss - 1);
+               arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
+               if (ts->sgi)
+                       arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+       } else if (ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) {
+               if (ts->mcs > 9) {
+                       ath11k_warn(ab, "Invalid VHT mcs index %d\n", ts->mcs);
+                       spin_unlock_bh(&ab->base_lock);
+                       rcu_read_unlock();
+                       return;
+               }
+
+               arsta->txrate.mcs = ts->mcs;
+               arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
+               if (ts->sgi)
+                       arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+       } else {
+               /*TODO: update HE rates */
+       }
+
+       arsta->txrate.nss = arsta->last_txrate.nss;
+       arsta->txrate.bw = ts->bw;
+
+       ath11k_accumulate_per_peer_tx_stats(arsta, peer_stats, rate_idx);
+       spin_unlock_bh(&ab->base_lock);
+       rcu_read_unlock();
+}
+
+static ssize_t ath11k_dbg_sta_dump_tx_stats(struct file *file,
+                                           char __user *user_buf,
+                                           size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       struct ath11k_htt_data_stats *stats;
+       static const char *str_name[ATH11K_STATS_TYPE_MAX] = {"succ", "fail",
+                                                             "retry", "ampdu"};
+       static const char *str[ATH11K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
+       int len = 0, i, j, k, retval = 0;
+       const int size = 2 * 4096;
+       char *buf;
+
+       buf = kzalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       mutex_lock(&ar->conf_mutex);
+
+       spin_lock_bh(&ar->data_lock);
+       for (k = 0; k < ATH11K_STATS_TYPE_MAX; k++) {
+               for (j = 0; j < ATH11K_COUNTER_TYPE_MAX; j++) {
+                       stats = &arsta->tx_stats->stats[k];
+                       len += scnprintf(buf + len, size - len, "%s_%s\n",
+                                        str_name[k],
+                                        str[j]);
+                       len += scnprintf(buf + len, size - len,
+                                        " HE MCS %s\n",
+                                        str[j]);
+                       for (i = 0; i < ATH11K_HE_MCS_NUM; i++)
+                               len += scnprintf(buf + len, size - len,
+                                                "  %llu ",
+                                                stats->he[j][i]);
+                       len += scnprintf(buf + len, size - len, "\n");
+                       len += scnprintf(buf + len, size - len,
+                                        " VHT MCS %s\n",
+                                        str[j]);
+                       for (i = 0; i < ATH11K_VHT_MCS_NUM; i++)
+                               len += scnprintf(buf + len, size - len,
+                                                "  %llu ",
+                                                stats->vht[j][i]);
+                       len += scnprintf(buf + len, size - len, "\n");
+                       len += scnprintf(buf + len, size - len, " HT MCS %s\n",
+                                        str[j]);
+                       for (i = 0; i < ATH11K_HT_MCS_NUM; i++)
+                               len += scnprintf(buf + len, size - len,
+                                                "  %llu ", stats->ht[j][i]);
+                       len += scnprintf(buf + len, size - len, "\n");
+                       len += scnprintf(buf + len, size - len,
+                                       " BW %s (20,40,80,160 MHz)\n", str[j]);
+                       len += scnprintf(buf + len, size - len,
+                                        "  %llu %llu %llu %llu\n",
+                                        stats->bw[j][0], stats->bw[j][1],
+                                        stats->bw[j][2], stats->bw[j][3]);
+                       len += scnprintf(buf + len, size - len,
+                                        " NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
+                       len += scnprintf(buf + len, size - len,
+                                        "  %llu %llu %llu %llu\n",
+                                        stats->nss[j][0], stats->nss[j][1],
+                                        stats->nss[j][2], stats->nss[j][3]);
+                       len += scnprintf(buf + len, size - len,
+                                        " GI %s (0.4us,0.8us,1.6us,3.2us)\n",
+                                        str[j]);
+                       len += scnprintf(buf + len, size - len,
+                                        "  %llu %llu %llu %llu\n",
+                                        stats->gi[j][0], stats->gi[j][1],
+                                        stats->gi[j][2], stats->gi[j][3]);
+                       len += scnprintf(buf + len, size - len,
+                                        " legacy rate %s (1,2 ... Mbps)\n  ",
+                                        str[j]);
+                       for (i = 0; i < ATH11K_LEGACY_NUM; i++)
+                               len += scnprintf(buf + len, size - len, "%llu ",
+                                                stats->legacy[j][i]);
+                       len += scnprintf(buf + len, size - len, "\n");
+               }
+       }
+
+       len += scnprintf(buf + len, size - len,
+                        "\nTX duration\n %llu usecs\n",
+                        arsta->tx_stats->tx_duration);
+       len += scnprintf(buf + len, size - len,
+                       "BA fails\n %llu\n", arsta->tx_stats->ba_fails);
+       len += scnprintf(buf + len, size - len,
+                       "ack fails\n %llu\n", arsta->tx_stats->ack_fails);
+       spin_unlock_bh(&ar->data_lock);
+
+       if (len > size)
+               len = size;
+       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+
+       mutex_unlock(&ar->conf_mutex);
+       return retval;
+}
+
+static const struct file_operations fops_tx_stats = {
+       .read = ath11k_dbg_sta_dump_tx_stats,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_dbg_sta_dump_rx_stats(struct file *file,
+                                           char __user *user_buf,
+                                           size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
+       int len = 0, i, retval = 0;
+       const int size = 4096;
+       char *buf;
+
+       if (!rx_stats)
+               return -ENOENT;
+
+       buf = kzalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       mutex_lock(&ar->conf_mutex);
+       spin_lock_bh(&ar->ab->base_lock);
+
+       len += scnprintf(buf + len, size - len, "RX peer stats:\n");
+       len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
+                        rx_stats->num_msdu);
+       len += scnprintf(buf + len, size - len, "Num of MSDUs with TCP L4: %llu\n",
+                        rx_stats->tcp_msdu_count);
+       len += scnprintf(buf + len, size - len, "Num of MSDUs with UDP L4: %llu\n",
+                        rx_stats->udp_msdu_count);
+       len += scnprintf(buf + len, size - len, "Num of MSDUs part of AMPDU: %llu\n",
+                        rx_stats->ampdu_msdu_count);
+       len += scnprintf(buf + len, size - len, "Num of MSDUs not part of AMPDU: %llu\n",
+                        rx_stats->non_ampdu_msdu_count);
+       len += scnprintf(buf + len, size - len, "Num of MSDUs using STBC: %llu\n",
+                        rx_stats->stbc_count);
+       len += scnprintf(buf + len, size - len, "Num of MSDUs beamformed: %llu\n",
+                        rx_stats->beamformed_count);
+       len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS ok: %llu\n",
+                        rx_stats->num_mpdu_fcs_ok);
+       len += scnprintf(buf + len, size - len, "Num of MPDUs with FCS error: %llu\n",
+                        rx_stats->num_mpdu_fcs_err);
+       len += scnprintf(buf + len, size - len,
+                        "GI: 0.8us %llu 0.4us %llu 1.6us %llu 3.2us %llu\n",
+                        rx_stats->gi_count[0], rx_stats->gi_count[1],
+                        rx_stats->gi_count[2], rx_stats->gi_count[3]);
+       len += scnprintf(buf + len, size - len,
+                        "BW: 20Mhz %llu 40Mhz %llu 80Mhz %llu 160Mhz %llu\n",
+                        rx_stats->bw_count[0], rx_stats->bw_count[1],
+                        rx_stats->bw_count[2], rx_stats->bw_count[3]);
+       len += scnprintf(buf + len, size - len, "BCC %llu LDPC %llu\n",
+                        rx_stats->coding_count[0], rx_stats->coding_count[1]);
+       len += scnprintf(buf + len, size - len,
+                        "preamble: 11A %llu 11B %llu 11N %llu 11AC %llu 11AX %llu\n",
+                        rx_stats->pream_cnt[0], rx_stats->pream_cnt[1],
+                        rx_stats->pream_cnt[2], rx_stats->pream_cnt[3],
+                        rx_stats->pream_cnt[4]);
+       len += scnprintf(buf + len, size - len,
+                        "reception type: SU %llu MU_MIMO %llu MU_OFDMA %llu MU_OFDMA_MIMO %llu\n",
+                        rx_stats->reception_type[0], rx_stats->reception_type[1],
+                        rx_stats->reception_type[2], rx_stats->reception_type[3]);
+       len += scnprintf(buf + len, size - len, "TID(0-15) Legacy TID(16):");
+       for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
+               len += scnprintf(buf + len, size - len, "%llu ", rx_stats->tid_count[i]);
+       len += scnprintf(buf + len, size - len, "\nMCS(0-11) Legacy MCS(12):");
+       for (i = 0; i < HAL_RX_MAX_MCS + 1; i++)
+               len += scnprintf(buf + len, size - len, "%llu ", rx_stats->mcs_count[i]);
+       len += scnprintf(buf + len, size - len, "\nNSS(1-8):");
+       for (i = 0; i < HAL_RX_MAX_NSS; i++)
+               len += scnprintf(buf + len, size - len, "%llu ", rx_stats->nss_count[i]);
+       len += scnprintf(buf + len, size - len, "\nRX Duration:%llu ",
+                        rx_stats->rx_duration);
+       len += scnprintf(buf + len, size - len, "\n");
+
+       spin_unlock_bh(&ar->ab->base_lock);
+
+       if (len > size)
+               len = size;
+       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+
+       mutex_unlock(&ar->conf_mutex);
+       return retval;
+}
+
+static const struct file_operations fops_rx_stats = {
+       .read = ath11k_dbg_sta_dump_rx_stats,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static int
+ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
+{
+       struct ieee80211_sta *sta = inode->i_private;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       struct debug_htt_stats_req *stats_req;
+       int ret;
+
+       stats_req = vzalloc(sizeof(*stats_req) + ATH11K_HTT_STATS_BUF_SIZE);
+       if (!stats_req)
+               return -ENOMEM;
+
+       mutex_lock(&ar->conf_mutex);
+       ar->debug.htt_stats.stats_req = stats_req;
+       stats_req->type = ATH11K_DBG_HTT_EXT_STATS_PEER_INFO;
+       memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
+       ret = ath11k_dbg_htt_stats_req(ar);
+       mutex_unlock(&ar->conf_mutex);
+       if (ret < 0)
+               goto out;
+
+       file->private_data = stats_req;
+       return 0;
+out:
+       vfree(stats_req);
+       return ret;
+}
+
+static int
+ath11k_dbg_sta_release_htt_peer_stats(struct inode *inode, struct file *file)
+{
+       vfree(file->private_data);
+       return 0;
+}
+
+static ssize_t ath11k_dbg_sta_read_htt_peer_stats(struct file *file,
+                                                 char __user *user_buf,
+                                                 size_t count, loff_t *ppos)
+{
+       struct debug_htt_stats_req *stats_req = file->private_data;
+       char *buf;
+       u32 length = 0;
+
+       buf = stats_req->buf;
+       length = min_t(u32, stats_req->buf_len, ATH11K_HTT_STATS_BUF_SIZE);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, length);
+}
+
+static const struct file_operations fops_htt_peer_stats = {
+       .open = ath11k_dbg_sta_open_htt_peer_stats,
+       .release = ath11k_dbg_sta_release_htt_peer_stats,
+       .read = ath11k_dbg_sta_read_htt_peer_stats,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath11k_dbg_sta_write_peer_pktlog(struct file *file,
+                                               const char __user *buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       int ret, enable;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH11K_STATE_ON) {
+               ret = -ENETDOWN;
+               goto out;
+       }
+
+       ret = kstrtoint_from_user(buf, count, 0, &enable);
+       if (ret)
+               goto out;
+
+       ar->debug.pktlog_peer_valid = enable;
+       memcpy(ar->debug.pktlog_peer_addr, sta->addr, ETH_ALEN);
+
+       /* Send peer based pktlog enable/disable */
+       ret = ath11k_wmi_pdev_peer_pktlog_filter(ar, sta->addr, enable);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set peer pktlog filter %pM: %d\n",
+                           sta->addr, ret);
+               goto out;
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "peer pktlog filter set to %d\n",
+                  enable);
+       ret = count;
+
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file,
+                                              char __user *ubuf,
+                                              size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arsta->arvif->ar;
+       char buf[32] = {0};
+       int len;
+
+       mutex_lock(&ar->conf_mutex);
+       len = scnprintf(buf, sizeof(buf), "%08x %pM\n",
+                       ar->debug.pktlog_peer_valid,
+                       ar->debug.pktlog_peer_addr);
+       mutex_unlock(&ar->conf_mutex);
+
+       return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_peer_pktlog = {
+       .write = ath11k_dbg_sta_write_peer_pktlog,
+       .read = ath11k_dbg_sta_read_peer_pktlog,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                           struct ieee80211_sta *sta, struct dentry *dir)
+{
+       struct ath11k *ar = hw->priv;
+
+       if (ath11k_debug_is_extd_tx_stats_enabled(ar))
+               debugfs_create_file("tx_stats", 0400, dir, sta,
+                                   &fops_tx_stats);
+       if (ath11k_debug_is_extd_rx_stats_enabled(ar))
+               debugfs_create_file("rx_stats", 0400, dir, sta,
+                                   &fops_rx_stats);
+
+       debugfs_create_file("htt_peer_stats", 0400, dir, sta,
+                           &fops_htt_peer_stats);
+
+       debugfs_create_file("peer_pktlog", 0644, dir, sta,
+                           &fops_peer_pktlog);
+}
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/kfifo.h>
+#include "core.h"
+#include "dp_tx.h"
+#include "hal_tx.h"
+#include "debug.h"
+#include "dp_rx.h"
+#include "peer.h"
+
+static void ath11k_dp_htt_htc_tx_complete(struct ath11k_base *ab,
+                                         struct sk_buff *skb)
+{
+       dev_kfree_skb_any(skb);
+}
+
+void ath11k_dp_peer_cleanup(struct ath11k *ar, int vdev_id, const u8 *addr)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_peer *peer;
+
+       /* TODO: Any other peer specific DP cleanup */
+
+       spin_lock_bh(&ab->base_lock);
+       peer = ath11k_peer_find(ab, vdev_id, addr);
+       if (!peer) {
+               ath11k_warn(ab, "failed to lookup peer %pM on vdev %d\n",
+                           addr, vdev_id);
+               spin_unlock_bh(&ab->base_lock);
+               return;
+       }
+
+       ath11k_peer_rx_tid_cleanup(ar, peer);
+       spin_unlock_bh(&ab->base_lock);
+}
+
+int ath11k_dp_peer_setup(struct ath11k *ar, int vdev_id, const u8 *addr)
+{
+       struct ath11k_base *ab = ar->ab;
+       u32 reo_dest;
+       int ret;
+
+       /* NOTE: reo_dest ring id starts from 1 unlike mac_id which starts from 0 */
+       reo_dest = ar->dp.mac_id + 1;
+       ret = ath11k_wmi_set_peer_param(ar, addr, vdev_id,
+                                       WMI_PEER_SET_DEFAULT_ROUTING,
+                                       DP_RX_HASH_ENABLE | (reo_dest << 1));
+
+       if (ret) {
+               ath11k_warn(ab, "failed to set default routing %d peer :%pM vdev_id :%d\n",
+                           ret, addr, vdev_id);
+               return ret;
+       }
+
+       ret = ath11k_peer_rx_tid_setup(ar, addr, vdev_id,
+                                      HAL_DESC_REO_NON_QOS_TID, 1, 0);
+       if (ret) {
+               ath11k_warn(ab, "failed to setup rxd tid queue for non-qos tid %d\n",
+                           ret);
+               return ret;
+       }
+
+       ret = ath11k_peer_rx_tid_setup(ar, addr, vdev_id, 0, 1, 0);
+       if (ret) {
+               ath11k_warn(ab, "failed to setup rxd tid queue for tid 0 %d\n",
+                           ret);
+               return ret;
+       }
+
+       /* TODO: Setup other peer specific resource used in data path */
+
+       return 0;
+}
+
+void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring)
+{
+       if (!ring->vaddr_unaligned)
+               return;
+
+       dma_free_coherent(ab->dev, ring->size, ring->vaddr_unaligned,
+                         ring->paddr_unaligned);
+
+       ring->vaddr_unaligned = NULL;
+}
+
+int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
+                        enum hal_ring_type type, int ring_num,
+                        int mac_id, int num_entries)
+{
+       struct hal_srng_params params = { 0 };
+       int entry_sz = ath11k_hal_srng_get_entrysize(type);
+       int max_entries = ath11k_hal_srng_get_max_entries(type);
+       int ret;
+
+       if (max_entries < 0 || entry_sz < 0)
+               return -EINVAL;
+
+       if (num_entries > max_entries)
+               num_entries = max_entries;
+
+       ring->size = (num_entries * entry_sz) + HAL_RING_BASE_ALIGN - 1;
+       ring->vaddr_unaligned = dma_alloc_coherent(ab->dev, ring->size,
+                                                  &ring->paddr_unaligned,
+                                                  GFP_KERNEL);
+       if (!ring->vaddr_unaligned)
+               return -ENOMEM;
+
+       ring->vaddr = PTR_ALIGN(ring->vaddr_unaligned, HAL_RING_BASE_ALIGN);
+       ring->paddr = ring->paddr_unaligned + ((unsigned long)ring->vaddr -
+                     (unsigned long)ring->vaddr_unaligned);
+
+       params.ring_base_vaddr = ring->vaddr;
+       params.ring_base_paddr = ring->paddr;
+       params.num_entries = num_entries;
+
+       switch (type) {
+       case HAL_REO_DST:
+               params.intr_batch_cntr_thres_entries =
+                                       HAL_SRNG_INT_BATCH_THRESHOLD_RX;
+               params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_RX;
+               break;
+       case HAL_RXDMA_BUF:
+       case HAL_RXDMA_MONITOR_BUF:
+       case HAL_RXDMA_MONITOR_STATUS:
+               params.low_threshold = num_entries >> 3;
+               params.flags |= HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN;
+               params.intr_batch_cntr_thres_entries = 0;
+               params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_RX;
+               break;
+       case HAL_WBM2SW_RELEASE:
+               if (ring_num < 3) {
+                       params.intr_batch_cntr_thres_entries =
+                                       HAL_SRNG_INT_BATCH_THRESHOLD_TX;
+                       params.intr_timer_thres_us =
+                                       HAL_SRNG_INT_TIMER_THRESHOLD_TX;
+                       break;
+               }
+               /* follow through when ring_num >= 3 */
+               /* fall through */
+       case HAL_REO_EXCEPTION:
+       case HAL_REO_REINJECT:
+       case HAL_REO_CMD:
+       case HAL_REO_STATUS:
+       case HAL_TCL_DATA:
+       case HAL_TCL_CMD:
+       case HAL_TCL_STATUS:
+       case HAL_WBM_IDLE_LINK:
+       case HAL_SW2WBM_RELEASE:
+       case HAL_RXDMA_DST:
+       case HAL_RXDMA_MONITOR_DST:
+       case HAL_RXDMA_MONITOR_DESC:
+       case HAL_RXDMA_DIR_BUF:
+               params.intr_batch_cntr_thres_entries =
+                                       HAL_SRNG_INT_BATCH_THRESHOLD_OTHER;
+               params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_OTHER;
+               break;
+       default:
+               ath11k_warn(ab, "Not a valid ring type in dp :%d\n", type);
+               return -EINVAL;
+       }
+
+       ret = ath11k_hal_srng_setup(ab, type, ring_num, mac_id, ¶ms);
+       if (ret < 0) {
+               ath11k_warn(ab, "failed to setup srng: %d ring_id %d\n",
+                           ret, ring_num);
+               return ret;
+       }
+
+       ring->ring_id = ret;
+
+       return 0;
+}
+
+static void ath11k_dp_srng_common_cleanup(struct ath11k_base *ab)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       int i;
+
+       ath11k_dp_srng_cleanup(ab, &dp->wbm_desc_rel_ring);
+       ath11k_dp_srng_cleanup(ab, &dp->tcl_cmd_ring);
+       ath11k_dp_srng_cleanup(ab, &dp->tcl_status_ring);
+       for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) {
+               ath11k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_data_ring);
+               ath11k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_comp_ring);
+       }
+       ath11k_dp_srng_cleanup(ab, &dp->reo_reinject_ring);
+       ath11k_dp_srng_cleanup(ab, &dp->rx_rel_ring);
+       ath11k_dp_srng_cleanup(ab, &dp->reo_except_ring);
+       ath11k_dp_srng_cleanup(ab, &dp->reo_cmd_ring);
+       ath11k_dp_srng_cleanup(ab, &dp->reo_status_ring);
+}
+
+static int ath11k_dp_srng_common_setup(struct ath11k_base *ab)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       struct hal_srng *srng;
+       int i, ret;
+
+       ret = ath11k_dp_srng_setup(ab, &dp->wbm_desc_rel_ring,
+                                  HAL_SW2WBM_RELEASE, 0, 0,
+                                  DP_WBM_RELEASE_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ab, "failed to set up wbm2sw_release ring :%d\n",
+                           ret);
+               goto err;
+       }
+
+       ret = ath11k_dp_srng_setup(ab, &dp->tcl_cmd_ring, HAL_TCL_CMD, 0, 0,
+                                  DP_TCL_CMD_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ab, "failed to set up tcl_cmd ring :%d\n", ret);
+               goto err;
+       }
+
+       ret = ath11k_dp_srng_setup(ab, &dp->tcl_status_ring, HAL_TCL_STATUS,
+                                  0, 0, DP_TCL_STATUS_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ab, "failed to set up tcl_status ring :%d\n", ret);
+               goto err;
+       }
+
+       for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) {
+               ret = ath11k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_data_ring,
+                                          HAL_TCL_DATA, i, 0,
+                                          DP_TCL_DATA_RING_SIZE);
+               if (ret) {
+                       ath11k_warn(ab, "failed to set up tcl_data ring (%d) :%d\n",
+                                   i, ret);
+                       goto err;
+               }
+
+               ret = ath11k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_comp_ring,
+                                          HAL_WBM2SW_RELEASE, i, 0,
+                                          DP_TX_COMP_RING_SIZE);
+               if (ret) {
+                       ath11k_warn(ab, "failed to set up tcl_comp ring ring (%d) :%d\n",
+                                   i, ret);
+                       goto err;
+               }
+
+               srng = &ab->hal.srng_list[dp->tx_ring[i].tcl_data_ring.ring_id];
+               ath11k_hal_tx_init_data_ring(ab, srng);
+       }
+
+       ret = ath11k_dp_srng_setup(ab, &dp->reo_reinject_ring, HAL_REO_REINJECT,
+                                  0, 0, DP_REO_REINJECT_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ab, "failed to set up reo_reinject ring :%d\n",
+                           ret);
+               goto err;
+       }
+
+       ret = ath11k_dp_srng_setup(ab, &dp->rx_rel_ring, HAL_WBM2SW_RELEASE,
+                                  3, 0, DP_RX_RELEASE_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ab, "failed to set up rx_rel ring :%d\n", ret);
+               goto err;
+       }
+
+       ret = ath11k_dp_srng_setup(ab, &dp->reo_except_ring, HAL_REO_EXCEPTION,
+                                  0, 0, DP_REO_EXCEPTION_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ab, "failed to set up reo_exception ring :%d\n",
+                           ret);
+               goto err;
+       }
+
+       ret = ath11k_dp_srng_setup(ab, &dp->reo_cmd_ring, HAL_REO_CMD,
+                                  0, 0, DP_REO_CMD_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ab, "failed to set up reo_cmd ring :%d\n", ret);
+               goto err;
+       }
+
+       srng = &ab->hal.srng_list[dp->reo_cmd_ring.ring_id];
+       ath11k_hal_reo_init_cmd_ring(ab, srng);
+
+       ret = ath11k_dp_srng_setup(ab, &dp->reo_status_ring, HAL_REO_STATUS,
+                                  0, 0, DP_REO_STATUS_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ab, "failed to set up reo_status ring :%d\n", ret);
+               goto err;
+       }
+
+       ath11k_hal_reo_hw_setup(ab);
+
+       return 0;
+
+err:
+       ath11k_dp_srng_common_cleanup(ab);
+
+       return ret;
+}
+
+static void ath11k_dp_scatter_idle_link_desc_cleanup(struct ath11k_base *ab)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       struct hal_wbm_idle_scatter_list *slist = dp->scatter_list;
+       int i;
+
+       for (i = 0; i < DP_IDLE_SCATTER_BUFS_MAX; i++) {
+               if (!slist[i].vaddr)
+                       continue;
+
+               dma_free_coherent(ab->dev, HAL_WBM_IDLE_SCATTER_BUF_SIZE_MAX,
+                                 slist[i].vaddr, slist[i].paddr);
+               slist[i].vaddr = NULL;
+       }
+}
+
+static int ath11k_dp_scatter_idle_link_desc_setup(struct ath11k_base *ab,
+                                                 int size,
+                                                 u32 n_link_desc_bank,
+                                                 u32 n_link_desc,
+                                                 u32 last_bank_sz)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       struct dp_link_desc_bank *link_desc_banks = dp->link_desc_banks;
+       struct hal_wbm_idle_scatter_list *slist = dp->scatter_list;
+       u32 n_entries_per_buf;
+       int num_scatter_buf, scatter_idx;
+       struct hal_wbm_link_desc *scatter_buf;
+       int align_bytes, n_entries;
+       dma_addr_t paddr;
+       int rem_entries;
+       int i;
+       int ret = 0;
+       u32 end_offset;
+
+       n_entries_per_buf = HAL_WBM_IDLE_SCATTER_BUF_SIZE /
+                           ath11k_hal_srng_get_entrysize(HAL_WBM_IDLE_LINK);
+       num_scatter_buf = DIV_ROUND_UP(size, HAL_WBM_IDLE_SCATTER_BUF_SIZE);
+
+       if (num_scatter_buf > DP_IDLE_SCATTER_BUFS_MAX)
+               return -EINVAL;
+
+       for (i = 0; i < num_scatter_buf; i++) {
+               slist[i].vaddr = dma_alloc_coherent(ab->dev,
+                                                   HAL_WBM_IDLE_SCATTER_BUF_SIZE_MAX,
+                                                   &slist[i].paddr, GFP_KERNEL);
+               if (!slist[i].vaddr) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+       }
+
+       scatter_idx = 0;
+       scatter_buf = slist[scatter_idx].vaddr;
+       rem_entries = n_entries_per_buf;
+
+       for (i = 0; i < n_link_desc_bank; i++) {
+               align_bytes = link_desc_banks[i].vaddr -
+                             link_desc_banks[i].vaddr_unaligned;
+               n_entries = (DP_LINK_DESC_ALLOC_SIZE_THRESH - align_bytes) /
+                            HAL_LINK_DESC_SIZE;
+               paddr = link_desc_banks[i].paddr;
+               while (n_entries) {
+                       ath11k_hal_set_link_desc_addr(scatter_buf, i, paddr);
+                       n_entries--;
+                       paddr += HAL_LINK_DESC_SIZE;
+                       if (rem_entries) {
+                               rem_entries--;
+                               scatter_buf++;
+                               continue;
+                       }
+
+                       rem_entries = n_entries_per_buf;
+                       scatter_idx++;
+                       scatter_buf = slist[scatter_idx].vaddr;
+               }
+       }
+
+       end_offset = (scatter_buf - slist[scatter_idx].vaddr) *
+                    sizeof(struct hal_wbm_link_desc);
+       ath11k_hal_setup_link_idle_list(ab, slist, num_scatter_buf,
+                                       n_link_desc, end_offset);
+
+       return 0;
+
+err:
+       ath11k_dp_scatter_idle_link_desc_cleanup(ab);
+
+       return ret;
+}
+
+static void
+ath11k_dp_link_desc_bank_free(struct ath11k_base *ab,
+                             struct dp_link_desc_bank *link_desc_banks)
+{
+       int i;
+
+       for (i = 0; i < DP_LINK_DESC_BANKS_MAX; i++) {
+               if (link_desc_banks[i].vaddr_unaligned) {
+                       dma_free_coherent(ab->dev,
+                                         link_desc_banks[i].size,
+                                         link_desc_banks[i].vaddr_unaligned,
+                                         link_desc_banks[i].paddr_unaligned);
+                       link_desc_banks[i].vaddr_unaligned = NULL;
+               }
+       }
+}
+
+static int ath11k_dp_link_desc_bank_alloc(struct ath11k_base *ab,
+                                         struct dp_link_desc_bank *desc_bank,
+                                         int n_link_desc_bank,
+                                         int last_bank_sz)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       int i;
+       int ret = 0;
+       int desc_sz = DP_LINK_DESC_ALLOC_SIZE_THRESH;
+
+       for (i = 0; i < n_link_desc_bank; i++) {
+               if (i == (n_link_desc_bank - 1) && last_bank_sz)
+                       desc_sz = last_bank_sz;
+
+               desc_bank[i].vaddr_unaligned =
+                                       dma_alloc_coherent(ab->dev, desc_sz,
+                                                          &desc_bank[i].paddr_unaligned,
+                                                          GFP_KERNEL);
+               if (!desc_bank[i].vaddr_unaligned) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               desc_bank[i].vaddr = PTR_ALIGN(desc_bank[i].vaddr_unaligned,
+                                              HAL_LINK_DESC_ALIGN);
+               desc_bank[i].paddr = desc_bank[i].paddr_unaligned +
+                                    ((unsigned long)desc_bank[i].vaddr -
+                                     (unsigned long)desc_bank[i].vaddr_unaligned);
+               desc_bank[i].size = desc_sz;
+       }
+
+       return 0;
+
+err:
+       ath11k_dp_link_desc_bank_free(ab, dp->link_desc_banks);
+
+       return ret;
+}
+
+void ath11k_dp_link_desc_cleanup(struct ath11k_base *ab,
+                                struct dp_link_desc_bank *desc_bank,
+                                u32 ring_type, struct dp_srng *ring)
+{
+       ath11k_dp_link_desc_bank_free(ab, desc_bank);
+
+       if (ring_type != HAL_RXDMA_MONITOR_DESC) {
+               ath11k_dp_srng_cleanup(ab, ring);
+               ath11k_dp_scatter_idle_link_desc_cleanup(ab);
+       }
+}
+
+static int ath11k_wbm_idle_ring_setup(struct ath11k_base *ab, u32 *n_link_desc)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       u32 n_mpdu_link_desc, n_mpdu_queue_desc;
+       u32 n_tx_msdu_link_desc, n_rx_msdu_link_desc;
+       int ret = 0;
+
+       n_mpdu_link_desc = (DP_NUM_TIDS_MAX * DP_AVG_MPDUS_PER_TID_MAX) /
+                          HAL_NUM_MPDUS_PER_LINK_DESC;
+
+       n_mpdu_queue_desc = n_mpdu_link_desc /
+                           HAL_NUM_MPDU_LINKS_PER_QUEUE_DESC;
+
+       n_tx_msdu_link_desc = (DP_NUM_TIDS_MAX * DP_AVG_FLOWS_PER_TID *
+                              DP_AVG_MSDUS_PER_FLOW) /
+                             HAL_NUM_TX_MSDUS_PER_LINK_DESC;
+
+       n_rx_msdu_link_desc = (DP_NUM_TIDS_MAX * DP_AVG_MPDUS_PER_TID_MAX *
+                              DP_AVG_MSDUS_PER_MPDU) /
+                             HAL_NUM_RX_MSDUS_PER_LINK_DESC;
+
+       *n_link_desc = n_mpdu_link_desc + n_mpdu_queue_desc +
+                     n_tx_msdu_link_desc + n_rx_msdu_link_desc;
+
+       ret = ath11k_dp_srng_setup(ab, &dp->wbm_idle_ring,
+                                  HAL_WBM_IDLE_LINK, 0, 0, *n_link_desc);
+       if (ret) {
+               ath11k_warn(ab, "failed to setup wbm_idle_ring: %d\n", ret);
+               return ret;
+       }
+       return ret;
+}
+
+int ath11k_dp_link_desc_setup(struct ath11k_base *ab,
+                             struct dp_link_desc_bank *link_desc_banks,
+                             u32 ring_type, struct hal_srng *srng,
+                             u32 n_link_desc)
+{
+       u32 tot_mem_sz;
+       u32 n_link_desc_bank, last_bank_sz;
+       u32 entry_sz, align_bytes, n_entries;
+       u32 paddr;
+       u32 *desc;
+       int i, ret;
+
+       if (n_link_desc & (n_link_desc - 1))
+               n_link_desc = 1 << fls(n_link_desc);
+
+       tot_mem_sz = n_link_desc * HAL_LINK_DESC_SIZE;
+       tot_mem_sz += HAL_LINK_DESC_ALIGN;
+
+       if (tot_mem_sz <= DP_LINK_DESC_ALLOC_SIZE_THRESH) {
+               n_link_desc_bank = 1;
+               last_bank_sz = tot_mem_sz;
+       } else {
+               n_link_desc_bank = tot_mem_sz /
+                                  (DP_LINK_DESC_ALLOC_SIZE_THRESH -
+                                   HAL_LINK_DESC_ALIGN);
+               last_bank_sz = tot_mem_sz %
+                              (DP_LINK_DESC_ALLOC_SIZE_THRESH -
+                               HAL_LINK_DESC_ALIGN);
+
+               if (last_bank_sz)
+                       n_link_desc_bank += 1;
+       }
+
+       if (n_link_desc_bank > DP_LINK_DESC_BANKS_MAX)
+               return -EINVAL;
+
+       ret = ath11k_dp_link_desc_bank_alloc(ab, link_desc_banks,
+                                            n_link_desc_bank, last_bank_sz);
+       if (ret)
+               return ret;
+
+       /* Setup link desc idle list for HW internal usage */
+       entry_sz = ath11k_hal_srng_get_entrysize(ring_type);
+       tot_mem_sz = entry_sz * n_link_desc;
+
+       /* Setup scatter desc list when the total memory requirement is more */
+       if (tot_mem_sz > DP_LINK_DESC_ALLOC_SIZE_THRESH &&
+           ring_type != HAL_RXDMA_MONITOR_DESC) {
+               ret = ath11k_dp_scatter_idle_link_desc_setup(ab, tot_mem_sz,
+                                                            n_link_desc_bank,
+                                                            n_link_desc,
+                                                            last_bank_sz);
+               if (ret) {
+                       ath11k_warn(ab, "failed to setup scatting idle list descriptor :%d\n",
+                                   ret);
+                       goto fail_desc_bank_free;
+               }
+
+               return 0;
+       }
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       for (i = 0; i < n_link_desc_bank; i++) {
+               align_bytes = link_desc_banks[i].vaddr -
+                             link_desc_banks[i].vaddr_unaligned;
+               n_entries = (link_desc_banks[i].size - align_bytes) /
+                           HAL_LINK_DESC_SIZE;
+               paddr = link_desc_banks[i].paddr;
+               while (n_entries &&
+                      (desc = ath11k_hal_srng_src_get_next_entry(ab, srng))) {
+                       ath11k_hal_set_link_desc_addr((struct hal_wbm_link_desc *)desc,
+                                                     i, paddr);
+                       n_entries--;
+                       paddr += HAL_LINK_DESC_SIZE;
+               }
+       }
+
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       return 0;
+
+fail_desc_bank_free:
+       ath11k_dp_link_desc_bank_free(ab, link_desc_banks);
+
+       return ret;
+}
+
+int ath11k_dp_service_srng(struct ath11k_base *ab,
+                          struct ath11k_ext_irq_grp *irq_grp,
+                          int budget)
+{
+       struct napi_struct *napi = &irq_grp->napi;
+       int grp_id = irq_grp->grp_id;
+       int work_done = 0;
+       int i = 0;
+       int tot_work_done = 0;
+
+       while (ath11k_tx_ring_mask[grp_id] >> i) {
+               if (ath11k_tx_ring_mask[grp_id] & BIT(i))
+                       ath11k_dp_tx_completion_handler(ab, i);
+               i++;
+       }
+
+       if (ath11k_rx_err_ring_mask[grp_id]) {
+               work_done = ath11k_dp_process_rx_err(ab, napi, budget);
+               budget -= work_done;
+               tot_work_done += work_done;
+               if (budget <= 0)
+                       goto done;
+       }
+
+       if (ath11k_rx_wbm_rel_ring_mask[grp_id]) {
+               work_done = ath11k_dp_rx_process_wbm_err(ab,
+                                                        napi,
+                                                        budget);
+               budget -= work_done;
+               tot_work_done += work_done;
+
+               if (budget <= 0)
+                       goto done;
+       }
+
+       if (ath11k_rx_ring_mask[grp_id]) {
+               for (i = 0; i <  ab->num_radios; i++) {
+                       if (ath11k_rx_ring_mask[grp_id] & BIT(i)) {
+                               work_done = ath11k_dp_process_rx(ab, i, napi,
+                                                                &irq_grp->pending_q,
+                                                                budget);
+                               budget -= work_done;
+                               tot_work_done += work_done;
+                       }
+                       if (budget <= 0)
+                               goto done;
+               }
+       }
+
+       if (rx_mon_status_ring_mask[grp_id]) {
+               for (i = 0; i <  ab->num_radios; i++) {
+                       if (rx_mon_status_ring_mask[grp_id] & BIT(i)) {
+                               work_done =
+                               ath11k_dp_rx_process_mon_rings(ab,
+                                                              i, napi,
+                                                              budget);
+                               budget -= work_done;
+                               tot_work_done += work_done;
+                       }
+                       if (budget <= 0)
+                               goto done;
+               }
+       }
+
+       if (ath11k_reo_status_ring_mask[grp_id])
+               ath11k_dp_process_reo_status(ab);
+
+       for (i = 0; i < ab->num_radios; i++) {
+               if (ath11k_rxdma2host_ring_mask[grp_id] & BIT(i)) {
+                       work_done = ath11k_dp_process_rxdma_err(ab, i, budget);
+                       budget -= work_done;
+                       tot_work_done += work_done;
+               }
+
+               if (budget <= 0)
+                       goto done;
+
+               if (ath11k_host2rxdma_ring_mask[grp_id] & BIT(i)) {
+                       struct ath11k_pdev_dp *dp = &ab->pdevs[i].ar->dp;
+                       struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
+
+                       ath11k_dp_rxbufs_replenish(ab, i, rx_ring, 0,
+                                                  HAL_RX_BUF_RBM_SW3_BM,
+                                                  GFP_ATOMIC);
+               }
+       }
+       /* TODO: Implement handler for other interrupts */
+
+done:
+       return tot_work_done;
+}
+
+void ath11k_dp_pdev_free(struct ath11k_base *ab)
+{
+       struct ath11k *ar;
+       int i;
+
+       for (i = 0; i < ab->num_radios; i++) {
+               ar = ab->pdevs[i].ar;
+               ath11k_dp_rx_pdev_free(ab, i);
+               ath11k_debug_unregister(ar);
+               ath11k_dp_rx_pdev_mon_detach(ar);
+       }
+}
+
+int ath11k_dp_pdev_alloc(struct ath11k_base *ab)
+{
+       struct ath11k *ar;
+       struct ath11k_pdev_dp *dp;
+       int ret;
+       int i;
+
+       for (i = 0; i <  ab->num_radios; i++) {
+               ar = ab->pdevs[i].ar;
+               dp = &ar->dp;
+               dp->mac_id = i;
+               idr_init(&dp->rx_refill_buf_ring.bufs_idr);
+               spin_lock_init(&dp->rx_refill_buf_ring.idr_lock);
+               atomic_set(&dp->num_tx_pending, 0);
+               init_waitqueue_head(&dp->tx_empty_waitq);
+               idr_init(&dp->rx_mon_status_refill_ring.bufs_idr);
+               spin_lock_init(&dp->rx_mon_status_refill_ring.idr_lock);
+               idr_init(&dp->rxdma_mon_buf_ring.bufs_idr);
+               spin_lock_init(&dp->rxdma_mon_buf_ring.idr_lock);
+       }
+
+       /* TODO:Per-pdev rx ring unlike tx ring which is mapped to different AC's */
+       for (i = 0; i < ab->num_radios; i++) {
+               ar = ab->pdevs[i].ar;
+               ret = ath11k_dp_rx_pdev_alloc(ab, i);
+               if (ret) {
+                       ath11k_warn(ab, "failed to allocate pdev rx for pdev_id :%d\n",
+                                   i);
+                       goto err;
+               }
+               ret = ath11k_dp_rx_pdev_mon_attach(ar);
+               if (ret) {
+                       ath11k_warn(ab, "failed to initialize mon pdev %d\n",
+                                   i);
+                       goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       ath11k_dp_pdev_free(ab);
+
+       return ret;
+}
+
+int ath11k_dp_htt_connect(struct ath11k_dp *dp)
+{
+       struct ath11k_htc_svc_conn_req conn_req;
+       struct ath11k_htc_svc_conn_resp conn_resp;
+       int status;
+
+       memset(&conn_req, 0, sizeof(conn_req));
+       memset(&conn_resp, 0, sizeof(conn_resp));
+
+       conn_req.ep_ops.ep_tx_complete = ath11k_dp_htt_htc_tx_complete;
+       conn_req.ep_ops.ep_rx_complete = ath11k_dp_htt_htc_t2h_msg_handler;
+
+       /* connect to control service */
+       conn_req.service_id = ATH11K_HTC_SVC_ID_HTT_DATA_MSG;
+
+       status = ath11k_htc_connect_service(&dp->ab->htc, &conn_req,
+                                           &conn_resp);
+
+       if (status)
+               return status;
+
+       dp->eid = conn_resp.eid;
+
+       return 0;
+}
+
+static void ath11k_dp_update_vdev_search(struct ath11k_vif *arvif)
+{
+       /* Enable AddrY (SA based search) for STA mode. All other modes it
+        * is going to be AddrX (DA based search). For STA mode, set search
+        * type based on AST value.
+        */
+       switch (arvif->vdev_type) {
+       case WMI_VDEV_TYPE_STA:
+               arvif->hal_addr_search_flags = HAL_TX_ADDRY_EN;
+               arvif->search_type = HAL_TX_ADDR_SEARCH_INDEX;
+               break;
+       case WMI_VDEV_TYPE_AP:
+       case WMI_VDEV_TYPE_IBSS:
+               arvif->hal_addr_search_flags = HAL_TX_ADDRX_EN;
+               arvif->search_type = HAL_TX_ADDR_SEARCH_DEFAULT;
+               break;
+       case WMI_VDEV_TYPE_MONITOR:
+       default:
+               return;
+       }
+}
+
+void ath11k_dp_vdev_tx_attach(struct ath11k *ar, struct ath11k_vif *arvif)
+{
+       arvif->tcl_metadata |= FIELD_PREP(HTT_TCL_META_DATA_TYPE, 1) |
+                              FIELD_PREP(HTT_TCL_META_DATA_VDEV_ID,
+                                         arvif->vdev_id) |
+                              FIELD_PREP(HTT_TCL_META_DATA_PDEV_ID,
+                                         ar->pdev->pdev_id);
+
+       /* set HTT extension valid bit to 0 by default */
+       arvif->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT;
+
+       ath11k_dp_update_vdev_search(arvif);
+}
+
+static int ath11k_dp_tx_pending_cleanup(int buf_id, void *skb, void *ctx)
+{
+       struct ath11k_base *ab = (struct ath11k_base *)ctx;
+       struct sk_buff *msdu = skb;
+
+       dma_unmap_single(ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len,
+                        DMA_TO_DEVICE);
+
+       dev_kfree_skb_any(msdu);
+
+       return 0;
+}
+
+void ath11k_dp_free(struct ath11k_base *ab)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       int i;
+
+       ath11k_dp_link_desc_cleanup(ab, dp->link_desc_banks,
+                                   HAL_WBM_IDLE_LINK, &dp->wbm_idle_ring);
+
+       ath11k_dp_srng_common_cleanup(ab);
+
+       ath11k_dp_reo_cmd_list_cleanup(ab);
+
+       for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) {
+               spin_lock_bh(&dp->tx_ring[i].tx_idr_lock);
+               idr_for_each(&dp->tx_ring[i].txbuf_idr,
+                            ath11k_dp_tx_pending_cleanup, ab);
+               idr_destroy(&dp->tx_ring[i].txbuf_idr);
+               spin_unlock_bh(&dp->tx_ring[i].tx_idr_lock);
+
+               spin_lock_bh(&dp->tx_ring[i].tx_status_lock);
+               kfifo_free(&dp->tx_ring[i].tx_status_fifo);
+               spin_unlock_bh(&dp->tx_ring[i].tx_status_lock);
+       }
+
+       /* Deinit any SOC level resource */
+}
+
+int ath11k_dp_alloc(struct ath11k_base *ab)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       struct hal_srng *srng = NULL;
+       size_t size = 0;
+       u32 n_link_desc = 0;
+       int ret;
+       int i;
+
+       dp->ab = ab;
+
+       INIT_LIST_HEAD(&dp->reo_cmd_list);
+       INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list);
+       spin_lock_init(&dp->reo_cmd_lock);
+
+       ret = ath11k_wbm_idle_ring_setup(ab, &n_link_desc);
+       if (ret) {
+               ath11k_warn(ab, "failed to setup wbm_idle_ring: %d\n", ret);
+               return ret;
+       }
+
+       srng = &ab->hal.srng_list[dp->wbm_idle_ring.ring_id];
+
+       ret = ath11k_dp_link_desc_setup(ab, dp->link_desc_banks,
+                                       HAL_WBM_IDLE_LINK, srng, n_link_desc);
+       if (ret) {
+               ath11k_warn(ab, "failed to setup link desc: %d\n", ret);
+               return ret;
+       }
+
+       ret = ath11k_dp_srng_common_setup(ab);
+       if (ret)
+               goto fail_link_desc_cleanup;
+
+       size = roundup_pow_of_two(DP_TX_COMP_RING_SIZE);
+
+       for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) {
+               idr_init(&dp->tx_ring[i].txbuf_idr);
+               spin_lock_init(&dp->tx_ring[i].tx_idr_lock);
+               dp->tx_ring[i].tcl_data_ring_id = i;
+
+               spin_lock_init(&dp->tx_ring[i].tx_status_lock);
+               ret = kfifo_alloc(&dp->tx_ring[i].tx_status_fifo, size,
+                                 GFP_KERNEL);
+               if (ret)
+                       goto fail_cmn_srng_cleanup;
+       }
+
+       for (i = 0; i < HAL_DSCP_TID_MAP_TBL_NUM_ENTRIES_MAX; i++)
+               ath11k_hal_tx_set_dscp_tid_map(ab, i);
+
+       /* Init any SOC level resource for DP */
+
+       return 0;
+
+fail_cmn_srng_cleanup:
+       ath11k_dp_srng_common_cleanup(ab);
+
+fail_link_desc_cleanup:
+       ath11k_dp_link_desc_cleanup(ab, dp->link_desc_banks,
+                                   HAL_WBM_IDLE_LINK, &dp->wbm_idle_ring);
+
+       return ret;
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_DP_H
+#define ATH11K_DP_H
+
+#include <linux/kfifo.h>
+#include "hal_rx.h"
+
+struct ath11k_base;
+struct ath11k_peer;
+struct ath11k_dp;
+struct ath11k_vif;
+struct hal_tcl_status_ring;
+struct ath11k_ext_irq_grp;
+
+struct dp_rx_tid {
+       u8 tid;
+       u32 *vaddr;
+       dma_addr_t paddr;
+       u32 size;
+       u32 ba_win_sz;
+       bool active;
+};
+
+#define DP_REO_DESC_FREE_TIMEOUT_MS 1000
+
+struct dp_reo_cache_flush_elem {
+       struct list_head list;
+       struct dp_rx_tid data;
+       unsigned long ts;
+};
+
+struct dp_reo_cmd {
+       struct list_head list;
+       struct dp_rx_tid data;
+       int cmd_num;
+       void (*handler)(struct ath11k_dp *, void *,
+                       enum hal_reo_cmd_status status);
+};
+
+struct dp_srng {
+       u32 *vaddr_unaligned;
+       u32 *vaddr;
+       dma_addr_t paddr_unaligned;
+       dma_addr_t paddr;
+       int size;
+       u32 ring_id;
+};
+
+struct dp_rxdma_ring {
+       struct dp_srng refill_buf_ring;
+       struct idr bufs_idr;
+       /* Protects bufs_idr */
+       spinlock_t idr_lock;
+       int bufs_max;
+};
+
+struct dp_tx_ring {
+       u8 tcl_data_ring_id;
+       struct dp_srng tcl_data_ring;
+       struct dp_srng tcl_comp_ring;
+       struct idr txbuf_idr;
+       u32 num_tx_pending;
+       /* Protects txbuf_idr and num_pending */
+       spinlock_t tx_idr_lock;
+       DECLARE_KFIFO_PTR(tx_status_fifo, struct hal_wbm_release_ring);
+       /* lock to protect tx_status_fifo because tx_status_fifo can be
+        * accessed concurrently.
+        */
+       spinlock_t tx_status_lock;
+};
+
+struct ath11k_pdev_mon_stats {
+       u32 status_ppdu_state;
+       u32 status_ppdu_start;
+       u32 status_ppdu_end;
+       u32 status_ppdu_compl;
+       u32 status_ppdu_start_mis;
+       u32 status_ppdu_end_mis;
+       u32 status_ppdu_done;
+       u32 dest_ppdu_done;
+       u32 dest_mpdu_done;
+       u32 dest_mpdu_drop;
+       u32 dup_mon_linkdesc_cnt;
+       u32 dup_mon_buf_cnt;
+};
+
+struct dp_link_desc_bank {
+       void *vaddr_unaligned;
+       void *vaddr;
+       dma_addr_t paddr_unaligned;
+       dma_addr_t paddr;
+       u32 size;
+};
+
+/* Size to enforce scatter idle list mode */
+#define DP_LINK_DESC_ALLOC_SIZE_THRESH 0x200000
+#define DP_LINK_DESC_BANKS_MAX 8
+
+#define DP_RX_DESC_COOKIE_INDEX_MAX            0x3ffff
+#define DP_RX_DESC_COOKIE_POOL_ID_MAX          0x1c0000
+#define DP_RX_DESC_COOKIE_MAX  \
+       (DP_RX_DESC_COOKIE_INDEX_MAX | DP_RX_DESC_COOKIE_POOL_ID_MAX)
+#define DP_NOT_PPDU_ID_WRAP_AROUND 20000
+
+enum ath11k_dp_ppdu_state {
+       DP_PPDU_STATUS_START,
+       DP_PPDU_STATUS_DONE,
+};
+
+struct ath11k_mon_data {
+       struct dp_link_desc_bank link_desc_banks[DP_LINK_DESC_BANKS_MAX];
+       struct hal_rx_mon_ppdu_info mon_ppdu_info;
+
+       u32 mon_ppdu_status;
+       u32 mon_last_buf_cookie;
+       u64 mon_last_linkdesc_paddr;
+       u16 chan_noise_floor;
+
+       struct ath11k_pdev_mon_stats rx_mon_stats;
+       /* lock for monitor data */
+       spinlock_t mon_lock;
+       struct sk_buff_head rx_status_q;
+};
+
+struct ath11k_pdev_dp {
+       u32 mac_id;
+       atomic_t num_tx_pending;
+       wait_queue_head_t tx_empty_waitq;
+       struct dp_srng reo_dst_ring;
+       struct dp_rxdma_ring rx_refill_buf_ring;
+       struct dp_srng rxdma_err_dst_ring;
+       struct dp_srng rxdma_mon_dst_ring;
+       struct dp_srng rxdma_mon_desc_ring;
+
+       struct dp_rxdma_ring rxdma_mon_buf_ring;
+       struct dp_rxdma_ring rx_mon_status_refill_ring;
+       struct ieee80211_rx_status rx_status;
+       struct ath11k_mon_data mon_data;
+};
+
+#define DP_NUM_CLIENTS_MAX 64
+#define DP_AVG_TIDS_PER_CLIENT 2
+#define DP_NUM_TIDS_MAX (DP_NUM_CLIENTS_MAX * DP_AVG_TIDS_PER_CLIENT)
+#define DP_AVG_MSDUS_PER_FLOW 128
+#define DP_AVG_FLOWS_PER_TID 2
+#define DP_AVG_MPDUS_PER_TID_MAX 128
+#define DP_AVG_MSDUS_PER_MPDU 4
+
+#define DP_RX_HASH_ENABLE      0 /* Disable hash based Rx steering */
+
+#define DP_BA_WIN_SZ_MAX       256
+
+#define DP_TCL_NUM_RING_MAX    3
+
+#define DP_IDLE_SCATTER_BUFS_MAX 16
+
+#define DP_WBM_RELEASE_RING_SIZE       64
+#define DP_TCL_DATA_RING_SIZE          512
+#define DP_TX_COMP_RING_SIZE           8192
+#define DP_TX_IDR_SIZE                 (DP_TX_COMP_RING_SIZE << 1)
+#define DP_TCL_CMD_RING_SIZE           32
+#define DP_TCL_STATUS_RING_SIZE                32
+#define DP_REO_DST_RING_MAX            4
+#define DP_REO_DST_RING_SIZE           2048
+#define DP_REO_REINJECT_RING_SIZE      32
+#define DP_RX_RELEASE_RING_SIZE                1024
+#define DP_REO_EXCEPTION_RING_SIZE     128
+#define DP_REO_CMD_RING_SIZE           128
+#define DP_REO_STATUS_RING_SIZE                256
+#define DP_RXDMA_BUF_RING_SIZE         4096
+#define DP_RXDMA_REFILL_RING_SIZE      2048
+#define DP_RXDMA_ERR_DST_RING_SIZE     1024
+#define DP_RXDMA_MON_STATUS_RING_SIZE  1024
+#define DP_RXDMA_MONITOR_BUF_RING_SIZE 4096
+#define DP_RXDMA_MONITOR_DST_RING_SIZE 2048
+#define DP_RXDMA_MONITOR_DESC_RING_SIZE        4096
+
+#define DP_RX_BUFFER_SIZE      2048
+#define DP_RX_BUFFER_ALIGN_SIZE        128
+
+#define DP_RXDMA_BUF_COOKIE_BUF_ID     GENMASK(17, 0)
+#define DP_RXDMA_BUF_COOKIE_PDEV_ID    GENMASK(20, 18)
+
+#define DP_HW2SW_MACID(mac_id) ((mac_id) ? ((mac_id) - 1) : 0)
+#define DP_SW2HW_MACID(mac_id) ((mac_id) + 1)
+
+#define DP_TX_DESC_ID_MAC_ID  GENMASK(1, 0)
+#define DP_TX_DESC_ID_MSDU_ID GENMASK(18, 2)
+#define DP_TX_DESC_ID_POOL_ID GENMASK(20, 19)
+
+struct ath11k_dp {
+       struct ath11k_base *ab;
+       enum ath11k_htc_ep_id eid;
+       struct completion htt_tgt_version_received;
+       u8 htt_tgt_ver_major;
+       u8 htt_tgt_ver_minor;
+       struct dp_link_desc_bank link_desc_banks[DP_LINK_DESC_BANKS_MAX];
+       struct dp_srng wbm_idle_ring;
+       struct dp_srng wbm_desc_rel_ring;
+       struct dp_srng tcl_cmd_ring;
+       struct dp_srng tcl_status_ring;
+       struct dp_srng reo_reinject_ring;
+       struct dp_srng rx_rel_ring;
+       struct dp_srng reo_except_ring;
+       struct dp_srng reo_cmd_ring;
+       struct dp_srng reo_status_ring;
+       struct dp_tx_ring tx_ring[DP_TCL_NUM_RING_MAX];
+       struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX];
+       struct list_head reo_cmd_list;
+       struct list_head reo_cmd_cache_flush_list;
+       /* protects access to reo_cmd_list and reo_cmd_cache_flush_list */
+       spinlock_t reo_cmd_lock;
+};
+
+/* HTT definitions */
+
+#define HTT_TCL_META_DATA_TYPE                 BIT(0)
+#define HTT_TCL_META_DATA_VALID_HTT            BIT(1)
+
+/* vdev meta data */
+#define HTT_TCL_META_DATA_VDEV_ID              GENMASK(9, 2)
+#define HTT_TCL_META_DATA_PDEV_ID              GENMASK(11, 10)
+#define HTT_TCL_META_DATA_HOST_INSPECTED       BIT(12)
+
+/* peer meta data */
+#define HTT_TCL_META_DATA_PEER_ID              GENMASK(15, 2)
+
+#define HTT_TX_WBM_COMP_STATUS_OFFSET 8
+
+/* HTT tx completion is overlayed in wbm_release_ring */
+#define HTT_TX_WBM_COMP_INFO0_STATUS           GENMASK(12, 9)
+#define HTT_TX_WBM_COMP_INFO0_REINJECT_REASON  GENMASK(16, 13)
+#define HTT_TX_WBM_COMP_INFO0_REINJECT_REASON  GENMASK(16, 13)
+
+#define HTT_TX_WBM_COMP_INFO1_ACK_RSSI         GENMASK(31, 24)
+
+struct htt_tx_wbm_completion {
+       u32 info0;
+       u32 info1;
+       u32 info2;
+       u32 info3;
+} __packed;
+
+enum htt_h2t_msg_type {
+       HTT_H2T_MSG_TYPE_VERSION_REQ            = 0,
+       HTT_H2T_MSG_TYPE_SRING_SETUP            = 0xb,
+       HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG  = 0xc,
+       HTT_H2T_MSG_TYPE_EXT_STATS_CFG          = 0x10,
+       HTT_H2T_MSG_TYPE_PPDU_STATS_CFG         = 0x11,
+};
+
+#define HTT_VER_REQ_INFO_MSG_ID                GENMASK(7, 0)
+
+struct htt_ver_req_cmd {
+       u32 ver_reg_info;
+} __packed;
+
+enum htt_srng_ring_type {
+       HTT_HW_TO_SW_RING,
+       HTT_SW_TO_HW_RING,
+       HTT_SW_TO_SW_RING,
+};
+
+enum htt_srng_ring_id {
+       HTT_RXDMA_HOST_BUF_RING,
+       HTT_RXDMA_MONITOR_STATUS_RING,
+       HTT_RXDMA_MONITOR_BUF_RING,
+       HTT_RXDMA_MONITOR_DESC_RING,
+       HTT_RXDMA_MONITOR_DEST_RING,
+       HTT_HOST1_TO_FW_RXBUF_RING,
+       HTT_HOST2_TO_FW_RXBUF_RING,
+       HTT_RXDMA_NON_MONITOR_DEST_RING,
+};
+
+/* host -> target  HTT_SRING_SETUP message
+ *
+ * After target is booted up, Host can send SRING setup message for
+ * each host facing LMAC SRING. Target setups up HW registers based
+ * on setup message and confirms back to Host if response_required is set.
+ * Host should wait for confirmation message before sending new SRING
+ * setup message
+ *
+ * The message would appear as follows:
+ *
+ * |31            24|23    20|19|18 16|15|14          8|7                0|
+ * |--------------- +-----------------+----------------+------------------|
+ * |    ring_type   |      ring_id    |    pdev_id     |     msg_type     |
+ * |----------------------------------------------------------------------|
+ * |                          ring_base_addr_lo                           |
+ * |----------------------------------------------------------------------|
+ * |                         ring_base_addr_hi                            |
+ * |----------------------------------------------------------------------|
+ * |ring_misc_cfg_flag|ring_entry_size|            ring_size              |
+ * |----------------------------------------------------------------------|
+ * |                         ring_head_offset32_remote_addr_lo            |
+ * |----------------------------------------------------------------------|
+ * |                         ring_head_offset32_remote_addr_hi            |
+ * |----------------------------------------------------------------------|
+ * |                         ring_tail_offset32_remote_addr_lo            |
+ * |----------------------------------------------------------------------|
+ * |                         ring_tail_offset32_remote_addr_hi            |
+ * |----------------------------------------------------------------------|
+ * |                          ring_msi_addr_lo                            |
+ * |----------------------------------------------------------------------|
+ * |                          ring_msi_addr_hi                            |
+ * |----------------------------------------------------------------------|
+ * |                          ring_msi_data                               |
+ * |----------------------------------------------------------------------|
+ * |         intr_timer_th            |IM|      intr_batch_counter_th     |
+ * |----------------------------------------------------------------------|
+ * |          reserved        |RR|PTCF|        intr_low_threshold         |
+ * |----------------------------------------------------------------------|
+ * Where
+ *     IM = sw_intr_mode
+ *     RR = response_required
+ *     PTCF = prefetch_timer_cfg
+ *
+ * The message is interpreted as follows:
+ * dword0  - b'0:7   - msg_type: This will be set to
+ *                     HTT_H2T_MSG_TYPE_SRING_SETUP
+ *           b'8:15  - pdev_id:
+ *                     0 (for rings at SOC/UMAC level),
+ *                     1/2/3 mac id (for rings at LMAC level)
+ *           b'16:23 - ring_id: identify which ring is to setup,
+ *                     more details can be got from enum htt_srng_ring_id
+ *           b'24:31 - ring_type: identify type of host rings,
+ *                     more details can be got from enum htt_srng_ring_type
+ * dword1  - b'0:31  - ring_base_addr_lo: Lower 32bits of ring base address
+ * dword2  - b'0:31  - ring_base_addr_hi: Upper 32bits of ring base address
+ * dword3  - b'0:15  - ring_size: size of the ring in unit of 4-bytes words
+ *           b'16:23 - ring_entry_size: Size of each entry in 4-byte word units
+ *           b'24:31 - ring_misc_cfg_flag: Valid only for HW_TO_SW_RING and
+ *                     SW_TO_HW_RING.
+ *                     Refer to HTT_SRING_SETUP_RING_MISC_CFG_RING defs.
+ * dword4  - b'0:31  - ring_head_off32_remote_addr_lo:
+ *                     Lower 32 bits of memory address of the remote variable
+ *                     storing the 4-byte word offset that identifies the head
+ *                     element within the ring.
+ *                     (The head offset variable has type u32.)
+ *                     Valid for HW_TO_SW and SW_TO_SW rings.
+ * dword5  - b'0:31  - ring_head_off32_remote_addr_hi:
+ *                     Upper 32 bits of memory address of the remote variable
+ *                     storing the 4-byte word offset that identifies the head
+ *                     element within the ring.
+ *                     (The head offset variable has type u32.)
+ *                     Valid for HW_TO_SW and SW_TO_SW rings.
+ * dword6  - b'0:31  - ring_tail_off32_remote_addr_lo:
+ *                     Lower 32 bits of memory address of the remote variable
+ *                     storing the 4-byte word offset that identifies the tail
+ *                     element within the ring.
+ *                     (The tail offset variable has type u32.)
+ *                     Valid for HW_TO_SW and SW_TO_SW rings.
+ * dword7  - b'0:31  - ring_tail_off32_remote_addr_hi:
+ *                     Upper 32 bits of memory address of the remote variable
+ *                     storing the 4-byte word offset that identifies the tail
+ *                     element within the ring.
+ *                     (The tail offset variable has type u32.)
+ *                     Valid for HW_TO_SW and SW_TO_SW rings.
+ * dword8  - b'0:31  - ring_msi_addr_lo: Lower 32bits of MSI cfg address
+ *                     valid only for HW_TO_SW_RING and SW_TO_HW_RING
+ * dword9  - b'0:31  - ring_msi_addr_hi: Upper 32bits of MSI cfg address
+ *                     valid only for HW_TO_SW_RING and SW_TO_HW_RING
+ * dword10 - b'0:31  - ring_msi_data: MSI data
+ *                     Refer to HTT_SRING_SETUP_RING_MSC_CFG_xxx defs
+ *                     valid only for HW_TO_SW_RING and SW_TO_HW_RING
+ * dword11 - b'0:14  - intr_batch_counter_th:
+ *                     batch counter threshold is in units of 4-byte words.
+ *                     HW internally maintains and increments batch count.
+ *                     (see SRING spec for detail description).
+ *                     When batch count reaches threshold value, an interrupt
+ *                     is generated by HW.
+ *           b'15    - sw_intr_mode:
+ *                     This configuration shall be static.
+ *                     Only programmed at power up.
+ *                     0: generate pulse style sw interrupts
+ *                     1: generate level style sw interrupts
+ *           b'16:31 - intr_timer_th:
+ *                     The timer init value when timer is idle or is
+ *                     initialized to start downcounting.
+ *                     In 8us units (to cover a range of 0 to 524 ms)
+ * dword12 - b'0:15  - intr_low_threshold:
+ *                     Used only by Consumer ring to generate ring_sw_int_p.
+ *                     Ring entries low threshold water mark, that is used
+ *                     in combination with the interrupt timer as well as
+ *                     the the clearing of the level interrupt.
+ *           b'16:18 - prefetch_timer_cfg:
+ *                     Used only by Consumer ring to set timer mode to
+ *                     support Application prefetch handling.
+ *                     The external tail offset/pointer will be updated
+ *                     at following intervals:
+ *                     3'b000: (Prefetch feature disabled; used only for debug)
+ *                     3'b001: 1 usec
+ *                     3'b010: 4 usec
+ *                     3'b011: 8 usec (default)
+ *                     3'b100: 16 usec
+ *                     Others: Reserverd
+ *           b'19    - response_required:
+ *                     Host needs HTT_T2H_MSG_TYPE_SRING_SETUP_DONE as response
+ *           b'20:31 - reserved:  reserved for future use
+ */
+
+#define HTT_SRNG_SETUP_CMD_INFO0_MSG_TYPE      GENMASK(7, 0)
+#define HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID       GENMASK(15, 8)
+#define HTT_SRNG_SETUP_CMD_INFO0_RING_ID       GENMASK(23, 16)
+#define HTT_SRNG_SETUP_CMD_INFO0_RING_TYPE     GENMASK(31, 24)
+
+#define HTT_SRNG_SETUP_CMD_INFO1_RING_SIZE                     GENMASK(15, 0)
+#define HTT_SRNG_SETUP_CMD_INFO1_RING_ENTRY_SIZE               GENMASK(23, 16)
+#define HTT_SRNG_SETUP_CMD_INFO1_RING_LOOP_CNT_DIS             BIT(25)
+#define HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_MSI_SWAP           BIT(27)
+#define HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_HOST_FW_SWAP       BIT(28)
+#define HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_TLV_SWAP           BIT(29)
+
+#define HTT_SRNG_SETUP_CMD_INTR_INFO_BATCH_COUNTER_THRESH      GENMASK(14, 0)
+#define HTT_SRNG_SETUP_CMD_INTR_INFO_SW_INTR_MODE              BIT(15)
+#define HTT_SRNG_SETUP_CMD_INTR_INFO_INTR_TIMER_THRESH         GENMASK(31, 16)
+
+#define HTT_SRNG_SETUP_CMD_INFO2_INTR_LOW_THRESH       GENMASK(15, 0)
+#define HTT_SRNG_SETUP_CMD_INFO2_PRE_FETCH_TIMER_CFG   BIT(16)
+#define HTT_SRNG_SETUP_CMD_INFO2_RESPONSE_REQUIRED     BIT(19)
+
+struct htt_srng_setup_cmd {
+       u32 info0;
+       u32 ring_base_addr_lo;
+       u32 ring_base_addr_hi;
+       u32 info1;
+       u32 ring_head_off32_remote_addr_lo;
+       u32 ring_head_off32_remote_addr_hi;
+       u32 ring_tail_off32_remote_addr_lo;
+       u32 ring_tail_off32_remote_addr_hi;
+       u32 ring_msi_addr_lo;
+       u32 ring_msi_addr_hi;
+       u32 msi_data;
+       u32 intr_info;
+       u32 info2;
+} __packed;
+
+/* host -> target FW  PPDU_STATS config message
+ *
+ * @details
+ * The following field definitions describe the format of the HTT host
+ * to target FW for PPDU_STATS_CFG msg.
+ * The message allows the host to configure the PPDU_STATS_IND messages
+ * produced by the target.
+ *
+ * |31          24|23          16|15           8|7            0|
+ * |-----------------------------------------------------------|
+ * |    REQ bit mask             |   pdev_mask  |   msg type   |
+ * |-----------------------------------------------------------|
+ * Header fields:
+ *  - MSG_TYPE
+ *    Bits 7:0
+ *    Purpose: identifies this is a req to configure ppdu_stats_ind from target
+ *    Value: 0x11
+ *  - PDEV_MASK
+ *    Bits 8:15
+ *    Purpose: identifies which pdevs this PPDU stats configuration applies to
+ *    Value: This is a overloaded field, refer to usage and interpretation of
+ *           PDEV in interface document.
+ *           Bit   8    :  Reserved for SOC stats
+ *           Bit 9 - 15 :  Indicates PDEV_MASK in DBDC
+ *                         Indicates MACID_MASK in DBS
+ *  - REQ_TLV_BIT_MASK
+ *    Bits 16:31
+ *    Purpose: each set bit indicates the corresponding PPDU stats TLV type
+ *        needs to be included in the target's PPDU_STATS_IND messages.
+ *    Value: refer htt_ppdu_stats_tlv_tag_t <<<???
+ *
+ */
+
+struct htt_ppdu_stats_cfg_cmd {
+       u32 msg;
+} __packed;
+
+#define HTT_PPDU_STATS_CFG_MSG_TYPE            GENMASK(7, 0)
+#define HTT_PPDU_STATS_CFG_PDEV_ID             GENMASK(16, 9)
+#define HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK    GENMASK(31, 16)
+
+enum htt_ppdu_stats_tag_type {
+       HTT_PPDU_STATS_TAG_COMMON,
+       HTT_PPDU_STATS_TAG_USR_COMMON,
+       HTT_PPDU_STATS_TAG_USR_RATE,
+       HTT_PPDU_STATS_TAG_USR_MPDU_ENQ_BITMAP_64,
+       HTT_PPDU_STATS_TAG_USR_MPDU_ENQ_BITMAP_256,
+       HTT_PPDU_STATS_TAG_SCH_CMD_STATUS,
+       HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON,
+       HTT_PPDU_STATS_TAG_USR_COMPLTN_BA_BITMAP_64,
+       HTT_PPDU_STATS_TAG_USR_COMPLTN_BA_BITMAP_256,
+       HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS,
+       HTT_PPDU_STATS_TAG_USR_COMPLTN_FLUSH,
+       HTT_PPDU_STATS_TAG_USR_COMMON_ARRAY,
+       HTT_PPDU_STATS_TAG_INFO,
+       HTT_PPDU_STATS_TAG_TX_MGMTCTRL_PAYLOAD,
+
+       /* New TLV's are added above to this line */
+       HTT_PPDU_STATS_TAG_MAX,
+};
+
+#define HTT_PPDU_STATS_TAG_DEFAULT (BIT(HTT_PPDU_STATS_TAG_COMMON) \
+                                  | BIT(HTT_PPDU_STATS_TAG_USR_COMMON) \
+                                  | BIT(HTT_PPDU_STATS_TAG_USR_RATE) \
+                                  | BIT(HTT_PPDU_STATS_TAG_SCH_CMD_STATUS) \
+                                  | BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON) \
+                                  | BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS) \
+                                  | BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_FLUSH) \
+                                  | BIT(HTT_PPDU_STATS_TAG_USR_COMMON_ARRAY))
+
+/* HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG Message
+ *
+ * details:
+ *    HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG message is sent by host to
+ *    configure RXDMA rings.
+ *    The configuration is per ring based and includes both packet subtypes
+ *    and PPDU/MPDU TLVs.
+ *
+ *    The message would appear as follows:
+ *
+ *    |31       26|25|24|23            16|15             8|7             0|
+ *    |-----------------+----------------+----------------+---------------|
+ *    |   rsvd1   |PS|SS|     ring_id    |     pdev_id    |    msg_type   |
+ *    |-------------------------------------------------------------------|
+ *    |              rsvd2               |           ring_buffer_size     |
+ *    |-------------------------------------------------------------------|
+ *    |                        packet_type_enable_flags_0                 |
+ *    |-------------------------------------------------------------------|
+ *    |                        packet_type_enable_flags_1                 |
+ *    |-------------------------------------------------------------------|
+ *    |                        packet_type_enable_flags_2                 |
+ *    |-------------------------------------------------------------------|
+ *    |                        packet_type_enable_flags_3                 |
+ *    |-------------------------------------------------------------------|
+ *    |                         tlv_filter_in_flags                       |
+ *    |-------------------------------------------------------------------|
+ * Where:
+ *     PS = pkt_swap
+ *     SS = status_swap
+ * The message is interpreted as follows:
+ * dword0 - b'0:7   - msg_type: This will be set to
+ *                    HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG
+ *          b'8:15  - pdev_id:
+ *                    0 (for rings at SOC/UMAC level),
+ *                    1/2/3 mac id (for rings at LMAC level)
+ *          b'16:23 - ring_id : Identify the ring to configure.
+ *                    More details can be got from enum htt_srng_ring_id
+ *          b'24    - status_swap: 1 is to swap status TLV
+ *          b'25    - pkt_swap:  1 is to swap packet TLV
+ *          b'26:31 - rsvd1:  reserved for future use
+ * dword1 - b'0:16  - ring_buffer_size: size of bufferes referenced by rx ring,
+ *                    in byte units.
+ *                    Valid only for HW_TO_SW_RING and SW_TO_HW_RING
+ *        - b'16:31 - rsvd2: Reserved for future use
+ * dword2 - b'0:31  - packet_type_enable_flags_0:
+ *                    Enable MGMT packet from 0b0000 to 0b1001
+ *                    bits from low to high: FP, MD, MO - 3 bits
+ *                        FP: Filter_Pass
+ *                        MD: Monitor_Direct
+ *                        MO: Monitor_Other
+ *                    10 mgmt subtypes * 3 bits -> 30 bits
+ *                    Refer to PKT_TYPE_ENABLE_FLAG0_xxx_MGMT_xxx defs
+ * dword3 - b'0:31  - packet_type_enable_flags_1:
+ *                    Enable MGMT packet from 0b1010 to 0b1111
+ *                    bits from low to high: FP, MD, MO - 3 bits
+ *                    Refer to PKT_TYPE_ENABLE_FLAG1_xxx_MGMT_xxx defs
+ * dword4 - b'0:31 -  packet_type_enable_flags_2:
+ *                    Enable CTRL packet from 0b0000 to 0b1001
+ *                    bits from low to high: FP, MD, MO - 3 bits
+ *                    Refer to PKT_TYPE_ENABLE_FLAG2_xxx_CTRL_xxx defs
+ * dword5 - b'0:31  - packet_type_enable_flags_3:
+ *                    Enable CTRL packet from 0b1010 to 0b1111,
+ *                    MCAST_DATA, UCAST_DATA, NULL_DATA
+ *                    bits from low to high: FP, MD, MO - 3 bits
+ *                    Refer to PKT_TYPE_ENABLE_FLAG3_xxx_CTRL_xxx defs
+ * dword6 - b'0:31 -  tlv_filter_in_flags:
+ *                    Filter in Attention/MPDU/PPDU/Header/User tlvs
+ *                    Refer to CFG_TLV_FILTER_IN_FLAG defs
+ */
+
+#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_MSG_TYPE   GENMASK(7, 0)
+#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID    GENMASK(15, 8)
+#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_RING_ID    GENMASK(23, 16)
+#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_SS         BIT(24)
+#define HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PS         BIT(25)
+
+#define HTT_RX_RING_SELECTION_CFG_CMD_INFO1_BUF_SIZE   GENMASK(15, 0)
+
+enum htt_rx_filter_tlv_flags {
+       HTT_RX_FILTER_TLV_FLAGS_MPDU_START              = BIT(0),
+       HTT_RX_FILTER_TLV_FLAGS_MSDU_START              = BIT(1),
+       HTT_RX_FILTER_TLV_FLAGS_RX_PACKET               = BIT(2),
+       HTT_RX_FILTER_TLV_FLAGS_MSDU_END                = BIT(3),
+       HTT_RX_FILTER_TLV_FLAGS_MPDU_END                = BIT(4),
+       HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER           = BIT(5),
+       HTT_RX_FILTER_TLV_FLAGS_PER_MSDU_HEADER         = BIT(6),
+       HTT_RX_FILTER_TLV_FLAGS_ATTENTION               = BIT(7),
+       HTT_RX_FILTER_TLV_FLAGS_PPDU_START              = BIT(8),
+       HTT_RX_FILTER_TLV_FLAGS_PPDU_END                = BIT(9),
+       HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS     = BIT(10),
+       HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT = BIT(11),
+       HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE    = BIT(12),
+};
+
+enum htt_rx_mgmt_pkt_filter_tlv_flags0 {
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_REQ          = BIT(0),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_REQ          = BIT(1),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_REQ          = BIT(2),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_RESP         = BIT(3),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_RESP         = BIT(4),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_RESP         = BIT(5),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_REQ        = BIT(6),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_REQ        = BIT(7),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_REQ        = BIT(8),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_RESP       = BIT(9),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_RESP       = BIT(10),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_RESP       = BIT(11),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_REQ          = BIT(12),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_REQ          = BIT(13),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_REQ          = BIT(14),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_RESP         = BIT(15),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_RESP         = BIT(16),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_RESP         = BIT(17),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_TIMING_ADV   = BIT(18),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_TIMING_ADV   = BIT(19),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_TIMING_ADV   = BIT(20),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_RESERVED_7         = BIT(21),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_RESERVED_7         = BIT(22),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_RESERVED_7         = BIT(23),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_BEACON             = BIT(24),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_BEACON             = BIT(25),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_BEACON             = BIT(26),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_ATIM               = BIT(27),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_ATIM               = BIT(28),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_ATIM               = BIT(29),
+};
+
+enum htt_rx_mgmt_pkt_filter_tlv_flags1 {
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_DISASSOC           = BIT(0),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_DISASSOC           = BIT(1),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_DISASSOC           = BIT(2),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_AUTH               = BIT(3),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_AUTH               = BIT(4),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_AUTH               = BIT(5),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_DEAUTH             = BIT(6),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_DEAUTH             = BIT(7),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_DEAUTH             = BIT(8),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION             = BIT(9),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION             = BIT(10),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION             = BIT(11),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION_NOACK       = BIT(12),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION_NOACK       = BIT(13),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION_NOACK       = BIT(14),
+       HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_RESERVED_15        = BIT(15),
+       HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_RESERVED_15        = BIT(16),
+       HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_RESERVED_15        = BIT(17),
+};
+
+enum htt_rx_ctrl_pkt_filter_tlv_flags2 {
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_1    = BIT(0),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_1    = BIT(1),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_1    = BIT(2),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_2    = BIT(3),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_2    = BIT(4),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_2    = BIT(5),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_TRIGGER       = BIT(6),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_TRIGGER       = BIT(7),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_TRIGGER       = BIT(8),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_4    = BIT(9),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_4    = BIT(10),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_4    = BIT(11),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_BF_REP_POLL   = BIT(12),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_BF_REP_POLL   = BIT(13),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_BF_REP_POLL   = BIT(14),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_VHT_NDP       = BIT(15),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_VHT_NDP       = BIT(16),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_VHT_NDP       = BIT(17),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_FRAME_EXT     = BIT(18),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_FRAME_EXT     = BIT(19),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_FRAME_EXT     = BIT(20),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_WRAPPER       = BIT(21),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_WRAPPER       = BIT(22),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_WRAPPER       = BIT(23),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_BAR                = BIT(24),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_BAR                = BIT(25),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_BAR                = BIT(26),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_BA                 = BIT(27),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_BA                 = BIT(28),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_BA                 = BIT(29),
+};
+
+enum htt_rx_ctrl_pkt_filter_tlv_flags3 {
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_PSPOLL             = BIT(0),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_PSPOLL             = BIT(1),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_PSPOLL             = BIT(2),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_RTS                = BIT(3),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_RTS                = BIT(4),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_RTS                = BIT(5),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_CTS                = BIT(6),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_CTS                = BIT(7),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_CTS                = BIT(8),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_ACK                = BIT(9),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_ACK                = BIT(10),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_ACK                = BIT(11),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND              = BIT(12),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND              = BIT(13),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND              = BIT(14),
+       HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND_ACK          = BIT(15),
+       HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND_ACK          = BIT(16),
+       HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND_ACK          = BIT(17),
+};
+
+enum htt_rx_data_pkt_filter_tlv_flasg3 {
+       HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_MCAST      = BIT(18),
+       HTT_RX_MD_DATA_PKT_FILTER_TLV_FLASG3_MCAST      = BIT(19),
+       HTT_RX_MO_DATA_PKT_FILTER_TLV_FLASG3_MCAST      = BIT(20),
+       HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_UCAST      = BIT(21),
+       HTT_RX_MD_DATA_PKT_FILTER_TLV_FLASG3_UCAST      = BIT(22),
+       HTT_RX_MO_DATA_PKT_FILTER_TLV_FLASG3_UCAST      = BIT(23),
+       HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_NULL_DATA  = BIT(24),
+       HTT_RX_MD_DATA_PKT_FILTER_TLV_FLASG3_NULL_DATA  = BIT(25),
+       HTT_RX_MO_DATA_PKT_FILTER_TLV_FLASG3_NULL_DATA  = BIT(26),
+};
+
+#define HTT_RX_FP_MGMT_FILTER_FLAGS0 \
+       (HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_REQ \
+       | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_RESP \
+       | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_REQ \
+       | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_RESP \
+       | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_REQ \
+       | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_RESP \
+       | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_TIMING_ADV \
+       | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_BEACON \
+       | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_ATIM)
+
+#define HTT_RX_MD_MGMT_FILTER_FLAGS0 \
+       (HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_REQ \
+       | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_RESP \
+       | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_REQ \
+       | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_RESP \
+       | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_REQ \
+       | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_RESP \
+       | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_TIMING_ADV \
+       | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_BEACON \
+       | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS0_ATIM)
+
+#define HTT_RX_MO_MGMT_FILTER_FLAGS0 \
+       (HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_REQ \
+       | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_ASSOC_RESP \
+       | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_REQ \
+       | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_REASSOC_RESP \
+       | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_REQ \
+       | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_RESP \
+       | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_PROBE_TIMING_ADV \
+       | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_BEACON \
+       | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_ATIM)
+
+#define HTT_RX_FP_MGMT_FILTER_FLAGS1 (HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_DISASSOC \
+                                    | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_AUTH \
+                                    | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_DEAUTH \
+                                    | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION \
+                                    | HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION_NOACK)
+
+#define HTT_RX_MD_MGMT_FILTER_FLAGS1 (HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_DISASSOC \
+                                    | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_AUTH \
+                                    | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_DEAUTH \
+                                    | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION \
+                                    | HTT_RX_MD_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION_NOACK)
+
+#define HTT_RX_MO_MGMT_FILTER_FLAGS1 (HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_DISASSOC \
+                                    | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_AUTH \
+                                    | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_DEAUTH \
+                                    | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION \
+                                    | HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_ACTION_NOACK)
+
+#define HTT_RX_FP_CTRL_FILTER_FLASG2 (HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_WRAPPER \
+                                    | HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_BAR \
+                                    | HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_BA)
+
+#define HTT_RX_MD_CTRL_FILTER_FLASG2 (HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_WRAPPER \
+                                    | HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_BAR \
+                                    | HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS2_BA)
+
+#define HTT_RX_MO_CTRL_FILTER_FLASG2 (HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_WRAPPER \
+                                    | HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_BAR \
+                                    | HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_BA)
+
+#define HTT_RX_FP_CTRL_FILTER_FLASG3 (HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_PSPOLL \
+                                    | HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_RTS \
+                                    | HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_CTS \
+                                    | HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_ACK \
+                                    | HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND \
+                                    | HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND_ACK)
+
+#define HTT_RX_MD_CTRL_FILTER_FLASG3 (HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_PSPOLL \
+                                    | HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_RTS \
+                                    | HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_CTS \
+                                    | HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_ACK \
+                                    | HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND \
+                                    | HTT_RX_MD_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND_ACK)
+
+#define HTT_RX_MO_CTRL_FILTER_FLASG3 (HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_PSPOLL \
+                                    | HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_RTS \
+                                    | HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_CTS \
+                                    | HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_ACK \
+                                    | HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND \
+                                    | HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS3_CFEND_ACK)
+
+#define HTT_RX_FP_DATA_FILTER_FLASG3 (HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_MCAST \
+                                    | HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_UCAST \
+                                    | HTT_RX_FP_DATA_PKT_FILTER_TLV_FLASG3_NULL_DATA)
+
+#define HTT_RX_MD_DATA_FILTER_FLASG3 (HTT_RX_MD_DATA_PKT_FILTER_TLV_FLASG3_MCAST \
+                                    | HTT_RX_MD_DATA_PKT_FILTER_TLV_FLASG3_UCAST \
+                                    | HTT_RX_MD_DATA_PKT_FILTER_TLV_FLASG3_NULL_DATA)
+
+#define HTT_RX_MO_DATA_FILTER_FLASG3 (HTT_RX_MO_DATA_PKT_FILTER_TLV_FLASG3_MCAST \
+                                    | HTT_RX_MO_DATA_PKT_FILTER_TLV_FLASG3_UCAST \
+                                    | HTT_RX_MO_DATA_PKT_FILTER_TLV_FLASG3_NULL_DATA)
+
+#define HTT_RX_MON_FP_MGMT_FILTER_FLAGS0 \
+               (HTT_RX_FP_MGMT_FILTER_FLAGS0 | \
+               HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS0_RESERVED_7)
+
+#define HTT_RX_MON_MO_MGMT_FILTER_FLAGS0 \
+               (HTT_RX_MO_MGMT_FILTER_FLAGS0 | \
+               HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS0_RESERVED_7)
+
+#define HTT_RX_MON_FP_MGMT_FILTER_FLAGS1 \
+               (HTT_RX_FP_MGMT_FILTER_FLAGS1 | \
+               HTT_RX_FP_MGMT_PKT_FILTER_TLV_FLAGS1_RESERVED_15)
+
+#define HTT_RX_MON_MO_MGMT_FILTER_FLAGS1 \
+               (HTT_RX_MO_MGMT_FILTER_FLAGS1 | \
+               HTT_RX_MO_MGMT_PKT_FILTER_TLV_FLAGS1_RESERVED_15)
+
+#define HTT_RX_MON_FP_CTRL_FILTER_FLASG2 \
+               (HTT_RX_FP_CTRL_FILTER_FLASG2 | \
+               HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_1 | \
+               HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_2 | \
+               HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_TRIGGER | \
+               HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_4 | \
+               HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_BF_REP_POLL | \
+               HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_VHT_NDP | \
+               HTT_RX_FP_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_FRAME_EXT)
+
+#define HTT_RX_MON_MO_CTRL_FILTER_FLASG2 \
+               (HTT_RX_MO_CTRL_FILTER_FLASG2 | \
+               HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_1 | \
+               HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_2 | \
+               HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_TRIGGER | \
+               HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_RESERVED_4 | \
+               HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_BF_REP_POLL | \
+               HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_VHT_NDP | \
+               HTT_RX_MO_CTRL_PKT_FILTER_TLV_FLAGS2_CTRL_FRAME_EXT)
+
+#define HTT_RX_MON_FP_CTRL_FILTER_FLASG3 HTT_RX_FP_CTRL_FILTER_FLASG3
+
+#define HTT_RX_MON_MO_CTRL_FILTER_FLASG3 HTT_RX_MO_CTRL_FILTER_FLASG3
+
+#define HTT_RX_MON_FP_DATA_FILTER_FLASG3 HTT_RX_FP_DATA_FILTER_FLASG3
+
+#define HTT_RX_MON_MO_DATA_FILTER_FLASG3 HTT_RX_MO_DATA_FILTER_FLASG3
+
+#define HTT_RX_MON_FILTER_TLV_FLAGS \
+               (HTT_RX_FILTER_TLV_FLAGS_MPDU_START | \
+               HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
+               HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
+               HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
+               HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
+               HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE)
+
+#define HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING \
+               (HTT_RX_FILTER_TLV_FLAGS_MPDU_START | \
+               HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
+               HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
+               HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
+               HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
+               HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE)
+
+#define HTT_RX_MON_FILTER_TLV_FLAGS_MON_BUF_RING \
+               (HTT_RX_FILTER_TLV_FLAGS_MPDU_START | \
+               HTT_RX_FILTER_TLV_FLAGS_MSDU_START | \
+               HTT_RX_FILTER_TLV_FLAGS_RX_PACKET | \
+               HTT_RX_FILTER_TLV_FLAGS_MSDU_END | \
+               HTT_RX_FILTER_TLV_FLAGS_MPDU_END | \
+               HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER | \
+               HTT_RX_FILTER_TLV_FLAGS_PER_MSDU_HEADER | \
+               HTT_RX_FILTER_TLV_FLAGS_ATTENTION)
+
+struct htt_rx_ring_selection_cfg_cmd {
+       u32 info0;
+       u32 info1;
+       u32 pkt_type_en_flags0;
+       u32 pkt_type_en_flags1;
+       u32 pkt_type_en_flags2;
+       u32 pkt_type_en_flags3;
+       u32 rx_filter_tlv;
+} __packed;
+
+struct htt_rx_ring_tlv_filter {
+       u32 rx_filter; /* see htt_rx_filter_tlv_flags */
+       u32 pkt_filter_flags0; /* MGMT */
+       u32 pkt_filter_flags1; /* MGMT */
+       u32 pkt_filter_flags2; /* CTRL */
+       u32 pkt_filter_flags3; /* DATA */
+};
+
+/* HTT message target->host */
+
+enum htt_t2h_msg_type {
+       HTT_T2H_MSG_TYPE_VERSION_CONF,
+       HTT_T2H_MSG_TYPE_RX_ADDBA       = 0x5,
+       HTT_T2H_MSG_TYPE_PKTLOG         = 0x8,
+       HTT_T2H_MSG_TYPE_SEC_IND        = 0xb,
+       HTT_T2H_MSG_TYPE_PEER_MAP       = 0x1e,
+       HTT_T2H_MSG_TYPE_PEER_UNMAP     = 0x1f,
+       HTT_T2H_MSG_TYPE_PPDU_STATS_IND = 0x1d,
+       HTT_T2H_MSG_TYPE_EXT_STATS_CONF = 0x1c,
+};
+
+#define HTT_TARGET_VERSION_MAJOR 3
+
+#define HTT_T2H_MSG_TYPE               GENMASK(7, 0)
+#define HTT_T2H_VERSION_CONF_MINOR     GENMASK(15, 8)
+#define HTT_T2H_VERSION_CONF_MAJOR     GENMASK(23, 16)
+
+struct htt_t2h_version_conf_msg {
+       u32 version;
+} __packed;
+
+#define HTT_T2H_PEER_MAP_INFO_VDEV_ID  GENMASK(15, 8)
+#define HTT_T2H_PEER_MAP_INFO_PEER_ID  GENMASK(31, 16)
+#define HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16    GENMASK(15, 0)
+#define HTT_T2H_PEER_MAP_INFO1_HW_PEER_ID      GENMASK(31, 16)
+#define HTT_T2H_PEER_MAP_INFO2_AST_HASH_VAL    GENMASK(15, 0)
+#define HTT_T2H_PEER_MAP_INFO2_NEXT_HOP_M      BIT(16)
+#define HTT_T2H_PEER_MAP_INFO2_NEXT_HOP_S      16
+
+struct htt_t2h_peer_map_event {
+       u32 info;
+       u32 mac_addr_l32;
+       u32 info1;
+       u32 info2;
+} __packed;
+
+#define HTT_T2H_PEER_UNMAP_INFO_VDEV_ID        HTT_T2H_PEER_MAP_INFO_VDEV_ID
+#define HTT_T2H_PEER_UNMAP_INFO_PEER_ID        HTT_T2H_PEER_MAP_INFO_PEER_ID
+#define HTT_T2H_PEER_UNMAP_INFO1_MAC_ADDR_H16 \
+                                       HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16
+#define HTT_T2H_PEER_MAP_INFO1_NEXT_HOP_M HTT_T2H_PEER_MAP_INFO2_NEXT_HOP_M
+#define HTT_T2H_PEER_MAP_INFO1_NEXT_HOP_S HTT_T2H_PEER_MAP_INFO2_NEXT_HOP_S
+
+struct htt_t2h_peer_unmap_event {
+       u32 info;
+       u32 mac_addr_l32;
+       u32 info1;
+} __packed;
+
+struct htt_resp_msg {
+       union {
+               struct htt_t2h_version_conf_msg version_msg;
+               struct htt_t2h_peer_map_event peer_map_ev;
+               struct htt_t2h_peer_unmap_event peer_unmap_ev;
+       };
+} __packed;
+
+/* ppdu stats
+ *
+ * @details
+ * The following field definitions describe the format of the HTT target
+ * to host ppdu stats indication message.
+ *
+ *
+ * |31                         16|15   12|11   10|9      8|7            0 |
+ * |----------------------------------------------------------------------|
+ * |    payload_size             | rsvd  |pdev_id|mac_id  |    msg type   |
+ * |----------------------------------------------------------------------|
+ * |                          ppdu_id                                     |
+ * |----------------------------------------------------------------------|
+ * |                        Timestamp in us                               |
+ * |----------------------------------------------------------------------|
+ * |                          reserved                                    |
+ * |----------------------------------------------------------------------|
+ * |                    type-specific stats info                          |
+ * |                     (see htt_ppdu_stats.h)                           |
+ * |----------------------------------------------------------------------|
+ * Header fields:
+ *  - MSG_TYPE
+ *    Bits 7:0
+ *    Purpose: Identifies this is a PPDU STATS indication
+ *             message.
+ *    Value: 0x1d
+ *  - mac_id
+ *    Bits 9:8
+ *    Purpose: mac_id of this ppdu_id
+ *    Value: 0-3
+ *  - pdev_id
+ *    Bits 11:10
+ *    Purpose: pdev_id of this ppdu_id
+ *    Value: 0-3
+ *     0 (for rings at SOC level),
+ *     1/2/3 PDEV -> 0/1/2
+ *  - payload_size
+ *    Bits 31:16
+ *    Purpose: total tlv size
+ *    Value: payload_size in bytes
+ */
+
+#define HTT_T2H_PPDU_STATS_INFO_PDEV_ID GENMASK(11, 10)
+#define HTT_T2H_PPDU_STATS_INFO_PAYLOAD_SIZE GENMASK(31, 16)
+
+struct ath11k_htt_ppdu_stats_msg {
+       u32 info;
+       u32 ppdu_id;
+       u32 timestamp;
+       u32 rsvd;
+       u8 data[0];
+} __packed;
+
+struct htt_tlv {
+       u32 header;
+       u8 value[0];
+} __packed;
+
+#define HTT_TLV_TAG                    GENMASK(11, 0)
+#define HTT_TLV_LEN                    GENMASK(23, 12)
+
+enum HTT_PPDU_STATS_BW {
+       HTT_PPDU_STATS_BANDWIDTH_5MHZ   = 0,
+       HTT_PPDU_STATS_BANDWIDTH_10MHZ  = 1,
+       HTT_PPDU_STATS_BANDWIDTH_20MHZ  = 2,
+       HTT_PPDU_STATS_BANDWIDTH_40MHZ  = 3,
+       HTT_PPDU_STATS_BANDWIDTH_80MHZ  = 4,
+       HTT_PPDU_STATS_BANDWIDTH_160MHZ = 5, /* includes 80+80 */
+       HTT_PPDU_STATS_BANDWIDTH_DYN    = 6,
+};
+
+#define HTT_PPDU_STATS_CMN_FLAGS_FRAME_TYPE_M  GENMASK(7, 0)
+#define HTT_PPDU_STATS_CMN_FLAGS_QUEUE_TYPE_M  GENMASK(15, 8)
+/* bw - HTT_PPDU_STATS_BW */
+#define HTT_PPDU_STATS_CMN_FLAGS_BW_M          GENMASK(19, 16)
+
+struct htt_ppdu_stats_common {
+       u32 ppdu_id;
+       u16 sched_cmdid;
+       u8 ring_id;
+       u8 num_users;
+       u32 flags; /* %HTT_PPDU_STATS_COMMON_FLAGS_*/
+       u32 chain_mask;
+       u32 fes_duration_us; /* frame exchange sequence */
+       u32 ppdu_sch_eval_start_tstmp_us;
+       u32 ppdu_sch_end_tstmp_us;
+       u32 ppdu_start_tstmp_us;
+       /* BIT [15 :  0] - phy mode (WLAN_PHY_MODE) with which ppdu was transmitted
+        * BIT [31 : 16] - bandwidth (in MHz) with which ppdu was transmitted
+        */
+       u16 phy_mode;
+       u16 bw_mhz;
+} __packed;
+
+#define HTT_PPDU_STATS_USER_RATE_INFO0_USER_POS_M      GENMASK(3, 0)
+#define HTT_PPDU_STATS_USER_RATE_INFO0_MU_GROUP_ID_M   GENMASK(11, 4)
+
+#define HTT_PPDU_STATS_USER_RATE_INFO1_RESP_TYPE_VALD_M        BIT(0)
+#define HTT_PPDU_STATS_USER_RATE_INFO1_PPDU_TYPE_M     GENMASK(5, 1)
+
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_LTF_SIZE_M      GENMASK(1, 0)
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_STBC_M          BIT(2)
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_HE_RE_M         BIT(3)
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_TXBF_M          GENMASK(7, 4)
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_BW_M            GENMASK(11, 8)
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_NSS_M           GENMASK(15, 12)
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_MCS_M           GENMASK(19, 16)
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_PREAMBLE_M      GENMASK(23, 20)
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_GI_M            GENMASK(27, 24)
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_DCM_M           BIT(28)
+#define HTT_PPDU_STATS_USER_RATE_FLAGS_LDPC_M          BIT(29)
+
+#define HTT_USR_RATE_PREAMBLE(_val) \
+               FIELD_GET(HTT_PPDU_STATS_USER_RATE_FLAGS_PREAMBLE_M, _val)
+#define HTT_USR_RATE_BW(_val) \
+               FIELD_GET(HTT_PPDU_STATS_USER_RATE_FLAGS_BW_M, _val)
+#define HTT_USR_RATE_NSS(_val) \
+               FIELD_GET(HTT_PPDU_STATS_USER_RATE_FLAGS_NSS_M, _val)
+#define HTT_USR_RATE_MCS(_val) \
+               FIELD_GET(HTT_PPDU_STATS_USER_RATE_FLAGS_MCS_M, _val)
+#define HTT_USR_RATE_GI(_val) \
+               FIELD_GET(HTT_PPDU_STATS_USER_RATE_FLAGS_GI_M, _val)
+
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_LTF_SIZE_M         GENMASK(1, 0)
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_STBC_M             BIT(2)
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_HE_RE_M            BIT(3)
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_TXBF_M             GENMASK(7, 4)
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_BW_M               GENMASK(11, 8)
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_NSS_M              GENMASK(15, 12)
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_MCS_M              GENMASK(19, 16)
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_PREAMBLE_M         GENMASK(23, 20)
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_GI_M               GENMASK(27, 24)
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_DCM_M              BIT(28)
+#define HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_LDPC_M             BIT(29)
+
+struct htt_ppdu_stats_user_rate {
+       u8 tid_num;
+       u8 reserved0;
+       u16 sw_peer_id;
+       u32 info0; /* %HTT_PPDU_STATS_USER_RATE_INFO0_*/
+       u16 ru_end;
+       u16 ru_start;
+       u16 resp_ru_end;
+       u16 resp_ru_start;
+       u32 info1; /* %HTT_PPDU_STATS_USER_RATE_INFO1_ */
+       u32 rate_flags; /* %HTT_PPDU_STATS_USER_RATE_FLAGS_ */
+       /* Note: resp_rate_info is only valid for if resp_type is UL */
+       u32 resp_rate_flags; /* %HTT_PPDU_STATS_USER_RATE_RESP_FLAGS_ */
+} __packed;
+
+#define HTT_PPDU_STATS_TX_INFO_FLAGS_RATECODE_M                GENMASK(7, 0)
+#define HTT_PPDU_STATS_TX_INFO_FLAGS_IS_AMPDU_M                BIT(8)
+#define HTT_PPDU_STATS_TX_INFO_FLAGS_BA_ACK_FAILED_M   GENMASK(10, 9)
+#define HTT_PPDU_STATS_TX_INFO_FLAGS_BW_M              GENMASK(13, 11)
+#define HTT_PPDU_STATS_TX_INFO_FLAGS_SGI_M             BIT(14)
+#define HTT_PPDU_STATS_TX_INFO_FLAGS_PEERID_M          GENMASK(31, 16)
+
+#define HTT_TX_INFO_IS_AMSDU(_flags) \
+                       FIELD_GET(HTT_PPDU_STATS_TX_INFO_FLAGS_IS_AMPDU_M, _flags)
+#define HTT_TX_INFO_BA_ACK_FAILED(_flags) \
+                       FIELD_GET(HTT_PPDU_STATS_TX_INFO_FLAGS_BA_ACK_FAILED_M, _flags)
+#define HTT_TX_INFO_RATECODE(_flags) \
+                       FIELD_GET(HTT_PPDU_STATS_TX_INFO_FLAGS_RATECODE_M, _flags)
+#define HTT_TX_INFO_PEERID(_flags) \
+                       FIELD_GET(HTT_PPDU_STATS_TX_INFO_FLAGS_PEERID_M, _flags)
+
+struct htt_tx_ppdu_stats_info {
+       struct htt_tlv tlv_hdr;
+       u32 tx_success_bytes;
+       u32 tx_retry_bytes;
+       u32 tx_failed_bytes;
+       u32 flags; /* %HTT_PPDU_STATS_TX_INFO_FLAGS_ */
+       u16 tx_success_msdus;
+       u16 tx_retry_msdus;
+       u16 tx_failed_msdus;
+       u16 tx_duration; /* united in us */
+} __packed;
+
+enum  htt_ppdu_stats_usr_compln_status {
+       HTT_PPDU_STATS_USER_STATUS_OK,
+       HTT_PPDU_STATS_USER_STATUS_FILTERED,
+       HTT_PPDU_STATS_USER_STATUS_RESP_TIMEOUT,
+       HTT_PPDU_STATS_USER_STATUS_RESP_MISMATCH,
+       HTT_PPDU_STATS_USER_STATUS_ABORT,
+};
+
+#define HTT_PPDU_STATS_USR_CMPLTN_CMN_FLAGS_LONG_RETRY_M       GENMASK(3, 0)
+#define HTT_PPDU_STATS_USR_CMPLTN_CMN_FLAGS_SHORT_RETRY_M      GENMASK(7, 4)
+#define HTT_PPDU_STATS_USR_CMPLTN_CMN_FLAGS_IS_AMPDU_M         BIT(8)
+#define HTT_PPDU_STATS_USR_CMPLTN_CMN_FLAGS_RESP_TYPE_M                GENMASK(12, 9)
+
+#define HTT_USR_CMPLTN_IS_AMPDU(_val) \
+           FIELD_GET(HTT_PPDU_STATS_USR_CMPLTN_CMN_FLAGS_IS_AMPDU_M, _val)
+#define HTT_USR_CMPLTN_LONG_RETRY(_val) \
+           FIELD_GET(HTT_PPDU_STATS_USR_CMPLTN_CMN_FLAGS_LONG_RETRY_M, _val)
+#define HTT_USR_CMPLTN_SHORT_RETRY(_val) \
+           FIELD_GET(HTT_PPDU_STATS_USR_CMPLTN_CMN_FLAGS_SHORT_RETRY_M, _val)
+
+struct htt_ppdu_stats_usr_cmpltn_cmn {
+       u8 status;
+       u8 tid_num;
+       u16 sw_peer_id;
+       /* RSSI value of last ack packet (units = dB above noise floor) */
+       u32 ack_rssi;
+       u16 mpdu_tried;
+       u16 mpdu_success;
+       u32 flags; /* %HTT_PPDU_STATS_USR_CMPLTN_CMN_FLAGS_LONG_RETRIES*/
+} __packed;
+
+#define HTT_PPDU_STATS_ACK_BA_INFO_NUM_MPDU_M  GENMASK(8, 0)
+#define HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M  GENMASK(24, 9)
+#define HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM     GENMASK(3, 0)
+
+struct htt_ppdu_stats_usr_cmpltn_ack_ba_status {
+       u32 ppdu_id;
+       u16 sw_peer_id;
+       u16 reserved0;
+       u32 info; /* %HTT_PPDU_STATS_USR_CMPLTN_CMN_INFO_ */
+       u16 current_seq;
+       u16 start_seq;
+       u32 success_bytes;
+} __packed;
+
+struct htt_ppdu_stats_usr_cmn_array {
+       struct htt_tlv tlv_hdr;
+       u32 num_ppdu_stats;
+       /* tx_ppdu_stats_info is filled by multiple struct htt_tx_ppdu_stats_info
+        * elements.
+        * tx_ppdu_stats_info is variable length, with length =
+        *     number_of_ppdu_stats * sizeof (struct htt_tx_ppdu_stats_info)
+        */
+       struct htt_tx_ppdu_stats_info tx_ppdu_info[0];
+} __packed;
+
+struct htt_ppdu_user_stats {
+       u16 peer_id;
+       u32 tlv_flags;
+       bool is_valid_peer_id;
+       struct htt_ppdu_stats_user_rate rate;
+       struct htt_ppdu_stats_usr_cmpltn_cmn cmpltn_cmn;
+       struct htt_ppdu_stats_usr_cmpltn_ack_ba_status ack_ba;
+};
+
+#define HTT_PPDU_STATS_MAX_USERS       8
+#define HTT_PPDU_DESC_MAX_DEPTH        16
+
+struct htt_ppdu_stats {
+       struct htt_ppdu_stats_common common;
+       struct htt_ppdu_user_stats user_stats[HTT_PPDU_STATS_MAX_USERS];
+};
+
+struct htt_ppdu_stats_info {
+       u32 ppdu_id;
+       struct htt_ppdu_stats ppdu_stats;
+       struct list_head list;
+};
+
+/**
+ * @brief target -> host packet log message
+ *
+ * @details
+ * The following field definitions describe the format of the packet log
+ * message sent from the target to the host.
+ * The message consists of a 4-octet header,followed by a variable number
+ * of 32-bit character values.
+ *
+ * |31                         16|15  12|11   10|9    8|7            0|
+ * |------------------------------------------------------------------|
+ * |        payload_size         | rsvd |pdev_id|mac_id|   msg type   |
+ * |------------------------------------------------------------------|
+ * |                              payload                             |
+ * |------------------------------------------------------------------|
+ *   - MSG_TYPE
+ *     Bits 7:0
+ *     Purpose: identifies this as a pktlog message
+ *     Value: HTT_T2H_MSG_TYPE_PKTLOG
+ *   - mac_id
+ *     Bits 9:8
+ *     Purpose: identifies which MAC/PHY instance generated this pktlog info
+ *     Value: 0-3
+ *   - pdev_id
+ *     Bits 11:10
+ *     Purpose: pdev_id
+ *     Value: 0-3
+ *     0 (for rings at SOC level),
+ *     1/2/3 PDEV -> 0/1/2
+ *   - payload_size
+ *     Bits 31:16
+ *     Purpose: explicitly specify the payload size
+ *     Value: payload size in bytes (payload size is a multiple of 4 bytes)
+ */
+struct htt_pktlog_msg {
+       u32 hdr;
+       u8 payload[0];
+};
+
+/**
+ * @brief host -> target FW extended statistics retrieve
+ *
+ * @details
+ * The following field definitions describe the format of the HTT host
+ * to target FW extended stats retrieve message.
+ * The message specifies the type of stats the host wants to retrieve.
+ *
+ * |31          24|23          16|15           8|7            0|
+ * |-----------------------------------------------------------|
+ * |   reserved   | stats type   |   pdev_mask  |   msg type   |
+ * |-----------------------------------------------------------|
+ * |                   config param [0]                        |
+ * |-----------------------------------------------------------|
+ * |                   config param [1]                        |
+ * |-----------------------------------------------------------|
+ * |                   config param [2]                        |
+ * |-----------------------------------------------------------|
+ * |                   config param [3]                        |
+ * |-----------------------------------------------------------|
+ * |                         reserved                          |
+ * |-----------------------------------------------------------|
+ * |                        cookie LSBs                        |
+ * |-----------------------------------------------------------|
+ * |                        cookie MSBs                        |
+ * |-----------------------------------------------------------|
+ * Header fields:
+ *  - MSG_TYPE
+ *    Bits 7:0
+ *    Purpose: identifies this is a extended stats upload request message
+ *    Value: 0x10
+ *  - PDEV_MASK
+ *    Bits 8:15
+ *    Purpose: identifies the mask of PDEVs to retrieve stats from
+ *    Value: This is a overloaded field, refer to usage and interpretation of
+ *           PDEV in interface document.
+ *           Bit   8    :  Reserved for SOC stats
+ *           Bit 9 - 15 :  Indicates PDEV_MASK in DBDC
+ *                         Indicates MACID_MASK in DBS
+ *  - STATS_TYPE
+ *    Bits 23:16
+ *    Purpose: identifies which FW statistics to upload
+ *    Value: Defined by htt_dbg_ext_stats_type (see htt_stats.h)
+ *  - Reserved
+ *    Bits 31:24
+ *  - CONFIG_PARAM [0]
+ *    Bits 31:0
+ *    Purpose: give an opaque configuration value to the specified stats type
+ *    Value: stats-type specific configuration value
+ *           Refer to htt_stats.h for interpretation for each stats sub_type
+ *  - CONFIG_PARAM [1]
+ *    Bits 31:0
+ *    Purpose: give an opaque configuration value to the specified stats type
+ *    Value: stats-type specific configuration value
+ *           Refer to htt_stats.h for interpretation for each stats sub_type
+ *  - CONFIG_PARAM [2]
+ *    Bits 31:0
+ *    Purpose: give an opaque configuration value to the specified stats type
+ *    Value: stats-type specific configuration value
+ *           Refer to htt_stats.h for interpretation for each stats sub_type
+ *  - CONFIG_PARAM [3]
+ *    Bits 31:0
+ *    Purpose: give an opaque configuration value to the specified stats type
+ *    Value: stats-type specific configuration value
+ *           Refer to htt_stats.h for interpretation for each stats sub_type
+ *  - Reserved [31:0] for future use.
+ *  - COOKIE_LSBS
+ *    Bits 31:0
+ *    Purpose: Provide a mechanism to match a target->host stats confirmation
+ *        message with its preceding host->target stats request message.
+ *    Value: LSBs of the opaque cookie specified by the host-side requestor
+ *  - COOKIE_MSBS
+ *    Bits 31:0
+ *    Purpose: Provide a mechanism to match a target->host stats confirmation
+ *        message with its preceding host->target stats request message.
+ *    Value: MSBs of the opaque cookie specified by the host-side requestor
+ */
+
+struct htt_ext_stats_cfg_hdr {
+       u8 msg_type;
+       u8 pdev_mask;
+       u8 stats_type;
+       u8 reserved;
+} __packed;
+
+struct htt_ext_stats_cfg_cmd {
+       struct htt_ext_stats_cfg_hdr hdr;
+       u32 cfg_param0;
+       u32 cfg_param1;
+       u32 cfg_param2;
+       u32 cfg_param3;
+       u32 reserved;
+       u32 cookie_lsb;
+       u32 cookie_msb;
+} __packed;
+
+/* htt stats config default params */
+#define HTT_STAT_DEFAULT_RESET_START_OFFSET 0
+#define HTT_STAT_DEFAULT_CFG0_ALL_HWQS 0xffffffff
+#define HTT_STAT_DEFAULT_CFG0_ALL_TXQS 0xffffffff
+#define HTT_STAT_DEFAULT_CFG0_ALL_CMDQS 0xffff
+#define HTT_STAT_DEFAULT_CFG0_ALL_RINGS 0xffff
+#define HTT_STAT_DEFAULT_CFG0_ACTIVE_PEERS 0xff
+#define HTT_STAT_DEFAULT_CFG0_CCA_CUMULATIVE 0x10
+#define HTT_STAT_DEFAULT_CFG0_ACTIVE_VDEVS 0xff
+
+/* HTT_DBG_EXT_STATS_PEER_INFO
+ * PARAMS:
+ * @config_param0:
+ *  [Bit0] - [0] for sw_peer_id, [1] for mac_addr based request
+ *  [Bit15 : Bit 1] htt_peer_stats_req_mode_t
+ *  [Bit31 : Bit16] sw_peer_id
+ * @config_param1:
+ *  peer_stats_req_type_mask:32 (enum htt_peer_stats_tlv_enum)
+ *   0 bit htt_peer_stats_cmn_tlv
+ *   1 bit htt_peer_details_tlv
+ *   2 bit htt_tx_peer_rate_stats_tlv
+ *   3 bit htt_rx_peer_rate_stats_tlv
+ *   4 bit htt_tx_tid_stats_tlv/htt_tx_tid_stats_v1_tlv
+ *   5 bit htt_rx_tid_stats_tlv
+ *   6 bit htt_msdu_flow_stats_tlv
+ * @config_param2: [Bit31 : Bit0] mac_addr31to0
+ * @config_param3: [Bit15 : Bit0] mac_addr47to32
+ *                [Bit31 : Bit16] reserved
+ */
+#define HTT_STAT_PEER_INFO_MAC_ADDR BIT(0)
+#define HTT_STAT_DEFAULT_PEER_REQ_TYPE 0x7f
+
+/* Used to set different configs to the specified stats type.*/
+struct htt_ext_stats_cfg_params {
+       u32 cfg0;
+       u32 cfg1;
+       u32 cfg2;
+       u32 cfg3;
+};
+
+/**
+ * @brief target -> host extended statistics upload
+ *
+ * @details
+ * The following field definitions describe the format of the HTT target
+ * to host stats upload confirmation message.
+ * The message contains a cookie echoed from the HTT host->target stats
+ * upload request, which identifies which request the confirmation is
+ * for, and a single stats can span over multiple HTT stats indication
+ * due to the HTT message size limitation so every HTT ext stats indication
+ * will have tag-length-value stats information elements.
+ * The tag-length header for each HTT stats IND message also includes a
+ * status field, to indicate whether the request for the stat type in
+ * question was fully met, partially met, unable to be met, or invalid
+ * (if the stat type in question is disabled in the target).
+ * A Done bit 1's indicate the end of the of stats info elements.
+ *
+ *
+ * |31                         16|15    12|11|10 8|7   5|4       0|
+ * |--------------------------------------------------------------|
+ * |                   reserved                   |    msg type   |
+ * |--------------------------------------------------------------|
+ * |                         cookie LSBs                          |
+ * |--------------------------------------------------------------|
+ * |                         cookie MSBs                          |
+ * |--------------------------------------------------------------|
+ * |      stats entry length     | rsvd   | D|  S |   stat type   |
+ * |--------------------------------------------------------------|
+ * |                   type-specific stats info                   |
+ * |                      (see htt_stats.h)                       |
+ * |--------------------------------------------------------------|
+ * Header fields:
+ *  - MSG_TYPE
+ *    Bits 7:0
+ *    Purpose: Identifies this is a extended statistics upload confirmation
+ *             message.
+ *    Value: 0x1c
+ *  - COOKIE_LSBS
+ *    Bits 31:0
+ *    Purpose: Provide a mechanism to match a target->host stats confirmation
+ *        message with its preceding host->target stats request message.
+ *    Value: LSBs of the opaque cookie specified by the host-side requestor
+ *  - COOKIE_MSBS
+ *    Bits 31:0
+ *    Purpose: Provide a mechanism to match a target->host stats confirmation
+ *        message with its preceding host->target stats request message.
+ *    Value: MSBs of the opaque cookie specified by the host-side requestor
+ *
+ * Stats Information Element tag-length header fields:
+ *  - STAT_TYPE
+ *    Bits 7:0
+ *    Purpose: identifies the type of statistics info held in the
+ *        following information element
+ *    Value: htt_dbg_ext_stats_type
+ *  - STATUS
+ *    Bits 10:8
+ *    Purpose: indicate whether the requested stats are present
+ *    Value: htt_dbg_ext_stats_status
+ *  - DONE
+ *    Bits 11
+ *    Purpose:
+ *        Indicates the completion of the stats entry, this will be the last
+ *        stats conf HTT segment for the requested stats type.
+ *    Value:
+ *        0 -> the stats retrieval is ongoing
+ *        1 -> the stats retrieval is complete
+ *  - LENGTH
+ *    Bits 31:16
+ *    Purpose: indicate the stats information size
+ *    Value: This field specifies the number of bytes of stats information
+ *       that follows the element tag-length header.
+ *       It is expected but not required that this length is a multiple of
+ *       4 bytes.
+ */
+
+#define HTT_T2H_EXT_STATS_INFO1_LENGTH   GENMASK(31, 16)
+
+struct ath11k_htt_extd_stats_msg {
+       u32 info0;
+       u64 cookie;
+       u32 info1;
+       u8 data[0];
+} __packed;
+
+struct htt_mac_addr {
+       u32 mac_addr_l32;
+       u32 mac_addr_h16;
+};
+
+static inline void ath11k_dp_get_mac_addr(u32 addr_l32, u16 addr_h16, u8 *addr)
+{
+       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
+               addr_l32 = swab32(addr_l32);
+               addr_h16 = swab16(addr_h16);
+       }
+
+       memcpy(addr, &addr_l32, 4);
+       memcpy(addr + 4, &addr_h16, ETH_ALEN - 4);
+}
+
+int ath11k_dp_service_srng(struct ath11k_base *ab,
+                          struct ath11k_ext_irq_grp *irq_grp,
+                          int budget);
+int ath11k_dp_htt_connect(struct ath11k_dp *dp);
+void ath11k_dp_vdev_tx_attach(struct ath11k *ar, struct ath11k_vif *arvif);
+void ath11k_dp_free(struct ath11k_base *ab);
+int ath11k_dp_alloc(struct ath11k_base *ab);
+int ath11k_dp_pdev_alloc(struct ath11k_base *ab);
+void ath11k_dp_pdev_free(struct ath11k_base *ab);
+int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id,
+                               int mac_id, enum hal_ring_type ring_type);
+int ath11k_dp_peer_setup(struct ath11k *ar, int vdev_id, const u8 *addr);
+void ath11k_dp_peer_cleanup(struct ath11k *ar, int vdev_id, const u8 *addr);
+void ath11k_dp_srng_cleanup(struct ath11k_base *ab, struct dp_srng *ring);
+int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
+                        enum hal_ring_type type, int ring_num,
+                        int mac_id, int num_entries);
+void ath11k_dp_link_desc_cleanup(struct ath11k_base *ab,
+                                struct dp_link_desc_bank *desc_bank,
+                                u32 ring_type, struct dp_srng *ring);
+int ath11k_dp_link_desc_setup(struct ath11k_base *ab,
+                             struct dp_link_desc_bank *link_desc_banks,
+                             u32 ring_type, struct hal_srng *srng,
+                             u32 n_link_desc);
+
+#endif
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/ieee80211.h>
+#include "core.h"
+#include "debug.h"
+#include "hal_desc.h"
+#include "hw.h"
+#include "dp_rx.h"
+#include "hal_rx.h"
+#include "dp_tx.h"
+#include "peer.h"
+
+static u8 *ath11k_dp_rx_h_80211_hdr(struct hal_rx_desc *desc)
+{
+       return desc->hdr_status;
+}
+
+static enum hal_encrypt_type ath11k_dp_rx_h_mpdu_start_enctype(struct hal_rx_desc *desc)
+{
+       if (!(__le32_to_cpu(desc->mpdu_start.info1) &
+           RX_MPDU_START_INFO1_ENCRYPT_INFO_VALID))
+               return HAL_ENCRYPT_TYPE_OPEN;
+
+       return FIELD_GET(RX_MPDU_START_INFO2_ENC_TYPE,
+                        __le32_to_cpu(desc->mpdu_start.info2));
+}
+
+static u8 ath11k_dp_rx_h_mpdu_start_decap_type(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MPDU_START_INFO5_DECAP_TYPE,
+                        __le32_to_cpu(desc->mpdu_start.info5));
+}
+
+static bool ath11k_dp_rx_h_attn_msdu_done(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_ATTENTION_INFO2_MSDU_DONE,
+                          __le32_to_cpu(desc->attention.info2));
+}
+
+static bool ath11k_dp_rx_h_attn_first_mpdu(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_ATTENTION_INFO1_FIRST_MPDU,
+                          __le32_to_cpu(desc->attention.info1));
+}
+
+static bool ath11k_dp_rx_h_attn_l4_cksum_fail(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_ATTENTION_INFO1_TCP_UDP_CKSUM_FAIL,
+                          __le32_to_cpu(desc->attention.info1));
+}
+
+static bool ath11k_dp_rx_h_attn_ip_cksum_fail(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_ATTENTION_INFO1_IP_CKSUM_FAIL,
+                          __le32_to_cpu(desc->attention.info1));
+}
+
+static bool ath11k_dp_rx_h_attn_is_decrypted(struct hal_rx_desc *desc)
+{
+       return (FIELD_GET(RX_ATTENTION_INFO2_DCRYPT_STATUS_CODE,
+                         __le32_to_cpu(desc->attention.info2)) ==
+               RX_DESC_DECRYPT_STATUS_CODE_OK);
+}
+
+static u32 ath11k_dp_rx_h_attn_mpdu_err(struct hal_rx_desc *desc)
+{
+       u32 info = __le32_to_cpu(desc->attention.info1);
+       u32 errmap = 0;
+
+       if (info & RX_ATTENTION_INFO1_FCS_ERR)
+               errmap |= DP_RX_MPDU_ERR_FCS;
+
+       if (info & RX_ATTENTION_INFO1_DECRYPT_ERR)
+               errmap |= DP_RX_MPDU_ERR_DECRYPT;
+
+       if (info & RX_ATTENTION_INFO1_TKIP_MIC_ERR)
+               errmap |= DP_RX_MPDU_ERR_TKIP_MIC;
+
+       if (info & RX_ATTENTION_INFO1_A_MSDU_ERROR)
+               errmap |= DP_RX_MPDU_ERR_AMSDU_ERR;
+
+       if (info & RX_ATTENTION_INFO1_OVERFLOW_ERR)
+               errmap |= DP_RX_MPDU_ERR_OVERFLOW;
+
+       if (info & RX_ATTENTION_INFO1_MSDU_LEN_ERR)
+               errmap |= DP_RX_MPDU_ERR_MSDU_LEN;
+
+       if (info & RX_ATTENTION_INFO1_MPDU_LEN_ERR)
+               errmap |= DP_RX_MPDU_ERR_MPDU_LEN;
+
+       return errmap;
+}
+
+static u16 ath11k_dp_rx_h_msdu_start_msdu_len(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO1_MSDU_LENGTH,
+                        __le32_to_cpu(desc->msdu_start.info1));
+}
+
+static u8 ath11k_dp_rx_h_msdu_start_sgi(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_SGI,
+                        __le32_to_cpu(desc->msdu_start.info3));
+}
+
+static u8 ath11k_dp_rx_h_msdu_start_rate_mcs(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_RATE_MCS,
+                        __le32_to_cpu(desc->msdu_start.info3));
+}
+
+static u8 ath11k_dp_rx_h_msdu_start_rx_bw(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_RECV_BW,
+                        __le32_to_cpu(desc->msdu_start.info3));
+}
+
+static u32 ath11k_dp_rx_h_msdu_start_freq(struct hal_rx_desc *desc)
+{
+       return __le32_to_cpu(desc->msdu_start.phy_meta_data);
+}
+
+static u8 ath11k_dp_rx_h_msdu_start_pkt_type(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_START_INFO3_PKT_TYPE,
+                        __le32_to_cpu(desc->msdu_start.info3));
+}
+
+static u8 ath11k_dp_rx_h_msdu_start_nss(struct hal_rx_desc *desc)
+{
+       u8 mimo_ss_bitmap = FIELD_GET(RX_MSDU_START_INFO3_MIMO_SS_BITMAP,
+                                     __le32_to_cpu(desc->msdu_start.info3));
+
+       return hweight8(mimo_ss_bitmap);
+}
+
+static u8 ath11k_dp_rx_h_msdu_end_l3pad(struct hal_rx_desc *desc)
+{
+       return FIELD_GET(RX_MSDU_END_INFO2_L3_HDR_PADDING,
+                        __le32_to_cpu(desc->msdu_end.info2));
+}
+
+static bool ath11k_dp_rx_h_msdu_end_first_msdu(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_MSDU_END_INFO2_FIRST_MSDU,
+                          __le32_to_cpu(desc->msdu_end.info2));
+}
+
+static bool ath11k_dp_rx_h_msdu_end_last_msdu(struct hal_rx_desc *desc)
+{
+       return !!FIELD_GET(RX_MSDU_END_INFO2_LAST_MSDU,
+                          __le32_to_cpu(desc->msdu_end.info2));
+}
+
+static void ath11k_dp_rx_desc_end_tlv_copy(struct hal_rx_desc *fdesc,
+                                          struct hal_rx_desc *ldesc)
+{
+       memcpy((u8 *)&fdesc->msdu_end, (u8 *)&ldesc->msdu_end,
+              sizeof(struct rx_msdu_end));
+       memcpy((u8 *)&fdesc->attention, (u8 *)&ldesc->attention,
+              sizeof(struct rx_attention));
+       memcpy((u8 *)&fdesc->mpdu_end, (u8 *)&ldesc->mpdu_end,
+              sizeof(struct rx_mpdu_end));
+}
+
+static u32 ath11k_dp_rxdesc_get_mpdulen_err(struct hal_rx_desc *rx_desc)
+{
+       struct rx_attention *rx_attn;
+
+       rx_attn = &rx_desc->attention;
+
+       return FIELD_GET(RX_ATTENTION_INFO1_MPDU_LEN_ERR,
+                        __le32_to_cpu(rx_attn->info1));
+}
+
+static u32 ath11k_dp_rxdesc_get_decap_format(struct hal_rx_desc *rx_desc)
+{
+       struct rx_msdu_start *rx_msdu_start;
+
+       rx_msdu_start = &rx_desc->msdu_start;
+
+       return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT,
+                        __le32_to_cpu(rx_msdu_start->info2));
+}
+
+static u8 *ath11k_dp_rxdesc_get_80211hdr(struct hal_rx_desc *rx_desc)
+{
+       u8 *rx_pkt_hdr;
+
+       rx_pkt_hdr = &rx_desc->msdu_payload[0];
+
+       return rx_pkt_hdr;
+}
+
+static bool ath11k_dp_rxdesc_mpdu_valid(struct hal_rx_desc *rx_desc)
+{
+       u32 tlv_tag;
+
+       tlv_tag = FIELD_GET(HAL_TLV_HDR_TAG,
+                           __le32_to_cpu(rx_desc->mpdu_start_tag));
+
+       return tlv_tag == HAL_RX_MPDU_START ? true : false;
+}
+
+static u32 ath11k_dp_rxdesc_get_ppduid(struct hal_rx_desc *rx_desc)
+{
+       return __le16_to_cpu(rx_desc->mpdu_start.phy_ppdu_id);
+}
+
+/* Returns number of Rx buffers replenished */
+int ath11k_dp_rxbufs_replenish(struct ath11k_base *ab, int mac_id,
+                              struct dp_rxdma_ring *rx_ring,
+                              int req_entries,
+                              enum hal_rx_buf_return_buf_manager mgr,
+                              gfp_t gfp)
+{
+       struct hal_srng *srng;
+       u32 *desc;
+       struct sk_buff *skb;
+       int num_free;
+       int num_remain;
+       int buf_id;
+       u32 cookie;
+       dma_addr_t paddr;
+
+       req_entries = min(req_entries, rx_ring->bufs_max);
+
+       srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       num_free = ath11k_hal_srng_src_num_free(ab, srng, true);
+       if (!req_entries && (num_free > (rx_ring->bufs_max * 3) / 4))
+               req_entries = num_free;
+
+       req_entries = min(num_free, req_entries);
+       num_remain = req_entries;
+
+       while (num_remain > 0) {
+               skb = dev_alloc_skb(DP_RX_BUFFER_SIZE +
+                                   DP_RX_BUFFER_ALIGN_SIZE);
+               if (!skb)
+                       break;
+
+               if (!IS_ALIGNED((unsigned long)skb->data,
+                               DP_RX_BUFFER_ALIGN_SIZE)) {
+                       skb_pull(skb,
+                                PTR_ALIGN(skb->data, DP_RX_BUFFER_ALIGN_SIZE) -
+                                skb->data);
+               }
+
+               paddr = dma_map_single(ab->dev, skb->data,
+                                      skb->len + skb_tailroom(skb),
+                                      DMA_FROM_DEVICE);
+               if (dma_mapping_error(ab->dev, paddr))
+                       goto fail_free_skb;
+
+               spin_lock_bh(&rx_ring->idr_lock);
+               buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0,
+                                  rx_ring->bufs_max * 3, gfp);
+               spin_unlock_bh(&rx_ring->idr_lock);
+               if (buf_id < 0)
+                       goto fail_dma_unmap;
+
+               desc = ath11k_hal_srng_src_get_next_entry(ab, srng);
+               if (!desc)
+                       goto fail_idr_remove;
+
+               ATH11K_SKB_RXCB(skb)->paddr = paddr;
+
+               cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) |
+                        FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id);
+
+               num_remain--;
+
+               ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr);
+       }
+
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       return req_entries - num_remain;
+
+fail_idr_remove:
+       spin_lock_bh(&rx_ring->idr_lock);
+       idr_remove(&rx_ring->bufs_idr, buf_id);
+       spin_unlock_bh(&rx_ring->idr_lock);
+fail_dma_unmap:
+       dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb),
+                        DMA_FROM_DEVICE);
+fail_free_skb:
+       dev_kfree_skb_any(skb);
+
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       return req_entries - num_remain;
+}
+
+static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar,
+                                        struct dp_rxdma_ring *rx_ring)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct sk_buff *skb;
+       int buf_id;
+
+       spin_lock_bh(&rx_ring->idr_lock);
+       idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) {
+               idr_remove(&rx_ring->bufs_idr, buf_id);
+               /* TODO: Understand where internal driver does this dma_unmap of
+                * of rxdma_buffer.
+                */
+               dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr,
+                                skb->len + skb_tailroom(skb), DMA_FROM_DEVICE);
+               dev_kfree_skb_any(skb);
+       }
+
+       idr_destroy(&rx_ring->bufs_idr);
+       spin_unlock_bh(&rx_ring->idr_lock);
+
+       rx_ring = &dp->rx_mon_status_refill_ring;
+
+       spin_lock_bh(&rx_ring->idr_lock);
+       idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) {
+               idr_remove(&rx_ring->bufs_idr, buf_id);
+               /* XXX: Understand where internal driver does this dma_unmap of
+                * of rxdma_buffer.
+                */
+               dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr,
+                                skb->len + skb_tailroom(skb), DMA_BIDIRECTIONAL);
+               dev_kfree_skb_any(skb);
+       }
+
+       idr_destroy(&rx_ring->bufs_idr);
+       spin_unlock_bh(&rx_ring->idr_lock);
+       return 0;
+}
+
+static int ath11k_dp_rxdma_pdev_buf_free(struct ath11k *ar)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
+
+       ath11k_dp_rxdma_buf_ring_free(ar, rx_ring);
+
+       rx_ring = &dp->rxdma_mon_buf_ring;
+       ath11k_dp_rxdma_buf_ring_free(ar, rx_ring);
+
+       rx_ring = &dp->rx_mon_status_refill_ring;
+       ath11k_dp_rxdma_buf_ring_free(ar, rx_ring);
+       return 0;
+}
+
+static int ath11k_dp_rxdma_ring_buf_setup(struct ath11k *ar,
+                                         struct dp_rxdma_ring *rx_ring,
+                                         u32 ringtype)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       int num_entries;
+
+       num_entries = rx_ring->refill_buf_ring.size /
+                     ath11k_hal_srng_get_entrysize(ringtype);
+
+       rx_ring->bufs_max = num_entries;
+       ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id, rx_ring, num_entries,
+                                  HAL_RX_BUF_RBM_SW3_BM, GFP_KERNEL);
+       return 0;
+}
+
+static int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
+
+       ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_BUF);
+
+       rx_ring = &dp->rxdma_mon_buf_ring;
+       ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_BUF);
+
+       rx_ring = &dp->rx_mon_status_refill_ring;
+       ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_STATUS);
+
+       return 0;
+}
+
+static void ath11k_dp_rx_pdev_srng_free(struct ath11k *ar)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+
+       ath11k_dp_srng_cleanup(ar->ab, &dp->rx_refill_buf_ring.refill_buf_ring);
+       ath11k_dp_srng_cleanup(ar->ab, &dp->reo_dst_ring);
+       ath11k_dp_srng_cleanup(ar->ab, &dp->rxdma_err_dst_ring);
+       ath11k_dp_srng_cleanup(ar->ab, &dp->rx_mon_status_refill_ring.refill_buf_ring);
+       ath11k_dp_srng_cleanup(ar->ab, &dp->rxdma_mon_buf_ring.refill_buf_ring);
+}
+
+static int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct dp_srng *srng = NULL;
+       int ret;
+
+       ret = ath11k_dp_srng_setup(ar->ab,
+                                  &dp->rx_refill_buf_ring.refill_buf_ring,
+                                  HAL_RXDMA_BUF, 0,
+                                  dp->mac_id, DP_RXDMA_BUF_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to setup rx_refill_buf_ring\n");
+               return ret;
+       }
+
+       ret = ath11k_dp_srng_setup(ar->ab, &dp->reo_dst_ring, HAL_REO_DST,
+                                  dp->mac_id, dp->mac_id,
+                                  DP_REO_DST_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to setup reo_dst_ring\n");
+               return ret;
+       }
+
+       ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_err_dst_ring,
+                                  HAL_RXDMA_DST, 0, dp->mac_id,
+                                  DP_RXDMA_ERR_DST_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to setup rxdma_err_dst_ring\n");
+               return ret;
+       }
+
+       srng = &dp->rx_mon_status_refill_ring.refill_buf_ring;
+       ret = ath11k_dp_srng_setup(ar->ab,
+                                  srng,
+                                  HAL_RXDMA_MONITOR_STATUS, 0, dp->mac_id,
+                                  DP_RXDMA_MON_STATUS_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to setup rx_mon_status_refill_ring\n");
+               return ret;
+       }
+       ret = ath11k_dp_srng_setup(ar->ab,
+                                  &dp->rxdma_mon_buf_ring.refill_buf_ring,
+                                  HAL_RXDMA_MONITOR_BUF, 0, dp->mac_id,
+                                  DP_RXDMA_MONITOR_BUF_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to setup HAL_RXDMA_MONITOR_BUF\n");
+               return ret;
+       }
+
+       ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_mon_dst_ring,
+                                  HAL_RXDMA_MONITOR_DST, 0, dp->mac_id,
+                                  DP_RXDMA_MONITOR_DST_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to setup HAL_RXDMA_MONITOR_DST\n");
+               return ret;
+       }
+
+       ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_mon_desc_ring,
+                                  HAL_RXDMA_MONITOR_DESC, 0, dp->mac_id,
+                                  DP_RXDMA_MONITOR_DESC_RING_SIZE);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to setup HAL_RXDMA_MONITOR_DESC\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       struct dp_reo_cmd *cmd, *tmp;
+       struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache;
+
+       spin_lock_bh(&dp->reo_cmd_lock);
+       list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
+               list_del(&cmd->list);
+               dma_unmap_single(ab->dev, cmd->data.paddr,
+                                cmd->data.size, DMA_BIDIRECTIONAL);
+               kfree(cmd->data.vaddr);
+               kfree(cmd);
+       }
+
+       list_for_each_entry_safe(cmd_cache, tmp_cache,
+                                &dp->reo_cmd_cache_flush_list, list) {
+               list_del(&cmd_cache->list);
+               dma_unmap_single(ab->dev, cmd_cache->data.paddr,
+                                cmd_cache->data.size, DMA_BIDIRECTIONAL);
+               kfree(cmd_cache->data.vaddr);
+               kfree(cmd_cache);
+       }
+       spin_unlock_bh(&dp->reo_cmd_lock);
+}
+
+static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx,
+                                  enum hal_reo_cmd_status status)
+{
+       struct dp_rx_tid *rx_tid = ctx;
+
+       if (status != HAL_REO_CMD_SUCCESS)
+               ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
+                           rx_tid->tid, status);
+
+       dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
+                        DMA_BIDIRECTIONAL);
+       kfree(rx_tid->vaddr);
+}
+
+static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
+                                     struct dp_rx_tid *rx_tid)
+{
+       struct ath11k_hal_reo_cmd cmd = {0};
+       unsigned long tot_desc_sz, desc_sz;
+       int ret;
+
+       tot_desc_sz = rx_tid->size;
+       desc_sz = ath11k_hal_reo_qdesc_size(0, HAL_DESC_REO_NON_QOS_TID);
+
+       while (tot_desc_sz > desc_sz) {
+               tot_desc_sz -= desc_sz;
+               cmd.addr_lo = lower_32_bits(rx_tid->paddr + tot_desc_sz);
+               cmd.addr_hi = upper_32_bits(rx_tid->paddr);
+               ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid,
+                                               HAL_REO_CMD_FLUSH_CACHE, &cmd,
+                                               NULL);
+               if (ret)
+                       ath11k_warn(ab,
+                                   "failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d)\n",
+                                   rx_tid->tid, ret);
+       }
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.addr_lo = lower_32_bits(rx_tid->paddr);
+       cmd.addr_hi = upper_32_bits(rx_tid->paddr);
+       cmd.flag |= HAL_REO_CMD_FLG_NEED_STATUS;
+       ret = ath11k_dp_tx_send_reo_cmd(ab, rx_tid,
+                                       HAL_REO_CMD_FLUSH_CACHE,
+                                       &cmd, ath11k_dp_reo_cmd_free);
+       if (ret) {
+               ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n",
+                          rx_tid->tid, ret);
+               dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
+                                DMA_BIDIRECTIONAL);
+               kfree(rx_tid->vaddr);
+       }
+}
+
+static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
+                                     enum hal_reo_cmd_status status)
+{
+       struct ath11k_base *ab = dp->ab;
+       struct dp_rx_tid *rx_tid = ctx;
+       struct dp_reo_cache_flush_elem *elem, *tmp;
+
+       if (status == HAL_REO_CMD_DRAIN) {
+               goto free_desc;
+       } else if (status != HAL_REO_CMD_SUCCESS) {
+               /* Shouldn't happen! Cleanup in case of other failure? */
+               ath11k_warn(ab, "failed to delete rx tid %d hw descriptor %d\n",
+                           rx_tid->tid, status);
+               return;
+       }
+
+       elem = kzalloc(sizeof(*elem), GFP_ATOMIC);
+       if (!elem)
+               goto free_desc;
+
+       elem->ts = jiffies;
+       memcpy(&elem->data, rx_tid, sizeof(*rx_tid));
+
+       spin_lock_bh(&dp->reo_cmd_lock);
+       list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list);
+       spin_unlock_bh(&dp->reo_cmd_lock);
+
+       /* Flush and invalidate aged REO desc from HW cache */
+       spin_lock_bh(&dp->reo_cmd_lock);
+       list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_cache_flush_list,
+                                list) {
+               if (time_after(jiffies, elem->ts +
+                              msecs_to_jiffies(DP_REO_DESC_FREE_TIMEOUT_MS))) {
+                       list_del(&elem->list);
+                       spin_unlock_bh(&dp->reo_cmd_lock);
+
+                       ath11k_dp_reo_cache_flush(ab, &elem->data);
+                       kfree(elem);
+                       spin_lock_bh(&dp->reo_cmd_lock);
+               }
+       }
+       spin_unlock_bh(&dp->reo_cmd_lock);
+
+       return;
+free_desc:
+       dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
+                        DMA_BIDIRECTIONAL);
+       kfree(rx_tid->vaddr);
+}
+
+static void ath11k_peer_rx_tid_delete(struct ath11k *ar,
+                                     struct ath11k_peer *peer, u8 tid)
+{
+       struct ath11k_hal_reo_cmd cmd = {0};
+       struct dp_rx_tid *rx_tid = &peer->rx_tid[tid];
+       int ret;
+
+       if (!rx_tid->active)
+               return;
+
+       cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
+       cmd.addr_lo = lower_32_bits(rx_tid->paddr);
+       cmd.addr_hi = upper_32_bits(rx_tid->paddr);
+       cmd.upd0 |= HAL_REO_CMD_UPD0_VLD;
+       ret = ath11k_dp_tx_send_reo_cmd(ar->ab, rx_tid,
+                                       HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd,
+                                       ath11k_dp_rx_tid_del_func);
+       if (ret) {
+               ath11k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
+                          tid, ret);
+               dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size,
+                                DMA_BIDIRECTIONAL);
+               kfree(rx_tid->vaddr);
+       }
+
+       rx_tid->active = false;
+}
+
+void ath11k_peer_rx_tid_cleanup(struct ath11k *ar, struct ath11k_peer *peer)
+{
+       int i;
+
+       for (i = 0; i <= IEEE80211_NUM_TIDS; i++)
+               ath11k_peer_rx_tid_delete(ar, peer, i);
+}
+
+static int ath11k_peer_rx_tid_reo_update(struct ath11k *ar,
+                                        struct ath11k_peer *peer,
+                                        struct dp_rx_tid *rx_tid,
+                                        u32 ba_win_sz, u16 ssn)
+{
+       struct ath11k_hal_reo_cmd cmd = {0};
+       int ret;
+
+       cmd.addr_lo = lower_32_bits(rx_tid->paddr);
+       cmd.addr_hi = upper_32_bits(rx_tid->paddr);
+       cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
+       cmd.upd0 = HAL_REO_CMD_UPD0_BA_WINDOW_SIZE |
+                  HAL_REO_CMD_UPD0_SSN;
+       cmd.ba_window_size = ba_win_sz;
+       cmd.upd2 = FIELD_PREP(HAL_REO_CMD_UPD2_SSN, ssn);
+
+       ret = ath11k_dp_tx_send_reo_cmd(ar->ab, rx_tid,
+                                       HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd,
+                                       NULL);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to update rx tid queue, tid %d (%d)\n",
+                           rx_tid->tid, ret);
+               return ret;
+       }
+
+       rx_tid->ba_win_sz = ba_win_sz;
+
+       return 0;
+}
+
+static void ath11k_dp_rx_tid_mem_free(struct ath11k_base *ab,
+                                     const u8 *peer_mac, int vdev_id, u8 tid)
+{
+       struct ath11k_peer *peer;
+       struct dp_rx_tid *rx_tid;
+
+       spin_lock_bh(&ab->base_lock);
+
+       peer = ath11k_peer_find(ab, vdev_id, peer_mac);
+       if (!peer) {
+               ath11k_warn(ab, "failed to find the peer to free up rx tid mem\n");
+               goto unlock_exit;
+       }
+
+       rx_tid = &peer->rx_tid[tid];
+       if (!rx_tid->active)
+               goto unlock_exit;
+
+       dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
+                        DMA_BIDIRECTIONAL);
+       kfree(rx_tid->vaddr);
+
+       rx_tid->active = false;
+
+unlock_exit:
+       spin_unlock_bh(&ab->base_lock);
+}
+
+int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
+                            u8 tid, u32 ba_win_sz, u16 ssn)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_peer *peer;
+       struct dp_rx_tid *rx_tid;
+       u32 hw_desc_sz;
+       u32 *addr_aligned;
+       void *vaddr;
+       dma_addr_t paddr;
+       int ret;
+
+       spin_lock_bh(&ab->base_lock);
+
+       peer = ath11k_peer_find(ab, vdev_id, peer_mac);
+       if (!peer) {
+               ath11k_warn(ab, "failed to find the peer to set up rx tid\n");
+               spin_unlock_bh(&ab->base_lock);
+               return -ENOENT;
+       }
+
+       rx_tid = &peer->rx_tid[tid];
+       /* Update the tid queue if it is already setup */
+       if (rx_tid->active) {
+               paddr = rx_tid->paddr;
+               ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid,
+                                                   ba_win_sz, ssn);
+               spin_unlock_bh(&ab->base_lock);
+               if (ret) {
+                       ath11k_warn(ab, "failed to update reo for rx tid %d\n", tid);
+                       return ret;
+               }
+
+               ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
+                                                            peer_mac, paddr,
+                                                            tid, 1, ba_win_sz);
+               if (ret)
+                       ath11k_warn(ab, "failed to send wmi command to update rx reorder queue, tid :%d (%d)\n",
+                                   tid, ret);
+               return ret;
+       }
+
+       rx_tid->tid = tid;
+
+       rx_tid->ba_win_sz = ba_win_sz;
+
+       /* TODO: Optimize the memory allocation for qos tid based on the
+        * the actual BA window size in REO tid update path.
+        */
+       if (tid == HAL_DESC_REO_NON_QOS_TID)
+               hw_desc_sz = ath11k_hal_reo_qdesc_size(ba_win_sz, tid);
+       else
+               hw_desc_sz = ath11k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid);
+
+       vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_KERNEL);
+       if (!vaddr) {
+               spin_unlock_bh(&ab->base_lock);
+               return -ENOMEM;
+       }
+
+       addr_aligned = PTR_ALIGN(vaddr, HAL_LINK_DESC_ALIGN);
+
+       ath11k_hal_reo_qdesc_setup(addr_aligned, tid, ba_win_sz, ssn);
+
+       paddr = dma_map_single(ab->dev, addr_aligned, hw_desc_sz,
+                              DMA_BIDIRECTIONAL);
+
+       ret = dma_mapping_error(ab->dev, paddr);
+       if (ret) {
+               spin_unlock_bh(&ab->base_lock);
+               goto err_mem_free;
+       }
+
+       rx_tid->vaddr = vaddr;
+       rx_tid->paddr = paddr;
+       rx_tid->size = hw_desc_sz;
+       rx_tid->active = true;
+
+       spin_unlock_bh(&ab->base_lock);
+
+       ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac,
+                                                    paddr, tid, 1, ba_win_sz);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to setup rx reorder queue, tid :%d (%d)\n",
+                           tid, ret);
+               ath11k_dp_rx_tid_mem_free(ab, peer_mac, vdev_id, tid);
+       }
+
+       return ret;
+
+err_mem_free:
+       kfree(vaddr);
+
+       return ret;
+}
+
+int ath11k_dp_rx_ampdu_start(struct ath11k *ar,
+                            struct ieee80211_ampdu_params *params)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_sta *arsta = (void *)params->sta->drv_priv;
+       int vdev_id = arsta->arvif->vdev_id;
+       int ret;
+
+       ret = ath11k_peer_rx_tid_setup(ar, params->sta->addr, vdev_id,
+                                      params->tid, params->buf_size,
+                                      params->ssn);
+       if (ret)
+               ath11k_warn(ab, "failed to setup rx tid %d\n", ret);
+
+       return ret;
+}
+
+int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+                           struct ieee80211_ampdu_params *params)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_peer *peer;
+       struct ath11k_sta *arsta = (void *)params->sta->drv_priv;
+       int vdev_id = arsta->arvif->vdev_id;
+       dma_addr_t paddr;
+       bool active;
+       int ret;
+
+       spin_lock_bh(&ab->base_lock);
+
+       peer = ath11k_peer_find(ab, vdev_id, params->sta->addr);
+       if (!peer) {
+               ath11k_warn(ab, "failed to find the peer to stop rx aggregation\n");
+               spin_unlock_bh(&ab->base_lock);
+               return -ENOENT;
+       }
+
+       paddr = peer->rx_tid[params->tid].paddr;
+       active = peer->rx_tid[params->tid].active;
+
+       ath11k_peer_rx_tid_delete(ar, peer, params->tid);
+
+       spin_unlock_bh(&ab->base_lock);
+
+       if (!active)
+               return 0;
+
+       ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id,
+                                                    params->sta->addr, paddr,
+                                                    params->tid, 1, 1);
+       if (ret)
+               ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n",
+                           ret);
+
+       return ret;
+}
+
+static int ath11k_get_ppdu_user_index(struct htt_ppdu_stats *ppdu_stats,
+                                     u16 peer_id)
+{
+       int i;
+
+       for (i = 0; i < HTT_PPDU_STATS_MAX_USERS - 1; i++) {
+               if (ppdu_stats->user_stats[i].is_valid_peer_id) {
+                       if (peer_id == ppdu_stats->user_stats[i].peer_id)
+                               return i;
+               } else {
+                       return i;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int ath11k_htt_tlv_ppdu_stats_parse(struct ath11k_base *ab,
+                                          u16 tag, u16 len, const void *ptr,
+                                          void *data)
+{
+       struct htt_ppdu_stats_info *ppdu_info;
+       struct htt_ppdu_user_stats *user_stats;
+       int cur_user;
+       u16 peer_id;
+
+       ppdu_info = (struct htt_ppdu_stats_info *)data;
+
+       switch (tag) {
+       case HTT_PPDU_STATS_TAG_COMMON:
+               if (len < sizeof(struct htt_ppdu_stats_common)) {
+                       ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n",
+                                   len, tag);
+                       return -EINVAL;
+               }
+               memcpy((void *)&ppdu_info->ppdu_stats.common, ptr,
+                      sizeof(struct htt_ppdu_stats_common));
+               break;
+       case HTT_PPDU_STATS_TAG_USR_RATE:
+               if (len < sizeof(struct htt_ppdu_stats_user_rate)) {
+                       ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n",
+                                   len, tag);
+                       return -EINVAL;
+               }
+
+               peer_id = ((struct htt_ppdu_stats_user_rate *)ptr)->sw_peer_id;
+               cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats,
+                                                     peer_id);
+               if (cur_user < 0)
+                       return -EINVAL;
+               user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user];
+               user_stats->peer_id = peer_id;
+               user_stats->is_valid_peer_id = true;
+               memcpy((void *)&user_stats->rate, ptr,
+                      sizeof(struct htt_ppdu_stats_user_rate));
+               user_stats->tlv_flags |= BIT(tag);
+               break;
+       case HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON:
+               if (len < sizeof(struct htt_ppdu_stats_usr_cmpltn_cmn)) {
+                       ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n",
+                                   len, tag);
+                       return -EINVAL;
+               }
+
+               peer_id = ((struct htt_ppdu_stats_usr_cmpltn_cmn *)ptr)->sw_peer_id;
+               cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats,
+                                                     peer_id);
+               if (cur_user < 0)
+                       return -EINVAL;
+               user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user];
+               user_stats->peer_id = peer_id;
+               user_stats->is_valid_peer_id = true;
+               memcpy((void *)&user_stats->cmpltn_cmn, ptr,
+                      sizeof(struct htt_ppdu_stats_usr_cmpltn_cmn));
+               user_stats->tlv_flags |= BIT(tag);
+               break;
+       case HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS:
+               if (len <
+                   sizeof(struct htt_ppdu_stats_usr_cmpltn_ack_ba_status)) {
+                       ath11k_warn(ab, "Invalid len %d for the tag 0x%x\n",
+                                   len, tag);
+                       return -EINVAL;
+               }
+
+               peer_id =
+               ((struct htt_ppdu_stats_usr_cmpltn_ack_ba_status *)ptr)->sw_peer_id;
+               cur_user = ath11k_get_ppdu_user_index(&ppdu_info->ppdu_stats,
+                                                     peer_id);
+               if (cur_user < 0)
+                       return -EINVAL;
+               user_stats = &ppdu_info->ppdu_stats.user_stats[cur_user];
+               user_stats->peer_id = peer_id;
+               user_stats->is_valid_peer_id = true;
+               memcpy((void *)&user_stats->ack_ba, ptr,
+                      sizeof(struct htt_ppdu_stats_usr_cmpltn_ack_ba_status));
+               user_stats->tlv_flags |= BIT(tag);
+               break;
+       }
+       return 0;
+}
+
+int ath11k_dp_htt_tlv_iter(struct ath11k_base *ab, const void *ptr, size_t len,
+                          int (*iter)(struct ath11k_base *ar, u16 tag, u16 len,
+                                      const void *ptr, void *data),
+                          void *data)
+{
+       const struct htt_tlv *tlv;
+       const void *begin = ptr;
+       u16 tlv_tag, tlv_len;
+       int ret = -EINVAL;
+
+       while (len > 0) {
+               if (len < sizeof(*tlv)) {
+                       ath11k_err(ab, "htt tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n",
+                                  ptr - begin, len, sizeof(*tlv));
+                       return -EINVAL;
+               }
+               tlv = (struct htt_tlv *)ptr;
+               tlv_tag = FIELD_GET(HTT_TLV_TAG, tlv->header);
+               tlv_len = FIELD_GET(HTT_TLV_LEN, tlv->header);
+               ptr += sizeof(*tlv);
+               len -= sizeof(*tlv);
+
+               if (tlv_len > len) {
+                       ath11k_err(ab, "htt tlv parse failure of tag %hhu at byte %zd (%zu bytes left, %hhu expected)\n",
+                                  tlv_tag, ptr - begin, len, tlv_len);
+                       return -EINVAL;
+               }
+               ret = iter(ab, tlv_tag, tlv_len, ptr, data);
+               if (ret == -ENOMEM)
+                       return ret;
+
+               ptr += tlv_len;
+               len -= tlv_len;
+       }
+       return 0;
+}
+
+static u8 ath11k_bw_to_mac80211_bw(u8 bw)
+{
+       u8 ret = 0;
+
+       switch (bw) {
+       case ATH11K_BW_20:
+               ret = RATE_INFO_BW_20;
+               break;
+       case ATH11K_BW_40:
+               ret = RATE_INFO_BW_40;
+               break;
+       case ATH11K_BW_80:
+               ret = RATE_INFO_BW_80;
+               break;
+       case ATH11K_BW_160:
+               ret = RATE_INFO_BW_160;
+               break;
+       }
+
+       return ret;
+}
+
+static u32 ath11k_bw_to_mac80211_bwflags(u8 bw)
+{
+       u32 bwflags = 0;
+
+       switch (bw) {
+       case ATH11K_BW_40:
+               bwflags = IEEE80211_TX_RC_40_MHZ_WIDTH;
+               break;
+       case ATH11K_BW_80:
+               bwflags = IEEE80211_TX_RC_80_MHZ_WIDTH;
+               break;
+       case ATH11K_BW_160:
+               bwflags = IEEE80211_TX_RC_160_MHZ_WIDTH;
+               break;
+       }
+
+       return bwflags;
+}
+
+static void
+ath11k_update_per_peer_tx_stats(struct ath11k *ar,
+                               struct htt_ppdu_stats *ppdu_stats, u8 user)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_peer *peer;
+       struct ieee80211_sta *sta;
+       struct ath11k_sta *arsta;
+       struct htt_ppdu_stats_user_rate *user_rate;
+       struct ieee80211_chanctx_conf *conf = NULL;
+       struct ath11k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats;
+       struct htt_ppdu_user_stats *usr_stats = &ppdu_stats->user_stats[user];
+       struct htt_ppdu_stats_common *common = &ppdu_stats->common;
+       int ret;
+       u8 flags, mcs, nss, bw, sgi, rate_idx = 0;
+       u32 succ_bytes = 0;
+       u16 rate = 0, succ_pkts = 0;
+       u32 tx_duration = 0;
+       bool is_ampdu = false;
+
+       if (!usr_stats)
+               return;
+
+       if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE)))
+               return;
+
+       if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON))
+               is_ampdu =
+                       HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags);
+
+       if (usr_stats->tlv_flags &
+           BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) {
+               succ_bytes = usr_stats->ack_ba.success_bytes;
+               succ_pkts = FIELD_GET(HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M,
+                                     usr_stats->ack_ba.info);
+       }
+
+       if (common->fes_duration_us)
+               tx_duration = common->fes_duration_us;
+
+       user_rate = &usr_stats->rate;
+       flags = HTT_USR_RATE_PREAMBLE(user_rate->rate_flags);
+       bw = HTT_USR_RATE_BW(user_rate->rate_flags) - 2;
+       nss = HTT_USR_RATE_NSS(user_rate->rate_flags) + 1;
+       mcs = HTT_USR_RATE_MCS(user_rate->rate_flags);
+       sgi = HTT_USR_RATE_GI(user_rate->rate_flags);
+
+       /* Note: If host configured fixed rates and in some other special
+        * cases, the broadcast/management frames are sent in different rates.
+        * Firmware rate's control to be skipped for this?
+        */
+
+       if (flags == WMI_RATE_PREAMBLE_VHT && mcs > 9) {
+               ath11k_warn(ab, "Invalid VHT mcs %hhd peer stats",  mcs);
+               return;
+       }
+
+       if (flags == WMI_RATE_PREAMBLE_HT && (mcs > 7 || nss < 1)) {
+               ath11k_warn(ab, "Invalid HT mcs %hhd nss %hhd peer stats",
+                           mcs, nss);
+               return;
+       }
+
+       if (flags == WMI_RATE_PREAMBLE_CCK || flags == WMI_RATE_PREAMBLE_OFDM) {
+               ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,
+                                                           flags,
+                                                           &rate_idx,
+                                                           &rate);
+               if (ret < 0)
+                       return;
+       }
+
+       rcu_read_lock();
+       spin_lock_bh(&ab->base_lock);
+       peer = ath11k_peer_find_by_id(ab, usr_stats->peer_id);
+
+       if (!peer || !peer->sta) {
+               spin_unlock_bh(&ab->base_lock);
+               rcu_read_unlock();
+               return;
+       }
+
+       sta = peer->sta;
+       arsta = (struct ath11k_sta *)sta->drv_priv;
+
+       memset(&arsta->txrate, 0, sizeof(arsta->txrate));
+       memset(&arsta->tx_info.status, 0, sizeof(arsta->tx_info.status));
+
+       switch (flags) {
+       case WMI_RATE_PREAMBLE_OFDM:
+               arsta->txrate.legacy = rate;
+               if (arsta->arvif && arsta->arvif->vif)
+                       conf = rcu_dereference(arsta->arvif->vif->chanctx_conf);
+               if (conf && conf->def.chan->band == NL80211_BAND_5GHZ)
+                       arsta->tx_info.status.rates[0].idx = rate_idx - 4;
+               break;
+       case WMI_RATE_PREAMBLE_CCK:
+               arsta->txrate.legacy = rate;
+               arsta->tx_info.status.rates[0].idx = rate_idx;
+               if (mcs > ATH11K_HW_RATE_CCK_LP_1M &&
+                   mcs <= ATH11K_HW_RATE_CCK_SP_2M)
+                       arsta->tx_info.status.rates[0].flags |=
+                                       IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+               break;
+       case WMI_RATE_PREAMBLE_HT:
+               arsta->txrate.mcs = mcs + 8 * (nss - 1);
+               arsta->tx_info.status.rates[0].idx = arsta->txrate.mcs;
+               arsta->txrate.flags = RATE_INFO_FLAGS_MCS;
+               arsta->tx_info.status.rates[0].flags |= IEEE80211_TX_RC_MCS;
+               if (sgi) {
+                       arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+                       arsta->tx_info.status.rates[0].flags |=
+                                       IEEE80211_TX_RC_SHORT_GI;
+               }
+               break;
+       case WMI_RATE_PREAMBLE_VHT:
+               arsta->txrate.mcs = mcs;
+               ieee80211_rate_set_vht(&arsta->tx_info.status.rates[0], mcs, nss);
+               arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
+               arsta->tx_info.status.rates[0].flags |= IEEE80211_TX_RC_VHT_MCS;
+               if (sgi) {
+                       arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+                       arsta->tx_info.status.rates[0].flags |=
+                                               IEEE80211_TX_RC_SHORT_GI;
+               }
+               break;
+       }
+
+       arsta->txrate.nss = nss;
+       arsta->txrate.bw = ath11k_bw_to_mac80211_bw(bw);
+       arsta->tx_info.status.rates[0].flags |= ath11k_bw_to_mac80211_bwflags(bw);
+
+       memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info));
+
+       if (succ_pkts) {
+               arsta->tx_info.flags = IEEE80211_TX_STAT_ACK;
+               arsta->tx_info.status.rates[0].count = 1;
+               ieee80211_tx_rate_update(ar->hw, sta, &arsta->tx_info);
+       }
+
+       memset(peer_stats, 0, sizeof(*peer_stats));
+
+       peer_stats->succ_pkts = succ_pkts;
+       peer_stats->succ_bytes = succ_bytes;
+       peer_stats->is_ampdu = is_ampdu;
+       peer_stats->duration = tx_duration;
+       peer_stats->ba_fails =
+               HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) +
+               HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags);
+
+       if (ath11k_debug_is_extd_tx_stats_enabled(ar))
+               ath11k_accumulate_per_peer_tx_stats(arsta,
+                                                   peer_stats, rate_idx);
+
+       spin_unlock_bh(&ab->base_lock);
+       rcu_read_unlock();
+}
+
+static void ath11k_htt_update_ppdu_stats(struct ath11k *ar,
+                                        struct htt_ppdu_stats *ppdu_stats)
+{
+       u8 user;
+
+       for (user = 0; user < HTT_PPDU_STATS_MAX_USERS - 1; user++)
+               ath11k_update_per_peer_tx_stats(ar, ppdu_stats, user);
+}
+
+static
+struct htt_ppdu_stats_info *ath11k_dp_htt_get_ppdu_desc(struct ath11k *ar,
+                                                       u32 ppdu_id)
+{
+       struct htt_ppdu_stats_info *ppdu_info = NULL;
+
+       spin_lock_bh(&ar->data_lock);
+       if (!list_empty(&ar->ppdu_stats_info)) {
+               list_for_each_entry(ppdu_info, &ar->ppdu_stats_info, list) {
+                       if (ppdu_info && ppdu_info->ppdu_id == ppdu_id) {
+                               spin_unlock_bh(&ar->data_lock);
+                               return ppdu_info;
+                       }
+               }
+
+               if (ar->ppdu_stat_list_depth > HTT_PPDU_DESC_MAX_DEPTH) {
+                       ppdu_info = list_first_entry(&ar->ppdu_stats_info,
+                                                    typeof(*ppdu_info), list);
+                       list_del(&ppdu_info->list);
+                       ar->ppdu_stat_list_depth--;
+                       ath11k_htt_update_ppdu_stats(ar, &ppdu_info->ppdu_stats);
+                       kfree(ppdu_info);
+               }
+       }
+       spin_unlock_bh(&ar->data_lock);
+
+       ppdu_info = kzalloc(sizeof(*ppdu_info), GFP_KERNEL);
+       if (!ppdu_info)
+               return NULL;
+
+       spin_lock_bh(&ar->data_lock);
+       list_add_tail(&ppdu_info->list, &ar->ppdu_stats_info);
+       ar->ppdu_stat_list_depth++;
+       spin_unlock_bh(&ar->data_lock);
+
+       return ppdu_info;
+}
+
+static int ath11k_htt_pull_ppdu_stats(struct ath11k_base *ab,
+                                     struct sk_buff *skb)
+{
+       struct ath11k_htt_ppdu_stats_msg *msg;
+       struct htt_ppdu_stats_info *ppdu_info;
+       struct ath11k *ar;
+       int ret;
+       u8 pdev_id;
+       u32 ppdu_id, len;
+
+       msg = (struct ath11k_htt_ppdu_stats_msg *)skb->data;
+       len = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PAYLOAD_SIZE, msg->info);
+       pdev_id = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PDEV_ID, msg->info);
+       ppdu_id = msg->ppdu_id;
+
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_pdev_id(ab, pdev_id);
+       if (!ar) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       if (ath11k_debug_is_pktlog_lite_mode_enabled(ar))
+               trace_ath11k_htt_ppdu_stats(ar, skb->data, len);
+
+       ppdu_info = ath11k_dp_htt_get_ppdu_desc(ar, ppdu_id);
+       if (!ppdu_info) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       ppdu_info->ppdu_id = ppdu_id;
+       ret = ath11k_dp_htt_tlv_iter(ab, msg->data, len,
+                                    ath11k_htt_tlv_ppdu_stats_parse,
+                                    (void *)ppdu_info);
+       if (ret) {
+               ath11k_warn(ab, "Failed to parse tlv %d\n", ret);
+               goto exit;
+       }
+
+exit:
+       rcu_read_unlock();
+
+       return ret;
+}
+
+static void ath11k_htt_pktlog(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct htt_pktlog_msg *data = (struct htt_pktlog_msg *)skb->data;
+       struct ath11k *ar;
+       u32 len;
+       u8 pdev_id;
+
+       len = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PAYLOAD_SIZE, data->hdr);
+
+       if (len > ATH11K_HTT_PKTLOG_MAX_SIZE) {
+               ath11k_warn(ab, "htt pktlog buffer size %d, expected < %d\n",
+                           len,
+                           ATH11K_HTT_PKTLOG_MAX_SIZE);
+               return;
+       }
+
+       pdev_id = FIELD_GET(HTT_T2H_PPDU_STATS_INFO_PDEV_ID, data->hdr);
+       pdev_id = DP_HW2SW_MACID(pdev_id);
+       ar = ab->pdevs[pdev_id].ar;
+
+       trace_ath11k_htt_pktlog(ar, data->payload, len);
+}
+
+void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab,
+                                      struct sk_buff *skb)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       struct htt_resp_msg *resp = (struct htt_resp_msg *)skb->data;
+       enum htt_t2h_msg_type type = FIELD_GET(HTT_T2H_MSG_TYPE, *(u32 *)resp);
+       u16 peer_id;
+       u8 vdev_id;
+       u8 mac_addr[ETH_ALEN];
+       u16 peer_mac_h16;
+       u16 ast_hash;
+
+       ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "dp_htt rx msg type :0x%0x\n", type);
+
+       switch (type) {
+       case HTT_T2H_MSG_TYPE_VERSION_CONF:
+               dp->htt_tgt_ver_major = FIELD_GET(HTT_T2H_VERSION_CONF_MAJOR,
+                                                 resp->version_msg.version);
+               dp->htt_tgt_ver_minor = FIELD_GET(HTT_T2H_VERSION_CONF_MINOR,
+                                                 resp->version_msg.version);
+               complete(&dp->htt_tgt_version_received);
+               break;
+       case HTT_T2H_MSG_TYPE_PEER_MAP:
+               vdev_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_VDEV_ID,
+                                   resp->peer_map_ev.info);
+               peer_id = FIELD_GET(HTT_T2H_PEER_MAP_INFO_PEER_ID,
+                                   resp->peer_map_ev.info);
+               peer_mac_h16 = FIELD_GET(HTT_T2H_PEER_MAP_INFO1_MAC_ADDR_H16,
+                                        resp->peer_map_ev.info1);
+               ath11k_dp_get_mac_addr(resp->peer_map_ev.mac_addr_l32,
+                                      peer_mac_h16, mac_addr);
+               ast_hash = FIELD_GET(HTT_T2H_PEER_MAP_INFO2_AST_HASH_VAL,
+                                    resp->peer_map_ev.info1);
+               ath11k_peer_map_event(ab, vdev_id, peer_id, mac_addr, ast_hash);
+               break;
+       case HTT_T2H_MSG_TYPE_PEER_UNMAP:
+               peer_id = FIELD_GET(HTT_T2H_PEER_UNMAP_INFO_PEER_ID,
+                                   resp->peer_unmap_ev.info);
+               ath11k_peer_unmap_event(ab, peer_id);
+               break;
+       case HTT_T2H_MSG_TYPE_PPDU_STATS_IND:
+               ath11k_htt_pull_ppdu_stats(ab, skb);
+               break;
+       case HTT_T2H_MSG_TYPE_EXT_STATS_CONF:
+               ath11k_dbg_htt_ext_stats_handler(ab, skb);
+               break;
+       case HTT_T2H_MSG_TYPE_PKTLOG:
+               ath11k_htt_pktlog(ab, skb);
+               break;
+       default:
+               ath11k_warn(ab, "htt event %d not handled\n", type);
+               break;
+       }
+
+       dev_kfree_skb_any(skb);
+}
+
+static int ath11k_dp_rx_msdu_coalesce(struct ath11k *ar,
+                                     struct sk_buff_head *msdu_list,
+                                     struct sk_buff *first, struct sk_buff *last,
+                                     u8 l3pad_bytes, int msdu_len)
+{
+       struct sk_buff *skb;
+       struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(first);
+       struct hal_rx_desc *ldesc;
+       int space_extra;
+       int rem_len;
+       int buf_len;
+
+       if (!rxcb->is_continuation) {
+               skb_put(first, HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len);
+               skb_pull(first, HAL_RX_DESC_SIZE + l3pad_bytes);
+               return 0;
+       }
+
+       if (WARN_ON_ONCE(msdu_len <= (DP_RX_BUFFER_SIZE -
+                        (HAL_RX_DESC_SIZE + l3pad_bytes)))) {
+               skb_put(first, HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len);
+               skb_pull(first, HAL_RX_DESC_SIZE + l3pad_bytes);
+               return 0;
+       }
+
+       ldesc = (struct hal_rx_desc *)last->data;
+       rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ldesc);
+       rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ldesc);
+
+       /* MSDU spans over multiple buffers because the length of the MSDU
+        * exceeds DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE. So assume the data
+        * in the first buf is of length DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE.
+        */
+       skb_put(first, DP_RX_BUFFER_SIZE);
+       skb_pull(first, HAL_RX_DESC_SIZE + l3pad_bytes);
+
+       space_extra = msdu_len - (DP_RX_BUFFER_SIZE + skb_tailroom(first));
+       if (space_extra > 0 &&
+           (pskb_expand_head(first, 0, space_extra, GFP_ATOMIC) < 0)) {
+               /* Free up all buffers of the MSDU */
+               while ((skb = __skb_dequeue(msdu_list)) != NULL) {
+                       rxcb = ATH11K_SKB_RXCB(skb);
+                       if (!rxcb->is_continuation) {
+                               dev_kfree_skb_any(skb);
+                               break;
+                       }
+                       dev_kfree_skb_any(skb);
+               }
+               return -ENOMEM;
+       }
+
+       /* When an MSDU spread over multiple buffers attention, MSDU_END and
+        * MPDU_END tlvs are valid only in the last buffer. Copy those tlvs.
+        */
+       ath11k_dp_rx_desc_end_tlv_copy(rxcb->rx_desc, ldesc);
+
+       rem_len = msdu_len -
+                 (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE - l3pad_bytes);
+       while ((skb = __skb_dequeue(msdu_list)) != NULL && rem_len > 0) {
+               rxcb = ATH11K_SKB_RXCB(skb);
+               if (rxcb->is_continuation)
+                       buf_len = DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE;
+               else
+                       buf_len = rem_len;
+
+               if (buf_len > (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE)) {
+                       WARN_ON_ONCE(1);
+                       dev_kfree_skb_any(skb);
+                       return -EINVAL;
+               }
+
+               skb_put(skb, buf_len + HAL_RX_DESC_SIZE);
+               skb_pull(skb, HAL_RX_DESC_SIZE);
+               skb_copy_from_linear_data(skb, skb_put(first, buf_len),
+                                         buf_len);
+               dev_kfree_skb_any(skb);
+
+               rem_len -= buf_len;
+               if (!rxcb->is_continuation)
+                       break;
+       }
+
+       return 0;
+}
+
+static struct sk_buff *ath11k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_list,
+                                                     struct sk_buff *first)
+{
+       struct sk_buff *skb;
+       struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(first);
+
+       if (!rxcb->is_continuation)
+               return first;
+
+       skb_queue_walk(msdu_list, skb) {
+               rxcb = ATH11K_SKB_RXCB(skb);
+               if (!rxcb->is_continuation)
+                       return skb;
+       }
+
+       return NULL;
+}
+
+static int ath11k_dp_rx_retrieve_amsdu(struct ath11k *ar,
+                                      struct sk_buff_head *msdu_list,
+                                      struct sk_buff_head *amsdu_list)
+{
+       struct sk_buff *msdu = skb_peek(msdu_list);
+       struct sk_buff *last_buf;
+       struct ath11k_skb_rxcb *rxcb;
+       struct ieee80211_hdr *hdr;
+       struct hal_rx_desc *rx_desc, *lrx_desc;
+       u16 msdu_len;
+       u8 l3_pad_bytes;
+       u8 *hdr_status;
+       int ret;
+
+       if (!msdu)
+               return -ENOENT;
+
+       rx_desc = (struct hal_rx_desc *)msdu->data;
+       hdr_status = ath11k_dp_rx_h_80211_hdr(rx_desc);
+       hdr = (struct ieee80211_hdr *)hdr_status;
+       /* Process only data frames */
+       if (!ieee80211_is_data(hdr->frame_control)) {
+               __skb_unlink(msdu, msdu_list);
+               dev_kfree_skb_any(msdu);
+               return -EINVAL;
+       }
+
+       do {
+               __skb_unlink(msdu, msdu_list);
+               last_buf = ath11k_dp_rx_get_msdu_last_buf(msdu_list, msdu);
+               if (!last_buf) {
+                       ath11k_warn(ar->ab,
+                                   "No valid Rx buffer to access Atten/MSDU_END/MPDU_END tlvs\n");
+                       ret = -EIO;
+                       goto free_out;
+               }
+
+               rx_desc = (struct hal_rx_desc *)msdu->data;
+               lrx_desc = (struct hal_rx_desc *)last_buf->data;
+
+               if (!ath11k_dp_rx_h_attn_msdu_done(lrx_desc)) {
+                       ath11k_warn(ar->ab, "msdu_done bit in attention is not set\n");
+                       ret = -EIO;
+                       goto free_out;
+               }
+
+               rxcb = ATH11K_SKB_RXCB(msdu);
+               rxcb->rx_desc = rx_desc;
+               msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(rx_desc);
+               l3_pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(lrx_desc);
+
+               if (!rxcb->is_continuation) {
+                       skb_put(msdu, HAL_RX_DESC_SIZE + l3_pad_bytes + msdu_len);
+                       skb_pull(msdu, HAL_RX_DESC_SIZE + l3_pad_bytes);
+               } else {
+                       ret = ath11k_dp_rx_msdu_coalesce(ar, msdu_list,
+                                                        msdu, last_buf,
+                                                        l3_pad_bytes, msdu_len);
+                       if (ret) {
+                               ath11k_warn(ar->ab,
+                                           "failed to coalesce msdu rx buffer%d\n", ret);
+                               goto free_out;
+                       }
+               }
+               __skb_queue_tail(amsdu_list, msdu);
+
+               /* Should we also consider msdu_cnt from mpdu_meta while
+                * preparing amsdu list?
+                */
+               if (rxcb->is_last_msdu)
+                       break;
+       } while ((msdu = skb_peek(msdu_list)) != NULL);
+
+       return 0;
+
+free_out:
+       dev_kfree_skb_any(msdu);
+       __skb_queue_purge(amsdu_list);
+
+       return ret;
+}
+
+static void ath11k_dp_rx_h_csum_offload(struct sk_buff *msdu)
+{
+       struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+       bool ip_csum_fail, l4_csum_fail;
+
+       ip_csum_fail = ath11k_dp_rx_h_attn_ip_cksum_fail(rxcb->rx_desc);
+       l4_csum_fail = ath11k_dp_rx_h_attn_l4_cksum_fail(rxcb->rx_desc);
+
+       msdu->ip_summed = (ip_csum_fail || l4_csum_fail) ?
+                         CHECKSUM_NONE : CHECKSUM_UNNECESSARY;
+}
+
+static int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar,
+                                      enum hal_encrypt_type enctype)
+{
+       switch (enctype) {
+       case HAL_ENCRYPT_TYPE_OPEN:
+       case HAL_ENCRYPT_TYPE_TKIP_NO_MIC:
+       case HAL_ENCRYPT_TYPE_TKIP_MIC:
+               return 0;
+       case HAL_ENCRYPT_TYPE_CCMP_128:
+               return IEEE80211_CCMP_MIC_LEN;
+       case HAL_ENCRYPT_TYPE_CCMP_256:
+               return IEEE80211_CCMP_256_MIC_LEN;
+       case HAL_ENCRYPT_TYPE_GCMP_128:
+       case HAL_ENCRYPT_TYPE_AES_GCMP_256:
+               return IEEE80211_GCMP_MIC_LEN;
+       case HAL_ENCRYPT_TYPE_WEP_40:
+       case HAL_ENCRYPT_TYPE_WEP_104:
+       case HAL_ENCRYPT_TYPE_WEP_128:
+       case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4:
+       case HAL_ENCRYPT_TYPE_WAPI:
+               break;
+       }
+
+       ath11k_warn(ar->ab, "unsupported encryption type %d for mic len\n", enctype);
+       return 0;
+}
+
+static int ath11k_dp_rx_crypto_param_len(struct ath11k *ar,
+                                        enum hal_encrypt_type enctype)
+{
+       switch (enctype) {
+       case HAL_ENCRYPT_TYPE_OPEN:
+               return 0;
+       case HAL_ENCRYPT_TYPE_TKIP_NO_MIC:
+       case HAL_ENCRYPT_TYPE_TKIP_MIC:
+               return IEEE80211_TKIP_IV_LEN;
+       case HAL_ENCRYPT_TYPE_CCMP_128:
+               return IEEE80211_CCMP_HDR_LEN;
+       case HAL_ENCRYPT_TYPE_CCMP_256:
+               return IEEE80211_CCMP_256_HDR_LEN;
+       case HAL_ENCRYPT_TYPE_GCMP_128:
+       case HAL_ENCRYPT_TYPE_AES_GCMP_256:
+               return IEEE80211_GCMP_HDR_LEN;
+       case HAL_ENCRYPT_TYPE_WEP_40:
+       case HAL_ENCRYPT_TYPE_WEP_104:
+       case HAL_ENCRYPT_TYPE_WEP_128:
+       case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4:
+       case HAL_ENCRYPT_TYPE_WAPI:
+               break;
+       }
+
+       ath11k_warn(ar->ab, "unsupported encryption type %d\n", enctype);
+       return 0;
+}
+
+static int ath11k_dp_rx_crypto_icv_len(struct ath11k *ar,
+                                      enum hal_encrypt_type enctype)
+{
+       switch (enctype) {
+       case HAL_ENCRYPT_TYPE_OPEN:
+       case HAL_ENCRYPT_TYPE_CCMP_128:
+       case HAL_ENCRYPT_TYPE_CCMP_256:
+       case HAL_ENCRYPT_TYPE_GCMP_128:
+       case HAL_ENCRYPT_TYPE_AES_GCMP_256:
+               return 0;
+       case HAL_ENCRYPT_TYPE_TKIP_NO_MIC:
+       case HAL_ENCRYPT_TYPE_TKIP_MIC:
+               return IEEE80211_TKIP_ICV_LEN;
+       case HAL_ENCRYPT_TYPE_WEP_40:
+       case HAL_ENCRYPT_TYPE_WEP_104:
+       case HAL_ENCRYPT_TYPE_WEP_128:
+       case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4:
+       case HAL_ENCRYPT_TYPE_WAPI:
+               break;
+       }
+
+       ath11k_warn(ar->ab, "unsupported encryption type %d\n", enctype);
+       return 0;
+}
+
+static void ath11k_dp_rx_h_undecap_nwifi(struct ath11k *ar,
+                                        struct sk_buff *msdu,
+                                        u8 *first_hdr,
+                                        enum hal_encrypt_type enctype,
+                                        struct ieee80211_rx_status *status)
+{
+       struct ieee80211_hdr *hdr;
+       size_t hdr_len;
+       u8 da[ETH_ALEN];
+       u8 sa[ETH_ALEN];
+
+       /* pull decapped header and copy SA & DA */
+       hdr = (struct ieee80211_hdr *)msdu->data;
+       ether_addr_copy(da, ieee80211_get_DA(hdr));
+       ether_addr_copy(sa, ieee80211_get_SA(hdr));
+       skb_pull(msdu, ieee80211_hdrlen(hdr->frame_control));
+
+       /* push original 802.11 header */
+       hdr = (struct ieee80211_hdr *)first_hdr;
+       hdr_len = ieee80211_hdrlen(hdr->frame_control);
+
+       if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
+               memcpy(skb_push(msdu,
+                               ath11k_dp_rx_crypto_param_len(ar, enctype)),
+                      (void *)hdr + hdr_len,
+                      ath11k_dp_rx_crypto_param_len(ar, enctype));
+       }
+
+       memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
+
+       /* original 802.11 header has a different DA and in
+        * case of 4addr it may also have different SA
+        */
+       hdr = (struct ieee80211_hdr *)msdu->data;
+       ether_addr_copy(ieee80211_get_DA(hdr), da);
+       ether_addr_copy(ieee80211_get_SA(hdr), sa);
+}
+
+static void ath11k_dp_rx_h_undecap_raw(struct ath11k *ar, struct sk_buff *msdu,
+                                      enum hal_encrypt_type enctype,
+                                      struct ieee80211_rx_status *status,
+                                      bool decrypted)
+{
+       struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+       struct ieee80211_hdr *hdr;
+       size_t hdr_len;
+       size_t crypto_len;
+
+       if (!rxcb->is_first_msdu ||
+           !(rxcb->is_first_msdu && rxcb->is_last_msdu)) {
+               WARN_ON_ONCE(1);
+               return;
+       }
+
+       skb_trim(msdu, msdu->len - FCS_LEN);
+
+       if (!decrypted)
+               return;
+
+       hdr = (void *)msdu->data;
+
+       /* Tail */
+       if (status->flag & RX_FLAG_IV_STRIPPED) {
+               skb_trim(msdu, msdu->len -
+                        ath11k_dp_rx_crypto_mic_len(ar, enctype));
+
+               skb_trim(msdu, msdu->len -
+                        ath11k_dp_rx_crypto_icv_len(ar, enctype));
+       } else {
+               /* MIC */
+               if (status->flag & RX_FLAG_MIC_STRIPPED)
+                       skb_trim(msdu, msdu->len -
+                                ath11k_dp_rx_crypto_mic_len(ar, enctype));
+
+               /* ICV */
+               if (status->flag & RX_FLAG_ICV_STRIPPED)
+                       skb_trim(msdu, msdu->len -
+                                ath11k_dp_rx_crypto_icv_len(ar, enctype));
+       }
+
+       /* MMIC */
+       if ((status->flag & RX_FLAG_MMIC_STRIPPED) &&
+           !ieee80211_has_morefrags(hdr->frame_control) &&
+           enctype == HAL_ENCRYPT_TYPE_TKIP_MIC)
+               skb_trim(msdu, msdu->len - IEEE80211_CCMP_MIC_LEN);
+
+       /* Head */
+       if (status->flag & RX_FLAG_IV_STRIPPED) {
+               hdr_len = ieee80211_hdrlen(hdr->frame_control);
+               crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype);
+
+               memmove((void *)msdu->data + crypto_len,
+                       (void *)msdu->data, hdr_len);
+               skb_pull(msdu, crypto_len);
+       }
+}
+
+static void *ath11k_dp_rx_h_find_rfc1042(struct ath11k *ar,
+                                        struct sk_buff *msdu,
+                                        enum hal_encrypt_type enctype)
+{
+       struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+       struct ieee80211_hdr *hdr;
+       size_t hdr_len, crypto_len;
+       void *rfc1042;
+       bool is_amsdu;
+
+       is_amsdu = !(rxcb->is_first_msdu && rxcb->is_last_msdu);
+       hdr = (struct ieee80211_hdr *)ath11k_dp_rx_h_80211_hdr(rxcb->rx_desc);
+       rfc1042 = hdr;
+
+       if (rxcb->is_first_msdu) {
+               hdr_len = ieee80211_hdrlen(hdr->frame_control);
+               crypto_len = ath11k_dp_rx_crypto_param_len(ar, enctype);
+
+               rfc1042 += hdr_len + crypto_len;
+       }
+
+       if (is_amsdu)
+               rfc1042 += sizeof(struct ath11k_dp_amsdu_subframe_hdr);
+
+       return rfc1042;
+}
+
+static void ath11k_dp_rx_h_undecap_eth(struct ath11k *ar,
+                                      struct sk_buff *msdu,
+                                      u8 *first_hdr,
+                                      enum hal_encrypt_type enctype,
+                                      struct ieee80211_rx_status *status)
+{
+       struct ieee80211_hdr *hdr;
+       struct ethhdr *eth;
+       size_t hdr_len;
+       u8 da[ETH_ALEN];
+       u8 sa[ETH_ALEN];
+       void *rfc1042;
+
+       rfc1042 = ath11k_dp_rx_h_find_rfc1042(ar, msdu, enctype);
+       if (WARN_ON_ONCE(!rfc1042))
+               return;
+
+       /* pull decapped header and copy SA & DA */
+       eth = (struct ethhdr *)msdu->data;
+       ether_addr_copy(da, eth->h_dest);
+       ether_addr_copy(sa, eth->h_source);
+       skb_pull(msdu, sizeof(struct ethhdr));
+
+       /* push rfc1042/llc/snap */
+       memcpy(skb_push(msdu, sizeof(struct ath11k_dp_rfc1042_hdr)), rfc1042,
+              sizeof(struct ath11k_dp_rfc1042_hdr));
+
+       /* push original 802.11 header */
+       hdr = (struct ieee80211_hdr *)first_hdr;
+       hdr_len = ieee80211_hdrlen(hdr->frame_control);
+
+       if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
+               memcpy(skb_push(msdu,
+                               ath11k_dp_rx_crypto_param_len(ar, enctype)),
+                      (void *)hdr + hdr_len,
+                      ath11k_dp_rx_crypto_param_len(ar, enctype));
+       }
+
+       memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
+
+       /* original 802.11 header has a different DA and in
+        * case of 4addr it may also have different SA
+        */
+       hdr = (struct ieee80211_hdr *)msdu->data;
+       ether_addr_copy(ieee80211_get_DA(hdr), da);
+       ether_addr_copy(ieee80211_get_SA(hdr), sa);
+}
+
+static void ath11k_dp_rx_h_undecap(struct ath11k *ar, struct sk_buff *msdu,
+                                  struct hal_rx_desc *rx_desc,
+                                  enum hal_encrypt_type enctype,
+                                  struct ieee80211_rx_status *status,
+                                  bool decrypted)
+{
+       u8 *first_hdr;
+       u8 decap;
+
+       first_hdr = ath11k_dp_rx_h_80211_hdr(rx_desc);
+       decap = ath11k_dp_rx_h_mpdu_start_decap_type(rx_desc);
+
+       switch (decap) {
+       case DP_RX_DECAP_TYPE_NATIVE_WIFI:
+               ath11k_dp_rx_h_undecap_nwifi(ar, msdu, first_hdr,
+                                            enctype, status);
+               break;
+       case DP_RX_DECAP_TYPE_RAW:
+               ath11k_dp_rx_h_undecap_raw(ar, msdu, enctype, status,
+                                          decrypted);
+               break;
+       case DP_RX_DECAP_TYPE_ETHERNET2_DIX:
+               ath11k_dp_rx_h_undecap_eth(ar, msdu, first_hdr,
+                                          enctype, status);
+               break;
+       case DP_RX_DECAP_TYPE_8023:
+               /* TODO: Handle undecap for these formats */
+               break;
+       }
+}
+
+static void ath11k_dp_rx_h_mpdu(struct ath11k *ar,
+                               struct sk_buff_head *amsdu_list,
+                               struct hal_rx_desc *rx_desc,
+                               struct ieee80211_rx_status *rx_status)
+{
+       struct ieee80211_hdr *hdr;
+       enum hal_encrypt_type enctype;
+       struct sk_buff *last_msdu;
+       struct sk_buff *msdu;
+       struct ath11k_skb_rxcb *last_rxcb;
+       bool is_decrypted;
+       u32 err_bitmap;
+       u8 *qos;
+
+       if (skb_queue_empty(amsdu_list))
+               return;
+
+       hdr = (struct ieee80211_hdr *)ath11k_dp_rx_h_80211_hdr(rx_desc);
+
+       /* Each A-MSDU subframe will use the original header as the base and be
+        * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl.
+        */
+       if (ieee80211_is_data_qos(hdr->frame_control)) {
+               qos = ieee80211_get_qos_ctl(hdr);
+               qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+       }
+
+       is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_desc);
+       enctype = ath11k_dp_rx_h_mpdu_start_enctype(rx_desc);
+
+       /* Some attention flags are valid only in the last MSDU. */
+       last_msdu = skb_peek_tail(amsdu_list);
+       last_rxcb = ATH11K_SKB_RXCB(last_msdu);
+
+       err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(last_rxcb->rx_desc);
+
+       /* Clear per-MPDU flags while leaving per-PPDU flags intact. */
+       rx_status->flag &= ~(RX_FLAG_FAILED_FCS_CRC |
+                            RX_FLAG_MMIC_ERROR |
+                            RX_FLAG_DECRYPTED |
+                            RX_FLAG_IV_STRIPPED |
+                            RX_FLAG_MMIC_STRIPPED);
+
+       if (err_bitmap & DP_RX_MPDU_ERR_FCS)
+               rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+       if (err_bitmap & DP_RX_MPDU_ERR_TKIP_MIC)
+               rx_status->flag |= RX_FLAG_MMIC_ERROR;
+
+       if (is_decrypted)
+               rx_status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_MMIC_STRIPPED |
+                                  RX_FLAG_MIC_STRIPPED | RX_FLAG_ICV_STRIPPED;
+
+       skb_queue_walk(amsdu_list, msdu) {
+               ath11k_dp_rx_h_csum_offload(msdu);
+               ath11k_dp_rx_h_undecap(ar, msdu, rx_desc,
+                                      enctype, rx_status, is_decrypted);
+       }
+}
+
+static void ath11k_dp_rx_h_rate(struct ath11k *ar, struct hal_rx_desc *rx_desc,
+                               struct ieee80211_rx_status *rx_status)
+{
+       struct ieee80211_supported_band *sband;
+       enum rx_msdu_start_pkt_type pkt_type;
+       u8 bw;
+       u8 rate_mcs, nss;
+       u8 sgi;
+       bool is_cck;
+
+       pkt_type = ath11k_dp_rx_h_msdu_start_pkt_type(rx_desc);
+       bw = ath11k_dp_rx_h_msdu_start_rx_bw(rx_desc);
+       rate_mcs = ath11k_dp_rx_h_msdu_start_rate_mcs(rx_desc);
+       nss = ath11k_dp_rx_h_msdu_start_nss(rx_desc);
+       sgi = ath11k_dp_rx_h_msdu_start_sgi(rx_desc);
+
+       switch (pkt_type) {
+       case RX_MSDU_START_PKT_TYPE_11A:
+       case RX_MSDU_START_PKT_TYPE_11B:
+               is_cck = (pkt_type == RX_MSDU_START_PKT_TYPE_11B);
+               sband = &ar->mac.sbands[rx_status->band];
+               rx_status->rate_idx = ath11k_mac_hw_rate_to_idx(sband, rate_mcs,
+                                                               is_cck);
+               break;
+       case RX_MSDU_START_PKT_TYPE_11N:
+               rx_status->encoding = RX_ENC_HT;
+               if (rate_mcs > ATH11K_HT_MCS_MAX) {
+                       ath11k_warn(ar->ab,
+                                   "Received with invalid mcs in HT mode %d\n",
+                                    rate_mcs);
+                       break;
+               }
+               rx_status->rate_idx = rate_mcs + (8 * (nss - 1));
+               if (sgi)
+                       rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+               rx_status->bw = ath11k_bw_to_mac80211_bw(bw);
+               break;
+       case RX_MSDU_START_PKT_TYPE_11AC:
+               rx_status->encoding = RX_ENC_VHT;
+               rx_status->rate_idx = rate_mcs;
+               if (rate_mcs > ATH11K_VHT_MCS_MAX) {
+                       ath11k_warn(ar->ab,
+                                   "Received with invalid mcs in VHT mode %d\n",
+                                    rate_mcs);
+                       break;
+               }
+               rx_status->nss = nss;
+               if (sgi)
+                       rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+               rx_status->bw = ath11k_bw_to_mac80211_bw(bw);
+               break;
+       case RX_MSDU_START_PKT_TYPE_11AX:
+               rx_status->rate_idx = rate_mcs;
+               if (rate_mcs > ATH11K_HE_MCS_MAX) {
+                       ath11k_warn(ar->ab,
+                                   "Received with invalid mcs in HE mode %d\n",
+                                   rate_mcs);
+                       break;
+               }
+               rx_status->encoding = RX_ENC_HE;
+               rx_status->nss = nss;
+               rx_status->bw = ath11k_bw_to_mac80211_bw(bw);
+               break;
+       }
+}
+
+static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc,
+                               struct ieee80211_rx_status *rx_status)
+{
+       u8 channel_num;
+
+       rx_status->freq = 0;
+       rx_status->rate_idx = 0;
+       rx_status->nss = 0;
+       rx_status->encoding = RX_ENC_LEGACY;
+       rx_status->bw = RATE_INFO_BW_20;
+
+       rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+
+       channel_num = ath11k_dp_rx_h_msdu_start_freq(rx_desc);
+
+       if (channel_num >= 1 && channel_num <= 14) {
+               rx_status->band = NL80211_BAND_2GHZ;
+       } else if (channel_num >= 36 && channel_num <= 173) {
+               rx_status->band = NL80211_BAND_5GHZ;
+       } else {
+               ath11k_warn(ar->ab, "Unsupported Channel info received %d\n",
+                           channel_num);
+               return;
+       }
+
+       rx_status->freq = ieee80211_channel_to_frequency(channel_num,
+                                                        rx_status->band);
+
+       ath11k_dp_rx_h_rate(ar, rx_desc, rx_status);
+}
+
+static void ath11k_dp_rx_process_amsdu(struct ath11k *ar,
+                                      struct sk_buff_head *amsdu_list,
+                                      struct ieee80211_rx_status *rx_status)
+{
+       struct sk_buff *first;
+       struct ath11k_skb_rxcb *rxcb;
+       struct hal_rx_desc *rx_desc;
+       bool first_mpdu;
+
+       if (skb_queue_empty(amsdu_list))
+               return;
+
+       first = skb_peek(amsdu_list);
+       rxcb = ATH11K_SKB_RXCB(first);
+       rx_desc = rxcb->rx_desc;
+
+       first_mpdu = ath11k_dp_rx_h_attn_first_mpdu(rx_desc);
+       if (first_mpdu)
+               ath11k_dp_rx_h_ppdu(ar, rx_desc, rx_status);
+
+       ath11k_dp_rx_h_mpdu(ar, amsdu_list, rx_desc, rx_status);
+}
+
+static char *ath11k_print_get_tid(struct ieee80211_hdr *hdr, char *out,
+                                 size_t size)
+{
+       u8 *qc;
+       int tid;
+
+       if (!ieee80211_is_data_qos(hdr->frame_control))
+               return "";
+
+       qc = ieee80211_get_qos_ctl(hdr);
+       tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+       snprintf(out, size, "tid %d", tid);
+
+       return out;
+}
+
+static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *napi,
+                                     struct sk_buff *msdu)
+{
+       struct ieee80211_rx_status *status;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
+       char tid[32];
+
+       status = IEEE80211_SKB_RXCB(msdu);
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+                  "rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
+                  msdu,
+                  msdu->len,
+                  ieee80211_get_SA(hdr),
+                  ath11k_print_get_tid(hdr, tid, sizeof(tid)),
+                  is_multicast_ether_addr(ieee80211_get_DA(hdr)) ?
+                                                       "mcast" : "ucast",
+                  (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4,
+                  (status->encoding == RX_ENC_LEGACY) ? "legacy" : "",
+                  (status->encoding == RX_ENC_HT) ? "ht" : "",
+                  (status->encoding == RX_ENC_VHT) ? "vht" : "",
+                  (status->encoding == RX_ENC_HE) ? "he" : "",
+                  (status->bw == RATE_INFO_BW_40) ? "40" : "",
+                  (status->bw == RATE_INFO_BW_80) ? "80" : "",
+                  (status->bw == RATE_INFO_BW_160) ? "160" : "",
+                  status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "",
+                  status->rate_idx,
+                  status->nss,
+                  status->freq,
+                  status->band, status->flag,
+                  !!(status->flag & RX_FLAG_FAILED_FCS_CRC),
+                  !!(status->flag & RX_FLAG_MMIC_ERROR),
+                  !!(status->flag & RX_FLAG_AMSDU_MORE));
+
+       /* TODO: trace rx packet */
+
+       ieee80211_rx_napi(ar->hw, NULL, msdu, napi);
+}
+
+static void ath11k_dp_rx_pre_deliver_amsdu(struct ath11k *ar,
+                                          struct sk_buff_head *amsdu_list,
+                                          struct ieee80211_rx_status *rxs)
+{
+       struct sk_buff *msdu;
+       struct sk_buff *first_subframe;
+       struct ieee80211_rx_status *status;
+
+       first_subframe = skb_peek(amsdu_list);
+
+       skb_queue_walk(amsdu_list, msdu) {
+               /* Setup per-MSDU flags */
+               if (skb_queue_empty(amsdu_list))
+                       rxs->flag &= ~RX_FLAG_AMSDU_MORE;
+               else
+                       rxs->flag |= RX_FLAG_AMSDU_MORE;
+
+               if (msdu == first_subframe) {
+                       first_subframe = NULL;
+                       rxs->flag &= ~RX_FLAG_ALLOW_SAME_PN;
+               } else {
+                       rxs->flag |= RX_FLAG_ALLOW_SAME_PN;
+               }
+               rxs->flag |= RX_FLAG_SKIP_MONITOR;
+
+               status = IEEE80211_SKB_RXCB(msdu);
+               *status = *rxs;
+       }
+}
+
+static void ath11k_dp_rx_process_pending_packets(struct ath11k_base *ab,
+                                                struct napi_struct *napi,
+                                                struct sk_buff_head *pending_q,
+                                                int *quota, u8 mac_id)
+{
+       struct ath11k *ar;
+       struct sk_buff *msdu;
+       struct ath11k_pdev *pdev;
+
+       if (skb_queue_empty(pending_q))
+               return;
+
+       ar = ab->pdevs[mac_id].ar;
+
+       rcu_read_lock();
+       pdev = rcu_dereference(ab->pdevs_active[mac_id]);
+
+       while (*quota && (msdu = __skb_dequeue(pending_q))) {
+               if (!pdev) {
+                       dev_kfree_skb_any(msdu);
+                       continue;
+               }
+
+               ath11k_dp_rx_deliver_msdu(ar, napi, msdu);
+               (*quota)--;
+       }
+       rcu_read_unlock();
+}
+
+int ath11k_dp_process_rx(struct ath11k_base *ab, int mac_id,
+                        struct napi_struct *napi, struct sk_buff_head *pending_q,
+                        int budget)
+{
+       struct ath11k *ar = ab->pdevs[mac_id].ar;
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct ieee80211_rx_status *rx_status = &dp->rx_status;
+       struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
+       struct hal_srng *srng;
+       struct hal_rx_meta_info meta_info;
+       struct sk_buff *msdu;
+       struct sk_buff_head msdu_list;
+       struct sk_buff_head amsdu_list;
+       struct ath11k_skb_rxcb *rxcb;
+       u32 *rx_desc;
+       int buf_id;
+       int num_buffs_reaped = 0;
+       int quota = budget;
+       int ret;
+       bool done = false;
+
+       /* Process any pending packets from the previous napi poll.
+        * Note: All msdu's in this pending_q corresponds to the same mac id
+        * due to pdev based reo dest mapping and also since each irq group id
+        * maps to specific reo dest ring.
+        */
+       ath11k_dp_rx_process_pending_packets(ab, napi, pending_q, "a,
+                                            mac_id);
+
+       /* If all quota is exhausted by processing the pending_q,
+        * Wait for the next napi poll to reap the new info
+        */
+       if (!quota)
+               goto exit;
+
+       __skb_queue_head_init(&msdu_list);
+
+       srng = &ab->hal.srng_list[dp->reo_dst_ring.ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+try_again:
+       while ((rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) {
+               memset(&meta_info, 0, sizeof(meta_info));
+               ath11k_hal_rx_parse_dst_ring_desc(ab, rx_desc, &meta_info);
+
+               buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
+                                  meta_info.msdu_meta.cookie);
+               spin_lock_bh(&rx_ring->idr_lock);
+               msdu = idr_find(&rx_ring->bufs_idr, buf_id);
+               if (!msdu) {
+                       ath11k_warn(ab, "frame rx with invalid buf_id %d\n",
+                                   buf_id);
+                       spin_unlock_bh(&rx_ring->idr_lock);
+                       continue;
+               }
+
+               idr_remove(&rx_ring->bufs_idr, buf_id);
+               spin_unlock_bh(&rx_ring->idr_lock);
+
+               rxcb = ATH11K_SKB_RXCB(msdu);
+               dma_unmap_single(ab->dev, rxcb->paddr,
+                                msdu->len + skb_tailroom(msdu),
+                                DMA_FROM_DEVICE);
+
+               num_buffs_reaped++;
+
+               if (meta_info.push_reason !=
+                   HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) {
+                       /* TODO: Check if the msdu can be sent up for processing */
+                       dev_kfree_skb_any(msdu);
+                       ab->soc_stats.hal_reo_error[dp->reo_dst_ring.ring_id]++;
+                       continue;
+               }
+
+               rxcb->is_first_msdu = meta_info.msdu_meta.first;
+               rxcb->is_last_msdu = meta_info.msdu_meta.last;
+               rxcb->is_continuation = meta_info.msdu_meta.continuation;
+               rxcb->mac_id = mac_id;
+               __skb_queue_tail(&msdu_list, msdu);
+
+               /* Stop reaping from the ring once quota is exhausted
+                * and we've received all msdu's in the the AMSDU. The
+                * additional msdu's reaped in excess of quota here would
+                * be pushed into the pending queue to be processed during
+                * the next napi poll.
+                * Note: More profiling can be done to see the impact on
+                * pending_q and throughput during various traffic & density
+                * and how use of budget instead of remaining quota affects it.
+                */
+               if (num_buffs_reaped >= quota && rxcb->is_last_msdu &&
+                   !rxcb->is_continuation) {
+                       done = true;
+                       break;
+               }
+       }
+
+       /* Hw might have updated the head pointer after we cached it.
+        * In this case, even though there are entries in the ring we'll
+        * get rx_desc NULL. Give the read another try with updated cached
+        * head pointer so that we can reap complete MPDU in the current
+        * rx processing.
+        */
+       if (!done && ath11k_hal_srng_dst_num_free(ab, srng, true)) {
+               ath11k_hal_srng_access_end(ab, srng);
+               goto try_again;
+       }
+
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       if (!num_buffs_reaped)
+               goto exit;
+
+       /* Should we reschedule it later if we are not able to replenish all
+        * the buffers?
+        */
+       ath11k_dp_rxbufs_replenish(ab, mac_id, rx_ring, num_buffs_reaped,
+                                  HAL_RX_BUF_RBM_SW3_BM, GFP_ATOMIC);
+
+       rcu_read_lock();
+       if (!rcu_dereference(ab->pdevs_active[mac_id])) {
+               __skb_queue_purge(&msdu_list);
+               goto rcu_unlock;
+       }
+
+       if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) {
+               __skb_queue_purge(&msdu_list);
+               goto rcu_unlock;
+       }
+
+       while (!skb_queue_empty(&msdu_list)) {
+               __skb_queue_head_init(&amsdu_list);
+               ret = ath11k_dp_rx_retrieve_amsdu(ar, &msdu_list, &amsdu_list);
+               if (ret) {
+                       if (ret == -EIO) {
+                               ath11k_err(ab, "rx ring got corrupted %d\n", ret);
+                               __skb_queue_purge(&msdu_list);
+                               /* Should stop processing any more rx in
+                                * future from this ring?
+                                */
+                               goto rcu_unlock;
+                       }
+
+                       /* A-MSDU retrieval got failed due to non-fatal condition,
+                        * continue processing with the next msdu.
+                        */
+                       continue;
+               }
+
+               ath11k_dp_rx_process_amsdu(ar, &amsdu_list, rx_status);
+
+               ath11k_dp_rx_pre_deliver_amsdu(ar, &amsdu_list, rx_status);
+               skb_queue_splice_tail(&amsdu_list, pending_q);
+       }
+
+       while (quota && (msdu = __skb_dequeue(pending_q))) {
+               ath11k_dp_rx_deliver_msdu(ar, napi, msdu);
+               quota--;
+       }
+
+rcu_unlock:
+       rcu_read_unlock();
+exit:
+       return budget - quota;
+}
+
+static void ath11k_dp_rx_update_peer_stats(struct ath11k_sta *arsta,
+                                          struct hal_rx_mon_ppdu_info *ppdu_info)
+{
+       struct ath11k_rx_peer_stats *rx_stats = arsta->rx_stats;
+       u32 num_msdu;
+
+       if (!rx_stats)
+               return;
+
+       num_msdu = ppdu_info->tcp_msdu_count + ppdu_info->tcp_ack_msdu_count +
+                  ppdu_info->udp_msdu_count + ppdu_info->other_msdu_count;
+
+       rx_stats->num_msdu += num_msdu;
+       rx_stats->tcp_msdu_count += ppdu_info->tcp_msdu_count +
+                                   ppdu_info->tcp_ack_msdu_count;
+       rx_stats->udp_msdu_count += ppdu_info->udp_msdu_count;
+       rx_stats->other_msdu_count += ppdu_info->other_msdu_count;
+
+       if (ppdu_info->preamble_type == HAL_RX_PREAMBLE_11A ||
+           ppdu_info->preamble_type == HAL_RX_PREAMBLE_11B) {
+               ppdu_info->nss = 1;
+               ppdu_info->mcs = HAL_RX_MAX_MCS;
+               ppdu_info->tid = IEEE80211_NUM_TIDS;
+       }
+
+       if (ppdu_info->nss > 0 && ppdu_info->nss <= HAL_RX_MAX_NSS)
+               rx_stats->nss_count[ppdu_info->nss - 1] += num_msdu;
+
+       if (ppdu_info->mcs <= HAL_RX_MAX_MCS)
+               rx_stats->mcs_count[ppdu_info->mcs] += num_msdu;
+
+       if (ppdu_info->gi < HAL_RX_GI_MAX)
+               rx_stats->gi_count[ppdu_info->gi] += num_msdu;
+
+       if (ppdu_info->bw < HAL_RX_BW_MAX)
+               rx_stats->bw_count[ppdu_info->bw] += num_msdu;
+
+       if (ppdu_info->ldpc < HAL_RX_SU_MU_CODING_MAX)
+               rx_stats->coding_count[ppdu_info->ldpc] += num_msdu;
+
+       if (ppdu_info->tid <= IEEE80211_NUM_TIDS)
+               rx_stats->tid_count[ppdu_info->tid] += num_msdu;
+
+       if (ppdu_info->preamble_type < HAL_RX_PREAMBLE_MAX)
+               rx_stats->pream_cnt[ppdu_info->preamble_type] += num_msdu;
+
+       if (ppdu_info->reception_type < HAL_RX_RECEPTION_TYPE_MAX)
+               rx_stats->reception_type[ppdu_info->reception_type] += num_msdu;
+
+       if (ppdu_info->is_stbc)
+               rx_stats->stbc_count += num_msdu;
+
+       if (ppdu_info->beamformed)
+               rx_stats->beamformed_count += num_msdu;
+
+       if (ppdu_info->num_mpdu_fcs_ok > 1)
+               rx_stats->ampdu_msdu_count += num_msdu;
+       else
+               rx_stats->non_ampdu_msdu_count += num_msdu;
+
+       rx_stats->num_mpdu_fcs_ok += ppdu_info->num_mpdu_fcs_ok;
+       rx_stats->num_mpdu_fcs_err += ppdu_info->num_mpdu_fcs_err;
+
+       arsta->rssi_comb = ppdu_info->rssi_comb;
+       rx_stats->rx_duration += ppdu_info->rx_duration;
+       arsta->rx_duration = rx_stats->rx_duration;
+}
+
+static struct sk_buff *ath11k_dp_rx_alloc_mon_status_buf(struct ath11k_base *ab,
+                                                        struct dp_rxdma_ring *rx_ring,
+                                                        int *buf_id, gfp_t gfp)
+{
+       struct sk_buff *skb;
+       dma_addr_t paddr;
+
+       skb = dev_alloc_skb(DP_RX_BUFFER_SIZE +
+                           DP_RX_BUFFER_ALIGN_SIZE);
+
+       if (!skb)
+               goto fail_alloc_skb;
+
+       if (!IS_ALIGNED((unsigned long)skb->data,
+                       DP_RX_BUFFER_ALIGN_SIZE)) {
+               skb_pull(skb, PTR_ALIGN(skb->data, DP_RX_BUFFER_ALIGN_SIZE) -
+                        skb->data);
+       }
+
+       paddr = dma_map_single(ab->dev, skb->data,
+                              skb->len + skb_tailroom(skb),
+                              DMA_BIDIRECTIONAL);
+       if (unlikely(dma_mapping_error(ab->dev, paddr)))
+               goto fail_free_skb;
+
+       spin_lock_bh(&rx_ring->idr_lock);
+       *buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0,
+                           rx_ring->bufs_max, gfp);
+       spin_unlock_bh(&rx_ring->idr_lock);
+       if (*buf_id < 0)
+               goto fail_dma_unmap;
+
+       ATH11K_SKB_RXCB(skb)->paddr = paddr;
+       return skb;
+
+fail_dma_unmap:
+       dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb),
+                        DMA_BIDIRECTIONAL);
+fail_free_skb:
+       dev_kfree_skb_any(skb);
+fail_alloc_skb:
+       return NULL;
+}
+
+int ath11k_dp_rx_mon_status_bufs_replenish(struct ath11k_base *ab, int mac_id,
+                                          struct dp_rxdma_ring *rx_ring,
+                                          int req_entries,
+                                          enum hal_rx_buf_return_buf_manager mgr,
+                                          gfp_t gfp)
+{
+       struct hal_srng *srng;
+       u32 *desc;
+       struct sk_buff *skb;
+       int num_free;
+       int num_remain;
+       int buf_id;
+       u32 cookie;
+       dma_addr_t paddr;
+
+       req_entries = min(req_entries, rx_ring->bufs_max);
+
+       srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       num_free = ath11k_hal_srng_src_num_free(ab, srng, true);
+
+       req_entries = min(num_free, req_entries);
+       num_remain = req_entries;
+
+       while (num_remain > 0) {
+               skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring,
+                                                       &buf_id, gfp);
+               if (!skb)
+                       break;
+               paddr = ATH11K_SKB_RXCB(skb)->paddr;
+
+               desc = ath11k_hal_srng_src_get_next_entry(ab, srng);
+               if (!desc)
+                       goto fail_desc_get;
+
+               cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) |
+                        FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id);
+
+               num_remain--;
+
+               ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr);
+       }
+
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       return req_entries - num_remain;
+
+fail_desc_get:
+       spin_lock_bh(&rx_ring->idr_lock);
+       idr_remove(&rx_ring->bufs_idr, buf_id);
+       spin_unlock_bh(&rx_ring->idr_lock);
+       dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb),
+                        DMA_BIDIRECTIONAL);
+       dev_kfree_skb_any(skb);
+       ath11k_hal_srng_access_end(ab, srng);
+       spin_unlock_bh(&srng->lock);
+
+       return req_entries - num_remain;
+}
+
+static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id,
+                                            int *budget, struct sk_buff_head *skb_list)
+{
+       struct ath11k *ar = ab->pdevs[mac_id].ar;
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct dp_rxdma_ring *rx_ring = &dp->rx_mon_status_refill_ring;
+       struct hal_srng *srng;
+       void *rx_mon_status_desc;
+       struct sk_buff *skb;
+       struct ath11k_skb_rxcb *rxcb;
+       struct hal_tlv_hdr *tlv;
+       u32 cookie;
+       int buf_id;
+       dma_addr_t paddr;
+       u8 rbm;
+       int num_buffs_reaped = 0;
+
+       srng = &ab->hal.srng_list[rx_ring->refill_buf_ring.ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+       while (*budget) {
+               *budget -= 1;
+               rx_mon_status_desc =
+                       ath11k_hal_srng_src_peek(ab, srng);
+               if (!rx_mon_status_desc)
+                       break;
+
+               ath11k_hal_rx_buf_addr_info_get(rx_mon_status_desc, &paddr,
+                                               &cookie, &rbm);
+               if (paddr) {
+                       buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie);
+
+                       spin_lock_bh(&rx_ring->idr_lock);
+                       skb = idr_find(&rx_ring->bufs_idr, buf_id);
+                       if (!skb) {
+                               ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n",
+                                           buf_id);
+                               spin_unlock_bh(&rx_ring->idr_lock);
+                               continue;
+                       }
+
+                       idr_remove(&rx_ring->bufs_idr, buf_id);
+                       spin_unlock_bh(&rx_ring->idr_lock);
+
+                       rxcb = ATH11K_SKB_RXCB(skb);
+
+                       dma_sync_single_for_cpu(ab->dev, rxcb->paddr,
+                                               skb->len + skb_tailroom(skb),
+                                               DMA_FROM_DEVICE);
+
+                       dma_unmap_single(ab->dev, rxcb->paddr,
+                                        skb->len + skb_tailroom(skb),
+                                        DMA_BIDIRECTIONAL);
+
+                       tlv = (struct hal_tlv_hdr *)skb->data;
+                       if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) !=
+                                       HAL_RX_STATUS_BUFFER_DONE) {
+                               ath11k_hal_srng_src_get_next_entry(ab, srng);
+                               continue;
+                       }
+
+                       __skb_queue_tail(skb_list, skb);
+               }
+
+               skb = ath11k_dp_rx_alloc_mon_status_buf(ab, rx_ring,
+                                                       &buf_id, GFP_ATOMIC);
+
+               if (!skb) {
+                       ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, 0, 0,
+                                                       HAL_RX_BUF_RBM_SW3_BM);
+                       num_buffs_reaped++;
+                       break;
+               }
+               rxcb = ATH11K_SKB_RXCB(skb);
+
+               cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, mac_id) |
+                        FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id);
+
+               ath11k_hal_rx_buf_addr_info_set(rx_mon_status_desc, rxcb->paddr,
+                                               cookie, HAL_RX_BUF_RBM_SW3_BM);
+               ath11k_hal_srng_src_get_next_entry(ab, srng);
+               num_buffs_reaped++;
+       }
+       ath11k_hal_srng_access_end(ab, srng);
+       spin_unlock_bh(&srng->lock);
+
+       return num_buffs_reaped;
+}
+
+int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
+                                   struct napi_struct *napi, int budget)
+{
+       struct ath11k *ar = ab->pdevs[mac_id].ar;
+       enum hal_rx_mon_status hal_status;
+       struct sk_buff *skb;
+       struct sk_buff_head skb_list;
+       struct hal_rx_mon_ppdu_info ppdu_info;
+       struct ath11k_peer *peer;
+       struct ath11k_sta *arsta;
+       int num_buffs_reaped = 0;
+
+       __skb_queue_head_init(&skb_list);
+
+       num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ab, mac_id, &budget,
+                                                            &skb_list);
+       if (!num_buffs_reaped)
+               goto exit;
+
+       while ((skb = __skb_dequeue(&skb_list))) {
+               memset(&ppdu_info, 0, sizeof(ppdu_info));
+               ppdu_info.peer_id = HAL_INVALID_PEERID;
+
+               if (ath11k_debug_is_pktlog_rx_stats_enabled(ar))
+                       trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE);
+
+               hal_status = ath11k_hal_rx_parse_mon_status(ab, &ppdu_info, skb);
+
+               if (ppdu_info.peer_id == HAL_INVALID_PEERID ||
+                   hal_status != HAL_RX_MON_STATUS_PPDU_DONE) {
+                       dev_kfree_skb_any(skb);
+                       continue;
+               }
+
+               rcu_read_lock();
+               spin_lock_bh(&ab->base_lock);
+               peer = ath11k_peer_find_by_id(ab, ppdu_info.peer_id);
+
+               if (!peer || !peer->sta) {
+                       ath11k_warn(ab, "failed to find the peer with peer_id %d\n",
+                                   ppdu_info.peer_id);
+                       spin_unlock_bh(&ab->base_lock);
+                       rcu_read_unlock();
+                       dev_kfree_skb_any(skb);
+                       continue;
+               }
+
+               arsta = (struct ath11k_sta *)peer->sta->drv_priv;
+               ath11k_dp_rx_update_peer_stats(arsta, &ppdu_info);
+
+               if (ath11k_debug_is_pktlog_peer_valid(ar, peer->addr))
+                       trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE);
+
+               spin_unlock_bh(&ab->base_lock);
+               rcu_read_unlock();
+
+               dev_kfree_skb_any(skb);
+       }
+exit:
+       return num_buffs_reaped;
+}
+
+static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
+                                        u32 *link_desc,
+                                        enum hal_wbm_rel_bm_act action)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       struct hal_srng *srng;
+       u32 *desc;
+       int ret = 0;
+
+       srng = &ab->hal.srng_list[dp->wbm_desc_rel_ring.ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       desc = ath11k_hal_srng_src_get_next_entry(ab, srng);
+       if (!desc) {
+               ret = -ENOBUFS;
+               goto exit;
+       }
+
+       ath11k_hal_rx_msdu_link_desc_set(ab, (void *)desc, (void *)link_desc,
+                                        action);
+
+exit:
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       return ret;
+}
+
+static void ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar,
+                                    struct sk_buff *msdu,
+                                    struct hal_rx_desc *rx_desc,
+                                    struct ieee80211_rx_status *rx_status)
+{
+       u8 rx_channel;
+       enum hal_encrypt_type enctype;
+       bool is_decrypted;
+       u32 err_bitmap;
+
+       is_decrypted = ath11k_dp_rx_h_attn_is_decrypted(rx_desc);
+       enctype = ath11k_dp_rx_h_mpdu_start_enctype(rx_desc);
+       err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_desc);
+
+       if (err_bitmap & DP_RX_MPDU_ERR_FCS)
+               rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+       if (err_bitmap & DP_RX_MPDU_ERR_TKIP_MIC)
+               rx_status->flag |= RX_FLAG_MMIC_ERROR;
+
+       rx_status->encoding = RX_ENC_LEGACY;
+       rx_status->bw = RATE_INFO_BW_20;
+
+       rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+
+       rx_channel = ath11k_dp_rx_h_msdu_start_freq(rx_desc);
+
+       if (rx_channel >= 1 && rx_channel <= 14) {
+               rx_status->band = NL80211_BAND_2GHZ;
+       } else if (rx_channel >= 36 && rx_channel <= 173) {
+               rx_status->band = NL80211_BAND_5GHZ;
+       } else {
+               ath11k_warn(ar->ab, "Unsupported Channel info received %d\n",
+                           rx_channel);
+               return;
+       }
+
+       rx_status->freq = ieee80211_channel_to_frequency(rx_channel,
+                                                        rx_status->band);
+       ath11k_dp_rx_h_rate(ar, rx_desc, rx_status);
+
+       /* Rx fragments are received in raw mode */
+       skb_trim(msdu, msdu->len - FCS_LEN);
+
+       if (is_decrypted) {
+               rx_status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_MIC_STRIPPED;
+               skb_trim(msdu, msdu->len -
+                        ath11k_dp_rx_crypto_mic_len(ar, enctype));
+       }
+}
+
+static int
+ath11k_dp_process_rx_err_buf(struct ath11k *ar, struct napi_struct *napi,
+                            int buf_id, bool frag)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
+       struct ieee80211_rx_status rx_status = {0};
+       struct sk_buff *msdu;
+       struct ath11k_skb_rxcb *rxcb;
+       struct ieee80211_rx_status *status;
+       struct hal_rx_desc *rx_desc;
+       u16 msdu_len;
+
+       spin_lock_bh(&rx_ring->idr_lock);
+       msdu = idr_find(&rx_ring->bufs_idr, buf_id);
+       if (!msdu) {
+               ath11k_warn(ar->ab, "rx err buf with invalid buf_id %d\n",
+                           buf_id);
+               spin_unlock_bh(&rx_ring->idr_lock);
+               return -EINVAL;
+       }
+
+       idr_remove(&rx_ring->bufs_idr, buf_id);
+       spin_unlock_bh(&rx_ring->idr_lock);
+
+       rxcb = ATH11K_SKB_RXCB(msdu);
+       dma_unmap_single(ar->ab->dev, rxcb->paddr,
+                        msdu->len + skb_tailroom(msdu),
+                        DMA_FROM_DEVICE);
+
+       if (!frag) {
+               /* Process only rx fragments below, and drop
+                * msdu's indicated due to error reasons.
+                */
+               dev_kfree_skb_any(msdu);
+               return 0;
+       }
+
+       rcu_read_lock();
+       if (!rcu_dereference(ar->ab->pdevs_active[ar->pdev_idx])) {
+               dev_kfree_skb_any(msdu);
+               goto exit;
+       }
+
+       if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) {
+               dev_kfree_skb_any(msdu);
+               goto exit;
+       }
+
+       rx_desc = (struct hal_rx_desc *)msdu->data;
+       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(rx_desc);
+       skb_put(msdu, HAL_RX_DESC_SIZE + msdu_len);
+       skb_pull(msdu, HAL_RX_DESC_SIZE);
+
+       ath11k_dp_rx_frag_h_mpdu(ar, msdu, rx_desc, &rx_status);
+
+       status = IEEE80211_SKB_RXCB(msdu);
+
+       *status = rx_status;
+
+       ath11k_dp_rx_deliver_msdu(ar, napi, msdu);
+
+exit:
+       rcu_read_unlock();
+       return 0;
+}
+
+int ath11k_dp_process_rx_err(struct ath11k_base *ab, struct napi_struct *napi,
+                            int budget)
+{
+       struct hal_rx_msdu_meta meta[HAL_NUM_RX_MSDUS_PER_LINK_DESC];
+       struct dp_link_desc_bank *link_desc_banks;
+       enum hal_rx_buf_return_buf_manager rbm;
+       int tot_n_bufs_reaped, quota, ret, i;
+       int n_bufs_reaped[MAX_RADIOS] = {0};
+       struct hal_rx_meta_info meta_info;
+       struct dp_rxdma_ring *rx_ring;
+       struct dp_srng *reo_except;
+       u32 desc_bank, num_msdus;
+       struct hal_srng *srng;
+       struct ath11k_dp *dp;
+       void *link_desc_va;
+       int buf_id, mac_id;
+       struct ath11k *ar;
+       dma_addr_t paddr;
+       u32 *desc;
+       bool is_frag;
+
+       tot_n_bufs_reaped = 0;
+       quota = budget;
+
+       dp = &ab->dp;
+       reo_except = &dp->reo_except_ring;
+       link_desc_banks = dp->link_desc_banks;
+
+       srng = &ab->hal.srng_list[reo_except->ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       while (budget &&
+              (desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) {
+               ab->soc_stats.err_ring_pkts++;
+               ret = ath11k_hal_desc_reo_parse_err(ab, desc, &paddr,
+                                                   &desc_bank);
+               if (ret) {
+                       ath11k_warn(ab, "failed to parse error reo desc %d\n",
+                                   ret);
+                       continue;
+               }
+               link_desc_va = link_desc_banks[desc_bank].vaddr +
+                              (paddr - link_desc_banks[desc_bank].paddr);
+               ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, meta,
+                                                &rbm);
+               if (rbm != HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST &&
+                   rbm != HAL_RX_BUF_RBM_SW3_BM) {
+                       ab->soc_stats.invalid_rbm++;
+                       ath11k_warn(ab, "invalid return buffer manager %d\n", rbm);
+                       ath11k_dp_rx_link_desc_return(ab, desc,
+                                                     HAL_WBM_REL_BM_ACT_REL_MSDU);
+                       continue;
+               }
+
+               memset(&meta_info, 0, sizeof(meta_info));
+               ath11k_hal_rx_parse_dst_ring_desc(ab, desc, &meta_info);
+
+               is_frag = meta_info.mpdu_meta.frag;
+
+               /* Return the link desc back to wbm idle list */
+               ath11k_dp_rx_link_desc_return(ab, desc,
+                                             HAL_WBM_REL_BM_ACT_PUT_IN_IDLE);
+
+               for (i = 0; i < num_msdus; i++) {
+                       buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
+                                          meta[i].cookie);
+
+                       mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID,
+                                          meta[i].cookie);
+
+                       ar = ab->pdevs[mac_id].ar;
+
+                       if (!ath11k_dp_process_rx_err_buf(ar, napi, buf_id,
+                                                         is_frag)) {
+                               n_bufs_reaped[mac_id]++;
+                               tot_n_bufs_reaped++;
+                       }
+               }
+
+               if (tot_n_bufs_reaped >= quota) {
+                       tot_n_bufs_reaped = quota;
+                       goto exit;
+               }
+
+               budget = quota - tot_n_bufs_reaped;
+       }
+
+exit:
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       for (i = 0; i <  ab->num_radios; i++) {
+               if (!n_bufs_reaped[i])
+                       continue;
+
+               ar = ab->pdevs[i].ar;
+               rx_ring = &ar->dp.rx_refill_buf_ring;
+
+               ath11k_dp_rxbufs_replenish(ab, i, rx_ring, n_bufs_reaped[i],
+                                          HAL_RX_BUF_RBM_SW3_BM, GFP_ATOMIC);
+       }
+
+       return tot_n_bufs_reaped;
+}
+
+static void ath11k_dp_rx_null_q_desc_sg_drop(struct ath11k *ar,
+                                            int msdu_len,
+                                            struct sk_buff_head *msdu_list)
+{
+       struct sk_buff *skb, *tmp;
+       struct ath11k_skb_rxcb *rxcb;
+       int n_buffs;
+
+       n_buffs = DIV_ROUND_UP(msdu_len,
+                              (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE));
+
+       skb_queue_walk_safe(msdu_list, skb, tmp) {
+               rxcb = ATH11K_SKB_RXCB(skb);
+               if (rxcb->err_rel_src == HAL_WBM_REL_SRC_MODULE_REO &&
+                   rxcb->err_code == HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO) {
+                       if (!n_buffs)
+                               break;
+                       __skb_unlink(skb, msdu_list);
+                       dev_kfree_skb_any(skb);
+                       n_buffs--;
+               }
+       }
+}
+
+static int ath11k_dp_rx_h_null_q_desc(struct ath11k *ar, struct sk_buff *msdu,
+                                     struct ieee80211_rx_status *status,
+                                     struct sk_buff_head *msdu_list)
+{
+       struct sk_buff_head amsdu_list;
+       u16 msdu_len;
+       struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data;
+       u8 l3pad_bytes;
+       struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+
+       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(desc);
+
+       if ((msdu_len + HAL_RX_DESC_SIZE) > DP_RX_BUFFER_SIZE) {
+               /* First buffer will be freed by the caller, so deduct it's length */
+               msdu_len = msdu_len - (DP_RX_BUFFER_SIZE - HAL_RX_DESC_SIZE);
+               ath11k_dp_rx_null_q_desc_sg_drop(ar, msdu_len, msdu_list);
+               return -EINVAL;
+       }
+
+       if (!ath11k_dp_rx_h_attn_msdu_done(desc)) {
+               ath11k_warn(ar->ab,
+                           "msdu_done bit not set in null_q_des processing\n");
+               __skb_queue_purge(msdu_list);
+               return -EIO;
+       }
+
+       /* Handle NULL queue descriptor violations arising out a missing
+        * REO queue for a given peer or a given TID. This typically
+        * may happen if a packet is received on a QOS enabled TID before the
+        * ADDBA negotiation for that TID, when the TID queue is setup. Or
+        * it may also happen for MC/BC frames if they are not routed to the
+        * non-QOS TID queue, in the absence of any other default TID queue.
+        * This error can show up both in a REO destination or WBM release ring.
+        */
+
+       __skb_queue_head_init(&amsdu_list);
+
+       rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(desc);
+       rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(desc);
+
+       l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(desc);
+
+       if ((HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE)
+               return -EINVAL;
+
+       skb_put(msdu, HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len);
+       skb_pull(msdu, HAL_RX_DESC_SIZE + l3pad_bytes);
+
+       ath11k_dp_rx_h_ppdu(ar, desc, status);
+
+       __skb_queue_tail(&amsdu_list, msdu);
+
+       ath11k_dp_rx_h_mpdu(ar, &amsdu_list, desc, status);
+
+       /* Please note that caller will having the access to msdu and completing
+        * rx with mac80211. Need not worry about cleaning up amsdu_list.
+        */
+
+       return 0;
+}
+
+static bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu,
+                                  struct ieee80211_rx_status *status,
+                                  struct sk_buff_head *msdu_list)
+{
+       struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+       bool drop = false;
+
+       ar->ab->soc_stats.reo_error[rxcb->err_code]++;
+
+       switch (rxcb->err_code) {
+       case HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO:
+               if (ath11k_dp_rx_h_null_q_desc(ar, msdu, status, msdu_list))
+                       drop = true;
+               break;
+       default:
+               /* TODO: Review other errors and process them to mac80211
+                * as appropriate.
+                */
+               drop = true;
+               break;
+       }
+
+       return drop;
+}
+
+static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
+                                       struct ieee80211_rx_status *status)
+{
+       u16 msdu_len;
+       struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data;
+       u8 l3pad_bytes;
+       struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+
+       rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(desc);
+       rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(desc);
+
+       l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(desc);
+       msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(desc);
+       skb_put(msdu, HAL_RX_DESC_SIZE + l3pad_bytes + msdu_len);
+       skb_pull(msdu, HAL_RX_DESC_SIZE + l3pad_bytes);
+
+       ath11k_dp_rx_h_ppdu(ar, desc, status);
+
+       status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
+                        RX_FLAG_DECRYPTED);
+
+       ath11k_dp_rx_h_undecap(ar, msdu, desc,
+                              HAL_ENCRYPT_TYPE_TKIP_MIC, status, false);
+}
+
+static bool ath11k_dp_rx_h_rxdma_err(struct ath11k *ar,  struct sk_buff *msdu,
+                                    struct ieee80211_rx_status *status)
+{
+       struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+       bool drop = false;
+
+       ar->ab->soc_stats.rxdma_error[rxcb->err_code]++;
+
+       switch (rxcb->err_code) {
+       case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
+               ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status);
+               break;
+       default:
+               /* TODO: Review other rxdma error code to check if anything is
+                * worth reporting to mac80211
+                */
+               drop = true;
+               break;
+       }
+
+       return drop;
+}
+
+static void ath11k_dp_rx_wbm_err(struct ath11k *ar,
+                                struct napi_struct *napi,
+                                struct sk_buff *msdu,
+                                struct sk_buff_head *msdu_list)
+{
+       struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
+       struct ieee80211_rx_status rxs = {0};
+       struct ieee80211_rx_status *status;
+       bool drop = true;
+
+       switch (rxcb->err_rel_src) {
+       case HAL_WBM_REL_SRC_MODULE_REO:
+               drop = ath11k_dp_rx_h_reo_err(ar, msdu, &rxs, msdu_list);
+               break;
+       case HAL_WBM_REL_SRC_MODULE_RXDMA:
+               drop = ath11k_dp_rx_h_rxdma_err(ar, msdu, &rxs);
+               break;
+       default:
+               /* msdu will get freed */
+               break;
+       }
+
+       if (drop) {
+               dev_kfree_skb_any(msdu);
+               return;
+       }
+
+       status = IEEE80211_SKB_RXCB(msdu);
+       *status = rxs;
+
+       ath11k_dp_rx_deliver_msdu(ar, napi, msdu);
+}
+
+int ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab,
+                                struct napi_struct *napi, int budget)
+{
+       struct ath11k *ar;
+       struct ath11k_dp *dp = &ab->dp;
+       struct dp_rxdma_ring *rx_ring;
+       struct hal_rx_wbm_rel_info err_info;
+       struct hal_srng *srng;
+       struct sk_buff *msdu;
+       struct sk_buff_head msdu_list[MAX_RADIOS];
+       struct ath11k_skb_rxcb *rxcb;
+       u32 *rx_desc;
+       int buf_id, mac_id;
+       int num_buffs_reaped[MAX_RADIOS] = {0};
+       int total_num_buffs_reaped = 0;
+       int ret, i;
+
+       for (i = 0; i < MAX_RADIOS; i++)
+               __skb_queue_head_init(&msdu_list[i]);
+
+       srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       while (budget) {
+               rx_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng);
+               if (!rx_desc)
+                       break;
+
+               ret = ath11k_hal_wbm_desc_parse_err(ab, rx_desc, &err_info);
+               if (ret) {
+                       ath11k_warn(ab,
+                                   "failed to parse rx error in wbm_rel ring desc %d\n",
+                                   ret);
+                       continue;
+               }
+
+               buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, err_info.cookie);
+               mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, err_info.cookie);
+
+               ar = ab->pdevs[mac_id].ar;
+               rx_ring = &ar->dp.rx_refill_buf_ring;
+
+               spin_lock_bh(&rx_ring->idr_lock);
+               msdu = idr_find(&rx_ring->bufs_idr, buf_id);
+               if (!msdu) {
+                       ath11k_warn(ab, "frame rx with invalid buf_id %d pdev %d\n",
+                                   buf_id, mac_id);
+                       spin_unlock_bh(&rx_ring->idr_lock);
+                       continue;
+               }
+
+               idr_remove(&rx_ring->bufs_idr, buf_id);
+               spin_unlock_bh(&rx_ring->idr_lock);
+
+               rxcb = ATH11K_SKB_RXCB(msdu);
+               dma_unmap_single(ab->dev, rxcb->paddr,
+                                msdu->len + skb_tailroom(msdu),
+                                DMA_FROM_DEVICE);
+
+               num_buffs_reaped[mac_id]++;
+               total_num_buffs_reaped++;
+               budget--;
+
+               if (err_info.push_reason !=
+                   HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) {
+                       dev_kfree_skb_any(msdu);
+                       continue;
+               }
+
+               rxcb->err_rel_src = err_info.err_rel_src;
+               rxcb->err_code = err_info.err_code;
+               rxcb->rx_desc = (struct hal_rx_desc *)msdu->data;
+               __skb_queue_tail(&msdu_list[mac_id], msdu);
+       }
+
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       if (!total_num_buffs_reaped)
+               goto done;
+
+       for (i = 0; i <  ab->num_radios; i++) {
+               if (!num_buffs_reaped[i])
+                       continue;
+
+               ar = ab->pdevs[i].ar;
+               rx_ring = &ar->dp.rx_refill_buf_ring;
+
+               ath11k_dp_rxbufs_replenish(ab, i, rx_ring, num_buffs_reaped[i],
+                                          HAL_RX_BUF_RBM_SW3_BM, GFP_ATOMIC);
+       }
+
+       rcu_read_lock();
+       for (i = 0; i <  ab->num_radios; i++) {
+               if (!rcu_dereference(ab->pdevs_active[i])) {
+                       __skb_queue_purge(&msdu_list[i]);
+                       continue;
+               }
+
+               ar = ab->pdevs[i].ar;
+
+               if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) {
+                       __skb_queue_purge(&msdu_list[i]);
+                       continue;
+               }
+
+               while ((msdu = __skb_dequeue(&msdu_list[i])) != NULL)
+                       ath11k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list[i]);
+       }
+       rcu_read_unlock();
+done:
+       return total_num_buffs_reaped;
+}
+
+int ath11k_dp_process_rxdma_err(struct ath11k_base *ab, int mac_id, int budget)
+{
+       struct ath11k *ar = ab->pdevs[mac_id].ar;
+       struct dp_srng *err_ring = &ar->dp.rxdma_err_dst_ring;
+       struct dp_rxdma_ring *rx_ring = &ar->dp.rx_refill_buf_ring;
+       struct dp_link_desc_bank *link_desc_banks = ab->dp.link_desc_banks;
+       struct hal_srng *srng;
+       struct hal_rx_msdu_meta meta[HAL_NUM_RX_MSDUS_PER_LINK_DESC];
+       enum hal_rx_buf_return_buf_manager rbm;
+       enum hal_reo_entr_rxdma_ecode rxdma_err_code;
+       struct ath11k_skb_rxcb *rxcb;
+       struct sk_buff *skb;
+       struct hal_reo_entrance_ring *entr_ring;
+       void *desc;
+       int num_buf_freed = 0;
+       int quota = budget;
+       dma_addr_t paddr;
+       u32 desc_bank;
+       void *link_desc_va;
+       int num_msdus;
+       int i;
+       int buf_id;
+
+       srng = &ab->hal.srng_list[err_ring->ring_id];
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       while (quota-- &&
+              (desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) {
+               ath11k_hal_rx_reo_ent_paddr_get(ab, desc, &paddr, &desc_bank);
+
+               entr_ring = (struct hal_reo_entrance_ring *)desc;
+               rxdma_err_code =
+                       FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_ERROR_CODE,
+                                 entr_ring->info1);
+               ab->soc_stats.rxdma_error[rxdma_err_code]++;
+
+               link_desc_va = link_desc_banks[desc_bank].vaddr +
+                              (paddr - link_desc_banks[desc_bank].paddr);
+               ath11k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, meta,
+                                                &rbm);
+
+               for (i = 0; i < num_msdus; i++) {
+                       buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
+                                          meta[i].cookie);
+
+                       spin_lock_bh(&rx_ring->idr_lock);
+                       skb = idr_find(&rx_ring->bufs_idr, buf_id);
+                       if (!skb) {
+                               ath11k_warn(ab, "rxdma error with invalid buf_id %d\n",
+                                           buf_id);
+                               spin_unlock_bh(&rx_ring->idr_lock);
+                               continue;
+                       }
+
+                       idr_remove(&rx_ring->bufs_idr, buf_id);
+                       spin_unlock_bh(&rx_ring->idr_lock);
+
+                       rxcb = ATH11K_SKB_RXCB(skb);
+                       dma_unmap_single(ab->dev, rxcb->paddr,
+                                        skb->len + skb_tailroom(skb),
+                                        DMA_FROM_DEVICE);
+                       dev_kfree_skb_any(skb);
+
+                       num_buf_freed++;
+               }
+
+               ath11k_dp_rx_link_desc_return(ab, desc,
+                                             HAL_WBM_REL_BM_ACT_PUT_IN_IDLE);
+       }
+
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+
+       if (num_buf_freed)
+               ath11k_dp_rxbufs_replenish(ab, mac_id, rx_ring, num_buf_freed,
+                                          HAL_RX_BUF_RBM_SW3_BM, GFP_ATOMIC);
+
+       return budget - quota;
+}
+
+void ath11k_dp_process_reo_status(struct ath11k_base *ab)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       struct hal_srng *srng;
+       struct dp_reo_cmd *cmd, *tmp;
+       bool found = false;
+       u32 *reo_desc;
+       u16 tag;
+       struct hal_reo_status reo_status;
+
+       srng = &ab->hal.srng_list[dp->reo_status_ring.ring_id];
+
+       memset(&reo_status, 0, sizeof(reo_status));
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+
+       while ((reo_desc = ath11k_hal_srng_dst_get_next_entry(ab, srng))) {
+               tag = FIELD_GET(HAL_SRNG_TLV_HDR_TAG, *reo_desc);
+
+               switch (tag) {
+               case HAL_REO_GET_QUEUE_STATS_STATUS:
+                       ath11k_hal_reo_status_queue_stats(ab, reo_desc,
+                                                         &reo_status);
+                       break;
+               case HAL_REO_FLUSH_QUEUE_STATUS:
+                       ath11k_hal_reo_flush_queue_status(ab, reo_desc,
+                                                         &reo_status);
+                       break;
+               case HAL_REO_FLUSH_CACHE_STATUS:
+                       ath11k_hal_reo_flush_cache_status(ab, reo_desc,
+                                                         &reo_status);
+                       break;
+               case HAL_REO_UNBLOCK_CACHE_STATUS:
+                       ath11k_hal_reo_unblk_cache_status(ab, reo_desc,
+                                                         &reo_status);
+                       break;
+               case HAL_REO_FLUSH_TIMEOUT_LIST_STATUS:
+                       ath11k_hal_reo_flush_timeout_list_status(ab, reo_desc,
+                                                                &reo_status);
+                       break;
+               case HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS:
+                       ath11k_hal_reo_desc_thresh_reached_status(ab, reo_desc,
+                                                                 &reo_status);
+                       break;
+               case HAL_REO_UPDATE_RX_REO_QUEUE_STATUS:
+                       ath11k_hal_reo_update_rx_reo_queue_status(ab, reo_desc,
+                                                                 &reo_status);
+                       break;
+               default:
+                       ath11k_warn(ab, "Unknown reo status type %d\n", tag);
+                       continue;
+               }
+
+               spin_lock_bh(&dp->reo_cmd_lock);
+               list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
+                       if (reo_status.uniform_hdr.cmd_num == cmd->cmd_num) {
+                               found = true;
+                               list_del(&cmd->list);
+                               break;
+                       }
+               }
+               spin_unlock_bh(&dp->reo_cmd_lock);
+
+               if (found) {
+                       cmd->handler(dp, (void *)&cmd->data,
+                                    reo_status.uniform_hdr.cmd_status);
+                       kfree(cmd);
+               }
+
+               found = false;
+       }
+
+       ath11k_hal_srng_access_end(ab, srng);
+
+       spin_unlock_bh(&srng->lock);
+}
+
+void ath11k_dp_rx_pdev_free(struct ath11k_base *ab, int mac_id)
+{
+       struct ath11k *ar = ab->pdevs[mac_id].ar;
+
+       ath11k_dp_rx_pdev_srng_free(ar);
+       ath11k_dp_rxdma_pdev_buf_free(ar);
+}
+
+int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id)
+{
+       struct ath11k *ar = ab->pdevs[mac_id].ar;
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       u32 ring_id;
+       int ret;
+
+       ret = ath11k_dp_rx_pdev_srng_alloc(ar);
+       if (ret) {
+               ath11k_warn(ab, "failed to setup rx srngs\n");
+               return ret;
+       }
+
+       ret = ath11k_dp_rxdma_pdev_buf_setup(ar);
+       if (ret) {
+               ath11k_warn(ab, "failed to setup rxdma ring\n");
+               return ret;
+       }
+
+       ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id;
+       ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, HAL_RXDMA_BUF);
+       if (ret) {
+               ath11k_warn(ab, "failed to configure rx_refill_buf_ring %d\n",
+                           ret);
+               return ret;
+       }
+
+       ring_id = dp->rxdma_err_dst_ring.ring_id;
+       ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id, HAL_RXDMA_DST);
+       if (ret) {
+               ath11k_warn(ab, "failed to configure rxdma_err_dest_ring %d\n",
+                           ret);
+               return ret;
+       }
+
+       ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id;
+       ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id,
+                                         mac_id, HAL_RXDMA_MONITOR_BUF);
+       if (ret) {
+               ath11k_warn(ab, "failed to configure rxdma_mon_buf_ring %d\n",
+                           ret);
+               return ret;
+       }
+       ret = ath11k_dp_tx_htt_srng_setup(ab,
+                                         dp->rxdma_mon_dst_ring.ring_id,
+                                         mac_id, HAL_RXDMA_MONITOR_DST);
+       if (ret) {
+               ath11k_warn(ab, "failed to configure rxdma_mon_dst_ring %d\n",
+                           ret);
+               return ret;
+       }
+       ret = ath11k_dp_tx_htt_srng_setup(ab,
+                                         dp->rxdma_mon_desc_ring.ring_id,
+                                         mac_id, HAL_RXDMA_MONITOR_DESC);
+       if (ret) {
+               ath11k_warn(ab, "failed to configure rxdma_mon_dst_ring %d\n",
+                           ret);
+               return ret;
+       }
+       ring_id = dp->rx_mon_status_refill_ring.refill_buf_ring.ring_id;
+       ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id,
+                                         HAL_RXDMA_MONITOR_STATUS);
+       if (ret) {
+               ath11k_warn(ab,
+                           "failed to configure mon_status_refill_ring %d\n",
+                           ret);
+               return ret;
+       }
+       return 0;
+}
+
+static void ath11k_dp_mon_set_frag_len(u32 *total_len, u32 *frag_len)
+{
+       if (*total_len >= (DP_RX_BUFFER_SIZE - sizeof(struct hal_rx_desc))) {
+               *frag_len = DP_RX_BUFFER_SIZE - sizeof(struct hal_rx_desc);
+               *total_len -= *frag_len;
+       } else {
+               *frag_len = *total_len;
+               *total_len = 0;
+       }
+}
+
+static
+int ath11k_dp_rx_monitor_link_desc_return(struct ath11k *ar,
+                                         void *p_last_buf_addr_info,
+                                         u8 mac_id)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct dp_srng *dp_srng;
+       void *hal_srng;
+       void *src_srng_desc;
+       int ret = 0;
+
+       dp_srng = &dp->rxdma_mon_desc_ring;
+       hal_srng = &ar->ab->hal.srng_list[dp_srng->ring_id];
+
+       ath11k_hal_srng_access_begin(ar->ab, hal_srng);
+
+       src_srng_desc = ath11k_hal_srng_src_get_next_entry(ar->ab, hal_srng);
+
+       if (src_srng_desc) {
+               struct ath11k_buffer_addr *src_desc =
+                               (struct ath11k_buffer_addr *)src_srng_desc;
+
+               *src_desc = *((struct ath11k_buffer_addr *)p_last_buf_addr_info);
+       } else {
+               ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+                          "Monitor Link Desc Ring %d Full", mac_id);
+               ret = -ENOMEM;
+       }
+
+       ath11k_hal_srng_access_end(ar->ab, hal_srng);
+       return ret;
+}
+
+static
+void ath11k_dp_rx_mon_next_link_desc_get(void *rx_msdu_link_desc,
+                                        dma_addr_t *paddr, u32 *sw_cookie,
+                                        void **pp_buf_addr_info)
+{
+       struct hal_rx_msdu_link *msdu_link =
+                       (struct hal_rx_msdu_link *)rx_msdu_link_desc;
+       struct ath11k_buffer_addr *buf_addr_info;
+       u8 rbm = 0;
+
+       buf_addr_info = (struct ath11k_buffer_addr *)&msdu_link->buf_addr_info;
+
+       ath11k_hal_rx_buf_addr_info_get(buf_addr_info, paddr, sw_cookie, &rbm);
+
+       *pp_buf_addr_info = (void *)buf_addr_info;
+}
+
+static int ath11k_dp_pkt_set_pktlen(struct sk_buff *skb, u32 len)
+{
+       if (skb->len > len) {
+               skb_trim(skb, len);
+       } else {
+               if (skb_tailroom(skb) < len - skb->len) {
+                       if ((pskb_expand_head(skb, 0,
+                                             len - skb->len - skb_tailroom(skb),
+                                             GFP_ATOMIC))) {
+                               dev_kfree_skb_any(skb);
+                               return -ENOMEM;
+                       }
+               }
+               skb_put(skb, (len - skb->len));
+       }
+       return 0;
+}
+
+static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar,
+                                       void *msdu_link_desc,
+                                       struct hal_rx_msdu_list *msdu_list,
+                                       u16 *num_msdus)
+{
+       struct hal_rx_msdu_details *msdu_details = NULL;
+       struct rx_msdu_desc *msdu_desc_info = NULL;
+       struct hal_rx_msdu_link *msdu_link = NULL;
+       int i;
+       u32 last = FIELD_PREP(RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU, 1);
+       u32 first = FIELD_PREP(RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU, 1);
+       u8  tmp  = 0;
+
+       msdu_link = (struct hal_rx_msdu_link *)msdu_link_desc;
+       msdu_details = &msdu_link->msdu_link[0];
+
+       for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) {
+               if (FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
+                             msdu_details[i].buf_addr_info.info0) == 0) {
+                       msdu_desc_info = &msdu_details[i - 1].rx_msdu_info;
+                       msdu_desc_info->info0 |= last;
+                       ;
+                       break;
+               }
+               msdu_desc_info = &msdu_details[i].rx_msdu_info;
+
+               if (!i)
+                       msdu_desc_info->info0 |= first;
+               else if (i == (HAL_RX_NUM_MSDU_DESC - 1))
+                       msdu_desc_info->info0 |= last;
+               msdu_list->msdu_info[i].msdu_flags = msdu_desc_info->info0;
+               msdu_list->msdu_info[i].msdu_len =
+                        HAL_RX_MSDU_PKT_LENGTH_GET(msdu_desc_info->info0);
+               msdu_list->sw_cookie[i] =
+                       FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
+                                 msdu_details[i].buf_addr_info.info1);
+               tmp = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR,
+                               msdu_details[i].buf_addr_info.info1);
+               msdu_list->rbm[i] = tmp;
+       }
+       *num_msdus = i;
+}
+
+static u32 ath11k_dp_rx_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id,
+                                       u32 *rx_bufs_used)
+{
+       u32 ret = 0;
+
+       if ((*ppdu_id < msdu_ppdu_id) &&
+           ((msdu_ppdu_id - *ppdu_id) < DP_NOT_PPDU_ID_WRAP_AROUND)) {
+               *ppdu_id = msdu_ppdu_id;
+               ret = msdu_ppdu_id;
+       } else if ((*ppdu_id > msdu_ppdu_id) &&
+               ((*ppdu_id - msdu_ppdu_id) > DP_NOT_PPDU_ID_WRAP_AROUND)) {
+               /* mon_dst is behind than mon_status
+                * skip dst_ring and free it
+                */
+               *rx_bufs_used += 1;
+               *ppdu_id = msdu_ppdu_id;
+               ret = msdu_ppdu_id;
+       }
+       return ret;
+}
+
+static void ath11k_dp_mon_get_buf_len(struct hal_rx_msdu_desc_info *info,
+                                     bool *is_frag, u32 *total_len,
+                                     u32 *frag_len, u32 *msdu_cnt)
+{
+       if (info->msdu_flags & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION) {
+               if (!*is_frag) {
+                       *total_len = info->msdu_len;
+                       *is_frag = true;
+               }
+               ath11k_dp_mon_set_frag_len(total_len,
+                                          frag_len);
+       } else {
+               if (*is_frag) {
+                       ath11k_dp_mon_set_frag_len(total_len,
+                                                  frag_len);
+               } else {
+                       *frag_len = info->msdu_len;
+               }
+               *is_frag = false;
+               *msdu_cnt -= 1;
+       }
+}
+
+static u32
+ath11k_dp_rx_mon_mpdu_pop(struct ath11k *ar,
+                         void *ring_entry, struct sk_buff **head_msdu,
+                         struct sk_buff **tail_msdu, u32 *npackets,
+                         u32 *ppdu_id)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
+       struct dp_rxdma_ring *rx_ring = &dp->rxdma_mon_buf_ring;
+       struct sk_buff *msdu = NULL, *last = NULL;
+       struct hal_rx_msdu_list msdu_list;
+       void *p_buf_addr_info, *p_last_buf_addr_info;
+       struct hal_rx_desc *rx_desc;
+       void *rx_msdu_link_desc;
+       dma_addr_t paddr;
+       u16 num_msdus = 0;
+       u32 rx_buf_size, rx_pkt_offset, sw_cookie;
+       u32 rx_bufs_used = 0, i = 0;
+       u32 msdu_ppdu_id = 0, msdu_cnt = 0;
+       u32 total_len = 0, frag_len = 0;
+       bool is_frag, is_first_msdu;
+       bool drop_mpdu = false;
+       struct ath11k_skb_rxcb *rxcb;
+       struct hal_reo_entrance_ring *ent_desc =
+                       (struct hal_reo_entrance_ring *)ring_entry;
+       int buf_id;
+
+       ath11k_hal_rx_reo_ent_buf_paddr_get(ring_entry, &paddr,
+                                           &sw_cookie, &p_last_buf_addr_info,
+                                           &msdu_cnt);
+
+       if (FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_PUSH_REASON,
+                     ent_desc->info1) ==
+                     HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED) {
+               u8 rxdma_err =
+                       FIELD_GET(HAL_REO_ENTR_RING_INFO1_RXDMA_ERROR_CODE,
+                                 ent_desc->info1);
+               if (rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR ||
+                   rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR ||
+                   rxdma_err == HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR) {
+                       drop_mpdu = true;
+                       pmon->rx_mon_stats.dest_mpdu_drop++;
+               }
+       }
+
+       is_frag = false;
+       is_first_msdu = true;
+
+       do {
+               if (pmon->mon_last_linkdesc_paddr == paddr) {
+                       pmon->rx_mon_stats.dup_mon_linkdesc_cnt++;
+                       return rx_bufs_used;
+               }
+
+               rx_msdu_link_desc =
+                       (void *)pmon->link_desc_banks[sw_cookie].vaddr +
+                       (paddr - pmon->link_desc_banks[sw_cookie].paddr);
+
+               ath11k_hal_rx_msdu_list_get(ar, rx_msdu_link_desc, &msdu_list,
+                                           &num_msdus);
+
+               for (i = 0; i < num_msdus; i++) {
+                       u32 l2_hdr_offset;
+
+                       if (pmon->mon_last_buf_cookie == msdu_list.sw_cookie[i]) {
+                               ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+                                          "i %d last_cookie %d is same\n",
+                                          i, pmon->mon_last_buf_cookie);
+                               drop_mpdu = true;
+                               pmon->rx_mon_stats.dup_mon_buf_cnt++;
+                               continue;
+                       }
+                       buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID,
+                                          msdu_list.sw_cookie[i]);
+
+                       spin_lock_bh(&rx_ring->idr_lock);
+                       msdu = idr_find(&rx_ring->bufs_idr, buf_id);
+                       spin_unlock_bh(&rx_ring->idr_lock);
+                       if (!msdu) {
+                               ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+                                          "msdu_pop: invalid buf_id %d\n", buf_id);
+                               break;
+                       }
+                       rxcb = ATH11K_SKB_RXCB(msdu);
+                       if (!rxcb->unmapped) {
+                               dma_unmap_single(ar->ab->dev, rxcb->paddr,
+                                                msdu->len +
+                                                skb_tailroom(msdu),
+                                                DMA_FROM_DEVICE);
+                               rxcb->unmapped = 1;
+                       }
+                       if (drop_mpdu) {
+                               ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+                                          "i %d drop msdu %p *ppdu_id %x\n",
+                                          i, msdu, *ppdu_id);
+                               dev_kfree_skb_any(msdu);
+                               msdu = NULL;
+                               goto next_msdu;
+                       }
+
+                       rx_desc = (struct hal_rx_desc *)msdu->data;
+
+                       rx_pkt_offset = sizeof(struct hal_rx_desc);
+                       l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(rx_desc);
+
+                       if (is_first_msdu) {
+                               if (!ath11k_dp_rxdesc_mpdu_valid(rx_desc)) {
+                                       drop_mpdu = true;
+                                       dev_kfree_skb_any(msdu);
+                                       msdu = NULL;
+                                       pmon->mon_last_linkdesc_paddr = paddr;
+                                       goto next_msdu;
+                               }
+
+                               msdu_ppdu_id =
+                                       ath11k_dp_rxdesc_get_ppduid(rx_desc);
+
+                               if (ath11k_dp_rx_mon_comp_ppduid(msdu_ppdu_id,
+                                                                ppdu_id,
+                                                                &rx_bufs_used))
+                                       return rx_bufs_used;
+                               pmon->mon_last_linkdesc_paddr = paddr;
+                               is_first_msdu = false;
+                       }
+                       ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i],
+                                                 &is_frag, &total_len,
+                                                 &frag_len, &msdu_cnt);
+                       rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len;
+
+                       ath11k_dp_pkt_set_pktlen(msdu, rx_buf_size);
+
+                       if (!(*head_msdu))
+                               *head_msdu = msdu;
+                       else if (last)
+                               last->next = msdu;
+
+                       last = msdu;
+next_msdu:
+                       pmon->mon_last_buf_cookie = msdu_list.sw_cookie[i];
+                       rx_bufs_used++;
+                       spin_lock_bh(&rx_ring->idr_lock);
+                       idr_remove(&rx_ring->bufs_idr, buf_id);
+                       spin_unlock_bh(&rx_ring->idr_lock);
+               }
+
+               ath11k_dp_rx_mon_next_link_desc_get(rx_msdu_link_desc, &paddr,
+                                                   &sw_cookie,
+                                                   &p_buf_addr_info);
+
+               if (ath11k_dp_rx_monitor_link_desc_return(ar,
+                                                         p_last_buf_addr_info,
+                                                         dp->mac_id))
+                       ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+                                  "dp_rx_monitor_link_desc_return failed");
+
+               p_last_buf_addr_info = p_buf_addr_info;
+
+       } while (paddr && msdu_cnt);
+
+       if (last)
+               last->next = NULL;
+
+       *tail_msdu = msdu;
+
+       if (msdu_cnt == 0)
+               *npackets = 1;
+
+       return rx_bufs_used;
+}
+
+static void ath11k_dp_rx_msdus_set_payload(struct sk_buff *msdu)
+{
+       u32 rx_pkt_offset, l2_hdr_offset;
+
+       rx_pkt_offset = sizeof(struct hal_rx_desc);
+       l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad((struct hal_rx_desc *)msdu->data);
+       skb_pull(msdu, rx_pkt_offset + l2_hdr_offset);
+}
+
+static struct sk_buff *
+ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar,
+                           u32 mac_id, struct sk_buff *head_msdu,
+                           struct sk_buff *last_msdu,
+                           struct ieee80211_rx_status *rxs)
+{
+       struct sk_buff *msdu, *mpdu_buf, *prev_buf;
+       u32 decap_format, wifi_hdr_len;
+       struct hal_rx_desc *rx_desc;
+       char *hdr_desc;
+       u8 *dest;
+       struct ieee80211_hdr_3addr *wh;
+
+       mpdu_buf = NULL;
+
+       if (!head_msdu)
+               goto err_merge_fail;
+
+       rx_desc = (struct hal_rx_desc *)head_msdu->data;
+
+       if (ath11k_dp_rxdesc_get_mpdulen_err(rx_desc))
+               return NULL;
+
+       decap_format = ath11k_dp_rxdesc_get_decap_format(rx_desc);
+
+       ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs);
+
+       if (decap_format == DP_RX_DECAP_TYPE_RAW) {
+               ath11k_dp_rx_msdus_set_payload(head_msdu);
+
+               prev_buf = head_msdu;
+               msdu = head_msdu->next;
+
+               while (msdu) {
+                       ath11k_dp_rx_msdus_set_payload(msdu);
+
+                       prev_buf = msdu;
+                       msdu = msdu->next;
+               }
+
+               prev_buf->next = NULL;
+
+               skb_trim(prev_buf, prev_buf->len - HAL_RX_FCS_LEN);
+       } else if (decap_format == DP_RX_DECAP_TYPE_NATIVE_WIFI) {
+               __le16 qos_field;
+               u8 qos_pkt = 0;
+
+               rx_desc = (struct hal_rx_desc *)head_msdu->data;
+               hdr_desc = ath11k_dp_rxdesc_get_80211hdr(rx_desc);
+
+               /* Base size */
+               wifi_hdr_len = sizeof(struct ieee80211_hdr_3addr);
+               wh = (struct ieee80211_hdr_3addr *)hdr_desc;
+
+               if (ieee80211_is_data_qos(wh->frame_control)) {
+                       struct ieee80211_qos_hdr *qwh =
+                                       (struct ieee80211_qos_hdr *)hdr_desc;
+
+                       qos_field = qwh->qos_ctrl;
+                       qos_pkt = 1;
+               }
+               msdu = head_msdu;
+
+               while (msdu) {
+                       rx_desc = (struct hal_rx_desc *)msdu->data;
+                       hdr_desc = ath11k_dp_rxdesc_get_80211hdr(rx_desc);
+
+                       if (qos_pkt) {
+                               dest = skb_push(msdu, sizeof(__le16));
+                               if (!dest)
+                                       goto err_merge_fail;
+                               memcpy(dest, hdr_desc, wifi_hdr_len);
+                               memcpy(dest + wifi_hdr_len,
+                                      (u8 *)&qos_field, sizeof(__le16));
+                       }
+                       ath11k_dp_rx_msdus_set_payload(msdu);
+                       prev_buf = msdu;
+                       msdu = msdu->next;
+               }
+               dest = skb_put(prev_buf, HAL_RX_FCS_LEN);
+               if (!dest)
+                       goto err_merge_fail;
+
+               ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+                          "mpdu_buf %pK mpdu_buf->len %u",
+                          prev_buf, prev_buf->len);
+       } else {
+               ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+                          "decap format %d is not supported!\n",
+                          decap_format);
+               goto err_merge_fail;
+       }
+
+       return head_msdu;
+
+err_merge_fail:
+       if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+                          "err_merge_fail mpdu_buf %pK", mpdu_buf);
+               /* Free the head buffer */
+               dev_kfree_skb_any(mpdu_buf);
+       }
+       return NULL;
+}
+
+static int ath11k_dp_rx_mon_deliver(struct ath11k *ar, u32 mac_id,
+                                   struct sk_buff *head_msdu,
+                                   struct sk_buff *tail_msdu,
+                                   struct napi_struct *napi)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct sk_buff *mon_skb, *skb_next, *header;
+       struct ieee80211_rx_status *rxs = &dp->rx_status, *status;
+
+       mon_skb = ath11k_dp_rx_mon_merg_msdus(ar, mac_id, head_msdu,
+                                             tail_msdu, rxs);
+
+       if (!mon_skb)
+               goto mon_deliver_fail;
+
+       header = mon_skb;
+
+       rxs->flag = 0;
+       do {
+               skb_next = mon_skb->next;
+               if (!skb_next)
+                       rxs->flag &= ~RX_FLAG_AMSDU_MORE;
+               else
+                       rxs->flag |= RX_FLAG_AMSDU_MORE;
+
+               if (mon_skb == header) {
+                       header = NULL;
+                       rxs->flag &= ~RX_FLAG_ALLOW_SAME_PN;
+               } else {
+                       rxs->flag |= RX_FLAG_ALLOW_SAME_PN;
+               }
+               rxs->flag |= RX_FLAG_ONLY_MONITOR;
+
+               status = IEEE80211_SKB_RXCB(mon_skb);
+               *status = *rxs;
+
+               ath11k_dp_rx_deliver_msdu(ar, napi, mon_skb);
+               mon_skb = skb_next;
+       } while (mon_skb && (mon_skb != tail_msdu));
+       rxs->flag = 0;
+
+       return 0;
+
+mon_deliver_fail:
+       mon_skb = head_msdu;
+       while (mon_skb) {
+               skb_next = mon_skb->next;
+               dev_kfree_skb_any(mon_skb);
+               mon_skb = skb_next;
+       }
+       return -EINVAL;
+}
+
+static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, u32 quota,
+                                         struct napi_struct *napi)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
+       void *ring_entry;
+       void *mon_dst_srng;
+       u32 ppdu_id;
+       u32 rx_bufs_used;
+       struct ath11k_pdev_mon_stats *rx_mon_stats;
+       u32      npackets = 0;
+
+       mon_dst_srng = &ar->ab->hal.srng_list[dp->rxdma_mon_dst_ring.ring_id];
+
+       if (!mon_dst_srng) {
+               ath11k_warn(ar->ab,
+                           "HAL Monitor Destination Ring Init Failed -- %pK",
+                           mon_dst_srng);
+               return;
+       }
+
+       spin_lock_bh(&pmon->mon_lock);
+
+       ath11k_hal_srng_access_begin(ar->ab, mon_dst_srng);
+
+       ppdu_id = pmon->mon_ppdu_info.ppdu_id;
+       rx_bufs_used = 0;
+       rx_mon_stats = &pmon->rx_mon_stats;
+
+       while ((ring_entry = ath11k_hal_srng_dst_peek(ar->ab, mon_dst_srng))) {
+               struct sk_buff *head_msdu, *tail_msdu;
+
+               head_msdu = NULL;
+               tail_msdu = NULL;
+
+               rx_bufs_used += ath11k_dp_rx_mon_mpdu_pop(ar, ring_entry,
+                                                         &head_msdu,
+                                                         &tail_msdu,
+                                                         &npackets, &ppdu_id);
+
+               if (ppdu_id != pmon->mon_ppdu_info.ppdu_id) {
+                       pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
+                       ath11k_dbg(ar->ab, ATH11K_DBG_DATA,
+                                  "dest_rx: new ppdu_id %x != status ppdu_id %x",
+                                  ppdu_id, pmon->mon_ppdu_info.ppdu_id);
+                       break;
+               }
+               if (head_msdu && tail_msdu) {
+                       ath11k_dp_rx_mon_deliver(ar, dp->mac_id, head_msdu,
+                                                tail_msdu, napi);
+                       rx_mon_stats->dest_mpdu_done++;
+               }
+
+               ring_entry = ath11k_hal_srng_dst_get_next_entry(ar->ab,
+                                                               mon_dst_srng);
+       }
+       ath11k_hal_srng_access_end(ar->ab, mon_dst_srng);
+
+       spin_unlock_bh(&pmon->mon_lock);
+
+       if (rx_bufs_used) {
+               rx_mon_stats->dest_ppdu_done++;
+               ath11k_dp_rxbufs_replenish(ar->ab, dp->mac_id,
+                                          &dp->rxdma_mon_buf_ring,
+                                          rx_bufs_used,
+                                          HAL_RX_BUF_RBM_SW3_BM, GFP_ATOMIC);
+       }
+}
+
+static void ath11k_dp_rx_mon_status_process_tlv(struct ath11k *ar,
+                                               u32 quota,
+                                               struct napi_struct *napi)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
+       struct hal_rx_mon_ppdu_info *ppdu_info;
+       struct sk_buff *status_skb;
+       u32 tlv_status = HAL_TLV_STATUS_BUF_DONE;
+       struct ath11k_pdev_mon_stats *rx_mon_stats;
+
+       ppdu_info = &pmon->mon_ppdu_info;
+       rx_mon_stats = &pmon->rx_mon_stats;
+
+       if (pmon->mon_ppdu_status != DP_PPDU_STATUS_START)
+               return;
+
+       while (!skb_queue_empty(&pmon->rx_status_q)) {
+               status_skb = skb_dequeue(&pmon->rx_status_q);
+
+               tlv_status = ath11k_hal_rx_parse_mon_status(ar->ab, ppdu_info,
+                                                           status_skb);
+               if (tlv_status == HAL_TLV_STATUS_PPDU_DONE) {
+                       rx_mon_stats->status_ppdu_done++;
+                       pmon->mon_ppdu_status = DP_PPDU_STATUS_DONE;
+                       ath11k_dp_rx_mon_dest_process(ar, quota, napi);
+                       pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
+               }
+               dev_kfree_skb_any(status_skb);
+       }
+}
+
+static int ath11k_dp_mon_process_rx(struct ath11k_base *ab, int mac_id,
+                                   struct napi_struct *napi, int budget)
+{
+       struct ath11k *ar = ab->pdevs[mac_id].ar;
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
+       int num_buffs_reaped = 0;
+
+       num_buffs_reaped = ath11k_dp_rx_reap_mon_status_ring(ar->ab, dp->mac_id, &budget,
+                                                            &pmon->rx_status_q);
+       if (num_buffs_reaped)
+               ath11k_dp_rx_mon_status_process_tlv(ar, budget, napi);
+
+       return num_buffs_reaped;
+}
+
+int ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id,
+                                  struct napi_struct *napi, int budget)
+{
+       struct ath11k *ar = ab->pdevs[mac_id].ar;
+       int ret = 0;
+
+       if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags))
+               ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget);
+       else
+               ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget);
+       return ret;
+}
+
+static int ath11k_dp_rx_pdev_mon_status_attach(struct ath11k *ar)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct ath11k_mon_data *pmon = (struct ath11k_mon_data *)&dp->mon_data;
+
+       skb_queue_head_init(&pmon->rx_status_q);
+
+       pmon->mon_ppdu_status = DP_PPDU_STATUS_START;
+
+       memset(&pmon->rx_mon_stats, 0,
+              sizeof(pmon->rx_mon_stats));
+       return 0;
+}
+
+int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct ath11k_mon_data *pmon = &dp->mon_data;
+       struct hal_srng *mon_desc_srng = NULL;
+       struct dp_srng *dp_srng;
+       int ret = 0;
+       u32 n_link_desc = 0;
+
+       ret = ath11k_dp_rx_pdev_mon_status_attach(ar);
+       if (ret) {
+               ath11k_warn(ar->ab, "pdev_mon_status_attach() failed");
+               return ret;
+       }
+
+       dp_srng = &dp->rxdma_mon_desc_ring;
+       n_link_desc = dp_srng->size /
+               ath11k_hal_srng_get_entrysize(HAL_RXDMA_MONITOR_DESC);
+       mon_desc_srng =
+               &ar->ab->hal.srng_list[dp->rxdma_mon_desc_ring.ring_id];
+
+       ret = ath11k_dp_link_desc_setup(ar->ab, pmon->link_desc_banks,
+                                       HAL_RXDMA_MONITOR_DESC, mon_desc_srng,
+                                       n_link_desc);
+       if (ret) {
+               ath11k_warn(ar->ab, "mon_link_desc_pool_setup() failed");
+               return ret;
+       }
+       pmon->mon_last_linkdesc_paddr = 0;
+       pmon->mon_last_buf_cookie = DP_RX_DESC_COOKIE_MAX + 1;
+       spin_lock_init(&pmon->mon_lock);
+       return 0;
+}
+
+static int ath11k_dp_mon_link_free(struct ath11k *ar)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct ath11k_mon_data *pmon = &dp->mon_data;
+
+       ath11k_dp_link_desc_cleanup(ar->ab, pmon->link_desc_banks,
+                                   HAL_RXDMA_MONITOR_DESC,
+                                   &dp->rxdma_mon_desc_ring);
+       return 0;
+}
+
+int ath11k_dp_rx_pdev_mon_detach(struct ath11k *ar)
+{
+       ath11k_dp_mon_link_free(ar);
+       return 0;
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+#ifndef ATH11K_DP_RX_H
+#define ATH11K_DP_RX_H
+
+#include "core.h"
+#include "rx_desc.h"
+#include "debug.h"
+
+#define DP_RX_MPDU_ERR_FCS                     BIT(0)
+#define DP_RX_MPDU_ERR_DECRYPT                 BIT(1)
+#define DP_RX_MPDU_ERR_TKIP_MIC                        BIT(2)
+#define DP_RX_MPDU_ERR_AMSDU_ERR               BIT(3)
+#define DP_RX_MPDU_ERR_OVERFLOW                        BIT(4)
+#define DP_RX_MPDU_ERR_MSDU_LEN                        BIT(5)
+#define DP_RX_MPDU_ERR_MPDU_LEN                        BIT(6)
+#define DP_RX_MPDU_ERR_UNENCRYPTED_FRAME       BIT(7)
+
+enum dp_rx_decap_type {
+       DP_RX_DECAP_TYPE_RAW,
+       DP_RX_DECAP_TYPE_NATIVE_WIFI,
+       DP_RX_DECAP_TYPE_ETHERNET2_DIX,
+       DP_RX_DECAP_TYPE_8023,
+};
+
+struct ath11k_dp_amsdu_subframe_hdr {
+       u8 dst[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       __be16 len;
+} __packed;
+
+struct ath11k_dp_rfc1042_hdr {
+       u8 llc_dsap;
+       u8 llc_ssap;
+       u8 llc_ctrl;
+       u8 snap_oui[3];
+       __be16 snap_type;
+} __packed;
+
+int ath11k_dp_rx_ampdu_start(struct ath11k *ar,
+                            struct ieee80211_ampdu_params *params);
+int ath11k_dp_rx_ampdu_stop(struct ath11k *ar,
+                           struct ieee80211_ampdu_params *params);
+void ath11k_peer_rx_tid_cleanup(struct ath11k *ar, struct ath11k_peer *peer);
+int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
+                            u8 tid, u32 ba_win_sz, u16 ssn);
+void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab,
+                                      struct sk_buff *skb);
+int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int pdev_idx);
+void ath11k_dp_rx_pdev_free(struct ath11k_base *ab, int pdev_idx);
+void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab);
+void ath11k_dp_process_reo_status(struct ath11k_base *ab);
+int ath11k_dp_process_rxdma_err(struct ath11k_base *ab, int mac_id, int budget);
+int ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab,
+                                struct napi_struct *napi, int budget);
+int ath11k_dp_process_rx_err(struct ath11k_base *ab, struct napi_struct *napi,
+                            int budget);
+int ath11k_dp_process_rx(struct ath11k_base *ab, int mac_id,
+                        struct napi_struct *napi, struct sk_buff_head *pending_q,
+                        int budget);
+int ath11k_dp_rxbufs_replenish(struct ath11k_base *ab, int mac_id,
+                              struct dp_rxdma_ring *rx_ring,
+                              int req_entries,
+                              enum hal_rx_buf_return_buf_manager mgr,
+                              gfp_t gfp);
+int ath11k_dp_htt_tlv_iter(struct ath11k_base *ab, const void *ptr, size_t len,
+                          int (*iter)(struct ath11k_base *ar, u16 tag, u16 len,
+                                      const void *ptr, void *data),
+                          void *data);
+int ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id,
+                                  struct napi_struct *napi, int budget);
+int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
+                                   struct napi_struct *napi, int budget);
+int ath11k_dp_rx_mon_status_bufs_replenish(struct ath11k_base *ab, int mac_id,
+                                          struct dp_rxdma_ring *rx_ring,
+                                          int req_entries,
+                                          enum hal_rx_buf_return_buf_manager mgr,
+                                          gfp_t gfp);
+int ath11k_dp_rx_pdev_mon_detach(struct ath11k *ar);
+int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar);
+
+#endif /* ATH11K_DP_RX_H */
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include "core.h"
+#include "dp_tx.h"
+#include "debug.h"
+#include "hw.h"
+
+/* NOTE: Any of the mapped ring id value must not exceed DP_TCL_NUM_RING_MAX */
+static const u8
+ath11k_txq_tcl_ring_map[ATH11K_HW_MAX_QUEUES] = { 0x0, 0x1, 0x2, 0x2 };
+
+static enum hal_tcl_encap_type
+ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb)
+{
+       /* TODO: Determine encap type based on vif_type and configuration */
+       return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI;
+}
+
+static void ath11k_dp_tx_encap_nwifi(struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       u8 *qos_ctl;
+
+       if (!ieee80211_is_data_qos(hdr->frame_control))
+               return;
+
+       qos_ctl = ieee80211_get_qos_ctl(hdr);
+       memmove(skb->data + IEEE80211_QOS_CTL_LEN,
+               skb->data, (void *)qos_ctl - (void *)skb->data);
+       skb_pull(skb, IEEE80211_QOS_CTL_LEN);
+
+       hdr = (void *)skb->data;
+       hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
+}
+
+static u8 ath11k_dp_tx_get_tid(struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+
+       if (!ieee80211_is_data_qos(hdr->frame_control))
+               return HAL_DESC_REO_NON_QOS_TID;
+       else
+               return skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+static enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher)
+{
+       switch (cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+               return HAL_ENCRYPT_TYPE_WEP_40;
+       case WLAN_CIPHER_SUITE_WEP104:
+               return HAL_ENCRYPT_TYPE_WEP_104;
+       case WLAN_CIPHER_SUITE_TKIP:
+               return HAL_ENCRYPT_TYPE_TKIP_MIC;
+       case WLAN_CIPHER_SUITE_CCMP:
+               return HAL_ENCRYPT_TYPE_CCMP_128;
+       case WLAN_CIPHER_SUITE_CCMP_256:
+               return HAL_ENCRYPT_TYPE_CCMP_256;
+       case WLAN_CIPHER_SUITE_GCMP:
+               return HAL_ENCRYPT_TYPE_GCMP_128;
+       case WLAN_CIPHER_SUITE_GCMP_256:
+               return HAL_ENCRYPT_TYPE_AES_GCMP_256;
+       default:
+               return HAL_ENCRYPT_TYPE_OPEN;
+       }
+}
+
+int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
+                struct sk_buff *skb)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_dp *dp = &ab->dp;
+       struct hal_tx_info ti = {0};
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
+       struct hal_srng *tcl_ring;
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       struct dp_tx_ring *tx_ring;
+       u8 cached_desc[HAL_TCL_DESC_LEN];
+       void *hal_tcl_desc;
+       u8 pool_id;
+       u8 hal_ring_id;
+       int ret;
+
+       if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
+               return -ESHUTDOWN;
+
+       if (!ieee80211_is_data(hdr->frame_control))
+               return -ENOTSUPP;
+
+       pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1);
+       ti.ring_id = ath11k_txq_tcl_ring_map[pool_id];
+
+       tx_ring = &dp->tx_ring[ti.ring_id];
+
+       spin_lock_bh(&tx_ring->tx_idr_lock);
+       ret = idr_alloc(&tx_ring->txbuf_idr, skb, 0,
+                       DP_TX_IDR_SIZE - 1, GFP_ATOMIC);
+       spin_unlock_bh(&tx_ring->tx_idr_lock);
+
+       if (ret < 0)
+               return -ENOSPC;
+
+       ti.desc_id = FIELD_PREP(DP_TX_DESC_ID_MAC_ID, ar->pdev_idx) |
+                    FIELD_PREP(DP_TX_DESC_ID_MSDU_ID, ret) |
+                    FIELD_PREP(DP_TX_DESC_ID_POOL_ID, pool_id);
+       ti.encap_type = ath11k_dp_tx_get_encap_type(arvif, skb);
+       ti.meta_data_flags = arvif->tcl_metadata;
+
+       if (info->control.hw_key)
+               ti.encrypt_type =
+                       ath11k_dp_tx_get_encrypt_type(info->control.hw_key->cipher);
+       else
+               ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
+
+       ti.addr_search_flags = arvif->hal_addr_search_flags;
+       ti.search_type = arvif->search_type;
+       ti.type = HAL_TCL_DESC_TYPE_BUFFER;
+       ti.pkt_offset = 0;
+       ti.lmac_id = ar->lmac_id;
+       ti.bss_ast_hash = arvif->ast_hash;
+       ti.dscp_tid_tbl_idx = 0;
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_IP4_CKSUM_EN, 1) |
+                            FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP4_CKSUM_EN, 1) |
+                            FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP6_CKSUM_EN, 1) |
+                            FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TCP4_CKSUM_EN, 1) |
+                            FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TCP6_CKSUM_EN, 1);
+       }
+
+       if (ieee80211_vif_is_mesh(arvif->vif))
+               ti.flags1 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_MESH_ENABLE, 1);
+
+       ti.flags1 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE, 1);
+
+       ti.tid = ath11k_dp_tx_get_tid(skb);
+
+       switch (ti.encap_type) {
+       case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:
+               ath11k_dp_tx_encap_nwifi(skb);
+               break;
+       case HAL_TCL_ENCAP_TYPE_RAW:
+               /*  TODO: for CHECKSUM_PARTIAL case in raw mode, HW checksum offload
+                *        is not applicable, hence manual checksum calculation using
+                *        skb_checksum_help() is needed
+                */
+       case HAL_TCL_ENCAP_TYPE_ETHERNET:
+       case HAL_TCL_ENCAP_TYPE_802_3:
+               /* TODO: Take care of other encap modes as well */
+               ret = -EINVAL;
+               goto fail_remove_idr;
+       }
+
+       ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
+       if (dma_mapping_error(ab->dev, ti.paddr)) {
+               ath11k_warn(ab, "failed to DMA map data Tx buffer\n");
+               ret = -ENOMEM;
+               goto fail_remove_idr;
+       }
+
+       ti.data_len = skb->len;
+       skb_cb->paddr = ti.paddr;
+       skb_cb->vif = arvif->vif;
+       skb_cb->ar = ar;
+
+       memset(cached_desc, 0, HAL_TCL_DESC_LEN);
+
+       ath11k_hal_tx_cmd_desc_setup(ab, cached_desc, &ti);
+
+       hal_ring_id = tx_ring->tcl_data_ring.ring_id;
+       tcl_ring = &ab->hal.srng_list[hal_ring_id];
+
+       spin_lock_bh(&tcl_ring->lock);
+
+       ath11k_hal_srng_access_begin(ab, tcl_ring);
+
+       hal_tcl_desc = (void *)ath11k_hal_srng_src_get_next_entry(ab, tcl_ring);
+       if (!hal_tcl_desc) {
+               /* NOTE: It is highly unlikely we'll be running out of tcl_ring
+                * desc because the desc is directly enqueued onto hw queue.
+                * So add tx packet throttling logic in future if required.
+                */
+               ath11k_hal_srng_access_end(ab, tcl_ring);
+               spin_unlock_bh(&tcl_ring->lock);
+               ret = -ENOMEM;
+               goto fail_unmap_dma;
+       }
+
+       ath11k_hal_tx_desc_sync(cached_desc, hal_tcl_desc);
+
+       ath11k_hal_srng_access_end(ab, tcl_ring);
+
+       spin_unlock_bh(&tcl_ring->lock);
+
+       spin_lock_bh(&tx_ring->tx_idr_lock);
+       tx_ring->num_tx_pending++;
+       spin_unlock_bh(&tx_ring->tx_idr_lock);
+
+       atomic_inc(&ar->dp.num_tx_pending);
+
+       return 0;
+
+fail_unmap_dma:
+       dma_unmap_single(ab->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE);
+
+fail_remove_idr:
+       spin_lock_bh(&tx_ring->tx_idr_lock);
+       idr_remove(&tx_ring->txbuf_idr,
+                  FIELD_GET(DP_TX_DESC_ID_MSDU_ID, ti.desc_id));
+       spin_unlock_bh(&tx_ring->tx_idr_lock);
+
+       return ret;
+}
+
+static void ath11k_dp_tx_free_txbuf(struct ath11k_base *ab, u8 mac_id,
+                                   int msdu_id,
+                                   struct dp_tx_ring *tx_ring)
+{
+       struct ath11k *ar;
+       struct sk_buff *msdu;
+       struct ath11k_skb_cb *skb_cb;
+
+       spin_lock_bh(&tx_ring->tx_idr_lock);
+       msdu = idr_find(&tx_ring->txbuf_idr, msdu_id);
+       if (!msdu) {
+               ath11k_warn(ab, "tx completion for unknown msdu_id %d\n",
+                           msdu_id);
+               spin_unlock_bh(&tx_ring->tx_idr_lock);
+               return;
+       }
+
+       skb_cb = ATH11K_SKB_CB(msdu);
+
+       idr_remove(&tx_ring->txbuf_idr, msdu_id);
+       tx_ring->num_tx_pending--;
+       spin_unlock_bh(&tx_ring->tx_idr_lock);
+
+       dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
+       dev_kfree_skb_any(msdu);
+
+       ar = ab->pdevs[mac_id].ar;
+       if (atomic_dec_and_test(&ar->dp.num_tx_pending))
+               wake_up(&ar->dp.tx_empty_waitq);
+}
+
+static void
+ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab,
+                                struct dp_tx_ring *tx_ring,
+                                struct ath11k_dp_htt_wbm_tx_status *ts)
+{
+       struct sk_buff *msdu;
+       struct ieee80211_tx_info *info;
+       struct ath11k_skb_cb *skb_cb;
+       struct ath11k *ar;
+
+       spin_lock_bh(&tx_ring->tx_idr_lock);
+       msdu = idr_find(&tx_ring->txbuf_idr, ts->msdu_id);
+       if (!msdu) {
+               ath11k_warn(ab, "htt tx completion for unknown msdu_id %d\n",
+                           ts->msdu_id);
+               spin_unlock_bh(&tx_ring->tx_idr_lock);
+               return;
+       }
+
+       skb_cb = ATH11K_SKB_CB(msdu);
+       info = IEEE80211_SKB_CB(msdu);
+
+       ar = skb_cb->ar;
+
+       idr_remove(&tx_ring->txbuf_idr, ts->msdu_id);
+       tx_ring->num_tx_pending--;
+       spin_unlock_bh(&tx_ring->tx_idr_lock);
+
+       if (atomic_dec_and_test(&ar->dp.num_tx_pending))
+               wake_up(&ar->dp.tx_empty_waitq);
+
+       dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
+
+       memset(&info->status, 0, sizeof(info->status));
+
+       if (ts->acked) {
+               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+                       info->flags |= IEEE80211_TX_STAT_ACK;
+                       info->status.ack_signal = ATH11K_DEFAULT_NOISE_FLOOR +
+                                                 ts->ack_rssi;
+                       info->status.is_valid_ack_signal = true;
+               } else {
+                       info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+               }
+       }
+
+       ieee80211_tx_status(ar->hw, msdu);
+}
+
+static void
+ath11k_dp_tx_process_htt_tx_complete(struct ath11k_base *ab,
+                                    void *desc, u8 mac_id,
+                                    u32 msdu_id, struct dp_tx_ring *tx_ring)
+{
+       struct htt_tx_wbm_completion *status_desc;
+       struct ath11k_dp_htt_wbm_tx_status ts = {0};
+       enum hal_wbm_htt_tx_comp_status wbm_status;
+
+       status_desc = desc + HTT_TX_WBM_COMP_STATUS_OFFSET;
+
+       wbm_status = FIELD_GET(HTT_TX_WBM_COMP_INFO0_STATUS,
+                              status_desc->info0);
+
+       switch (wbm_status) {
+       case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK:
+       case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP:
+       case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL:
+               ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK);
+               ts.msdu_id = msdu_id;
+               ts.ack_rssi = FIELD_GET(HTT_TX_WBM_COMP_INFO1_ACK_RSSI,
+                                       status_desc->info1);
+               ath11k_dp_tx_htt_tx_complete_buf(ab, tx_ring, &ts);
+               break;
+       case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ:
+       case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT:
+               ath11k_dp_tx_free_txbuf(ab, mac_id, msdu_id, tx_ring);
+               break;
+       case HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY:
+               /* This event is to be handled only when the driver decides to
+                * use WDS offload functionality.
+                */
+               break;
+       default:
+               ath11k_warn(ab, "Unknown htt tx status %d\n", wbm_status);
+               break;
+       }
+}
+
+static void ath11k_dp_tx_cache_peer_stats(struct ath11k *ar,
+                                         struct sk_buff *msdu,
+                                         struct hal_tx_status *ts)
+{
+       struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
+
+       if (ts->try_cnt > 1) {
+               peer_stats->retry_pkts += ts->try_cnt - 1;
+               peer_stats->retry_bytes += (ts->try_cnt - 1) * msdu->len;
+
+               if (ts->status != HAL_WBM_TQM_REL_REASON_FRAME_ACKED) {
+                       peer_stats->failed_pkts += 1;
+                       peer_stats->failed_bytes += msdu->len;
+               }
+       }
+}
+
+static void ath11k_dp_tx_complete_msdu(struct ath11k *ar,
+                                      struct sk_buff *msdu,
+                                      struct hal_tx_status *ts)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ieee80211_tx_info *info;
+       struct ath11k_skb_cb *skb_cb;
+
+       if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) {
+               /* Must not happen */
+               return;
+       }
+
+       skb_cb = ATH11K_SKB_CB(msdu);
+
+       dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
+
+       rcu_read_lock();
+
+       if (!rcu_dereference(ab->pdevs_active[ar->pdev_idx])) {
+               dev_kfree_skb_any(msdu);
+               goto exit;
+       }
+
+       if (!skb_cb->vif) {
+               dev_kfree_skb_any(msdu);
+               goto exit;
+       }
+
+       info = IEEE80211_SKB_CB(msdu);
+       memset(&info->status, 0, sizeof(info->status));
+
+       /* skip tx rate update from ieee80211_status*/
+       info->status.rates[0].idx = -1;
+
+       if (ts->status == HAL_WBM_TQM_REL_REASON_FRAME_ACKED &&
+           !(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+               info->flags |= IEEE80211_TX_STAT_ACK;
+               info->status.ack_signal = ATH11K_DEFAULT_NOISE_FLOOR +
+                                         ts->ack_rssi;
+               info->status.is_valid_ack_signal = true;
+       }
+
+       if (ts->status == HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX &&
+           (info->flags & IEEE80211_TX_CTL_NO_ACK))
+               info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+
+       if (ath11k_debug_is_extd_tx_stats_enabled(ar)) {
+               if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) {
+                       if (ar->last_ppdu_id == 0) {
+                               ar->last_ppdu_id = ts->ppdu_id;
+                       } else if (ar->last_ppdu_id == ts->ppdu_id ||
+                                  ar->cached_ppdu_id == ar->last_ppdu_id) {
+                               ar->cached_ppdu_id = ar->last_ppdu_id;
+                               ar->cached_stats.is_ampdu = true;
+                               ath11k_update_per_peer_stats_from_txcompl(ar, msdu, ts);
+                               memset(&ar->cached_stats, 0,
+                                      sizeof(struct ath11k_per_peer_tx_stats));
+                       } else {
+                               ar->cached_stats.is_ampdu = false;
+                               ath11k_update_per_peer_stats_from_txcompl(ar, msdu, ts);
+                               memset(&ar->cached_stats, 0,
+                                      sizeof(struct ath11k_per_peer_tx_stats));
+                       }
+                       ar->last_ppdu_id = ts->ppdu_id;
+               }
+
+               ath11k_dp_tx_cache_peer_stats(ar, msdu, ts);
+       }
+
+       /* NOTE: Tx rate status reporting. Tx completion status does not have
+        * necessary information (for example nss) to build the tx rate.
+        * Might end up reporting it out-of-band from HTT stats.
+        */
+
+       ieee80211_tx_status(ar->hw, msdu);
+
+exit:
+       rcu_read_unlock();
+}
+
+void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id)
+{
+       struct ath11k *ar;
+       struct ath11k_dp *dp = &ab->dp;
+       int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id;
+       struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id];
+       struct sk_buff *msdu;
+       struct hal_wbm_release_ring tx_status;
+       struct hal_tx_status ts;
+       struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id];
+       u32 *desc;
+       u32 msdu_id;
+       u8 mac_id;
+
+       spin_lock_bh(&status_ring->lock);
+
+       ath11k_hal_srng_access_begin(ab, status_ring);
+
+       spin_lock_bh(&tx_ring->tx_status_lock);
+       while (!kfifo_is_full(&tx_ring->tx_status_fifo) &&
+              (desc = ath11k_hal_srng_dst_get_next_entry(ab, status_ring))) {
+               ath11k_hal_tx_status_desc_sync((void *)desc,
+                                              (void *)&tx_status);
+               kfifo_put(&tx_ring->tx_status_fifo, tx_status);
+       }
+
+       if ((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) &&
+           kfifo_is_full(&tx_ring->tx_status_fifo)) {
+               /* TODO: Process pending tx_status messages when kfifo_is_full() */
+               ath11k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n");
+       }
+
+       spin_unlock_bh(&tx_ring->tx_status_lock);
+
+       ath11k_hal_srng_access_end(ab, status_ring);
+       spin_unlock_bh(&status_ring->lock);
+
+       spin_lock_bh(&tx_ring->tx_status_lock);
+       while (kfifo_get(&tx_ring->tx_status_fifo, &tx_status)) {
+               memset(&ts, 0, sizeof(ts));
+               ath11k_hal_tx_status_parse(ab, &tx_status, &ts);
+
+               mac_id = FIELD_GET(DP_TX_DESC_ID_MAC_ID, ts.desc_id);
+               msdu_id = FIELD_GET(DP_TX_DESC_ID_MSDU_ID, ts.desc_id);
+
+               if (ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) {
+                       ath11k_dp_tx_process_htt_tx_complete(ab,
+                                                            (void *)&tx_status,
+                                                            mac_id, msdu_id,
+                                                            tx_ring);
+                       continue;
+               }
+
+               spin_lock_bh(&tx_ring->tx_idr_lock);
+               msdu = idr_find(&tx_ring->txbuf_idr, msdu_id);
+               if (!msdu) {
+                       ath11k_warn(ab, "tx completion for unknown msdu_id %d\n",
+                                   msdu_id);
+                       spin_unlock_bh(&tx_ring->tx_idr_lock);
+                       continue;
+               }
+               idr_remove(&tx_ring->txbuf_idr, msdu_id);
+               tx_ring->num_tx_pending--;
+               spin_unlock_bh(&tx_ring->tx_idr_lock);
+
+               ar = ab->pdevs[mac_id].ar;
+
+               if (atomic_dec_and_test(&ar->dp.num_tx_pending))
+                       wake_up(&ar->dp.tx_empty_waitq);
+
+               /* TODO: Locking optimization so that tx_completion for an msdu
+                * is not called with tx_status_lock acquired
+                */
+               ath11k_dp_tx_complete_msdu(ar, msdu, &ts);
+       }
+       spin_unlock_bh(&tx_ring->tx_status_lock);
+}
+
+int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid,
+                             enum hal_reo_cmd_type type,
+                             struct ath11k_hal_reo_cmd *cmd,
+                             void (*cb)(struct ath11k_dp *, void *,
+                                        enum hal_reo_cmd_status))
+{
+       struct ath11k_dp *dp = &ab->dp;
+       struct dp_reo_cmd *dp_cmd;
+       struct hal_srng *cmd_ring;
+       int cmd_num;
+
+       cmd_ring = &ab->hal.srng_list[dp->reo_cmd_ring.ring_id];
+       cmd_num = ath11k_hal_reo_cmd_send(ab, cmd_ring, type, cmd);
+
+       /* reo cmd ring descriptors has cmd_num starting from 1 */
+       if (cmd_num <= 0)
+               return -EINVAL;
+
+       if (!cb)
+               return 0;
+
+       /* Can this be optimized so that we keep the pending command list only
+        * for tid delete command to free up the resoruce on the command status
+        * indication?
+        */
+       dp_cmd = kzalloc(sizeof(*dp_cmd), GFP_ATOMIC);
+
+       if (!dp_cmd)
+               return -ENOMEM;
+
+       memcpy(&dp_cmd->data, rx_tid, sizeof(struct dp_rx_tid));
+       dp_cmd->cmd_num = cmd_num;
+       dp_cmd->handler = cb;
+
+       spin_lock_bh(&dp->reo_cmd_lock);
+       list_add_tail(&dp_cmd->list, &dp->reo_cmd_list);
+       spin_unlock_bh(&dp->reo_cmd_lock);
+
+       return 0;
+}
+
+static int
+ath11k_dp_tx_get_ring_id_type(struct ath11k_base *ab,
+                             int mac_id, u32 ring_id,
+                             enum hal_ring_type ring_type,
+                             enum htt_srng_ring_type *htt_ring_type,
+                             enum htt_srng_ring_id *htt_ring_id)
+{
+       int lmac_ring_id_offset = 0;
+       int ret = 0;
+
+       switch (ring_type) {
+       case HAL_RXDMA_BUF:
+               lmac_ring_id_offset = mac_id * HAL_SRNG_RINGS_PER_LMAC;
+               if (!(ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF +
+                                 lmac_ring_id_offset) ||
+                   ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_BUF +
+                               lmac_ring_id_offset))) {
+                       ret = -EINVAL;
+               }
+               *htt_ring_id = HTT_RXDMA_HOST_BUF_RING;
+               *htt_ring_type = HTT_SW_TO_HW_RING;
+               break;
+       case HAL_RXDMA_DST:
+               *htt_ring_id = HTT_RXDMA_NON_MONITOR_DEST_RING;
+               *htt_ring_type = HTT_HW_TO_SW_RING;
+               break;
+       case HAL_RXDMA_MONITOR_BUF:
+               *htt_ring_id = HTT_RXDMA_MONITOR_BUF_RING;
+               *htt_ring_type = HTT_SW_TO_HW_RING;
+               break;
+       case HAL_RXDMA_MONITOR_STATUS:
+               *htt_ring_id = HTT_RXDMA_MONITOR_STATUS_RING;
+               *htt_ring_type = HTT_SW_TO_HW_RING;
+               break;
+       case HAL_RXDMA_MONITOR_DST:
+               *htt_ring_id = HTT_RXDMA_MONITOR_DEST_RING;
+               *htt_ring_type = HTT_HW_TO_SW_RING;
+               break;
+       case HAL_RXDMA_MONITOR_DESC:
+               *htt_ring_id = HTT_RXDMA_MONITOR_DESC_RING;
+               *htt_ring_type = HTT_SW_TO_HW_RING;
+               break;
+       default:
+               ath11k_warn(ab, "Unsupported ring type in DP :%d\n", ring_type);
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id,
+                               int mac_id, enum hal_ring_type ring_type)
+{
+       struct htt_srng_setup_cmd *cmd;
+       struct hal_srng *srng = &ab->hal.srng_list[ring_id];
+       struct hal_srng_params params;
+       struct sk_buff *skb;
+       u32 ring_entry_sz;
+       int len = sizeof(*cmd);
+       dma_addr_t hp_addr, tp_addr;
+       enum htt_srng_ring_type htt_ring_type;
+       enum htt_srng_ring_id htt_ring_id;
+       int ret = 0;
+
+       skb = ath11k_htc_alloc_skb(ab, len);
+       if (!skb)
+               return -ENOMEM;
+
+       memset(¶ms, 0, sizeof(params));
+       ath11k_hal_srng_get_params(ab, srng, ¶ms);
+
+       hp_addr = ath11k_hal_srng_get_hp_addr(ab, srng);
+       tp_addr = ath11k_hal_srng_get_tp_addr(ab, srng);
+
+       if (ath11k_dp_tx_get_ring_id_type(ab, mac_id, ring_id,
+                                         ring_type, &htt_ring_type,
+                                         &htt_ring_id))
+               goto err_free;
+
+       skb_put(skb, len);
+       cmd = (struct htt_srng_setup_cmd *)skb->data;
+       cmd->info0 = FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_MSG_TYPE,
+                               HTT_H2T_MSG_TYPE_SRING_SETUP);
+       if (htt_ring_type == HTT_SW_TO_HW_RING ||
+           htt_ring_type == HTT_HW_TO_SW_RING)
+               cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID,
+                                        DP_SW2HW_MACID(mac_id));
+       else
+               cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID,
+                                        mac_id);
+       cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_RING_TYPE,
+                                htt_ring_type);
+       cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_RING_ID, htt_ring_id);
+
+       cmd->ring_base_addr_lo = params.ring_base_paddr &
+                                HAL_ADDR_LSB_REG_MASK;
+
+       cmd->ring_base_addr_hi = (u64)params.ring_base_paddr >>
+                                HAL_ADDR_MSB_REG_SHIFT;
+
+       ret = ath11k_hal_srng_get_entrysize(ring_type);
+       if (ret < 0)
+               return -EINVAL;
+
+       ring_entry_sz = ret;
+
+       ring_entry_sz >>= 2;
+       cmd->info1 = FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_ENTRY_SIZE,
+                               ring_entry_sz);
+       cmd->info1 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_SIZE,
+                                params.num_entries * ring_entry_sz);
+       cmd->info1 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_MSI_SWAP,
+                                !!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP));
+       cmd->info1 |= FIELD_PREP(
+                       HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_TLV_SWAP,
+                       !!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP));
+       cmd->info1 |= FIELD_PREP(
+                       HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_HOST_FW_SWAP,
+                       !!(params.flags & HAL_SRNG_FLAGS_RING_PTR_SWAP));
+       if (htt_ring_type == HTT_SW_TO_HW_RING)
+               cmd->info1 |= HTT_SRNG_SETUP_CMD_INFO1_RING_LOOP_CNT_DIS;
+
+       cmd->ring_head_off32_remote_addr_lo = hp_addr & HAL_ADDR_LSB_REG_MASK;
+       cmd->ring_head_off32_remote_addr_hi = (u64)hp_addr >>
+                                             HAL_ADDR_MSB_REG_SHIFT;
+
+       cmd->ring_tail_off32_remote_addr_lo = tp_addr & HAL_ADDR_LSB_REG_MASK;
+       cmd->ring_tail_off32_remote_addr_hi = (u64)tp_addr >>
+                                             HAL_ADDR_MSB_REG_SHIFT;
+
+       cmd->ring_msi_addr_lo = 0;
+       cmd->ring_msi_addr_hi = 0;
+       cmd->msi_data = 0;
+
+       cmd->intr_info = FIELD_PREP(
+                       HTT_SRNG_SETUP_CMD_INTR_INFO_BATCH_COUNTER_THRESH,
+                       params.intr_batch_cntr_thres_entries * ring_entry_sz);
+       cmd->intr_info |= FIELD_PREP(
+                       HTT_SRNG_SETUP_CMD_INTR_INFO_INTR_TIMER_THRESH,
+                       params.intr_timer_thres_us >> 3);
+
+       cmd->info2 = 0;
+       if (params.flags & HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN) {
+               cmd->info2 = FIELD_PREP(
+                               HTT_SRNG_SETUP_CMD_INFO2_INTR_LOW_THRESH,
+                               params.low_threshold);
+       }
+
+       ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb);
+       if (ret)
+               goto err_free;
+
+       return 0;
+
+err_free:
+       dev_kfree_skb_any(skb);
+
+       return ret;
+}
+
+#define HTT_TARGET_VERSION_TIMEOUT_HZ (3 * HZ)
+
+int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab)
+{
+       struct ath11k_dp *dp = &ab->dp;
+       struct sk_buff *skb;
+       struct htt_ver_req_cmd *cmd;
+       int len = sizeof(*cmd);
+       int ret;
+
+       init_completion(&dp->htt_tgt_version_received);
+
+       skb = ath11k_htc_alloc_skb(ab, len);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_put(skb, len);
+       cmd = (struct htt_ver_req_cmd *)skb->data;
+       cmd->ver_reg_info = FIELD_PREP(HTT_VER_REQ_INFO_MSG_ID,
+                                      HTT_H2T_MSG_TYPE_VERSION_REQ);
+
+       ret = ath11k_htc_send(&ab->htc, dp->eid, skb);
+       if (ret) {
+               dev_kfree_skb_any(skb);
+               return ret;
+       }
+
+       ret = wait_for_completion_timeout(&dp->htt_tgt_version_received,
+                                         HTT_TARGET_VERSION_TIMEOUT_HZ);
+       if (ret == 0) {
+               ath11k_warn(ab, "htt target version request timed out\n");
+               return -ETIMEDOUT;
+       }
+
+       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 0;
+}
+
+int ath11k_dp_tx_htt_h2t_ppdu_stats_req(struct ath11k *ar, u32 mask)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_dp *dp = &ab->dp;
+       struct sk_buff *skb;
+       struct htt_ppdu_stats_cfg_cmd *cmd;
+       int len = sizeof(*cmd);
+       u8 pdev_mask;
+       int ret;
+
+       skb = ath11k_htc_alloc_skb(ab, len);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_put(skb, len);
+       cmd = (struct htt_ppdu_stats_cfg_cmd *)skb->data;
+       cmd->msg = FIELD_PREP(HTT_PPDU_STATS_CFG_MSG_TYPE,
+                             HTT_H2T_MSG_TYPE_PPDU_STATS_CFG);
+
+       pdev_mask = 1 << (ar->pdev_idx);
+       cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_PDEV_ID, pdev_mask);
+       cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK, mask);
+
+       ret = ath11k_htc_send(&ab->htc, dp->eid, skb);
+       if (ret) {
+               dev_kfree_skb_any(skb);
+               return ret;
+       }
+
+       return 0;
+}
+
+int ath11k_dp_tx_htt_rx_filter_setup(struct ath11k_base *ab, u32 ring_id,
+                                    int mac_id, enum hal_ring_type ring_type,
+                                    int rx_buf_size,
+                                    struct htt_rx_ring_tlv_filter *tlv_filter)
+{
+       struct htt_rx_ring_selection_cfg_cmd *cmd;
+       struct hal_srng *srng = &ab->hal.srng_list[ring_id];
+       struct hal_srng_params params;
+       struct sk_buff *skb;
+       int len = sizeof(*cmd);
+       enum htt_srng_ring_type htt_ring_type;
+       enum htt_srng_ring_id htt_ring_id;
+       int ret = 0;
+
+       skb = ath11k_htc_alloc_skb(ab, len);
+       if (!skb)
+               return -ENOMEM;
+
+       memset(¶ms, 0, sizeof(params));
+       ath11k_hal_srng_get_params(ab, srng, ¶ms);
+
+       if (ath11k_dp_tx_get_ring_id_type(ab, mac_id, ring_id,
+                                         ring_type, &htt_ring_type,
+                                         &htt_ring_id))
+               goto err_free;
+
+       skb_put(skb, len);
+       cmd = (struct htt_rx_ring_selection_cfg_cmd *)skb->data;
+       cmd->info0 = FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_MSG_TYPE,
+                               HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG);
+       if (htt_ring_type == HTT_SW_TO_HW_RING ||
+           htt_ring_type == HTT_HW_TO_SW_RING)
+               cmd->info0 |=
+                       FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID,
+                                  DP_SW2HW_MACID(mac_id));
+       else
+               cmd->info0 |=
+                       FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID,
+                                  mac_id);
+       cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_RING_ID,
+                                htt_ring_id);
+       cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_SS,
+                                !!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP));
+       cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PS,
+                                !!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP));
+
+       cmd->info1 = FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO1_BUF_SIZE,
+                               rx_buf_size);
+       cmd->pkt_type_en_flags0 = tlv_filter->pkt_filter_flags0;
+       cmd->pkt_type_en_flags1 = tlv_filter->pkt_filter_flags1;
+       cmd->pkt_type_en_flags2 = tlv_filter->pkt_filter_flags2;
+       cmd->pkt_type_en_flags3 = tlv_filter->pkt_filter_flags3;
+       cmd->rx_filter_tlv = tlv_filter->rx_filter;
+
+       ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb);
+       if (ret)
+               goto err_free;
+
+       return 0;
+
+err_free:
+       dev_kfree_skb_any(skb);
+
+       return ret;
+}
+
+int
+ath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type,
+                                  struct htt_ext_stats_cfg_params *cfg_params,
+                                  u64 cookie)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_dp *dp = &ab->dp;
+       struct sk_buff *skb;
+       struct htt_ext_stats_cfg_cmd *cmd;
+       int len = sizeof(*cmd);
+       int ret;
+
+       skb = ath11k_htc_alloc_skb(ab, len);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_put(skb, len);
+
+       cmd = (struct htt_ext_stats_cfg_cmd *)skb->data;
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG;
+
+       cmd->hdr.pdev_mask = 1 << ar->pdev->pdev_id;
+
+       cmd->hdr.stats_type = type;
+       cmd->cfg_param0 = cfg_params->cfg0;
+       cmd->cfg_param1 = cfg_params->cfg1;
+       cmd->cfg_param2 = cfg_params->cfg2;
+       cmd->cfg_param3 = cfg_params->cfg3;
+       cmd->cookie_lsb = lower_32_bits(cookie);
+       cmd->cookie_msb = upper_32_bits(cookie);
+
+       ret = ath11k_htc_send(&ab->htc, dp->eid, skb);
+       if (ret) {
+               ath11k_warn(ab, "failed to send htt type stats request: %d",
+                           ret);
+               dev_kfree_skb_any(skb);
+               return ret;
+       }
+
+       return 0;
+}
+
+int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset)
+{
+       struct ath11k_pdev_dp *dp = &ar->dp;
+       struct htt_rx_ring_tlv_filter tlv_filter = {0};
+       int ret = 0, ring_id = 0;
+
+       ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id;
+
+       if (!reset) {
+               tlv_filter.rx_filter = HTT_RX_MON_FILTER_TLV_FLAGS_MON_BUF_RING;
+               tlv_filter.pkt_filter_flags0 =
+                                       HTT_RX_MON_FP_MGMT_FILTER_FLAGS0 |
+                                       HTT_RX_MON_MO_MGMT_FILTER_FLAGS0;
+               tlv_filter.pkt_filter_flags1 =
+                                       HTT_RX_MON_FP_MGMT_FILTER_FLAGS1 |
+                                       HTT_RX_MON_MO_MGMT_FILTER_FLAGS1;
+               tlv_filter.pkt_filter_flags2 =
+                                       HTT_RX_MON_FP_CTRL_FILTER_FLASG2 |
+                                       HTT_RX_MON_MO_CTRL_FILTER_FLASG2;
+               tlv_filter.pkt_filter_flags3 =
+                                       HTT_RX_MON_FP_CTRL_FILTER_FLASG3 |
+                                       HTT_RX_MON_MO_CTRL_FILTER_FLASG3 |
+                                       HTT_RX_MON_FP_DATA_FILTER_FLASG3 |
+                                       HTT_RX_MON_MO_DATA_FILTER_FLASG3;
+       }
+
+       ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, dp->mac_id,
+                                              HAL_RXDMA_MONITOR_BUF,
+                                              DP_RXDMA_REFILL_RING_SIZE,
+                                              &tlv_filter);
+       if (ret)
+               return ret;
+
+       ring_id = dp->rx_mon_status_refill_ring.refill_buf_ring.ring_id;
+       if (!reset)
+               tlv_filter.rx_filter =
+                               HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING;
+       else
+               tlv_filter = ath11k_mac_mon_status_filter_default;
+
+       ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, dp->mac_id,
+                                              HAL_RXDMA_MONITOR_STATUS,
+                                              DP_RXDMA_REFILL_RING_SIZE,
+                                              &tlv_filter);
+       return ret;
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_DP_TX_H
+#define ATH11K_DP_TX_H
+
+#include "core.h"
+#include "hal_tx.h"
+
+struct ath11k_dp_htt_wbm_tx_status {
+       u32 msdu_id;
+       bool acked;
+       int ack_rssi;
+};
+
+int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab);
+int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
+                struct sk_buff *skb);
+void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id);
+int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid,
+                             enum hal_reo_cmd_type type,
+                             struct ath11k_hal_reo_cmd *cmd,
+                             void (*func)(struct ath11k_dp *, void *,
+                                          enum hal_reo_cmd_status));
+
+int ath11k_dp_tx_htt_h2t_ppdu_stats_req(struct ath11k *ar, u32 mask);
+int
+ath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type,
+                                  struct htt_ext_stats_cfg_params *cfg_params,
+                                  u64 cookie);
+int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset);
+
+int ath11k_dp_tx_htt_rx_filter_setup(struct ath11k_base *ab, u32 ring_id,
+                                    int mac_id, enum hal_ring_type ring_type,
+                                    int rx_buf_size,
+                                    struct htt_rx_ring_tlv_filter *tlv_filter);
+
+#endif
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+#include <linux/dma-mapping.h>
+#include "ahb.h"
+#include "hal_tx.h"
+#include "debug.h"
+#include "hal_desc.h"
+
+static const struct hal_srng_config hw_srng_config[] = {
+       /* TODO: max_rings can populated by querying HW capabilities */
+       { /* REO_DST */
+               .start_ring_id = HAL_SRNG_RING_ID_REO2SW1,
+               .max_rings = 4,
+               .entry_size = sizeof(struct hal_reo_dest_ring) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_DST,
+               .reg_start = {
+                       HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_BASE_LSB,
+                       HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_HP,
+               },
+               .reg_size = {
+                       HAL_REO2_RING_BASE_LSB - HAL_REO1_RING_BASE_LSB,
+                       HAL_REO2_RING_HP - HAL_REO1_RING_HP,
+               },
+               .max_size = HAL_REO_REO2SW1_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* REO_EXCEPTION */
+               /* Designating REO2TCL ring as exception ring. This ring is
+                * similar to other REO2SW rings though it is named as REO2TCL.
+                * Any of theREO2SW rings can be used as exception ring.
+                */
+               .start_ring_id = HAL_SRNG_RING_ID_REO2TCL,
+               .max_rings = 1,
+               .entry_size = sizeof(struct hal_reo_dest_ring) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_DST,
+               .reg_start = {
+                       HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_BASE_LSB,
+                       HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_TCL_RING_HP,
+               },
+               .max_size = HAL_REO_REO2TCL_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* REO_REINJECT */
+               .start_ring_id = HAL_SRNG_RING_ID_SW2REO,
+               .max_rings = 1,
+               .entry_size = sizeof(struct hal_reo_entrance_ring) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .reg_start = {
+                       HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_BASE_LSB,
+                       HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_HP,
+               },
+               .max_size = HAL_REO_SW2REO_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* REO_CMD */
+               .start_ring_id = HAL_SRNG_RING_ID_REO_CMD,
+               .max_rings = 1,
+               .entry_size = (sizeof(struct hal_tlv_hdr) +
+                       sizeof(struct hal_reo_get_queue_stats)) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .reg_start = {
+                       HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_RING_BASE_LSB,
+                       HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_HP,
+               },
+               .max_size = HAL_REO_CMD_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* REO_STATUS */
+               .start_ring_id = HAL_SRNG_RING_ID_REO_STATUS,
+               .max_rings = 1,
+               .entry_size = (sizeof(struct hal_tlv_hdr) +
+                       sizeof(struct hal_reo_get_queue_stats_status)) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_DST,
+               .reg_start = {
+                       HAL_SEQ_WCSS_UMAC_REO_REG +
+                               HAL_REO_STATUS_RING_BASE_LSB,
+                       HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_HP,
+               },
+               .max_size = HAL_REO_STATUS_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* TCL_DATA */
+               .start_ring_id = HAL_SRNG_RING_ID_SW2TCL1,
+               .max_rings = 3,
+               .entry_size = (sizeof(struct hal_tlv_hdr) +
+                            sizeof(struct hal_tcl_data_cmd)) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .reg_start = {
+                       HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_BASE_LSB,
+                       HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_HP,
+               },
+               .reg_size = {
+                       HAL_TCL2_RING_BASE_LSB - HAL_TCL1_RING_BASE_LSB,
+                       HAL_TCL2_RING_HP - HAL_TCL1_RING_HP,
+               },
+               .max_size = HAL_SW2TCL1_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* TCL_CMD */
+               .start_ring_id = HAL_SRNG_RING_ID_SW2TCL_CMD,
+               .max_rings = 1,
+               .entry_size = (sizeof(struct hal_tlv_hdr) +
+                            sizeof(struct hal_tcl_gse_cmd)) >> 2,
+               .lmac_ring =  false,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .reg_start = {
+                       HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_BASE_LSB,
+                       HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_HP,
+               },
+               .max_size = HAL_SW2TCL1_CMD_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* TCL_STATUS */
+               .start_ring_id = HAL_SRNG_RING_ID_TCL_STATUS,
+               .max_rings = 1,
+               .entry_size = (sizeof(struct hal_tlv_hdr) +
+                            sizeof(struct hal_tcl_status_ring)) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_DST,
+               .reg_start = {
+                       HAL_SEQ_WCSS_UMAC_TCL_REG +
+                               HAL_TCL_STATUS_RING_BASE_LSB,
+                       HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP,
+               },
+               .max_size = HAL_TCL_STATUS_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* CE_SRC */
+               .start_ring_id = HAL_SRNG_RING_ID_CE0_SRC,
+               .max_rings = 12,
+               .entry_size = sizeof(struct hal_ce_srng_src_desc) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .reg_start = {
+                       (HAL_SEQ_WCSS_UMAC_CE0_SRC_REG +
+                        HAL_CE_DST_RING_BASE_LSB),
+                       HAL_SEQ_WCSS_UMAC_CE0_SRC_REG + HAL_CE_DST_RING_HP,
+               },
+               .reg_size = {
+                       (HAL_SEQ_WCSS_UMAC_CE1_SRC_REG -
+                        HAL_SEQ_WCSS_UMAC_CE0_SRC_REG),
+                       (HAL_SEQ_WCSS_UMAC_CE1_SRC_REG -
+                        HAL_SEQ_WCSS_UMAC_CE0_SRC_REG),
+               },
+               .max_size = HAL_CE_SRC_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* CE_DST */
+               .start_ring_id = HAL_SRNG_RING_ID_CE0_DST,
+               .max_rings = 12,
+               .entry_size = sizeof(struct hal_ce_srng_dest_desc) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .reg_start = {
+                       (HAL_SEQ_WCSS_UMAC_CE0_DST_REG +
+                        HAL_CE_DST_RING_BASE_LSB),
+                       HAL_SEQ_WCSS_UMAC_CE0_DST_REG + HAL_CE_DST_RING_HP,
+               },
+               .reg_size = {
+                       (HAL_SEQ_WCSS_UMAC_CE1_DST_REG -
+                        HAL_SEQ_WCSS_UMAC_CE0_DST_REG),
+                       (HAL_SEQ_WCSS_UMAC_CE1_DST_REG -
+                        HAL_SEQ_WCSS_UMAC_CE0_DST_REG),
+               },
+               .max_size = HAL_CE_DST_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* CE_DST_STATUS */
+               .start_ring_id = HAL_SRNG_RING_ID_CE0_DST_STATUS,
+               .max_rings = 12,
+               .entry_size = sizeof(struct hal_ce_srng_dst_status_desc) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_DST,
+               .reg_start = {
+                       (HAL_SEQ_WCSS_UMAC_CE0_DST_REG +
+                        HAL_CE_DST_STATUS_RING_BASE_LSB),
+                       (HAL_SEQ_WCSS_UMAC_CE0_DST_REG +
+                        HAL_CE_DST_STATUS_RING_HP),
+               },
+               .reg_size = {
+                       (HAL_SEQ_WCSS_UMAC_CE1_DST_REG -
+                        HAL_SEQ_WCSS_UMAC_CE0_DST_REG),
+                       (HAL_SEQ_WCSS_UMAC_CE1_DST_REG -
+                        HAL_SEQ_WCSS_UMAC_CE0_DST_REG),
+               },
+               .max_size = HAL_CE_DST_STATUS_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* WBM_IDLE_LINK */
+               .start_ring_id = HAL_SRNG_RING_ID_WBM_IDLE_LINK,
+               .max_rings = 1,
+               .entry_size = sizeof(struct hal_wbm_link_desc) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .reg_start = {
+                       (HAL_SEQ_WCSS_UMAC_WBM_REG +
+                        HAL_WBM_IDLE_LINK_RING_BASE_LSB),
+                       (HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_IDLE_LINK_RING_HP),
+               },
+               .max_size = HAL_WBM_IDLE_LINK_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* SW2WBM_RELEASE */
+               .start_ring_id = HAL_SRNG_RING_ID_WBM_SW_RELEASE,
+               .max_rings = 1,
+               .entry_size = sizeof(struct hal_wbm_release_ring) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .reg_start = {
+                       (HAL_SEQ_WCSS_UMAC_WBM_REG +
+                        HAL_WBM_RELEASE_RING_BASE_LSB),
+                       (HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_RELEASE_RING_HP),
+               },
+               .max_size = HAL_SW2WBM_RELEASE_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* WBM2SW_RELEASE */
+               .start_ring_id = HAL_SRNG_RING_ID_WBM2SW0_RELEASE,
+               .max_rings = 4,
+               .entry_size = sizeof(struct hal_wbm_release_ring) >> 2,
+               .lmac_ring = false,
+               .ring_dir = HAL_SRNG_DIR_DST,
+               .reg_start = {
+                       (HAL_SEQ_WCSS_UMAC_WBM_REG +
+                        HAL_WBM0_RELEASE_RING_BASE_LSB),
+                       (HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM0_RELEASE_RING_HP),
+               },
+               .reg_size = {
+                       (HAL_WBM1_RELEASE_RING_BASE_LSB -
+                        HAL_WBM0_RELEASE_RING_BASE_LSB),
+                       (HAL_WBM1_RELEASE_RING_HP - HAL_WBM0_RELEASE_RING_HP),
+               },
+               .max_size = HAL_WBM2SW_RELEASE_RING_BASE_MSB_RING_SIZE,
+       },
+       { /* RXDMA_BUF */
+               .start_ring_id = HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF,
+               .max_rings = 2,
+               .entry_size = sizeof(struct hal_wbm_buffer_ring) >> 2,
+               .lmac_ring = true,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .max_size = HAL_RXDMA_RING_MAX_SIZE,
+       },
+       { /* RXDMA_DST */
+               .start_ring_id = HAL_SRNG_RING_ID_WMAC1_RXDMA2SW0,
+               .max_rings = 1,
+               .entry_size = sizeof(struct hal_reo_entrance_ring) >> 2,
+               .lmac_ring = true,
+               .ring_dir = HAL_SRNG_DIR_DST,
+               .max_size = HAL_RXDMA_RING_MAX_SIZE,
+       },
+       { /* RXDMA_MONITOR_BUF */
+               .start_ring_id = HAL_SRNG_RING_ID_WMAC1_SW2RXDMA2_BUF,
+               .max_rings = 1,
+               .entry_size = sizeof(struct hal_wbm_buffer_ring) >> 2,
+               .lmac_ring = true,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .max_size = HAL_RXDMA_RING_MAX_SIZE,
+       },
+       { /* RXDMA_MONITOR_STATUS */
+               .start_ring_id = HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_STATBUF,
+               .max_rings = 1,
+               .entry_size = sizeof(struct hal_wbm_buffer_ring) >> 2,
+               .lmac_ring = true,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .max_size = HAL_RXDMA_RING_MAX_SIZE,
+       },
+       { /* RXDMA_MONITOR_DST */
+               .start_ring_id = HAL_SRNG_RING_ID_WMAC1_RXDMA2SW1,
+               .max_rings = 1,
+               .entry_size = sizeof(struct hal_reo_entrance_ring) >> 2,
+               .lmac_ring = true,
+               .ring_dir = HAL_SRNG_DIR_DST,
+               .max_size = HAL_RXDMA_RING_MAX_SIZE,
+       },
+       { /* RXDMA_MONITOR_DESC */
+               .start_ring_id = HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_DESC,
+               .max_rings = 1,
+               .entry_size = sizeof(struct hal_wbm_buffer_ring) >> 2,
+               .lmac_ring = true,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .max_size = HAL_RXDMA_RING_MAX_SIZE,
+       },
+       { /* RXDMA DIR BUF */
+               .start_ring_id = HAL_SRNG_RING_ID_RXDMA_DIR_BUF,
+               .max_rings = 1,
+               .entry_size = 8 >> 2, /* TODO: Define the struct */
+               .lmac_ring = true,
+               .ring_dir = HAL_SRNG_DIR_SRC,
+               .max_size = HAL_RXDMA_RING_MAX_SIZE,
+       },
+};
+
+static int ath11k_hal_alloc_cont_rdp(struct ath11k_base *ab)
+{
+       struct ath11k_hal *hal = &ab->hal;
+       size_t size;
+
+       size = sizeof(u32) * HAL_SRNG_RING_ID_MAX;
+       hal->rdp.vaddr = dma_alloc_coherent(ab->dev, size, &hal->rdp.paddr,
+                                           GFP_KERNEL);
+       if (!hal->rdp.vaddr)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void ath11k_hal_free_cont_rdp(struct ath11k_base *ab)
+{
+       struct ath11k_hal *hal = &ab->hal;
+       size_t size;
+
+       if (!hal->rdp.vaddr)
+               return;
+
+       size = sizeof(u32) * HAL_SRNG_RING_ID_MAX;
+       dma_free_coherent(ab->dev, size,
+                         hal->rdp.vaddr, hal->rdp.paddr);
+       hal->rdp.vaddr = NULL;
+}
+
+static int ath11k_hal_alloc_cont_wrp(struct ath11k_base *ab)
+{
+       struct ath11k_hal *hal = &ab->hal;
+       size_t size;
+
+       size = sizeof(u32) * HAL_SRNG_NUM_LMAC_RINGS;
+       hal->wrp.vaddr = dma_alloc_coherent(ab->dev, size, &hal->wrp.paddr,
+                                           GFP_KERNEL);
+       if (!hal->wrp.vaddr)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void ath11k_hal_free_cont_wrp(struct ath11k_base *ab)
+{
+       struct ath11k_hal *hal = &ab->hal;
+       size_t size;
+
+       if (!hal->wrp.vaddr)
+               return;
+
+       size = sizeof(u32) * HAL_SRNG_NUM_LMAC_RINGS;
+       dma_free_coherent(ab->dev, size,
+                         hal->wrp.vaddr, hal->wrp.paddr);
+       hal->wrp.vaddr = NULL;
+}
+
+static void ath11k_hal_ce_dst_setup(struct ath11k_base *ab,
+                                   struct hal_srng *srng, int ring_num)
+{
+       const struct hal_srng_config *srng_config = &hw_srng_config[HAL_CE_DST];
+       u32 addr;
+       u32 val;
+
+       addr = HAL_CE_DST_RING_CTRL +
+              srng_config->reg_start[HAL_SRNG_REG_GRP_R0] +
+              ring_num * srng_config->reg_size[HAL_SRNG_REG_GRP_R0];
+       val = ath11k_ahb_read32(ab, addr);
+       val &= ~HAL_CE_DST_R0_DEST_CTRL_MAX_LEN;
+       val |= FIELD_PREP(HAL_CE_DST_R0_DEST_CTRL_MAX_LEN,
+                         srng->u.dst_ring.max_buffer_length);
+       ath11k_ahb_write32(ab, addr, val);
+}
+
+static void ath11k_hal_srng_dst_hw_init(struct ath11k_base *ab,
+                                       struct hal_srng *srng)
+{
+       struct ath11k_hal *hal = &ab->hal;
+       u32 val;
+       u64 hp_addr;
+       u32 reg_base;
+
+       reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];
+
+       if (srng->flags & HAL_SRNG_FLAGS_MSI_INTR) {
+               ath11k_ahb_write32(ab, reg_base +
+                                      HAL_REO1_RING_MSI1_BASE_LSB_OFFSET,
+                                  (u32)srng->msi_addr);
+
+               val = FIELD_PREP(HAL_REO1_RING_MSI1_BASE_MSB_ADDR,
+                                ((u64)srng->msi_addr >>
+                                 HAL_ADDR_MSB_REG_SHIFT)) |
+                     HAL_REO1_RING_MSI1_BASE_MSB_MSI1_ENABLE;
+               ath11k_ahb_write32(ab, reg_base +
+                                      HAL_REO1_RING_MSI1_BASE_MSB_OFFSET, val);
+
+               ath11k_ahb_write32(ab,
+                                  reg_base + HAL_REO1_RING_MSI1_DATA_OFFSET,
+                                  srng->msi_data);
+       }
+
+       ath11k_ahb_write32(ab, reg_base, (u32)srng->ring_base_paddr);
+
+       val = FIELD_PREP(HAL_REO1_RING_BASE_MSB_RING_BASE_ADDR_MSB,
+                        ((u64)srng->ring_base_paddr >>
+                         HAL_ADDR_MSB_REG_SHIFT)) |
+             FIELD_PREP(HAL_REO1_RING_BASE_MSB_RING_SIZE,
+                        (srng->entry_size * srng->num_entries));
+       ath11k_ahb_write32(ab, reg_base + HAL_REO1_RING_BASE_MSB_OFFSET, val);
+
+       val = FIELD_PREP(HAL_REO1_RING_ID_RING_ID, srng->ring_id) |
+             FIELD_PREP(HAL_REO1_RING_ID_ENTRY_SIZE, srng->entry_size);
+       ath11k_ahb_write32(ab, reg_base + HAL_REO1_RING_ID_OFFSET, val);
+
+       /* interrupt setup */
+       val = FIELD_PREP(HAL_REO1_RING_PRDR_INT_SETUP_INTR_TMR_THOLD,
+                        (srng->intr_timer_thres_us >> 3));
+
+       val |= FIELD_PREP(HAL_REO1_RING_PRDR_INT_SETUP_BATCH_COUNTER_THOLD,
+                         (srng->intr_batch_cntr_thres_entries *
+                          srng->entry_size));
+
+       ath11k_ahb_write32(ab,
+                          reg_base + HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET,
+                          val);
+
+       hp_addr = hal->rdp.paddr +
+                 ((unsigned long)srng->u.dst_ring.hp_addr -
+                  (unsigned long)hal->rdp.vaddr);
+       ath11k_ahb_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_LSB_OFFSET,
+                          hp_addr & HAL_ADDR_LSB_REG_MASK);
+       ath11k_ahb_write32(ab, reg_base + HAL_REO1_RING_HP_ADDR_MSB_OFFSET,
+                          hp_addr >> HAL_ADDR_MSB_REG_SHIFT);
+
+       /* Initialize head and tail pointers to indicate ring is empty */
+       reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2];
+       ath11k_ahb_write32(ab, reg_base, 0);
+       ath11k_ahb_write32(ab, reg_base + HAL_REO1_RING_TP_OFFSET, 0);
+       *srng->u.dst_ring.hp_addr = 0;
+
+       reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];
+       val = 0;
+       if (srng->flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP)
+               val |= HAL_REO1_RING_MISC_DATA_TLV_SWAP;
+       if (srng->flags & HAL_SRNG_FLAGS_RING_PTR_SWAP)
+               val |= HAL_REO1_RING_MISC_HOST_FW_SWAP;
+       if (srng->flags & HAL_SRNG_FLAGS_MSI_SWAP)
+               val |= HAL_REO1_RING_MISC_MSI_SWAP;
+       val |= HAL_REO1_RING_MISC_SRNG_ENABLE;
+
+       ath11k_ahb_write32(ab, reg_base + HAL_REO1_RING_MISC_OFFSET, val);
+}
+
+static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab,
+                                       struct hal_srng *srng)
+{
+       struct ath11k_hal *hal = &ab->hal;
+       u32 val;
+       u64 tp_addr;
+       u32 reg_base;
+
+       reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];
+
+       if (srng->flags & HAL_SRNG_FLAGS_MSI_INTR) {
+               ath11k_ahb_write32(ab, reg_base +
+                                      HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET,
+                                  (u32)srng->msi_addr);
+
+               val = FIELD_PREP(HAL_TCL1_RING_MSI1_BASE_MSB_ADDR,
+                                ((u64)srng->msi_addr >>
+                                 HAL_ADDR_MSB_REG_SHIFT)) |
+                     HAL_TCL1_RING_MSI1_BASE_MSB_MSI1_ENABLE;
+               ath11k_ahb_write32(ab, reg_base +
+                                      HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET,
+                                  val);
+
+               ath11k_ahb_write32(ab, reg_base +
+                                      HAL_TCL1_RING_MSI1_DATA_OFFSET,
+                                  srng->msi_data);
+       }
+
+       ath11k_ahb_write32(ab, reg_base, (u32)srng->ring_base_paddr);
+
+       val = FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB,
+                        ((u64)srng->ring_base_paddr >>
+                         HAL_ADDR_MSB_REG_SHIFT)) |
+             FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_SIZE,
+                        (srng->entry_size * srng->num_entries));
+       ath11k_ahb_write32(ab, reg_base + HAL_TCL1_RING_BASE_MSB_OFFSET, val);
+
+       val = FIELD_PREP(HAL_REO1_RING_ID_ENTRY_SIZE, srng->entry_size);
+       ath11k_ahb_write32(ab, reg_base + HAL_TCL1_RING_ID_OFFSET, val);
+
+       /* interrupt setup */
+       /* NOTE: IPQ8074 v2 requires the interrupt timer threshold in the
+        * unit of 8 usecs instead of 1 usec (as required by v1).
+        */
+       val = FIELD_PREP(HAL_TCL1_RING_CONSR_INT_SETUP_IX0_INTR_TMR_THOLD,
+                        srng->intr_timer_thres_us);
+
+       val |= FIELD_PREP(HAL_TCL1_RING_CONSR_INT_SETUP_IX0_BATCH_COUNTER_THOLD,
+                         (srng->intr_batch_cntr_thres_entries *
+                          srng->entry_size));
+
+       ath11k_ahb_write32(ab,
+                          reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET,
+                          val);
+
+       val = 0;
+       if (srng->flags & HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN) {
+               val |= FIELD_PREP(HAL_TCL1_RING_CONSR_INT_SETUP_IX1_LOW_THOLD,
+                                 srng->u.src_ring.low_threshold);
+       }
+       ath11k_ahb_write32(ab,
+                          reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET,
+                          val);
+
+       if (srng->ring_id != HAL_SRNG_RING_ID_WBM_IDLE_LINK) {
+               tp_addr = hal->rdp.paddr +
+                         ((unsigned long)srng->u.src_ring.tp_addr -
+                          (unsigned long)hal->rdp.vaddr);
+               ath11k_ahb_write32(ab,
+                                  reg_base + HAL_TCL1_RING_TP_ADDR_LSB_OFFSET,
+                                  tp_addr & HAL_ADDR_LSB_REG_MASK);
+               ath11k_ahb_write32(ab,
+                                  reg_base + HAL_TCL1_RING_TP_ADDR_MSB_OFFSET,
+                                  tp_addr >> HAL_ADDR_MSB_REG_SHIFT);
+       }
+
+       /* Initialize head and tail pointers to indicate ring is empty */
+       reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2];
+       ath11k_ahb_write32(ab, reg_base, 0);
+       ath11k_ahb_write32(ab, reg_base + HAL_TCL1_RING_TP_OFFSET, 0);
+       *srng->u.src_ring.tp_addr = 0;
+
+       reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];
+       val = 0;
+       if (srng->flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP)
+               val |= HAL_TCL1_RING_MISC_DATA_TLV_SWAP;
+       if (srng->flags & HAL_SRNG_FLAGS_RING_PTR_SWAP)
+               val |= HAL_TCL1_RING_MISC_HOST_FW_SWAP;
+       if (srng->flags & HAL_SRNG_FLAGS_MSI_SWAP)
+               val |= HAL_TCL1_RING_MISC_MSI_SWAP;
+
+       /* Loop count is not used for SRC rings */
+       val |= HAL_TCL1_RING_MISC_MSI_LOOPCNT_DISABLE;
+
+       val |= HAL_TCL1_RING_MISC_SRNG_ENABLE;
+
+       ath11k_ahb_write32(ab, reg_base + HAL_TCL1_RING_MISC_OFFSET, val);
+}
+
+static void ath11k_hal_srng_hw_init(struct ath11k_base *ab,
+                                   struct hal_srng *srng)
+{
+       if (srng->ring_dir == HAL_SRNG_DIR_SRC)
+               ath11k_hal_srng_src_hw_init(ab, srng);
+       else
+               ath11k_hal_srng_dst_hw_init(ab, srng);
+}
+
+static int ath11k_hal_srng_get_ring_id(struct ath11k_base *ab,
+                                      enum hal_ring_type type,
+                                      int ring_num, int mac_id)
+{
+       const struct hal_srng_config *srng_config = &hw_srng_config[type];
+       int ring_id;
+
+       if (ring_num >= srng_config->max_rings) {
+               ath11k_warn(ab, "invalid ring number :%d\n", ring_num);
+               return -EINVAL;
+       }
+
+       ring_id = srng_config->start_ring_id + ring_num;
+       if (srng_config->lmac_ring)
+               ring_id += mac_id * HAL_SRNG_RINGS_PER_LMAC;
+
+       if (WARN_ON(ring_id >= HAL_SRNG_RING_ID_MAX))
+               return -EINVAL;
+
+       return ring_id;
+}
+
+int ath11k_hal_srng_get_entrysize(u32 ring_type)
+{
+       const struct hal_srng_config *srng_config;
+
+       if (WARN_ON(ring_type >= HAL_MAX_RING_TYPES))
+               return -EINVAL;
+
+       srng_config = &hw_srng_config[ring_type];
+
+       return (srng_config->entry_size << 2);
+}
+
+int ath11k_hal_srng_get_max_entries(u32 ring_type)
+{
+       const struct hal_srng_config *srng_config;
+
+       if (WARN_ON(ring_type >= HAL_MAX_RING_TYPES))
+               return -EINVAL;
+
+       srng_config = &hw_srng_config[ring_type];
+
+       return (srng_config->max_size / srng_config->entry_size);
+}
+
+void ath11k_hal_srng_get_params(struct ath11k_base *ab, struct hal_srng *srng,
+                               struct hal_srng_params *params)
+{
+       params->ring_base_paddr = srng->ring_base_paddr;
+       params->ring_base_vaddr = srng->ring_base_vaddr;
+       params->num_entries = srng->num_entries;
+       params->intr_timer_thres_us = srng->intr_timer_thres_us;
+       params->intr_batch_cntr_thres_entries =
+               srng->intr_batch_cntr_thres_entries;
+       params->low_threshold = srng->u.src_ring.low_threshold;
+       params->flags = srng->flags;
+}
+
+dma_addr_t ath11k_hal_srng_get_hp_addr(struct ath11k_base *ab,
+                                      struct hal_srng *srng)
+{
+       if (!(srng->flags & HAL_SRNG_FLAGS_LMAC_RING))
+               return 0;
+
+       if (srng->ring_dir == HAL_SRNG_DIR_SRC)
+               return ab->hal.wrp.paddr +
+                      ((unsigned long)srng->u.src_ring.hp_addr -
+                       (unsigned long)ab->hal.wrp.vaddr);
+       else
+               return ab->hal.rdp.paddr +
+                      ((unsigned long)srng->u.dst_ring.hp_addr -
+                        (unsigned long)ab->hal.rdp.vaddr);
+}
+
+dma_addr_t ath11k_hal_srng_get_tp_addr(struct ath11k_base *ab,
+                                      struct hal_srng *srng)
+{
+       if (!(srng->flags & HAL_SRNG_FLAGS_LMAC_RING))
+               return 0;
+
+       if (srng->ring_dir == HAL_SRNG_DIR_SRC)
+               return ab->hal.rdp.paddr +
+                      ((unsigned long)srng->u.src_ring.tp_addr -
+                       (unsigned long)ab->hal.rdp.vaddr);
+       else
+               return ab->hal.wrp.paddr +
+                      ((unsigned long)srng->u.dst_ring.tp_addr -
+                       (unsigned long)ab->hal.wrp.vaddr);
+}
+
+u32 ath11k_hal_ce_get_desc_size(enum hal_ce_desc type)
+{
+       switch (type) {
+       case HAL_CE_DESC_SRC:
+               return sizeof(struct hal_ce_srng_src_desc);
+       case HAL_CE_DESC_DST:
+               return sizeof(struct hal_ce_srng_dest_desc);
+       case HAL_CE_DESC_DST_STATUS:
+               return sizeof(struct hal_ce_srng_dst_status_desc);
+       }
+
+       return 0;
+}
+
+void ath11k_hal_ce_src_set_desc(void *buf, dma_addr_t paddr, u32 len, u32 id,
+                               u8 byte_swap_data)
+{
+       struct hal_ce_srng_src_desc *desc = (struct hal_ce_srng_src_desc *)buf;
+
+       desc->buffer_addr_low = paddr & HAL_ADDR_LSB_REG_MASK;
+       desc->buffer_addr_info =
+               FIELD_PREP(HAL_CE_SRC_DESC_ADDR_INFO_ADDR_HI,
+                          ((u64)paddr >> HAL_ADDR_MSB_REG_SHIFT)) |
+               FIELD_PREP(HAL_CE_SRC_DESC_ADDR_INFO_BYTE_SWAP,
+                          byte_swap_data) |
+               FIELD_PREP(HAL_CE_SRC_DESC_ADDR_INFO_GATHER, 0) |
+               FIELD_PREP(HAL_CE_SRC_DESC_ADDR_INFO_LEN, len);
+       desc->meta_info = FIELD_PREP(HAL_CE_SRC_DESC_META_INFO_DATA, id);
+}
+
+void ath11k_hal_ce_dst_set_desc(void *buf, dma_addr_t paddr)
+{
+       struct hal_ce_srng_dest_desc *desc =
+               (struct hal_ce_srng_dest_desc *)buf;
+
+       desc->buffer_addr_low = paddr & HAL_ADDR_LSB_REG_MASK;
+       desc->buffer_addr_info =
+               FIELD_PREP(HAL_CE_DEST_DESC_ADDR_INFO_ADDR_HI,
+                          ((u64)paddr >> HAL_ADDR_MSB_REG_SHIFT));
+}
+
+u32 ath11k_hal_ce_dst_status_get_length(void *buf)
+{
+       struct hal_ce_srng_dst_status_desc *desc =
+               (struct hal_ce_srng_dst_status_desc *)buf;
+       u32 len;
+
+       len = FIELD_GET(HAL_CE_DST_STATUS_DESC_FLAGS_LEN, desc->flags);
+       desc->flags &= ~HAL_CE_DST_STATUS_DESC_FLAGS_LEN;
+
+       return len;
+}
+
+void ath11k_hal_set_link_desc_addr(struct hal_wbm_link_desc *desc, u32 cookie,
+                                  dma_addr_t paddr)
+{
+       desc->buf_addr_info.info0 = FIELD_PREP(BUFFER_ADDR_INFO0_ADDR,
+                                              (paddr & HAL_ADDR_LSB_REG_MASK));
+       desc->buf_addr_info.info1 = FIELD_PREP(BUFFER_ADDR_INFO1_ADDR,
+                                              ((u64)paddr >> HAL_ADDR_MSB_REG_SHIFT)) |
+                                   FIELD_PREP(BUFFER_ADDR_INFO1_RET_BUF_MGR, 1) |
+                                   FIELD_PREP(BUFFER_ADDR_INFO1_SW_COOKIE, cookie);
+}
+
+u32 *ath11k_hal_srng_dst_peek(struct ath11k_base *ab, struct hal_srng *srng)
+{
+       lockdep_assert_held(&srng->lock);
+
+       if (srng->u.dst_ring.tp != srng->u.dst_ring.cached_hp)
+               return (srng->ring_base_vaddr + srng->u.dst_ring.tp);
+
+       return NULL;
+}
+
+u32 *ath11k_hal_srng_dst_get_next_entry(struct ath11k_base *ab,
+                                       struct hal_srng *srng)
+{
+       u32 *desc;
+
+       lockdep_assert_held(&srng->lock);
+
+       if (srng->u.dst_ring.tp == srng->u.dst_ring.cached_hp)
+               return NULL;
+
+       desc = srng->ring_base_vaddr + srng->u.dst_ring.tp;
+
+       srng->u.dst_ring.tp = (srng->u.dst_ring.tp + srng->entry_size) %
+                             srng->ring_size;
+
+       return desc;
+}
+
+int ath11k_hal_srng_dst_num_free(struct ath11k_base *ab, struct hal_srng *srng,
+                                bool sync_hw_ptr)
+{
+       u32 tp, hp;
+
+       lockdep_assert_held(&srng->lock);
+
+       tp = srng->u.dst_ring.tp;
+
+       if (sync_hw_ptr) {
+               hp = *srng->u.dst_ring.hp_addr;
+               srng->u.dst_ring.cached_hp = hp;
+       } else {
+               hp = srng->u.dst_ring.cached_hp;
+       }
+
+       if (hp >= tp)
+               return (hp - tp) / srng->entry_size;
+       else
+               return (srng->ring_size - tp + hp) / srng->entry_size;
+}
+
+/* Returns number of available entries in src ring */
+int ath11k_hal_srng_src_num_free(struct ath11k_base *ab, struct hal_srng *srng,
+                                bool sync_hw_ptr)
+{
+       u32 tp, hp;
+
+       lockdep_assert_held(&srng->lock);
+
+       hp = srng->u.src_ring.hp;
+
+       if (sync_hw_ptr) {
+               tp = *srng->u.src_ring.tp_addr;
+               srng->u.src_ring.cached_tp = tp;
+       } else {
+               tp = srng->u.src_ring.cached_tp;
+       }
+
+       if (tp > hp)
+               return ((tp - hp) / srng->entry_size) - 1;
+       else
+               return ((srng->ring_size - hp + tp) / srng->entry_size) - 1;
+}
+
+u32 *ath11k_hal_srng_src_get_next_entry(struct ath11k_base *ab,
+                                       struct hal_srng *srng)
+{
+       u32 *desc;
+       u32 next_hp;
+
+       lockdep_assert_held(&srng->lock);
+
+       /* TODO: Using % is expensive, but we have to do this since size of some
+        * SRNG rings is not power of 2 (due to descriptor sizes). Need to see
+        * if separate function is defined for rings having power of 2 ring size
+        * (TCL2SW, REO2SW, SW2RXDMA and CE rings) so that we can avoid the
+        * overhead of % by using mask (with &).
+        */
+       next_hp = (srng->u.src_ring.hp + srng->entry_size) % srng->ring_size;
+
+       if (next_hp == srng->u.src_ring.cached_tp)
+               return NULL;
+
+       desc = srng->ring_base_vaddr + srng->u.src_ring.hp;
+       srng->u.src_ring.hp = next_hp;
+
+       /* TODO: Reap functionality is not used by all rings. If particular
+        * ring does not use reap functionality, we need not update reap_hp
+        * with next_hp pointer. Need to make sure a separate function is used
+        * before doing any optimization by removing below code updating
+        * reap_hp.
+        */
+       srng->u.src_ring.reap_hp = next_hp;
+
+       return desc;
+}
+
+u32 *ath11k_hal_srng_src_reap_next(struct ath11k_base *ab,
+                                  struct hal_srng *srng)
+{
+       u32 *desc;
+       u32 next_reap_hp;
+
+       lockdep_assert_held(&srng->lock);
+
+       next_reap_hp = (srng->u.src_ring.reap_hp + srng->entry_size) %
+                      srng->ring_size;
+
+       if (next_reap_hp == srng->u.src_ring.cached_tp)
+               return NULL;
+
+       desc = srng->ring_base_vaddr + next_reap_hp;
+       srng->u.src_ring.reap_hp = next_reap_hp;
+
+       return desc;
+}
+
+u32 *ath11k_hal_srng_src_get_next_reaped(struct ath11k_base *ab,
+                                        struct hal_srng *srng)
+{
+       u32 *desc;
+
+       lockdep_assert_held(&srng->lock);
+
+       if (srng->u.src_ring.hp == srng->u.src_ring.reap_hp)
+               return NULL;
+
+       desc = srng->ring_base_vaddr + srng->u.src_ring.hp;
+       srng->u.src_ring.hp = (srng->u.src_ring.hp + srng->entry_size) %
+                             srng->ring_size;
+
+       return desc;
+}
+
+u32 *ath11k_hal_srng_src_peek(struct ath11k_base *ab, struct hal_srng *srng)
+{
+       lockdep_assert_held(&srng->lock);
+
+       if (((srng->u.src_ring.hp + srng->entry_size) % srng->ring_size) ==
+           srng->u.src_ring.cached_tp)
+               return NULL;
+
+       return srng->ring_base_vaddr + srng->u.src_ring.hp;
+}
+
+void ath11k_hal_srng_access_begin(struct ath11k_base *ab, struct hal_srng *srng)
+{
+       lockdep_assert_held(&srng->lock);
+
+       if (srng->ring_dir == HAL_SRNG_DIR_SRC)
+               srng->u.src_ring.cached_tp =
+                       *(volatile u32 *)srng->u.src_ring.tp_addr;
+       else
+               srng->u.dst_ring.cached_hp = *srng->u.dst_ring.hp_addr;
+}
+
+/* Update cached ring head/tail pointers to HW. ath11k_hal_srng_access_begin()
+ * should have been called before this.
+ */
+void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng)
+{
+       lockdep_assert_held(&srng->lock);
+
+       /* TODO: See if we need a write memory barrier here */
+       if (srng->flags & HAL_SRNG_FLAGS_LMAC_RING) {
+               /* For LMAC rings, ring pointer updates are done through FW and
+                * hence written to a shared memory location that is read by FW
+                */
+               if (srng->ring_dir == HAL_SRNG_DIR_SRC)
+                       *srng->u.src_ring.hp_addr = srng->u.src_ring.hp;
+               else
+                       *srng->u.dst_ring.tp_addr = srng->u.dst_ring.tp;
+       } else {
+               if (srng->ring_dir == HAL_SRNG_DIR_SRC) {
+                       ath11k_ahb_write32(ab,
+                                          (unsigned long)srng->u.src_ring.hp_addr -
+                                          (unsigned long)ab->mem,
+                                          srng->u.src_ring.hp);
+               } else {
+                       ath11k_ahb_write32(ab,
+                                          (unsigned long)srng->u.dst_ring.tp_addr -
+                                          (unsigned long)ab->mem,
+                                          srng->u.dst_ring.tp);
+               }
+       }
+}
+
+void ath11k_hal_setup_link_idle_list(struct ath11k_base *ab,
+                                    struct hal_wbm_idle_scatter_list *sbuf,
+                                    u32 nsbufs, u32 tot_link_desc,
+                                    u32 end_offset)
+{
+       struct ath11k_buffer_addr *link_addr;
+       int i;
+       u32 reg_scatter_buf_sz = HAL_WBM_IDLE_SCATTER_BUF_SIZE / 64;
+
+       link_addr = (void *)sbuf[0].vaddr + HAL_WBM_IDLE_SCATTER_BUF_SIZE;
+
+       for (i = 1; i < nsbufs; i++) {
+               link_addr->info0 = sbuf[i].paddr & HAL_ADDR_LSB_REG_MASK;
+               link_addr->info1 = FIELD_PREP(
+                               HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32,
+                               (u64)sbuf[i].paddr >> HAL_ADDR_MSB_REG_SHIFT) |
+                               FIELD_PREP(
+                               HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_MATCH_TAG,
+                               BASE_ADDR_MATCH_TAG_VAL);
+
+               link_addr = (void *)sbuf[i].vaddr +
+                            HAL_WBM_IDLE_SCATTER_BUF_SIZE;
+       }
+
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_R0_IDLE_LIST_CONTROL_ADDR,
+                          FIELD_PREP(HAL_WBM_SCATTER_BUFFER_SIZE, reg_scatter_buf_sz) |
+                          FIELD_PREP(HAL_WBM_LINK_DESC_IDLE_LIST_MODE, 0x1));
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_R0_IDLE_LIST_SIZE_ADDR,
+                          FIELD_PREP(HAL_WBM_SCATTER_RING_SIZE_OF_IDLE_LINK_DESC_LIST,
+                                     reg_scatter_buf_sz * nsbufs));
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG +
+                          HAL_WBM_SCATTERED_RING_BASE_LSB,
+                          FIELD_PREP(BUFFER_ADDR_INFO0_ADDR,
+                                     sbuf[0].paddr & HAL_ADDR_LSB_REG_MASK));
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG +
+                          HAL_WBM_SCATTERED_RING_BASE_MSB,
+                          FIELD_PREP(
+                               HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32,
+                               (u64)sbuf[0].paddr >> HAL_ADDR_MSB_REG_SHIFT) |
+                               FIELD_PREP(
+                               HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_MATCH_TAG,
+                               BASE_ADDR_MATCH_TAG_VAL));
+
+       /* Setup head and tail pointers for the idle list */
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG +
+                          HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX0,
+                          FIELD_PREP(BUFFER_ADDR_INFO0_ADDR,
+                                     sbuf[nsbufs - 1].paddr));
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG +
+                          HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX1,
+                          FIELD_PREP(
+                               HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32,
+                               ((u64)sbuf[nsbufs - 1].paddr >>
+                                HAL_ADDR_MSB_REG_SHIFT)) |
+                          FIELD_PREP(HAL_WBM_SCATTERED_DESC_HEAD_P_OFFSET_IX1,
+                                     (end_offset >> 2)));
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG +
+                          HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX0,
+                          FIELD_PREP(BUFFER_ADDR_INFO0_ADDR,
+                                     sbuf[0].paddr));
+
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG +
+                          HAL_WBM_SCATTERED_DESC_PTR_TAIL_INFO_IX0,
+                          FIELD_PREP(BUFFER_ADDR_INFO0_ADDR,
+                                     sbuf[0].paddr));
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG +
+                          HAL_WBM_SCATTERED_DESC_PTR_TAIL_INFO_IX1,
+                          FIELD_PREP(
+                               HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32,
+                               ((u64)sbuf[0].paddr >> HAL_ADDR_MSB_REG_SHIFT)) |
+                          FIELD_PREP(HAL_WBM_SCATTERED_DESC_TAIL_P_OFFSET_IX1,
+                                     0));
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG +
+                          HAL_WBM_SCATTERED_DESC_PTR_HP_ADDR,
+                          2 * tot_link_desc);
+
+       /* Enable the SRNG */
+       ath11k_ahb_write32(ab,
+                          HAL_SEQ_WCSS_UMAC_WBM_REG +
+                          HAL_WBM_IDLE_LINK_RING_MISC_ADDR, 0x40);
+}
+
+int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
+                         int ring_num, int mac_id,
+                         struct hal_srng_params *params)
+{
+       struct ath11k_hal *hal = &ab->hal;
+       const struct hal_srng_config *srng_config = &hw_srng_config[type];
+       struct hal_srng *srng;
+       int ring_id;
+       u32 lmac_idx;
+       int i;
+       u32 reg_base;
+
+       ring_id = ath11k_hal_srng_get_ring_id(ab, type, ring_num, mac_id);
+       if (ring_id < 0)
+               return ring_id;
+
+       srng = &hal->srng_list[ring_id];
+
+       srng->ring_id = ring_id;
+       srng->ring_dir = srng_config->ring_dir;
+       srng->ring_base_paddr = params->ring_base_paddr;
+       srng->ring_base_vaddr = params->ring_base_vaddr;
+       srng->entry_size = srng_config->entry_size;
+       srng->num_entries = params->num_entries;
+       srng->ring_size = srng->entry_size * srng->num_entries;
+       srng->intr_batch_cntr_thres_entries =
+                               params->intr_batch_cntr_thres_entries;
+       srng->intr_timer_thres_us = params->intr_timer_thres_us;
+       srng->flags = params->flags;
+       spin_lock_init(&srng->lock);
+
+       for (i = 0; i < HAL_SRNG_NUM_REG_GRP; i++) {
+               srng->hwreg_base[i] = srng_config->reg_start[i] +
+                                     (ring_num * srng_config->reg_size[i]);
+       }
+
+       memset(srng->ring_base_vaddr, 0,
+              (srng->entry_size * srng->num_entries) << 2);
+
+       /* TODO: Add comments on these swap configurations */
+       if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+               srng->flags |= HAL_SRNG_FLAGS_MSI_SWAP | HAL_SRNG_FLAGS_DATA_TLV_SWAP |
+                              HAL_SRNG_FLAGS_RING_PTR_SWAP;
+
+       reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2];
+
+       if (srng->ring_dir == HAL_SRNG_DIR_SRC) {
+               srng->u.src_ring.hp = 0;
+               srng->u.src_ring.cached_tp = 0;
+               srng->u.src_ring.reap_hp = srng->ring_size - srng->entry_size;
+               srng->u.src_ring.tp_addr = (void *)(hal->rdp.vaddr + ring_id);
+               srng->u.src_ring.low_threshold = params->low_threshold *
+                                                srng->entry_size;
+               if (srng_config->lmac_ring) {
+                       lmac_idx = ring_id - HAL_SRNG_RING_ID_LMAC1_ID_START;
+                       srng->u.src_ring.hp_addr = (void *)(hal->wrp.vaddr +
+                                                  lmac_idx);
+                       srng->flags |= HAL_SRNG_FLAGS_LMAC_RING;
+               } else {
+                       srng->u.src_ring.hp_addr =
+                               (u32 *)((unsigned long)ab->mem + reg_base);
+               }
+       } else {
+               /* During initialization loop count in all the descriptors
+                * will be set to zero, and HW will set it to 1 on completing
+                * descriptor update in first loop, and increments it by 1 on
+                * subsequent loops (loop count wraps around after reaching
+                * 0xffff). The 'loop_cnt' in SW ring state is the expected
+                * loop count in descriptors updated by HW (to be processed
+                * by SW).
+                */
+               srng->u.dst_ring.loop_cnt = 1;
+               srng->u.dst_ring.tp = 0;
+               srng->u.dst_ring.cached_hp = 0;
+               srng->u.dst_ring.hp_addr = (void *)(hal->rdp.vaddr + ring_id);
+               if (srng_config->lmac_ring) {
+                       /* For LMAC rings, tail pointer updates will be done
+                        * through FW by writing to a shared memory location
+                        */
+                       lmac_idx = ring_id - HAL_SRNG_RING_ID_LMAC1_ID_START;
+                       srng->u.dst_ring.tp_addr = (void *)(hal->wrp.vaddr +
+                                                  lmac_idx);
+                       srng->flags |= HAL_SRNG_FLAGS_LMAC_RING;
+               } else {
+                       srng->u.dst_ring.tp_addr =
+                               (u32 *)((unsigned long)ab->mem + reg_base +
+                                       (HAL_REO1_RING_TP - HAL_REO1_RING_HP));
+               }
+       }
+
+       if (srng_config->lmac_ring)
+               return ring_id;
+
+       ath11k_hal_srng_hw_init(ab, srng);
+
+       if (type == HAL_CE_DST) {
+               srng->u.dst_ring.max_buffer_length = params->max_buffer_len;
+               ath11k_hal_ce_dst_setup(ab, srng, ring_num);
+       }
+
+       return ring_id;
+}
+
+int ath11k_hal_srng_init(struct ath11k_base *ab)
+{
+       struct ath11k_hal *hal = &ab->hal;
+       int ret;
+
+       memset(hal, 0, sizeof(*hal));
+
+       hal->srng_config = hw_srng_config;
+
+       ret = ath11k_hal_alloc_cont_rdp(ab);
+       if (ret)
+               goto err_hal;
+
+       ret = ath11k_hal_alloc_cont_wrp(ab);
+       if (ret)
+               goto err_free_cont_rdp;
+
+       return 0;
+
+err_free_cont_rdp:
+       ath11k_hal_free_cont_rdp(ab);
+
+err_hal:
+       return ret;
+}
+
+void ath11k_hal_srng_deinit(struct ath11k_base *ab)
+{
+       ath11k_hal_free_cont_rdp(ab);
+       ath11k_hal_free_cont_wrp(ab);
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_HAL_H
+#define ATH11K_HAL_H
+
+#include "hal_desc.h"
+#include "rx_desc.h"
+
+struct ath11k_base;
+
+#define HAL_LINK_DESC_SIZE                     (32 << 2)
+#define HAL_LINK_DESC_ALIGN                    128
+#define HAL_NUM_MPDUS_PER_LINK_DESC            6
+#define HAL_NUM_TX_MSDUS_PER_LINK_DESC         7
+#define HAL_NUM_RX_MSDUS_PER_LINK_DESC         6
+#define HAL_NUM_MPDU_LINKS_PER_QUEUE_DESC      12
+#define HAL_MAX_AVAIL_BLK_RES                  3
+
+#define HAL_RING_BASE_ALIGN    8
+
+#define HAL_WBM_IDLE_SCATTER_BUF_SIZE_MAX      32704
+/* TODO: Check with hw team on the supported scatter buf size */
+#define HAL_WBM_IDLE_SCATTER_NEXT_PTR_SIZE     8
+#define HAL_WBM_IDLE_SCATTER_BUF_SIZE (HAL_WBM_IDLE_SCATTER_BUF_SIZE_MAX - \
+                                      HAL_WBM_IDLE_SCATTER_NEXT_PTR_SIZE)
+
+#define HAL_DSCP_TID_MAP_TBL_NUM_ENTRIES_MAX   48
+#define HAL_DSCP_TID_TBL_SIZE                  24
+
+/* calculate the register address from bar0 of shadow register x */
+#define SHADOW_BASE_ADDRESS                    0x00003024
+#define SHADOW_NUM_REGISTERS                           36
+
+/* WCSS Relative address */
+#define HAL_SEQ_WCSS_UMAC_REO_REG              0x00a38000
+#define HAL_SEQ_WCSS_UMAC_TCL_REG              0x00a44000
+#define HAL_SEQ_WCSS_UMAC_CE0_SRC_REG          0x00a00000
+#define HAL_SEQ_WCSS_UMAC_CE0_DST_REG          0x00a01000
+#define HAL_SEQ_WCSS_UMAC_CE1_SRC_REG          0x00a02000
+#define HAL_SEQ_WCSS_UMAC_CE1_DST_REG          0x00a03000
+#define HAL_SEQ_WCSS_UMAC_WBM_REG              0x00a34000
+
+/* SW2TCL(x) R0 ring configuration address */
+#define HAL_TCL1_RING_CMN_CTRL_REG             0x00000014
+#define HAL_TCL1_RING_DSCP_TID_MAP             0x0000002c
+#define HAL_TCL1_RING_BASE_LSB                 0x00000510
+#define HAL_TCL1_RING_BASE_MSB                 0x00000514
+#define HAL_TCL1_RING_ID                       0x00000518
+#define HAL_TCL1_RING_MISC                     0x00000520
+#define HAL_TCL1_RING_TP_ADDR_LSB              0x0000052c
+#define HAL_TCL1_RING_TP_ADDR_MSB              0x00000530
+#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0   0x00000540
+#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1   0x00000544
+#define HAL_TCL1_RING_MSI1_BASE_LSB            0x00000558
+#define HAL_TCL1_RING_MSI1_BASE_MSB            0x0000055c
+#define HAL_TCL1_RING_MSI1_DATA                        0x00000560
+#define HAL_TCL2_RING_BASE_LSB                 0x00000568
+#define HAL_TCL_RING_BASE_LSB                  0x00000618
+
+#define HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET \
+               (HAL_TCL1_RING_MSI1_BASE_LSB - HAL_TCL1_RING_BASE_LSB)
+#define HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET \
+               (HAL_TCL1_RING_MSI1_BASE_MSB - HAL_TCL1_RING_BASE_LSB)
+#define HAL_TCL1_RING_MSI1_DATA_OFFSET \
+               (HAL_TCL1_RING_MSI1_DATA - HAL_TCL1_RING_BASE_LSB)
+#define HAL_TCL1_RING_BASE_MSB_OFFSET \
+               (HAL_TCL1_RING_BASE_MSB - HAL_TCL1_RING_BASE_LSB)
+#define HAL_TCL1_RING_ID_OFFSET \
+               (HAL_TCL1_RING_ID - HAL_TCL1_RING_BASE_LSB)
+#define HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET \
+               (HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0 - HAL_TCL1_RING_BASE_LSB)
+#define HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET \
+               (HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1 - HAL_TCL1_RING_BASE_LSB)
+#define HAL_TCL1_RING_TP_ADDR_LSB_OFFSET \
+               (HAL_TCL1_RING_TP_ADDR_LSB - HAL_TCL1_RING_BASE_LSB)
+#define HAL_TCL1_RING_TP_ADDR_MSB_OFFSET \
+               (HAL_TCL1_RING_TP_ADDR_MSB - HAL_TCL1_RING_BASE_LSB)
+#define HAL_TCL1_RING_MISC_OFFSET \
+               (HAL_TCL1_RING_MISC - HAL_TCL1_RING_BASE_LSB)
+
+/* SW2TCL(x) R2 ring pointers (head/tail) address */
+#define HAL_TCL1_RING_HP                       0x00002000
+#define HAL_TCL1_RING_TP                       0x00002004
+#define HAL_TCL2_RING_HP                       0x00002008
+#define HAL_TCL_RING_HP                                0x00002018
+
+#define HAL_TCL1_RING_TP_OFFSET \
+               (HAL_TCL1_RING_TP - HAL_TCL1_RING_HP)
+
+/* TCL STATUS ring address */
+#define HAL_TCL_STATUS_RING_BASE_LSB           0x00000720
+#define HAL_TCL_STATUS_RING_HP                 0x00002030
+
+/* REO2SW(x) R0 ring configuration address */
+#define HAL_REO1_GEN_ENABLE                    0x00000000
+#define HAL_REO1_DEST_RING_CTRL_IX_2           0x0000000c
+#define HAL_REO1_DEST_RING_CTRL_IX_3           0x00000010
+#define HAL_REO1_RING_BASE_LSB                 0x0000029c
+#define HAL_REO1_RING_BASE_MSB                 0x000002a0
+#define HAL_REO1_RING_ID                       0x000002a4
+#define HAL_REO1_RING_MISC                     0x000002ac
+#define HAL_REO1_RING_HP_ADDR_LSB              0x000002b0
+#define HAL_REO1_RING_HP_ADDR_MSB              0x000002b4
+#define HAL_REO1_RING_PRODUCER_INT_SETUP       0x000002c0
+#define HAL_REO1_RING_MSI1_BASE_LSB            0x000002e4
+#define HAL_REO1_RING_MSI1_BASE_MSB            0x000002e8
+#define HAL_REO1_RING_MSI1_DATA                        0x000002ec
+#define HAL_REO2_RING_BASE_LSB                 0x000002f4
+#define HAL_REO1_AGING_THRESH_IX_0             0x00000564
+#define HAL_REO1_AGING_THRESH_IX_1             0x00000568
+#define HAL_REO1_AGING_THRESH_IX_2             0x0000056c
+#define HAL_REO1_AGING_THRESH_IX_3             0x00000570
+
+#define HAL_REO1_RING_MSI1_BASE_LSB_OFFSET \
+               (HAL_REO1_RING_MSI1_BASE_LSB - HAL_REO1_RING_BASE_LSB)
+#define HAL_REO1_RING_MSI1_BASE_MSB_OFFSET \
+               (HAL_REO1_RING_MSI1_BASE_MSB - HAL_REO1_RING_BASE_LSB)
+#define HAL_REO1_RING_MSI1_DATA_OFFSET \
+               (HAL_REO1_RING_MSI1_DATA - HAL_REO1_RING_BASE_LSB)
+#define HAL_REO1_RING_BASE_MSB_OFFSET \
+               (HAL_REO1_RING_BASE_MSB - HAL_REO1_RING_BASE_LSB)
+#define HAL_REO1_RING_ID_OFFSET (HAL_REO1_RING_ID - HAL_REO1_RING_BASE_LSB)
+#define HAL_REO1_RING_PRODUCER_INT_SETUP_OFFSET \
+               (HAL_REO1_RING_PRODUCER_INT_SETUP - HAL_REO1_RING_BASE_LSB)
+#define HAL_REO1_RING_HP_ADDR_LSB_OFFSET \
+               (HAL_REO1_RING_HP_ADDR_LSB - HAL_REO1_RING_BASE_LSB)
+#define HAL_REO1_RING_HP_ADDR_MSB_OFFSET \
+               (HAL_REO1_RING_HP_ADDR_MSB - HAL_REO1_RING_BASE_LSB)
+#define HAL_REO1_RING_MISC_OFFSET (HAL_REO1_RING_MISC - HAL_REO1_RING_BASE_LSB)
+
+/* REO2SW(x) R2 ring pointers (head/tail) address */
+#define HAL_REO1_RING_HP                       0x00003038
+#define HAL_REO1_RING_TP                       0x0000303c
+#define HAL_REO2_RING_HP                       0x00003040
+
+#define HAL_REO1_RING_TP_OFFSET        (HAL_REO1_RING_TP - HAL_REO1_RING_HP)
+
+/* REO2TCL R0 ring configuration address */
+#define HAL_REO_TCL_RING_BASE_LSB              0x000003fc
+
+/* REO2TCL R2 ring pointer (head/tail) address */
+#define HAL_REO_TCL_RING_HP                    0x00003058
+
+/* REO CMD R0 address */
+#define HAL_REO_CMD_RING_BASE_LSB              0x00000194
+
+/* REO CMD R2 address */
+#define HAL_REO_CMD_HP                         0x00003020
+
+/* SW2REO R0 address */
+#define HAL_SW2REO_RING_BASE_LSB               0x000001ec
+
+/* SW2REO R2 address */
+#define HAL_SW2REO_RING_HP                     0x00003028
+
+/* CE ring R0 address */
+#define HAL_CE_DST_RING_BASE_LSB               0x00000000
+#define HAL_CE_DST_STATUS_RING_BASE_LSB                0x00000058
+#define HAL_CE_DST_RING_CTRL                   0x000000b0
+
+/* CE ring R2 address */
+#define HAL_CE_DST_RING_HP                     0x00000400
+#define HAL_CE_DST_STATUS_RING_HP              0x00000408
+
+/* REO status address */
+#define HAL_REO_STATUS_RING_BASE_LSB           0x00000504
+#define HAL_REO_STATUS_HP                      0x00003070
+
+/* WBM Idle R0 address */
+#define HAL_WBM_IDLE_LINK_RING_BASE_LSB                0x00000860
+#define HAL_WBM_IDLE_LINK_RING_MISC_ADDR       0x00000870
+#define HAL_WBM_R0_IDLE_LIST_CONTROL_ADDR      0x00000048
+#define HAL_WBM_R0_IDLE_LIST_SIZE_ADDR         0x0000004c
+#define HAL_WBM_SCATTERED_RING_BASE_LSB                0x00000058
+#define HAL_WBM_SCATTERED_RING_BASE_MSB                0x0000005c
+#define HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX0 0x00000068
+#define HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX1 0x0000006c
+#define HAL_WBM_SCATTERED_DESC_PTR_TAIL_INFO_IX0 0x00000078
+#define HAL_WBM_SCATTERED_DESC_PTR_TAIL_INFO_IX1 0x0000007c
+#define HAL_WBM_SCATTERED_DESC_PTR_HP_ADDR      0x00000084
+
+/* WBM Idle R2 address */
+#define HAL_WBM_IDLE_LINK_RING_HP              0x000030b0
+
+/* SW2WBM R0 release address */
+#define HAL_WBM_RELEASE_RING_BASE_LSB          0x000001d8
+
+/* SW2WBM R2 release address */
+#define HAL_WBM_RELEASE_RING_HP                        0x00003018
+
+/* WBM2SW R0 release address */
+#define HAL_WBM0_RELEASE_RING_BASE_LSB         0x00000910
+#define HAL_WBM1_RELEASE_RING_BASE_LSB         0x00000968
+
+/* WBM2SW R2 release address */
+#define HAL_WBM0_RELEASE_RING_HP               0x000030c0
+#define HAL_WBM1_RELEASE_RING_HP               0x000030c8
+
+/* TCL ring feild mask and offset */
+#define HAL_TCL1_RING_BASE_MSB_RING_SIZE               GENMASK(27, 8)
+#define HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB      GENMASK(7, 0)
+#define HAL_TCL1_RING_ID_ENTRY_SIZE                    GENMASK(7, 0)
+#define HAL_TCL1_RING_MISC_MSI_LOOPCNT_DISABLE         BIT(1)
+#define HAL_TCL1_RING_MISC_MSI_SWAP                    BIT(3)
+#define HAL_TCL1_RING_MISC_HOST_FW_SWAP                        BIT(4)
+#define HAL_TCL1_RING_MISC_DATA_TLV_SWAP               BIT(5)
+#define HAL_TCL1_RING_MISC_SRNG_ENABLE                 BIT(6)
+#define HAL_TCL1_RING_CONSR_INT_SETUP_IX0_INTR_TMR_THOLD   GENMASK(31, 16)
+#define HAL_TCL1_RING_CONSR_INT_SETUP_IX0_BATCH_COUNTER_THOLD GENMASK(14, 0)
+#define HAL_TCL1_RING_CONSR_INT_SETUP_IX1_LOW_THOLD    GENMASK(15, 0)
+#define HAL_TCL1_RING_MSI1_BASE_MSB_MSI1_ENABLE                BIT(8)
+#define HAL_TCL1_RING_MSI1_BASE_MSB_ADDR               GENMASK(7, 0)
+#define HAL_TCL1_RING_CMN_CTRL_DSCP_TID_MAP_PROG_EN    BIT(17)
+#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP               GENMASK(31, 0)
+#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP0              GENMASK(2, 0)
+#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP1              GENMASK(5, 3)
+#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP2              GENMASK(8, 6)
+#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP3              GENMASK(11, 9)
+#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP4              GENMASK(14, 12)
+#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP5              GENMASK(17, 15)
+#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP6              GENMASK(20, 18)
+#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP7              GENMASK(23, 21)
+
+/* REO ring feild mask and offset */
+#define HAL_REO1_RING_BASE_MSB_RING_SIZE               GENMASK(27, 8)
+#define HAL_REO1_RING_BASE_MSB_RING_BASE_ADDR_MSB      GENMASK(7, 0)
+#define HAL_REO1_RING_ID_RING_ID                       GENMASK(15, 8)
+#define HAL_REO1_RING_ID_ENTRY_SIZE                    GENMASK(7, 0)
+#define HAL_REO1_RING_MISC_MSI_SWAP                    BIT(3)
+#define HAL_REO1_RING_MISC_HOST_FW_SWAP                        BIT(4)
+#define HAL_REO1_RING_MISC_DATA_TLV_SWAP               BIT(5)
+#define HAL_REO1_RING_MISC_SRNG_ENABLE                 BIT(6)
+#define HAL_REO1_RING_PRDR_INT_SETUP_INTR_TMR_THOLD    GENMASK(31, 16)
+#define HAL_REO1_RING_PRDR_INT_SETUP_BATCH_COUNTER_THOLD GENMASK(14, 0)
+#define HAL_REO1_RING_MSI1_BASE_MSB_MSI1_ENABLE                BIT(8)
+#define HAL_REO1_RING_MSI1_BASE_MSB_ADDR               GENMASK(7, 0)
+#define HAL_REO1_GEN_ENABLE_FRAG_DST_RING              GENMASK(25, 23)
+#define HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE          BIT(2)
+#define HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE         BIT(3)
+
+/* CE ring bit field mask and shift */
+#define HAL_CE_DST_R0_DEST_CTRL_MAX_LEN                        GENMASK(15, 0)
+
+#define HAL_ADDR_LSB_REG_MASK                          0xffffffff
+
+#define HAL_ADDR_MSB_REG_SHIFT                         32
+
+/* WBM ring bit field mask and shift */
+#define HAL_WBM_LINK_DESC_IDLE_LIST_MODE               BIT(1)
+#define HAL_WBM_SCATTER_BUFFER_SIZE                    GENMASK(10, 2)
+#define HAL_WBM_SCATTER_RING_SIZE_OF_IDLE_LINK_DESC_LIST GENMASK(31, 16)
+#define HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32     GENMASK(7, 0)
+#define HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_MATCH_TAG GENMASK(31, 8)
+
+#define HAL_WBM_SCATTERED_DESC_HEAD_P_OFFSET_IX1       GENMASK(20, 8)
+#define HAL_WBM_SCATTERED_DESC_TAIL_P_OFFSET_IX1       GENMASK(20, 8)
+
+#define BASE_ADDR_MATCH_TAG_VAL 0x5
+
+#define HAL_REO_REO2SW1_RING_BASE_MSB_RING_SIZE                0x000fffff
+#define HAL_REO_REO2TCL_RING_BASE_MSB_RING_SIZE                0x000fffff
+#define HAL_REO_SW2REO_RING_BASE_MSB_RING_SIZE         0x0000ffff
+#define HAL_REO_CMD_RING_BASE_MSB_RING_SIZE            0x0000ffff
+#define HAL_REO_STATUS_RING_BASE_MSB_RING_SIZE         0x0000ffff
+#define HAL_SW2TCL1_RING_BASE_MSB_RING_SIZE            0x000fffff
+#define HAL_SW2TCL1_CMD_RING_BASE_MSB_RING_SIZE                0x000fffff
+#define HAL_TCL_STATUS_RING_BASE_MSB_RING_SIZE         0x0000ffff
+#define HAL_CE_SRC_RING_BASE_MSB_RING_SIZE             0x0000ffff
+#define HAL_CE_DST_RING_BASE_MSB_RING_SIZE             0x0000ffff
+#define HAL_CE_DST_STATUS_RING_BASE_MSB_RING_SIZE      0x0000ffff
+#define HAL_WBM_IDLE_LINK_RING_BASE_MSB_RING_SIZE      0x0000ffff
+#define HAL_SW2WBM_RELEASE_RING_BASE_MSB_RING_SIZE     0x0000ffff
+#define HAL_WBM2SW_RELEASE_RING_BASE_MSB_RING_SIZE     0x000fffff
+#define HAL_RXDMA_RING_MAX_SIZE                                0x0000ffff
+
+#define HAL_RX_DESC_SIZE (sizeof(struct hal_rx_desc))
+
+/* Add any other errors here and return them in
+ * ath11k_hal_rx_desc_get_err().
+ */
+
+enum hal_srng_ring_id {
+       HAL_SRNG_RING_ID_REO2SW1 = 0,
+       HAL_SRNG_RING_ID_REO2SW2,
+       HAL_SRNG_RING_ID_REO2SW3,
+       HAL_SRNG_RING_ID_REO2SW4,
+       HAL_SRNG_RING_ID_REO2TCL,
+       HAL_SRNG_RING_ID_SW2REO,
+
+       HAL_SRNG_RING_ID_REO_CMD = 8,
+       HAL_SRNG_RING_ID_REO_STATUS,
+
+       HAL_SRNG_RING_ID_SW2TCL1 = 16,
+       HAL_SRNG_RING_ID_SW2TCL2,
+       HAL_SRNG_RING_ID_SW2TCL3,
+       HAL_SRNG_RING_ID_SW2TCL4,
+
+       HAL_SRNG_RING_ID_SW2TCL_CMD = 24,
+       HAL_SRNG_RING_ID_TCL_STATUS,
+
+       HAL_SRNG_RING_ID_CE0_SRC = 32,
+       HAL_SRNG_RING_ID_CE1_SRC,
+       HAL_SRNG_RING_ID_CE2_SRC,
+       HAL_SRNG_RING_ID_CE3_SRC,
+       HAL_SRNG_RING_ID_CE4_SRC,
+       HAL_SRNG_RING_ID_CE5_SRC,
+       HAL_SRNG_RING_ID_CE6_SRC,
+       HAL_SRNG_RING_ID_CE7_SRC,
+       HAL_SRNG_RING_ID_CE8_SRC,
+       HAL_SRNG_RING_ID_CE9_SRC,
+       HAL_SRNG_RING_ID_CE10_SRC,
+       HAL_SRNG_RING_ID_CE11_SRC,
+
+       HAL_SRNG_RING_ID_CE0_DST = 56,
+       HAL_SRNG_RING_ID_CE1_DST,
+       HAL_SRNG_RING_ID_CE2_DST,
+       HAL_SRNG_RING_ID_CE3_DST,
+       HAL_SRNG_RING_ID_CE4_DST,
+       HAL_SRNG_RING_ID_CE5_DST,
+       HAL_SRNG_RING_ID_CE6_DST,
+       HAL_SRNG_RING_ID_CE7_DST,
+       HAL_SRNG_RING_ID_CE8_DST,
+       HAL_SRNG_RING_ID_CE9_DST,
+       HAL_SRNG_RING_ID_CE10_DST,
+       HAL_SRNG_RING_ID_CE11_DST,
+
+       HAL_SRNG_RING_ID_CE0_DST_STATUS = 80,
+       HAL_SRNG_RING_ID_CE1_DST_STATUS,
+       HAL_SRNG_RING_ID_CE2_DST_STATUS,
+       HAL_SRNG_RING_ID_CE3_DST_STATUS,
+       HAL_SRNG_RING_ID_CE4_DST_STATUS,
+       HAL_SRNG_RING_ID_CE5_DST_STATUS,
+       HAL_SRNG_RING_ID_CE6_DST_STATUS,
+       HAL_SRNG_RING_ID_CE7_DST_STATUS,
+       HAL_SRNG_RING_ID_CE8_DST_STATUS,
+       HAL_SRNG_RING_ID_CE9_DST_STATUS,
+       HAL_SRNG_RING_ID_CE10_DST_STATUS,
+       HAL_SRNG_RING_ID_CE11_DST_STATUS,
+
+       HAL_SRNG_RING_ID_WBM_IDLE_LINK = 104,
+       HAL_SRNG_RING_ID_WBM_SW_RELEASE,
+       HAL_SRNG_RING_ID_WBM2SW0_RELEASE,
+       HAL_SRNG_RING_ID_WBM2SW1_RELEASE,
+       HAL_SRNG_RING_ID_WBM2SW2_RELEASE,
+       HAL_SRNG_RING_ID_WBM2SW3_RELEASE,
+
+       HAL_SRNG_RING_ID_UMAC_ID_END = 127,
+       HAL_SRNG_RING_ID_LMAC1_ID_START,
+
+       HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF = HAL_SRNG_RING_ID_LMAC1_ID_START,
+       HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_BUF,
+       HAL_SRNG_RING_ID_WMAC1_SW2RXDMA2_BUF,
+       HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_STATBUF,
+       HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_STATBUF,
+       HAL_SRNG_RING_ID_WMAC1_RXDMA2SW0,
+       HAL_SRNG_RING_ID_WMAC1_RXDMA2SW1,
+       HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_DESC,
+       HAL_SRNG_RING_ID_RXDMA_DIR_BUF,
+
+       HAL_SRNG_RING_ID_LMAC1_ID_END = 143
+};
+
+/* SRNG registers are split into two groups R0 and R2 */
+#define HAL_SRNG_REG_GRP_R0    0
+#define HAL_SRNG_REG_GRP_R2    1
+#define HAL_SRNG_NUM_REG_GRP    2
+
+#define HAL_SRNG_NUM_LMACS      3
+#define HAL_SRNG_REO_EXCEPTION  HAL_SRNG_RING_ID_REO2SW1
+#define HAL_SRNG_RINGS_PER_LMAC (HAL_SRNG_RING_ID_LMAC1_ID_END - \
+                                HAL_SRNG_RING_ID_LMAC1_ID_START)
+#define HAL_SRNG_NUM_LMAC_RINGS (HAL_SRNG_NUM_LMACS * HAL_SRNG_RINGS_PER_LMAC)
+#define HAL_SRNG_RING_ID_MAX    (HAL_SRNG_RING_ID_UMAC_ID_END + \
+                                HAL_SRNG_NUM_LMAC_RINGS)
+
+enum hal_ring_type {
+       HAL_REO_DST,
+       HAL_REO_EXCEPTION,
+       HAL_REO_REINJECT,
+       HAL_REO_CMD,
+       HAL_REO_STATUS,
+       HAL_TCL_DATA,
+       HAL_TCL_CMD,
+       HAL_TCL_STATUS,
+       HAL_CE_SRC,
+       HAL_CE_DST,
+       HAL_CE_DST_STATUS,
+       HAL_WBM_IDLE_LINK,
+       HAL_SW2WBM_RELEASE,
+       HAL_WBM2SW_RELEASE,
+       HAL_RXDMA_BUF,
+       HAL_RXDMA_DST,
+       HAL_RXDMA_MONITOR_BUF,
+       HAL_RXDMA_MONITOR_STATUS,
+       HAL_RXDMA_MONITOR_DST,
+       HAL_RXDMA_MONITOR_DESC,
+       HAL_RXDMA_DIR_BUF,
+       HAL_MAX_RING_TYPES,
+};
+
+#define HAL_RX_MAX_BA_WINDOW   256
+
+#define HAL_DEFAULT_REO_TIMEOUT_USEC           (40 * 1000)
+
+/**
+ * enum hal_reo_cmd_type: Enum for REO command type
+ * @CMD_GET_QUEUE_STATS: Get REO queue status/stats
+ * @CMD_FLUSH_QUEUE: Flush all frames in REO queue
+ * @CMD_FLUSH_CACHE: Flush descriptor entries in the cache
+ * @CMD_UNBLOCK_CACHE: Unblock a descriptor's address that was blocked
+ *      earlier with a 'REO_FLUSH_CACHE' command
+ * @CMD_FLUSH_TIMEOUT_LIST: Flush buffers/descriptors from timeout list
+ * @CMD_UPDATE_RX_REO_QUEUE: Update REO queue settings
+ */
+enum hal_reo_cmd_type {
+       HAL_REO_CMD_GET_QUEUE_STATS     = 0,
+       HAL_REO_CMD_FLUSH_QUEUE         = 1,
+       HAL_REO_CMD_FLUSH_CACHE         = 2,
+       HAL_REO_CMD_UNBLOCK_CACHE       = 3,
+       HAL_REO_CMD_FLUSH_TIMEOUT_LIST  = 4,
+       HAL_REO_CMD_UPDATE_RX_QUEUE     = 5,
+};
+
+/**
+ * enum hal_reo_cmd_status: Enum for execution status of REO command
+ * @HAL_REO_CMD_SUCCESS: Command has successfully executed
+ * @HAL_REO_CMD_BLOCKED: Command could not be executed as the queue
+ *                      or cache was blocked
+ * @HAL_REO_CMD_FAILED: Command execution failed, could be due to
+ *                     invalid queue desc
+ * @HAL_REO_CMD_RESOURCE_BLOCKED:
+ * @HAL_REO_CMD_DRAIN:
+ */
+enum hal_reo_cmd_status {
+       HAL_REO_CMD_SUCCESS             = 0,
+       HAL_REO_CMD_BLOCKED             = 1,
+       HAL_REO_CMD_FAILED              = 2,
+       HAL_REO_CMD_RESOURCE_BLOCKED    = 3,
+       HAL_REO_CMD_DRAIN               = 0xff,
+};
+
+struct hal_wbm_idle_scatter_list {
+       dma_addr_t paddr;
+       struct hal_wbm_link_desc *vaddr;
+};
+
+struct hal_srng_params {
+       dma_addr_t ring_base_paddr;
+       u32 *ring_base_vaddr;
+       int num_entries;
+       u32 intr_batch_cntr_thres_entries;
+       u32 intr_timer_thres_us;
+       u32 flags;
+       u32 max_buffer_len;
+       u32 low_threshold;
+
+       /* Add more params as needed */
+};
+
+enum hal_srng_dir {
+       HAL_SRNG_DIR_SRC,
+       HAL_SRNG_DIR_DST
+};
+
+/* srng flags */
+#define HAL_SRNG_FLAGS_MSI_SWAP                        0x00000008
+#define HAL_SRNG_FLAGS_RING_PTR_SWAP           0x00000010
+#define HAL_SRNG_FLAGS_DATA_TLV_SWAP           0x00000020
+#define HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN      0x00010000
+#define HAL_SRNG_FLAGS_MSI_INTR                        0x00020000
+#define HAL_SRNG_FLAGS_LMAC_RING               0x80000000
+
+#define HAL_SRNG_TLV_HDR_TAG           GENMASK(9, 1)
+#define HAL_SRNG_TLV_HDR_LEN           GENMASK(25, 10)
+
+/* Common SRNG ring structure for source and destination rings */
+struct hal_srng {
+       /* Unique SRNG ring ID */
+       u8 ring_id;
+
+       /* Ring initialization done */
+       u8 initialized;
+
+       /* Interrupt/MSI value assigned to this ring */
+       int irq;
+
+       /* Physical base address of the ring */
+       dma_addr_t ring_base_paddr;
+
+       /* Virtual base address of the ring */
+       u32 *ring_base_vaddr;
+
+       /* Number of entries in ring */
+       u32 num_entries;
+
+       /* Ring size */
+       u32 ring_size;
+
+       /* Ring size mask */
+       u32 ring_size_mask;
+
+       /* Size of ring entry */
+       u32 entry_size;
+
+       /* Interrupt timer threshold - in micro seconds */
+       u32 intr_timer_thres_us;
+
+       /* Interrupt batch counter threshold - in number of ring entries */
+       u32 intr_batch_cntr_thres_entries;
+
+       /* MSI Address */
+       dma_addr_t msi_addr;
+
+       /* MSI data */
+       u32 msi_data;
+
+       /* Misc flags */
+       u32 flags;
+
+       /* Lock for serializing ring index updates */
+       spinlock_t lock;
+
+       /* Start offset of SRNG register groups for this ring
+        * TBD: See if this is required - register address can be derived
+        * from ring ID
+        */
+       u32 hwreg_base[HAL_SRNG_NUM_REG_GRP];
+
+       /* Source or Destination ring */
+       enum hal_srng_dir ring_dir;
+
+       union {
+               struct {
+                       /* SW tail pointer */
+                       u32 tp;
+
+                       /* Shadow head pointer location to be updated by HW */
+                       volatile u32 *hp_addr;
+
+                       /* Cached head pointer */
+                       u32 cached_hp;
+
+                       /* Tail pointer location to be updated by SW - This
+                        * will be a register address and need not be
+                        * accessed through SW structure
+                        */
+                       u32 *tp_addr;
+
+                       /* Current SW loop cnt */
+                       u32 loop_cnt;
+
+                       /* max transfer size */
+                       u16 max_buffer_length;
+               } dst_ring;
+
+               struct {
+                       /* SW head pointer */
+                       u32 hp;
+
+                       /* SW reap head pointer */
+                       u32 reap_hp;
+
+                       /* Shadow tail pointer location to be updated by HW */
+                       u32 *tp_addr;
+
+                       /* Cached tail pointer */
+                       u32 cached_tp;
+
+                       /* Head pointer location to be updated by SW - This
+                        * will be a register address and need not be accessed
+                        * through SW structure
+                        */
+                       u32 *hp_addr;
+
+                       /* Low threshold - in number of ring entries */
+                       u32 low_threshold;
+               } src_ring;
+       } u;
+};
+
+/* Interrupt mitigation - Batch threshold in terms of numer of frames */
+#define HAL_SRNG_INT_BATCH_THRESHOLD_TX 256
+#define HAL_SRNG_INT_BATCH_THRESHOLD_RX 128
+#define HAL_SRNG_INT_BATCH_THRESHOLD_OTHER 1
+
+/* Interrupt mitigation - timer threshold in us */
+#define HAL_SRNG_INT_TIMER_THRESHOLD_TX 1000
+#define HAL_SRNG_INT_TIMER_THRESHOLD_RX 500
+#define HAL_SRNG_INT_TIMER_THRESHOLD_OTHER 1000
+
+/* HW SRNG configuration table */
+struct hal_srng_config {
+       int start_ring_id;
+       u16 max_rings;
+       u16 entry_size;
+       u32 reg_start[HAL_SRNG_NUM_REG_GRP];
+       u16 reg_size[HAL_SRNG_NUM_REG_GRP];
+       u8 lmac_ring;
+       enum hal_srng_dir ring_dir;
+       u32 max_size;
+};
+
+/**
+ * enum hal_rx_buf_return_buf_manager
+ *
+ * @HAL_RX_BUF_RBM_WBM_IDLE_BUF_LIST: Buffer returned to WBM idle buffer list
+ * @HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST: Descriptor returned to WBM idle
+ *     descriptor list.
+ * @HAL_RX_BUF_RBM_FW_BM: Buffer returned to FW
+ * @HAL_RX_BUF_RBM_SW0_BM: For Tx completion -- returned to host
+ * @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
+ */
+
+enum hal_rx_buf_return_buf_manager {
+       HAL_RX_BUF_RBM_WBM_IDLE_BUF_LIST,
+       HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST,
+       HAL_RX_BUF_RBM_FW_BM,
+       HAL_RX_BUF_RBM_SW0_BM,
+       HAL_RX_BUF_RBM_SW1_BM,
+       HAL_RX_BUF_RBM_SW2_BM,
+       HAL_RX_BUF_RBM_SW3_BM,
+};
+
+#define HAL_SRNG_DESC_LOOP_CNT         0xf0000000
+
+#define HAL_REO_CMD_FLG_NEED_STATUS            BIT(0)
+#define HAL_REO_CMD_FLG_STATS_CLEAR            BIT(1)
+#define HAL_REO_CMD_FLG_FLUSH_BLOCK_LATER      BIT(2)
+#define HAL_REO_CMD_FLG_FLUSH_RELEASE_BLOCKING BIT(3)
+#define HAL_REO_CMD_FLG_FLUSH_NO_INVAL         BIT(4)
+#define HAL_REO_CMD_FLG_FLUSH_FWD_ALL_MPDUS    BIT(5)
+#define HAL_REO_CMD_FLG_FLUSH_ALL              BIT(6)
+#define HAL_REO_CMD_FLG_UNBLK_RESOURCE         BIT(7)
+#define HAL_REO_CMD_FLG_UNBLK_CACHE            BIT(8)
+
+/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO0_UPD_* feilds */
+#define HAL_REO_CMD_UPD0_RX_QUEUE_NUM          BIT(8)
+#define HAL_REO_CMD_UPD0_VLD                   BIT(9)
+#define HAL_REO_CMD_UPD0_ALDC                  BIT(10)
+#define HAL_REO_CMD_UPD0_DIS_DUP_DETECTION     BIT(11)
+#define HAL_REO_CMD_UPD0_SOFT_REORDER_EN       BIT(12)
+#define HAL_REO_CMD_UPD0_AC                    BIT(13)
+#define HAL_REO_CMD_UPD0_BAR                   BIT(14)
+#define HAL_REO_CMD_UPD0_RETRY                 BIT(15)
+#define HAL_REO_CMD_UPD0_CHECK_2K_MODE         BIT(16)
+#define HAL_REO_CMD_UPD0_OOR_MODE              BIT(17)
+#define HAL_REO_CMD_UPD0_BA_WINDOW_SIZE                BIT(18)
+#define HAL_REO_CMD_UPD0_PN_CHECK              BIT(19)
+#define HAL_REO_CMD_UPD0_EVEN_PN               BIT(20)
+#define HAL_REO_CMD_UPD0_UNEVEN_PN             BIT(21)
+#define HAL_REO_CMD_UPD0_PN_HANDLE_ENABLE      BIT(22)
+#define HAL_REO_CMD_UPD0_PN_SIZE               BIT(23)
+#define HAL_REO_CMD_UPD0_IGNORE_AMPDU_FLG      BIT(24)
+#define HAL_REO_CMD_UPD0_SVLD                  BIT(25)
+#define HAL_REO_CMD_UPD0_SSN                   BIT(26)
+#define HAL_REO_CMD_UPD0_SEQ_2K_ERR            BIT(27)
+#define HAL_REO_CMD_UPD0_PN_ERR                        BIT(28)
+#define HAL_REO_CMD_UPD0_PN_VALID              BIT(29)
+#define HAL_REO_CMD_UPD0_PN                    BIT(30)
+
+/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO1_* feilds */
+#define HAL_REO_CMD_UPD1_VLD                   BIT(16)
+#define HAL_REO_CMD_UPD1_ALDC                  GENMASK(18, 17)
+#define HAL_REO_CMD_UPD1_DIS_DUP_DETECTION     BIT(19)
+#define HAL_REO_CMD_UPD1_SOFT_REORDER_EN       BIT(20)
+#define HAL_REO_CMD_UPD1_AC                    GENMASK(22, 21)
+#define HAL_REO_CMD_UPD1_BAR                   BIT(23)
+#define HAL_REO_CMD_UPD1_RETRY                 BIT(24)
+#define HAL_REO_CMD_UPD1_CHECK_2K_MODE         BIT(25)
+#define HAL_REO_CMD_UPD1_OOR_MODE              BIT(26)
+#define HAL_REO_CMD_UPD1_PN_CHECK              BIT(27)
+#define HAL_REO_CMD_UPD1_EVEN_PN               BIT(28)
+#define HAL_REO_CMD_UPD1_UNEVEN_PN             BIT(29)
+#define HAL_REO_CMD_UPD1_PN_HANDLE_ENABLE      BIT(30)
+#define HAL_REO_CMD_UPD1_IGNORE_AMPDU_FLG      BIT(31)
+
+/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO2_* feilds */
+#define HAL_REO_CMD_UPD2_SVLD                  BIT(10)
+#define HAL_REO_CMD_UPD2_SSN                   GENMASK(22, 11)
+#define HAL_REO_CMD_UPD2_SEQ_2K_ERR            BIT(23)
+#define HAL_REO_CMD_UPD2_PN_ERR                        BIT(24)
+
+#define HAL_REO_DEST_RING_CTRL_HASH_RING_MAP   GENMASK(31, 8)
+
+struct ath11k_hal_reo_cmd {
+       u32 addr_lo;
+       u32 flag;
+       u32 upd0;
+       u32 upd1;
+       u32 upd2;
+       u32 pn[4];
+       u16 rx_queue_num;
+       u16 min_rel;
+       u16 min_fwd;
+       u8 addr_hi;
+       u8 ac_list;
+       u8 blocking_idx;
+       u16 ba_window_size;
+       u8 pn_size;
+};
+
+enum hal_pn_type {
+       HAL_PN_TYPE_NONE,
+       HAL_PN_TYPE_WPA,
+       HAL_PN_TYPE_WAPI_EVEN,
+       HAL_PN_TYPE_WAPI_UNEVEN,
+};
+
+enum hal_ce_desc {
+       HAL_CE_DESC_SRC,
+       HAL_CE_DESC_DST,
+       HAL_CE_DESC_DST_STATUS,
+};
+
+struct hal_reo_status_header {
+       u16 cmd_num;
+       enum hal_reo_cmd_status cmd_status;
+       u16 cmd_exe_time;
+       u32 timestamp;
+};
+
+struct hal_reo_status_queue_stats {
+       u16 ssn;
+       u16 curr_idx;
+       u32 pn[4];
+       u32 last_rx_queue_ts;
+       u32 last_rx_dequeue_ts;
+       u32 rx_bitmap[8]; /* Bitmap from 0-255 */
+       u32 curr_mpdu_cnt;
+       u32 curr_msdu_cnt;
+       u16 fwd_due_to_bar_cnt;
+       u16 dup_cnt;
+       u32 frames_in_order_cnt;
+       u32 num_mpdu_processed_cnt;
+       u32 num_msdu_processed_cnt;
+       u32 total_num_processed_byte_cnt;
+       u32 late_rx_mpdu_cnt;
+       u32 reorder_hole_cnt;
+       u8 timeout_cnt;
+       u8 bar_rx_cnt;
+       u8 num_window_2k_jump_cnt;
+};
+
+struct hal_reo_status_flush_queue {
+       bool err_detected;
+};
+
+enum hal_reo_status_flush_cache_err_code {
+       HAL_REO_STATUS_FLUSH_CACHE_ERR_CODE_SUCCESS,
+       HAL_REO_STATUS_FLUSH_CACHE_ERR_CODE_IN_USE,
+       HAL_REO_STATUS_FLUSH_CACHE_ERR_CODE_NOT_FOUND,
+};
+
+struct hal_reo_status_flush_cache {
+       bool err_detected;
+       enum hal_reo_status_flush_cache_err_code err_code;
+       bool cache_controller_flush_status_hit;
+       u8 cache_controller_flush_status_desc_type;
+       u8 cache_controller_flush_status_client_id;
+       u8 cache_controller_flush_status_err;
+       u8 cache_controller_flush_status_cnt;
+};
+
+enum hal_reo_status_unblock_cache_type {
+       HAL_REO_STATUS_UNBLOCK_BLOCKING_RESOURCE,
+       HAL_REO_STATUS_UNBLOCK_ENTIRE_CACHE_USAGE,
+};
+
+struct hal_reo_status_unblock_cache {
+       bool err_detected;
+       enum hal_reo_status_unblock_cache_type unblock_type;
+};
+
+struct hal_reo_status_flush_timeout_list {
+       bool err_detected;
+       bool list_empty;
+       u16 release_desc_cnt;
+       u16 fwd_buf_cnt;
+};
+
+enum hal_reo_threshold_idx {
+       HAL_REO_THRESHOLD_IDX_DESC_COUNTER0,
+       HAL_REO_THRESHOLD_IDX_DESC_COUNTER1,
+       HAL_REO_THRESHOLD_IDX_DESC_COUNTER2,
+       HAL_REO_THRESHOLD_IDX_DESC_COUNTER_SUM,
+};
+
+struct hal_reo_status_desc_thresh_reached {
+       enum hal_reo_threshold_idx threshold_idx;
+       u32 link_desc_counter0;
+       u32 link_desc_counter1;
+       u32 link_desc_counter2;
+       u32 link_desc_counter_sum;
+};
+
+struct hal_reo_status {
+       struct hal_reo_status_header uniform_hdr;
+       u8 loop_cnt;
+       union {
+               struct hal_reo_status_queue_stats queue_stats;
+               struct hal_reo_status_flush_queue flush_queue;
+               struct hal_reo_status_flush_cache flush_cache;
+               struct hal_reo_status_unblock_cache unblock_cache;
+               struct hal_reo_status_flush_timeout_list timeout_list;
+               struct hal_reo_status_desc_thresh_reached desc_thresh_reached;
+       } u;
+};
+
+/**
+ * HAL context to be used to access SRNG APIs (currently used by data path
+ * and transport (CE) modules)
+ */
+struct ath11k_hal {
+       /* HAL internal state for all SRNG rings.
+        */
+       struct hal_srng srng_list[HAL_SRNG_RING_ID_MAX];
+
+       /* SRNG configuration table */
+       const struct hal_srng_config *srng_config;
+
+       /* Remote pointer memory for HW/FW updates */
+       struct {
+               u32 *vaddr;
+               dma_addr_t paddr;
+       } rdp;
+
+       /* Shared memory for ring pointer updates from host to FW */
+       struct {
+               u32 *vaddr;
+               dma_addr_t paddr;
+       } wrp;
+
+       /* Available REO blocking resources bitmap */
+       u8 avail_blk_resource;
+
+       u8 current_blk_index;
+
+       /* shadow register configuration */
+       u32 shadow_reg_addr[SHADOW_NUM_REGISTERS];
+       int num_shadow_reg_configured;
+};
+
+u32 ath11k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid);
+void ath11k_hal_reo_qdesc_setup(void *vaddr, int tid, u32 ba_window_size,
+                               u32 start_seqtype);
+void ath11k_hal_reo_init_cmd_ring(struct ath11k_base *ab,
+                                 struct hal_srng *srng);
+void ath11k_hal_reo_hw_setup(struct ath11k_base *ab);
+void ath11k_hal_setup_link_idle_list(struct ath11k_base *ab,
+                                    struct hal_wbm_idle_scatter_list *sbuf,
+                                    u32 nsbufs, u32 tot_link_desc,
+                                    u32 end_offset);
+
+dma_addr_t ath11k_hal_srng_get_tp_addr(struct ath11k_base *ab,
+                                      struct hal_srng *srng);
+dma_addr_t ath11k_hal_srng_get_hp_addr(struct ath11k_base *ab,
+                                      struct hal_srng *srng);
+void ath11k_hal_set_link_desc_addr(struct hal_wbm_link_desc *desc, u32 cookie,
+                                  dma_addr_t paddr);
+u32 ath11k_hal_ce_get_desc_size(enum hal_ce_desc type);
+void ath11k_hal_ce_src_set_desc(void *buf, dma_addr_t paddr, u32 len, u32 id,
+                               u8 byte_swap_data);
+void ath11k_hal_ce_dst_set_desc(void *buf, dma_addr_t paddr);
+u32 ath11k_hal_ce_dst_status_get_length(void *buf);
+int ath11k_hal_srng_get_entrysize(u32 ring_type);
+int ath11k_hal_srng_get_max_entries(u32 ring_type);
+void ath11k_hal_srng_get_params(struct ath11k_base *ab, struct hal_srng *srng,
+                               struct hal_srng_params *params);
+u32 *ath11k_hal_srng_dst_get_next_entry(struct ath11k_base *ab,
+                                       struct hal_srng *srng);
+u32 *ath11k_hal_srng_dst_peek(struct ath11k_base *ab, struct hal_srng *srng);
+int ath11k_hal_srng_dst_num_free(struct ath11k_base *ab, struct hal_srng *srng,
+                                bool sync_hw_ptr);
+u32 *ath11k_hal_srng_src_peek(struct ath11k_base *ab, struct hal_srng *srng);
+u32 *ath11k_hal_srng_src_get_next_reaped(struct ath11k_base *ab,
+                                        struct hal_srng *srng);
+u32 *ath11k_hal_srng_src_reap_next(struct ath11k_base *ab,
+                                  struct hal_srng *srng);
+u32 *ath11k_hal_srng_src_get_next_entry(struct ath11k_base *ab,
+                                       struct hal_srng *srng);
+int ath11k_hal_srng_src_num_free(struct ath11k_base *ab, struct hal_srng *srng,
+                                bool sync_hw_ptr);
+void ath11k_hal_srng_access_begin(struct ath11k_base *ab,
+                                 struct hal_srng *srng);
+void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng);
+int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type,
+                         int ring_num, int mac_id,
+                         struct hal_srng_params *params);
+int ath11k_hal_srng_init(struct ath11k_base *ath11k);
+void ath11k_hal_srng_deinit(struct ath11k_base *ath11k);
+
+#endif
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+#ifndef ATH11K_HAL_DESC_H
+#define ATH11K_HAL_DESC_H
+
+#define BUFFER_ADDR_INFO0_ADDR         GENMASK(31, 0)
+
+#define BUFFER_ADDR_INFO1_ADDR         GENMASK(7, 0)
+#define BUFFER_ADDR_INFO1_RET_BUF_MGR  GENMASK(10, 8)
+#define BUFFER_ADDR_INFO1_SW_COOKIE    GENMASK(31, 11)
+
+struct ath11k_buffer_addr {
+       u32 info0;
+       u32 info1;
+} __packed;
+
+/* ath11k_buffer_addr
+ *
+ * info0
+ *             Address (lower 32 bits) of the msdu buffer or msdu extension
+ *             descriptor or Link descriptor
+ *
+ * addr
+ *             Address (upper 8 bits) of the msdu buffer or msdu extension
+ *             descriptor or Link descriptor
+ *
+ * return_buffer_manager (RBM)
+ *             Consumer: WBM
+ *             Producer: SW/FW
+ *             Indicates to which buffer manager the buffer or MSDU_EXTENSION
+ *             descriptor or link descriptor that is being pointed to shall be
+ *             returned after the frame has been processed. It is used by WBM
+ *             for routing purposes.
+ *
+ *             Values are defined in enum %HAL_RX_BUF_RBM_
+ *
+ * sw_buffer_cookie
+ *             Cookie field exclusively used by SW. HW ignores the contents,
+ *             accept that it passes the programmed value on to other
+ *             descriptors together with the physical address.
+ *
+ *             Field can be used by SW to for example associate the buffers
+ *             physical address with the virtual address.
+ */
+
+enum hal_tlv_tag {
+       HAL_MACTX_CBF_START                    =   0 /* 0x0 */,
+       HAL_PHYRX_DATA                         =   1 /* 0x1 */,
+       HAL_PHYRX_CBF_DATA_RESP                =   2 /* 0x2 */,
+       HAL_PHYRX_ABORT_REQUEST                =   3 /* 0x3 */,
+       HAL_PHYRX_USER_ABORT_NOTIFICATION      =   4 /* 0x4 */,
+       HAL_MACTX_DATA_RESP                    =   5 /* 0x5 */,
+       HAL_MACTX_CBF_DATA                     =   6 /* 0x6 */,
+       HAL_MACTX_CBF_DONE                     =   7 /* 0x7 */,
+       HAL_MACRX_CBF_READ_REQUEST             =   8 /* 0x8 */,
+       HAL_MACRX_CBF_DATA_REQUEST             =   9 /* 0x9 */,
+       HAL_MACRX_EXPECT_NDP_RECEPTION         =  10 /* 0xa */,
+       HAL_MACRX_FREEZE_CAPTURE_CHANNEL       =  11 /* 0xb */,
+       HAL_MACRX_NDP_TIMEOUT                  =  12 /* 0xc */,
+       HAL_MACRX_ABORT_ACK                    =  13 /* 0xd */,
+       HAL_MACRX_REQ_IMPLICIT_FB              =  14 /* 0xe */,
+       HAL_MACRX_CHAIN_MASK                   =  15 /* 0xf */,
+       HAL_MACRX_NAP_USER                     =  16 /* 0x10 */,
+       HAL_MACRX_ABORT_REQUEST                =  17 /* 0x11 */,
+       HAL_PHYTX_OTHER_TRANSMIT_INFO16        =  18 /* 0x12 */,
+       HAL_PHYTX_ABORT_ACK                    =  19 /* 0x13 */,
+       HAL_PHYTX_ABORT_REQUEST                =  20 /* 0x14 */,
+       HAL_PHYTX_PKT_END                      =  21 /* 0x15 */,
+       HAL_PHYTX_PPDU_HEADER_INFO_REQUEST     =  22 /* 0x16 */,
+       HAL_PHYTX_REQUEST_CTRL_INFO            =  23 /* 0x17 */,
+       HAL_PHYTX_DATA_REQUEST                 =  24 /* 0x18 */,
+       HAL_PHYTX_BF_CV_LOADING_DONE           =  25 /* 0x19 */,
+       HAL_PHYTX_NAP_ACK                      =  26 /* 0x1a */,
+       HAL_PHYTX_NAP_DONE                     =  27 /* 0x1b */,
+       HAL_PHYTX_OFF_ACK                      =  28 /* 0x1c */,
+       HAL_PHYTX_ON_ACK                       =  29 /* 0x1d */,
+       HAL_PHYTX_SYNTH_OFF_ACK                =  30 /* 0x1e */,
+       HAL_PHYTX_DEBUG16                      =  31 /* 0x1f */,
+       HAL_MACTX_ABORT_REQUEST                =  32 /* 0x20 */,
+       HAL_MACTX_ABORT_ACK                    =  33 /* 0x21 */,
+       HAL_MACTX_PKT_END                      =  34 /* 0x22 */,
+       HAL_MACTX_PRE_PHY_DESC                 =  35 /* 0x23 */,
+       HAL_MACTX_BF_PARAMS_COMMON             =  36 /* 0x24 */,
+       HAL_MACTX_BF_PARAMS_PER_USER           =  37 /* 0x25 */,
+       HAL_MACTX_PREFETCH_CV                  =  38 /* 0x26 */,
+       HAL_MACTX_USER_DESC_COMMON             =  39 /* 0x27 */,
+       HAL_MACTX_USER_DESC_PER_USER           =  40 /* 0x28 */,
+       HAL_EXAMPLE_USER_TLV_16                =  41 /* 0x29 */,
+       HAL_EXAMPLE_TLV_16                     =  42 /* 0x2a */,
+       HAL_MACTX_PHY_OFF                      =  43 /* 0x2b */,
+       HAL_MACTX_PHY_ON                       =  44 /* 0x2c */,
+       HAL_MACTX_SYNTH_OFF                    =  45 /* 0x2d */,
+       HAL_MACTX_EXPECT_CBF_COMMON            =  46 /* 0x2e */,
+       HAL_MACTX_EXPECT_CBF_PER_USER          =  47 /* 0x2f */,
+       HAL_MACTX_PHY_DESC                     =  48 /* 0x30 */,
+       HAL_MACTX_L_SIG_A                      =  49 /* 0x31 */,
+       HAL_MACTX_L_SIG_B                      =  50 /* 0x32 */,
+       HAL_MACTX_HT_SIG                       =  51 /* 0x33 */,
+       HAL_MACTX_VHT_SIG_A                    =  52 /* 0x34 */,
+       HAL_MACTX_VHT_SIG_B_SU20               =  53 /* 0x35 */,
+       HAL_MACTX_VHT_SIG_B_SU40               =  54 /* 0x36 */,
+       HAL_MACTX_VHT_SIG_B_SU80               =  55 /* 0x37 */,
+       HAL_MACTX_VHT_SIG_B_SU160              =  56 /* 0x38 */,
+       HAL_MACTX_VHT_SIG_B_MU20               =  57 /* 0x39 */,
+       HAL_MACTX_VHT_SIG_B_MU40               =  58 /* 0x3a */,
+       HAL_MACTX_VHT_SIG_B_MU80               =  59 /* 0x3b */,
+       HAL_MACTX_VHT_SIG_B_MU160              =  60 /* 0x3c */,
+       HAL_MACTX_SERVICE                      =  61 /* 0x3d */,
+       HAL_MACTX_HE_SIG_A_SU                  =  62 /* 0x3e */,
+       HAL_MACTX_HE_SIG_A_MU_DL               =  63 /* 0x3f */,
+       HAL_MACTX_HE_SIG_A_MU_UL               =  64 /* 0x40 */,
+       HAL_MACTX_HE_SIG_B1_MU                 =  65 /* 0x41 */,
+       HAL_MACTX_HE_SIG_B2_MU                 =  66 /* 0x42 */,
+       HAL_MACTX_HE_SIG_B2_OFDMA              =  67 /* 0x43 */,
+       HAL_MACTX_DELETE_CV                    =  68 /* 0x44 */,
+       HAL_MACTX_MU_UPLINK_COMMON             =  69 /* 0x45 */,
+       HAL_MACTX_MU_UPLINK_USER_SETUP         =  70 /* 0x46 */,
+       HAL_MACTX_OTHER_TRANSMIT_INFO          =  71 /* 0x47 */,
+       HAL_MACTX_PHY_NAP                      =  72 /* 0x48 */,
+       HAL_MACTX_DEBUG                        =  73 /* 0x49 */,
+       HAL_PHYRX_ABORT_ACK                    =  74 /* 0x4a */,
+       HAL_PHYRX_GENERATED_CBF_DETAILS        =  75 /* 0x4b */,
+       HAL_PHYRX_RSSI_LEGACY                  =  76 /* 0x4c */,
+       HAL_PHYRX_RSSI_HT                      =  77 /* 0x4d */,
+       HAL_PHYRX_USER_INFO                    =  78 /* 0x4e */,
+       HAL_PHYRX_PKT_END                      =  79 /* 0x4f */,
+       HAL_PHYRX_DEBUG                        =  80 /* 0x50 */,
+       HAL_PHYRX_CBF_TRANSFER_DONE            =  81 /* 0x51 */,
+       HAL_PHYRX_CBF_TRANSFER_ABORT           =  82 /* 0x52 */,
+       HAL_PHYRX_L_SIG_A                      =  83 /* 0x53 */,
+       HAL_PHYRX_L_SIG_B                      =  84 /* 0x54 */,
+       HAL_PHYRX_HT_SIG                       =  85 /* 0x55 */,
+       HAL_PHYRX_VHT_SIG_A                    =  86 /* 0x56 */,
+       HAL_PHYRX_VHT_SIG_B_SU20               =  87 /* 0x57 */,
+       HAL_PHYRX_VHT_SIG_B_SU40               =  88 /* 0x58 */,
+       HAL_PHYRX_VHT_SIG_B_SU80               =  89 /* 0x59 */,
+       HAL_PHYRX_VHT_SIG_B_SU160              =  90 /* 0x5a */,
+       HAL_PHYRX_VHT_SIG_B_MU20               =  91 /* 0x5b */,
+       HAL_PHYRX_VHT_SIG_B_MU40               =  92 /* 0x5c */,
+       HAL_PHYRX_VHT_SIG_B_MU80               =  93 /* 0x5d */,
+       HAL_PHYRX_VHT_SIG_B_MU160              =  94 /* 0x5e */,
+       HAL_PHYRX_HE_SIG_A_SU                  =  95 /* 0x5f */,
+       HAL_PHYRX_HE_SIG_A_MU_DL               =  96 /* 0x60 */,
+       HAL_PHYRX_HE_SIG_A_MU_UL               =  97 /* 0x61 */,
+       HAL_PHYRX_HE_SIG_B1_MU                 =  98 /* 0x62 */,
+       HAL_PHYRX_HE_SIG_B2_MU                 =  99 /* 0x63 */,
+       HAL_PHYRX_HE_SIG_B2_OFDMA              = 100 /* 0x64 */,
+       HAL_PHYRX_OTHER_RECEIVE_INFO           = 101 /* 0x65 */,
+       HAL_PHYRX_COMMON_USER_INFO             = 102 /* 0x66 */,
+       HAL_PHYRX_DATA_DONE                    = 103 /* 0x67 */,
+       HAL_RECEIVE_RSSI_INFO                  = 104 /* 0x68 */,
+       HAL_RECEIVE_USER_INFO                  = 105 /* 0x69 */,
+       HAL_MIMO_CONTROL_INFO                  = 106 /* 0x6a */,
+       HAL_RX_LOCATION_INFO                   = 107 /* 0x6b */,
+       HAL_COEX_TX_REQ                        = 108 /* 0x6c */,
+       HAL_DUMMY                              = 109 /* 0x6d */,
+       HAL_RX_TIMING_OFFSET_INFO              = 110 /* 0x6e */,
+       HAL_EXAMPLE_TLV_32_NAME                = 111 /* 0x6f */,
+       HAL_MPDU_LIMIT                         = 112 /* 0x70 */,
+       HAL_NA_LENGTH_END                      = 113 /* 0x71 */,
+       HAL_OLE_BUF_STATUS                     = 114 /* 0x72 */,
+       HAL_PCU_PPDU_SETUP_DONE                = 115 /* 0x73 */,
+       HAL_PCU_PPDU_SETUP_END                 = 116 /* 0x74 */,
+       HAL_PCU_PPDU_SETUP_INIT                = 117 /* 0x75 */,
+       HAL_PCU_PPDU_SETUP_START               = 118 /* 0x76 */,
+       HAL_PDG_FES_SETUP                      = 119 /* 0x77 */,
+       HAL_PDG_RESPONSE                       = 120 /* 0x78 */,
+       HAL_PDG_TX_REQ                         = 121 /* 0x79 */,
+       HAL_SCH_WAIT_INSTR                     = 122 /* 0x7a */,
+       HAL_SCHEDULER_TLV                      = 123 /* 0x7b */,
+       HAL_TQM_FLOW_EMPTY_STATUS              = 124 /* 0x7c */,
+       HAL_TQM_FLOW_NOT_EMPTY_STATUS          = 125 /* 0x7d */,
+       HAL_TQM_GEN_MPDU_LENGTH_LIST           = 126 /* 0x7e */,
+       HAL_TQM_GEN_MPDU_LENGTH_LIST_STATUS    = 127 /* 0x7f */,
+       HAL_TQM_GEN_MPDUS                      = 128 /* 0x80 */,
+       HAL_TQM_GEN_MPDUS_STATUS               = 129 /* 0x81 */,
+       HAL_TQM_REMOVE_MPDU                    = 130 /* 0x82 */,
+       HAL_TQM_REMOVE_MPDU_STATUS             = 131 /* 0x83 */,
+       HAL_TQM_REMOVE_MSDU                    = 132 /* 0x84 */,
+       HAL_TQM_REMOVE_MSDU_STATUS             = 133 /* 0x85 */,
+       HAL_TQM_UPDATE_TX_MPDU_COUNT           = 134 /* 0x86 */,
+       HAL_TQM_WRITE_CMD                      = 135 /* 0x87 */,
+       HAL_OFDMA_TRIGGER_DETAILS              = 136 /* 0x88 */,
+       HAL_TX_DATA                            = 137 /* 0x89 */,
+       HAL_TX_FES_SETUP                       = 138 /* 0x8a */,
+       HAL_RX_PACKET                          = 139 /* 0x8b */,
+       HAL_EXPECTED_RESPONSE                  = 140 /* 0x8c */,
+       HAL_TX_MPDU_END                        = 141 /* 0x8d */,
+       HAL_TX_MPDU_START                      = 142 /* 0x8e */,
+       HAL_TX_MSDU_END                        = 143 /* 0x8f */,
+       HAL_TX_MSDU_START                      = 144 /* 0x90 */,
+       HAL_TX_SW_MODE_SETUP                   = 145 /* 0x91 */,
+       HAL_TXPCU_BUFFER_STATUS                = 146 /* 0x92 */,
+       HAL_TXPCU_USER_BUFFER_STATUS           = 147 /* 0x93 */,
+       HAL_DATA_TO_TIME_CONFIG                = 148 /* 0x94 */,
+       HAL_EXAMPLE_USER_TLV_32                = 149 /* 0x95 */,
+       HAL_MPDU_INFO                          = 150 /* 0x96 */,
+       HAL_PDG_USER_SETUP                     = 151 /* 0x97 */,
+       HAL_TX_11AH_SETUP                      = 152 /* 0x98 */,
+       HAL_REO_UPDATE_RX_REO_QUEUE_STATUS     = 153 /* 0x99 */,
+       HAL_TX_PEER_ENTRY                      = 154 /* 0x9a */,
+       HAL_TX_RAW_OR_NATIVE_FRAME_SETUP       = 155 /* 0x9b */,
+       HAL_EXAMPLE_STRUCT_NAME                = 156 /* 0x9c */,
+       HAL_PCU_PPDU_SETUP_END_INFO            = 157 /* 0x9d */,
+       HAL_PPDU_RATE_SETTING                  = 158 /* 0x9e */,
+       HAL_PROT_RATE_SETTING                  = 159 /* 0x9f */,
+       HAL_RX_MPDU_DETAILS                    = 160 /* 0xa0 */,
+       HAL_EXAMPLE_USER_TLV_42                = 161 /* 0xa1 */,
+       HAL_RX_MSDU_LINK                       = 162 /* 0xa2 */,
+       HAL_RX_REO_QUEUE                       = 163 /* 0xa3 */,
+       HAL_ADDR_SEARCH_ENTRY                  = 164 /* 0xa4 */,
+       HAL_SCHEDULER_CMD                      = 165 /* 0xa5 */,
+       HAL_TX_FLUSH                           = 166 /* 0xa6 */,
+       HAL_TQM_ENTRANCE_RING                  = 167 /* 0xa7 */,
+       HAL_TX_DATA_WORD                       = 168 /* 0xa8 */,
+       HAL_TX_MPDU_DETAILS                    = 169 /* 0xa9 */,
+       HAL_TX_MPDU_LINK                       = 170 /* 0xaa */,
+       HAL_TX_MPDU_LINK_PTR                   = 171 /* 0xab */,
+       HAL_TX_MPDU_QUEUE_HEAD                 = 172 /* 0xac */,
+       HAL_TX_MPDU_QUEUE_EXT                  = 173 /* 0xad */,
+       HAL_TX_MPDU_QUEUE_EXT_PTR              = 174 /* 0xae */,
+       HAL_TX_MSDU_DETAILS                    = 175 /* 0xaf */,
+       HAL_TX_MSDU_EXTENSION                  = 176 /* 0xb0 */,
+       HAL_TX_MSDU_FLOW                       = 177 /* 0xb1 */,
+       HAL_TX_MSDU_LINK                       = 178 /* 0xb2 */,
+       HAL_TX_MSDU_LINK_ENTRY_PTR             = 179 /* 0xb3 */,
+       HAL_RESPONSE_RATE_SETTING              = 180 /* 0xb4 */,
+       HAL_TXPCU_BUFFER_BASICS                = 181 /* 0xb5 */,
+       HAL_UNIFORM_DESCRIPTOR_HEADER          = 182 /* 0xb6 */,
+       HAL_UNIFORM_TQM_CMD_HEADER             = 183 /* 0xb7 */,
+       HAL_UNIFORM_TQM_STATUS_HEADER          = 184 /* 0xb8 */,
+       HAL_USER_RATE_SETTING                  = 185 /* 0xb9 */,
+       HAL_WBM_BUFFER_RING                    = 186 /* 0xba */,
+       HAL_WBM_LINK_DESCRIPTOR_RING           = 187 /* 0xbb */,
+       HAL_WBM_RELEASE_RING                   = 188 /* 0xbc */,
+       HAL_TX_FLUSH_REQ                       = 189 /* 0xbd */,
+       HAL_RX_MSDU_DETAILS                    = 190 /* 0xbe */,
+       HAL_TQM_WRITE_CMD_STATUS               = 191 /* 0xbf */,
+       HAL_TQM_GET_MPDU_QUEUE_STATS           = 192 /* 0xc0 */,
+       HAL_TQM_GET_MSDU_FLOW_STATS            = 193 /* 0xc1 */,
+       HAL_EXAMPLE_USER_CTLV_32               = 194 /* 0xc2 */,
+       HAL_TX_FES_STATUS_START                = 195 /* 0xc3 */,
+       HAL_TX_FES_STATUS_USER_PPDU            = 196 /* 0xc4 */,
+       HAL_TX_FES_STATUS_USER_RESPONSE        = 197 /* 0xc5 */,
+       HAL_TX_FES_STATUS_END                  = 198 /* 0xc6 */,
+       HAL_RX_TRIG_INFO                       = 199 /* 0xc7 */,
+       HAL_RXPCU_TX_SETUP_CLEAR               = 200 /* 0xc8 */,
+       HAL_RX_FRAME_BITMAP_REQ                = 201 /* 0xc9 */,
+       HAL_RX_FRAME_BITMAP_ACK                = 202 /* 0xca */,
+       HAL_COEX_RX_STATUS                     = 203 /* 0xcb */,
+       HAL_RX_START_PARAM                     = 204 /* 0xcc */,
+       HAL_RX_PPDU_START                      = 205 /* 0xcd */,
+       HAL_RX_PPDU_END                        = 206 /* 0xce */,
+       HAL_RX_MPDU_START                      = 207 /* 0xcf */,
+       HAL_RX_MPDU_END                        = 208 /* 0xd0 */,
+       HAL_RX_MSDU_START                      = 209 /* 0xd1 */,
+       HAL_RX_MSDU_END                        = 210 /* 0xd2 */,
+       HAL_RX_ATTENTION                       = 211 /* 0xd3 */,
+       HAL_RECEIVED_RESPONSE_INFO             = 212 /* 0xd4 */,
+       HAL_RX_PHY_SLEEP                       = 213 /* 0xd5 */,
+       HAL_RX_HEADER                          = 214 /* 0xd6 */,
+       HAL_RX_PEER_ENTRY                      = 215 /* 0xd7 */,
+       HAL_RX_FLUSH                           = 216 /* 0xd8 */,
+       HAL_RX_RESPONSE_REQUIRED_INFO          = 217 /* 0xd9 */,
+       HAL_RX_FRAMELESS_BAR_DETAILS           = 218 /* 0xda */,
+       HAL_TQM_GET_MPDU_QUEUE_STATS_STATUS    = 219 /* 0xdb */,
+       HAL_TQM_GET_MSDU_FLOW_STATS_STATUS     = 220 /* 0xdc */,
+       HAL_TX_CBF_INFO                        = 221 /* 0xdd */,
+       HAL_PCU_PPDU_SETUP_USER                = 222 /* 0xde */,
+       HAL_RX_MPDU_PCU_START                  = 223 /* 0xdf */,
+       HAL_RX_PM_INFO                         = 224 /* 0xe0 */,
+       HAL_RX_USER_PPDU_END                   = 225 /* 0xe1 */,
+       HAL_RX_PRE_PPDU_START                  = 226 /* 0xe2 */,
+       HAL_RX_PREAMBLE                        = 227 /* 0xe3 */,
+       HAL_TX_FES_SETUP_COMPLETE              = 228 /* 0xe4 */,
+       HAL_TX_LAST_MPDU_FETCHED               = 229 /* 0xe5 */,
+       HAL_TXDMA_STOP_REQUEST                 = 230 /* 0xe6 */,
+       HAL_RXPCU_SETUP                        = 231 /* 0xe7 */,
+       HAL_RXPCU_USER_SETUP                   = 232 /* 0xe8 */,
+       HAL_TX_FES_STATUS_ACK_OR_BA            = 233 /* 0xe9 */,
+       HAL_TQM_ACKED_MPDU                     = 234 /* 0xea */,
+       HAL_COEX_TX_RESP                       = 235 /* 0xeb */,
+       HAL_COEX_TX_STATUS                     = 236 /* 0xec */,
+       HAL_MACTX_COEX_PHY_CTRL                = 237 /* 0xed */,
+       HAL_COEX_STATUS_BROADCAST              = 238 /* 0xee */,
+       HAL_RESPONSE_START_STATUS              = 239 /* 0xef */,
+       HAL_RESPONSE_END_STATUS                = 240 /* 0xf0 */,
+       HAL_CRYPTO_STATUS                      = 241 /* 0xf1 */,
+       HAL_RECEIVED_TRIGGER_INFO              = 242 /* 0xf2 */,
+       HAL_REO_ENTRANCE_RING                  = 243 /* 0xf3 */,
+       HAL_RX_MPDU_LINK                       = 244 /* 0xf4 */,
+       HAL_COEX_TX_STOP_CTRL                  = 245 /* 0xf5 */,
+       HAL_RX_PPDU_ACK_REPORT                 = 246 /* 0xf6 */,
+       HAL_RX_PPDU_NO_ACK_REPORT              = 247 /* 0xf7 */,
+       HAL_SCH_COEX_STATUS                    = 248 /* 0xf8 */,
+       HAL_SCHEDULER_COMMAND_STATUS           = 249 /* 0xf9 */,
+       HAL_SCHEDULER_RX_PPDU_NO_RESPONSE_STATUS = 250 /* 0xfa */,
+       HAL_TX_FES_STATUS_PROT                 = 251 /* 0xfb */,
+       HAL_TX_FES_STATUS_START_PPDU           = 252 /* 0xfc */,
+       HAL_TX_FES_STATUS_START_PROT           = 253 /* 0xfd */,
+       HAL_TXPCU_PHYTX_DEBUG32                = 254 /* 0xfe */,
+       HAL_TXPCU_PHYTX_OTHER_TRANSMIT_INFO32  = 255 /* 0xff */,
+       HAL_TX_MPDU_COUNT_TRANSFER_END         = 256 /* 0x100 */,
+       HAL_WHO_ANCHOR_OFFSET                  = 257 /* 0x101 */,
+       HAL_WHO_ANCHOR_VALUE                   = 258 /* 0x102 */,
+       HAL_WHO_CCE_INFO                       = 259 /* 0x103 */,
+       HAL_WHO_COMMIT                         = 260 /* 0x104 */,
+       HAL_WHO_COMMIT_DONE                    = 261 /* 0x105 */,
+       HAL_WHO_FLUSH                          = 262 /* 0x106 */,
+       HAL_WHO_L2_LLC                         = 263 /* 0x107 */,
+       HAL_WHO_L2_PAYLOAD                     = 264 /* 0x108 */,
+       HAL_WHO_L3_CHECKSUM                    = 265 /* 0x109 */,
+       HAL_WHO_L3_INFO                        = 266 /* 0x10a */,
+       HAL_WHO_L4_CHECKSUM                    = 267 /* 0x10b */,
+       HAL_WHO_L4_INFO                        = 268 /* 0x10c */,
+       HAL_WHO_MSDU                           = 269 /* 0x10d */,
+       HAL_WHO_MSDU_MISC                      = 270 /* 0x10e */,
+       HAL_WHO_PACKET_DATA                    = 271 /* 0x10f */,
+       HAL_WHO_PACKET_HDR                     = 272 /* 0x110 */,
+       HAL_WHO_PPDU_END                       = 273 /* 0x111 */,
+       HAL_WHO_PPDU_START                     = 274 /* 0x112 */,
+       HAL_WHO_TSO                            = 275 /* 0x113 */,
+       HAL_WHO_WMAC_HEADER_PV0                = 276 /* 0x114 */,
+       HAL_WHO_WMAC_HEADER_PV1                = 277 /* 0x115 */,
+       HAL_WHO_WMAC_IV                        = 278 /* 0x116 */,
+       HAL_MPDU_INFO_END                      = 279 /* 0x117 */,
+       HAL_MPDU_INFO_BITMAP                   = 280 /* 0x118 */,
+       HAL_TX_QUEUE_EXTENSION                 = 281 /* 0x119 */,
+       HAL_RX_PEER_ENTRY_DETAILS              = 282 /* 0x11a */,
+       HAL_RX_REO_QUEUE_REFERENCE             = 283 /* 0x11b */,
+       HAL_RX_REO_QUEUE_EXT                   = 284 /* 0x11c */,
+       HAL_SCHEDULER_SELFGEN_RESPONSE_STATUS  = 285 /* 0x11d */,
+       HAL_TQM_UPDATE_TX_MPDU_COUNT_STATUS    = 286 /* 0x11e */,
+       HAL_TQM_ACKED_MPDU_STATUS              = 287 /* 0x11f */,
+       HAL_TQM_ADD_MSDU_STATUS                = 288 /* 0x120 */,
+       HAL_RX_MPDU_LINK_PTR                   = 289 /* 0x121 */,
+       HAL_REO_DESTINATION_RING               = 290 /* 0x122 */,
+       HAL_TQM_LIST_GEN_DONE                  = 291 /* 0x123 */,
+       HAL_WHO_TERMINATE                      = 292 /* 0x124 */,
+       HAL_TX_LAST_MPDU_END                   = 293 /* 0x125 */,
+       HAL_TX_CV_DATA                         = 294 /* 0x126 */,
+       HAL_TCL_ENTRANCE_FROM_PPE_RING         = 295 /* 0x127 */,
+       HAL_PPDU_TX_END                        = 296 /* 0x128 */,
+       HAL_PROT_TX_END                        = 297 /* 0x129 */,
+       HAL_PDG_RESPONSE_RATE_SETTING          = 298 /* 0x12a */,
+       HAL_MPDU_INFO_GLOBAL_END               = 299 /* 0x12b */,
+       HAL_TQM_SCH_INSTR_GLOBAL_END           = 300 /* 0x12c */,
+       HAL_RX_PPDU_END_USER_STATS             = 301 /* 0x12d */,
+       HAL_RX_PPDU_END_USER_STATS_EXT         = 302 /* 0x12e */,
+       HAL_NO_ACK_REPORT                      = 303 /* 0x12f */,
+       HAL_ACK_REPORT                         = 304 /* 0x130 */,
+       HAL_UNIFORM_REO_CMD_HEADER             = 305 /* 0x131 */,
+       HAL_REO_GET_QUEUE_STATS                = 306 /* 0x132 */,
+       HAL_REO_FLUSH_QUEUE                    = 307 /* 0x133 */,
+       HAL_REO_FLUSH_CACHE                    = 308 /* 0x134 */,
+       HAL_REO_UNBLOCK_CACHE                  = 309 /* 0x135 */,
+       HAL_UNIFORM_REO_STATUS_HEADER          = 310 /* 0x136 */,
+       HAL_REO_GET_QUEUE_STATS_STATUS         = 311 /* 0x137 */,
+       HAL_REO_FLUSH_QUEUE_STATUS             = 312 /* 0x138 */,
+       HAL_REO_FLUSH_CACHE_STATUS             = 313 /* 0x139 */,
+       HAL_REO_UNBLOCK_CACHE_STATUS           = 314 /* 0x13a */,
+       HAL_TQM_FLUSH_CACHE                    = 315 /* 0x13b */,
+       HAL_TQM_UNBLOCK_CACHE                  = 316 /* 0x13c */,
+       HAL_TQM_FLUSH_CACHE_STATUS             = 317 /* 0x13d */,
+       HAL_TQM_UNBLOCK_CACHE_STATUS           = 318 /* 0x13e */,
+       HAL_RX_PPDU_END_STATUS_DONE            = 319 /* 0x13f */,
+       HAL_RX_STATUS_BUFFER_DONE              = 320 /* 0x140 */,
+       HAL_BUFFER_ADDR_INFO                   = 321 /* 0x141 */,
+       HAL_RX_MSDU_DESC_INFO                  = 322 /* 0x142 */,
+       HAL_RX_MPDU_DESC_INFO                  = 323 /* 0x143 */,
+       HAL_TCL_DATA_CMD                       = 324 /* 0x144 */,
+       HAL_TCL_GSE_CMD                        = 325 /* 0x145 */,
+       HAL_TCL_EXIT_BASE                      = 326 /* 0x146 */,
+       HAL_TCL_COMPACT_EXIT_RING              = 327 /* 0x147 */,
+       HAL_TCL_REGULAR_EXIT_RING              = 328 /* 0x148 */,
+       HAL_TCL_EXTENDED_EXIT_RING             = 329 /* 0x149 */,
+       HAL_UPLINK_COMMON_INFO                 = 330 /* 0x14a */,
+       HAL_UPLINK_USER_SETUP_INFO             = 331 /* 0x14b */,
+       HAL_TX_DATA_SYNC                       = 332 /* 0x14c */,
+       HAL_PHYRX_CBF_READ_REQUEST_ACK         = 333 /* 0x14d */,
+       HAL_TCL_STATUS_RING                    = 334 /* 0x14e */,
+       HAL_TQM_GET_MPDU_HEAD_INFO             = 335 /* 0x14f */,
+       HAL_TQM_SYNC_CMD                       = 336 /* 0x150 */,
+       HAL_TQM_GET_MPDU_HEAD_INFO_STATUS      = 337 /* 0x151 */,
+       HAL_TQM_SYNC_CMD_STATUS                = 338 /* 0x152 */,
+       HAL_TQM_THRESHOLD_DROP_NOTIFICATION_STATUS = 339 /* 0x153 */,
+       HAL_TQM_DESCRIPTOR_THRESHOLD_REACHED_STATUS = 340 /* 0x154 */,
+       HAL_REO_FLUSH_TIMEOUT_LIST             = 341 /* 0x155 */,
+       HAL_REO_FLUSH_TIMEOUT_LIST_STATUS      = 342 /* 0x156 */,
+       HAL_REO_TO_PPE_RING                    = 343 /* 0x157 */,
+       HAL_RX_MPDU_INFO                       = 344 /* 0x158 */,
+       HAL_REO_DESCRIPTOR_THRESHOLD_REACHED_STATUS = 345 /* 0x159 */,
+       HAL_SCHEDULER_RX_SIFS_RESPONSE_TRIGGER_STATUS = 346 /* 0x15a */,
+       HAL_EXAMPLE_USER_TLV_32_NAME           = 347 /* 0x15b */,
+       HAL_RX_PPDU_START_USER_INFO            = 348 /* 0x15c */,
+       HAL_RX_RXPCU_CLASSIFICATION_OVERVIEW   = 349 /* 0x15d */,
+       HAL_RX_RING_MASK                       = 350 /* 0x15e */,
+       HAL_WHO_CLASSIFY_INFO                  = 351 /* 0x15f */,
+       HAL_TXPT_CLASSIFY_INFO                 = 352 /* 0x160 */,
+       HAL_RXPT_CLASSIFY_INFO                 = 353 /* 0x161 */,
+       HAL_TX_FLOW_SEARCH_ENTRY               = 354 /* 0x162 */,
+       HAL_RX_FLOW_SEARCH_ENTRY               = 355 /* 0x163 */,
+       HAL_RECEIVED_TRIGGER_INFO_DETAILS      = 356 /* 0x164 */,
+       HAL_COEX_MAC_NAP                       = 357 /* 0x165 */,
+       HAL_MACRX_ABORT_REQUEST_INFO           = 358 /* 0x166 */,
+       HAL_MACTX_ABORT_REQUEST_INFO           = 359 /* 0x167 */,
+       HAL_PHYRX_ABORT_REQUEST_INFO           = 360 /* 0x168 */,
+       HAL_PHYTX_ABORT_REQUEST_INFO           = 361 /* 0x169 */,
+       HAL_RXPCU_PPDU_END_INFO                = 362 /* 0x16a */,
+       HAL_WHO_MESH_CONTROL                   = 363 /* 0x16b */,
+       HAL_L_SIG_A_INFO                       = 364 /* 0x16c */,
+       HAL_L_SIG_B_INFO                       = 365 /* 0x16d */,
+       HAL_HT_SIG_INFO                        = 366 /* 0x16e */,
+       HAL_VHT_SIG_A_INFO                     = 367 /* 0x16f */,
+       HAL_VHT_SIG_B_SU20_INFO                = 368 /* 0x170 */,
+       HAL_VHT_SIG_B_SU40_INFO                = 369 /* 0x171 */,
+       HAL_VHT_SIG_B_SU80_INFO                = 370 /* 0x172 */,
+       HAL_VHT_SIG_B_SU160_INFO               = 371 /* 0x173 */,
+       HAL_VHT_SIG_B_MU20_INFO                = 372 /* 0x174 */,
+       HAL_VHT_SIG_B_MU40_INFO                = 373 /* 0x175 */,
+       HAL_VHT_SIG_B_MU80_INFO                = 374 /* 0x176 */,
+       HAL_VHT_SIG_B_MU160_INFO               = 375 /* 0x177 */,
+       HAL_SERVICE_INFO                       = 376 /* 0x178 */,
+       HAL_HE_SIG_A_SU_INFO                   = 377 /* 0x179 */,
+       HAL_HE_SIG_A_MU_DL_INFO                = 378 /* 0x17a */,
+       HAL_HE_SIG_A_MU_UL_INFO                = 379 /* 0x17b */,
+       HAL_HE_SIG_B1_MU_INFO                  = 380 /* 0x17c */,
+       HAL_HE_SIG_B2_MU_INFO                  = 381 /* 0x17d */,
+       HAL_HE_SIG_B2_OFDMA_INFO               = 382 /* 0x17e */,
+       HAL_PDG_SW_MODE_BW_START               = 383 /* 0x17f */,
+       HAL_PDG_SW_MODE_BW_END                 = 384 /* 0x180 */,
+       HAL_PDG_WAIT_FOR_MAC_REQUEST           = 385 /* 0x181 */,
+       HAL_PDG_WAIT_FOR_PHY_REQUEST           = 386 /* 0x182 */,
+       HAL_SCHEDULER_END                      = 387 /* 0x183 */,
+       HAL_PEER_TABLE_ENTRY                   = 388 /* 0x184 */,
+       HAL_SW_PEER_INFO                       = 389 /* 0x185 */,
+       HAL_RXOLE_CCE_CLASSIFY_INFO            = 390 /* 0x186 */,
+       HAL_TCL_CCE_CLASSIFY_INFO              = 391 /* 0x187 */,
+       HAL_RXOLE_CCE_INFO                     = 392 /* 0x188 */,
+       HAL_TCL_CCE_INFO                       = 393 /* 0x189 */,
+       HAL_TCL_CCE_SUPERRULE                  = 394 /* 0x18a */,
+       HAL_CCE_RULE                           = 395 /* 0x18b */,
+       HAL_RX_PPDU_START_DROPPED              = 396 /* 0x18c */,
+       HAL_RX_PPDU_END_DROPPED                = 397 /* 0x18d */,
+       HAL_RX_PPDU_END_STATUS_DONE_DROPPED    = 398 /* 0x18e */,
+       HAL_RX_MPDU_START_DROPPED              = 399 /* 0x18f */,
+       HAL_RX_MSDU_START_DROPPED              = 400 /* 0x190 */,
+       HAL_RX_MSDU_END_DROPPED                = 401 /* 0x191 */,
+       HAL_RX_MPDU_END_DROPPED                = 402 /* 0x192 */,
+       HAL_RX_ATTENTION_DROPPED               = 403 /* 0x193 */,
+       HAL_TXPCU_USER_SETUP                   = 404 /* 0x194 */,
+       HAL_RXPCU_USER_SETUP_EXT               = 405 /* 0x195 */,
+       HAL_CE_SRC_DESC                        = 406 /* 0x196 */,
+       HAL_CE_STAT_DESC                       = 407 /* 0x197 */,
+       HAL_RXOLE_CCE_SUPERRULE                = 408 /* 0x198 */,
+       HAL_TX_RATE_STATS_INFO                 = 409 /* 0x199 */,
+       HAL_CMD_PART_0_END                     = 410 /* 0x19a */,
+       HAL_MACTX_SYNTH_ON                     = 411 /* 0x19b */,
+       HAL_SCH_CRITICAL_TLV_REFERENCE         = 412 /* 0x19c */,
+       HAL_TQM_MPDU_GLOBAL_START              = 413 /* 0x19d */,
+       HAL_EXAMPLE_TLV_32                     = 414 /* 0x19e */,
+       HAL_TQM_UPDATE_TX_MSDU_FLOW            = 415 /* 0x19f */,
+       HAL_TQM_UPDATE_TX_MPDU_QUEUE_HEAD      = 416 /* 0x1a0 */,
+       HAL_TQM_UPDATE_TX_MSDU_FLOW_STATUS     = 417 /* 0x1a1 */,
+       HAL_TQM_UPDATE_TX_MPDU_QUEUE_HEAD_STATUS = 418 /* 0x1a2 */,
+       HAL_REO_UPDATE_RX_REO_QUEUE            = 419 /* 0x1a3 */,
+       HAL_CE_DST_DESC                        = 420 /* 0x1a4 */,
+       HAL_TLV_BASE                           = 511 /* 0x1ff */,
+};
+
+#define HAL_TLV_HDR_TAG                GENMASK(9, 1)
+#define HAL_TLV_HDR_LEN                GENMASK(25, 10)
+
+#define HAL_TLV_ALIGN  4
+
+struct hal_tlv_hdr {
+       u32 tl;
+       u8 value[0];
+} __packed;
+
+#define RX_MPDU_DESC_INFO0_MSDU_COUNT          GENMASK(7, 0)
+#define RX_MPDU_DESC_INFO0_SEQ_NUM             GENMASK(19, 8)
+#define RX_MPDU_DESC_INFO0_FRAG_FLAG           BIT(20)
+#define RX_MPDU_DESC_INFO0_MPDU_RETRY          BIT(21)
+#define RX_MPDU_DESC_INFO0_AMPDU_FLAG          BIT(22)
+#define RX_MPDU_DESC_INFO0_BAR_FRAME           BIT(23)
+#define RX_MPDU_DESC_INFO0_VALID_PN            BIT(24)
+#define RX_MPDU_DESC_INFO0_VALID_SA            BIT(25)
+#define RX_MPDU_DESC_INFO0_SA_IDX_TIMEOUT      BIT(26)
+#define RX_MPDU_DESC_INFO0_VALID_DA            BIT(27)
+#define RX_MPDU_DESC_INFO0_DA_MCBC             BIT(28)
+#define RX_MPDU_DESC_INFO0_DA_IDX_TIMEOUT      BIT(29)
+#define RX_MPDU_DESC_INFO0_RAW_MPDU            BIT(30)
+
+struct rx_mpdu_desc {
+       u32 info0; /* %RX_MPDU_DESC_INFO */
+       u32 meta_data;
+} __packed;
+
+/* rx_mpdu_desc
+ *             Producer: RXDMA
+ *             Consumer: REO/SW/FW
+ *
+ * msdu_count
+ *             The number of MSDUs within the MPDU
+ *
+ * mpdu_sequence_number
+ *             The field can have two different meanings based on the setting
+ *             of field 'bar_frame'. If 'bar_frame' is set, it means the MPDU
+ *             start sequence number from the BAR frame otherwise it means
+ *             the MPDU sequence number of the received frame.
+ *
+ * fragment_flag
+ *             When set, this MPDU is a fragment and REO should forward this
+ *             fragment MPDU to the REO destination ring without any reorder
+ *             checks, pn checks or bitmap update. This implies that REO is
+ *             forwarding the pointer to the MSDU link descriptor.
+ *
+ * mpdu_retry_bit
+ *             The retry bit setting from the MPDU header of the received frame
+ *
+ * ampdu_flag
+ *             Indicates the MPDU was received as part of an A-MPDU.
+ *
+ * bar_frame
+ *             Indicates the received frame is a BAR frame. After processing,
+ *             this frame shall be pushed to SW or deleted.
+ *
+ * valid_pn
+ *             When not set, REO will not perform a PN sequence number check.
+ *
+ * valid_sa
+ *             Indicates OLE found a valid SA entry for all MSDUs in this MPDU.
+ *
+ * sa_idx_timeout
+ *             Indicates, at least 1 MSDU within the MPDU has an unsuccessful
+ *             MAC source address search due to the expiration of search timer.
+ *
+ * valid_da
+ *             When set, OLE found a valid DA entry for all MSDUs in this MPDU.
+ *
+ * da_mcbc
+ *             Field Only valid if valid_da is set. Indicates at least one of
+ *             the DA addresses is a Multicast or Broadcast address.
+ *
+ * da_idx_timeout
+ *             Indicates, at least 1 MSDU within the MPDU has an unsuccessful
+ *             MAC destination address search due to the expiration of search
+ *             timer.
+ *
+ * raw_mpdu
+ *             Field only valid when first_msdu_in_mpdu_flag is set. Indicates
+ *             the contents in the MSDU buffer contains a 'RAW' MPDU.
+ */
+
+enum hal_rx_msdu_desc_reo_dest_ind {
+       HAL_RX_MSDU_DESC_REO_DEST_IND_TCL,
+       HAL_RX_MSDU_DESC_REO_DEST_IND_SW1,
+       HAL_RX_MSDU_DESC_REO_DEST_IND_SW2,
+       HAL_RX_MSDU_DESC_REO_DEST_IND_SW3,
+       HAL_RX_MSDU_DESC_REO_DEST_IND_SW4,
+       HAL_RX_MSDU_DESC_REO_DEST_IND_RELEASE,
+       HAL_RX_MSDU_DESC_REO_DEST_IND_FW,
+};
+
+#define RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU  BIT(0)
+#define RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU   BIT(1)
+#define RX_MSDU_DESC_INFO0_MSDU_CONTINUATION   BIT(2)
+#define RX_MSDU_DESC_INFO0_MSDU_LENGTH         GENMASK(16, 3)
+#define RX_MSDU_DESC_INFO0_REO_DEST_IND                GENMASK(21, 17)
+#define RX_MSDU_DESC_INFO0_MSDU_DROP           BIT(22)
+#define RX_MSDU_DESC_INFO0_VALID_SA            BIT(23)
+#define RX_MSDU_DESC_INFO0_SA_IDX_TIMEOUT      BIT(24)
+#define RX_MSDU_DESC_INFO0_VALID_DA            BIT(25)
+#define RX_MSDU_DESC_INFO0_DA_MCBC             BIT(26)
+#define RX_MSDU_DESC_INFO0_DA_IDX_TIMEOUT      BIT(27)
+
+#define HAL_RX_MSDU_PKT_LENGTH_GET(val)                \
+       (FIELD_GET(RX_MSDU_DESC_INFO0_MSDU_LENGTH, (val)))
+
+struct rx_msdu_desc {
+       u32 info0;
+       u32 rsvd0;
+} __packed;
+
+/* rx_msdu_desc
+ *
+ * first_msdu_in_mpdu
+ *             Indicates first msdu in mpdu.
+ *
+ * last_msdu_in_mpdu
+ *             Indicates last msdu in mpdu. This flag can be true only when
+ *             'Msdu_continuation' set to 0. This implies that when an msdu
+ *             is spread out over multiple buffers and thus msdu_continuation
+ *             is set, only for the very last buffer of the msdu, can the
+ *             'last_msdu_in_mpdu' be set.
+ *
+ *             When both first_msdu_in_mpdu and last_msdu_in_mpdu are set,
+ *             the MPDU that this MSDU belongs to only contains a single MSDU.
+ *
+ * msdu_continuation
+ *             When set, this MSDU buffer was not able to hold the entire MSDU.
+ *             The next buffer will therefor contain additional information
+ *             related to this MSDU.
+ *
+ * msdu_length
+ *             Field is only valid in combination with the 'first_msdu_in_mpdu'
+ *             being set. Full MSDU length in bytes after decapsulation. This
+ *             field is still valid for MPDU frames without A-MSDU. It still
+ *             represents MSDU length after decapsulation Or in case of RAW
+ *             MPDUs, it indicates the length of the entire MPDU (without FCS
+ *             field).
+ *
+ * reo_destination_indication
+ *             The id of the reo exit ring where the msdu frame shall push
+ *             after (MPDU level) reordering has finished. Values are defined
+ *             in enum %HAL_RX_MSDU_DESC_REO_DEST_IND_.
+ *
+ * msdu_drop
+ *             Indicates that REO shall drop this MSDU and not forward it to
+ *             any other ring.
+ *
+ * valid_sa
+ *             Indicates OLE found a valid SA entry for this MSDU.
+ *
+ * sa_idx_timeout
+ *             Indicates, an unsuccessful MAC source address search due to
+ *             the expiration of search timer for this MSDU.
+ *
+ * valid_da
+ *             When set, OLE found a valid DA entry for this MSDU.
+ *
+ * da_mcbc
+ *             Field Only valid if valid_da is set. Indicates the DA address
+ *             is a Multicast or Broadcast address for this MSDU.
+ *
+ * da_idx_timeout
+ *             Indicates, an unsuccessful MAC destination address search due
+ *             to the expiration of search timer fot this MSDU.
+ */
+
+enum hal_reo_dest_ring_buffer_type {
+       HAL_REO_DEST_RING_BUFFER_TYPE_MSDU,
+       HAL_REO_DEST_RING_BUFFER_TYPE_LINK_DESC,
+};
+
+enum hal_reo_dest_ring_push_reason {
+       HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED,
+       HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION,
+};
+
+enum hal_reo_dest_ring_error_code {
+       HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO,
+       HAL_REO_DEST_RING_ERROR_CODE_DESC_INVALID,
+       HAL_REO_DEST_RING_ERROR_CODE_AMPDU_IN_NON_BA,
+       HAL_REO_DEST_RING_ERROR_CODE_NON_BA_DUPLICATE,
+       HAL_REO_DEST_RING_ERROR_CODE_BA_DUPLICATE,
+       HAL_REO_DEST_RING_ERROR_CODE_FRAME_2K_JUMP,
+       HAL_REO_DEST_RING_ERROR_CODE_BAR_2K_JUMP,
+       HAL_REO_DEST_RING_ERROR_CODE_FRAME_OOR,
+       HAL_REO_DEST_RING_ERROR_CODE_BAR_OOR,
+       HAL_REO_DEST_RING_ERROR_CODE_NO_BA_SESSION,
+       HAL_REO_DEST_RING_ERROR_CODE_FRAME_SN_EQUALS_SSN,
+       HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED,
+       HAL_REO_DEST_RING_ERROR_CODE_2K_ERR_FLAG_SET,
+       HAL_REO_DEST_RING_ERROR_CODE_PN_ERR_FLAG_SET,
+       HAL_REO_DEST_RING_ERROR_CODE_DESC_BLOCKED,
+       HAL_REO_DEST_RING_ERROR_CODE_MAX,
+};
+
+#define HAL_REO_DEST_RING_INFO0_QUEUE_ADDR_HI          GENMASK(7, 0)
+#define HAL_REO_DEST_RING_INFO0_BUFFER_TYPE            BIT(8)
+#define HAL_REO_DEST_RING_INFO0_PUSH_REASON            GENMASK(10, 9)
+#define HAL_REO_DEST_RING_INFO0_ERROR_CODE             GENMASK(15, 11)
+#define HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM           GENMASK(31, 16)
+
+#define HAL_REO_DEST_RING_INFO1_REORDER_INFO_VALID     BIT(0)
+#define HAL_REO_DEST_RING_INFO1_REORDER_OPCODE         GENMASK(4, 1)
+#define HAL_REO_DEST_RING_INFO1_REORDER_SLOT_IDX       GENMASK(12, 5)
+
+#define HAL_REO_DEST_RING_INFO2_RING_ID                        GENMASK(27, 20)
+#define HAL_REO_DEST_RING_INFO2_LOOPING_COUNT          GENMASK(31, 28)
+
+struct hal_reo_dest_ring {
+       struct ath11k_buffer_addr buf_addr_info;
+       struct rx_mpdu_desc rx_mpdu_info;
+       struct rx_msdu_desc rx_msdu_info;
+       u32 queue_addr_lo;
+       u32 info0; /* %HAL_REO_DEST_RING_INFO0_ */
+       u32 info1; /* %HAL_REO_DEST_RING_INFO1_ */
+       u32 rsvd0;
+       u32 rsvd1;
+       u32 rsvd2;
+       u32 rsvd3;
+       u32 rsvd4;
+       u32 rsvd5;
+       u32 info2; /* %HAL_REO_DEST_RING_INFO2_ */
+} __packed;
+
+/* hal_reo_dest_ring
+ *
+ *             Producer: RXDMA
+ *             Consumer: REO/SW/FW
+ *
+ * buf_addr_info
+ *             Details of the physical address of a buffer or MSDU
+ *             link descriptor.
+ *
+ * rx_mpdu_info
+ *             General information related to the MPDU that is passed
+ *             on from REO entrance ring to the REO destination ring.
+ *
+ * rx_msdu_info
+ *             General information related to the MSDU that is passed
+ *             on from RXDMA all the way to to the REO destination ring.
+ *
+ * queue_addr_lo
+ *             Address (lower 32 bits) of the REO queue descriptor.
+ *
+ * queue_addr_hi
+ *             Address (upper 8 bits) of the REO queue descriptor.
+ *
+ * buffer_type
+ *             Indicates the type of address provided in the buf_addr_info.
+ *             Values are defined in enum %HAL_REO_DEST_RING_BUFFER_TYPE_.
+ *
+ * push_reason
+ *             Reason for pushing this frame to this exit ring. Values are
+ *             defined in enum %HAL_REO_DEST_RING_PUSH_REASON_.
+ *
+ * error_code
+ *             Valid only when 'push_reason' is set. All error codes are
+ *             defined in enum %HAL_REO_DEST_RING_ERROR_CODE_.
+ *
+ * rx_queue_num
+ *             Indicates the REO MPDU reorder queue id from which this frame
+ *             originated.
+ *
+ * reorder_info_valid
+ *             When set, REO has been instructed to not perform the actual
+ *             re-ordering of frames for this queue, but just to insert
+ *             the reorder opcodes.
+ *
+ * reorder_opcode
+ *             Field is valid when 'reorder_info_valid' is set. This field is
+ *             always valid for debug purpose as well.
+ *
+ * reorder_slot_idx
+ *             Valid only when 'reorder_info_valid' is set.
+ *
+ * ring_id
+ *             The buffer pointer ring id.
+ *             0 - Idle ring
+ *             1 - N refers to other rings.
+ *
+ * looping_count
+ *             Indicates the number of times the producer of entries into
+ *             this ring has looped around the ring.
+ */
+
+enum hal_reo_entr_rxdma_ecode {
+       HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_FCS_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_UNECRYPTED_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LEN_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LIMIT_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_WIFI_PARSE_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_PARSE_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_SA_TIMEOUT_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_DA_TIMEOUT_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_FLOW_TIMEOUT_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR,
+       HAL_REO_ENTR_RING_RXDMA_ECODE_MAX,
+};
+
+#define HAL_REO_ENTR_RING_INFO0_QUEUE_ADDR_HI          GENMASK(7, 0)
+#define HAL_REO_ENTR_RING_INFO0_MPDU_BYTE_COUNT                GENMASK(21, 8)
+#define HAL_REO_ENTR_RING_INFO0_DEST_IND               GENMASK(26, 22)
+#define HAL_REO_ENTR_RING_INFO0_FRAMELESS_BAR          BIT(27)
+
+#define HAL_REO_ENTR_RING_INFO1_RXDMA_PUSH_REASON      GENMASK(1, 0)
+#define HAL_REO_ENTR_RING_INFO1_RXDMA_ERROR_CODE       GENMASK(6, 2)
+
+struct hal_reo_entrance_ring {
+       struct ath11k_buffer_addr buf_addr_info;
+       struct rx_mpdu_desc rx_mpdu_info;
+       u32 queue_addr_lo;
+       u32 info0; /* %HAL_REO_ENTR_RING_INFO0_ */
+       u32 info1; /* %HAL_REO_ENTR_RING_INFO1_ */
+       u32 info2; /* %HAL_REO_DEST_RING_INFO2_ */
+
+} __packed;
+
+/* hal_reo_entrance_ring
+ *
+ *             Producer: RXDMA
+ *             Consumer: REO
+ *
+ * buf_addr_info
+ *             Details of the physical address of a buffer or MSDU
+ *             link descriptor.
+ *
+ * rx_mpdu_info
+ *             General information related to the MPDU that is passed
+ *             on from REO entrance ring to the REO destination ring.
+ *
+ * queue_addr_lo
+ *             Address (lower 32 bits) of the REO queue descriptor.
+ *
+ * queue_addr_hi
+ *             Address (upper 8 bits) of the REO queue descriptor.
+ *
+ * mpdu_byte_count
+ *             An approximation of the number of bytes received in this MPDU.
+ *             Used to keeps stats on the amount of data flowing
+ *             through a queue.
+ *
+ * reo_destination_indication
+ *             The id of the reo exit ring where the msdu frame shall push
+ *             after (MPDU level) reordering has finished. Values are defined
+ *             in enum %HAL_RX_MSDU_DESC_REO_DEST_IND_.
+ *
+ * frameless_bar
+ *             Indicates that this REO entrance ring struct contains BAR info
+ *             from a multi TID BAR frame. The original multi TID BAR frame
+ *             itself contained all the REO info for the first TID, but all
+ *             the subsequent TID info and their linkage to the REO descriptors
+ *             is passed down as 'frameless' BAR info.
+ *
+ *             The only fields valid in this descriptor when this bit is set
+ *             are queue_addr_lo, queue_addr_hi, mpdu_sequence_number,
+ *             bar_frame and peer_meta_data.
+ *
+ * rxdma_push_reason
+ *             Reason for pushing this frame to this exit ring. Values are
+ *             defined in enum %HAL_REO_DEST_RING_PUSH_REASON_.
+ *
+ * rxdma_error_code
+ *             Valid only when 'push_reason' is set. All error codes are
+ *             defined in enum %HAL_REO_ENTR_RING_RXDMA_ECODE_.
+ *
+ * ring_id
+ *             The buffer pointer ring id.
+ *             0 - Idle ring
+ *             1 - N refers to other rings.
+ *
+ * looping_count
+ *             Indicates the number of times the producer of entries into
+ *             this ring has looped around the ring.
+ */
+
+#define HAL_REO_CMD_HDR_INFO0_CMD_NUMBER       GENMASK(15, 0)
+#define HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED  BIT(16)
+
+struct hal_reo_cmd_hdr {
+       u32 info0;
+} __packed;
+
+#define HAL_REO_GET_QUEUE_STATS_INFO0_QUEUE_ADDR_HI    GENMASK(7, 0)
+#define HAL_REO_GET_QUEUE_STATS_INFO0_CLEAR_STATS      BIT(8)
+
+struct hal_reo_get_queue_stats {
+       struct hal_reo_cmd_hdr cmd;
+       u32 queue_addr_lo;
+       u32 info0;
+       u32 rsvd0[6];
+} __packed;
+
+/* hal_reo_get_queue_stats
+ *             Producer: SW
+ *             Consumer: REO
+ *
+ * cmd
+ *             Details for command execution tracking purposes.
+ *
+ * queue_addr_lo
+ *             Address (lower 32 bits) of the REO queue descriptor.
+ *
+ * queue_addr_hi
+ *             Address (upper 8 bits) of the REO queue descriptor.
+ *
+ * clear_stats
+ *             Clear stats settings. When set, Clear the stats after
+ *             generating the status.
+ *
+ *             Following stats will be cleared.
+ *             Timeout_count
+ *             Forward_due_to_bar_count
+ *             Duplicate_count
+ *             Frames_in_order_count
+ *             BAR_received_count
+ *             MPDU_Frames_processed_count
+ *             MSDU_Frames_processed_count
+ *             Total_processed_byte_count
+ *             Late_receive_MPDU_count
+ *             window_jump_2k
+ *             Hole_count
+ */
+
+#define HAL_REO_FLUSH_QUEUE_INFO0_DESC_ADDR_HI         GENMASK(7, 0)
+#define HAL_REO_FLUSH_QUEUE_INFO0_BLOCK_DESC_ADDR      BIT(8)
+#define HAL_REO_FLUSH_QUEUE_INFO0_BLOCK_RESRC_IDX      GENMASK(10, 9)
+
+struct hal_reo_flush_queue {
+       struct hal_reo_cmd_hdr cmd;
+       u32 desc_addr_lo;
+       u32 info0;
+       u32 rsvd0[6];
+} __packed;
+
+#define HAL_REO_FLUSH_CACHE_INFO0_CACHE_ADDR_HI                GENMASK(7, 0)
+#define HAL_REO_FLUSH_CACHE_INFO0_FWD_ALL_MPDUS                BIT(8)
+#define HAL_REO_FLUSH_CACHE_INFO0_RELEASE_BLOCK_IDX    BIT(9)
+#define HAL_REO_FLUSH_CACHE_INFO0_BLOCK_RESRC_IDX      GENMASK(11, 10)
+#define HAL_REO_FLUSH_CACHE_INFO0_FLUSH_WO_INVALIDATE  BIT(12)
+#define HAL_REO_FLUSH_CACHE_INFO0_BLOCK_CACHE_USAGE    BIT(13)
+#define HAL_REO_FLUSH_CACHE_INFO0_FLUSH_ALL            BIT(14)
+
+struct hal_reo_flush_cache {
+       struct hal_reo_cmd_hdr cmd;
+       u32 cache_addr_lo;
+       u32 info0;
+       u32 rsvd0[6];
+} __packed;
+
+#define HAL_TCL_DATA_CMD_INFO0_DESC_TYPE       BIT(0)
+#define HAL_TCL_DATA_CMD_INFO0_EPD             BIT(1)
+#define HAL_TCL_DATA_CMD_INFO0_ENCAP_TYPE      GENMASK(3, 2)
+#define HAL_TCL_DATA_CMD_INFO0_ENCRYPT_TYPE    GENMASK(7, 4)
+#define HAL_TCL_DATA_CMD_INFO0_SRC_BUF_SWAP    BIT(8)
+#define HAL_TCL_DATA_CMD_INFO0_LNK_META_SWAP   BIT(9)
+#define HAL_TCL_DATA_CMD_INFO0_SEARCH_TYPE     BIT(12)
+#define HAL_TCL_DATA_CMD_INFO0_ADDRX_EN                BIT(14)
+#define HAL_TCL_DATA_CMD_INFO0_ADDRY_EN                BIT(15)
+#define HAL_TCL_DATA_CMD_INFO0_CMD_NUM         GENMASK(31, 16)
+
+#define HAL_TCL_DATA_CMD_INFO1_DATA_LEN                GENMASK(15, 0)
+#define HAL_TCL_DATA_CMD_INFO1_IP4_CKSUM_EN    BIT(16)
+#define HAL_TCL_DATA_CMD_INFO1_UDP4_CKSUM_EN   BIT(17)
+#define HAL_TCL_DATA_CMD_INFO1_UDP6_CKSUM_EN   BIT(18)
+#define HAL_TCL_DATA_CMD_INFO1_TCP4_CKSUM_EN   BIT(19)
+#define HAL_TCL_DATA_CMD_INFO1_TCP6_CKSUM_EN   BIT(20)
+#define HAL_TCL_DATA_CMD_INFO1_TO_FW           BIT(21)
+#define HAL_TCL_DATA_CMD_INFO1_PKT_OFFSET      GENMASK(31, 23)
+
+#define HAL_TCL_DATA_CMD_INFO2_BUF_TIMESTAMP   GENMASK(18, 0)
+#define HAL_TCL_DATA_CMD_INFO2_BUF_T_VALID     BIT(19)
+#define HAL_TCL_DATA_CMD_INFO2_MESH_ENABLE     BIT(20)
+#define HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE   BIT(21)
+#define HAL_TCL_DATA_CMD_INFO2_TID             GENMASK(25, 22)
+#define HAL_TCL_DATA_CMD_INFO2_LMAC_ID         GENMASK(27, 26)
+
+#define HAL_TCL_DATA_CMD_INFO3_DSCP_TID_TABLE_IDX      GENMASK(5, 0)
+#define HAL_TCL_DATA_CMD_INFO3_SEARCH_INDEX            GENMASK(25, 6)
+#define HAL_TCL_DATA_CMD_INFO3_CACHE_SET_NUM           GENMASK(29, 26)
+
+#define HAL_TCL_DATA_CMD_INFO4_RING_ID                 GENMASK(27, 20)
+#define HAL_TCL_DATA_CMD_INFO4_LOOPING_COUNT           GENMASK(31, 28)
+
+enum hal_encrypt_type {
+       HAL_ENCRYPT_TYPE_WEP_40,
+       HAL_ENCRYPT_TYPE_WEP_104,
+       HAL_ENCRYPT_TYPE_TKIP_NO_MIC,
+       HAL_ENCRYPT_TYPE_WEP_128,
+       HAL_ENCRYPT_TYPE_TKIP_MIC,
+       HAL_ENCRYPT_TYPE_WAPI,
+       HAL_ENCRYPT_TYPE_CCMP_128,
+       HAL_ENCRYPT_TYPE_OPEN,
+       HAL_ENCRYPT_TYPE_CCMP_256,
+       HAL_ENCRYPT_TYPE_GCMP_128,
+       HAL_ENCRYPT_TYPE_AES_GCMP_256,
+       HAL_ENCRYPT_TYPE_WAPI_GCM_SM4,
+};
+
+enum hal_tcl_encap_type {
+       HAL_TCL_ENCAP_TYPE_RAW,
+       HAL_TCL_ENCAP_TYPE_NATIVE_WIFI,
+       HAL_TCL_ENCAP_TYPE_ETHERNET,
+       HAL_TCL_ENCAP_TYPE_802_3 = 3,
+};
+
+enum hal_tcl_desc_type {
+       HAL_TCL_DESC_TYPE_BUFFER,
+       HAL_TCL_DESC_TYPE_EXT_DESC,
+};
+
+enum hal_wbm_htt_tx_comp_status {
+       HAL_WBM_REL_HTT_TX_COMP_STATUS_OK,
+       HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP,
+       HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL,
+       HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ,
+       HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT,
+       HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY,
+};
+
+struct hal_tcl_data_cmd {
+       struct ath11k_buffer_addr buf_addr_info;
+       u32 info0;
+       u32 info1;
+       u32 info2;
+       u32 info3;
+       u32 info4;
+} __packed;
+
+/* hal_tcl_data_cmd
+ *
+ * buf_addr_info
+ *             Details of the physical address of a buffer or MSDU
+ *             link descriptor.
+ *
+ * desc_type
+ *             Indicates the type of address provided in the buf_addr_info.
+ *             Values are defined in enum %HAL_REO_DEST_RING_BUFFER_TYPE_.
+ *
+ * epd
+ *             When this bit is set then input packet is an EPD type.
+ *
+ * encap_type
+ *             Indicates the encapsulation that HW will perform. Values are
+ *             defined in enum %HAL_TCL_ENCAP_TYPE_.
+ *
+ * encrypt_type
+ *             Field only valid for encap_type: RAW
+ *             Values are defined in enum %HAL_ENCRYPT_TYPE_.
+ *
+ * src_buffer_swap
+ *             Treats source memory (packet buffer) organization as big-endian.
+ *             1'b0: Source memory is little endian
+ *             1'b1: Source memory is big endian
+ *
+ * link_meta_swap
+ *             Treats link descriptor and Metadata as big-endian.
+ *             1'b0: memory is little endian
+ *             1'b1: memory is big endian
+ *
+ * search_type
+ *             Search type select
+ *             0 - Normal search, 1 - Index based address search,
+ *             2 - Index based flow search
+ *
+ * addrx_en
+ * addry_en
+ *             Address X/Y search enable in ASE correspondingly.
+ *             1'b0: Search disable
+ *             1'b1: Search Enable
+ *
+ * cmd_num
+ *             This number can be used to match against status.
+ *
+ * data_length
+ *             MSDU length in case of direct descriptor. Length of link
+ *             extension descriptor in case of Link extension descriptor.
+ *
+ * *_checksum_en
+ *             Enable checksum replacement for ipv4, udp_over_ipv4, ipv6,
+ *             udp_over_ipv6, tcp_over_ipv4 and tcp_over_ipv6.
+ *
+ * to_fw
+ *             Forward packet to FW along with classification result. The
+ *             packet will not be forward to TQM when this bit is set.
+ *             1'b0: Use classification result to forward the packet.
+ *             1'b1: Override classification result & forward packet only to fw
+ *
+ * packet_offset
+ *             Packet offset from Metadata in case of direct buffer descriptor.
+ *
+ * buffer_timestamp
+ * buffer_timestamp_valid
+ *             Frame system entrance timestamp. It shall be filled by first
+ *             module (SW, TCL or TQM) that sees the frames first.
+ *
+ * mesh_enable
+ *             For raw WiFi frames, this indicates transmission to a mesh STA,
+ *             enabling the interpretation of the 'Mesh Control Present' bit
+ *             (bit 8) of QoS Control.
+ *             For native WiFi frames, this indicates that a 'Mesh Control'
+ *             field is present between the header and the LLC.
+ *
+ * hlos_tid_overwrite
+ *
+ *             When set, TCL shall ignore the IP DSCP and VLAN PCP
+ *             fields and use HLOS_TID as the final TID. Otherwise TCL
+ *             shall consider the DSCP and PCP fields as well as HLOS_TID
+ *             and choose a final TID based on the configured priority
+ *
+ * hlos_tid
+ *             HLOS MSDU priority
+ *             Field is used when HLOS_TID_overwrite is set.
+ *
+ * lmac_id
+ *             TCL uses this LMAC_ID in address search, i.e, while
+ *             finding matching entry for the packet in AST corresponding
+ *             to given LMAC_ID
+ *
+ *             If LMAC ID is all 1s (=> value 3), it indicates wildcard
+ *             match for any MAC
+ *
+ * dscp_tid_table_num
+ *             DSCP to TID mapping table number that need to be used
+ *             for the MSDU.
+ *
+ * search_index
+ *             The index that will be used for index based address or
+ *             flow search. The field is valid when 'search_type' is  1 or 2.
+ *
+ * cache_set_num
+ *
+ *             Cache set number that should be used to cache the index
+ *             based search results, for address and flow search. This
+ *             value should be equal to LSB four bits of the hash value of
+ *             match data, in case of search index points to an entry which
+ *             may be used in content based search also. The value can be
+ *             anything when the entry pointed by search index will not be
+ *             used for content based search.
+ *
+ * ring_id
+ *             The buffer pointer ring ID.
+ *             0 refers to the IDLE ring
+ *             1 - N refers to other rings
+ *
+ * looping_count
+ *
+ *             A count value that indicates the number of times the
+ *             producer of entries into the Ring has looped around the
+ *             ring.
+ *
+ *             At initialization time, this value is set to 0. On the
+ *             first loop, this value is set to 1. After the max value is
+ *             reached allowed by the number of bits for this field, the
+ *             count value continues with 0 again.
+ *
+ *             In case SW is the consumer of the ring entries, it can
+ *             use this field to figure out up to where the producer of
+ *             entries has created new entries. This eliminates the need to
+ *             check where the head pointer' of the ring is located once
+ *             the SW starts processing an interrupt indicating that new
+ *             entries have been put into this ring...
+ *
+ *             Also note that SW if it wants only needs to look at the
+ *             LSB bit of this count value.
+ */
+
+#define HAL_TCL_DESC_LEN sizeof(struct hal_tcl_data_cmd)
+
+enum hal_tcl_gse_ctrl {
+       HAL_TCL_GSE_CTRL_RD_STAT,
+       HAL_TCL_GSE_CTRL_SRCH_DIS,
+       HAL_TCL_GSE_CTRL_WR_BK_SINGLE,
+       HAL_TCL_GSE_CTRL_WR_BK_ALL,
+       HAL_TCL_GSE_CTRL_INVAL_SINGLE,
+       HAL_TCL_GSE_CTRL_INVAL_ALL,
+       HAL_TCL_GSE_CTRL_WR_BK_INVAL_SINGLE,
+       HAL_TCL_GSE_CTRL_WR_BK_INVAL_ALL,
+       HAL_TCL_GSE_CTRL_CLR_STAT_SINGLE,
+};
+
+/* hal_tcl_gse_ctrl
+ *
+ * rd_stat
+ *             Report or Read statistics
+ * srch_dis
+ *             Search disable. Report only Hash.
+ * wr_bk_single
+ *             Write Back single entry
+ * wr_bk_all
+ *             Write Back entire cache entry
+ * inval_single
+ *             Invalidate single cache entry
+ * inval_all
+ *             Invalidate entire cache
+ * wr_bk_inval_single
+ *             Write back and invalidate single entry in cache
+ * wr_bk_inval_all
+ *             Write back and invalidate entire cache
+ * clr_stat_single
+ *             Clear statistics for single entry
+ */
+
+#define HAL_TCL_GSE_CMD_INFO0_CTRL_BUF_ADDR_HI         GENMASK(7, 0)
+#define HAL_TCL_GSE_CMD_INFO0_GSE_CTRL                 GENMASK(11, 8)
+#define HAL_TCL_GSE_CMD_INFO0_GSE_SEL                  BIT(12)
+#define HAL_TCL_GSE_CMD_INFO0_STATUS_DEST_RING_ID      BIT(13)
+#define HAL_TCL_GSE_CMD_INFO0_SWAP                     BIT(14)
+
+#define HAL_TCL_GSE_CMD_INFO1_RING_ID                  GENMASK(27, 20)
+#define HAL_TCL_GSE_CMD_INFO1_LOOPING_COUNT            GENMASK(31, 28)
+
+struct hal_tcl_gse_cmd {
+       u32 ctrl_buf_addr_lo;
+       u32 info0;
+       u32 meta_data[2];
+       u32 rsvd0[2];
+       u32 info1;
+} __packed;
+
+/* hal_tcl_gse_cmd
+ *
+ * ctrl_buf_addr_lo, ctrl_buf_addr_hi
+ *             Address of a control buffer containing additional info needed
+ *             for this command execution.
+ *
+ * gse_ctrl
+ *             GSE control operations. This includes cache operations and table
+ *             entry statistics read/clear operation. Values are defined in
+ *             enum %HAL_TCL_GSE_CTRL.
+ *
+ * gse_sel
+ *             To select the ASE/FSE to do the operation mention by GSE_ctrl.
+ *             0: FSE select 1: ASE select
+ *
+ * status_destination_ring_id
+ *             TCL status ring to which the GSE status needs to be send.
+ *
+ * swap
+ *             Bit to enable byte swapping of contents of buffer.
+ *
+ * meta_data
+ *             Meta data to be returned in the status descriptor
+ */
+
+enum hal_tcl_cache_op_res {
+       HAL_TCL_CACHE_OP_RES_DONE,
+       HAL_TCL_CACHE_OP_RES_NOT_FOUND,
+       HAL_TCL_CACHE_OP_RES_TIMEOUT,
+};
+
+#define HAL_TCL_STATUS_RING_INFO0_GSE_CTRL             GENMASK(3, 0)
+#define HAL_TCL_STATUS_RING_INFO0_GSE_SEL              BIT(4)
+#define HAL_TCL_STATUS_RING_INFO0_CACHE_OP_RES         GENMASK(6, 5)
+#define HAL_TCL_STATUS_RING_INFO0_MSDU_CNT             GENMASK(31, 8)
+
+#define HAL_TCL_STATUS_RING_INFO1_HASH_IDX             GENMASK(19, 0)
+
+#define HAL_TCL_STATUS_RING_INFO2_RING_ID              GENMASK(27, 20)
+#define HAL_TCL_STATUS_RING_INFO2_LOOPING_COUNT                GENMASK(31, 28)
+
+struct hal_tcl_status_ring {
+       u32 info0;
+       u32 msdu_byte_count;
+       u32 msdu_timestamp;
+       u32 meta_data[2];
+       u32 info1;
+       u32 rsvd0;
+       u32 info2;
+} __packed;
+
+/* hal_tcl_status_ring
+ *
+ * gse_ctrl
+ *             GSE control operations. This includes cache operations and table
+ *             entry statistics read/clear operation. Values are defined in
+ *             enum %HAL_TCL_GSE_CTRL.
+ *
+ * gse_sel
+ *             To select the ASE/FSE to do the operation mention by GSE_ctrl.
+ *             0: FSE select 1: ASE select
+ *
+ * cache_op_res
+ *             Cache operation result. Values are defined in enum
+ *             %HAL_TCL_CACHE_OP_RES_.
+ *
+ * msdu_cnt
+ * msdu_byte_count
+ *             MSDU count of Entry and MSDU byte count for entry 1.
+ *
+ * hash_indx
+ *             Hash value of the entry in case of search failed or disabled.
+ */
+
+#define HAL_CE_SRC_DESC_ADDR_INFO_ADDR_HI      GENMASK(7, 0)
+#define HAL_CE_SRC_DESC_ADDR_INFO_HASH_EN      BIT(8)
+#define HAL_CE_SRC_DESC_ADDR_INFO_BYTE_SWAP    BIT(9)
+#define HAL_CE_SRC_DESC_ADDR_INFO_DEST_SWAP    BIT(10)
+#define HAL_CE_SRC_DESC_ADDR_INFO_GATHER       BIT(11)
+#define HAL_CE_SRC_DESC_ADDR_INFO_LEN          GENMASK(31, 16)
+
+#define HAL_CE_SRC_DESC_META_INFO_DATA         GENMASK(15, 0)
+
+#define HAL_CE_SRC_DESC_FLAGS_RING_ID          GENMASK(27, 20)
+#define HAL_CE_SRC_DESC_FLAGS_LOOP_CNT         HAL_SRNG_DESC_LOOP_CNT
+
+struct hal_ce_srng_src_desc {
+       u32 buffer_addr_low;
+       u32 buffer_addr_info; /* %HAL_CE_SRC_DESC_ADDR_INFO_ */
+       u32 meta_info; /* %HAL_CE_SRC_DESC_META_INFO_ */
+       u32 flags; /* %HAL_CE_SRC_DESC_FLAGS_ */
+} __packed;
+
+/*
+ * hal_ce_srng_src_desc
+ *
+ * buffer_addr_lo
+ *             LSB 32 bits of the 40 Bit Pointer to the source buffer
+ *
+ * buffer_addr_hi
+ *             MSB 8 bits of the 40 Bit Pointer to the source buffer
+ *
+ * toeplitz_en
+ *             Enable generation of 32-bit Toeplitz-LFSR hash for
+ *             data transfer. In case of gather field in first source
+ *             ring entry of the gather copy cycle in taken into account.
+ *
+ * src_swap
+ *             Treats source memory organization as big-endian. For
+ *             each dword read (4 bytes), the byte 0 is swapped with byte 3
+ *             and byte 1 is swapped with byte 2.
+ *             In case of gather field in first source ring entry of
+ *             the gather copy cycle in taken into account.
+ *
+ * dest_swap
+ *             Treats destination memory organization as big-endian.
+ *             For each dword write (4 bytes), the byte 0 is swapped with
+ *             byte 3 and byte 1 is swapped with byte 2.
+ *             In case of gather field in first source ring entry of
+ *             the gather copy cycle in taken into account.
+ *
+ * gather
+ *             Enables gather of multiple copy engine source
+ *             descriptors to one destination.
+ *
+ * ce_res_0
+ *             Reserved
+ *
+ *
+ * length
+ *             Length of the buffer in units of octets of the current
+ *             descriptor
+ *
+ * fw_metadata
+ *             Meta data used by FW.
+ *             In case of gather field in first source ring entry of
+ *             the gather copy cycle in taken into account.
+ *
+ * ce_res_1
+ *             Reserved
+ *
+ * ce_res_2
+ *             Reserved
+ *
+ * ring_id
+ *             The buffer pointer ring ID.
+ *             0 refers to the IDLE ring
+ *             1 - N refers to other rings
+ *             Helps with debugging when dumping ring contents.
+ *
+ * looping_count
+ *             A count value that indicates the number of times the
+ *             producer of entries into the Ring has looped around the
+ *             ring.
+ *
+ *             At initialization time, this value is set to 0. On the
+ *             first loop, this value is set to 1. After the max value is
+ *             reached allowed by the number of bits for this field, the
+ *             count value continues with 0 again.
+ *
+ *             In case SW is the consumer of the ring entries, it can
+ *             use this field to figure out up to where the producer of
+ *             entries has created new entries. This eliminates the need to
+ *             check where the head pointer' of the ring is located once
+ *             the SW starts processing an interrupt indicating that new
+ *             entries have been put into this ring...
+ *
+ *             Also note that SW if it wants only needs to look at the
+ *             LSB bit of this count value.
+ */
+
+#define HAL_CE_DEST_DESC_ADDR_INFO_ADDR_HI             GENMASK(7, 0)
+#define HAL_CE_DEST_DESC_ADDR_INFO_RING_ID             GENMASK(27, 20)
+#define HAL_CE_DEST_DESC_ADDR_INFO_LOOP_CNT            HAL_SRNG_DESC_LOOP_CNT
+
+struct hal_ce_srng_dest_desc {
+       u32 buffer_addr_low;
+       u32 buffer_addr_info; /* %HAL_CE_DEST_DESC_ADDR_INFO_ */
+} __packed;
+
+/* hal_ce_srng_dest_desc
+ *
+ * dst_buffer_low
+ *             LSB 32 bits of the 40 Bit Pointer to the Destination
+ *             buffer
+ *
+ * dst_buffer_high
+ *             MSB 8 bits of the 40 Bit Pointer to the Destination
+ *             buffer
+ *
+ * ce_res_4
+ *             Reserved
+ *
+ * ring_id
+ *             The buffer pointer ring ID.
+ *             0 refers to the IDLE ring
+ *             1 - N refers to other rings
+ *             Helps with debugging when dumping ring contents.
+ *
+ * looping_count
+ *             A count value that indicates the number of times the
+ *             producer of entries into the Ring has looped around the
+ *             ring.
+ *
+ *             At initialization time, this value is set to 0. On the
+ *             first loop, this value is set to 1. After the max value is
+ *             reached allowed by the number of bits for this field, the
+ *             count value continues with 0 again.
+ *
+ *             In case SW is the consumer of the ring entries, it can
+ *             use this field to figure out up to where the producer of
+ *             entries has created new entries. This eliminates the need to
+ *             check where the head pointer' of the ring is located once
+ *             the SW starts processing an interrupt indicating that new
+ *             entries have been put into this ring...
+ *
+ *             Also note that SW if it wants only needs to look at the
+ *             LSB bit of this count value.
+ */
+
+#define HAL_CE_DST_STATUS_DESC_FLAGS_HASH_EN           BIT(8)
+#define HAL_CE_DST_STATUS_DESC_FLAGS_BYTE_SWAP         BIT(9)
+#define HAL_CE_DST_STATUS_DESC_FLAGS_DEST_SWAP         BIT(10)
+#define HAL_CE_DST_STATUS_DESC_FLAGS_GATHER            BIT(11)
+#define HAL_CE_DST_STATUS_DESC_FLAGS_LEN               GENMASK(31, 16)
+
+#define HAL_CE_DST_STATUS_DESC_META_INFO_DATA          GENMASK(7, 0)
+#define HAL_CE_DST_STATUS_DESC_META_INFO_RING_ID       GENMASK(27, 20)
+#define HAL_CE_DST_STATUS_DESC_META_INFO_LOOP_CNT      HAL_SRNG_DESC_LOOP_CNT
+
+struct hal_ce_srng_dst_status_desc {
+       u32 flags; /* %HAL_CE_DST_STATUS_DESC_FLAGS_ */
+       u32 toeplitz_hash0;
+       u32 toeplitz_hash1;
+       u32 meta_info; /* HAL_CE_DST_STATUS_DESC_META_INFO_ */
+} __packed;
+
+/* hal_ce_srng_dst_status_desc
+ *
+ * ce_res_5
+ *             Reserved
+ *
+ * toeplitz_en
+ *
+ * src_swap
+ *             Source memory buffer swapped
+ *
+ * dest_swap
+ *             Destination  memory buffer swapped
+ *
+ * gather
+ *             Gather of multiple copy engine source descriptors to one
+ *             destination enabled
+ *
+ * ce_res_6
+ *             Reserved
+ *
+ * length
+ *             Sum of all the Lengths of the source descriptor in the
+ *             gather chain
+ *
+ * toeplitz_hash_0
+ *             32 LS bits of 64 bit Toeplitz LFSR hash result
+ *
+ * toeplitz_hash_1
+ *             32 MS bits of 64 bit Toeplitz LFSR hash result
+ *
+ * fw_metadata
+ *             Meta data used by FW
+ *             In case of gather field in first source ring entry of
+ *             the gather copy cycle in taken into account.
+ *
+ * ce_res_7
+ *             Reserved
+ *
+ * ring_id
+ *             The buffer pointer ring ID.
+ *             0 refers to the IDLE ring
+ *             1 - N refers to other rings
+ *             Helps with debugging when dumping ring contents.
+ *
+ * looping_count
+ *             A count value that indicates the number of times the
+ *             producer of entries into the Ring has looped around the
+ *             ring.
+ *
+ *             At initialization time, this value is set to 0. On the
+ *             first loop, this value is set to 1. After the max value is
+ *             reached allowed by the number of bits for this field, the
+ *             count value continues with 0 again.
+ *
+ *             In case SW is the consumer of the ring entries, it can
+ *             use this field to figure out up to where the producer of
+ *             entries has created new entries. This eliminates the need to
+ *             check where the head pointer' of the ring is located once
+ *             the SW starts processing an interrupt indicating that new
+ *             entries have been put into this ring...
+ *
+ *             Also note that SW if it wants only needs to look at the
+ *                     LSB bit of this count value.
+ */
+
+#define HAL_TX_RATE_STATS_INFO0_VALID          BIT(0)
+#define HAL_TX_RATE_STATS_INFO0_BW             GENMASK(2, 1)
+#define HAL_TX_RATE_STATS_INFO0_PKT_TYPE       GENMASK(6, 3)
+#define HAL_TX_RATE_STATS_INFO0_STBC           BIT(7)
+#define HAL_TX_RATE_STATS_INFO0_LDPC           BIT(8)
+#define HAL_TX_RATE_STATS_INFO0_SGI            GENMASK(10, 9)
+#define HAL_TX_RATE_STATS_INFO0_MCS            GENMASK(14, 11)
+#define HAL_TX_RATE_STATS_INFO0_OFDMA_TX       BIT(15)
+#define HAL_TX_RATE_STATS_INFO0_TONES_IN_RU    GENMASK(27, 16)
+
+enum hal_tx_rate_stats_bw {
+       HAL_TX_RATE_STATS_BW_20,
+       HAL_TX_RATE_STATS_BW_40,
+       HAL_TX_RATE_STATS_BW_80,
+       HAL_TX_RATE_STATS_BW_160,
+};
+
+enum hal_tx_rate_stats_pkt_type {
+       HAL_TX_RATE_STATS_PKT_TYPE_11A,
+       HAL_TX_RATE_STATS_PKT_TYPE_11B,
+       HAL_TX_RATE_STATS_PKT_TYPE_11N,
+       HAL_TX_RATE_STATS_PKT_TYPE_11AC,
+       HAL_TX_RATE_STATS_PKT_TYPE_11AX,
+};
+
+enum hal_tx_rate_stats_sgi {
+       HAL_TX_RATE_STATS_SGI_08US,
+       HAL_TX_RATE_STATS_SGI_04US,
+       HAL_TX_RATE_STATS_SGI_16US,
+       HAL_TX_RATE_STATS_SGI_32US,
+};
+
+struct hal_tx_rate_stats {
+       u32 info0;
+       u32 tsf;
+} __packed;
+
+struct hal_wbm_link_desc {
+       struct ath11k_buffer_addr buf_addr_info;
+} __packed;
+
+/* hal_wbm_link_desc
+ *
+ *     Producer: WBM
+ *     Consumer: WBM
+ *
+ * buf_addr_info
+ *             Details of the physical address of a buffer or MSDU
+ *             link descriptor.
+ */
+
+enum hal_wbm_rel_src_module {
+       HAL_WBM_REL_SRC_MODULE_TQM,
+       HAL_WBM_REL_SRC_MODULE_RXDMA,
+       HAL_WBM_REL_SRC_MODULE_REO,
+       HAL_WBM_REL_SRC_MODULE_FW,
+       HAL_WBM_REL_SRC_MODULE_SW,
+};
+
+enum hal_wbm_rel_desc_type {
+       HAL_WBM_REL_DESC_TYPE_REL_MSDU,
+       HAL_WBM_REL_DESC_TYPE_MSDU_LINK,
+       HAL_WBM_REL_DESC_TYPE_MPDU_LINK,
+       HAL_WBM_REL_DESC_TYPE_MSDU_EXT,
+       HAL_WBM_REL_DESC_TYPE_QUEUE_EXT,
+};
+
+/* hal_wbm_rel_desc_type
+ *
+ * msdu_buffer
+ *     The address points to an MSDU buffer
+ *
+ * msdu_link_descriptor
+ *     The address points to an Tx MSDU link descriptor
+ *
+ * mpdu_link_descriptor
+ *     The address points to an MPDU link descriptor
+ *
+ * msdu_ext_descriptor
+ *     The address points to an MSDU extension descriptor
+ *
+ * queue_ext_descriptor
+ *     The address points to an TQM queue extension descriptor. WBM should
+ *     treat this is the same way as a link descriptor.
+ */
+
+enum hal_wbm_rel_bm_act {
+       HAL_WBM_REL_BM_ACT_PUT_IN_IDLE,
+       HAL_WBM_REL_BM_ACT_REL_MSDU,
+};
+
+/* hal_wbm_rel_bm_act
+ *
+ * put_in_idle_list
+ *     Put the buffer or descriptor back in the idle list. In case of MSDU or
+ *     MDPU link descriptor, BM does not need to check to release any
+ *     individual MSDU buffers.
+ *
+ * release_msdu_list
+ *     This BM action can only be used in combination with desc_type being
+ *     msdu_link_descriptor. Field first_msdu_index points out which MSDU
+ *     pointer in the MSDU link descriptor is the first of an MPDU that is
+ *     released. BM shall release all the MSDU buffers linked to this first
+ *     MSDU buffer pointer. All related MSDU buffer pointer entries shall be
+ *     set to value 0, which represents the 'NULL' pointer. When all MSDU
+ *     buffer pointers in the MSDU link descriptor are 'NULL', the MSDU link
+ *     descriptor itself shall also be released.
+ */
+
+#define HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE           GENMASK(2, 0)
+#define HAL_WBM_RELEASE_INFO0_BM_ACTION                        GENMASK(5, 3)
+#define HAL_WBM_RELEASE_INFO0_DESC_TYPE                        GENMASK(8, 6)
+#define HAL_WBM_RELEASE_INFO0_FIRST_MSDU_IDX           GENMASK(12, 9)
+#define HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON       GENMASK(16, 13)
+#define HAL_WBM_RELEASE_INFO0_RXDMA_PUSH_REASON                GENMASK(18, 17)
+#define HAL_WBM_RELEASE_INFO0_RXDMA_ERROR_CODE         GENMASK(23, 19)
+#define HAL_WBM_RELEASE_INFO0_REO_PUSH_REASON          GENMASK(25, 24)
+#define HAL_WBM_RELEASE_INFO0_REO_ERROR_CODE           GENMASK(30, 26)
+#define HAL_WBM_RELEASE_INFO0_WBM_INTERNAL_ERROR       BIT(31)
+
+#define HAL_WBM_RELEASE_INFO1_TQM_STATUS_NUMBER                GENMASK(23, 0)
+#define HAL_WBM_RELEASE_INFO1_TRANSMIT_COUNT           GENMASK(30, 24)
+
+#define HAL_WBM_RELEASE_INFO2_ACK_FRAME_RSSI           GENMASK(7, 0)
+#define HAL_WBM_RELEASE_INFO2_SW_REL_DETAILS_VALID     BIT(8)
+#define HAL_WBM_RELEASE_INFO2_FIRST_MSDU               BIT(9)
+#define HAL_WBM_RELEASE_INFO2_LAST_MSDU                        BIT(10)
+#define HAL_WBM_RELEASE_INFO2_MSDU_IN_AMSDU            BIT(11)
+#define HAL_WBM_RELEASE_INFO2_FW_TX_NOTIF_FRAME                BIT(12)
+#define HAL_WBM_RELEASE_INFO2_BUFFER_TIMESTAMP         GENMASK(31, 13)
+
+#define HAL_WBM_RELEASE_INFO3_PEER_ID                  GENMASK(15, 0)
+#define HAL_WBM_RELEASE_INFO3_TID                      GENMASK(19, 16)
+#define HAL_WBM_RELEASE_INFO3_RING_ID                  GENMASK(27, 20)
+#define HAL_WBM_RELEASE_INFO3_LOOPING_COUNT            GENMASK(31, 28)
+
+#define HAL_WBM_REL_HTT_TX_COMP_INFO0_STATUS           GENMASK(12, 9)
+#define HAL_WBM_REL_HTT_TX_COMP_INFO0_REINJ_REASON     GENMASK(16, 13)
+#define HAL_WBM_REL_HTT_TX_COMP_INFO0_EXP_FRAME                BIT(17)
+
+struct hal_wbm_release_ring {
+       struct ath11k_buffer_addr buf_addr_info;
+       u32 info0;
+       u32 info1;
+       u32 info2;
+       struct hal_tx_rate_stats rate_stats;
+       u32 info3;
+} __packed;
+
+/* hal_wbm_release_ring
+ *
+ *     Producer: SW/TQM/RXDMA/REO/SWITCH
+ *     Consumer: WBM/SW/FW
+ *
+ * HTT tx status is overlayed on wbm_release ring on 4-byte words 2, 3, 4 and 5
+ * for software based completions.
+ *
+ * buf_addr_info
+ *     Details of the physical address of the buffer or link descriptor.
+ *
+ * release_source_module
+ *     Indicates which module initiated the release of this buffer/descriptor.
+ *     Values are defined in enum %HAL_WBM_REL_SRC_MODULE_.
+ *
+ * bm_action
+ *     Field only valid when the field return_buffer_manager in
+ *     Released_buff_or_desc_addr_info indicates:
+ *             WBM_IDLE_BUF_LIST / WBM_IDLE_DESC_LIST
+ *     Values are defined in enum %HAL_WBM_REL_BM_ACT_.
+ *
+ * buffer_or_desc_type
+ *     Field only valid when WBM is marked as the return_buffer_manager in
+ *     the Released_Buffer_address_info. Indicates that type of buffer or
+ *     descriptor is being released. Values are in enum %HAL_WBM_REL_DESC_TYPE.
+ *
+ * first_msdu_index
+ *     Field only valid for the bm_action release_msdu_list. The index of the
+ *     first MSDU in an MSDU link descriptor all belonging to the same MPDU.
+ *
+ * tqm_release_reason
+ *     Field only valid when Release_source_module is set to release_source_TQM
+ *     Release reasons are defined in enum %HAL_WBM_TQM_REL_REASON_.
+ *
+ * rxdma_push_reason
+ * reo_push_reason
+ *     Indicates why rxdma/reo pushed the frame to this ring and values are
+ *     defined in enum %HAL_REO_DEST_RING_PUSH_REASON_.
+ *
+ * rxdma_error_code
+ *     Field only valid when 'rxdma_push_reason' set to 'error_detected'.
+ *     Values are defined in enum %HAL_REO_ENTR_RING_RXDMA_ECODE_.
+ *
+ * reo_error_code
+ *     Field only valid when 'reo_push_reason' set to 'error_detected'. Values
+ *     are defined in enum %HAL_REO_DEST_RING_ERROR_CODE_.
+ *
+ * wbm_internal_error
+ *     Is set when WBM got a buffer pointer but the action was to push it to
+ *     the idle link descriptor ring or do link related activity OR
+ *     Is set when WBM got a link buffer pointer but the action was to push it
+ *     to the buffer descriptor ring.
+ *
+ * tqm_status_number
+ *     The value in this field is equal to tqm_cmd_number in TQM command. It is
+ *     used to correlate the statu with TQM commands. Only valid when
+ *     release_source_module is TQM.
+ *
+ * transmit_count
+ *     The number of times the frame has been transmitted, valid only when
+ *     release source in TQM.
+ *
+ * ack_frame_rssi
+ *     This field is only valid when the source is TQM. If this frame is
+ *     removed as the result of the reception of an ACK or BA, this field
+ *     indicates the RSSI of the received ACK or BA frame.
+ *
+ * sw_release_details_valid
+ *     This is set when WMB got a 'release_msdu_list' command from TQM and
+ *     return buffer manager is not WMB. WBM will then de-aggregate all MSDUs
+ *     and pass them one at a time on to the 'buffer owner'.
+ *
+ * first_msdu
+ *     Field only valid when SW_release_details_valid is set.
+ *     When set, this MSDU is the first MSDU pointed to in the
+ *     'release_msdu_list' command.
+ *
+ * last_msdu
+ *     Field only valid when SW_release_details_valid is set.
+ *     When set, this MSDU is the last MSDU pointed to in the
+ *     'release_msdu_list' command.
+ *
+ * msdu_part_of_amsdu
+ *     Field only valid when SW_release_details_valid is set.
+ *     When set, this MSDU was part of an A-MSDU in MPDU
+ *
+ * fw_tx_notify_frame
+ *     Field only valid when SW_release_details_valid is set.
+ *
+ * buffer_timestamp
+ *     Field only valid when SW_release_details_valid is set.
+ *     This is the Buffer_timestamp field from the
+ *     Timestamp in units of 1024 us
+ *
+ * struct hal_tx_rate_stats rate_stats
+ *     Details for command execution tracking purposes.
+ *
+ * sw_peer_id
+ * tid
+ *     Field only valid when Release_source_module is set to
+ *     release_source_TQM
+ *
+ *     1) Release of msdu buffer due to drop_frame = 1. Flow is
+ *     not fetched and hence sw_peer_id and tid = 0
+ *
+ *     buffer_or_desc_type = e_num 0
+ *     MSDU_rel_buffertqm_release_reason = e_num 1
+ *     tqm_rr_rem_cmd_rem
+ *
+ *     2) Release of msdu buffer due to Flow is not fetched and
+ *     hence sw_peer_id and tid = 0
+ *
+ *     buffer_or_desc_type = e_num 0
+ *     MSDU_rel_buffertqm_release_reason = e_num 1
+ *     tqm_rr_rem_cmd_rem
+ *
+ *     3) Release of msdu link due to remove_mpdu or acked_mpdu
+ *     command.
+ *
+ *     buffer_or_desc_type = e_num1
+ *     msdu_link_descriptortqm_release_reason can be:e_num 1
+ *     tqm_rr_rem_cmd_reme_num 2 tqm_rr_rem_cmd_tx
+ *     e_num 3 tqm_rr_rem_cmd_notxe_num 4 tqm_rr_rem_cmd_aged
+ *
+ *     This field represents the TID from the TX_MSDU_FLOW
+ *     descriptor or TX_MPDU_QUEUE descriptor
+ *
+ * rind_id
+ *     For debugging.
+ *     This field is filled in by the SRNG module.
+ *     It help to identify the ring that is being looked
+ *
+ * looping_count
+ *     A count value that indicates the number of times the
+ *     producer of entries into the Buffer Manager Ring has looped
+ *     around the ring.
+ *
+ *     At initialization time, this value is set to 0. On the
+ *     first loop, this value is set to 1. After the max value is
+ *     reached allowed by the number of bits for this field, the
+ *     count value continues with 0 again.
+ *
+ *     In case SW is the consumer of the ring entries, it can
+ *     use this field to figure out up to where the producer of
+ *     entries has created new entries. This eliminates the need to
+ *     check where the head pointer' of the ring is located once
+ *     the SW starts processing an interrupt indicating that new
+ *     entries have been put into this ring...
+ *
+ *     Also note that SW if it wants only needs to look at the
+ *     LSB bit of this count value.
+ */
+
+/**
+ * enum hal_wbm_tqm_rel_reason - TQM release reason code
+ * @HAL_WBM_TQM_REL_REASON_FRAME_ACKED: ACK or BACK received for the frame
+ * @HAL_WBM_TQM_REL_REASON_CMD_REMOVE_MPDU: Command remove_mpdus initiated by SW
+ * @HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX: Command remove transmitted_mpdus
+ *     initiated by sw.
+ * @HAL_WBM_TQM_REL_REASON_CMD_REMOVE_NOTX: Command remove untransmitted_mpdus
+ *     initiated by sw.
+ * @HAL_WBM_TQM_REL_REASON_CMD_REMOVE_AGED_FRAMES: Command remove aged msdus or
+ *     mpdus.
+ * @HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON1: Remove command initiated by
+ *     fw with fw_reason1.
+ * @HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON2: Remove command initiated by
+ *     fw with fw_reason2.
+ * @HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON3: Remove command initiated by
+ *     fw with fw_reason3.
+ */
+enum hal_wbm_tqm_rel_reason {
+       HAL_WBM_TQM_REL_REASON_FRAME_ACKED,
+       HAL_WBM_TQM_REL_REASON_CMD_REMOVE_MPDU,
+       HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX,
+       HAL_WBM_TQM_REL_REASON_CMD_REMOVE_NOTX,
+       HAL_WBM_TQM_REL_REASON_CMD_REMOVE_AGED_FRAMES,
+       HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON1,
+       HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON2,
+       HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON3,
+};
+
+struct hal_wbm_buffer_ring {
+       struct ath11k_buffer_addr buf_addr_info;
+};
+
+enum hal_desc_owner {
+       HAL_DESC_OWNER_WBM,
+       HAL_DESC_OWNER_SW,
+       HAL_DESC_OWNER_TQM,
+       HAL_DESC_OWNER_RXDMA,
+       HAL_DESC_OWNER_REO,
+       HAL_DESC_OWNER_SWITCH,
+};
+
+enum hal_desc_buf_type {
+       HAL_DESC_BUF_TYPE_TX_MSDU_LINK,
+       HAL_DESC_BUF_TYPE_TX_MPDU_LINK,
+       HAL_DESC_BUF_TYPE_TX_MPDU_QUEUE_HEAD,
+       HAL_DESC_BUF_TYPE_TX_MPDU_QUEUE_EXT,
+       HAL_DESC_BUF_TYPE_TX_FLOW,
+       HAL_DESC_BUF_TYPE_TX_BUFFER,
+       HAL_DESC_BUF_TYPE_RX_MSDU_LINK,
+       HAL_DESC_BUF_TYPE_RX_MPDU_LINK,
+       HAL_DESC_BUF_TYPE_RX_REO_QUEUE,
+       HAL_DESC_BUF_TYPE_RX_REO_QUEUE_EXT,
+       HAL_DESC_BUF_TYPE_RX_BUFFER,
+       HAL_DESC_BUF_TYPE_IDLE_LINK,
+};
+
+#define HAL_DESC_REO_OWNED             4
+#define HAL_DESC_REO_QUEUE_DESC                8
+#define HAL_DESC_REO_QUEUE_EXT_DESC    9
+#define HAL_DESC_REO_NON_QOS_TID       16
+
+#define HAL_DESC_HDR_INFO0_OWNER       GENMASK(3, 0)
+#define HAL_DESC_HDR_INFO0_BUF_TYPE    GENMASK(7, 4)
+#define HAL_DESC_HDR_INFO0_DBG_RESERVED        GENMASK(31, 8)
+
+struct hal_desc_header {
+       u32 info0;
+} __packed;
+
+struct hal_rx_mpdu_link_ptr {
+       struct ath11k_buffer_addr addr_info;
+} __packed;
+
+struct hal_rx_msdu_details {
+       struct ath11k_buffer_addr buf_addr_info;
+       struct rx_msdu_desc rx_msdu_info;
+} __packed;
+
+#define HAL_RX_MSDU_LNK_INFO0_RX_QUEUE_NUMBER          GENMASK(15, 0)
+#define HAL_RX_MSDU_LNK_INFO0_FIRST_MSDU_LNK           BIT(16)
+
+struct hal_rx_msdu_link {
+       struct hal_desc_header desc_hdr;
+       struct ath11k_buffer_addr buf_addr_info;
+       u32 info0;
+       u32 pn[4];
+       struct hal_rx_msdu_details msdu_link[6];
+} __packed;
+
+struct hal_rx_reo_queue_ext {
+       struct hal_desc_header desc_hdr;
+       u32 rsvd;
+       struct hal_rx_mpdu_link_ptr mpdu_link[15];
+} __packed;
+
+/* hal_rx_reo_queue_ext
+ *     Consumer: REO
+ *     Producer: REO
+ *
+ * descriptor_header
+ *     Details about which module owns this struct.
+ *
+ * mpdu_link
+ *     Pointer to the next MPDU_link descriptor in the MPDU queue.
+ */
+
+enum hal_rx_reo_queue_pn_size {
+       HAL_RX_REO_QUEUE_PN_SIZE_24,
+       HAL_RX_REO_QUEUE_PN_SIZE_48,
+       HAL_RX_REO_QUEUE_PN_SIZE_128,
+};
+
+#define HAL_RX_REO_QUEUE_RX_QUEUE_NUMBER               GENMASK(15, 0)
+
+#define HAL_RX_REO_QUEUE_INFO0_VLD                     BIT(0)
+#define HAL_RX_REO_QUEUE_INFO0_ASSOC_LNK_DESC_COUNTER  GENMASK(2, 1)
+#define HAL_RX_REO_QUEUE_INFO0_DIS_DUP_DETECTION       BIT(3)
+#define HAL_RX_REO_QUEUE_INFO0_SOFT_REORDER_EN         BIT(4)
+#define HAL_RX_REO_QUEUE_INFO0_AC                      GENMASK(6, 5)
+#define HAL_RX_REO_QUEUE_INFO0_BAR                     BIT(7)
+#define HAL_RX_REO_QUEUE_INFO0_RETRY                   BIT(8)
+#define HAL_RX_REO_QUEUE_INFO0_CHECK_2K_MODE           BIT(9)
+#define HAL_RX_REO_QUEUE_INFO0_OOR_MODE                        BIT(10)
+#define HAL_RX_REO_QUEUE_INFO0_BA_WINDOW_SIZE          GENMASK(18, 11)
+#define HAL_RX_REO_QUEUE_INFO0_PN_CHECK                        BIT(19)
+#define HAL_RX_REO_QUEUE_INFO0_EVEN_PN                 BIT(20)
+#define HAL_RX_REO_QUEUE_INFO0_UNEVEN_PN               BIT(21)
+#define HAL_RX_REO_QUEUE_INFO0_PN_HANDLE_ENABLE                BIT(22)
+#define HAL_RX_REO_QUEUE_INFO0_PN_SIZE                 GENMASK(24, 23)
+#define HAL_RX_REO_QUEUE_INFO0_IGNORE_AMPDU_FLG                BIT(25)
+
+#define HAL_RX_REO_QUEUE_INFO1_SVLD                    BIT(0)
+#define HAL_RX_REO_QUEUE_INFO1_SSN                     GENMASK(12, 1)
+#define HAL_RX_REO_QUEUE_INFO1_CURRENT_IDX             GENMASK(20, 13)
+#define HAL_RX_REO_QUEUE_INFO1_SEQ_2K_ERR              BIT(21)
+#define HAL_RX_REO_QUEUE_INFO1_PN_ERR                  BIT(22)
+#define HAL_RX_REO_QUEUE_INFO1_PN_VALID                        BIT(31)
+
+#define HAL_RX_REO_QUEUE_INFO2_MPDU_COUNT              GENMASK(6, 0)
+#define HAL_RX_REO_QUEUE_INFO2_MSDU_COUNT              (31, 7)
+
+#define HAL_RX_REO_QUEUE_INFO3_TIMEOUT_COUNT           GENMASK(9, 4)
+#define HAL_RX_REO_QUEUE_INFO3_FWD_DUE_TO_BAR_CNT      GENMASK(15, 10)
+#define HAL_RX_REO_QUEUE_INFO3_DUPLICATE_COUNT         GENMASK(31, 10)
+
+#define HAL_RX_REO_QUEUE_INFO4_FRAME_IN_ORD_COUNT      GENMASK(23, 0)
+#define HAL_RX_REO_QUEUE_INFO4_BAR_RECVD_COUNT         GENMASK(31, 24)
+
+#define HAL_RX_REO_QUEUE_INFO5_LATE_RX_MPDU_COUNT      GENMASK(11, 0)
+#define HAL_RX_REO_QUEUE_INFO5_WINDOW_JUMP_2K          GENMASK(15, 12)
+#define HAL_RX_REO_QUEUE_INFO5_HOLE_COUNT              GENMASK(31, 16)
+
+struct hal_rx_reo_queue {
+       struct hal_desc_header desc_hdr;
+       u32 rx_queue_num;
+       u32 info0;
+       u32 info1;
+       u32 pn[4];
+       u32 last_rx_enqueue_timestamp;
+       u32 last_rx_dequeue_timestamp;
+       u32 next_aging_queue[2];
+       u32 prev_aging_queue[2];
+       u32 rx_bitmap[8];
+       u32 info2;
+       u32 info3;
+       u32 info4;
+       u32 processed_mpdus;
+       u32 processed_msdus;
+       u32 processed_total_bytes;
+       u32 info5;
+       u32 rsvd[3];
+       struct hal_rx_reo_queue_ext ext_desc[0];
+} __packed;
+
+/* hal_rx_reo_queue
+ *
+ * descriptor_header
+ *     Details about which module owns this struct. Note that sub field
+ *     Buffer_type shall be set to receive_reo_queue_descriptor.
+ *
+ * receive_queue_number
+ *     Indicates the MPDU queue ID to which this MPDU link descriptor belongs.
+ *
+ * vld
+ *     Valid bit indicating a session is established and the queue descriptor
+ *     is valid.
+ * associated_link_descriptor_counter
+ *     Indicates which of the 3 link descriptor counters shall be incremented
+ *     or decremented when link descriptors are added or removed from this
+ *     flow queue.
+ * disable_duplicate_detection
+ *     When set, do not perform any duplicate detection.
+ * soft_reorder_enable
+ *     When set, REO has been instructed to not perform the actual re-ordering
+ *     of frames for this queue, but just to insert the reorder opcodes.
+ * ac
+ *     Indicates the access category of the queue descriptor.
+ * bar
+ *     Indicates if BAR has been received.
+ * retry
+ *     Retry bit is checked if this bit is set.
+ * chk_2k_mode
+ *     Indicates what type of operation is expected from Reo when the received
+ *     frame SN falls within the 2K window.
+ * oor_mode
+ *     Indicates what type of operation is expected when the received frame
+ *     falls within the OOR window.
+ * ba_window_size
+ *     Indicates the negotiated (window size + 1). Max of 256 bits.
+ *
+ *     A value 255 means 256 bitmap, 63 means 64 bitmap, 0 (means non-BA
+ *     session, with window size of 0). The 3 values here are the main values
+ *     validated, but other values should work as well.
+ *
+ *     A BA window size of 0 (=> one frame entry bitmat), means that there is
+ *     no additional rx_reo_queue_ext desc. following rx_reo_queue in memory.
+ *     A BA window size of 1 - 105, means that there is 1 rx_reo_queue_ext.
+ *     A BA window size of 106 - 210, means that there are 2 rx_reo_queue_ext.
+ *     A BA window size of 211 - 256, means that there are 3 rx_reo_queue_ext.
+ * pn_check_needed, pn_shall_be_even, pn_shall_be_uneven, pn_handling_enable,
+ * pn_size
+ *     REO shall perform the PN increment check, even number check, uneven
+ *     number check, PN error check and size of the PN field check.
+ * ignore_ampdu_flag
+ *     REO shall ignore the ampdu_flag on entrance descriptor for this queue.
+ *
+ * svld
+ *     Sequence number in next field is valid one.
+ * ssn
+ *      Starting Sequence number of the session.
+ * current_index
+ *     Points to last forwarded packet
+ * seq_2k_error_detected_flag
+ *     REO has detected a 2k error jump in the sequence number and from that
+ *     moment forward, all new frames are forwarded directly to FW, without
+ *     duplicate detect, reordering, etc.
+ * pn_error_detected_flag
+ *     REO has detected a PN error.
+ */
+
+#define HAL_REO_UPD_RX_QUEUE_INFO0_QUEUE_ADDR_HI               GENMASK(7, 0)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_RX_QUEUE_NUM            BIT(8)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_VLD                     BIT(9)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_ASSOC_LNK_DESC_CNT      BIT(10)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_DIS_DUP_DETECTION       BIT(11)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_SOFT_REORDER_EN         BIT(12)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_AC                      BIT(13)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_BAR                     BIT(14)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_RETRY                   BIT(15)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_CHECK_2K_MODE           BIT(16)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_OOR_MODE                        BIT(17)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_BA_WINDOW_SIZE          BIT(18)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN_CHECK                        BIT(19)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_EVEN_PN                 BIT(20)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_UNEVEN_PN               BIT(21)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN_HANDLE_ENABLE                BIT(22)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN_SIZE                 BIT(23)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_IGNORE_AMPDU_FLG                BIT(24)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_SVLD                    BIT(25)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_SSN                     BIT(26)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_SEQ_2K_ERR              BIT(27)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN_ERR                  BIT(28)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN_VALID                        BIT(29)
+#define HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN                      BIT(30)
+
+#define HAL_REO_UPD_RX_QUEUE_INFO1_RX_QUEUE_NUMBER             GENMASK(15, 0)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_VLD                         BIT(16)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_ASSOC_LNK_DESC_COUNTER      GENMASK(18, 17)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_DIS_DUP_DETECTION           BIT(19)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_SOFT_REORDER_EN             BIT(20)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_AC                          GENMASK(22, 21)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_BAR                         BIT(23)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_RETRY                       BIT(24)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_CHECK_2K_MODE               BIT(25)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_OOR_MODE                    BIT(26)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_PN_CHECK                    BIT(27)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_EVEN_PN                     BIT(28)
+#define HAL_REO_UPD_RX_QUEUE_INFO1_UNEVEN_PN                   BIT(29)
+#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)
+
+struct hal_reo_update_rx_queue {
+       struct hal_reo_cmd_hdr cmd;
+       u32 queue_addr_lo;
+       u32 info0;
+       u32 info1;
+       u32 info2;
+       u32 pn[4];
+} __packed;
+
+#define HAL_REO_UNBLOCK_CACHE_INFO0_UNBLK_CACHE                BIT(0)
+#define HAL_REO_UNBLOCK_CACHE_INFO0_RESOURCE_IDX       GENMASK(2, 1)
+
+struct hal_reo_unblock_cache {
+       struct hal_reo_cmd_hdr cmd;
+       u32 info0;
+       u32 rsvd[7];
+} __packed;
+
+enum hal_reo_exec_status {
+       HAL_REO_EXEC_STATUS_SUCCESS,
+       HAL_REO_EXEC_STATUS_BLOCKED,
+       HAL_REO_EXEC_STATUS_FAILED,
+       HAL_REO_EXEC_STATUS_RESOURCE_BLOCKED,
+};
+
+#define HAL_REO_STATUS_HDR_INFO0_STATUS_NUM    GENMASK(15, 0)
+#define HAL_REO_STATUS_HDR_INFO0_EXEC_TIME     GENMASK(25, 16)
+#define HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS   GENMASK(27, 26)
+
+struct hal_reo_status_hdr {
+       u32 info0;
+       u32 timestamp;
+} __packed;
+
+/* hal_reo_status_hdr
+ *             Producer: REO
+ *             Consumer: SW
+ *
+ * status_num
+ *             The value in this field is equal to value of the reo command
+ *             number. This field helps to correlate the statuses with the REO
+ *             commands.
+ *
+ * execution_time (in us)
+ *             The amount of time REO took to excecute the command. Note that
+ *             this time does not include the duration of the command waiting
+ *             in the command ring, before the execution started.
+ *
+ * execution_status
+ *             Execution status of the command. Values are defined in
+ *             enum %HAL_REO_EXEC_STATUS_.
+ */
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_SSN               GENMASK(11, 0)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_CUR_IDX           GENMASK(19, 12)
+
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO1_MPDU_COUNT                GENMASK(6, 0)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO1_MSDU_COUNT                GENMASK(31, 7)
+
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO2_TIMEOUT_COUNT     GENMASK(9, 4)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO2_FDTB_COUNT                GENMASK(15, 10)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO2_DUPLICATE_COUNT   GENMASK(31, 16)
+
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO3_FIO_COUNT         GENMASK(23, 0)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO3_BAR_RCVD_CNT      GENMASK(31, 24)
+
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_LATE_RX_MPDU      GENMASK(11, 0)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_WINDOW_JMP2K      GENMASK(15, 12)
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_HOLE_COUNT                GENMASK(31, 16)
+
+#define HAL_REO_GET_QUEUE_STATS_STATUS_INFO5_LOOPING_CNT       GENMASK(31, 28)
+
+struct hal_reo_get_queue_stats_status {
+       struct hal_reo_status_hdr hdr;
+       u32 info0;
+       u32 pn[4];
+       u32 last_rx_enqueue_timestamp;
+       u32 last_rx_dequeue_timestamp;
+       u32 rx_bitmap[8];
+       u32 info1;
+       u32 info2;
+       u32 info3;
+       u32 num_mpdu_frames;
+       u32 num_msdu_frames;
+       u32 total_bytes;
+       u32 info4;
+       u32 info5;
+} __packed;
+
+/* hal_reo_get_queue_stats_status
+ *             Producer: REO
+ *             Consumer: SW
+ *
+ * status_hdr
+ *             Details that can link this status with the original command. It
+ *             also contains info on how long REO took to execute this command.
+ *
+ * ssn
+ *             Starting Sequence number of the session, this changes whenever
+ *             window moves (can be filled by SW then maintained by REO).
+ *
+ * current_index
+ *             Points to last forwarded packet.
+ *
+ * pn
+ *             Bits of the PN number.
+ *
+ * last_rx_enqueue_timestamp
+ * last_rx_dequeue_timestamp
+ *             Timestamp of arrival of the last MPDU for this queue and
+ *             Timestamp of forwarding an MPDU accordingly.
+ *
+ * rx_bitmap
+ *             When a bit is set, the corresponding frame is currently held
+ *             in the re-order queue. The bitmap  is Fully managed by HW.
+ *
+ * current_mpdu_count
+ * current_msdu_count
+ *             The number of MPDUs and MSDUs in the queue.
+ *
+ * timeout_count
+ *             The number of times REO started forwarding frames even though
+ *             there is a hole in the bitmap. Forwarding reason is timeout.
+ *
+ * forward_due_to_bar_count
+ *             The number of times REO started forwarding frames even though
+ *             there is a hole in the bitmap. Fwd reason is reception of BAR.
+ *
+ * duplicate_count
+ *             The number of duplicate frames that have been detected.
+ *
+ * frames_in_order_count
+ *             The number of frames that have been received in order (without
+ *             a hole that prevented them from being forwarded immediately).
+ *
+ * bar_received_count
+ *             The number of times a BAR frame is received.
+ *
+ * mpdu_frames_processed_count
+ * msdu_frames_processed_count
+ *             The total number of MPDU/MSDU frames that have been processed.
+ *
+ * total_bytes
+ *             An approximation of the number of bytes received for this queue.
+ *
+ * late_receive_mpdu_count
+ *             The number of MPDUs received after the window had already moved
+ *             on. The 'late' sequence window is defined as
+ *             (Window SSN - 256) - (Window SSN - 1).
+ *
+ * window_jump_2k
+ *             The number of times the window moved more than 2K
+ *
+ * hole_count
+ *             The number of times a hole was created in the receive bitmap.
+ *
+ * looping_count
+ *             A count value that indicates the number of times the producer of
+ *             entries into this Ring has looped around the ring.
+ */
+
+#define HAL_REO_STATUS_LOOP_CNT                        GENMASK(31, 28)
+
+#define HAL_REO_FLUSH_QUEUE_INFO0_ERR_DETECTED BIT(0)
+#define HAL_REO_FLUSH_QUEUE_INFO0_RSVD         GENMASK(31, 1)
+#define HAL_REO_FLUSH_QUEUE_INFO1_RSVD         GENMASK(27, 0)
+
+struct hal_reo_flush_queue_status {
+       struct hal_reo_status_hdr hdr;
+       u32 info0;
+       u32 rsvd0[21];
+       u32 info1;
+} __packed;
+
+/* hal_reo_flush_queue_status
+ *             Producer: REO
+ *             Consumer: SW
+ *
+ * status_hdr
+ *             Details that can link this status with the original command. It
+ *             also contains info on how long REO took to execute this command.
+ *
+ * error_detected
+ *             Status of blocking resource
+ *
+ *             0 - No error has been detected while executing this command
+ *             1 - Error detected. The resource to be used for blocking was
+ *                 already in use.
+ *
+ * looping_count
+ *             A count value that indicates the number of times the producer of
+ *             entries into this Ring has looped around the ring.
+ */
+
+#define HAL_REO_FLUSH_CACHE_STATUS_INFO0_IS_ERR                        BIT(0)
+#define HAL_REO_FLUSH_CACHE_STATUS_INFO0_BLOCK_ERR_CODE                GENMASK(2, 1)
+#define HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_STATUS_HIT      BIT(8)
+#define HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_DESC_TYPE       GENMASK(11, 9)
+#define HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_CLIENT_ID       GENMASK(15, 12)
+#define HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_ERR             GENMASK(17, 16)
+#define HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_COUNT           GENMASK(25, 18)
+
+struct hal_reo_flush_cache_status {
+       struct hal_reo_status_hdr hdr;
+       u32 info0;
+       u32 rsvd0[21];
+       u32 info1;
+} __packed;
+
+/* hal_reo_flush_cache_status
+ *             Producer: REO
+ *             Consumer: SW
+ *
+ * status_hdr
+ *             Details that can link this status with the original command. It
+ *             also contains info on how long REO took to execute this command.
+ *
+ * error_detected
+ *             Status for blocking resource handling
+ *
+ *             0 - No error has been detected while executing this command
+ *             1 - An error in the blocking resource management was detected
+ *
+ * block_error_details
+ *             only valid when error_detected is set
+ *
+ *             0 - No blocking related errors found
+ *             1 - Blocking resource is already in use
+ *             2 - Resource requested to be unblocked, was not blocked
+ *
+ * cache_controller_flush_status_hit
+ *             The status that the cache controller returned on executing the
+ *             flush command.
+ *
+ *             0 - miss; 1 - hit
+ *
+ * cache_controller_flush_status_desc_type
+ *             Flush descriptor type
+ *
+ * cache_controller_flush_status_client_id
+ *             Module who made the flush request
+ *
+ *             In REO, this is always 0
+ *
+ * cache_controller_flush_status_error
+ *             Error condition
+ *
+ *             0 - No error found
+ *             1 - HW interface is still busy
+ *             2 - Line currently locked. Used for one line flush command
+ *             3 - At least one line is still locked.
+ *                 Used for cache flush command.
+ *
+ * cache_controller_flush_count
+ *             The number of lines that were actually flushed out
+ *
+ * looping_count
+ *             A count value that indicates the number of times the producer of
+ *             entries into this Ring has looped around the ring.
+ */
+
+#define HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_IS_ERR      BIT(0)
+#define HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_TYPE                BIT(1)
+
+struct hal_reo_unblock_cache_status {
+       struct hal_reo_status_hdr hdr;
+       u32 info0;
+       u32 rsvd0[21];
+       u32 info1;
+} __packed;
+
+/* hal_reo_unblock_cache_status
+ *             Producer: REO
+ *             Consumer: SW
+ *
+ * status_hdr
+ *             Details that can link this status with the original command. It
+ *             also contains info on how long REO took to execute this command.
+ *
+ * error_detected
+ *             0 - No error has been detected while executing this command
+ *             1 - The blocking resource was not in use, and therefore it could
+ *                 not be unblocked.
+ *
+ * unblock_type
+ *             Reference to the type of unblock command
+ *             0 - Unblock a blocking resource
+ *             1 - The entire cache usage is unblock
+ *
+ * looping_count
+ *             A count value that indicates the number of times the producer of
+ *             entries into this Ring has looped around the ring.
+ */
+
+#define HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_IS_ERR              BIT(0)
+#define HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_LIST_EMPTY          BIT(1)
+
+#define HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_REL_DESC_COUNT      GENMASK(15, 0)
+#define HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_FWD_BUF_COUNT       GENMASK(31, 16)
+
+struct hal_reo_flush_timeout_list_status {
+       struct hal_reo_status_hdr hdr;
+       u32 info0;
+       u32 info1;
+       u32 rsvd0[20];
+       u32 info2;
+} __packed;
+
+/* hal_reo_flush_timeout_list_status
+ *             Producer: REO
+ *             Consumer: SW
+ *
+ * status_hdr
+ *             Details that can link this status with the original command. It
+ *             also contains info on how long REO took to execute this command.
+ *
+ * error_detected
+ *             0 - No error has been detected while executing this command
+ *             1 - Command not properly executed and returned with error
+ *
+ * timeout_list_empty
+ *             When set, REO has depleted the timeout list and all entries are
+ *             gone.
+ *
+ * release_desc_count
+ *             Producer: SW; Consumer: REO
+ *             The number of link descriptor released
+ *
+ * forward_buf_count
+ *             Producer: SW; Consumer: REO
+ *             The number of buffers forwarded to the REO destination rings
+ *
+ * looping_count
+ *             A count value that indicates the number of times the producer of
+ *             entries into this Ring has looped around the ring.
+ */
+
+#define HAL_REO_DESC_THRESH_STATUS_INFO0_THRESH_INDEX          GENMASK(1, 0)
+#define HAL_REO_DESC_THRESH_STATUS_INFO1_LINK_DESC_COUNTER0    GENMASK(23, 0)
+#define HAL_REO_DESC_THRESH_STATUS_INFO2_LINK_DESC_COUNTER1    GENMASK(23, 0)
+#define HAL_REO_DESC_THRESH_STATUS_INFO3_LINK_DESC_COUNTER2    GENMASK(23, 0)
+#define HAL_REO_DESC_THRESH_STATUS_INFO4_LINK_DESC_COUNTER_SUM GENMASK(23, 0)
+
+struct hal_reo_desc_thresh_reached_status {
+       struct hal_reo_status_hdr hdr;
+       u32 info0;
+       u32 info1;
+       u32 info2;
+       u32 info3;
+       u32 info4;
+       u32 rsvd0[17];
+       u32 info5;
+} __packed;
+
+/* hal_reo_desc_thresh_reached_status
+ *             Producer: REO
+ *             Consumer: SW
+ *
+ * status_hdr
+ *             Details that can link this status with the original command. It
+ *             also contains info on how long REO took to execute this command.
+ *
+ * threshold_index
+ *             The index of the threshold register whose value got reached
+ *
+ * link_descriptor_counter0
+ * link_descriptor_counter1
+ * link_descriptor_counter2
+ * link_descriptor_counter_sum
+ *             Value of the respective counters at generation of this message
+ *
+ * looping_count
+ *             A count value that indicates the number of times the producer of
+ *             entries into this Ring has looped around the ring.
+ */
+
+#endif /* ATH11K_HAL_DESC_H */
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include "ahb.h"
+#include "debug.h"
+#include "hal.h"
+#include "hal_tx.h"
+#include "hal_rx.h"
+#include "hal_desc.h"
+
+static void ath11k_hal_reo_set_desc_hdr(struct hal_desc_header *hdr,
+                                       u8 owner, u8 buffer_type, u32 magic)
+{
+       hdr->info0 = FIELD_PREP(HAL_DESC_HDR_INFO0_OWNER, owner) |
+                    FIELD_PREP(HAL_DESC_HDR_INFO0_BUF_TYPE, buffer_type);
+
+       /* Magic pattern in reserved bits for debugging */
+       hdr->info0 |= FIELD_PREP(HAL_DESC_HDR_INFO0_DBG_RESERVED, magic);
+}
+
+static int ath11k_hal_reo_cmd_queue_stats(struct hal_tlv_hdr *tlv,
+                                         struct ath11k_hal_reo_cmd *cmd)
+{
+       struct hal_reo_get_queue_stats *desc;
+
+       tlv->tl = FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_GET_QUEUE_STATS) |
+                 FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
+
+       desc = (struct hal_reo_get_queue_stats *)tlv->value;
+       memset(&desc->queue_addr_lo, 0,
+              (sizeof(*desc) - sizeof(struct hal_reo_cmd_hdr)));
+
+       desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+       if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
+               desc->cmd.info0 |= HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+
+       desc->queue_addr_lo = cmd->addr_lo;
+       desc->info0 = FIELD_PREP(HAL_REO_GET_QUEUE_STATS_INFO0_QUEUE_ADDR_HI,
+                                cmd->addr_hi);
+       if (cmd->flag & HAL_REO_CMD_FLG_STATS_CLEAR)
+               desc->info0 |= HAL_REO_GET_QUEUE_STATS_INFO0_CLEAR_STATS;
+
+       return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER, desc->cmd.info0);
+}
+
+static int ath11k_hal_reo_cmd_flush_cache(struct ath11k_hal *hal, struct hal_tlv_hdr *tlv,
+                                         struct ath11k_hal_reo_cmd *cmd)
+{
+       struct hal_reo_flush_cache *desc;
+       u8 avail_slot = ffz(hal->avail_blk_resource);
+
+       if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_BLOCK_LATER) {
+               if (avail_slot >= HAL_MAX_AVAIL_BLK_RES)
+                       return -ENOSPC;
+
+               hal->current_blk_index = avail_slot;
+       }
+
+       tlv->tl = FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_FLUSH_CACHE) |
+                 FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
+
+       desc = (struct hal_reo_flush_cache *)tlv->value;
+       memset(&desc->cache_addr_lo, 0,
+              (sizeof(*desc) - sizeof(struct hal_reo_cmd_hdr)));
+
+       desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+       if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
+               desc->cmd.info0 |= HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+
+       desc->cache_addr_lo = cmd->addr_lo;
+       desc->info0 = FIELD_PREP(HAL_REO_FLUSH_CACHE_INFO0_CACHE_ADDR_HI,
+                                cmd->addr_hi);
+
+       if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_FWD_ALL_MPDUS)
+               desc->info0 |= HAL_REO_FLUSH_CACHE_INFO0_FWD_ALL_MPDUS;
+
+       if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_BLOCK_LATER) {
+               desc->info0 |= HAL_REO_FLUSH_CACHE_INFO0_BLOCK_CACHE_USAGE;
+               desc->info0 |=
+                       FIELD_PREP(HAL_REO_FLUSH_CACHE_INFO0_BLOCK_RESRC_IDX,
+                                  avail_slot);
+       }
+
+       if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_NO_INVAL)
+               desc->info0 |= HAL_REO_FLUSH_CACHE_INFO0_FLUSH_WO_INVALIDATE;
+
+       if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_ALL)
+               desc->info0 |= HAL_REO_FLUSH_CACHE_INFO0_FLUSH_ALL;
+
+       return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER, desc->cmd.info0);
+}
+
+static int ath11k_hal_reo_cmd_update_rx_queue(struct hal_tlv_hdr *tlv,
+                                             struct ath11k_hal_reo_cmd *cmd)
+{
+       struct hal_reo_update_rx_queue *desc;
+
+       tlv->tl = FIELD_PREP(HAL_TLV_HDR_TAG, HAL_REO_UPDATE_RX_REO_QUEUE) |
+                 FIELD_PREP(HAL_TLV_HDR_LEN, sizeof(*desc));
+
+       desc = (struct hal_reo_update_rx_queue *)tlv->value;
+       memset(&desc->queue_addr_lo, 0,
+              (sizeof(*desc) - sizeof(struct hal_reo_cmd_hdr)));
+
+       desc->cmd.info0 &= ~HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+       if (cmd->flag & HAL_REO_CMD_FLG_NEED_STATUS)
+               desc->cmd.info0 |= HAL_REO_CMD_HDR_INFO0_STATUS_REQUIRED;
+
+       desc->queue_addr_lo = cmd->addr_lo;
+       desc->info0 =
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_QUEUE_ADDR_HI,
+                          cmd->addr_hi) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_RX_QUEUE_NUM,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_RX_QUEUE_NUM)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_VLD,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_VLD)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_ASSOC_LNK_DESC_CNT,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_ALDC)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_DIS_DUP_DETECTION,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_DIS_DUP_DETECTION)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_SOFT_REORDER_EN,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_SOFT_REORDER_EN)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_AC,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_AC)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_BAR,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_BAR)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_RETRY,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_RETRY)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_CHECK_2K_MODE,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_CHECK_2K_MODE)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_OOR_MODE,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_OOR_MODE)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_BA_WINDOW_SIZE,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_BA_WINDOW_SIZE)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN_CHECK,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_PN_CHECK)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_EVEN_PN,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_EVEN_PN)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_UNEVEN_PN,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_UNEVEN_PN)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN_HANDLE_ENABLE,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_PN_HANDLE_ENABLE)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN_SIZE,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_PN_SIZE)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_IGNORE_AMPDU_FLG,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_IGNORE_AMPDU_FLG)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_SVLD,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_SVLD)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_SSN,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_SSN)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_SEQ_2K_ERR,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_SEQ_2K_ERR)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN_VALID,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_PN_VALID)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO0_UPD_PN,
+                          !!(cmd->upd0 & HAL_REO_CMD_UPD0_PN));
+
+       desc->info1 =
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_RX_QUEUE_NUMBER,
+                          cmd->rx_queue_num) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_VLD,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_VLD)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_ASSOC_LNK_DESC_COUNTER,
+                          FIELD_GET(HAL_REO_CMD_UPD1_ALDC, cmd->upd1)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_DIS_DUP_DETECTION,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_DIS_DUP_DETECTION)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_SOFT_REORDER_EN,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_SOFT_REORDER_EN)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_AC,
+                          FIELD_GET(HAL_REO_CMD_UPD1_AC, cmd->upd1)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_BAR,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_BAR)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_CHECK_2K_MODE,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_CHECK_2K_MODE)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_RETRY,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_RETRY)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_OOR_MODE,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_OOR_MODE)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_PN_CHECK,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_PN_CHECK)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_EVEN_PN,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_EVEN_PN)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_UNEVEN_PN,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_UNEVEN_PN)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_PN_HANDLE_ENABLE,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_PN_HANDLE_ENABLE)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO1_IGNORE_AMPDU_FLG,
+                          !!(cmd->upd1 & HAL_REO_CMD_UPD1_IGNORE_AMPDU_FLG));
+
+       if (cmd->pn_size == 24)
+               cmd->pn_size = HAL_RX_REO_QUEUE_PN_SIZE_24;
+       else if (cmd->pn_size == 48)
+               cmd->pn_size = HAL_RX_REO_QUEUE_PN_SIZE_48;
+       else if (cmd->pn_size == 128)
+               cmd->pn_size = HAL_RX_REO_QUEUE_PN_SIZE_128;
+
+       if (cmd->ba_window_size < 1)
+               cmd->ba_window_size = 1;
+
+       if (cmd->ba_window_size == 1)
+               cmd->ba_window_size++;
+
+       desc->info2 =
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO2_BA_WINDOW_SIZE,
+                          cmd->ba_window_size - 1) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO2_PN_SIZE, cmd->pn_size) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO2_SVLD,
+                          !!(cmd->upd2 & HAL_REO_CMD_UPD2_SVLD)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO2_SSN,
+                          FIELD_GET(HAL_REO_CMD_UPD2_SSN, cmd->upd2)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO2_SEQ_2K_ERR,
+                          !!(cmd->upd2 & HAL_REO_CMD_UPD2_SEQ_2K_ERR)) |
+               FIELD_PREP(HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR,
+                          !!(cmd->upd2 & HAL_REO_CMD_UPD2_PN_ERR));
+
+       return FIELD_GET(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER, desc->cmd.info0);
+}
+
+int ath11k_hal_reo_cmd_send(struct ath11k_base *ab, struct hal_srng *srng,
+                           enum hal_reo_cmd_type type,
+                           struct ath11k_hal_reo_cmd *cmd)
+{
+       struct hal_tlv_hdr *reo_desc;
+       int ret;
+
+       spin_lock_bh(&srng->lock);
+
+       ath11k_hal_srng_access_begin(ab, srng);
+       reo_desc = (struct hal_tlv_hdr *)ath11k_hal_srng_src_get_next_entry(ab, srng);
+       if (!reo_desc) {
+               ret = -ENOBUFS;
+               goto out;
+       }
+
+       switch (type) {
+       case HAL_REO_CMD_GET_QUEUE_STATS:
+               ret = ath11k_hal_reo_cmd_queue_stats(reo_desc, cmd);
+               break;
+       case HAL_REO_CMD_FLUSH_CACHE:
+               ret = ath11k_hal_reo_cmd_flush_cache(&ab->hal, reo_desc, cmd);
+               break;
+       case HAL_REO_CMD_UPDATE_RX_QUEUE:
+               ret = ath11k_hal_reo_cmd_update_rx_queue(reo_desc, cmd);
+               break;
+       case HAL_REO_CMD_FLUSH_QUEUE:
+       case HAL_REO_CMD_UNBLOCK_CACHE:
+       case HAL_REO_CMD_FLUSH_TIMEOUT_LIST:
+               ath11k_warn(ab, "Unsupported reo command %d\n", type);
+               ret = -ENOTSUPP;
+               break;
+       default:
+               ath11k_warn(ab, "Unknown reo command %d\n", type);
+               ret = -EINVAL;
+               break;
+       }
+
+out:
+       ath11k_hal_srng_access_end(ab, srng);
+       spin_unlock_bh(&srng->lock);
+
+       return ret;
+}
+
+void ath11k_hal_rx_buf_addr_info_set(void *desc, dma_addr_t paddr,
+                                    u32 cookie, u8 manager)
+{
+       struct ath11k_buffer_addr *binfo = (struct ath11k_buffer_addr *)desc;
+       u32 paddr_lo, paddr_hi;
+
+       paddr_lo = lower_32_bits(paddr);
+       paddr_hi = upper_32_bits(paddr);
+       binfo->info0 = FIELD_PREP(BUFFER_ADDR_INFO0_ADDR, paddr_lo);
+       binfo->info1 = FIELD_PREP(BUFFER_ADDR_INFO1_ADDR, paddr_hi) |
+                      FIELD_PREP(BUFFER_ADDR_INFO1_SW_COOKIE, cookie) |
+                      FIELD_PREP(BUFFER_ADDR_INFO1_RET_BUF_MGR, manager);
+}
+
+void ath11k_hal_rx_buf_addr_info_get(void *desc, dma_addr_t *paddr,
+                                    u32 *cookie, u8 *rbm)
+{
+       struct ath11k_buffer_addr *binfo = (struct ath11k_buffer_addr *)desc;
+
+       *paddr =
+               (((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR, binfo->info1)) << 32) |
+               FIELD_GET(BUFFER_ADDR_INFO0_ADDR, binfo->info0);
+       *cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, binfo->info1);
+       *rbm = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR, binfo->info1);
+}
+
+void ath11k_hal_rx_msdu_link_info_get(void *link_desc, u32 *num_msdus,
+                                     struct hal_rx_msdu_meta *meta,
+                                     enum hal_rx_buf_return_buf_manager *rbm)
+{
+       struct hal_rx_msdu_link *link = (struct hal_rx_msdu_link *)link_desc;
+       struct hal_rx_msdu_details *msdu;
+       int i;
+
+       *num_msdus = HAL_NUM_RX_MSDUS_PER_LINK_DESC;
+
+       msdu = &link->msdu_link[0];
+       *rbm = FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR,
+                        msdu->buf_addr_info.info1);
+
+       for (i = 0; i < *num_msdus; i++) {
+               msdu = &link->msdu_link[i];
+
+               if (!FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
+                              msdu->buf_addr_info.info0)) {
+                       *num_msdus = i;
+                       break;
+               }
+               meta->msdu_len = FIELD_GET(RX_MSDU_DESC_INFO0_MSDU_LENGTH,
+                                          msdu->rx_msdu_info.info0);
+               meta->first = !!(msdu->rx_msdu_info.info0 &
+                                RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU);
+               meta->last = !!(msdu->rx_msdu_info.info0 &
+                               RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU);
+               meta->continuation = !!(msdu->rx_msdu_info.info0 &
+                                       RX_MSDU_DESC_INFO0_MSDU_CONTINUATION);
+               meta->cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
+                                        msdu->buf_addr_info.info1);
+               meta++;
+       }
+}
+
+int ath11k_hal_desc_reo_parse_err(struct ath11k_base *ab, u32 *rx_desc,
+                                 dma_addr_t *paddr, u32 *desc_bank)
+{
+       struct hal_reo_dest_ring *desc = (struct hal_reo_dest_ring *)rx_desc;
+       enum hal_reo_dest_ring_push_reason push_reason;
+       enum hal_reo_dest_ring_error_code err_code;
+
+       push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON,
+                               desc->info0);
+       err_code = FIELD_GET(HAL_REO_DEST_RING_INFO0_ERROR_CODE,
+                            desc->info0);
+       ab->soc_stats.reo_error[err_code]++;
+
+       if (push_reason != HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED &&
+           push_reason != HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) {
+               ath11k_warn(ab, "expected error push reason code, received %d\n",
+                           push_reason);
+               return -EINVAL;
+       }
+
+       if (FIELD_GET(HAL_REO_DEST_RING_INFO0_BUFFER_TYPE, desc->info0) !=
+           HAL_REO_DEST_RING_BUFFER_TYPE_LINK_DESC) {
+               ath11k_warn(ab, "expected buffer type link_desc");
+               return -EINVAL;
+       }
+
+       ath11k_hal_rx_reo_ent_paddr_get(ab, rx_desc, paddr, desc_bank);
+
+       return 0;
+}
+
+void ath11k_hal_rx_parse_dst_ring_desc(struct ath11k_base *ab, u32 *rx_desc,
+                                      struct hal_rx_meta_info *meta_info)
+{
+       struct hal_reo_dest_ring *desc = (struct hal_reo_dest_ring *)rx_desc;
+       struct rx_mpdu_desc *mpdu = &desc->rx_mpdu_info;
+       struct rx_msdu_desc *msdu = &desc->rx_msdu_info;
+       struct hal_rx_mpdu_meta *meta_mpdu = &meta_info->mpdu_meta;
+       struct hal_rx_msdu_meta *meta_msdu = &meta_info->msdu_meta;
+
+       meta_info->push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON,
+                                          desc->info0);
+
+       meta_mpdu->msdu_cnt = FIELD_GET(RX_MPDU_DESC_INFO0_MSDU_COUNT,
+                                       mpdu->info0);
+       meta_mpdu->seq_num = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, mpdu->info0);
+       meta_mpdu->frag = !!(mpdu->info0 & RX_MPDU_DESC_INFO0_FRAG_FLAG);
+       meta_mpdu->retry = !!(mpdu->info0 & RX_MPDU_DESC_INFO0_MPDU_RETRY);
+       meta_mpdu->ampdu = !!(mpdu->info0 & RX_MPDU_DESC_INFO0_AMPDU_FLAG);
+       meta_mpdu->raw = !!(mpdu->info0 & RX_MPDU_DESC_INFO0_RAW_MPDU);
+       meta_mpdu->peer_meta = mpdu->meta_data;
+
+       meta_msdu->cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
+                                     desc->buf_addr_info.info1);
+       meta_msdu->msdu_len = FIELD_GET(RX_MSDU_DESC_INFO0_MSDU_LENGTH,
+                                       msdu->info0);
+       meta_msdu->first =
+               !!(msdu->info0 & RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU);
+       meta_msdu->last =
+               !!(msdu->info0 & RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU);
+       meta_msdu->continuation =
+               !!(msdu->info0 & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION);
+}
+
+int ath11k_hal_wbm_desc_parse_err(struct ath11k_base *ab, void *desc,
+                                 struct hal_rx_wbm_rel_info *rel_info)
+{
+       struct hal_wbm_release_ring *wbm_desc = desc;
+       enum hal_wbm_rel_desc_type type;
+       enum hal_wbm_rel_src_module rel_src;
+
+       type = FIELD_GET(HAL_WBM_RELEASE_INFO0_DESC_TYPE,
+                        wbm_desc->info0);
+       /* We expect only WBM_REL buffer type */
+       if (type != HAL_WBM_REL_DESC_TYPE_REL_MSDU) {
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       rel_src = FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE,
+                           wbm_desc->info0);
+       if (rel_src != HAL_WBM_REL_SRC_MODULE_RXDMA &&
+           rel_src != HAL_WBM_REL_SRC_MODULE_REO)
+               return -EINVAL;
+
+       if (FIELD_GET(BUFFER_ADDR_INFO1_RET_BUF_MGR,
+                     wbm_desc->buf_addr_info.info1) != HAL_RX_BUF_RBM_SW3_BM) {
+               ab->soc_stats.invalid_rbm++;
+               return -EINVAL;
+       }
+
+       rel_info->cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
+                                    wbm_desc->buf_addr_info.info1);
+       rel_info->err_rel_src = rel_src;
+       if (rel_src == HAL_WBM_REL_SRC_MODULE_REO) {
+               rel_info->push_reason =
+                       FIELD_GET(HAL_WBM_RELEASE_INFO0_REO_PUSH_REASON,
+                                 wbm_desc->info0);
+               rel_info->err_code =
+                       FIELD_GET(HAL_WBM_RELEASE_INFO0_REO_ERROR_CODE,
+                                 wbm_desc->info0);
+       } else {
+               rel_info->push_reason =
+                       FIELD_GET(HAL_WBM_RELEASE_INFO0_RXDMA_PUSH_REASON,
+                                 wbm_desc->info0);
+               rel_info->err_code =
+                       FIELD_GET(HAL_WBM_RELEASE_INFO0_RXDMA_ERROR_CODE,
+                                 wbm_desc->info0);
+       }
+
+       rel_info->first_msdu = FIELD_GET(HAL_WBM_RELEASE_INFO2_FIRST_MSDU,
+                                        wbm_desc->info2);
+       rel_info->last_msdu = FIELD_GET(HAL_WBM_RELEASE_INFO2_LAST_MSDU,
+                                       wbm_desc->info2);
+       return 0;
+}
+
+void ath11k_hal_rx_reo_ent_paddr_get(struct ath11k_base *ab, void *desc,
+                                    dma_addr_t *paddr, u32 *desc_bank)
+{
+       struct ath11k_buffer_addr *buff_addr = desc;
+
+       *paddr = ((u64)(FIELD_GET(BUFFER_ADDR_INFO1_ADDR, buff_addr->info1)) << 32) |
+                 FIELD_GET(BUFFER_ADDR_INFO0_ADDR, buff_addr->info0);
+
+       *desc_bank = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, buff_addr->info1);
+}
+
+void ath11k_hal_rx_msdu_link_desc_set(struct ath11k_base *ab, void *desc,
+                                     void *link_desc,
+                                     enum hal_wbm_rel_bm_act action)
+{
+       struct hal_wbm_release_ring *dst_desc = desc;
+       struct hal_wbm_release_ring *src_desc = link_desc;
+
+       dst_desc->buf_addr_info = src_desc->buf_addr_info;
+       dst_desc->info0 |= FIELD_PREP(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE,
+                                     HAL_WBM_REL_SRC_MODULE_SW) |
+                          FIELD_PREP(HAL_WBM_RELEASE_INFO0_BM_ACTION, action) |
+                          FIELD_PREP(HAL_WBM_RELEASE_INFO0_DESC_TYPE,
+                                     HAL_WBM_REL_DESC_TYPE_MSDU_LINK);
+}
+
+void ath11k_hal_reo_status_queue_stats(struct ath11k_base *ab, u32 *reo_desc,
+                                      struct hal_reo_status *status)
+{
+       struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+       struct hal_reo_get_queue_stats_status *desc =
+               (struct hal_reo_get_queue_stats_status *)tlv->value;
+
+       status->uniform_hdr.cmd_num =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM,
+                                         desc->hdr.info0);
+       status->uniform_hdr.cmd_status =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS,
+                                         desc->hdr.info0);
+
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "Queue stats status:\n");
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "header: cmd_num %d status %d\n",
+                  status->uniform_hdr.cmd_num,
+                  status->uniform_hdr.cmd_status);
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "ssn %ld cur_idx %ld\n",
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_SSN,
+                            desc->info0),
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_CUR_IDX,
+                            desc->info0));
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "pn = [%08x, %08x, %08x, %08x]\n",
+                  desc->pn[0], desc->pn[1], desc->pn[2], desc->pn[3]);
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "last_rx: enqueue_tstamp %08x dequeue_tstamp %08x\n",
+                  desc->last_rx_enqueue_timestamp,
+                  desc->last_rx_dequeue_timestamp);
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "rx_bitmap [%08x %08x %08x %08x %08x %08x %08x %08x]\n",
+                  desc->rx_bitmap[0], desc->rx_bitmap[1], desc->rx_bitmap[2],
+                  desc->rx_bitmap[3], desc->rx_bitmap[4], desc->rx_bitmap[5],
+                  desc->rx_bitmap[6], desc->rx_bitmap[7]);
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "count: cur_mpdu %ld cur_msdu %ld\n",
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO1_MPDU_COUNT,
+                            desc->info1),
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO1_MSDU_COUNT,
+                            desc->info1));
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "fwd_timeout %ld fwd_bar %ld dup_count %ld\n",
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO2_TIMEOUT_COUNT,
+                            desc->info2),
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO2_FDTB_COUNT,
+                            desc->info2),
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO2_DUPLICATE_COUNT,
+                            desc->info2));
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "frames_in_order %ld bar_rcvd %ld\n",
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO3_FIO_COUNT,
+                            desc->info3),
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO3_BAR_RCVD_CNT,
+                            desc->info3));
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "num_mpdus %d num_msdus %d total_bytes %d\n",
+                  desc->num_mpdu_frames, desc->num_msdu_frames,
+                  desc->total_bytes);
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "late_rcvd %ld win_jump_2k %ld hole_cnt %ld\n",
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_LATE_RX_MPDU,
+                            desc->info4),
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_WINDOW_JMP2K,
+                            desc->info4),
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_HOLE_COUNT,
+                            desc->info4));
+       ath11k_dbg(ab, ATH11k_DBG_HAL, "looping count %ld\n",
+                  FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO5_LOOPING_CNT,
+                            desc->info5));
+}
+
+int ath11k_hal_reo_process_status(u8 *reo_desc, u8 *status)
+{
+       struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+       struct hal_reo_status_hdr *hdr;
+
+       hdr = (struct hal_reo_status_hdr *)tlv->value;
+       *status = FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, hdr->info0);
+
+       return FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM, hdr->info0);
+}
+
+void ath11k_hal_reo_flush_queue_status(struct ath11k_base *ab, u32 *reo_desc,
+                                      struct hal_reo_status *status)
+{
+       struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+       struct hal_reo_flush_queue_status *desc =
+               (struct hal_reo_flush_queue_status *)tlv->value;
+
+       status->uniform_hdr.cmd_num =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM,
+                                         desc->hdr.info0);
+       status->uniform_hdr.cmd_status =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS,
+                                         desc->hdr.info0);
+       status->u.flush_queue.err_detected =
+               FIELD_GET(HAL_REO_FLUSH_QUEUE_INFO0_ERR_DETECTED,
+                         desc->info0);
+}
+
+void ath11k_hal_reo_flush_cache_status(struct ath11k_base *ab, u32 *reo_desc,
+                                      struct hal_reo_status *status)
+{
+       struct ath11k_hal *hal = &ab->hal;
+       struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+       struct hal_reo_flush_cache_status *desc =
+               (struct hal_reo_flush_cache_status *)tlv->value;
+
+       status->uniform_hdr.cmd_num =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM,
+                                         desc->hdr.info0);
+       status->uniform_hdr.cmd_status =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS,
+                                         desc->hdr.info0);
+
+       status->u.flush_cache.err_detected =
+                       FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_IS_ERR,
+                                 desc->info0);
+       status->u.flush_cache.err_code =
+               FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_BLOCK_ERR_CODE,
+                         desc->info0);
+       if (!status->u.flush_cache.err_code)
+               hal->avail_blk_resource |= BIT(hal->current_blk_index);
+
+       status->u.flush_cache.cache_controller_flush_status_hit =
+               FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_STATUS_HIT,
+                         desc->info0);
+
+       status->u.flush_cache.cache_controller_flush_status_desc_type =
+               FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_DESC_TYPE,
+                         desc->info0);
+       status->u.flush_cache.cache_controller_flush_status_client_id =
+               FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_CLIENT_ID,
+                         desc->info0);
+       status->u.flush_cache.cache_controller_flush_status_err =
+               FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_ERR,
+                         desc->info0);
+       status->u.flush_cache.cache_controller_flush_status_cnt =
+               FIELD_GET(HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_COUNT,
+                         desc->info0);
+}
+
+void ath11k_hal_reo_unblk_cache_status(struct ath11k_base *ab, u32 *reo_desc,
+                                      struct hal_reo_status *status)
+{
+       struct ath11k_hal *hal = &ab->hal;
+       struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+       struct hal_reo_unblock_cache_status *desc =
+               (struct hal_reo_unblock_cache_status *)tlv->value;
+
+       status->uniform_hdr.cmd_num =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM,
+                                         desc->hdr.info0);
+       status->uniform_hdr.cmd_status =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS,
+                                         desc->hdr.info0);
+
+       status->u.unblock_cache.err_detected =
+                       FIELD_GET(HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_IS_ERR,
+                                 desc->info0);
+       status->u.unblock_cache.unblock_type =
+                       FIELD_GET(HAL_REO_UNBLOCK_CACHE_STATUS_INFO0_TYPE,
+                                 desc->info0);
+
+       if (!status->u.unblock_cache.err_detected &&
+           status->u.unblock_cache.unblock_type ==
+           HAL_REO_STATUS_UNBLOCK_BLOCKING_RESOURCE)
+               hal->avail_blk_resource &= ~BIT(hal->current_blk_index);
+}
+
+void ath11k_hal_reo_flush_timeout_list_status(struct ath11k_base *ab,
+                                             u32 *reo_desc,
+                                             struct hal_reo_status *status)
+{
+       struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+       struct hal_reo_flush_timeout_list_status *desc =
+               (struct hal_reo_flush_timeout_list_status *)tlv->value;
+
+       status->uniform_hdr.cmd_num =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM,
+                                         desc->hdr.info0);
+       status->uniform_hdr.cmd_status =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS,
+                                         desc->hdr.info0);
+
+       status->u.timeout_list.err_detected =
+                       FIELD_GET(HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_IS_ERR,
+                                 desc->info0);
+       status->u.timeout_list.list_empty =
+                       FIELD_GET(HAL_REO_FLUSH_TIMEOUT_STATUS_INFO0_LIST_EMPTY,
+                                 desc->info0);
+
+       status->u.timeout_list.release_desc_cnt =
+               FIELD_GET(HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_REL_DESC_COUNT,
+                         desc->info1);
+       status->u.timeout_list.fwd_buf_cnt =
+               FIELD_GET(HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_FWD_BUF_COUNT,
+                         desc->info1);
+}
+
+void ath11k_hal_reo_desc_thresh_reached_status(struct ath11k_base *ab,
+                                              u32 *reo_desc,
+                                              struct hal_reo_status *status)
+{
+       struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+       struct hal_reo_desc_thresh_reached_status *desc =
+               (struct hal_reo_desc_thresh_reached_status *)tlv->value;
+
+       status->uniform_hdr.cmd_num =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM,
+                                         desc->hdr.info0);
+       status->uniform_hdr.cmd_status =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS,
+                                         desc->hdr.info0);
+
+       status->u.desc_thresh_reached.threshold_idx =
+               FIELD_GET(HAL_REO_DESC_THRESH_STATUS_INFO0_THRESH_INDEX,
+                         desc->info0);
+
+       status->u.desc_thresh_reached.link_desc_counter0 =
+               FIELD_GET(HAL_REO_DESC_THRESH_STATUS_INFO1_LINK_DESC_COUNTER0,
+                         desc->info1);
+
+       status->u.desc_thresh_reached.link_desc_counter1 =
+               FIELD_GET(HAL_REO_DESC_THRESH_STATUS_INFO2_LINK_DESC_COUNTER1,
+                         desc->info2);
+
+       status->u.desc_thresh_reached.link_desc_counter2 =
+               FIELD_GET(HAL_REO_DESC_THRESH_STATUS_INFO3_LINK_DESC_COUNTER2,
+                         desc->info3);
+
+       status->u.desc_thresh_reached.link_desc_counter_sum =
+               FIELD_GET(HAL_REO_DESC_THRESH_STATUS_INFO4_LINK_DESC_COUNTER_SUM,
+                         desc->info4);
+}
+
+void ath11k_hal_reo_update_rx_reo_queue_status(struct ath11k_base *ab,
+                                              u32 *reo_desc,
+                                              struct hal_reo_status *status)
+{
+       struct hal_tlv_hdr *tlv = (struct hal_tlv_hdr *)reo_desc;
+       struct hal_reo_status_hdr *desc =
+               (struct hal_reo_status_hdr *)tlv->value;
+
+       status->uniform_hdr.cmd_num =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_STATUS_NUM,
+                                         desc->info0);
+       status->uniform_hdr.cmd_status =
+                               FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS,
+                                         desc->info0);
+}
+
+u32 ath11k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid)
+{
+       u32 num_ext_desc;
+
+       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 {
+               num_ext_desc = 3;
+       }
+
+       return sizeof(struct hal_rx_reo_queue) +
+               (num_ext_desc * sizeof(struct hal_rx_reo_queue_ext));
+}
+
+void ath11k_hal_reo_qdesc_setup(void *vaddr, int tid, u32 ba_window_size,
+                               u32 start_seq)
+{
+       struct hal_rx_reo_queue *qdesc = (struct hal_rx_reo_queue *)vaddr;
+       struct hal_rx_reo_queue_ext *ext_desc;
+
+       memset(qdesc, 0, sizeof(*qdesc));
+
+       ath11k_hal_reo_set_desc_hdr(&qdesc->desc_hdr, HAL_DESC_REO_OWNED,
+                                   HAL_DESC_REO_QUEUE_DESC,
+                                   REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_0);
+
+       qdesc->rx_queue_num = FIELD_PREP(HAL_RX_REO_QUEUE_RX_QUEUE_NUMBER, tid);
+
+       qdesc->info0 =
+               FIELD_PREP(HAL_RX_REO_QUEUE_INFO0_VLD, 1) |
+               FIELD_PREP(HAL_RX_REO_QUEUE_INFO0_ASSOC_LNK_DESC_COUNTER, 1) |
+               FIELD_PREP(HAL_RX_REO_QUEUE_INFO0_AC, ath11k_tid_to_ac(tid));
+
+       if (ba_window_size < 1)
+               ba_window_size = 1;
+
+       if (ba_window_size == 1 && tid != HAL_DESC_REO_NON_QOS_TID)
+               ba_window_size++;
+
+       if (ba_window_size == 1)
+               qdesc->info0 |= FIELD_PREP(HAL_RX_REO_QUEUE_INFO0_RETRY, 1);
+
+       qdesc->info0 |= FIELD_PREP(HAL_RX_REO_QUEUE_INFO0_BA_WINDOW_SIZE,
+                                  ba_window_size - 1);
+
+       /* TODO: Set Ignore ampdu flags based on BA window size and/or
+        * AMPDU capabilities
+        */
+       qdesc->info0 |= FIELD_PREP(HAL_RX_REO_QUEUE_INFO0_IGNORE_AMPDU_FLG, 1);
+
+       qdesc->info1 |= FIELD_PREP(HAL_RX_REO_QUEUE_INFO1_SVLD, 0);
+
+       if (start_seq <= 0xfff)
+               qdesc->info1 = FIELD_PREP(HAL_RX_REO_QUEUE_INFO1_SSN,
+                                         start_seq);
+
+       if (tid == HAL_DESC_REO_NON_QOS_TID)
+               return;
+
+       ext_desc = qdesc->ext_desc;
+
+       /* TODO: HW queue descriptors are currently allocated for max BA
+        * window size for all QOS TIDs so that same descriptor can be used
+        * later when ADDBA request is recevied. This should be changed to
+        * allocate HW queue descriptors based on BA window size being
+        * negotiated (0 for non BA cases), and reallocate when BA window
+        * size changes and also send WMI message to FW to change the REO
+        * queue descriptor in Rx peer entry as part of dp_rx_tid_update.
+        */
+       memset(ext_desc, 0, 3 * sizeof(*ext_desc));
+       ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
+                                   HAL_DESC_REO_QUEUE_EXT_DESC,
+                                   REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1);
+       ext_desc++;
+       ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
+                                   HAL_DESC_REO_QUEUE_EXT_DESC,
+                                   REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2);
+       ext_desc++;
+       ath11k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
+                                   HAL_DESC_REO_QUEUE_EXT_DESC,
+                                   REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_3);
+}
+
+void ath11k_hal_reo_init_cmd_ring(struct ath11k_base *ab,
+                                 struct hal_srng *srng)
+{
+       struct hal_srng_params params;
+       struct hal_tlv_hdr *tlv;
+       struct hal_reo_get_queue_stats *desc;
+       int i, cmd_num = 1;
+       int entry_size;
+       u8 *entry;
+
+       memset(¶ms, 0, sizeof(params));
+
+       entry_size = ath11k_hal_srng_get_entrysize(HAL_REO_CMD);
+       ath11k_hal_srng_get_params(ab, srng, ¶ms);
+       entry = (u8 *)params.ring_base_vaddr;
+
+       for (i = 0; i < params.num_entries; i++) {
+               tlv = (struct hal_tlv_hdr *)entry;
+               desc = (struct hal_reo_get_queue_stats *)tlv->value;
+               desc->cmd.info0 =
+                       FIELD_PREP(HAL_REO_CMD_HDR_INFO0_CMD_NUMBER, cmd_num++);
+               entry += entry_size;
+       }
+}
+
+void ath11k_hal_reo_hw_setup(struct ath11k_base *ab)
+{
+       u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG;
+       u32 val;
+
+       val = ath11k_ahb_read32(ab, reo_base + HAL_REO1_GEN_ENABLE);
+
+       val &= ~HAL_REO1_GEN_ENABLE_FRAG_DST_RING;
+       val |= FIELD_PREP(HAL_REO1_GEN_ENABLE_FRAG_DST_RING,
+                         HAL_SRNG_RING_ID_REO2SW1) |
+              FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE, 1) |
+              FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1);
+       ath11k_ahb_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val);
+
+       ath11k_ahb_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0,
+                          HAL_DEFAULT_REO_TIMEOUT_USEC);
+       ath11k_ahb_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1,
+                          HAL_DEFAULT_REO_TIMEOUT_USEC);
+       ath11k_ahb_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2,
+                          HAL_DEFAULT_REO_TIMEOUT_USEC);
+       ath11k_ahb_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3,
+                          HAL_DEFAULT_REO_TIMEOUT_USEC);
+}
+
+static enum hal_rx_mon_status
+ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab,
+                                  struct hal_rx_mon_ppdu_info *ppdu_info,
+                                  u32 tlv_tag, u8 *tlv_data)
+{
+       u32 info0, info1;
+
+       switch (tlv_tag) {
+       case HAL_RX_PPDU_START: {
+               struct hal_rx_ppdu_start *ppdu_start =
+                       (struct hal_rx_ppdu_start *)tlv_data;
+
+               ppdu_info->ppdu_id =
+                       FIELD_GET(HAL_RX_PPDU_START_INFO0_PPDU_ID,
+                                 __le32_to_cpu(ppdu_start->info0));
+               ppdu_info->chan_num = __le32_to_cpu(ppdu_start->chan_num);
+               ppdu_info->ppdu_ts = __le32_to_cpu(ppdu_start->ppdu_start_ts);
+               break;
+       }
+       case HAL_RX_PPDU_END_USER_STATS: {
+               struct hal_rx_ppdu_end_user_stats *eu_stats =
+                       (struct hal_rx_ppdu_end_user_stats *)tlv_data;
+
+               info0 = __le32_to_cpu(eu_stats->info0);
+               info1 = __le32_to_cpu(eu_stats->info1);
+
+               ppdu_info->tid =
+                       ffs(FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP,
+                                     __le32_to_cpu(eu_stats->info6))) - 1;
+               ppdu_info->tcp_msdu_count =
+                       FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO4_TCP_MSDU_CNT,
+                                 __le32_to_cpu(eu_stats->info4));
+               ppdu_info->udp_msdu_count =
+                       FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO4_UDP_MSDU_CNT,
+                                 __le32_to_cpu(eu_stats->info4));
+               ppdu_info->other_msdu_count =
+                       FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO5_OTHER_MSDU_CNT,
+                                 __le32_to_cpu(eu_stats->info5));
+               ppdu_info->tcp_ack_msdu_count =
+                       FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO5_TCP_ACK_MSDU_CNT,
+                                 __le32_to_cpu(eu_stats->info5));
+               ppdu_info->preamble_type =
+                       FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO1_PKT_TYPE, info1);
+               ppdu_info->num_mpdu_fcs_ok =
+                       FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO1_MPDU_CNT_FCS_OK,
+                                 info1);
+               ppdu_info->num_mpdu_fcs_err =
+                       FIELD_GET(HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR,
+                                 info0);
+               break;
+       }
+       case HAL_PHYRX_HT_SIG: {
+               struct hal_rx_ht_sig_info *ht_sig =
+                       (struct hal_rx_ht_sig_info *)tlv_data;
+
+               info0 = __le32_to_cpu(ht_sig->info0);
+               info1 = __le32_to_cpu(ht_sig->info1);
+
+               ppdu_info->mcs = FIELD_GET(HAL_RX_HT_SIG_INFO_INFO0_MCS, info0);
+               ppdu_info->bw = FIELD_GET(HAL_RX_HT_SIG_INFO_INFO0_BW, info0);
+               ppdu_info->is_stbc = FIELD_GET(HAL_RX_HT_SIG_INFO_INFO1_STBC,
+                                              info1);
+               ppdu_info->ldpc = FIELD_GET(HAL_RX_HT_SIG_INFO_INFO1_FEC_CODING, info1);
+               ppdu_info->gi = info1 & HAL_RX_HT_SIG_INFO_INFO1_GI;
+
+               switch (ppdu_info->mcs) {
+               case 0 ... 7:
+                       ppdu_info->nss = 1;
+                       break;
+               case 8 ... 15:
+                       ppdu_info->nss = 2;
+                       break;
+               case 16 ... 23:
+                       ppdu_info->nss = 3;
+                       break;
+               case 24 ... 31:
+                       ppdu_info->nss = 4;
+                       break;
+               }
+
+               if (ppdu_info->nss > 1)
+                       ppdu_info->mcs = ppdu_info->mcs % 8;
+
+               ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
+               break;
+       }
+       case HAL_PHYRX_L_SIG_B: {
+               struct hal_rx_lsig_b_info *lsigb =
+                       (struct hal_rx_lsig_b_info *)tlv_data;
+
+               ppdu_info->rate = FIELD_GET(HAL_RX_LSIG_B_INFO_INFO0_RATE,
+                                           __le32_to_cpu(lsigb->info0));
+               ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
+               break;
+       }
+       case HAL_PHYRX_L_SIG_A: {
+               struct hal_rx_lsig_a_info *lsiga =
+                       (struct hal_rx_lsig_a_info *)tlv_data;
+
+               ppdu_info->rate = FIELD_GET(HAL_RX_LSIG_A_INFO_INFO0_RATE,
+                                           __le32_to_cpu(lsiga->info0));
+               ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
+               break;
+       }
+       case HAL_PHYRX_VHT_SIG_A: {
+               struct hal_rx_vht_sig_a_info *vht_sig =
+                       (struct hal_rx_vht_sig_a_info *)tlv_data;
+               u32 nsts;
+               u32 group_id;
+
+               info0 = __le32_to_cpu(vht_sig->info0);
+               info1 = __le32_to_cpu(vht_sig->info1);
+
+               ppdu_info->ldpc = FIELD_GET(HAL_RX_VHT_SIG_A_INFO_INFO1_SU_MU_CODING,
+                                           info0);
+               ppdu_info->mcs = FIELD_GET(HAL_RX_VHT_SIG_A_INFO_INFO1_MCS,
+                                          info1);
+               ppdu_info->gi =
+                       FIELD_GET(HAL_RX_VHT_SIG_A_INFO_INFO1_GI_SETTING,
+                                 info1);
+               ppdu_info->is_stbc = info0 & HAL_RX_VHT_SIG_A_INFO_INFO0_STBC;
+               nsts = FIELD_GET(HAL_RX_VHT_SIG_A_INFO_INFO0_NSTS, info0);
+               if (ppdu_info->is_stbc && nsts > 0)
+                       nsts = ((nsts + 1) >> 1) - 1;
+
+               ppdu_info->nss = (nsts & VHT_SIG_SU_NSS_MASK) + 1;
+               ppdu_info->bw = FIELD_GET(HAL_RX_VHT_SIG_A_INFO_INFO0_BW,
+                                         info0);
+               ppdu_info->beamformed = info1 &
+                                       HAL_RX_VHT_SIG_A_INFO_INFO1_BEAMFORMED;
+               group_id = FIELD_GET(HAL_RX_VHT_SIG_A_INFO_INFO0_GROUP_ID,
+                                    info0);
+               if (group_id == 0 || group_id == 63)
+                       ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
+               else
+                       ppdu_info->reception_type =
+                               HAL_RX_RECEPTION_TYPE_MU_MIMO;
+               break;
+       }
+       case HAL_PHYRX_HE_SIG_A_SU: {
+               struct hal_rx_he_sig_a_su_info *he_sig_a =
+                       (struct hal_rx_he_sig_a_su_info *)tlv_data;
+               u32 nsts, cp_ltf, dcm;
+
+               info0 = __le32_to_cpu(he_sig_a->info0);
+               info1 = __le32_to_cpu(he_sig_a->info1);
+
+               ppdu_info->mcs =
+                       FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_MCS,
+                                 info0);
+               ppdu_info->bw =
+                       FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_BW,
+                                 info0);
+               ppdu_info->ldpc = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO1_CODING, info0);
+               ppdu_info->is_stbc = info1 &
+                                    HAL_RX_HE_SIG_A_SU_INFO_INFO1_STBC;
+               ppdu_info->beamformed = info1 &
+                                       HAL_RX_HE_SIG_A_SU_INFO_INFO1_TXBF;
+               dcm = info0 & HAL_RX_HE_SIG_A_SU_INFO_INFO0_DCM;
+               cp_ltf = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_CP_LTF_SIZE,
+                                  info0);
+               nsts = FIELD_GET(HAL_RX_HE_SIG_A_SU_INFO_INFO0_NSTS, info0);
+
+               switch (cp_ltf) {
+               case 0:
+               case 1:
+                       ppdu_info->gi = HAL_RX_GI_0_8_US;
+                       break;
+               case 2:
+                       ppdu_info->gi = HAL_RX_GI_1_6_US;
+                       break;
+               case 3:
+                       if (dcm && ppdu_info->is_stbc)
+                               ppdu_info->gi = HAL_RX_GI_0_8_US;
+                       else
+                               ppdu_info->gi = HAL_RX_GI_3_2_US;
+                       break;
+               }
+
+               ppdu_info->nss = nsts + 1;
+               ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU;
+               break;
+       }
+       case HAL_PHYRX_HE_SIG_A_MU_DL: {
+               struct hal_rx_he_sig_a_mu_dl_info *he_sig_a_mu_dl =
+                       (struct hal_rx_he_sig_a_mu_dl_info *)tlv_data;
+
+               u32 cp_ltf;
+
+               info0 = __le32_to_cpu(he_sig_a_mu_dl->info0);
+               info1 = __le32_to_cpu(he_sig_a_mu_dl->info1);
+
+               ppdu_info->bw =
+                       FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_TRANSMIT_BW,
+                                 info0);
+               cp_ltf = FIELD_GET(HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_CP_LTF_SIZE,
+                                  info0);
+
+               switch (cp_ltf) {
+               case 0:
+               case 1:
+                       ppdu_info->gi = HAL_RX_GI_0_8_US;
+                       break;
+               case 2:
+                       ppdu_info->gi = HAL_RX_GI_1_6_US;
+                       break;
+               case 3:
+                       ppdu_info->gi = HAL_RX_GI_3_2_US;
+                       break;
+               }
+
+               ppdu_info->is_stbc = info1 &
+                                    HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_STBC;
+               ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO;
+               break;
+       }
+       case HAL_PHYRX_HE_SIG_B1_MU: {
+               /* TODO: Check if resource unit(RU) allocation stats
+                * are required
+                */
+               ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO;
+               break;
+       }
+       case HAL_PHYRX_HE_SIG_B2_MU: {
+               struct hal_rx_he_sig_b2_mu_info *he_sig_b2_mu =
+                       (struct hal_rx_he_sig_b2_mu_info *)tlv_data;
+
+               info0 = __le32_to_cpu(he_sig_b2_mu->info0);
+
+               ppdu_info->mcs =
+                       FIELD_GET(HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_MCS,
+                                 info0);
+               ppdu_info->nss =
+                       FIELD_GET(HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_NSTS,
+                                 info0) + 1;
+               ppdu_info->ldpc = FIELD_GET(HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_CODING,
+                                           info0);
+               break;
+       }
+       case HAL_PHYRX_HE_SIG_B2_OFDMA: {
+               struct hal_rx_he_sig_b2_ofdma_info *he_sig_b2_ofdma =
+                       (struct hal_rx_he_sig_b2_ofdma_info *)tlv_data;
+
+               info0 = __le32_to_cpu(he_sig_b2_ofdma->info0);
+
+               ppdu_info->mcs =
+                       FIELD_GET(HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_MCS,
+                                 info0);
+               ppdu_info->nss =
+                       FIELD_GET(HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_NSTS,
+                                 info0) + 1;
+               ppdu_info->beamformed =
+                       info0 &
+                       HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_TXBF;
+               ppdu_info->ldpc = FIELD_GET(HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_CODING,
+                                           info0);
+               ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_OFDMA;
+               break;
+       }
+       case HAL_PHYRX_RSSI_LEGACY: {
+               struct hal_rx_phyrx_rssi_legacy_info *rssi =
+                       (struct hal_rx_phyrx_rssi_legacy_info *)tlv_data;
+
+               /* TODO: Please note that the combined rssi will not be accurate
+                * in MU case. Rssi in MU needs to be retrieved from
+                * PHYRX_OTHER_RECEIVE_INFO TLV.
+                */
+               ppdu_info->rssi_comb =
+                       FIELD_GET(HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB,
+                                 __le32_to_cpu(rssi->info0));
+               break;
+       }
+       case HAL_RX_MPDU_START: {
+               struct hal_rx_mpdu_info *mpdu_info =
+                       (struct hal_rx_mpdu_info *)tlv_data;
+               u16 peer_id;
+
+               peer_id = FIELD_GET(HAL_RX_MPDU_INFO_INFO0_PEERID,
+                                   __le32_to_cpu(mpdu_info->info0));
+               if (peer_id)
+                       ppdu_info->peer_id = peer_id;
+               break;
+       }
+       case HAL_RXPCU_PPDU_END_INFO: {
+               struct hal_rx_ppdu_end_duration *ppdu_rx_duration =
+                       (struct hal_rx_ppdu_end_duration *)tlv_data;
+               ppdu_info->rx_duration =
+                       FIELD_GET(HAL_RX_PPDU_END_DURATION,
+                                 __le32_to_cpu(ppdu_rx_duration->info0));
+               break;
+       }
+       case HAL_DUMMY:
+               return HAL_RX_MON_STATUS_BUF_DONE;
+       case HAL_RX_PPDU_END_STATUS_DONE:
+       case 0:
+               return HAL_RX_MON_STATUS_PPDU_DONE;
+       default:
+               break;
+       }
+
+       return HAL_RX_MON_STATUS_PPDU_NOT_DONE;
+}
+
+enum hal_rx_mon_status
+ath11k_hal_rx_parse_mon_status(struct ath11k_base *ab,
+                              struct hal_rx_mon_ppdu_info *ppdu_info,
+                              struct sk_buff *skb)
+{
+       struct hal_tlv_hdr *tlv;
+       enum hal_rx_mon_status hal_status = HAL_RX_MON_STATUS_BUF_DONE;
+       u16 tlv_tag;
+       u16 tlv_len;
+       u8 *ptr = skb->data;
+
+       do {
+               tlv = (struct hal_tlv_hdr *)ptr;
+               tlv_tag = FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl);
+               tlv_len = FIELD_GET(HAL_TLV_HDR_LEN, tlv->tl);
+               ptr += sizeof(*tlv);
+
+               /* The actual length of PPDU_END is the combined length of many PHY
+                * TLVs that follow. Skip the TLV header and
+                * rx_rxpcu_classification_overview that follows the header to get to
+                * next TLV.
+                */
+               if (tlv_tag == HAL_RX_PPDU_END)
+                       tlv_len = sizeof(struct hal_rx_rxpcu_classification_overview);
+
+               hal_status = ath11k_hal_rx_parse_mon_status_tlv(ab, ppdu_info,
+                                                               tlv_tag, ptr);
+               ptr += tlv_len;
+               ptr = PTR_ALIGN(ptr, HAL_TLV_ALIGN);
+
+               if ((ptr - skb->data) >= DP_RX_BUFFER_SIZE)
+                       break;
+       } while (hal_status == HAL_RX_MON_STATUS_PPDU_NOT_DONE);
+
+       return hal_status;
+}
+
+void ath11k_hal_rx_reo_ent_buf_paddr_get(void *rx_desc, dma_addr_t *paddr,
+                                        u32 *sw_cookie, void **pp_buf_addr,
+                                        u32  *msdu_cnt)
+{
+       struct hal_reo_entrance_ring *reo_ent_ring =
+               (struct hal_reo_entrance_ring *)rx_desc;
+       struct ath11k_buffer_addr *buf_addr_info;
+       struct rx_mpdu_desc *rx_mpdu_desc_info_details;
+
+       rx_mpdu_desc_info_details =
+                       (struct rx_mpdu_desc *)&reo_ent_ring->rx_mpdu_info;
+
+       *msdu_cnt = FIELD_GET(RX_MPDU_DESC_INFO0_MSDU_COUNT,
+                             rx_mpdu_desc_info_details->info0);
+
+       buf_addr_info = (struct ath11k_buffer_addr *)&reo_ent_ring->buf_addr_info;
+
+       *paddr = (((u64)FIELD_GET(BUFFER_ADDR_INFO1_ADDR,
+                                 buf_addr_info->info1)) << 32) |
+                       FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
+                                 buf_addr_info->info0);
+
+       *sw_cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
+                              buf_addr_info->info1);
+
+       *pp_buf_addr = (void *)buf_addr_info;
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_HAL_RX_H
+#define ATH11K_HAL_RX_H
+
+struct hal_rx_mpdu_meta {
+       u32 peer_meta;
+       u16 msdu_cnt;
+       u16 seq_num;
+       bool frag;
+       bool retry;
+       bool ampdu;
+       bool raw;
+};
+
+struct hal_rx_msdu_meta {
+       u32 cookie;
+       u32 msdu_len;
+       bool first;
+       bool last;
+       bool continuation;
+};
+
+struct hal_rx_meta_info {
+       enum hal_reo_dest_ring_push_reason push_reason;
+       struct hal_rx_mpdu_meta mpdu_meta;
+       struct hal_rx_msdu_meta msdu_meta;
+};
+
+struct hal_rx_wbm_rel_info {
+       u32 cookie;
+       enum hal_wbm_rel_src_module err_rel_src;
+       enum hal_reo_dest_ring_push_reason push_reason;
+       u32 err_code;
+       bool first_msdu;
+       bool last_msdu;
+};
+
+#define HAL_INVALID_PEERID 0xffff
+#define VHT_SIG_SU_NSS_MASK 0x7
+
+#define HAL_RX_MAX_MCS 12
+#define HAL_RX_MAX_NSS 8
+
+struct hal_rx_mon_status_tlv_hdr {
+       u32 hdr;
+       u8 value[0];
+};
+
+enum hal_rx_su_mu_coding {
+       HAL_RX_SU_MU_CODING_BCC,
+       HAL_RX_SU_MU_CODING_LDPC,
+       HAL_RX_SU_MU_CODING_MAX,
+};
+
+enum hal_rx_gi {
+       HAL_RX_GI_0_8_US,
+       HAL_RX_GI_0_4_US,
+       HAL_RX_GI_1_6_US,
+       HAL_RX_GI_3_2_US,
+       HAL_RX_GI_MAX,
+};
+
+enum hal_rx_bw {
+       HAL_RX_BW_20MHZ,
+       HAL_RX_BW_40MHZ,
+       HAL_RX_BW_80MHZ,
+       HAL_RX_BW_160MHZ,
+       HAL_RX_BW_MAX,
+};
+
+enum hal_rx_preamble {
+       HAL_RX_PREAMBLE_11A,
+       HAL_RX_PREAMBLE_11B,
+       HAL_RX_PREAMBLE_11N,
+       HAL_RX_PREAMBLE_11AC,
+       HAL_RX_PREAMBLE_11AX,
+       HAL_RX_PREAMBLE_MAX,
+};
+
+enum hal_rx_reception_type {
+       HAL_RX_RECEPTION_TYPE_SU,
+       HAL_RX_RECEPTION_TYPE_MU_MIMO,
+       HAL_RX_RECEPTION_TYPE_MU_OFDMA,
+       HAL_RX_RECEPTION_TYPE_MU_OFDMA_MIMO,
+       HAL_RX_RECEPTION_TYPE_MAX,
+};
+
+#define HAL_TLV_STATUS_PPDU_NOT_DONE            0
+#define HAL_TLV_STATUS_PPDU_DONE                1
+#define HAL_TLV_STATUS_BUF_DONE                 2
+#define HAL_TLV_STATUS_PPDU_NON_STD_DONE        3
+#define HAL_RX_FCS_LEN                          4
+
+enum hal_rx_mon_status {
+       HAL_RX_MON_STATUS_PPDU_NOT_DONE,
+       HAL_RX_MON_STATUS_PPDU_DONE,
+       HAL_RX_MON_STATUS_BUF_DONE,
+};
+
+struct hal_rx_mon_ppdu_info {
+       u32 ppdu_id;
+       u32 ppdu_ts;
+       u32 num_mpdu_fcs_ok;
+       u32 num_mpdu_fcs_err;
+       u32 preamble_type;
+       u16 chan_num;
+       u16 tcp_msdu_count;
+       u16 tcp_ack_msdu_count;
+       u16 udp_msdu_count;
+       u16 other_msdu_count;
+       u16 peer_id;
+       u8 rate;
+       u8 mcs;
+       u8 nss;
+       u8 bw;
+       u8 is_stbc;
+       u8 gi;
+       u8 ldpc;
+       u8 beamformed;
+       u8 rssi_comb;
+       u8 tid;
+       u8 reception_type;
+       u64 rx_duration;
+};
+
+#define HAL_RX_PPDU_START_INFO0_PPDU_ID                GENMASK(15, 0)
+
+struct hal_rx_ppdu_start {
+       __le32 info0;
+       __le32 chan_num;
+       __le32 ppdu_start_ts;
+} __packed;
+
+#define HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR      GENMASK(25, 16)
+
+#define HAL_RX_PPDU_END_USER_STATS_INFO1_MPDU_CNT_FCS_OK       GENMASK(8, 0)
+#define HAL_RX_PPDU_END_USER_STATS_INFO1_FC_VALID              BIT(9)
+#define HAL_RX_PPDU_END_USER_STATS_INFO1_QOS_CTRL_VALID                BIT(10)
+#define HAL_RX_PPDU_END_USER_STATS_INFO1_HT_CTRL_VALID         BIT(11)
+#define HAL_RX_PPDU_END_USER_STATS_INFO1_PKT_TYPE              GENMASK(23, 20)
+
+#define HAL_RX_PPDU_END_USER_STATS_INFO2_AST_INDEX             GENMASK(15, 0)
+#define HAL_RX_PPDU_END_USER_STATS_INFO2_FRAME_CTRL            GENMASK(31, 16)
+
+#define HAL_RX_PPDU_END_USER_STATS_INFO3_QOS_CTRL              GENMASK(31, 16)
+
+#define HAL_RX_PPDU_END_USER_STATS_INFO4_UDP_MSDU_CNT          GENMASK(15, 0)
+#define HAL_RX_PPDU_END_USER_STATS_INFO4_TCP_MSDU_CNT          GENMASK(31, 16)
+
+#define HAL_RX_PPDU_END_USER_STATS_INFO5_OTHER_MSDU_CNT                GENMASK(15, 0)
+#define HAL_RX_PPDU_END_USER_STATS_INFO5_TCP_ACK_MSDU_CNT      GENMASK(31, 16)
+
+#define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP            GENMASK(15, 0)
+#define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_EOSP_BITMAP       GENMASK(31, 16)
+
+struct hal_rx_ppdu_end_user_stats {
+       __le32 rsvd0[2];
+       __le32 info0;
+       __le32 info1;
+       __le32 info2;
+       __le32 info3;
+       __le32 ht_ctrl;
+       __le32 rsvd1[2];
+       __le32 info4;
+       __le32 info5;
+       __le32 info6;
+       __le32 rsvd2[11];
+} __packed;
+
+#define HAL_RX_HT_SIG_INFO_INFO0_MCS           GENMASK(6, 0)
+#define HAL_RX_HT_SIG_INFO_INFO0_BW            BIT(7)
+
+#define HAL_RX_HT_SIG_INFO_INFO1_STBC          GENMASK(5, 4)
+#define HAL_RX_HT_SIG_INFO_INFO1_FEC_CODING    BIT(6)
+#define HAL_RX_HT_SIG_INFO_INFO1_GI            BIT(7)
+
+struct hal_rx_ht_sig_info {
+       __le32 info0;
+       __le32 info1;
+} __packed;
+
+#define HAL_RX_LSIG_B_INFO_INFO0_RATE  GENMASK(3, 0)
+#define HAL_RX_LSIG_B_INFO_INFO0_LEN   GENMASK(15, 4)
+
+struct hal_rx_lsig_b_info {
+       __le32 info0;
+} __packed;
+
+#define HAL_RX_LSIG_A_INFO_INFO0_RATE          GENMASK(3, 0)
+#define HAL_RX_LSIG_A_INFO_INFO0_LEN           GENMASK(16, 5)
+#define HAL_RX_LSIG_A_INFO_INFO0_PKT_TYPE      GENMASK(27, 24)
+
+struct hal_rx_lsig_a_info {
+       __le32 info0;
+} __packed;
+
+#define HAL_RX_VHT_SIG_A_INFO_INFO0_BW         GENMASK(1, 0)
+#define HAL_RX_VHT_SIG_A_INFO_INFO0_STBC       BIT(3)
+#define HAL_RX_VHT_SIG_A_INFO_INFO0_GROUP_ID   GENMASK(9, 4)
+#define HAL_RX_VHT_SIG_A_INFO_INFO0_NSTS       GENMASK(21, 10)
+
+#define HAL_RX_VHT_SIG_A_INFO_INFO1_GI_SETTING         GENMASK(1, 0)
+#define HAL_RX_VHT_SIG_A_INFO_INFO1_SU_MU_CODING       BIT(2)
+#define HAL_RX_VHT_SIG_A_INFO_INFO1_MCS                        GENMASK(7, 4)
+#define HAL_RX_VHT_SIG_A_INFO_INFO1_BEAMFORMED         BIT(8)
+
+struct hal_rx_vht_sig_a_info {
+       __le32 info0;
+       __le32 info1;
+} __packed;
+
+#define HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_MCS     GENMASK(6, 3)
+#define HAL_RX_HE_SIG_A_SU_INFO_INFO0_DCM              BIT(7)
+#define HAL_RX_HE_SIG_A_SU_INFO_INFO0_TRANSMIT_BW      GENMASK(20, 19)
+#define HAL_RX_HE_SIG_A_SU_INFO_INFO0_CP_LTF_SIZE      GENMASK(22, 21)
+#define HAL_RX_HE_SIG_A_SU_INFO_INFO0_NSTS             GENMASK(25, 23)
+
+#define HAL_RX_HE_SIG_A_SU_INFO_INFO1_CODING           BIT(7)
+#define HAL_RX_HE_SIG_A_SU_INFO_INFO1_STBC             BIT(9)
+#define HAL_RX_HE_SIG_A_SU_INFO_INFO1_TXBF             BIT(10)
+
+struct hal_rx_he_sig_a_su_info {
+       __le32 info0;
+       __le32 info1;
+} __packed;
+
+#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_TRANSMIT_BW   GENMASK(17, 15)
+#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO0_CP_LTF_SIZE   GENMASK(24, 23)
+
+#define HAL_RX_HE_SIG_A_MU_DL_INFO_INFO1_STBC          BIT(12)
+
+struct hal_rx_he_sig_a_mu_dl_info {
+       __le32 info0;
+       __le32 info1;
+} __packed;
+
+#define HAL_RX_HE_SIG_B1_MU_INFO_INFO0_RU_ALLOCATION   GENMASK(7, 0)
+
+struct hal_rx_he_sig_b1_mu_info {
+       __le32 info0;
+} __packed;
+
+#define HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_MCS         GENMASK(18, 15)
+#define HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_CODING      BIT(20)
+#define HAL_RX_HE_SIG_B2_MU_INFO_INFO0_STA_NSTS                GENMASK(31, 29)
+
+struct hal_rx_he_sig_b2_mu_info {
+       __le32 info0;
+} __packed;
+
+#define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_NSTS     GENMASK(13, 11)
+#define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_TXBF     BIT(19)
+#define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_MCS      GENMASK(18, 15)
+#define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_DCM      BIT(19)
+#define HAL_RX_HE_SIG_B2_OFDMA_INFO_INFO0_STA_CODING   BIT(20)
+
+struct hal_rx_he_sig_b2_ofdma_info {
+       __le32 info0;
+} __packed;
+
+#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB  GENMASK(15, 8)
+
+struct hal_rx_phyrx_rssi_legacy_info {
+       __le32 rsvd[35];
+       __le32 info0;
+} __packed;
+
+#define HAL_RX_MPDU_INFO_INFO0_PEERID  GENMASK(31, 16)
+struct hal_rx_mpdu_info {
+       __le32 rsvd0;
+       __le32 info0;
+       __le32 rsvd1[21];
+} __packed;
+
+#define HAL_RX_PPDU_END_DURATION       GENMASK(23, 0)
+struct hal_rx_ppdu_end_duration {
+       __le32 rsvd0[9];
+       __le32 info0;
+       __le32 rsvd1[4];
+} __packed;
+
+struct hal_rx_rxpcu_classification_overview {
+       u32 rsvd0;
+} __packed;
+
+struct hal_rx_msdu_desc_info {
+       u32 msdu_flags;
+       u16 msdu_len; /* 14 bits for length */
+};
+
+#define HAL_RX_NUM_MSDU_DESC 6
+struct hal_rx_msdu_list {
+       struct hal_rx_msdu_desc_info msdu_info[HAL_RX_NUM_MSDU_DESC];
+       u32 sw_cookie[HAL_RX_NUM_MSDU_DESC];
+       u8 rbm[HAL_RX_NUM_MSDU_DESC];
+};
+
+void ath11k_hal_reo_status_queue_stats(struct ath11k_base *ab, u32 *reo_desc,
+                                      struct hal_reo_status *status);
+void ath11k_hal_reo_flush_queue_status(struct ath11k_base *ab, u32 *reo_desc,
+                                      struct hal_reo_status *status);
+void ath11k_hal_reo_flush_cache_status(struct ath11k_base *ab, u32 *reo_desc,
+                                      struct hal_reo_status *status);
+void ath11k_hal_reo_flush_cache_status(struct ath11k_base *ab, u32 *reo_desc,
+                                      struct hal_reo_status *status);
+void ath11k_hal_reo_unblk_cache_status(struct ath11k_base *ab, u32 *reo_desc,
+                                      struct hal_reo_status *status);
+void ath11k_hal_reo_flush_timeout_list_status(struct ath11k_base *ab,
+                                             u32 *reo_desc,
+                                             struct hal_reo_status *status);
+void ath11k_hal_reo_desc_thresh_reached_status(struct ath11k_base *ab,
+                                              u32 *reo_desc,
+                                              struct hal_reo_status *status);
+void ath11k_hal_reo_update_rx_reo_queue_status(struct ath11k_base *ab,
+                                              u32 *reo_desc,
+                                              struct hal_reo_status *status);
+int ath11k_hal_reo_process_status(u8 *reo_desc, u8 *status);
+void ath11k_hal_rx_msdu_link_info_get(void *link_desc, u32 *num_msdus,
+                                     struct hal_rx_msdu_meta *meta,
+                                     enum hal_rx_buf_return_buf_manager *rbm);
+void ath11k_hal_rx_msdu_link_desc_set(struct ath11k_base *ab, void *desc,
+                                     void *link_desc,
+                                     enum hal_wbm_rel_bm_act action);
+void ath11k_hal_rx_buf_addr_info_set(void *desc, dma_addr_t paddr,
+                                    u32 cookie, u8 manager);
+void ath11k_hal_rx_buf_addr_info_get(void *desc, dma_addr_t *paddr,
+                                    u32 *cookie, u8 *rbm);
+int ath11k_hal_desc_reo_parse_err(struct ath11k_base *ab, u32 *rx_desc,
+                                 dma_addr_t *paddr, u32 *desc_bank);
+void ath11k_hal_rx_parse_dst_ring_desc(struct ath11k_base *ab, u32 *rx_desc,
+                                      struct hal_rx_meta_info *meta_info);
+int ath11k_hal_wbm_desc_parse_err(struct ath11k_base *ab, void *desc,
+                                 struct hal_rx_wbm_rel_info *rel_info);
+void ath11k_hal_rx_reo_ent_paddr_get(struct ath11k_base *ab, void *desc,
+                                    dma_addr_t *paddr, u32 *desc_bank);
+void ath11k_hal_rx_reo_ent_buf_paddr_get(void *rx_desc,
+                                        dma_addr_t *paddr, u32 *sw_cookie,
+                                        void **pp_buf_addr_info,
+                                        u32 *msdu_cnt);
+enum hal_rx_mon_status
+ath11k_hal_rx_parse_mon_status(struct ath11k_base *ab,
+                              struct hal_rx_mon_ppdu_info *ppdu_info,
+                              struct sk_buff *skb);
+#define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_0 0xDDBEEF
+#define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1 0xADBEEF
+#define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2 0xBDBEEF
+#define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_3 0xCDBEEF
+#endif
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include "ahb.h"
+#include "hal.h"
+#include "hal_tx.h"
+
+#define DSCP_TID_MAP_TBL_ENTRY_SIZE 64
+
+/* dscp_tid_map - Default DSCP-TID mapping
+ *
+ * DSCP        TID
+ * 000000      0
+ * 001000      1
+ * 010000      2
+ * 011000      3
+ * 100000      4
+ * 101000      5
+ * 110000      6
+ * 111000      7
+ */
+static const u8 dscp_tid_map[DSCP_TID_MAP_TBL_ENTRY_SIZE] = {
+       0, 0, 0, 0, 0, 0, 0, 0,
+       1, 1, 1, 1, 1, 1, 1, 1,
+       2, 2, 2, 2, 2, 2, 2, 2,
+       3, 3, 3, 3, 3, 3, 3, 3,
+       4, 4, 4, 4, 4, 4, 4, 4,
+       5, 5, 5, 5, 5, 5, 5, 5,
+       6, 6, 6, 6, 6, 6, 6, 6,
+       7, 7, 7, 7, 7, 7, 7, 7,
+};
+
+void ath11k_hal_tx_cmd_desc_setup(struct ath11k_base *ab, void *cmd,
+                                 struct hal_tx_info *ti)
+{
+       struct hal_tcl_data_cmd *tcl_cmd = (struct hal_tcl_data_cmd *)cmd;
+
+       tcl_cmd->buf_addr_info.info0 =
+               FIELD_PREP(BUFFER_ADDR_INFO0_ADDR, ti->paddr);
+       tcl_cmd->buf_addr_info.info1 =
+               FIELD_PREP(BUFFER_ADDR_INFO1_ADDR,
+                          ((uint64_t)ti->paddr >> HAL_ADDR_MSB_REG_SHIFT));
+       tcl_cmd->buf_addr_info.info1 |=
+               FIELD_PREP(BUFFER_ADDR_INFO1_RET_BUF_MGR,
+                          (ti->ring_id + HAL_RX_BUF_RBM_SW0_BM)) |
+               FIELD_PREP(BUFFER_ADDR_INFO1_SW_COOKIE, ti->desc_id);
+
+       tcl_cmd->info0 =
+               FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_DESC_TYPE, ti->type) |
+               FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_ENCAP_TYPE, ti->encap_type) |
+               FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_ENCRYPT_TYPE,
+                          ti->encrypt_type) |
+               FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_ADDRX_EN,
+                          ti->addr_search_flags) |
+               FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_ADDRY_EN,
+                          ti->addr_search_flags) |
+               FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_CMD_NUM,
+                          ti->meta_data_flags);
+
+       tcl_cmd->info1 = ti->flags0 |
+               FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_DATA_LEN, ti->data_len) |
+               FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_PKT_OFFSET, ti->pkt_offset);
+
+       tcl_cmd->info2 = ti->flags1 |
+               FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TID, ti->tid) |
+               FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_LMAC_ID, ti->lmac_id);
+
+       tcl_cmd->info3 = FIELD_PREP(HAL_TCL_DATA_CMD_INFO3_DSCP_TID_TABLE_IDX,
+                                   ti->dscp_tid_tbl_idx) |
+                        FIELD_PREP(HAL_TCL_DATA_CMD_INFO3_SEARCH_INDEX,
+                                   ti->bss_ast_hash);
+}
+
+/* Commit the descriptor to hardware */
+void ath11k_hal_tx_desc_sync(void *tx_desc_cached, void *hw_desc)
+{
+       memcpy(hw_desc + sizeof(struct hal_tlv_hdr), tx_desc_cached,
+              sizeof(struct hal_tcl_data_cmd));
+}
+
+/* Get the descriptor status from hardware */
+void ath11k_hal_tx_status_desc_sync(void *hw_desc, void *local_desc)
+{
+       memcpy(local_desc, hw_desc, HAL_TX_STATUS_DESC_LEN);
+}
+
+void ath11k_hal_tx_status_parse(struct ath11k_base *ab,
+                               struct hal_wbm_release_ring *desc,
+                               struct hal_tx_status *ts)
+{
+       ts->buf_rel_source =
+               FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0);
+       if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW &&
+           ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)
+               return;
+
+       ts->desc_id = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,
+                               desc->buf_addr_info.info1);
+
+       if (ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)
+               return;
+
+       ts->status = FIELD_GET(HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON,
+                              desc->info0);
+       ts->ppdu_id = FIELD_GET(HAL_WBM_RELEASE_INFO1_TQM_STATUS_NUMBER,
+                               desc->info1);
+       ts->try_cnt = FIELD_GET(HAL_WBM_RELEASE_INFO1_TRANSMIT_COUNT,
+                               desc->info1);
+
+       ts->ack_rssi = FIELD_GET(HAL_WBM_RELEASE_INFO2_ACK_FRAME_RSSI,
+                                desc->info2);
+       if (desc->info2 & HAL_WBM_RELEASE_INFO2_FIRST_MSDU)
+               ts->flags |= HAL_TX_STATUS_FLAGS_FIRST_MSDU;
+
+       if (desc->info2 & HAL_WBM_RELEASE_INFO2_LAST_MSDU)
+               ts->flags |= HAL_TX_STATUS_FLAGS_LAST_MSDU;
+
+       if (desc->info2 & HAL_WBM_RELEASE_INFO2_MSDU_IN_AMSDU)
+               ts->flags |= HAL_TX_STATUS_FLAGS_MSDU_IN_AMSDU;
+
+       ts->peer_id = FIELD_GET(HAL_WBM_RELEASE_INFO3_PEER_ID, desc->info3);
+       ts->tid = FIELD_GET(HAL_WBM_RELEASE_INFO3_TID, desc->info3);
+
+       if (!(desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_VALID))
+               return;
+
+       ts->flags |= HAL_TX_STATUS_FLAGS_RATE_STATS_VALID;
+       ts->tsf = desc->rate_stats.tsf;
+       ts->bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, desc->rate_stats.info0);
+       ts->pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE,
+                                desc->rate_stats.info0);
+       if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_STBC)
+               ts->flags |= HAL_TX_STATUS_FLAGS_RATE_STBC;
+       if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_LDPC)
+               ts->flags |= HAL_TX_STATUS_FLAGS_RATE_LDPC;
+       if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_OFDMA_TX)
+               ts->flags |= HAL_TX_STATUS_FLAGS_OFDMA;
+
+       ts->sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI,
+                           desc->rate_stats.info0);
+       ts->mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS,
+                           desc->rate_stats.info0);
+       ts->num_tones_in_ru = FIELD_GET(HAL_TX_RATE_STATS_INFO0_TONES_IN_RU,
+                                       desc->rate_stats.info0);
+}
+
+void ath11k_hal_tx_set_dscp_tid_map(struct ath11k_base *ab, int id)
+{
+       u32 ctrl_reg_val;
+       u32 addr;
+       u8 hw_map_val[HAL_DSCP_TID_TBL_SIZE];
+       int i;
+       u32 value;
+       int cnt = 0;
+
+       ctrl_reg_val = ath11k_ahb_read32(ab, HAL_SEQ_WCSS_UMAC_TCL_REG +
+                                        HAL_TCL1_RING_CMN_CTRL_REG);
+       /* Enable read/write access */
+       ctrl_reg_val |= HAL_TCL1_RING_CMN_CTRL_DSCP_TID_MAP_PROG_EN;
+       ath11k_ahb_write32(ab, HAL_SEQ_WCSS_UMAC_TCL_REG +
+                          HAL_TCL1_RING_CMN_CTRL_REG, ctrl_reg_val);
+
+       addr = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_DSCP_TID_MAP +
+              (4 * id * (HAL_DSCP_TID_TBL_SIZE / 4));
+
+       /* Configure each DSCP-TID mapping in three bits there by configure
+        * three bytes in an iteration.
+        */
+       for (i = 0; i < DSCP_TID_MAP_TBL_ENTRY_SIZE; i += 8) {
+               value = FIELD_PREP(HAL_TCL1_RING_FIELD_DSCP_TID_MAP0,
+                                  dscp_tid_map[i]) |
+                       FIELD_PREP(HAL_TCL1_RING_FIELD_DSCP_TID_MAP1,
+                                  dscp_tid_map[i + 1]) |
+                       FIELD_PREP(HAL_TCL1_RING_FIELD_DSCP_TID_MAP2,
+                                  dscp_tid_map[i + 2]) |
+                       FIELD_PREP(HAL_TCL1_RING_FIELD_DSCP_TID_MAP3,
+                                  dscp_tid_map[i + 3]) |
+                       FIELD_PREP(HAL_TCL1_RING_FIELD_DSCP_TID_MAP4,
+                                  dscp_tid_map[i + 4]) |
+                       FIELD_PREP(HAL_TCL1_RING_FIELD_DSCP_TID_MAP5,
+                                  dscp_tid_map[i + 5]) |
+                       FIELD_PREP(HAL_TCL1_RING_FIELD_DSCP_TID_MAP6,
+                                  dscp_tid_map[i + 6]) |
+                       FIELD_PREP(HAL_TCL1_RING_FIELD_DSCP_TID_MAP7,
+                                  dscp_tid_map[i + 7]);
+               memcpy(&hw_map_val[cnt], (u8 *)&value, 3);
+               cnt += 3;
+       }
+
+       for (i = 0; i < HAL_DSCP_TID_TBL_SIZE; i += 4) {
+               ath11k_ahb_write32(ab, addr, *(u32 *)&hw_map_val[i]);
+               addr += 4;
+       }
+
+       /* Disable read/write access */
+       ctrl_reg_val = ath11k_ahb_read32(ab, HAL_SEQ_WCSS_UMAC_TCL_REG +
+                                        HAL_TCL1_RING_CMN_CTRL_REG);
+       ctrl_reg_val &= ~HAL_TCL1_RING_CMN_CTRL_DSCP_TID_MAP_PROG_EN;
+       ath11k_ahb_write32(ab, HAL_SEQ_WCSS_UMAC_TCL_REG +
+                          HAL_TCL1_RING_CMN_CTRL_REG,
+                          ctrl_reg_val);
+}
+
+void ath11k_hal_tx_init_data_ring(struct ath11k_base *ab, struct hal_srng *srng)
+{
+       struct hal_srng_params params;
+       struct hal_tlv_hdr *tlv;
+       int i, entry_size;
+       u8 *desc;
+
+       memset(¶ms, 0, sizeof(params));
+
+       entry_size = ath11k_hal_srng_get_entrysize(HAL_TCL_DATA);
+       ath11k_hal_srng_get_params(ab, srng, ¶ms);
+       desc = (u8 *)params.ring_base_vaddr;
+
+       for (i = 0; i < params.num_entries; i++) {
+               tlv = (struct hal_tlv_hdr *)desc;
+               tlv->tl = FIELD_PREP(HAL_TLV_HDR_TAG, HAL_TCL_DATA_CMD) |
+                         FIELD_PREP(HAL_TLV_HDR_LEN,
+                                    sizeof(struct hal_tcl_data_cmd));
+               desc += entry_size;
+       }
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_HAL_TX_H
+#define ATH11K_HAL_TX_H
+
+#include "hal_desc.h"
+
+#define HAL_TX_ADDRX_EN                        1
+#define HAL_TX_ADDRY_EN                        2
+
+#define HAL_TX_ADDR_SEARCH_INDEX       0
+#define HAL_TX_ADDR_SEARCH_DEFAULT     1
+
+struct hal_tx_info {
+       u16 meta_data_flags; /* %HAL_TCL_DATA_CMD_INFO0_META_ */
+       u8 ring_id;
+       u32 desc_id;
+       enum hal_tcl_desc_type type;
+       enum hal_tcl_encap_type encap_type;
+       dma_addr_t paddr;
+       u32 data_len;
+       u32 pkt_offset;
+       enum hal_encrypt_type encrypt_type;
+       u32 flags0; /* %HAL_TCL_DATA_CMD_INFO1_ */
+       u32 flags1; /* %HAL_TCL_DATA_CMD_INFO2_ */
+       u16 addr_search_flags; /* %HAL_TCL_DATA_CMD_INFO0_ADDR(X/Y)_ */
+       u16 bss_ast_hash;
+       u8 tid;
+       u8 search_type; /* %HAL_TX_ADDR_SEARCH_ */
+       u8 lmac_id;
+       u8 dscp_tid_tbl_idx;
+};
+
+/* TODO: Check if the actual desc macros can be used instead */
+#define HAL_TX_STATUS_FLAGS_FIRST_MSDU         BIT(0)
+#define HAL_TX_STATUS_FLAGS_LAST_MSDU          BIT(1)
+#define HAL_TX_STATUS_FLAGS_MSDU_IN_AMSDU      BIT(2)
+#define HAL_TX_STATUS_FLAGS_RATE_STATS_VALID   BIT(3)
+#define HAL_TX_STATUS_FLAGS_RATE_LDPC          BIT(4)
+#define HAL_TX_STATUS_FLAGS_RATE_STBC          BIT(5)
+#define HAL_TX_STATUS_FLAGS_OFDMA              BIT(6)
+
+#define HAL_TX_STATUS_DESC_LEN         sizeof(struct hal_wbm_release_ring)
+
+/* Tx status parsed from srng desc */
+struct hal_tx_status {
+       enum hal_wbm_rel_src_module buf_rel_source;
+       u32 desc_id;
+       enum hal_wbm_tqm_rel_reason status;
+       u8 ack_rssi;
+       enum hal_tx_rate_stats_bw bw;
+       enum hal_tx_rate_stats_pkt_type pkt_type;
+       enum hal_tx_rate_stats_sgi sgi;
+       u8 mcs;
+       u16 num_tones_in_ru;
+       u32 flags; /* %HAL_TX_STATUS_FLAGS_ */
+       u32 tsf;
+       u32 ppdu_id;
+       u8 try_cnt;
+       u8 tid;
+       u16 peer_id;
+};
+
+void ath11k_hal_tx_cmd_desc_setup(struct ath11k_base *ab, void *cmd,
+                                 struct hal_tx_info *ti);
+void ath11k_hal_tx_desc_sync(void *tx_desc_cached, void *hw_desc);
+void ath11k_hal_tx_status_parse(struct ath11k_base *ab,
+                               struct hal_wbm_release_ring *desc,
+                               struct hal_tx_status *ts);
+void ath11k_hal_tx_status_desc_sync(void *hw_desc, void *local_desc);
+void ath11k_hal_tx_set_dscp_tid_map(struct ath11k_base *ab, int id);
+int ath11k_hal_reo_cmd_send(struct ath11k_base *ab, struct hal_srng *srng,
+                           enum hal_reo_cmd_type type,
+                           struct ath11k_hal_reo_cmd *cmd);
+void ath11k_hal_tx_init_data_ring(struct ath11k_base *ab,
+                                 struct hal_srng *srng);
+#endif
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+#include <linux/skbuff.h>
+#include <linux/ctype.h>
+
+#include "ahb.h"
+#include "debug.h"
+
+struct sk_buff *ath11k_htc_alloc_skb(struct ath11k_base *ab, int size)
+{
+       struct sk_buff *skb;
+
+       skb = dev_alloc_skb(size + sizeof(struct ath11k_htc_hdr));
+       if (!skb)
+               return NULL;
+
+       skb_reserve(skb, sizeof(struct ath11k_htc_hdr));
+
+       /* FW/HTC requires 4-byte aligned streams */
+       if (!IS_ALIGNED((unsigned long)skb->data, 4))
+               ath11k_warn(ab, "Unaligned HTC tx skb\n");
+
+       return skb;
+}
+
+static void ath11k_htc_control_tx_complete(struct ath11k_base *ab,
+                                          struct sk_buff *skb)
+{
+       kfree_skb(skb);
+}
+
+static struct sk_buff *ath11k_htc_build_tx_ctrl_skb(void *ab)
+{
+       struct sk_buff *skb;
+       struct ath11k_skb_cb *skb_cb;
+
+       skb = dev_alloc_skb(ATH11K_HTC_CONTROL_BUFFER_SIZE);
+       if (!skb)
+               return NULL;
+
+       skb_reserve(skb, sizeof(struct ath11k_htc_hdr));
+       WARN_ON_ONCE(!IS_ALIGNED((unsigned long)skb->data, 4));
+
+       skb_cb = ATH11K_SKB_CB(skb);
+       memset(skb_cb, 0, sizeof(*skb_cb));
+
+       ath11k_dbg(ab, ATH11K_DBG_HTC, "%s: skb %pK\n", __func__, skb);
+       return skb;
+}
+
+static inline void ath11k_htc_restore_tx_skb(struct ath11k_htc *htc,
+                                            struct sk_buff *skb)
+{
+       struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
+
+       dma_unmap_single(htc->ab->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
+       skb_pull(skb, sizeof(struct ath11k_htc_hdr));
+}
+
+static void ath11k_htc_prepare_tx_skb(struct ath11k_htc_ep *ep,
+                                     struct sk_buff *skb)
+{
+       struct ath11k_htc_hdr *hdr;
+
+       hdr = (struct ath11k_htc_hdr *)skb->data;
+
+       memset(hdr, 0, sizeof(*hdr));
+       hdr->htc_info = FIELD_PREP(HTC_HDR_ENDPOINTID, ep->eid) |
+                       FIELD_PREP(HTC_HDR_PAYLOADLEN,
+                                  (skb->len - sizeof(*hdr))) |
+                       FIELD_PREP(HTC_HDR_FLAGS,
+                                  ATH11K_HTC_FLAG_NEED_CREDIT_UPDATE);
+
+       spin_lock_bh(&ep->htc->tx_lock);
+       hdr->ctrl_info = FIELD_PREP(HTC_HDR_CONTROLBYTES1, ep->seq_no++);
+       spin_unlock_bh(&ep->htc->tx_lock);
+}
+
+int ath11k_htc_send(struct ath11k_htc *htc,
+                   enum ath11k_htc_ep_id eid,
+                   struct sk_buff *skb)
+{
+       struct ath11k_htc_ep *ep = &htc->endpoint[eid];
+       struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
+       struct device *dev = htc->ab->dev;
+       struct ath11k_base *ab = htc->ab;
+       int credits = 0;
+       int ret;
+
+       if (eid >= ATH11K_HTC_EP_COUNT) {
+               ath11k_warn(ab, "Invalid endpoint id: %d\n", eid);
+               return -ENOENT;
+       }
+
+       skb_push(skb, sizeof(struct ath11k_htc_hdr));
+
+       if (ep->tx_credit_flow_enabled) {
+               credits = DIV_ROUND_UP(skb->len, htc->target_credit_size);
+               spin_lock_bh(&htc->tx_lock);
+               if (ep->tx_credits < credits) {
+                       ath11k_dbg(ab, ATH11K_DBG_HTC,
+                                  "htc insufficient credits ep %d required %d available %d\n",
+                                  eid, credits, ep->tx_credits);
+                       spin_unlock_bh(&htc->tx_lock);
+                       ret = -EAGAIN;
+                       goto err_pull;
+               }
+               ep->tx_credits -= credits;
+               ath11k_dbg(ab, ATH11K_DBG_HTC,
+                          "htc ep %d consumed %d credits (total %d)\n",
+                          eid, credits, ep->tx_credits);
+               spin_unlock_bh(&htc->tx_lock);
+       }
+
+       ath11k_htc_prepare_tx_skb(ep, skb);
+
+       skb_cb->eid = eid;
+       skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
+       ret = dma_mapping_error(dev, skb_cb->paddr);
+       if (ret) {
+               ret = -EIO;
+               goto err_credits;
+       }
+
+       ret = ath11k_ce_send(htc->ab, skb, ep->ul_pipe_id, ep->eid);
+       if (ret)
+               goto err_unmap;
+
+       return 0;
+
+err_unmap:
+       dma_unmap_single(dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
+err_credits:
+       if (ep->tx_credit_flow_enabled) {
+               spin_lock_bh(&htc->tx_lock);
+               ep->tx_credits += credits;
+               ath11k_dbg(ab, ATH11K_DBG_HTC,
+                          "htc ep %d reverted %d credits back (total %d)\n",
+                          eid, credits, ep->tx_credits);
+               spin_unlock_bh(&htc->tx_lock);
+
+               if (ep->ep_ops.ep_tx_credits)
+                       ep->ep_ops.ep_tx_credits(htc->ab);
+       }
+err_pull:
+       skb_pull(skb, sizeof(struct ath11k_htc_hdr));
+       return ret;
+}
+
+static void
+ath11k_htc_process_credit_report(struct ath11k_htc *htc,
+                                const struct ath11k_htc_credit_report *report,
+                                int len,
+                                enum ath11k_htc_ep_id eid)
+{
+       struct ath11k_base *ab = htc->ab;
+       struct ath11k_htc_ep *ep;
+       int i, n_reports;
+
+       if (len % sizeof(*report))
+               ath11k_warn(ab, "Uneven credit report len %d", len);
+
+       n_reports = len / sizeof(*report);
+
+       spin_lock_bh(&htc->tx_lock);
+       for (i = 0; i < n_reports; i++, report++) {
+               if (report->eid >= ATH11K_HTC_EP_COUNT)
+                       break;
+
+               ep = &htc->endpoint[report->eid];
+               ep->tx_credits += report->credits;
+
+               ath11k_dbg(ab, ATH11K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
+                          report->eid, report->credits, ep->tx_credits);
+
+               if (ep->ep_ops.ep_tx_credits) {
+                       spin_unlock_bh(&htc->tx_lock);
+                       ep->ep_ops.ep_tx_credits(htc->ab);
+                       spin_lock_bh(&htc->tx_lock);
+               }
+       }
+       spin_unlock_bh(&htc->tx_lock);
+}
+
+static int ath11k_htc_process_trailer(struct ath11k_htc *htc,
+                                     u8 *buffer,
+                                     int length,
+                                     enum ath11k_htc_ep_id src_eid)
+{
+       struct ath11k_base *ab = htc->ab;
+       int status = 0;
+       struct ath11k_htc_record *record;
+       size_t len;
+
+       while (length > 0) {
+               record = (struct ath11k_htc_record *)buffer;
+
+               if (length < sizeof(record->hdr)) {
+                       status = -EINVAL;
+                       break;
+               }
+
+               if (record->hdr.len > length) {
+                       /* no room left in buffer for record */
+                       ath11k_warn(ab, "Invalid record length: %d\n",
+                                   record->hdr.len);
+                       status = -EINVAL;
+                       break;
+               }
+
+               switch (record->hdr.id) {
+               case ATH11K_HTC_RECORD_CREDITS:
+                       len = sizeof(struct ath11k_htc_credit_report);
+                       if (record->hdr.len < len) {
+                               ath11k_warn(ab, "Credit report too long\n");
+                               status = -EINVAL;
+                               break;
+                       }
+                       ath11k_htc_process_credit_report(htc,
+                                                        record->credit_report,
+                                                        record->hdr.len,
+                                                        src_eid);
+                       break;
+               default:
+                       ath11k_warn(ab, "Unhandled record: id:%d length:%d\n",
+                                   record->hdr.id, record->hdr.len);
+                       break;
+               }
+
+               if (status)
+                       break;
+
+               /* multiple records may be present in a trailer */
+               buffer += sizeof(record->hdr) + record->hdr.len;
+               length -= sizeof(record->hdr) + record->hdr.len;
+       }
+
+       return status;
+}
+
+void ath11k_htc_rx_completion_handler(struct ath11k_base *ab,
+                                     struct sk_buff *skb)
+{
+       int status = 0;
+       struct ath11k_htc *htc = &ab->htc;
+       struct ath11k_htc_hdr *hdr;
+       struct ath11k_htc_ep *ep;
+       u16 payload_len;
+       u32 trailer_len = 0;
+       size_t min_len;
+       u8 eid;
+       bool trailer_present;
+
+       hdr = (struct ath11k_htc_hdr *)skb->data;
+       skb_pull(skb, sizeof(*hdr));
+
+       eid = FIELD_GET(HTC_HDR_ENDPOINTID, hdr->htc_info);
+
+       if (eid >= ATH11K_HTC_EP_COUNT) {
+               ath11k_warn(ab, "HTC Rx: invalid eid %d\n", eid);
+               goto out;
+       }
+
+       ep = &htc->endpoint[eid];
+
+       payload_len = FIELD_GET(HTC_HDR_PAYLOADLEN, hdr->htc_info);
+
+       if (payload_len + sizeof(*hdr) > ATH11K_HTC_MAX_LEN) {
+               ath11k_warn(ab, "HTC rx frame too long, len: %zu\n",
+                           payload_len + sizeof(*hdr));
+               goto out;
+       }
+
+       if (skb->len < payload_len) {
+               ath11k_warn(ab, "HTC Rx: insufficient length, got %d, expected %d\n",
+                           skb->len, payload_len);
+               goto out;
+       }
+
+       /* get flags to check for trailer */
+       trailer_present = (FIELD_GET(HTC_HDR_FLAGS, hdr->htc_info)) &
+                         ATH11K_HTC_FLAG_TRAILER_PRESENT;
+
+       if (trailer_present) {
+               u8 *trailer;
+
+               trailer_len = FIELD_GET(HTC_HDR_CONTROLBYTES0, hdr->ctrl_info);
+               min_len = sizeof(struct ath11k_htc_record_hdr);
+
+               if ((trailer_len < min_len) ||
+                   (trailer_len > payload_len)) {
+                       ath11k_warn(ab, "Invalid trailer length: %d\n",
+                                   trailer_len);
+                       goto out;
+               }
+
+               trailer = (u8 *)hdr;
+               trailer += sizeof(*hdr);
+               trailer += payload_len;
+               trailer -= trailer_len;
+               status = ath11k_htc_process_trailer(htc, trailer,
+                                                   trailer_len, eid);
+               if (status)
+                       goto out;
+
+               skb_trim(skb, skb->len - trailer_len);
+       }
+
+       if (trailer_len >= payload_len)
+               /* zero length packet with trailer data, just drop these */
+               goto out;
+
+       if (eid == ATH11K_HTC_EP_0) {
+               struct ath11k_htc_msg *msg = (struct ath11k_htc_msg *)skb->data;
+
+               switch (FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id)) {
+               case ATH11K_HTC_MSG_READY_ID:
+               case ATH11K_HTC_MSG_CONNECT_SERVICE_RESP_ID:
+                       /* handle HTC control message */
+                       if (completion_done(&htc->ctl_resp)) {
+                               /* this is a fatal error, target should not be
+                                * sending unsolicited messages on the ep 0
+                                */
+                               ath11k_warn(ab, "HTC rx ctrl still processing\n");
+                               complete(&htc->ctl_resp);
+                               goto out;
+                       }
+
+                       htc->control_resp_len =
+                               min_t(int, skb->len,
+                                     ATH11K_HTC_MAX_CTRL_MSG_LEN);
+
+                       memcpy(htc->control_resp_buffer, skb->data,
+                              htc->control_resp_len);
+
+                       complete(&htc->ctl_resp);
+                       break;
+               default:
+                       ath11k_warn(ab, "ignoring unsolicited htc ep0 event\n");
+                       break;
+               }
+               goto out;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_HTC, "htc rx completion ep %d skb %pK\n",
+                  eid, skb);
+       ep->ep_ops.ep_rx_complete(ab, skb);
+
+       /* poll tx completion for interrupt disabled CE's */
+       ath11k_ce_poll_send_completed(ab, ep->ul_pipe_id);
+
+       /* skb is now owned by the rx completion handler */
+       skb = NULL;
+out:
+       kfree_skb(skb);
+}
+
+static void ath11k_htc_control_rx_complete(struct ath11k_base *ab,
+                                          struct sk_buff *skb)
+{
+       /* This is unexpected. FW is not supposed to send regular rx on this
+        * endpoint.
+        */
+       ath11k_warn(ab, "unexpected htc rx\n");
+       kfree_skb(skb);
+}
+
+static const char *htc_service_name(enum ath11k_htc_svc_id id)
+{
+       switch (id) {
+       case ATH11K_HTC_SVC_ID_RESERVED:
+               return "Reserved";
+       case ATH11K_HTC_SVC_ID_RSVD_CTRL:
+               return "Control";
+       case ATH11K_HTC_SVC_ID_WMI_CONTROL:
+               return "WMI";
+       case ATH11K_HTC_SVC_ID_WMI_DATA_BE:
+               return "DATA BE";
+       case ATH11K_HTC_SVC_ID_WMI_DATA_BK:
+               return "DATA BK";
+       case ATH11K_HTC_SVC_ID_WMI_DATA_VI:
+               return "DATA VI";
+       case ATH11K_HTC_SVC_ID_WMI_DATA_VO:
+               return "DATA VO";
+       case ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1:
+               return "WMI MAC1";
+       case ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2:
+               return "WMI MAC2";
+       case ATH11K_HTC_SVC_ID_NMI_CONTROL:
+               return "NMI Control";
+       case ATH11K_HTC_SVC_ID_NMI_DATA:
+               return "NMI Data";
+       case ATH11K_HTC_SVC_ID_HTT_DATA_MSG:
+               return "HTT Data";
+       case ATH11K_HTC_SVC_ID_TEST_RAW_STREAMS:
+               return "RAW";
+       case ATH11K_HTC_SVC_ID_IPA_TX:
+               return "IPA TX";
+       case ATH11K_HTC_SVC_ID_PKT_LOG:
+               return "PKT LOG";
+       }
+
+       return "Unknown";
+}
+
+static void ath11k_htc_reset_endpoint_states(struct ath11k_htc *htc)
+{
+       struct ath11k_htc_ep *ep;
+       int i;
+
+       for (i = ATH11K_HTC_EP_0; i < ATH11K_HTC_EP_COUNT; i++) {
+               ep = &htc->endpoint[i];
+               ep->service_id = ATH11K_HTC_SVC_ID_UNUSED;
+               ep->max_ep_message_len = 0;
+               ep->max_tx_queue_depth = 0;
+               ep->eid = i;
+               ep->htc = htc;
+               ep->tx_credit_flow_enabled = true;
+       }
+}
+
+static u8 ath11k_htc_get_credit_allocation(struct ath11k_htc *htc,
+                                          u16 service_id)
+{
+       u8 i, allocation = 0;
+
+       for (i = 0; i < ATH11K_HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) {
+               if (htc->service_alloc_table[i].service_id == service_id) {
+                       allocation =
+                               htc->service_alloc_table[i].credit_allocation;
+               }
+       }
+
+       return allocation;
+}
+
+static int ath11k_htc_setup_target_buffer_assignments(struct ath11k_htc *htc)
+{
+       struct ath11k_htc_svc_tx_credits *serv_entry;
+       u32 svc_id[] = {
+               ATH11K_HTC_SVC_ID_WMI_CONTROL,
+               ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1,
+               ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2,
+       };
+       int i, credits;
+
+       credits =  htc->total_transmit_credits;
+       serv_entry = htc->service_alloc_table;
+
+       if ((htc->wmi_ep_count == 0) ||
+           (htc->wmi_ep_count > ARRAY_SIZE(svc_id)))
+               return -EINVAL;
+
+       /* Divide credits among number of endpoints for WMI */
+       credits = credits / htc->wmi_ep_count;
+       for (i = 0; i < htc->wmi_ep_count; i++) {
+               serv_entry[i].service_id = svc_id[i];
+               serv_entry[i].credit_allocation = credits;
+       }
+
+       return 0;
+}
+
+int ath11k_htc_wait_target(struct ath11k_htc *htc)
+{
+       int i, status = 0;
+       struct ath11k_base *ab = htc->ab;
+       unsigned long time_left;
+       struct ath11k_htc_ready *ready;
+       u16 message_id;
+       u16 credit_count;
+       u16 credit_size;
+
+       time_left = wait_for_completion_timeout(&htc->ctl_resp,
+                                               ATH11K_HTC_WAIT_TIMEOUT_HZ);
+       if (!time_left) {
+               ath11k_warn(ab, "failed to receive control response completion, polling..\n");
+
+               for (i = 0; i < CE_COUNT; i++)
+                       ath11k_ce_per_engine_service(htc->ab, i);
+
+               time_left =
+                       wait_for_completion_timeout(&htc->ctl_resp,
+                                                   ATH11K_HTC_WAIT_TIMEOUT_HZ);
+
+               if (!time_left)
+                       status = -ETIMEDOUT;
+       }
+
+       if (status < 0) {
+               ath11k_warn(ab, "ctl_resp never came in (%d)\n", status);
+               return status;
+       }
+
+       if (htc->control_resp_len < sizeof(*ready)) {
+               ath11k_warn(ab, "Invalid HTC ready msg len:%d\n",
+                           htc->control_resp_len);
+               return -ECOMM;
+       }
+
+       ready = (struct ath11k_htc_ready *)htc->control_resp_buffer;
+       message_id   = FIELD_GET(HTC_MSG_MESSAGEID, ready->id_credit_count);
+       credit_count = FIELD_GET(HTC_READY_MSG_CREDITCOUNT,
+                                ready->id_credit_count);
+       credit_size  = FIELD_GET(HTC_READY_MSG_CREDITSIZE, ready->size_ep);
+
+       if (message_id != ATH11K_HTC_MSG_READY_ID) {
+               ath11k_warn(ab, "Invalid HTC ready msg: 0x%x\n", message_id);
+               return -ECOMM;
+       }
+
+       htc->total_transmit_credits = credit_count;
+       htc->target_credit_size = credit_size;
+
+       ath11k_dbg(ab, ATH11K_DBG_HTC,
+                  "Target ready! transmit resources: %d size:%d\n",
+                  htc->total_transmit_credits, htc->target_credit_size);
+
+       if ((htc->total_transmit_credits == 0) ||
+           (htc->target_credit_size == 0)) {
+               ath11k_warn(ab, "Invalid credit size received\n");
+               return -ECOMM;
+       }
+
+       ath11k_htc_setup_target_buffer_assignments(htc);
+
+       return 0;
+}
+
+int ath11k_htc_connect_service(struct ath11k_htc *htc,
+                              struct ath11k_htc_svc_conn_req *conn_req,
+                              struct ath11k_htc_svc_conn_resp *conn_resp)
+{
+       struct ath11k_base *ab = htc->ab;
+       struct ath11k_htc_conn_svc *req_msg;
+       struct ath11k_htc_conn_svc_resp resp_msg_dummy;
+       struct ath11k_htc_conn_svc_resp *resp_msg = &resp_msg_dummy;
+       enum ath11k_htc_ep_id assigned_eid = ATH11K_HTC_EP_COUNT;
+       struct ath11k_htc_ep *ep;
+       struct sk_buff *skb;
+       unsigned int max_msg_size = 0;
+       int length, status;
+       unsigned long time_left;
+       bool disable_credit_flow_ctrl = false;
+       u16 message_id, service_id, flags = 0;
+       u8 tx_alloc = 0;
+
+       /* special case for HTC pseudo control service */
+       if (conn_req->service_id == ATH11K_HTC_SVC_ID_RSVD_CTRL) {
+               disable_credit_flow_ctrl = true;
+               assigned_eid = ATH11K_HTC_EP_0;
+               max_msg_size = ATH11K_HTC_MAX_CTRL_MSG_LEN;
+               memset(&resp_msg_dummy, 0, sizeof(resp_msg_dummy));
+               goto setup;
+       }
+
+       tx_alloc = ath11k_htc_get_credit_allocation(htc,
+                                                   conn_req->service_id);
+       if (!tx_alloc)
+               ath11k_dbg(ab, ATH11K_DBG_BOOT,
+                          "boot htc service %s does not allocate target credits\n",
+                          htc_service_name(conn_req->service_id));
+
+       skb = ath11k_htc_build_tx_ctrl_skb(htc->ab);
+       if (!skb) {
+               ath11k_warn(ab, "Failed to allocate HTC packet\n");
+               return -ENOMEM;
+       }
+
+       length = sizeof(*req_msg);
+       skb_put(skb, length);
+       memset(skb->data, 0, length);
+
+       req_msg = (struct ath11k_htc_conn_svc *)skb->data;
+       req_msg->msg_svc_id = FIELD_PREP(HTC_MSG_MESSAGEID,
+                                        ATH11K_HTC_MSG_CONNECT_SERVICE_ID);
+
+       flags |= FIELD_PREP(ATH11K_HTC_CONN_FLAGS_RECV_ALLOC, tx_alloc);
+
+       /* Only enable credit flow control for WMI ctrl service */
+       if (!(conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL ||
+             conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1 ||
+             conn_req->service_id == ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2)) {
+               flags |= ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
+               disable_credit_flow_ctrl = true;
+       }
+
+       req_msg->flags_len = FIELD_PREP(HTC_SVC_MSG_CONNECTIONFLAGS, flags);
+       req_msg->msg_svc_id |= FIELD_PREP(HTC_SVC_MSG_SERVICE_ID,
+                                         conn_req->service_id);
+
+       reinit_completion(&htc->ctl_resp);
+
+       status = ath11k_htc_send(htc, ATH11K_HTC_EP_0, skb);
+       if (status) {
+               kfree_skb(skb);
+               return status;
+       }
+
+       /* wait for response */
+       time_left = wait_for_completion_timeout(&htc->ctl_resp,
+                                               ATH11K_HTC_CONN_SVC_TIMEOUT_HZ);
+       if (!time_left) {
+               ath11k_err(ab, "Service connect timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       /* we controlled the buffer creation, it's aligned */
+       resp_msg = (struct ath11k_htc_conn_svc_resp *)htc->control_resp_buffer;
+       message_id = FIELD_GET(HTC_MSG_MESSAGEID, resp_msg->msg_svc_id);
+       service_id = FIELD_GET(HTC_SVC_RESP_MSG_SERVICEID,
+                              resp_msg->msg_svc_id);
+
+       if ((message_id != ATH11K_HTC_MSG_CONNECT_SERVICE_RESP_ID) ||
+           (htc->control_resp_len < sizeof(*resp_msg))) {
+               ath11k_err(ab, "Invalid resp message ID 0x%x", message_id);
+               return -EPROTO;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_HTC,
+                  "HTC Service %s connect response: status: 0x%lx, assigned ep: 0x%lx\n",
+                  htc_service_name(service_id),
+                  FIELD_GET(HTC_SVC_RESP_MSG_STATUS, resp_msg->flags_len),
+                  FIELD_GET(HTC_SVC_RESP_MSG_ENDPOINTID, resp_msg->flags_len));
+
+       conn_resp->connect_resp_code = FIELD_GET(HTC_SVC_RESP_MSG_STATUS,
+                                                resp_msg->flags_len);
+
+       /* check response status */
+       if (conn_resp->connect_resp_code != ATH11K_HTC_CONN_SVC_STATUS_SUCCESS) {
+               ath11k_err(ab, "HTC Service %s connect request failed: 0x%x)\n",
+                          htc_service_name(service_id),
+                      conn_resp->connect_resp_code);
+               return -EPROTO;
+       }
+
+       assigned_eid = (enum ath11k_htc_ep_id)FIELD_GET(
+                                               HTC_SVC_RESP_MSG_ENDPOINTID,
+                                               resp_msg->flags_len);
+
+       max_msg_size = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE,
+                                resp_msg->flags_len);
+
+setup:
+
+       if (assigned_eid >= ATH11K_HTC_EP_COUNT)
+               return -EPROTO;
+
+       if (max_msg_size == 0)
+               return -EPROTO;
+
+       ep = &htc->endpoint[assigned_eid];
+       ep->eid = assigned_eid;
+
+       if (ep->service_id != ATH11K_HTC_SVC_ID_UNUSED)
+               return -EPROTO;
+
+       /* return assigned endpoint to caller */
+       conn_resp->eid = assigned_eid;
+       conn_resp->max_msg_len = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE,
+                                          resp_msg->flags_len);
+
+       /* setup the endpoint */
+       ep->service_id = conn_req->service_id;
+       ep->max_tx_queue_depth = conn_req->max_send_queue_depth;
+       ep->max_ep_message_len = FIELD_GET(HTC_SVC_RESP_MSG_MAXMSGSIZE,
+                                          resp_msg->flags_len);
+       ep->tx_credits = tx_alloc;
+
+       /* copy all the callbacks */
+       ep->ep_ops = conn_req->ep_ops;
+
+       status = ath11k_ahb_map_service_to_pipe(htc->ab,
+                                               ep->service_id,
+                                               &ep->ul_pipe_id,
+                                               &ep->dl_pipe_id);
+       if (status)
+               return status;
+
+       ath11k_dbg(ab, ATH11K_DBG_BOOT,
+                  "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
+                  htc_service_name(ep->service_id), ep->ul_pipe_id,
+                  ep->dl_pipe_id, ep->eid);
+
+       if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {
+               ep->tx_credit_flow_enabled = false;
+               ath11k_dbg(ab, ATH11K_DBG_BOOT,
+                          "boot htc service '%s' eid %d TX flow control disabled\n",
+                          htc_service_name(ep->service_id), assigned_eid);
+       }
+
+       return status;
+}
+
+int ath11k_htc_start(struct ath11k_htc *htc)
+{
+       struct sk_buff *skb;
+       int status = 0;
+       struct ath11k_base *ab = htc->ab;
+       struct ath11k_htc_setup_complete_extended *msg;
+
+       skb = ath11k_htc_build_tx_ctrl_skb(htc->ab);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_put(skb, sizeof(*msg));
+       memset(skb->data, 0, skb->len);
+
+       msg = (struct ath11k_htc_setup_complete_extended *)skb->data;
+       msg->msg_id = FIELD_PREP(HTC_MSG_MESSAGEID,
+                                ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID);
+
+       ath11k_dbg(ab, ATH11K_DBG_HTC, "HTC is using TX credit flow control\n");
+
+       status = ath11k_htc_send(htc, ATH11K_HTC_EP_0, skb);
+       if (status) {
+               kfree_skb(skb);
+               return status;
+       }
+
+       return 0;
+}
+
+int ath11k_htc_init(struct ath11k_base *ab)
+{
+       struct ath11k_htc *htc = &ab->htc;
+       struct ath11k_htc_svc_conn_req conn_req;
+       struct ath11k_htc_svc_conn_resp conn_resp;
+       int ret;
+
+       spin_lock_init(&htc->tx_lock);
+
+       ath11k_htc_reset_endpoint_states(htc);
+
+       htc->ab = ab;
+
+       switch (ab->wmi_sc.preferred_hw_mode) {
+       case WMI_HOST_HW_MODE_SINGLE:
+               htc->wmi_ep_count = 1;
+               break;
+       case WMI_HOST_HW_MODE_DBS:
+       case WMI_HOST_HW_MODE_DBS_OR_SBS:
+               htc->wmi_ep_count = 2;
+               break;
+       case WMI_HOST_HW_MODE_DBS_SBS:
+               htc->wmi_ep_count = 3;
+               break;
+       default:
+               htc->wmi_ep_count = 3;
+               break;
+       }
+
+       /* setup our pseudo HTC control endpoint connection */
+       memset(&conn_req, 0, sizeof(conn_req));
+       memset(&conn_resp, 0, sizeof(conn_resp));
+       conn_req.ep_ops.ep_tx_complete = ath11k_htc_control_tx_complete;
+       conn_req.ep_ops.ep_rx_complete = ath11k_htc_control_rx_complete;
+       conn_req.max_send_queue_depth = ATH11K_NUM_CONTROL_TX_BUFFERS;
+       conn_req.service_id = ATH11K_HTC_SVC_ID_RSVD_CTRL;
+
+       /* connect fake service */
+       ret = ath11k_htc_connect_service(htc, &conn_req, &conn_resp);
+       if (ret) {
+               ath11k_err(ab, "could not connect to htc service (%d)\n", ret);
+               return ret;
+       }
+
+       init_completion(&htc->ctl_resp);
+
+       return 0;
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_HTC_H
+#define ATH11K_HTC_H
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/bug.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+
+struct ath11k_base;
+
+#define HTC_HDR_ENDPOINTID                       GENMASK(7, 0)
+#define HTC_HDR_FLAGS                            GENMASK(15, 8)
+#define HTC_HDR_PAYLOADLEN                       GENMASK(31, 16)
+#define HTC_HDR_CONTROLBYTES0                    GENMASK(7, 0)
+#define HTC_HDR_CONTROLBYTES1                    GENMASK(15, 8)
+#define HTC_HDR_RESERVED                         GENMASK(31, 16)
+
+#define HTC_SVC_MSG_SERVICE_ID                   GENMASK(31, 16)
+#define HTC_SVC_MSG_CONNECTIONFLAGS              GENMASK(15, 0)
+#define HTC_SVC_MSG_SERVICEMETALENGTH            GENMASK(23, 16)
+#define HTC_READY_MSG_CREDITCOUNT                GENMASK(31, 16)
+#define HTC_READY_MSG_CREDITSIZE                 GENMASK(15, 0)
+#define HTC_READY_MSG_MAXENDPOINTS               GENMASK(23, 16)
+
+#define HTC_READY_EX_MSG_HTCVERSION              GENMASK(7, 0)
+#define HTC_READY_EX_MSG_MAXMSGSPERHTCBUNDLE     GENMASK(15, 8)
+
+#define HTC_SVC_RESP_MSG_SERVICEID           GENMASK(31, 16)
+#define HTC_SVC_RESP_MSG_STATUS              GENMASK(7, 0)
+#define HTC_SVC_RESP_MSG_ENDPOINTID          GENMASK(15, 8)
+#define HTC_SVC_RESP_MSG_MAXMSGSIZE          GENMASK(31, 16)
+#define HTC_SVC_RESP_MSG_SERVICEMETALENGTH   GENMASK(7, 0)
+
+#define HTC_MSG_MESSAGEID                        GENMASK(15, 0)
+#define HTC_SETUP_COMPLETE_EX_MSG_SETUPFLAGS     GENMASK(31, 0)
+#define HTC_SETUP_COMPLETE_EX_MSG_MAXMSGSPERBUNDLEDRECV      GENMASK(7, 0)
+#define HTC_SETUP_COMPLETE_EX_MSG_RSVD0          GENMASK(15, 8)
+#define HTC_SETUP_COMPLETE_EX_MSG_RSVD1          GENMASK(23, 16)
+#define HTC_SETUP_COMPLETE_EX_MSG_RSVD2          GENMASK(31, 24)
+
+enum ath11k_htc_tx_flags {
+       ATH11K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
+       ATH11K_HTC_FLAG_SEND_BUNDLE        = 0x02
+};
+
+enum ath11k_htc_rx_flags {
+       ATH11K_HTC_FLAG_TRAILER_PRESENT = 0x02,
+       ATH11K_HTC_FLAG_BUNDLE_MASK     = 0xF0
+};
+
+struct ath11k_htc_hdr {
+       u32 htc_info;
+       u32 ctrl_info;
+} __packed __aligned(4);
+
+enum ath11k_htc_msg_id {
+       ATH11K_HTC_MSG_READY_ID                = 1,
+       ATH11K_HTC_MSG_CONNECT_SERVICE_ID      = 2,
+       ATH11K_HTC_MSG_CONNECT_SERVICE_RESP_ID = 3,
+       ATH11K_HTC_MSG_SETUP_COMPLETE_ID       = 4,
+       ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID    = 5,
+       ATH11K_HTC_MSG_SEND_SUSPEND_COMPLETE   = 6
+};
+
+enum ath11k_htc_version {
+       ATH11K_HTC_VERSION_2P0 = 0x00, /* 2.0 */
+       ATH11K_HTC_VERSION_2P1 = 0x01, /* 2.1 */
+};
+
+#define ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_MASK GENMASK(1, 0)
+#define ATH11K_HTC_CONN_FLAGS_RECV_ALLOC GENMASK(15, 8)
+
+enum ath11k_htc_conn_flags {
+       ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH    = 0x0,
+       ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_ONE_HALF      = 0x1,
+       ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS = 0x2,
+       ATH11K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_UNITY         = 0x3,
+       ATH11K_HTC_CONN_FLAGS_REDUCE_CREDIT_DRIBBLE    = 1 << 2,
+       ATH11K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 1 << 3
+};
+
+enum ath11k_htc_conn_svc_status {
+       ATH11K_HTC_CONN_SVC_STATUS_SUCCESS      = 0,
+       ATH11K_HTC_CONN_SVC_STATUS_NOT_FOUND    = 1,
+       ATH11K_HTC_CONN_SVC_STATUS_FAILED       = 2,
+       ATH11K_HTC_CONN_SVC_STATUS_NO_RESOURCES = 3,
+       ATH11K_HTC_CONN_SVC_STATUS_NO_MORE_EP   = 4
+};
+
+struct ath11k_htc_ready {
+       u32 id_credit_count;
+       u32 size_ep;
+} __packed;
+
+struct ath11k_htc_ready_extended {
+       struct ath11k_htc_ready base;
+       u32 ver_bundle;
+} __packed;
+
+struct ath11k_htc_conn_svc {
+       u32 msg_svc_id;
+       u32 flags_len;
+} __packed;
+
+struct ath11k_htc_conn_svc_resp {
+       u32 msg_svc_id;
+       u32 flags_len;
+       u32 svc_meta_pad;
+} __packed;
+
+struct ath11k_htc_setup_complete_extended {
+       u32 msg_id;
+       u32 flags;
+       u32 max_msgs_per_bundled_recv;
+} __packed;
+
+struct ath11k_htc_msg {
+       u32 msg_svc_id;
+       u32 flags_len;
+} __packed __aligned(4);
+
+enum ath11k_htc_record_id {
+       ATH11K_HTC_RECORD_NULL    = 0,
+       ATH11K_HTC_RECORD_CREDITS = 1
+};
+
+struct ath11k_htc_record_hdr {
+       u8 id; /* @enum ath11k_htc_record_id */
+       u8 len;
+       u8 pad0;
+       u8 pad1;
+} __packed;
+
+struct ath11k_htc_credit_report {
+       u8 eid; /* @enum ath11k_htc_ep_id */
+       u8 credits;
+       u8 pad0;
+       u8 pad1;
+} __packed;
+
+struct ath11k_htc_record {
+       struct ath11k_htc_record_hdr hdr;
+       union {
+               struct ath11k_htc_credit_report credit_report[0];
+               u8 pauload[0];
+       };
+} __packed __aligned(4);
+
+/* note: the trailer offset is dynamic depending
+ * on payload length. this is only a struct layout draft
+ */
+struct ath11k_htc_frame {
+       struct ath11k_htc_hdr hdr;
+       union {
+               struct ath11k_htc_msg msg;
+               u8 payload[0];
+       };
+       struct ath11k_htc_record trailer[0];
+} __packed __aligned(4);
+
+enum ath11k_htc_svc_gid {
+       ATH11K_HTC_SVC_GRP_RSVD = 0,
+       ATH11K_HTC_SVC_GRP_WMI = 1,
+       ATH11K_HTC_SVC_GRP_NMI = 2,
+       ATH11K_HTC_SVC_GRP_HTT = 3,
+       ATH11K_HTC_SVC_GRP_CFG = 4,
+       ATH11K_HTC_SVC_GRP_IPA = 5,
+       ATH11K_HTC_SVC_GRP_PKTLOG = 6,
+
+       ATH11K_HTC_SVC_GRP_TEST = 254,
+       ATH11K_HTC_SVC_GRP_LAST = 255,
+};
+
+#define SVC(group, idx) \
+       (int)(((int)(group) << 8) | (int)(idx))
+
+enum ath11k_htc_svc_id {
+       /* NOTE: service ID of 0x0000 is reserved and should never be used */
+       ATH11K_HTC_SVC_ID_RESERVED      = 0x0000,
+       ATH11K_HTC_SVC_ID_UNUSED        = ATH11K_HTC_SVC_ID_RESERVED,
+
+       ATH11K_HTC_SVC_ID_RSVD_CTRL     = SVC(ATH11K_HTC_SVC_GRP_RSVD, 1),
+       ATH11K_HTC_SVC_ID_WMI_CONTROL   = SVC(ATH11K_HTC_SVC_GRP_WMI, 0),
+       ATH11K_HTC_SVC_ID_WMI_DATA_BE   = SVC(ATH11K_HTC_SVC_GRP_WMI, 1),
+       ATH11K_HTC_SVC_ID_WMI_DATA_BK   = SVC(ATH11K_HTC_SVC_GRP_WMI, 2),
+       ATH11K_HTC_SVC_ID_WMI_DATA_VI   = SVC(ATH11K_HTC_SVC_GRP_WMI, 3),
+       ATH11K_HTC_SVC_ID_WMI_DATA_VO   = SVC(ATH11K_HTC_SVC_GRP_WMI, 4),
+       ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1 = SVC(ATH11K_HTC_SVC_GRP_WMI, 5),
+       ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2 = SVC(ATH11K_HTC_SVC_GRP_WMI, 6),
+
+       ATH11K_HTC_SVC_ID_NMI_CONTROL   = SVC(ATH11K_HTC_SVC_GRP_NMI, 0),
+       ATH11K_HTC_SVC_ID_NMI_DATA      = SVC(ATH11K_HTC_SVC_GRP_NMI, 1),
+
+       ATH11K_HTC_SVC_ID_HTT_DATA_MSG  = SVC(ATH11K_HTC_SVC_GRP_HTT, 0),
+
+       /* raw stream service (i.e. flash, tcmd, calibration apps) */
+       ATH11K_HTC_SVC_ID_TEST_RAW_STREAMS = SVC(ATH11K_HTC_SVC_GRP_TEST, 0),
+       ATH11K_HTC_SVC_ID_IPA_TX = SVC(ATH11K_HTC_SVC_GRP_IPA, 0),
+       ATH11K_HTC_SVC_ID_PKT_LOG = SVC(ATH11K_HTC_SVC_GRP_PKTLOG, 0),
+};
+
+#undef SVC
+
+enum ath11k_htc_ep_id {
+       ATH11K_HTC_EP_UNUSED = -1,
+       ATH11K_HTC_EP_0 = 0,
+       ATH11K_HTC_EP_1 = 1,
+       ATH11K_HTC_EP_2,
+       ATH11K_HTC_EP_3,
+       ATH11K_HTC_EP_4,
+       ATH11K_HTC_EP_5,
+       ATH11K_HTC_EP_6,
+       ATH11K_HTC_EP_7,
+       ATH11K_HTC_EP_8,
+       ATH11K_HTC_EP_COUNT,
+};
+
+struct ath11k_htc_ops {
+       void (*target_send_suspend_complete)(struct ath11k_base *ar);
+};
+
+struct ath11k_htc_ep_ops {
+       void (*ep_tx_complete)(struct ath11k_base *, struct sk_buff *);
+       void (*ep_rx_complete)(struct ath11k_base *, struct sk_buff *);
+       void (*ep_tx_credits)(struct ath11k_base *);
+};
+
+/* service connection information */
+struct ath11k_htc_svc_conn_req {
+       u16 service_id;
+       struct ath11k_htc_ep_ops ep_ops;
+       int max_send_queue_depth;
+};
+
+/* service connection response information */
+struct ath11k_htc_svc_conn_resp {
+       u8 buffer_len;
+       u8 actual_len;
+       enum ath11k_htc_ep_id eid;
+       unsigned int max_msg_len;
+       u8 connect_resp_code;
+};
+
+#define ATH11K_NUM_CONTROL_TX_BUFFERS 2
+#define ATH11K_HTC_MAX_LEN 4096
+#define ATH11K_HTC_MAX_CTRL_MSG_LEN 256
+#define ATH11K_HTC_WAIT_TIMEOUT_HZ (1 * HZ)
+#define ATH11K_HTC_CONTROL_BUFFER_SIZE (ATH11K_HTC_MAX_CTRL_MSG_LEN + \
+                                       sizeof(struct ath11k_htc_hdr))
+#define ATH11K_HTC_CONN_SVC_TIMEOUT_HZ (1 * HZ)
+#define ATH11K_HTC_MAX_SERVICE_ALLOC_ENTRIES 8
+
+struct ath11k_htc_ep {
+       struct ath11k_htc *htc;
+       enum ath11k_htc_ep_id eid;
+       enum ath11k_htc_svc_id service_id;
+       struct ath11k_htc_ep_ops ep_ops;
+
+       int max_tx_queue_depth;
+       int max_ep_message_len;
+       u8 ul_pipe_id;
+       u8 dl_pipe_id;
+
+       u8 seq_no; /* for debugging */
+       int tx_credits;
+       bool tx_credit_flow_enabled;
+};
+
+struct ath11k_htc_svc_tx_credits {
+       u16 service_id;
+       u8  credit_allocation;
+};
+
+struct ath11k_htc {
+       struct ath11k_base *ab;
+       struct ath11k_htc_ep endpoint[ATH11K_HTC_EP_COUNT];
+
+       /* protects endpoints */
+       spinlock_t tx_lock;
+
+       struct ath11k_htc_ops htc_ops;
+
+       u8 control_resp_buffer[ATH11K_HTC_MAX_CTRL_MSG_LEN];
+       int control_resp_len;
+
+       struct completion ctl_resp;
+
+       int total_transmit_credits;
+       struct ath11k_htc_svc_tx_credits
+               service_alloc_table[ATH11K_HTC_MAX_SERVICE_ALLOC_ENTRIES];
+       int target_credit_size;
+       u8 wmi_ep_count;
+};
+
+int ath11k_htc_init(struct ath11k_base *ar);
+int ath11k_htc_wait_target(struct ath11k_htc *htc);
+int ath11k_htc_start(struct ath11k_htc *htc);
+int ath11k_htc_connect_service(struct ath11k_htc *htc,
+                              struct ath11k_htc_svc_conn_req  *conn_req,
+                              struct ath11k_htc_svc_conn_resp *conn_resp);
+int ath11k_htc_send(struct ath11k_htc *htc, enum ath11k_htc_ep_id eid,
+                   struct sk_buff *packet);
+struct sk_buff *ath11k_htc_alloc_skb(struct ath11k_base *ar, int size);
+void ath11k_htc_rx_completion_handler(struct ath11k_base *ar,
+                                     struct sk_buff *skb);
+
+#endif
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_HW_H
+#define ATH11K_HW_H
+
+/* Target configuration defines */
+
+/* Num VDEVS per radio */
+#define TARGET_NUM_VDEVS       (16 + 1)
+
+#define TARGET_NUM_PEERS_PDEV  (512 + TARGET_NUM_VDEVS)
+
+/* Num of peers for Single Radio mode */
+#define TARGET_NUM_PEERS_SINGLE                (TARGET_NUM_PEERS_PDEV)
+
+/* Num of peers for DBS */
+#define TARGET_NUM_PEERS_DBS           (2 * TARGET_NUM_PEERS_PDEV)
+
+/* Num of peers for DBS_SBS */
+#define TARGET_NUM_PEERS_DBS_SBS       (3 * TARGET_NUM_PEERS_PDEV)
+
+/* Max num of stations (per radio) */
+#define TARGET_NUM_STATIONS    512
+
+#define TARGET_NUM_PEERS(x)    TARGET_NUM_PEERS_##x
+#define TARGET_NUM_PEER_KEYS   2
+#define TARGET_NUM_TIDS(x)     (2 * TARGET_NUM_PEERS(x) + \
+                                4 * TARGET_NUM_VDEVS + 8)
+
+#define TARGET_AST_SKID_LIMIT  16
+#define TARGET_NUM_OFFLD_PEERS 4
+#define TARGET_NUM_OFFLD_REORDER_BUFFS 4
+
+#define TARGET_TX_CHAIN_MASK   (BIT(0) | BIT(1) | BIT(2) | BIT(4))
+#define TARGET_RX_CHAIN_MASK   (BIT(0) | BIT(1) | BIT(2) | BIT(4))
+#define TARGET_RX_TIMEOUT_LO_PRI       100
+#define TARGET_RX_TIMEOUT_HI_PRI       40
+
+#define TARGET_DECAP_MODE_RAW          0
+#define TARGET_DECAP_MODE_NATIVE_WIFI  1
+#define TARGET_DECAP_MODE_ETH          2
+
+#define TARGET_SCAN_MAX_PENDING_REQS   4
+#define TARGET_BMISS_OFFLOAD_MAX_VDEV  3
+#define TARGET_ROAM_OFFLOAD_MAX_VDEV   3
+#define TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES    8
+#define TARGET_GTK_OFFLOAD_MAX_VDEV    3
+#define TARGET_NUM_MCAST_GROUPS                12
+#define TARGET_NUM_MCAST_TABLE_ELEMS   64
+#define TARGET_MCAST2UCAST_MODE                2
+#define TARGET_TX_DBG_LOG_SIZE         1024
+#define TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1
+#define TARGET_VOW_CONFIG              0
+#define TARGET_NUM_MSDU_DESC           (2500)
+#define TARGET_MAX_FRAG_ENTRIES                6
+#define TARGET_MAX_BCN_OFFLD           16
+#define TARGET_NUM_WDS_ENTRIES         32
+#define TARGET_DMA_BURST_SIZE          1
+#define TARGET_RX_BATCHMODE            1
+
+#define ATH11K_HW_MAX_QUEUES           4
+
+#define ATH11k_HW_RATECODE_CCK_SHORT_PREAM_MASK  0x4
+
+#define ATH11K_FW_DIR                  "ath11k"
+
+/* IPQ8074 definitions */
+#define IPQ8074_FW_DIR                 "IPQ8074"
+#define IPQ8074_MAX_BOARD_DATA_SZ      (256 * 1024)
+#define IPQ8074_MAX_CAL_DATA_SZ                IPQ8074_MAX_BOARD_DATA_SZ
+
+#define ATH11K_BOARD_MAGIC             "QCA-ATH11K-BOARD"
+#define ATH11K_BOARD_API2_FILE         "board-2.bin"
+#define ATH11K_DEFAULT_BOARD_FILE      "bdwlan.bin"
+#define ATH11K_DEFAULT_CAL_FILE                "caldata.bin"
+
+enum ath11k_hw_rate_cck {
+       ATH11K_HW_RATE_CCK_LP_11M = 0,
+       ATH11K_HW_RATE_CCK_LP_5_5M,
+       ATH11K_HW_RATE_CCK_LP_2M,
+       ATH11K_HW_RATE_CCK_LP_1M,
+       ATH11K_HW_RATE_CCK_SP_11M,
+       ATH11K_HW_RATE_CCK_SP_5_5M,
+       ATH11K_HW_RATE_CCK_SP_2M,
+};
+
+enum ath11k_hw_rate_ofdm {
+       ATH11K_HW_RATE_OFDM_48M = 0,
+       ATH11K_HW_RATE_OFDM_24M,
+       ATH11K_HW_RATE_OFDM_12M,
+       ATH11K_HW_RATE_OFDM_6M,
+       ATH11K_HW_RATE_OFDM_54M,
+       ATH11K_HW_RATE_OFDM_36M,
+       ATH11K_HW_RATE_OFDM_18M,
+       ATH11K_HW_RATE_OFDM_9M,
+};
+
+struct ath11k_hw_params {
+       const char *name;
+       struct {
+               const char *dir;
+               size_t board_size;
+               size_t cal_size;
+       } fw;
+};
+
+struct ath11k_fw_ie {
+       __le32 id;
+       __le32 len;
+       u8 data[0];
+};
+
+enum ath11k_bd_ie_board_type {
+       ATH11K_BD_IE_BOARD_NAME = 0,
+       ATH11K_BD_IE_BOARD_DATA = 1,
+};
+
+enum ath11k_bd_ie_type {
+       /* contains sub IEs of enum ath11k_bd_ie_board_type */
+       ATH11K_BD_IE_BOARD = 0,
+       ATH11K_BD_IE_BOARD_EXT = 1,
+};
+
+#endif
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <net/mac80211.h>
+#include <linux/etherdevice.h>
+#include "mac.h"
+#include "core.h"
+#include "debug.h"
+#include "wmi.h"
+#include "hw.h"
+#include "dp_tx.h"
+#include "dp_rx.h"
+#include "testmode.h"
+#include "peer.h"
+
+#define CHAN2G(_channel, _freq, _flags) { \
+       .band                   = NL80211_BAND_2GHZ, \
+       .hw_value               = (_channel), \
+       .center_freq            = (_freq), \
+       .flags                  = (_flags), \
+       .max_antenna_gain       = 0, \
+       .max_power              = 30, \
+}
+
+#define CHAN5G(_channel, _freq, _flags) { \
+       .band                   = NL80211_BAND_5GHZ, \
+       .hw_value               = (_channel), \
+       .center_freq            = (_freq), \
+       .flags                  = (_flags), \
+       .max_antenna_gain       = 0, \
+       .max_power              = 30, \
+}
+
+static const struct ieee80211_channel ath11k_2ghz_channels[] = {
+       CHAN2G(1, 2412, 0),
+       CHAN2G(2, 2417, 0),
+       CHAN2G(3, 2422, 0),
+       CHAN2G(4, 2427, 0),
+       CHAN2G(5, 2432, 0),
+       CHAN2G(6, 2437, 0),
+       CHAN2G(7, 2442, 0),
+       CHAN2G(8, 2447, 0),
+       CHAN2G(9, 2452, 0),
+       CHAN2G(10, 2457, 0),
+       CHAN2G(11, 2462, 0),
+       CHAN2G(12, 2467, 0),
+       CHAN2G(13, 2472, 0),
+       CHAN2G(14, 2484, 0),
+};
+
+static const struct ieee80211_channel ath11k_5ghz_channels[] = {
+       CHAN5G(36, 5180, 0),
+       CHAN5G(40, 5200, 0),
+       CHAN5G(44, 5220, 0),
+       CHAN5G(48, 5240, 0),
+       CHAN5G(52, 5260, 0),
+       CHAN5G(56, 5280, 0),
+       CHAN5G(60, 5300, 0),
+       CHAN5G(64, 5320, 0),
+       CHAN5G(100, 5500, 0),
+       CHAN5G(104, 5520, 0),
+       CHAN5G(108, 5540, 0),
+       CHAN5G(112, 5560, 0),
+       CHAN5G(116, 5580, 0),
+       CHAN5G(120, 5600, 0),
+       CHAN5G(124, 5620, 0),
+       CHAN5G(128, 5640, 0),
+       CHAN5G(132, 5660, 0),
+       CHAN5G(136, 5680, 0),
+       CHAN5G(140, 5700, 0),
+       CHAN5G(144, 5720, 0),
+       CHAN5G(149, 5745, 0),
+       CHAN5G(153, 5765, 0),
+       CHAN5G(157, 5785, 0),
+       CHAN5G(161, 5805, 0),
+       CHAN5G(165, 5825, 0),
+       CHAN5G(169, 5845, 0),
+       CHAN5G(173, 5865, 0),
+};
+
+static struct ieee80211_rate ath11k_legacy_rates[] = {
+       { .bitrate = 10,
+         .hw_value = ATH11K_HW_RATE_CCK_LP_1M },
+       { .bitrate = 20,
+         .hw_value = ATH11K_HW_RATE_CCK_LP_2M,
+         .hw_value_short = ATH11K_HW_RATE_CCK_SP_2M,
+         .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 55,
+         .hw_value = ATH11K_HW_RATE_CCK_LP_5_5M,
+         .hw_value_short = ATH11K_HW_RATE_CCK_SP_5_5M,
+         .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 110,
+         .hw_value = ATH11K_HW_RATE_CCK_LP_11M,
+         .hw_value_short = ATH11K_HW_RATE_CCK_SP_11M,
+         .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+
+       { .bitrate = 60, .hw_value = ATH11K_HW_RATE_OFDM_6M },
+       { .bitrate = 90, .hw_value = ATH11K_HW_RATE_OFDM_9M },
+       { .bitrate = 120, .hw_value = ATH11K_HW_RATE_OFDM_12M },
+       { .bitrate = 180, .hw_value = ATH11K_HW_RATE_OFDM_18M },
+       { .bitrate = 240, .hw_value = ATH11K_HW_RATE_OFDM_24M },
+       { .bitrate = 360, .hw_value = ATH11K_HW_RATE_OFDM_36M },
+       { .bitrate = 480, .hw_value = ATH11K_HW_RATE_OFDM_48M },
+       { .bitrate = 540, .hw_value = ATH11K_HW_RATE_OFDM_54M },
+};
+
+static const int
+ath11k_phymodes[NUM_NL80211_BANDS][ATH11K_CHAN_WIDTH_NUM] = {
+       [NL80211_BAND_2GHZ] = {
+                       [NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
+                       [NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
+                       [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20_2G,
+                       [NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20_2G,
+                       [NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40_2G,
+                       [NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80_2G,
+                       [NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN,
+                       [NL80211_CHAN_WIDTH_160] = MODE_UNKNOWN,
+       },
+       [NL80211_BAND_5GHZ] = {
+                       [NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
+                       [NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
+                       [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20,
+                       [NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20,
+                       [NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40,
+                       [NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80,
+                       [NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160,
+                       [NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80,
+       },
+};
+
+const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default = {
+       .rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START |
+                    HTT_RX_FILTER_TLV_FLAGS_PPDU_END |
+                    HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE,
+       .pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0,
+       .pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1,
+       .pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2,
+       .pkt_filter_flags3 = HTT_RX_FP_DATA_FILTER_FLASG3 |
+                            HTT_RX_FP_CTRL_FILTER_FLASG3
+};
+
+#define ATH11K_MAC_FIRST_OFDM_RATE_IDX 4
+#define ath11k_g_rates ath11k_legacy_rates
+#define ath11k_g_rates_size (ARRAY_SIZE(ath11k_legacy_rates))
+#define ath11k_a_rates (ath11k_legacy_rates + 4)
+#define ath11k_a_rates_size (ARRAY_SIZE(ath11k_legacy_rates) - 4)
+
+#define ATH11K_MAC_SCAN_TIMEOUT_MSECS 200 /* in msecs */
+
+static const u32 ath11k_smps_map[] = {
+       [WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC,
+       [WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC,
+       [WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE,
+       [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
+};
+
+int ath11k_mac_hw_ratecode_to_legacy_rate(u8 hw_rc, u8 preamble, u8 *rateidx,
+                                         u16 *rate)
+{
+       /* As default, it is OFDM rates */
+       int i = ATH11K_MAC_FIRST_OFDM_RATE_IDX;
+       int max_rates_idx = ath11k_g_rates_size;
+
+       if (preamble == WMI_RATE_PREAMBLE_CCK) {
+               hw_rc &= ~ATH11k_HW_RATECODE_CCK_SHORT_PREAM_MASK;
+               i = 0;
+               max_rates_idx = ATH11K_MAC_FIRST_OFDM_RATE_IDX;
+       }
+
+       while (i < max_rates_idx) {
+               if (hw_rc == ath11k_legacy_rates[i].hw_value) {
+                       *rateidx = i;
+                       *rate = ath11k_legacy_rates[i].bitrate;
+                       return 0;
+               }
+               i++;
+       }
+
+       return -EINVAL;
+}
+
+static int get_num_chains(u32 mask)
+{
+       int num_chains = 0;
+
+       while (mask) {
+               if (mask & BIT(0))
+                       num_chains++;
+               mask >>= 1;
+       }
+
+       return num_chains;
+}
+
+u8 ath11k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
+                            u32 bitrate)
+{
+       int i;
+
+       for (i = 0; i < sband->n_bitrates; i++)
+               if (sband->bitrates[i].bitrate == bitrate)
+                       return i;
+
+       return 0;
+}
+
+static u32
+ath11k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
+{
+       int nss;
+
+       for (nss = IEEE80211_HT_MCS_MASK_LEN - 1; nss >= 0; nss--)
+               if (ht_mcs_mask[nss])
+                       return nss + 1;
+
+       return 1;
+}
+
+static u32
+ath11k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+{
+       int nss;
+
+       for (nss = NL80211_VHT_NSS_MAX - 1; nss >= 0; nss--)
+               if (vht_mcs_mask[nss])
+                       return nss + 1;
+
+       return 1;
+}
+
+static u8 ath11k_parse_mpdudensity(u8 mpdudensity)
+{
+/* 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
+ *   0 for no restriction
+ *   1 for 1/4 us
+ *   2 for 1/2 us
+ *   3 for 1 us
+ *   4 for 2 us
+ *   5 for 4 us
+ *   6 for 8 us
+ *   7 for 16 us
+ */
+       switch (mpdudensity) {
+       case 0:
+               return 0;
+       case 1:
+       case 2:
+       case 3:
+       /* Our lower layer calculations limit our precision to
+        * 1 microsecond
+        */
+               return 1;
+       case 4:
+               return 2;
+       case 5:
+               return 4;
+       case 6:
+               return 8;
+       case 7:
+               return 16;
+       default:
+               return 0;
+       }
+}
+
+static int ath11k_mac_vif_chan(struct ieee80211_vif *vif,
+                              struct cfg80211_chan_def *def)
+{
+       struct ieee80211_chanctx_conf *conf;
+
+       rcu_read_lock();
+       conf = rcu_dereference(vif->chanctx_conf);
+       if (!conf) {
+               rcu_read_unlock();
+               return -ENOENT;
+       }
+
+       *def = conf->def;
+       rcu_read_unlock();
+
+       return 0;
+}
+
+static bool ath11k_mac_bitrate_is_cck(int bitrate)
+{
+       switch (bitrate) {
+       case 10:
+       case 20:
+       case 55:
+       case 110:
+               return true;
+       }
+
+       return false;
+}
+
+u8 ath11k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
+                            u8 hw_rate, bool cck)
+{
+       const struct ieee80211_rate *rate;
+       int i;
+
+       for (i = 0; i < sband->n_bitrates; i++) {
+               rate = &sband->bitrates[i];
+
+               if (ath11k_mac_bitrate_is_cck(rate->bitrate) != cck)
+                       continue;
+
+               if (rate->hw_value == hw_rate)
+                       return i;
+               else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE &&
+                        rate->hw_value_short == hw_rate)
+                       return i;
+       }
+
+       return 0;
+}
+
+static u8 ath11k_mac_bitrate_to_rate(int bitrate)
+{
+       return DIV_ROUND_UP(bitrate, 5) |
+              (ath11k_mac_bitrate_is_cck(bitrate) ? BIT(7) : 0);
+}
+
+static void ath11k_get_arvif_iter(void *data, u8 *mac,
+                                 struct ieee80211_vif *vif)
+{
+       struct ath11k_vif_iter *arvif_iter = data;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+
+       if (arvif->vdev_id == arvif_iter->vdev_id)
+               arvif_iter->arvif = arvif;
+}
+
+struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id)
+{
+       struct ath11k_vif_iter arvif_iter;
+       u32 flags;
+
+       memset(&arvif_iter, 0, sizeof(struct ath11k_vif_iter));
+       arvif_iter.vdev_id = vdev_id;
+
+       flags = IEEE80211_IFACE_ITER_RESUME_ALL;
+       ieee80211_iterate_active_interfaces_atomic(ar->hw,
+                                                  flags,
+                                                  ath11k_get_arvif_iter,
+                                                  &arvif_iter);
+       if (!arvif_iter.arvif)
+               return NULL;
+
+       return arvif_iter.arvif;
+}
+
+struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab,
+                                                  u32 vdev_id)
+{
+       int i;
+       struct ath11k_pdev *pdev;
+       struct ath11k_vif *arvif;
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = rcu_dereference(ab->pdevs_active[i]);
+               if (pdev && pdev->ar) {
+                       arvif = ath11k_mac_get_arvif(pdev->ar, vdev_id);
+                       if (arvif)
+                               return arvif;
+               }
+       }
+
+       return NULL;
+}
+
+struct ath11k *ath11k_mac_get_ar_by_vdev_id(struct ath11k_base *ab, u32 vdev_id)
+{
+       int i;
+       struct ath11k_pdev *pdev;
+       struct ath11k_vif *arvif;
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = rcu_dereference(ab->pdevs_active[i]);
+               if (pdev && pdev->ar) {
+                       arvif = ath11k_mac_get_arvif(pdev->ar, vdev_id);
+                       if (arvif)
+                               return arvif->ar;
+               }
+       }
+
+       return NULL;
+}
+
+struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id)
+{
+       int i;
+       struct ath11k_pdev *pdev;
+
+       if (WARN_ON(pdev_id > ab->num_radios))
+               return NULL;
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = rcu_dereference(ab->pdevs_active[i]);
+
+               if (pdev && pdev->pdev_id == pdev_id)
+                       return (pdev->ar ? pdev->ar : NULL);
+       }
+
+       return NULL;
+}
+
+struct ath11k *ath11k_mac_get_ar_vdev_stop_status(struct ath11k_base *ab,
+                                                 u32 vdev_id)
+{
+       int i;
+       struct ath11k_pdev *pdev;
+       struct ath11k *ar;
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = rcu_dereference(ab->pdevs_active[i]);
+               if (pdev && pdev->ar) {
+                       ar = pdev->ar;
+
+                       spin_lock_bh(&ar->data_lock);
+                       if (ar->vdev_stop_status.stop_in_progress &&
+                           ar->vdev_stop_status.vdev_id == vdev_id) {
+                               ar->vdev_stop_status.stop_in_progress = false;
+                               spin_unlock_bh(&ar->data_lock);
+                               return ar;
+                       }
+                       spin_unlock_bh(&ar->data_lock);
+               }
+       }
+       return NULL;
+}
+
+static void ath11k_pdev_caps_update(struct ath11k *ar)
+{
+       struct ath11k_base *ab = ar->ab;
+
+       ar->max_tx_power = ab->target_caps.hw_max_tx_power;
+
+       /* FIXME Set min_tx_power to ab->target_caps.hw_min_tx_power.
+        * But since the received value in svcrdy is same as hw_max_tx_power,
+        * we can set ar->min_tx_power to 0 currently until
+        * this is fixed in firmware
+        */
+       ar->min_tx_power = 0;
+
+       ar->txpower_limit_2g = ar->max_tx_power;
+       ar->txpower_limit_5g = ar->max_tx_power;
+       ar->txpower_scale = WMI_HOST_TP_SCALE_MAX;
+}
+
+static int ath11k_mac_txpower_recalc(struct ath11k *ar)
+{
+       struct ath11k_pdev *pdev = ar->pdev;
+       struct ath11k_vif *arvif;
+       int ret, txpower = -1;
+       u32 param;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       list_for_each_entry(arvif, &ar->arvifs, list) {
+               if (arvif->txpower <= 0)
+                       continue;
+
+               if (txpower == -1)
+                       txpower = arvif->txpower;
+               else
+                       txpower = min(txpower, arvif->txpower);
+       }
+
+       if (txpower == -1)
+               return 0;
+
+       /* txpwr is set as 2 units per dBm in FW*/
+       txpower = min_t(u32, max_t(u32, ar->min_tx_power, txpower),
+                       ar->max_tx_power) * 2;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "txpower to set in hw %d\n",
+                  txpower / 2);
+
+       if ((pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) &&
+           ar->txpower_limit_2g != txpower) {
+               param = WMI_PDEV_PARAM_TXPOWER_LIMIT2G;
+               ret = ath11k_wmi_pdev_set_param(ar, param,
+                                               txpower, ar->pdev->pdev_id);
+               if (ret)
+                       goto fail;
+               ar->txpower_limit_2g = txpower;
+       }
+
+       if ((pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP) &&
+           ar->txpower_limit_5g != txpower) {
+               param = WMI_PDEV_PARAM_TXPOWER_LIMIT5G;
+               ret = ath11k_wmi_pdev_set_param(ar, param,
+                                               txpower, ar->pdev->pdev_id);
+               if (ret)
+                       goto fail;
+               ar->txpower_limit_5g = txpower;
+       }
+
+       return 0;
+
+fail:
+       ath11k_warn(ar->ab, "failed to recalc txpower limit %d using pdev param %d: %d\n",
+                   txpower / 2, param, ret);
+       return ret;
+}
+
+static int ath11k_recalc_rtscts_prot(struct ath11k_vif *arvif)
+{
+       struct ath11k *ar = arvif->ar;
+       u32 vdev_param, rts_cts = 0;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       vdev_param = WMI_VDEV_PARAM_ENABLE_RTSCTS;
+
+       /* Enable RTS/CTS protection for sw retries (when legacy stations
+        * are in BSS) or by default only for second rate series.
+        * TODO: Check if we need to enable CTS 2 Self in any case
+        */
+       rts_cts = WMI_USE_RTS_CTS;
+
+       if (arvif->num_legacy_stations > 0)
+               rts_cts |= WMI_RTSCTS_ACROSS_SW_RETRIES << 4;
+       else
+               rts_cts |= WMI_RTSCTS_FOR_SECOND_RATESERIES << 4;
+
+       /* Need not send duplicate param value to firmware */
+       if (arvif->rtscts_prot_mode == rts_cts)
+               return 0;
+
+       arvif->rtscts_prot_mode = rts_cts;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d recalc rts/cts prot %d\n",
+                  arvif->vdev_id, rts_cts);
+
+       ret =  ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                            vdev_param, rts_cts);
+       if (ret)
+               ath11k_warn(ar->ab, "failed to recalculate rts/cts prot for vdev %d: %d\n",
+                           arvif->vdev_id, ret);
+
+       return ret;
+}
+
+static int ath11k_mac_set_kickout(struct ath11k_vif *arvif)
+{
+       struct ath11k *ar = arvif->ar;
+       u32 param;
+       int ret;
+
+       ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_STA_KICKOUT_TH,
+                                       ATH11K_KICKOUT_THRESHOLD,
+                                       ar->pdev->pdev_id);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set kickout threshold on vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+
+       param = WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param,
+                                           ATH11K_KEEPALIVE_MIN_IDLE);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set keepalive minimum idle time on vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+
+       param = WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param,
+                                           ATH11K_KEEPALIVE_MAX_IDLE);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set keepalive maximum idle time on vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+
+       param = WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param,
+                                           ATH11K_KEEPALIVE_MAX_UNRESPONSIVE);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void ath11k_mac_peer_cleanup_all(struct ath11k *ar)
+{
+       struct ath11k_peer *peer, *tmp;
+       struct ath11k_base *ab = ar->ab;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       spin_lock_bh(&ab->base_lock);
+       list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
+               ath11k_peer_rx_tid_cleanup(ar, peer);
+               list_del(&peer->list);
+               kfree(peer);
+       }
+       spin_unlock_bh(&ab->base_lock);
+
+       ar->num_peers = 0;
+       ar->num_stations = 0;
+}
+
+static int ath11k_monitor_vdev_up(struct ath11k *ar, int vdev_id)
+{
+       int ret = 0;
+
+       ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n",
+                           vdev_id, ret);
+               return ret;
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i started\n",
+                  vdev_id);
+       return 0;
+}
+
+static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed)
+{
+       struct ath11k *ar = hw->priv;
+       int ret = 0;
+
+       /* mac80211 requires this op to be present and that's why
+        * there's an empty function, this can be extended when
+        * required.
+        */
+
+       mutex_lock(&ar->conf_mutex);
+
+       /* TODO: Handle configuration changes as appropriate */
+
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
+{
+       struct ath11k *ar = arvif->ar;
+       struct ath11k_base *ab = ar->ab;
+       struct ieee80211_hw *hw = ar->hw;
+       struct ieee80211_vif *vif = arvif->vif;
+       struct ieee80211_mutable_offsets offs = {};
+       struct sk_buff *bcn;
+       int ret;
+
+       if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+               return 0;
+
+       bcn = ieee80211_beacon_get_template(hw, vif, &offs);
+       if (!bcn) {
+               ath11k_warn(ab, "failed to get beacon template from mac80211\n");
+               return -EPERM;
+       }
+
+       ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn);
+
+       kfree_skb(bcn);
+
+       if (ret)
+               ath11k_warn(ab, "failed to submit beacon template command: %d\n",
+                           ret);
+
+       return ret;
+}
+
+static void ath11k_control_beaconing(struct ath11k_vif *arvif,
+                                    struct ieee80211_bss_conf *info)
+{
+       struct ath11k *ar = arvif->ar;
+       int ret = 0;
+
+       lockdep_assert_held(&arvif->ar->conf_mutex);
+
+       if (!info->enable_beacon) {
+               ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id);
+               if (ret)
+                       ath11k_warn(ar->ab, "failed to down vdev_id %i: %d\n",
+                                   arvif->vdev_id, ret);
+
+               arvif->is_up = false;
+               return;
+       }
+
+       /* Install the beacon template to the FW */
+       ret = ath11k_mac_setup_bcn_tmpl(arvif);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to update bcn tmpl during vdev up: %d\n",
+                           ret);
+               return;
+       }
+
+       arvif->tx_seq_no = 0x1000;
+
+       arvif->aid = 0;
+
+       ether_addr_copy(arvif->bssid, info->bssid);
+
+       ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+                                arvif->bssid);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to bring up vdev %d: %i\n",
+                           arvif->vdev_id, ret);
+               return;
+       }
+
+       arvif->is_up = true;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
+}
+
+static void ath11k_peer_assoc_h_basic(struct ath11k *ar,
+                                     struct ieee80211_vif *vif,
+                                     struct ieee80211_sta *sta,
+                                     struct peer_assoc_params *arg)
+{
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       u32 aid;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (vif->type == NL80211_IFTYPE_STATION)
+               aid = vif->bss_conf.aid;
+       else
+               aid = sta->aid;
+
+       ether_addr_copy(arg->peer_mac, sta->addr);
+       arg->vdev_id = arvif->vdev_id;
+       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_nss = 1;
+       arg->peer_caps = vif->bss_conf.assoc_capability;
+}
+
+static void ath11k_peer_assoc_h_crypto(struct ath11k *ar,
+                                      struct ieee80211_vif *vif,
+                                      struct ieee80211_sta *sta,
+                                      struct peer_assoc_params *arg)
+{
+       struct ieee80211_bss_conf *info = &vif->bss_conf;
+       struct cfg80211_chan_def def;
+       struct cfg80211_bss *bss;
+       const u8 *rsnie = NULL;
+       const u8 *wpaie = NULL;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
+               return;
+
+       bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0,
+                              IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
+       if (bss) {
+               const struct cfg80211_bss_ies *ies;
+
+               rcu_read_lock();
+               rsnie = ieee80211_bss_get_ie(bss, WLAN_EID_RSN);
+
+               ies = rcu_dereference(bss->ies);
+
+               wpaie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
+                                               WLAN_OUI_TYPE_MICROSOFT_WPA,
+                                               ies->data,
+                                               ies->len);
+               rcu_read_unlock();
+               cfg80211_put_bss(ar->hw->wiphy, bss);
+       }
+
+       /* FIXME: base on RSN IE/WPA IE is a correct idea? */
+       if (rsnie || wpaie) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                          "%s: rsn ie found\n", __func__);
+               arg->need_ptk_4_way = true;
+       }
+
+       if (wpaie) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                          "%s: wpa ie found\n", __func__);
+               arg->need_gtk_2_way = true;
+       }
+
+       if (sta->mfp) {
+               /* TODO: Need to check if FW supports PMF? */
+               arg->is_pmf_enabled = true;
+       }
+
+       /* TODO: safe_mode_enabled (bypass 4-way handshake) flag req? */
+}
+
+static void ath11k_peer_assoc_h_rates(struct ath11k *ar,
+                                     struct ieee80211_vif *vif,
+                                     struct ieee80211_sta *sta,
+                                     struct peer_assoc_params *arg)
+{
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates;
+       struct cfg80211_chan_def def;
+       const struct ieee80211_supported_band *sband;
+       const struct ieee80211_rate *rates;
+       enum nl80211_band band;
+       u32 ratemask;
+       u8 rate;
+       int i;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
+               return;
+
+       band = def.chan->band;
+       sband = ar->hw->wiphy->bands[band];
+       ratemask = sta->supp_rates[band];
+       ratemask &= arvif->bitrate_mask.control[band].legacy;
+       rates = sband->bitrates;
+
+       rateset->num_rates = 0;
+
+       for (i = 0; i < 32; i++, ratemask >>= 1, rates++) {
+               if (!(ratemask & 1))
+                       continue;
+
+               rate = ath11k_mac_bitrate_to_rate(rates->bitrate);
+               rateset->rates[rateset->num_rates] = rate;
+               rateset->num_rates++;
+       }
+}
+
+static bool
+ath11k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
+{
+       int nss;
+
+       for (nss = 0; nss < IEEE80211_HT_MCS_MASK_LEN; nss++)
+               if (ht_mcs_mask[nss])
+                       return false;
+
+       return true;
+}
+
+static bool
+ath11k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+{
+       int nss;
+
+       for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++)
+               if (vht_mcs_mask[nss])
+                       return false;
+
+       return true;
+}
+
+static void ath11k_peer_assoc_h_ht(struct ath11k *ar,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_sta *sta,
+                                  struct peer_assoc_params *arg)
+{
+       const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct cfg80211_chan_def def;
+       enum nl80211_band band;
+       const u8 *ht_mcs_mask;
+       int i, n;
+       u8 max_nss;
+       u32 stbc;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
+               return;
+
+       if (!ht_cap->ht_supported)
+               return;
+
+       band = def.chan->band;
+       ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
+
+       if (ath11k_peer_assoc_h_ht_masked(ht_mcs_mask))
+               return;
+
+       arg->ht_flag = true;
+
+       arg->peer_max_mpdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
+                                   ht_cap->ampdu_factor)) - 1;
+
+       arg->peer_mpdu_density =
+               ath11k_parse_mpdudensity(ht_cap->ampdu_density);
+
+       arg->peer_ht_caps = ht_cap->cap;
+       arg->peer_rate_caps |= WMI_HOST_RC_HT_FLAG;
+
+       if (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)
+               arg->ldpc_flag = true;
+
+       if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
+               arg->bw_40 = true;
+               arg->peer_rate_caps |= WMI_HOST_RC_CW40_FLAG;
+       }
+
+       if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) {
+               if (ht_cap->cap & (IEEE80211_HT_CAP_SGI_20 |
+                   IEEE80211_HT_CAP_SGI_40))
+                       arg->peer_rate_caps |= WMI_HOST_RC_SGI_FLAG;
+       }
+
+       if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) {
+               arg->peer_rate_caps |= WMI_HOST_RC_TX_STBC_FLAG;
+               arg->stbc_flag = true;
+       }
+
+       if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) {
+               stbc = ht_cap->cap & IEEE80211_HT_CAP_RX_STBC;
+               stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT;
+               stbc = stbc << WMI_HOST_RC_RX_STBC_FLAG_S;
+               arg->peer_rate_caps |= stbc;
+               arg->stbc_flag = true;
+       }
+
+       if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
+               arg->peer_rate_caps |= WMI_HOST_RC_TS_FLAG;
+       else if (ht_cap->mcs.rx_mask[1])
+               arg->peer_rate_caps |= WMI_HOST_RC_DS_FLAG;
+
+       for (i = 0, n = 0, max_nss = 0; i < IEEE80211_HT_MCS_MASK_LEN * 8; i++)
+               if ((ht_cap->mcs.rx_mask[i / 8] & BIT(i % 8)) &&
+                   (ht_mcs_mask[i / 8] & BIT(i % 8))) {
+                       max_nss = (i / 8) + 1;
+                       arg->peer_ht_rates.rates[n++] = i;
+               }
+
+       /* This is a workaround for HT-enabled STAs which break the spec
+        * and have no HT capabilities RX mask (no HT RX MCS map).
+        *
+        * As per spec, in section 20.3.5 Modulation and coding scheme (MCS),
+        * MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs.
+        *
+        * Firmware asserts if such situation occurs.
+        */
+       if (n == 0) {
+               arg->peer_ht_rates.num_rates = 8;
+               for (i = 0; i < arg->peer_ht_rates.num_rates; i++)
+                       arg->peer_ht_rates.rates[i] = i;
+       } else {
+               arg->peer_ht_rates.num_rates = n;
+               arg->peer_nss = min(sta->rx_nss, max_nss);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
+                  arg->peer_mac,
+                  arg->peer_ht_rates.num_rates,
+                  arg->peer_nss);
+}
+
+static int ath11k_mac_get_max_vht_mcs_map(u16 mcs_map, int nss)
+{
+       switch ((mcs_map >> (2 * nss)) & 0x3) {
+       case IEEE80211_VHT_MCS_SUPPORT_0_7: return BIT(8) - 1;
+       case IEEE80211_VHT_MCS_SUPPORT_0_8: return BIT(9) - 1;
+       case IEEE80211_VHT_MCS_SUPPORT_0_9: return BIT(10) - 1;
+       }
+       return 0;
+}
+
+static u16
+ath11k_peer_assoc_h_vht_limit(u16 tx_mcs_set,
+                             const u16 vht_mcs_limit[NL80211_VHT_NSS_MAX])
+{
+       int idx_limit;
+       int nss;
+       u16 mcs_map;
+       u16 mcs;
+
+       for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
+               mcs_map = ath11k_mac_get_max_vht_mcs_map(tx_mcs_set, nss) &
+                         vht_mcs_limit[nss];
+
+               if (mcs_map)
+                       idx_limit = fls(mcs_map) - 1;
+               else
+                       idx_limit = -1;
+
+               switch (idx_limit) {
+               case 0: /* fall through */
+               case 1: /* fall through */
+               case 2: /* fall through */
+               case 3: /* fall through */
+               case 4: /* fall through */
+               case 5: /* fall through */
+               case 6: /* fall through */
+               case 7:
+                       mcs = IEEE80211_VHT_MCS_SUPPORT_0_7;
+                       break;
+               case 8:
+                       mcs = IEEE80211_VHT_MCS_SUPPORT_0_8;
+                       break;
+               case 9:
+                       mcs = IEEE80211_VHT_MCS_SUPPORT_0_9;
+                       break;
+               default:
+                       WARN_ON(1);
+                       /* fall through */
+               case -1:
+                       mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED;
+                       break;
+               }
+
+               tx_mcs_set &= ~(0x3 << (nss * 2));
+               tx_mcs_set |= mcs << (nss * 2);
+       }
+
+       return tx_mcs_set;
+}
+
+static void ath11k_peer_assoc_h_vht(struct ath11k *ar,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_sta *sta,
+                                   struct peer_assoc_params *arg)
+{
+       const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct cfg80211_chan_def def;
+       enum nl80211_band band;
+       const u16 *vht_mcs_mask;
+       u8 ampdu_factor;
+       u8 max_nss, vht_mcs;
+       int i;
+
+       if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
+               return;
+
+       if (!vht_cap->vht_supported)
+               return;
+
+       band = def.chan->band;
+       vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
+       if (ath11k_peer_assoc_h_vht_masked(vht_mcs_mask))
+               return;
+
+       arg->vht_flag = true;
+
+       /* TODO: similar flags required? */
+       arg->vht_capable = true;
+
+       if (def.chan->band == NL80211_BAND_2GHZ)
+               arg->vht_ng_flag = true;
+
+       arg->peer_vht_caps = vht_cap->cap;
+
+       ampdu_factor = (vht_cap->cap &
+                       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
+                      IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+
+       /* Workaround: Some Netgear/Linksys 11ac APs set Rx A-MPDU factor to
+        * zero in VHT IE. Using it would result in degraded throughput.
+        * arg->peer_max_mpdu at this point contains HT max_mpdu so keep
+        * it if VHT max_mpdu is smaller.
+        */
+       arg->peer_max_mpdu = max(arg->peer_max_mpdu,
+                                (1U << (IEEE80211_HT_MAX_AMPDU_FACTOR +
+                                       ampdu_factor)) - 1);
+
+       if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
+               arg->bw_80 = true;
+
+       if (sta->bandwidth == IEEE80211_STA_RX_BW_160)
+               arg->bw_160 = true;
+
+       /* Calculate peer NSS capability from VHT capabilities if STA
+        * supports VHT.
+        */
+       for (i = 0, max_nss = 0, vht_mcs = 0; i < NL80211_VHT_NSS_MAX; i++) {
+               vht_mcs = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) >>
+                         (2 * i) & 3;
+
+               if (vht_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED &&
+                   vht_mcs_mask[i])
+                       max_nss = i + 1;
+       }
+       arg->peer_nss = min(sta->rx_nss, max_nss);
+       arg->rx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.rx_highest);
+       arg->rx_mcs_set = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
+       arg->tx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.tx_highest);
+       arg->tx_mcs_set = ath11k_peer_assoc_h_vht_limit(
+               __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask);
+
+       /* In IPQ8074 platform, VHT mcs rate 10 and 11 is enabled by default.
+        * VHT mcs rate 10 and 11 is not suppoerted in 11ac standard.
+        * so explicitly disable the VHT MCS rate 10 and 11 in 11ac mode.
+        */
+       arg->tx_mcs_set &= ~IEEE80211_VHT_MCS_SUPPORT_0_11_MASK;
+       arg->tx_mcs_set |= IEEE80211_DISABLE_VHT_MCS_SUPPORT_0_11;
+
+       /* TODO:  Check */
+       arg->tx_max_mcs_nss = 0xFF;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
+                  sta->addr, arg->peer_max_mpdu, arg->peer_flags);
+
+       /* TODO: rxnss_override */
+}
+
+static void ath11k_peer_assoc_h_he(struct ath11k *ar,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_sta *sta,
+                                  struct peer_assoc_params *arg)
+{
+       /* TODO: Implementation */
+}
+
+static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta,
+                                    struct peer_assoc_params *arg)
+{
+       const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
+       int smps;
+
+       if (!ht_cap->ht_supported)
+               return;
+
+       smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
+       smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+       switch (smps) {
+       case WLAN_HT_CAP_SM_PS_STATIC:
+               arg->static_mimops_flag = true;
+               break;
+       case WLAN_HT_CAP_SM_PS_DYNAMIC:
+               arg->dynamic_mimops_flag = true;
+               break;
+       case WLAN_HT_CAP_SM_PS_DISABLED:
+               arg->spatial_mux_flag = true;
+               break;
+       default:
+               break;
+       }
+}
+
+static void ath11k_peer_assoc_h_qos(struct ath11k *ar,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_sta *sta,
+                                   struct peer_assoc_params *arg)
+{
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+
+       switch (arvif->vdev_type) {
+       case WMI_VDEV_TYPE_AP:
+               if (sta->wme) {
+                       /* TODO: Check WME vs QoS */
+                       arg->is_wme_set = true;
+                       arg->qos_flag = true;
+               }
+
+               if (sta->wme && sta->uapsd_queues) {
+                       /* TODO: Check WME vs QoS */
+                       arg->is_wme_set = true;
+                       arg->apsd_flag = true;
+                       arg->peer_rate_caps |= WMI_HOST_RC_UAPSD_FLAG;
+               }
+               break;
+       case WMI_VDEV_TYPE_STA:
+               if (sta->wme) {
+                       arg->is_wme_set = true;
+                       arg->qos_flag = true;
+               }
+               break;
+       default:
+               break;
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac peer %pM qos %d\n",
+                  sta->addr, arg->qos_flag);
+}
+
+static int ath11k_peer_assoc_qos_ap(struct ath11k *ar,
+                                   struct ath11k_vif *arvif,
+                                   struct ieee80211_sta *sta)
+{
+       struct ap_ps_params params;
+       u32 max_sp;
+       u32 uapsd;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       params.vdev_id = arvif->vdev_id;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
+                  sta->uapsd_queues, sta->max_sp);
+
+       uapsd = 0;
+       if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
+               uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
+                        WMI_AP_PS_UAPSD_AC3_TRIGGER_EN;
+       if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
+               uapsd |= WMI_AP_PS_UAPSD_AC2_DELIVERY_EN |
+                        WMI_AP_PS_UAPSD_AC2_TRIGGER_EN;
+       if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
+               uapsd |= WMI_AP_PS_UAPSD_AC1_DELIVERY_EN |
+                        WMI_AP_PS_UAPSD_AC1_TRIGGER_EN;
+       if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
+               uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN |
+                        WMI_AP_PS_UAPSD_AC0_TRIGGER_EN;
+
+       max_sp = 0;
+       if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
+               max_sp = sta->max_sp;
+
+       params.param = WMI_AP_PS_PEER_PARAM_UAPSD;
+       params.value = uapsd;
+       ret = ath11k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, ¶ms);
+       if (ret)
+               goto err;
+
+       params.param = WMI_AP_PS_PEER_PARAM_MAX_SP;
+       params.value = max_sp;
+       ret = ath11k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, ¶ms);
+       if (ret)
+               goto err;
+
+       /* TODO revisit during testing */
+       params.param = WMI_AP_PS_PEER_PARAM_SIFS_RESP_FRMTYPE;
+       params.value = DISABLE_SIFS_RESPONSE_TRIGGER;
+       ret = ath11k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, ¶ms);
+       if (ret)
+               goto err;
+
+       params.param = WMI_AP_PS_PEER_PARAM_SIFS_RESP_UAPSD;
+       params.value = DISABLE_SIFS_RESPONSE_TRIGGER;
+       ret = ath11k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, ¶ms);
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       ath11k_warn(ar->ab, "failed to set ap ps peer param %d for vdev %i: %d\n",
+                   params.param, arvif->vdev_id, ret);
+       return ret;
+}
+
+static bool ath11k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta)
+{
+       return sta->supp_rates[NL80211_BAND_2GHZ] >>
+              ATH11K_MAC_FIRST_OFDM_RATE_IDX;
+}
+
+static enum wmi_phy_mode ath11k_mac_get_phymode_vht(struct ath11k *ar,
+                                                   struct ieee80211_sta *sta)
+{
+       if (sta->bandwidth == IEEE80211_STA_RX_BW_160) {
+               switch (sta->vht_cap.cap &
+                       IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
+               case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
+                       return MODE_11AC_VHT160;
+               case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
+                       return MODE_11AC_VHT80_80;
+               default:
+                       /* not sure if this is a valid case? */
+                       return MODE_11AC_VHT160;
+               }
+       }
+
+       if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
+               return MODE_11AC_VHT80;
+
+       if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
+               return MODE_11AC_VHT40;
+
+       if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
+               return MODE_11AC_VHT20;
+
+       return MODE_UNKNOWN;
+}
+
+static void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
+                                       struct ieee80211_vif *vif,
+                                       struct ieee80211_sta *sta,
+                                       struct peer_assoc_params *arg)
+{
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct cfg80211_chan_def def;
+       enum nl80211_band band;
+       const u8 *ht_mcs_mask;
+       const u16 *vht_mcs_mask;
+       enum wmi_phy_mode phymode = MODE_UNKNOWN;
+
+       if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
+               return;
+
+       band = def.chan->band;
+       ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
+       vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
+       switch (band) {
+       case NL80211_BAND_2GHZ:
+               if (sta->vht_cap.vht_supported &&
+                   !ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
+                       if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
+                               phymode = MODE_11AC_VHT40;
+                       else
+                               phymode = MODE_11AC_VHT20;
+               } else if (sta->ht_cap.ht_supported &&
+                          !ath11k_peer_assoc_h_ht_masked(ht_mcs_mask)) {
+                       if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
+                               phymode = MODE_11NG_HT40;
+                       else
+                               phymode = MODE_11NG_HT20;
+               } else if (ath11k_mac_sta_has_ofdm_only(sta)) {
+                       phymode = MODE_11G;
+               } else {
+                       phymode = MODE_11B;
+               }
+               /* TODO: HE */
+
+               break;
+       case NL80211_BAND_5GHZ:
+               /* Check VHT first */
+               if (sta->vht_cap.vht_supported &&
+                   !ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
+                       phymode = ath11k_mac_get_phymode_vht(ar, sta);
+               } else if (sta->ht_cap.ht_supported &&
+                          !ath11k_peer_assoc_h_ht_masked(ht_mcs_mask)) {
+                       if (sta->bandwidth >= IEEE80211_STA_RX_BW_40)
+                               phymode = MODE_11NA_HT40;
+                       else
+                               phymode = MODE_11NA_HT20;
+               } else {
+                       phymode = MODE_11A;
+               }
+               /* TODO: HE Phymode */
+               break;
+       default:
+               break;
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac peer %pM phymode %s\n",
+                  sta->addr, ath11k_wmi_phymode_str(phymode));
+
+       arg->peer_phymode = phymode;
+       WARN_ON(phymode == MODE_UNKNOWN);
+}
+
+static void ath11k_peer_assoc_prepare(struct ath11k *ar,
+                                     struct ieee80211_vif *vif,
+                                     struct ieee80211_sta *sta,
+                                     struct peer_assoc_params *arg,
+                                     bool reassoc)
+{
+       lockdep_assert_held(&ar->conf_mutex);
+
+       memset(arg, 0, sizeof(*arg));
+
+       reinit_completion(&ar->peer_assoc_done);
+
+       arg->peer_new_assoc = !reassoc;
+       ath11k_peer_assoc_h_basic(ar, vif, sta, arg);
+       ath11k_peer_assoc_h_crypto(ar, vif, sta, arg);
+       ath11k_peer_assoc_h_rates(ar, vif, sta, arg);
+       ath11k_peer_assoc_h_ht(ar, vif, sta, arg);
+       ath11k_peer_assoc_h_vht(ar, vif, sta, arg);
+       ath11k_peer_assoc_h_he(ar, vif, sta, arg);
+       ath11k_peer_assoc_h_qos(ar, vif, sta, arg);
+       ath11k_peer_assoc_h_phymode(ar, vif, sta, arg);
+       ath11k_peer_assoc_h_smps(sta, arg);
+
+       /* TODO: amsdu_disable req? */
+}
+
+static int ath11k_setup_peer_smps(struct ath11k *ar, struct ath11k_vif *arvif,
+                                 const u8 *addr,
+                                 const struct ieee80211_sta_ht_cap *ht_cap)
+{
+       int smps;
+
+       if (!ht_cap->ht_supported)
+               return 0;
+
+       smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
+       smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+       if (smps >= ARRAY_SIZE(ath11k_smps_map))
+               return -EINVAL;
+
+       return ath11k_wmi_set_peer_param(ar, addr, arvif->vdev_id,
+                                        WMI_PEER_MIMO_PS_STATE,
+                                        ath11k_smps_map[smps]);
+}
+
+static void ath11k_bss_assoc(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
+                            struct ieee80211_bss_conf *bss_conf)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct peer_assoc_params peer_arg;
+       struct ieee80211_sta *ap_sta;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n",
+                  arvif->vdev_id, arvif->bssid, arvif->aid);
+
+       rcu_read_lock();
+
+       ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
+       if (!ap_sta) {
+               ath11k_warn(ar->ab, "failed to find station entry for bss %pM vdev %i\n",
+                           bss_conf->bssid, arvif->vdev_id);
+               rcu_read_unlock();
+               return;
+       }
+
+       ath11k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg, false);
+
+       rcu_read_unlock();
+
+       ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n",
+                           bss_conf->bssid, arvif->vdev_id, ret);
+               return;
+       }
+
+       if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
+               ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
+                           bss_conf->bssid, arvif->vdev_id);
+               return;
+       }
+
+       ret = ath11k_setup_peer_smps(ar, arvif, bss_conf->bssid,
+                                    &ap_sta->ht_cap);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n",
+                           arvif->vdev_id, ret);
+               return;
+       }
+
+       WARN_ON(arvif->is_up);
+
+       arvif->aid = bss_conf->aid;
+       ether_addr_copy(arvif->bssid, bss_conf->bssid);
+
+       ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set vdev %d up: %d\n",
+                           arvif->vdev_id, ret);
+               return;
+       }
+
+       arvif->is_up = true;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                  "mac vdev %d up (associated) bssid %pM aid %d\n",
+                  arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
+
+       /* Authorize BSS Peer */
+       ret = ath11k_wmi_set_peer_param(ar, arvif->bssid,
+                                       arvif->vdev_id,
+                                       WMI_PEER_AUTHORIZE,
+                                       1);
+       if (ret)
+               ath11k_warn(ar->ab, "Unable to authorize BSS peer: %d\n", ret);
+}
+
+static void ath11k_bss_disassoc(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n",
+                  arvif->vdev_id, arvif->bssid);
+
+       ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id);
+       if (ret)
+               ath11k_warn(ar->ab, "failed to down vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+
+       arvif->is_up = false;
+
+       /* TODO: cancel connection_loss_work */
+}
+
+static u32 ath11k_mac_get_rate_hw_value(int bitrate)
+{
+       u32 preamble;
+       u16 hw_value;
+       int rate;
+       size_t i;
+
+       if (ath11k_mac_bitrate_is_cck(bitrate))
+               preamble = WMI_RATE_PREAMBLE_CCK;
+       else
+               preamble = WMI_RATE_PREAMBLE_OFDM;
+
+       for (i = 0; i < ARRAY_SIZE(ath11k_legacy_rates); i++) {
+               if (ath11k_legacy_rates[i].bitrate != bitrate)
+                       continue;
+
+               hw_value = ath11k_legacy_rates[i].hw_value;
+               rate = ATH11K_HW_RATE_CODE(hw_value, 0, preamble);
+
+               return rate;
+       }
+
+       return -EINVAL;
+}
+
+static void ath11k_recalculate_mgmt_rate(struct ath11k *ar,
+                                        struct ieee80211_vif *vif,
+                                        struct cfg80211_chan_def *def)
+{
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       const struct ieee80211_supported_band *sband;
+       u8 basic_rate_idx;
+       int hw_rate_code;
+       u32 vdev_param;
+       u16 bitrate;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       sband = ar->hw->wiphy->bands[def->chan->band];
+       basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
+       bitrate = sband->bitrates[basic_rate_idx].bitrate;
+
+       hw_rate_code = ath11k_mac_get_rate_hw_value(bitrate);
+       if (hw_rate_code < 0) {
+               ath11k_warn(ar->ab, "bitrate not supported %d\n", bitrate);
+               return;
+       }
+
+       vdev_param = WMI_VDEV_PARAM_MGMT_RATE;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param,
+                                           hw_rate_code);
+       if (ret)
+               ath11k_warn(ar->ab, "failed to set mgmt tx rate %d\n", ret);
+
+       vdev_param = WMI_VDEV_PARAM_BEACON_RATE;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param,
+                                           hw_rate_code);
+       if (ret)
+               ath11k_warn(ar->ab, "failed to set beacon tx rate %d\n", ret);
+}
+
+static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
+                                          struct ieee80211_vif *vif,
+                                          struct ieee80211_bss_conf *info,
+                                          u32 changed)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       struct cfg80211_chan_def def;
+       u32 param_id, param_value;
+       enum nl80211_band band;
+       u32 vdev_param;
+       int mcast_rate;
+       u32 preamble;
+       u16 hw_value;
+       u16 bitrate;
+       int ret = 0;
+       u8 rateidx;
+       u32 rate;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (changed & BSS_CHANGED_BEACON_INT) {
+               arvif->beacon_interval = info->beacon_int;
+
+               param_id = WMI_VDEV_PARAM_BEACON_INTERVAL;
+               ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                                   param_id,
+                                                   arvif->beacon_interval);
+               if (ret)
+                       ath11k_warn(ar->ab, "Failed to set beacon interval for VDEV: %d\n",
+                                   arvif->vdev_id);
+               else
+                       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                                  "Beacon interval: %d set for VDEV: %d\n",
+                                  arvif->beacon_interval, arvif->vdev_id);
+       }
+
+       if (changed & BSS_CHANGED_BEACON) {
+               param_id = WMI_PDEV_PARAM_BEACON_TX_MODE;
+               param_value = WMI_BEACON_STAGGERED_MODE;
+               ret = ath11k_wmi_pdev_set_param(ar, param_id,
+                                               param_value, ar->pdev->pdev_id);
+               if (ret)
+                       ath11k_warn(ar->ab, "Failed to set beacon mode for VDEV: %d\n",
+                                   arvif->vdev_id);
+               else
+                       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                                  "Set staggered beacon mode for VDEV: %d\n",
+                                  arvif->vdev_id);
+
+               ret = ath11k_mac_setup_bcn_tmpl(arvif);
+               if (ret)
+                       ath11k_warn(ar->ab, "failed to update bcn template: %d\n",
+                                   ret);
+       }
+
+       if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) {
+               arvif->dtim_period = info->dtim_period;
+
+               param_id = WMI_VDEV_PARAM_DTIM_PERIOD;
+               ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                                   param_id,
+                                                   arvif->dtim_period);
+
+               if (ret)
+                       ath11k_warn(ar->ab, "Failed to set dtim period for VDEV %d: %i\n",
+                                   arvif->vdev_id, ret);
+               else
+                       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                                  "DTIM period: %d set for VDEV: %d\n",
+                                  arvif->dtim_period, arvif->vdev_id);
+       }
+
+       if (changed & BSS_CHANGED_SSID &&
+           vif->type == NL80211_IFTYPE_AP) {
+               arvif->u.ap.ssid_len = info->ssid_len;
+               if (info->ssid_len)
+                       memcpy(arvif->u.ap.ssid, info->ssid, info->ssid_len);
+               arvif->u.ap.hidden_ssid = info->hidden_ssid;
+       }
+
+       if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
+               ether_addr_copy(arvif->bssid, info->bssid);
+
+       if (changed & BSS_CHANGED_BEACON_ENABLED)
+               ath11k_control_beaconing(arvif, info);
+
+       if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+               u32 cts_prot;
+
+               cts_prot = !!(info->use_cts_prot);
+               param_id = WMI_VDEV_PARAM_PROTECTION_MODE;
+
+               if (arvif->is_started) {
+                       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                                           param_id, cts_prot);
+                       if (ret)
+                               ath11k_warn(ar->ab, "Failed to set CTS prot for VDEV: %d\n",
+                                           arvif->vdev_id);
+                       else
+                               ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "Set CTS prot: %d for VDEV: %d\n",
+                                          cts_prot, arvif->vdev_id);
+               } else {
+                       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "defer protection mode setup, vdev is not ready yet\n");
+               }
+       }
+
+       if (changed & BSS_CHANGED_ERP_SLOT) {
+               u32 slottime;
+
+               if (info->use_short_slot)
+                       slottime = WMI_VDEV_SLOT_TIME_SHORT; /* 9us */
+
+               else
+                       slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */
+
+               param_id = WMI_VDEV_PARAM_SLOT_TIME;
+               ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                                   param_id, slottime);
+               if (ret)
+                       ath11k_warn(ar->ab, "Failed to set erp slot for VDEV: %d\n",
+                                   arvif->vdev_id);
+               else
+                       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                                  "Set slottime: %d for VDEV: %d\n",
+                                  slottime, arvif->vdev_id);
+       }
+
+       if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+               u32 preamble;
+
+               if (info->use_short_preamble)
+                       preamble = WMI_VDEV_PREAMBLE_SHORT;
+               else
+                       preamble = WMI_VDEV_PREAMBLE_LONG;
+
+               param_id = WMI_VDEV_PARAM_PREAMBLE;
+               ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                                   param_id, preamble);
+               if (ret)
+                       ath11k_warn(ar->ab, "Failed to set preamble for VDEV: %d\n",
+                                   arvif->vdev_id);
+               else
+                       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                                  "Set preamble: %d for VDEV: %d\n",
+                                  preamble, arvif->vdev_id);
+       }
+
+       if (changed & BSS_CHANGED_ASSOC) {
+               if (info->assoc)
+                       ath11k_bss_assoc(hw, vif, info);
+               else
+                       ath11k_bss_disassoc(hw, vif);
+       }
+
+       if (changed & BSS_CHANGED_TXPOWER) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev_id %i txpower %d\n",
+                          arvif->vdev_id, info->txpower);
+
+               arvif->txpower = info->txpower;
+               ath11k_mac_txpower_recalc(ar);
+       }
+
+       if (changed & BSS_CHANGED_MCAST_RATE &&
+           !ath11k_mac_vif_chan(arvif->vif, &def)) {
+               band = def.chan->band;
+               mcast_rate = vif->bss_conf.mcast_rate[band];
+
+               if (mcast_rate > 0)
+                       rateidx = mcast_rate - 1;
+               else
+                       rateidx = ffs(vif->bss_conf.basic_rates) - 1;
+
+               if (ar->pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP)
+                       rateidx += ATH11K_MAC_FIRST_OFDM_RATE_IDX;
+
+               bitrate = ath11k_legacy_rates[rateidx].bitrate;
+               hw_value = ath11k_legacy_rates[rateidx].hw_value;
+
+               if (ath11k_mac_bitrate_is_cck(bitrate))
+                       preamble = WMI_RATE_PREAMBLE_CCK;
+               else
+                       preamble = WMI_RATE_PREAMBLE_OFDM;
+
+               rate = ATH11K_HW_RATE_CODE(hw_value, 0, preamble);
+
+               ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                          "mac vdev %d mcast_rate %x\n",
+                          arvif->vdev_id, rate);
+
+               vdev_param = WMI_VDEV_PARAM_MCAST_DATA_RATE;
+               ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                                   vdev_param, rate);
+               if (ret)
+                       ath11k_warn(ar->ab,
+                                   "failed to set mcast rate on vdev %i: %d\n",
+                                   arvif->vdev_id,  ret);
+
+               vdev_param = WMI_VDEV_PARAM_BCAST_DATA_RATE;
+               ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                                   vdev_param, rate);
+               if (ret)
+                       ath11k_warn(ar->ab,
+                                   "failed to set bcast rate on vdev %i: %d\n",
+                                   arvif->vdev_id,  ret);
+       }
+
+       if (changed & BSS_CHANGED_BASIC_RATES &&
+           !ath11k_mac_vif_chan(arvif->vif, &def))
+               ath11k_recalculate_mgmt_rate(ar, vif, &def);
+
+       mutex_unlock(&ar->conf_mutex);
+}
+
+void __ath11k_mac_scan_finish(struct ath11k *ar)
+{
+       lockdep_assert_held(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH11K_SCAN_IDLE:
+               break;
+       case ATH11K_SCAN_RUNNING:
+       case ATH11K_SCAN_ABORTING:
+               if (!ar->scan.is_roc) {
+                       struct cfg80211_scan_info info = {
+                               .aborted = (ar->scan.state ==
+                                           ATH11K_SCAN_ABORTING),
+                       };
+
+                       ieee80211_scan_completed(ar->hw, &info);
+               } else if (ar->scan.roc_notify) {
+                       ieee80211_remain_on_channel_expired(ar->hw);
+               }
+               /* fall through */
+       case ATH11K_SCAN_STARTING:
+               ar->scan.state = ATH11K_SCAN_IDLE;
+               ar->scan_channel = NULL;
+               ar->scan.roc_freq = 0;
+               cancel_delayed_work(&ar->scan.timeout);
+               complete(&ar->scan.completed);
+               break;
+       }
+}
+
+void ath11k_mac_scan_finish(struct ath11k *ar)
+{
+       spin_lock_bh(&ar->data_lock);
+       __ath11k_mac_scan_finish(ar);
+       spin_unlock_bh(&ar->data_lock);
+}
+
+static int ath11k_scan_stop(struct ath11k *ar)
+{
+       struct scan_cancel_param arg = {
+               .req_type = WLAN_SCAN_CANCEL_SINGLE,
+               .scan_id = ATH11K_SCAN_ID,
+       };
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       /* TODO: Fill other STOP Params */
+       arg.pdev_id = ar->pdev->pdev_id;
+
+       ret = ath11k_wmi_send_scan_stop_cmd(ar, &arg);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to stop wmi scan: %d\n", ret);
+               goto out;
+       }
+
+       ret = wait_for_completion_timeout(&ar->scan.completed, 3 * HZ);
+       if (ret == 0) {
+               ath11k_warn(ar->ab,
+                           "failed to receive scan abort comple: timed out\n");
+               ret = -ETIMEDOUT;
+       } else if (ret > 0) {
+               ret = 0;
+       }
+
+out:
+       /* Scan state should be updated upon scan completion but in case
+        * firmware fails to deliver the event (for whatever reason) it is
+        * desired to clean up scan state anyway. Firmware may have just
+        * dropped the scan completion event delivery due to transport pipe
+        * being overflown with data and/or it can recover on its own before
+        * next scan request is submitted.
+        */
+       spin_lock_bh(&ar->data_lock);
+       if (ar->scan.state != ATH11K_SCAN_IDLE)
+               __ath11k_mac_scan_finish(ar);
+       spin_unlock_bh(&ar->data_lock);
+
+       return ret;
+}
+
+static void ath11k_scan_abort(struct ath11k *ar)
+{
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       spin_lock_bh(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH11K_SCAN_IDLE:
+               /* This can happen if timeout worker kicked in and called
+                * abortion while scan completion was being processed.
+                */
+               break;
+       case ATH11K_SCAN_STARTING:
+       case ATH11K_SCAN_ABORTING:
+               ath11k_warn(ar->ab, "refusing scan abortion due to invalid scan state: %d\n",
+                           ar->scan.state);
+               break;
+       case ATH11K_SCAN_RUNNING:
+               ar->scan.state = ATH11K_SCAN_ABORTING;
+               spin_unlock_bh(&ar->data_lock);
+
+               ret = ath11k_scan_stop(ar);
+               if (ret)
+                       ath11k_warn(ar->ab, "failed to abort scan: %d\n", ret);
+
+               spin_lock_bh(&ar->data_lock);
+               break;
+       }
+
+       spin_unlock_bh(&ar->data_lock);
+}
+
+static void ath11k_scan_timeout_work(struct work_struct *work)
+{
+       struct ath11k *ar = container_of(work, struct ath11k,
+                                        scan.timeout.work);
+
+       mutex_lock(&ar->conf_mutex);
+       ath11k_scan_abort(ar);
+       mutex_unlock(&ar->conf_mutex);
+}
+
+static int ath11k_start_scan(struct ath11k *ar,
+                            struct scan_req_params *arg)
+{
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ret = ath11k_wmi_send_scan_start_cmd(ar, arg);
+       if (ret)
+               return ret;
+
+       ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ);
+       if (ret == 0) {
+               ret = ath11k_scan_stop(ar);
+               if (ret)
+                       ath11k_warn(ar->ab, "failed to stop scan: %d\n", ret);
+
+               return -ETIMEDOUT;
+       }
+
+       /* If we failed to start the scan, return error code at
+        * this point.  This is probably due to some issue in the
+        * firmware, but no need to wedge the driver due to that...
+        */
+       spin_lock_bh(&ar->data_lock);
+       if (ar->scan.state == ATH11K_SCAN_IDLE) {
+               spin_unlock_bh(&ar->data_lock);
+               return -EINVAL;
+       }
+       spin_unlock_bh(&ar->data_lock);
+
+       return 0;
+}
+
+static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_scan_request *hw_req)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       struct cfg80211_scan_request *req = &hw_req->req;
+       struct scan_req_params arg;
+       int ret = 0;
+       int i;
+
+       mutex_lock(&ar->conf_mutex);
+
+       spin_lock_bh(&ar->data_lock);
+       switch (ar->scan.state) {
+       case ATH11K_SCAN_IDLE:
+               reinit_completion(&ar->scan.started);
+               reinit_completion(&ar->scan.completed);
+               ar->scan.state = ATH11K_SCAN_STARTING;
+               ar->scan.is_roc = false;
+               ar->scan.vdev_id = arvif->vdev_id;
+               ret = 0;
+               break;
+       case ATH11K_SCAN_STARTING:
+       case ATH11K_SCAN_RUNNING:
+       case ATH11K_SCAN_ABORTING:
+               ret = -EBUSY;
+               break;
+       }
+       spin_unlock_bh(&ar->data_lock);
+
+       if (ret)
+               goto exit;
+
+       memset(&arg, 0, sizeof(arg));
+       ath11k_wmi_start_scan_init(ar, &arg);
+       arg.vdev_id = arvif->vdev_id;
+       arg.scan_id = ATH11K_SCAN_ID;
+
+       if (req->ie_len) {
+               arg.extraie.len = req->ie_len;
+               arg.extraie.ptr = kzalloc(req->ie_len, GFP_KERNEL);
+               memcpy(arg.extraie.ptr, req->ie, req->ie_len);
+       }
+
+       if (req->n_ssids) {
+               arg.num_ssids = req->n_ssids;
+               for (i = 0; i < arg.num_ssids; i++) {
+                       arg.ssid[i].length  = req->ssids[i].ssid_len;
+                       memcpy(&arg.ssid[i].ssid, req->ssids[i].ssid,
+                              req->ssids[i].ssid_len);
+               }
+       } else {
+               arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE;
+       }
+
+       if (req->n_channels) {
+               arg.num_chan = req->n_channels;
+               for (i = 0; i < arg.num_chan; i++)
+                       arg.chan_list[i] = req->channels[i]->center_freq;
+       }
+
+       ret = ath11k_start_scan(ar, &arg);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to start hw scan: %d\n", ret);
+               spin_lock_bh(&ar->data_lock);
+               ar->scan.state = ATH11K_SCAN_IDLE;
+               spin_unlock_bh(&ar->data_lock);
+       }
+
+       /* Add a 200ms margin to account for event/command processing */
+       ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+                                    msecs_to_jiffies(arg.max_scan_time +
+                                                     ATH11K_MAC_SCAN_TIMEOUT_MSECS));
+
+exit:
+       if (req->ie_len)
+               kfree(arg.extraie.ptr);
+
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static void ath11k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw,
+                                        struct ieee80211_vif *vif)
+{
+       struct ath11k *ar = hw->priv;
+
+       mutex_lock(&ar->conf_mutex);
+       ath11k_scan_abort(ar);
+       mutex_unlock(&ar->conf_mutex);
+
+       cancel_delayed_work_sync(&ar->scan.timeout);
+}
+
+static int ath11k_install_key(struct ath11k_vif *arvif,
+                             struct ieee80211_key_conf *key,
+                             enum set_key_cmd cmd,
+                             const u8 *macaddr, u32 flags)
+{
+       int ret;
+       struct ath11k *ar = arvif->ar;
+       struct wmi_vdev_install_key_arg arg = {
+               .vdev_id = arvif->vdev_id,
+               .key_idx = key->keyidx,
+               .key_len = key->keylen,
+               .key_data = key->key,
+               .key_flags = flags,
+               .macaddr = macaddr,
+       };
+
+       lockdep_assert_held(&arvif->ar->conf_mutex);
+
+       reinit_completion(&ar->install_key_done);
+
+       if (cmd == DISABLE_KEY) {
+               /* TODO: Check if FW expects  value other than NONE for del */
+               /* arg.key_cipher = WMI_CIPHER_NONE; */
+               arg.key_len = 0;
+               arg.key_data = NULL;
+               goto install;
+       }
+
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_CCMP:
+               arg.key_cipher = WMI_CIPHER_AES_CCM;
+               /* TODO: Re-check if flag is valid */
+               key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT;
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               arg.key_cipher = WMI_CIPHER_TKIP;
+               arg.key_txmic_len = 8;
+               arg.key_rxmic_len = 8;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP_256:
+               arg.key_cipher = WMI_CIPHER_AES_CCM;
+               break;
+       case WLAN_CIPHER_SUITE_GCMP:
+       case WLAN_CIPHER_SUITE_GCMP_256:
+               arg.key_cipher = WMI_CIPHER_AES_GCM;
+               break;
+       default:
+               ath11k_warn(ar->ab, "cipher %d is not supported\n", key->cipher);
+               return -EOPNOTSUPP;
+       }
+
+install:
+       ret = ath11k_wmi_vdev_install_key(arvif->ar, &arg);
+       if (ret)
+               return ret;
+
+       if (!wait_for_completion_timeout(&ar->install_key_done, 1 * HZ))
+               return -ETIMEDOUT;
+
+       return ar->install_key_status ? -EINVAL : 0;
+}
+
+static int ath11k_clear_peer_keys(struct ath11k_vif *arvif,
+                                 const u8 *addr)
+{
+       struct ath11k *ar = arvif->ar;
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_peer *peer;
+       int first_errno = 0;
+       int ret;
+       int i;
+       u32 flags = 0;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       spin_lock_bh(&ab->base_lock);
+       peer = ath11k_peer_find(ab, arvif->vdev_id, addr);
+       spin_unlock_bh(&ab->base_lock);
+
+       if (!peer)
+               return -ENOENT;
+
+       for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
+               if (!peer->keys[i])
+                       continue;
+
+               /* key flags are not required to delete the key */
+               ret = ath11k_install_key(arvif, peer->keys[i],
+                                        DISABLE_KEY, addr, flags);
+               if (ret < 0 && first_errno == 0)
+                       first_errno = ret;
+
+               if (ret < 0)
+                       ath11k_warn(ab, "failed to remove peer key %d: %d\n",
+                                   i, ret);
+
+               spin_lock_bh(&ab->base_lock);
+               peer->keys[i] = NULL;
+               spin_unlock_bh(&ab->base_lock);
+       }
+
+       return first_errno;
+}
+
+static int ath11k_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 ath11k *ar = hw->priv;
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       struct ath11k_peer *peer;
+       const u8 *peer_addr;
+       int ret = 0;
+       u32 flags = 0;
+
+       /* BIP needs to be done in software */
+       if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+           key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
+           key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
+           key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
+               return 1;
+
+       if (key->keyidx > WMI_MAX_KEY_INDEX)
+               return -ENOSPC;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (sta)
+               peer_addr = sta->addr;
+       else if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
+               peer_addr = vif->bss_conf.bssid;
+       else
+               peer_addr = vif->addr;
+
+       key->hw_key_idx = key->keyidx;
+
+       /* the peer should not disappear in mid-way (unless FW goes awry) since
+        * we already hold conf_mutex. we just make sure its there now.
+        */
+       spin_lock_bh(&ab->base_lock);
+       peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr);
+       spin_unlock_bh(&ab->base_lock);
+
+       if (!peer) {
+               if (cmd == SET_KEY) {
+                       ath11k_warn(ab, "cannot install key for non-existent peer %pM\n",
+                                   peer_addr);
+                       ret = -EOPNOTSUPP;
+                       goto exit;
+               } else {
+                       /* if the peer doesn't exist there is no key to disable
+                        * anymore
+                        */
+                       goto exit;
+               }
+       }
+
+       if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
+               flags |= WMI_KEY_PAIRWISE;
+       else
+               flags |= WMI_KEY_GROUP;
+
+       ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags);
+       if (ret) {
+               ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret);
+               goto exit;
+       }
+
+       spin_lock_bh(&ab->base_lock);
+       peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr);
+       if (peer && cmd == SET_KEY)
+               peer->keys[key->keyidx] = key;
+       else if (peer && cmd == DISABLE_KEY)
+               peer->keys[key->keyidx] = NULL;
+       else if (!peer)
+               /* impossible unless FW goes crazy */
+               ath11k_warn(ab, "peer %pM disappeared!\n", peer_addr);
+       spin_unlock_bh(&ab->base_lock);
+
+exit:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static int
+ath11k_mac_bitrate_mask_num_vht_rates(struct ath11k *ar,
+                                     enum nl80211_band band,
+                                     const struct cfg80211_bitrate_mask *mask)
+{
+       int num_rates = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++)
+               num_rates += hweight16(mask->control[band].vht_mcs[i]);
+
+       return num_rates;
+}
+
+static int
+ath11k_mac_set_peer_vht_fixed_rate(struct ath11k_vif *arvif,
+                                  struct ieee80211_sta *sta,
+                                  const struct cfg80211_bitrate_mask *mask,
+                                  enum nl80211_band band)
+{
+       struct ath11k *ar = arvif->ar;
+       u8 vht_rate, nss;
+       u32 rate_code;
+       int ret, i;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       nss = 0;
+
+       for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
+               if (hweight16(mask->control[band].vht_mcs[i]) == 1) {
+                       nss = i + 1;
+                       vht_rate = ffs(mask->control[band].vht_mcs[i]) - 1;
+               }
+       }
+
+       if (!nss) {
+               ath11k_warn(ar->ab, "No single VHT Fixed rate found to set for %pM",
+                           sta->addr);
+               return -EINVAL;
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                  "Setting Fixed VHT Rate for peer %pM. Device will not switch to any other selected rates",
+                  sta->addr);
+
+       rate_code = ATH11K_HW_RATE_CODE(vht_rate, nss - 1,
+                                       WMI_RATE_PREAMBLE_VHT);
+       ret = ath11k_wmi_set_peer_param(ar, sta->addr,
+                                       arvif->vdev_id,
+                                       WMI_PEER_PARAM_FIXED_RATE,
+                                       rate_code);
+       if (ret)
+               ath11k_warn(ar->ab,
+                           "failed to update STA %pM Fixed Rate %d: %d\n",
+                            sta->addr, rate_code, ret);
+
+       return ret;
+}
+
+static int ath11k_station_assoc(struct ath11k *ar,
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_sta *sta,
+                               bool reassoc)
+{
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       struct peer_assoc_params peer_arg;
+       int ret = 0;
+       struct cfg80211_chan_def def;
+       enum nl80211_band band;
+       struct cfg80211_bitrate_mask *mask;
+       u8 num_vht_rates;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
+               return -EPERM;
+
+       band = def.chan->band;
+       mask = &arvif->bitrate_mask;
+
+       ath11k_peer_assoc_prepare(ar, vif, sta, &peer_arg, reassoc);
+
+       ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n",
+                           sta->addr, arvif->vdev_id, ret);
+               return ret;
+       }
+
+       if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
+               ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
+                           sta->addr, arvif->vdev_id);
+               return -ETIMEDOUT;
+       }
+
+       num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask);
+
+       /* If single VHT rate is configured (by set_bitrate_mask()),
+        * peer_assoc will disable VHT. This is now enabled by a peer specific
+        * fixed param.
+        * Note that all other rates and NSS will be disabled for this peer.
+        */
+       if (sta->vht_cap.vht_supported && num_vht_rates == 1) {
+               ret = ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask,
+                                                        band);
+               if (ret)
+                       return ret;
+       }
+
+       /* Re-assoc is run only to update supported rates for given station. It
+        * doesn't make much sense to reconfigure the peer completely.
+        */
+       if (reassoc)
+               return 0;
+
+       ret = ath11k_setup_peer_smps(ar, arvif, sta->addr,
+                                    &sta->ht_cap);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+
+       if (!sta->wme) {
+               arvif->num_legacy_stations++;
+               ret = ath11k_recalc_rtscts_prot(arvif);
+               if (ret)
+                       return ret;
+       }
+
+       if (sta->wme && sta->uapsd_queues) {
+               ret = ath11k_peer_assoc_qos_ap(ar, arvif, sta);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to set qos params for STA %pM for vdev %i: %d\n",
+                                   sta->addr, arvif->vdev_id, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int ath11k_station_disassoc(struct ath11k *ar,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_sta *sta)
+{
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       int ret = 0;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (!sta->wme) {
+               arvif->num_legacy_stations--;
+               ret = ath11k_recalc_rtscts_prot(arvif);
+               if (ret)
+                       return ret;
+       }
+
+       ret = ath11k_clear_peer_keys(arvif, sta->addr);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to clear all peer keys for vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+       return 0;
+}
+
+static void ath11k_sta_rc_update_wk(struct work_struct *wk)
+{
+       struct ath11k *ar;
+       struct ath11k_vif *arvif;
+       struct ath11k_sta *arsta;
+       struct ieee80211_sta *sta;
+       struct cfg80211_chan_def def;
+       enum nl80211_band band;
+       const u8 *ht_mcs_mask;
+       const u16 *vht_mcs_mask;
+       u32 changed, bw, nss, smps;
+       int err, num_vht_rates;
+       const struct cfg80211_bitrate_mask *mask;
+       struct peer_assoc_params peer_arg;
+
+       arsta = container_of(wk, struct ath11k_sta, update_wk);
+       sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
+       arvif = arsta->arvif;
+       ar = arvif->ar;
+
+       if (WARN_ON(ath11k_mac_vif_chan(arvif->vif, &def)))
+               return;
+
+       band = def.chan->band;
+       ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
+       vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+
+       spin_lock_bh(&ar->data_lock);
+
+       changed = arsta->changed;
+       arsta->changed = 0;
+
+       bw = arsta->bw;
+       nss = arsta->nss;
+       smps = arsta->smps;
+
+       spin_unlock_bh(&ar->data_lock);
+
+       mutex_lock(&ar->conf_mutex);
+
+       nss = max_t(u32, 1, nss);
+       nss = min(nss, max(ath11k_mac_max_ht_nss(ht_mcs_mask),
+                          ath11k_mac_max_vht_nss(vht_mcs_mask)));
+
+       if (changed & IEEE80211_RC_BW_CHANGED) {
+               err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
+                                               WMI_PEER_CHWIDTH, bw);
+               if (err)
+                       ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n",
+                                   sta->addr, bw, err);
+       }
+
+       if (changed & IEEE80211_RC_NSS_CHANGED) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM nss %d\n",
+                          sta->addr, nss);
+
+               err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
+                                               WMI_PEER_NSS, nss);
+               if (err)
+                       ath11k_warn(ar->ab, "failed to update STA %pM nss %d: %d\n",
+                                   sta->addr, nss, err);
+       }
+
+       if (changed & IEEE80211_RC_SMPS_CHANGED) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM smps %d\n",
+                          sta->addr, smps);
+
+               err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
+                                               WMI_PEER_MIMO_PS_STATE, smps);
+               if (err)
+                       ath11k_warn(ar->ab, "failed to update STA %pM smps %d: %d\n",
+                                   sta->addr, smps, err);
+       }
+
+       if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
+               mask = &arvif->bitrate_mask;
+               num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band,
+                                                                     mask);
+
+               /* Peer_assoc_prepare will reject vht rates in
+                * bitrate_mask if its not available in range format and
+                * sets vht tx_rateset as unsupported. So multiple VHT MCS
+                * setting(eg. MCS 4,5,6) per peer is not supported here.
+                * But, Single rate in VHT mask can be set as per-peer
+                * fixed rate. But even if any HT rates are configured in
+                * the bitrate mask, device will not switch to those rates
+                * when per-peer Fixed rate is set.
+                * TODO: Check RATEMASK_CMDID to support auto rates selection
+                * across HT/VHT and for multiple VHT MCS support.
+                */
+               if (sta->vht_cap.vht_supported && num_vht_rates == 1) {
+                       ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask,
+                                                          band);
+               } else {
+                       /* If the peer is non-VHT or no fixed VHT rate
+                        * is provided in the new bitrate mask we set the
+                        * other rates using peer_assoc command.
+                        */
+                       ath11k_peer_assoc_prepare(ar, arvif->vif, sta,
+                                                 &peer_arg, true);
+
+                       err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
+                       if (err)
+                               ath11k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n",
+                                           sta->addr, arvif->vdev_id, err);
+
+                       if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ))
+                               ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
+                                           sta->addr, arvif->vdev_id);
+               }
+       }
+
+       mutex_unlock(&ar->conf_mutex);
+}
+
+static int ath11k_mac_inc_num_stations(struct ath11k_vif *arvif,
+                                      struct ieee80211_sta *sta)
+{
+       struct ath11k *ar = arvif->ar;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
+               return 0;
+
+       if (ar->num_stations >= ar->max_num_stations)
+               return -ENOBUFS;
+
+       ar->num_stations++;
+
+       return 0;
+}
+
+static void ath11k_mac_dec_num_stations(struct ath11k_vif *arvif,
+                                       struct ieee80211_sta *sta)
+{
+       struct ath11k *ar = arvif->ar;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
+               return;
+
+       ar->num_stations--;
+}
+
+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 = (struct ath11k_sta *)sta->drv_priv;
+       struct peer_create_params peer_param;
+       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);
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (old_state == IEEE80211_STA_NOTEXIST &&
+           new_state == IEEE80211_STA_NONE) {
+               memset(arsta, 0, sizeof(*arsta));
+               arsta->arvif = arvif;
+               INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk);
+
+               ret = ath11k_mac_inc_num_stations(arvif, sta);
+               if (ret) {
+                       ath11k_warn(ar->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 exit;
+               }
+
+               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(ar->ab, "Failed to add peer: %pM for VDEV: %d\n",
+                                   sta->addr, arvif->vdev_id);
+                       ath11k_mac_dec_num_stations(arvif, sta);
+                       goto exit;
+               }
+
+               ath11k_info(ar->ab, "Added peer: %pM for VDEV: %d\n",
+                           sta->addr, arvif->vdev_id);
+
+               if (ath11k_debug_is_extd_tx_stats_enabled(ar)) {
+                       arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats),
+                                                 GFP_KERNEL);
+                       if (!arsta->tx_stats) {
+                               ret = -ENOMEM;
+                               goto exit;
+                       }
+               }
+
+               if (ieee80211_vif_is_mesh(vif)) {
+                       ret = ath11k_wmi_set_peer_param(ar, sta->addr,
+                                                       arvif->vdev_id,
+                                                       WMI_PEER_USE_4ADDR, 1);
+                       if (ret) {
+                               ath11k_warn(ar->ab, "failed to STA %pM 4addr capability: %d\n",
+                                           sta->addr, ret);
+                               goto exit;
+                       }
+               }
+
+               ret = ath11k_dp_peer_setup(ar, arvif->vdev_id, sta->addr);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to setup dp for peer %pM on vdev %i (%d)\n",
+                                   sta->addr, arvif->vdev_id, ret);
+                       ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
+                       ath11k_mac_dec_num_stations(arvif, sta);
+               }
+       } else if ((old_state == IEEE80211_STA_NONE &&
+                   new_state == IEEE80211_STA_NOTEXIST)) {
+               ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr);
+
+               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_info(ar->ab,
+                                   "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;
+       } 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);
+               else
+                       ath11k_info(ar->ab,
+                                   "Station %pM moved to assoc state\n",
+                                   sta->addr);
+       } 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);
+               else
+                       ath11k_info(ar->ab,
+                                   "Station %pM moved to disassociated state\n",
+                                   sta->addr);
+       }
+
+exit:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif,
+                                       struct ieee80211_sta *sta,
+                                       u32 changed)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct ath11k_peer *peer;
+       u32 bw, smps;
+
+       spin_lock_bh(&ar->ab->base_lock);
+
+       peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
+       if (!peer) {
+               spin_unlock_bh(&ar->ab->base_lock);
+               ath11k_warn(ar->ab, "mac sta rc update failed to find peer %pM on vdev %i\n",
+                           sta->addr, arvif->vdev_id);
+               return;
+       }
+
+       spin_unlock_bh(&ar->ab->base_lock);
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                  "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
+                  sta->addr, changed, sta->bandwidth, sta->rx_nss,
+                  sta->smps_mode);
+
+       spin_lock_bh(&ar->data_lock);
+
+       if (changed & IEEE80211_RC_BW_CHANGED) {
+               bw = WMI_PEER_CHWIDTH_20MHZ;
+
+               switch (sta->bandwidth) {
+               case IEEE80211_STA_RX_BW_20:
+                       bw = WMI_PEER_CHWIDTH_20MHZ;
+                       break;
+               case IEEE80211_STA_RX_BW_40:
+                       bw = WMI_PEER_CHWIDTH_40MHZ;
+                       break;
+               case IEEE80211_STA_RX_BW_80:
+                       bw = WMI_PEER_CHWIDTH_80MHZ;
+                       break;
+               case IEEE80211_STA_RX_BW_160:
+                       bw = WMI_PEER_CHWIDTH_160MHZ;
+                       break;
+               default:
+                       ath11k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n",
+                                   sta->bandwidth, sta->addr);
+                       bw = WMI_PEER_CHWIDTH_20MHZ;
+                       break;
+               }
+
+               arsta->bw = bw;
+       }
+
+       if (changed & IEEE80211_RC_NSS_CHANGED)
+               arsta->nss = sta->rx_nss;
+
+       if (changed & IEEE80211_RC_SMPS_CHANGED) {
+               smps = WMI_PEER_SMPS_PS_NONE;
+
+               switch (sta->smps_mode) {
+               case IEEE80211_SMPS_AUTOMATIC:
+               case IEEE80211_SMPS_OFF:
+                       smps = WMI_PEER_SMPS_PS_NONE;
+                       break;
+               case IEEE80211_SMPS_STATIC:
+                       smps = WMI_PEER_SMPS_STATIC;
+                       break;
+               case IEEE80211_SMPS_DYNAMIC:
+                       smps = WMI_PEER_SMPS_DYNAMIC;
+                       break;
+               default:
+                       ath11k_warn(ar->ab, "Invalid smps %d in sta rc update for %pM\n",
+                                   sta->smps_mode, sta->addr);
+                       smps = WMI_PEER_SMPS_PS_NONE;
+                       break;
+               }
+
+               arsta->smps = smps;
+       }
+
+       arsta->changed |= changed;
+
+       spin_unlock_bh(&ar->data_lock);
+
+       ieee80211_queue_work(hw, &arsta->update_wk);
+}
+
+static int ath11k_conf_tx_uapsd(struct ath11k *ar, struct ieee80211_vif *vif,
+                               u16 ac, bool enable)
+{
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       u32 value = 0;
+       int ret = 0;
+
+       if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+               return 0;
+
+       switch (ac) {
+       case IEEE80211_AC_VO:
+               value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN |
+                       WMI_STA_PS_UAPSD_AC3_TRIGGER_EN;
+               break;
+       case IEEE80211_AC_VI:
+               value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN |
+                       WMI_STA_PS_UAPSD_AC2_TRIGGER_EN;
+               break;
+       case IEEE80211_AC_BE:
+               value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN |
+                       WMI_STA_PS_UAPSD_AC1_TRIGGER_EN;
+               break;
+       case IEEE80211_AC_BK:
+               value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN |
+                       WMI_STA_PS_UAPSD_AC0_TRIGGER_EN;
+               break;
+       }
+
+       if (enable)
+               arvif->u.sta.uapsd |= value;
+       else
+               arvif->u.sta.uapsd &= ~value;
+
+       ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
+                                         WMI_STA_PS_PARAM_UAPSD,
+                                         arvif->u.sta.uapsd);
+       if (ret) {
+               ath11k_warn(ar->ab, "could not set uapsd params %d\n", ret);
+               goto exit;
+       }
+
+       if (arvif->u.sta.uapsd)
+               value = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD;
+       else
+               value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
+
+       ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
+                                         WMI_STA_PS_PARAM_RX_WAKE_POLICY,
+                                         value);
+       if (ret)
+               ath11k_warn(ar->ab, "could not set rx wake param %d\n", ret);
+
+exit:
+       return ret;
+}
+
+static int ath11k_mac_op_conf_tx(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif, u16 ac,
+                                const struct ieee80211_tx_queue_params *params)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct wmi_wmm_params_arg *p = NULL;
+       int ret;
+
+       mutex_lock(&ar->conf_mutex);
+
+       switch (ac) {
+       case IEEE80211_AC_VO:
+               p = &arvif->wmm_params.ac_vo;
+               break;
+       case IEEE80211_AC_VI:
+               p = &arvif->wmm_params.ac_vi;
+               break;
+       case IEEE80211_AC_BE:
+               p = &arvif->wmm_params.ac_be;
+               break;
+       case IEEE80211_AC_BK:
+               p = &arvif->wmm_params.ac_bk;
+               break;
+       }
+
+       if (WARN_ON(!p)) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       p->cwmin = params->cw_min;
+       p->cwmax = params->cw_max;
+       p->aifs = params->aifs;
+
+       /* The channel time duration programmed in the HW is in absolute
+        * microseconds, while mac80211 gives the txop in units of
+        * 32 microseconds.
+        */
+       p->txop = params->txop * 32;
+
+       ret = ath11k_wmi_send_wmm_update_cmd_tlv(ar, arvif->vdev_id,
+                                                &arvif->wmm_params);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set wmm params: %d\n", ret);
+               goto exit;
+       }
+
+       ret = ath11k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
+
+       if (ret)
+               ath11k_warn(ar->ab, "failed to set sta uapsd: %d\n", ret);
+
+exit:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static struct ieee80211_sta_ht_cap
+ath11k_create_ht_cap(struct ath11k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask)
+{
+       int i;
+       struct ieee80211_sta_ht_cap ht_cap = {0};
+       u32 ar_vht_cap = ar->pdev->cap.vht_cap;
+
+       if (!(ar_ht_cap & WMI_HT_CAP_ENABLED))
+               return ht_cap;
+
+       ht_cap.ht_supported = 1;
+       ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+       ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
+       ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+       ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
+       ht_cap.cap |= WLAN_HT_CAP_SM_PS_STATIC << IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+       if (ar_ht_cap & WMI_HT_CAP_HT20_SGI)
+               ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+
+       if (ar_ht_cap & WMI_HT_CAP_HT40_SGI)
+               ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+
+       if (ar_ht_cap & WMI_HT_CAP_DYNAMIC_SMPS) {
+               u32 smps;
+
+               smps   = WLAN_HT_CAP_SM_PS_DYNAMIC;
+               smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+               ht_cap.cap |= smps;
+       }
+
+       if (ar_ht_cap & WMI_HT_CAP_TX_STBC)
+               ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
+
+       if (ar_ht_cap & WMI_HT_CAP_RX_STBC) {
+               u32 stbc;
+
+               stbc   = ar_ht_cap;
+               stbc  &= WMI_HT_CAP_RX_STBC;
+               stbc >>= WMI_HT_CAP_RX_STBC_MASK_SHIFT;
+               stbc <<= IEEE80211_HT_CAP_RX_STBC_SHIFT;
+               stbc  &= IEEE80211_HT_CAP_RX_STBC;
+
+               ht_cap.cap |= stbc;
+       }
+
+       if (ar_ht_cap & WMI_HT_CAP_RX_LDPC)
+               ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
+       if (ar_ht_cap & WMI_HT_CAP_L_SIG_TXOP_PROT)
+               ht_cap.cap |= IEEE80211_HT_CAP_LSIG_TXOP_PROT;
+
+       if (ar_vht_cap & WMI_VHT_CAP_MAX_MPDU_LEN_MASK)
+               ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
+
+       for (i = 0; i < ar->num_rx_chains; i++) {
+               if (rate_cap_rx_chainmask & BIT(i))
+                       ht_cap.mcs.rx_mask[i] = 0xFF;
+       }
+
+       ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
+
+       return ht_cap;
+}
+
+static int ath11k_mac_set_txbf_conf(struct ath11k_vif *arvif)
+{
+       u32 value = 0;
+       struct ath11k *ar = arvif->ar;
+       int nsts;
+       int sound_dim;
+       u32 vht_cap = ar->pdev->cap.vht_cap;
+       u32 vdev_param = WMI_VDEV_PARAM_TXBF;
+
+       if (vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) {
+               nsts = vht_cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
+               nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
+               value |= SM(nsts, WMI_TXBF_STS_CAP_OFFSET);
+       }
+
+       if (vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
+               sound_dim = vht_cap &
+                           IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
+               sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
+               if (sound_dim > (ar->num_tx_chains - 1))
+                       sound_dim = ar->num_tx_chains - 1;
+               value |= SM(sound_dim, WMI_BF_SOUND_DIM_OFFSET);
+       }
+
+       if (!value)
+               return 0;
+
+       if (vht_cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) {
+               value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER;
+
+               if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) &&
+                   arvif->vdev_type == WMI_VDEV_TYPE_AP)
+                       value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER;
+       }
+
+       /* TODO: SUBFEE not validated in HK, disable here until validated? */
+
+       if (vht_cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
+               value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE;
+
+               if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) &&
+                   arvif->vdev_type == WMI_VDEV_TYPE_STA)
+                       value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE;
+       }
+
+       return ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                            vdev_param, value);
+}
+
+static void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
+{
+       bool subfer, subfee;
+       int sound_dim = 0;
+
+       subfer = !!(*vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE));
+       subfee = !!(*vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE));
+
+       if (ar->num_tx_chains < 2) {
+               *vht_cap &= ~(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
+               subfer = false;
+       }
+
+       /* If SU Beaformer is not set, then disable MU Beamformer Capability */
+       if (!subfer)
+               *vht_cap &= ~(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
+
+       /* If SU Beaformee is not set, then disable MU Beamformee Capability */
+       if (!subfee)
+               *vht_cap &= ~(IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+
+       sound_dim = (*vht_cap & IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK);
+       sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
+       *vht_cap &= ~IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
+
+       /* TODO: Need to check invalid STS and Sound_dim values set by FW? */
+
+       /* Enable Sounding Dimension Field only if SU BF is enabled */
+       if (subfer) {
+               if (sound_dim > (ar->num_tx_chains - 1))
+                       sound_dim = ar->num_tx_chains - 1;
+
+               sound_dim <<= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
+               sound_dim &=  IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
+               *vht_cap |= sound_dim;
+       }
+
+       /* Use the STS advertised by FW unless SU Beamformee is not supported*/
+       if (!subfee)
+               *vht_cap &= ~(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
+}
+
+static struct ieee80211_sta_vht_cap
+ath11k_create_vht_cap(struct ath11k *ar, u32 rate_cap_tx_chainmask,
+                     u32 rate_cap_rx_chainmask)
+{
+       struct ieee80211_sta_vht_cap vht_cap = {0};
+       u16 txmcs_map, rxmcs_map;
+       int i;
+
+       vht_cap.vht_supported = 1;
+       vht_cap.cap = ar->pdev->cap.vht_cap;
+
+       ath11k_set_vht_txbf_cap(ar, &vht_cap.cap);
+
+       /* TODO: Enable back VHT160 mode once association issues are fixed */
+       /* Disabling VHT160 and VHT80+80 modes */
+       vht_cap.cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+       vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
+
+       rxmcs_map = 0;
+       txmcs_map = 0;
+       for (i = 0; i < 8; i++) {
+               if (i < ar->num_tx_chains && rate_cap_tx_chainmask & BIT(i))
+                       txmcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2);
+               else
+                       txmcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2);
+
+               if (i < ar->num_rx_chains && rate_cap_rx_chainmask & BIT(i))
+                       rxmcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2);
+               else
+                       rxmcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2);
+       }
+
+       if (rate_cap_tx_chainmask <= 1)
+               vht_cap.cap &= ~IEEE80211_VHT_CAP_TXSTBC;
+
+       vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_map);
+       vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_map);
+
+       return vht_cap;
+}
+
+static void ath11k_mac_setup_ht_vht_cap(struct ath11k *ar,
+                                       struct ath11k_pdev_cap *cap,
+                                       u32 *ht_cap_info)
+{
+       struct ieee80211_supported_band *band;
+       u32 rate_cap_tx_chainmask;
+       u32 rate_cap_rx_chainmask;
+       u32 ht_cap;
+
+       rate_cap_tx_chainmask = ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift;
+       rate_cap_rx_chainmask = ar->cfg_rx_chainmask >> cap->rx_chain_mask_shift;
+
+       if (cap->supported_bands & WMI_HOST_WLAN_2G_CAP) {
+               band = &ar->mac.sbands[NL80211_BAND_2GHZ];
+               ht_cap = cap->band[NL80211_BAND_2GHZ].ht_cap_info;
+               if (ht_cap_info)
+                       *ht_cap_info = ht_cap;
+               band->ht_cap = ath11k_create_ht_cap(ar, ht_cap,
+                                                   rate_cap_rx_chainmask);
+       }
+
+       if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) {
+               band = &ar->mac.sbands[NL80211_BAND_5GHZ];
+               ht_cap = cap->band[NL80211_BAND_5GHZ].ht_cap_info;
+               if (ht_cap_info)
+                       *ht_cap_info = ht_cap;
+               band->ht_cap = ath11k_create_ht_cap(ar, ht_cap,
+                                                   rate_cap_rx_chainmask);
+               band->vht_cap = ath11k_create_vht_cap(ar, rate_cap_tx_chainmask,
+                                                     rate_cap_rx_chainmask);
+       }
+}
+
+static int ath11k_check_chain_mask(struct ath11k *ar, u32 ant, bool is_tx_ant)
+{
+       /* TODO: Check the request chainmask against the supported
+        * chainmask table which is advertised in extented_service_ready event
+        */
+
+       return 0;
+}
+
+static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant)
+{
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (ath11k_check_chain_mask(ar, tx_ant, true))
+               return -EINVAL;
+
+       if (ath11k_check_chain_mask(ar, rx_ant, false))
+               return -EINVAL;
+
+       ar->cfg_tx_chainmask = tx_ant;
+       ar->cfg_rx_chainmask = rx_ant;
+
+       if (ar->state != ATH11K_STATE_ON &&
+           ar->state != ATH11K_STATE_RESTARTED)
+               return 0;
+
+       ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_TX_CHAIN_MASK,
+                                       tx_ant, ar->pdev->pdev_id);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set tx-chainmask: %d, req 0x%x\n",
+                           ret, tx_ant);
+               return ret;
+       }
+
+       ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RX_CHAIN_MASK,
+                                       rx_ant, ar->pdev->pdev_id);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set rx-chainmask: %d, req 0x%x\n",
+                           ret, rx_ant);
+               return ret;
+       }
+
+       /* Reload HT/VHT capability */
+       ath11k_mac_setup_ht_vht_cap(ar, &ar->pdev->cap, NULL);
+
+       return 0;
+}
+
+int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
+{
+       struct ath11k *ar = ctx;
+       struct ath11k_base *ab = ar->ab;
+       struct sk_buff *msdu = skb;
+       struct ieee80211_tx_info *info;
+
+       spin_lock_bh(&ar->txmgmt_idr_lock);
+       idr_remove(&ar->txmgmt_idr, buf_id);
+       spin_unlock_bh(&ar->txmgmt_idr_lock);
+       dma_unmap_single(ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len,
+                        DMA_TO_DEVICE);
+
+       info = IEEE80211_SKB_CB(msdu);
+       memset(&info->status, 0, sizeof(info->status));
+
+       ieee80211_free_txskb(ar->hw, msdu);
+
+       return 0;
+}
+
+static int ath11k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
+{
+       struct ieee80211_vif *vif = ctx;
+       struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb);
+       struct sk_buff *msdu = skb;
+       struct ath11k *ar = skb_cb->ar;
+       struct ath11k_base *ab = ar->ab;
+
+       if (skb_cb->vif == vif) {
+               spin_lock_bh(&ar->txmgmt_idr_lock);
+               idr_remove(&ar->txmgmt_idr, buf_id);
+               spin_unlock_bh(&ar->txmgmt_idr_lock);
+               dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len,
+                                DMA_TO_DEVICE);
+       }
+
+       return 0;
+}
+
+static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
+                                 struct sk_buff *skb)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       dma_addr_t paddr;
+       int buf_id;
+       int ret;
+
+       spin_lock_bh(&ar->txmgmt_idr_lock);
+       buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0,
+                          ATH11K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC);
+       spin_unlock_bh(&ar->txmgmt_idr_lock);
+       if (buf_id < 0)
+               return -ENOSPC;
+
+       if ((ieee80211_is_action(hdr->frame_control) ||
+            ieee80211_is_deauth(hdr->frame_control) ||
+            ieee80211_is_disassoc(hdr->frame_control)) &&
+            ieee80211_has_protected(hdr->frame_control)) {
+               skb_put(skb, IEEE80211_CCMP_MIC_LEN);
+       }
+
+       paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
+       if (dma_mapping_error(ab->dev, paddr)) {
+               ath11k_warn(ab, "failed to DMA map mgmt Tx buffer\n");
+               ret = -EIO;
+               goto err_free_idr;
+       }
+
+       ATH11K_SKB_CB(skb)->paddr = paddr;
+
+       ret = ath11k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send mgmt frame: %d\n", ret);
+               goto err_unmap_buf;
+       }
+
+       return 0;
+
+err_unmap_buf:
+       dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr,
+                        skb->len, DMA_TO_DEVICE);
+err_free_idr:
+       spin_lock_bh(&ar->txmgmt_idr_lock);
+       idr_remove(&ar->txmgmt_idr, buf_id);
+       spin_unlock_bh(&ar->txmgmt_idr_lock);
+
+       return ret;
+}
+
+static void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar)
+{
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL)
+               ieee80211_free_txskb(ar->hw, skb);
+}
+
+static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
+{
+       struct ath11k *ar = container_of(work, struct ath11k, wmi_mgmt_tx_work);
+       struct ieee80211_tx_info *info;
+       struct ath11k_vif *arvif;
+       struct sk_buff *skb;
+       int ret;
+
+       while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) {
+               info = IEEE80211_SKB_CB(skb);
+               arvif = ath11k_vif_to_arvif(info->control.vif);
+
+               ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to transmit management frame %d\n",
+                                   ret);
+                       ieee80211_free_txskb(ar->hw, skb);
+               } else {
+                       atomic_inc(&ar->num_pending_mgmt_tx);
+               }
+       }
+}
+
+static int ath11k_mac_mgmt_tx(struct ath11k *ar, struct sk_buff *skb,
+                             bool is_prb_rsp)
+{
+       struct sk_buff_head *q = &ar->wmi_mgmt_tx_queue;
+
+       if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
+               return -ESHUTDOWN;
+
+       /* Drop probe response packets when the pending management tx
+        * count has reached a certain threshold, so as to prioritize
+        * other mgmt packets like auth and assoc to be sent on time
+        * for establishing successful connections.
+        */
+       if (is_prb_rsp &&
+           atomic_read(&ar->num_pending_mgmt_tx) > ATH11K_PRB_RSP_DROP_THRESHOLD) {
+               ath11k_warn(ar->ab,
+                           "dropping probe response as pending queue is almost full\n");
+               return -ENOSPC;
+       }
+
+       if (skb_queue_len(q) == ATH11K_TX_MGMT_NUM_PENDING_MAX) {
+               ath11k_warn(ar->ab, "mgmt tx queue is full\n");
+               return -ENOSPC;
+       }
+
+       skb_queue_tail(q, skb);
+       ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
+
+       return 0;
+}
+
+static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
+                            struct ieee80211_tx_control *control,
+                            struct sk_buff *skb)
+{
+       struct ath11k *ar = hw->priv;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_vif *vif = info->control.vif;
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       bool is_prb_rsp;
+       int ret;
+
+       if (ieee80211_is_mgmt(hdr->frame_control)) {
+               is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
+               ret = ath11k_mac_mgmt_tx(ar, skb, is_prb_rsp);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to queue management frame %d\n",
+                                   ret);
+                       ieee80211_free_txskb(ar->hw, skb);
+               }
+               return;
+       }
+
+       ret = ath11k_dp_tx(ar, arvif, skb);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to transmit frame %d\n", ret);
+               ieee80211_free_txskb(ar->hw, skb);
+       }
+}
+
+void ath11k_mac_drain_tx(struct ath11k *ar)
+{
+       /* make sure rcu-protected mac80211 tx path itself is drained */
+       synchronize_net();
+
+       cancel_work_sync(&ar->wmi_mgmt_tx_work);
+       ath11k_mgmt_over_wmi_tx_purge(ar);
+}
+
+static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable)
+{
+       struct htt_rx_ring_tlv_filter tlv_filter = {0};
+       u32 ring_id;
+
+       if (enable)
+               tlv_filter = ath11k_mac_mon_status_filter_default;
+
+       ring_id = ar->dp.rx_mon_status_refill_ring.refill_buf_ring.ring_id;
+
+       return ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
+                                               HAL_RXDMA_MONITOR_STATUS,
+                                               DP_RX_BUFFER_SIZE, &tlv_filter);
+}
+
+static int ath11k_mac_op_start(struct ieee80211_hw *hw)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_pdev *pdev = ar->pdev;
+       int ret;
+
+       ath11k_mac_drain_tx(ar);
+       mutex_lock(&ar->conf_mutex);
+
+       switch (ar->state) {
+       case ATH11K_STATE_OFF:
+               ar->state = ATH11K_STATE_ON;
+               break;
+       case ATH11K_STATE_RESTARTING:
+               ar->state = ATH11K_STATE_RESTARTED;
+               break;
+       case ATH11K_STATE_RESTARTED:
+       case ATH11K_STATE_WEDGED:
+       case ATH11K_STATE_ON:
+               WARN_ON(1);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS,
+                                       1, pdev->pdev_id);
+
+       if (ret) {
+               ath11k_err(ar->ab, "failed to enable PMF QOS: (%d\n", ret);
+               goto err;
+       }
+
+       ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 1,
+                                       pdev->pdev_id);
+       if (ret) {
+               ath11k_err(ar->ab, "failed to enable dynamic bw: %d\n", ret);
+               goto err;
+       }
+
+       ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ARP_AC_OVERRIDE,
+                                       0, pdev->pdev_id);
+       if (ret) {
+               ath11k_err(ab, "failed to set ac override for ARP: %d\n",
+                          ret);
+               goto err;
+       }
+
+       ret = ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(ar, pdev->pdev_id);
+       if (ret) {
+               ath11k_err(ab, "failed to offload radar detection: %d\n",
+                          ret);
+               goto err;
+       }
+
+       ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
+                                                 HTT_PPDU_STATS_TAG_DEFAULT);
+       if (ret) {
+               ath11k_err(ab, "failed to req ppdu stats: %d\n", ret);
+               goto err;
+       }
+
+       ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_MESH_MCAST_ENABLE,
+                                       1, pdev->pdev_id);
+
+       if (ret) {
+               ath11k_err(ar->ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret);
+               goto err;
+       }
+
+       __ath11k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask);
+
+       /* TODO: Do we need to enable ANI? */
+
+       ath11k_reg_update_chan_list(ar);
+
+       ar->num_started_vdevs = 0;
+       ar->num_created_vdevs = 0;
+       ar->num_peers = 0;
+
+       /* Configure monitor status ring with default rx_filter to get rx status
+        * such as rssi, rx_duration.
+        */
+       ret = ath11k_mac_config_mon_status_default(ar, true);
+       if (ret) {
+               ath11k_err(ab, "failed to configure monitor status ring with default rx_filter: (%d)\n",
+                          ret);
+               goto err;
+       }
+
+       mutex_unlock(&ar->conf_mutex);
+
+       rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx],
+                          &ab->pdevs[ar->pdev_idx]);
+
+       return 0;
+
+err:
+       ar->state = ATH11K_STATE_OFF;
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static void ath11k_mac_op_stop(struct ieee80211_hw *hw)
+{
+       struct ath11k *ar = hw->priv;
+       struct htt_ppdu_stats_info *ppdu_stats, *tmp;
+       int ret;
+
+       ath11k_mac_drain_tx(ar);
+
+       mutex_lock(&ar->conf_mutex);
+       ret = ath11k_mac_config_mon_status_default(ar, false);
+       if (ret)
+               ath11k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n",
+                          ret);
+
+       clear_bit(ATH11K_CAC_RUNNING, &ar->dev_flags);
+       ar->state = ATH11K_STATE_OFF;
+       mutex_unlock(&ar->conf_mutex);
+
+       cancel_delayed_work_sync(&ar->scan.timeout);
+       cancel_work_sync(&ar->regd_update_work);
+
+       spin_lock_bh(&ar->data_lock);
+       list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
+               list_del(&ppdu_stats->list);
+               kfree(ppdu_stats);
+       }
+       spin_unlock_bh(&ar->data_lock);
+
+       rcu_assign_pointer(ar->ab->pdevs_active[ar->pdev_idx], NULL);
+
+       synchronize_rcu();
+
+       atomic_set(&ar->num_pending_mgmt_tx, 0);
+}
+
+static void
+ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif,
+                                   struct vdev_create_params *params)
+{
+       struct ath11k *ar = arvif->ar;
+       struct ath11k_pdev *pdev = ar->pdev;
+
+       params->if_id = arvif->vdev_id;
+       params->type = arvif->vdev_type;
+       params->subtype = arvif->vdev_subtype;
+       params->pdev_id = pdev->pdev_id;
+
+       if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) {
+               params->chains[NL80211_BAND_2GHZ].tx = ar->num_tx_chains;
+               params->chains[NL80211_BAND_2GHZ].rx = ar->num_rx_chains;
+       }
+       if (pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP) {
+               params->chains[NL80211_BAND_5GHZ].tx = ar->num_tx_chains;
+               params->chains[NL80211_BAND_5GHZ].rx = ar->num_rx_chains;
+       }
+}
+
+static u32
+ath11k_mac_prepare_he_mode(struct ath11k_pdev *pdev, u32 viftype)
+{
+       struct ath11k_pdev_cap *pdev_cap = &pdev->cap;
+       struct ath11k_band_cap *cap_band = NULL;
+       u32 *hecap_phy_ptr = NULL;
+       u32 hemode = 0;
+
+       if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP)
+               cap_band = &pdev_cap->band[NL80211_BAND_2GHZ];
+       else
+               cap_band = &pdev_cap->band[NL80211_BAND_5GHZ];
+
+       hecap_phy_ptr = &cap_band->he_cap_phy_info[0];
+
+       hemode = FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE) |
+               FIELD_PREP(HE_MODE_SU_TX_BFER, HECAP_PHY_SUBFMR_GET(hecap_phy_ptr)) |
+               FIELD_PREP(HE_MODE_UL_MUMIMO, HECAP_PHY_ULMUMIMO_GET(hecap_phy_ptr));
+
+       /* TODO WDS and other modes */
+       if (viftype == NL80211_IFTYPE_AP) {
+               hemode |= FIELD_PREP(HE_MODE_MU_TX_BFER,
+                          HECAP_PHY_MUBFMR_GET(hecap_phy_ptr)) |
+                       FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) |
+                       FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE);
+       } else {
+               hemode |= FIELD_PREP(HE_MODE_MU_TX_BFEE, HE_MU_BFEE_ENABLE);
+       }
+
+       return hemode;
+}
+
+static int ath11k_set_he_mu_sounding_mode(struct ath11k *ar,
+                                         struct ath11k_vif *arvif)
+{
+       u32 param_id, param_value;
+       struct ath11k_base *ab = ar->ab;
+       int ret = 0;
+
+       param_id = WMI_VDEV_PARAM_SET_HEMU_MODE;
+       param_value = ath11k_mac_prepare_he_mode(ar->pdev, arvif->vif->type);
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                           param_id, param_value);
+       if (ret) {
+               ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d param_value %x\n",
+                           arvif->vdev_id, ret, param_value);
+               return ret;
+       }
+       param_id = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE;
+       param_value =
+               FIELD_PREP(HE_VHT_SOUNDING_MODE, HE_VHT_SOUNDING_MODE_ENABLE) |
+               FIELD_PREP(HE_TRIG_NONTRIG_SOUNDING_MODE,
+                          HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE);
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                           param_id, param_value);
+       if (ret) {
+               ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+       return ret;
+}
+
+static int ath11k_mac_op_add_interface(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);
+       struct vdev_create_params vdev_param = {0};
+       struct peer_create_params peer_param;
+       u32 param_id, param_value;
+       u16 nss;
+       int i;
+       int ret;
+       int bit;
+
+       vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (vif->type == NL80211_IFTYPE_AP &&
+           ar->num_peers > (ar->max_num_peers - 1)) {
+               ath11k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
+               ret = -ENOBUFS;
+               goto err;
+       }
+
+       if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
+               ath11k_warn(ab, "failed to create vdev, reached max vdev limit %d\n",
+                           TARGET_NUM_VDEVS);
+               ret = -EBUSY;
+               goto err;
+       }
+
+       memset(arvif, 0, sizeof(*arvif));
+
+       arvif->ar = ar;
+       arvif->vif = vif;
+
+       INIT_LIST_HEAD(&arvif->list);
+
+       /* Should we initialize any worker to handle connection loss indication
+        * from firmware in sta mode?
+        */
+
+       for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
+               arvif->bitrate_mask.control[i].legacy = 0xffffffff;
+               memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
+                      sizeof(arvif->bitrate_mask.control[i].ht_mcs));
+               memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
+                      sizeof(arvif->bitrate_mask.control[i].vht_mcs));
+       }
+
+       bit = __ffs64(ab->free_vdev_map);
+
+       arvif->vdev_id = bit;
+       arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_UNSPECIFIED:
+       case NL80211_IFTYPE_STATION:
+               arvif->vdev_type = WMI_VDEV_TYPE_STA;
+               break;
+       case NL80211_IFTYPE_MESH_POINT:
+               arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S;
+               /* fall through */
+       case NL80211_IFTYPE_AP:
+               arvif->vdev_type = WMI_VDEV_TYPE_AP;
+               break;
+       case NL80211_IFTYPE_MONITOR:
+               arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac add interface id %d type %d subtype %d map %llx\n",
+                  arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
+                  ab->free_vdev_map);
+
+       vif->cab_queue = arvif->vdev_id % (ATH11K_HW_MAX_QUEUES - 1);
+       for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++)
+               vif->hw_queue[i] = i % (ATH11K_HW_MAX_QUEUES - 1);
+
+       ath11k_mac_setup_vdev_create_params(arvif, &vdev_param);
+
+       ret = ath11k_wmi_vdev_create(ar, vif->addr, &vdev_param);
+       if (ret) {
+               ath11k_warn(ab, "failed to create WMI vdev %d: %d\n",
+                           arvif->vdev_id, ret);
+               goto err;
+       }
+
+       ar->num_created_vdevs++;
+
+       ab->free_vdev_map &= ~(1LL << arvif->vdev_id);
+       spin_lock_bh(&ar->data_lock);
+       list_add(&arvif->list, &ar->arvifs);
+       spin_unlock_bh(&ar->data_lock);
+
+       param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
+       param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                           param_id, param_value);
+       if (ret) {
+               ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
+                           arvif->vdev_id, ret);
+               goto err_vdev_del;
+       }
+
+       nss = get_num_chains(ar->cfg_tx_chainmask) ? : 1;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                           WMI_VDEV_PARAM_NSS, nss);
+       if (ret) {
+               ath11k_warn(ab, "failed to set vdev %d chainmask 0x%x, nss %d :%d\n",
+                           arvif->vdev_id, ar->cfg_tx_chainmask, nss, ret);
+               goto err_vdev_del;
+       }
+
+       switch (arvif->vdev_type) {
+       case WMI_VDEV_TYPE_AP:
+               peer_param.vdev_id = arvif->vdev_id;
+               peer_param.peer_addr = vif->addr;
+               peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
+               ret = ath11k_peer_create(ar, arvif, NULL, &peer_param);
+               if (ret) {
+                       ath11k_warn(ab, "failed to vdev %d create peer for AP: %d\n",
+                                   arvif->vdev_id, ret);
+                       goto err_vdev_del;
+               }
+
+               ret = ath11k_mac_set_kickout(arvif);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to set vdev %i kickout parameters: %d\n",
+                                   arvif->vdev_id, ret);
+                       goto err_peer_del;
+               }
+               break;
+       case WMI_VDEV_TYPE_STA:
+               param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY;
+               param_value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
+               ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
+                                                 param_id, param_value);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to set vdev %d RX wake policy: %d\n",
+                                   arvif->vdev_id, ret);
+                       goto err_peer_del;
+               }
+
+               param_id = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
+               param_value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
+               ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
+                                                 param_id, param_value);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to set vdev %d TX wake threshold: %d\n",
+                                   arvif->vdev_id, ret);
+                       goto err_peer_del;
+               }
+
+               param_id = WMI_STA_PS_PARAM_PSPOLL_COUNT;
+               param_value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
+               ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
+                                                 param_id, param_value);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to set vdev %d pspoll count: %d\n",
+                                   arvif->vdev_id, ret);
+                       goto err_peer_del;
+               }
+               break;
+       default:
+               break;
+       }
+
+       arvif->txpower = vif->bss_conf.txpower;
+       ret = ath11k_mac_txpower_recalc(ar);
+       if (ret)
+               goto err_peer_del;
+
+       param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
+       param_value = ar->hw->wiphy->rts_threshold;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                           param_id, param_value);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set rts threshold for vdev %d: %d\n",
+                           arvif->vdev_id, ret);
+       }
+
+       ret = ath11k_mac_set_txbf_conf(arvif);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set txbf conf for vdev %d: %d\n",
+                           arvif->vdev_id, ret);
+       }
+
+       ath11k_dp_vdev_tx_attach(ar, arvif);
+
+       mutex_unlock(&ar->conf_mutex);
+
+       return 0;
+
+err_peer_del:
+       if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+               ar->num_peers--;
+               ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, arvif->vdev_id);
+       }
+
+err_vdev_del:
+       ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
+       ar->num_created_vdevs--;
+       ab->free_vdev_map |= 1LL << arvif->vdev_id;
+       spin_lock_bh(&ar->data_lock);
+       list_del(&arvif->list);
+       spin_unlock_bh(&ar->data_lock);
+
+err:
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static int ath11k_mac_vif_unref(int buf_id, void *skb, void *ctx)
+{
+       struct ieee80211_vif *vif = (struct ieee80211_vif *)ctx;
+       struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb);
+
+       if (skb_cb->vif == vif)
+               skb_cb->vif = NULL;
+
+       return 0;
+}
+
+static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
+                                          struct ieee80211_vif *vif)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+       struct ath11k_base *ab = ar->ab;
+       int ret;
+       int i;
+
+       mutex_lock(&ar->conf_mutex);
+
+       ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n",
+                  arvif->vdev_id);
+
+       ab->free_vdev_map |= 1LL << (arvif->vdev_id);
+       spin_lock_bh(&ar->data_lock);
+       list_del(&arvif->list);
+       spin_unlock_bh(&ar->data_lock);
+
+       if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+               ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr);
+               if (ret)
+                       ath11k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n",
+                                   arvif->vdev_id, ret);
+       }
+
+       ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
+       if (ret)
+               ath11k_warn(ab, "failed to delete WMI vdev %d: %d\n",
+                           arvif->vdev_id, ret);
+
+       ar->num_created_vdevs--;
+
+       ath11k_peer_cleanup(ar, arvif->vdev_id);
+
+       idr_for_each(&ar->txmgmt_idr,
+                    ath11k_mac_vif_txmgmt_idr_remove, vif);
+
+       for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) {
+               spin_lock_bh(&ab->dp.tx_ring[i].tx_idr_lock);
+               idr_for_each(&ab->dp.tx_ring[i].txbuf_idr,
+                            ath11k_mac_vif_unref, vif);
+               spin_unlock_bh(&ab->dp.tx_ring[i].tx_idr_lock);
+       }
+
+       /* Recalc txpower for remaining vdev */
+       ath11k_mac_txpower_recalc(ar);
+       clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
+
+       /* TODO: recal traffic pause state based on the available vdevs */
+
+       mutex_unlock(&ar->conf_mutex);
+}
+
+/* FIXME: Has to be verified. */
+#define SUPPORTED_FILTERS                      \
+       (FIF_ALLMULTI |                         \
+       FIF_CONTROL |                           \
+       FIF_PSPOLL |                            \
+       FIF_OTHER_BSS |                         \
+       FIF_BCN_PRBRESP_PROMISC |               \
+       FIF_PROBE_REQ |                         \
+       FIF_FCSFAIL)
+
+static void ath11k_mac_op_configure_filter(struct ieee80211_hw *hw,
+                                          unsigned int changed_flags,
+                                          unsigned int *total_flags,
+                                          u64 multicast)
+{
+       struct ath11k *ar = hw->priv;
+       bool reset_flag = false;
+       int ret = 0;
+
+       mutex_lock(&ar->conf_mutex);
+
+       changed_flags &= SUPPORTED_FILTERS;
+       *total_flags &= SUPPORTED_FILTERS;
+       ar->filter_flags = *total_flags;
+
+       /* For monitor mode */
+       reset_flag = !(ar->filter_flags & FIF_BCN_PRBRESP_PROMISC);
+
+       ret = ath11k_dp_tx_htt_monitor_mode_ring_config(ar, reset_flag);
+       if (!ret) {
+               if (!reset_flag)
+                       set_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
+               else
+                       clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
+       } else {
+               ath11k_warn(ar->ab,
+                           "fail to set monitor filter: %d\n", ret);
+       }
+       mutex_unlock(&ar->conf_mutex);
+}
+
+static int ath11k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
+{
+       struct ath11k *ar = hw->priv;
+
+       mutex_lock(&ar->conf_mutex);
+
+       *tx_ant = ar->cfg_tx_chainmask;
+       *rx_ant = ar->cfg_rx_chainmask;
+
+       mutex_unlock(&ar->conf_mutex);
+
+       return 0;
+}
+
+static int ath11k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+{
+       struct ath11k *ar = hw->priv;
+       int ret;
+
+       mutex_lock(&ar->conf_mutex);
+       ret = __ath11k_set_antenna(ar, tx_ant, rx_ant);
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static int ath11k_mac_op_ampdu_action(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif,
+                                     struct ieee80211_ampdu_params *params)
+{
+       struct ath11k *ar = hw->priv;
+       int ret = -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+
+       switch (params->action) {
+       case IEEE80211_AMPDU_RX_START:
+               ret = ath11k_dp_rx_ampdu_start(ar, params);
+               break;
+       case IEEE80211_AMPDU_RX_STOP:
+               ret = ath11k_dp_rx_ampdu_stop(ar, params);
+               break;
+       case IEEE80211_AMPDU_TX_START:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               /* Tx A-MPDU aggregation offloaded to hw/fw so deny mac80211
+                * Tx aggregation requests.
+                */
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static int ath11k_mac_op_add_chanctx(struct ieee80211_hw *hw,
+                                    struct ieee80211_chanctx_conf *ctx)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_base *ab = ar->ab;
+
+       ath11k_dbg(ab, ATH11K_DBG_MAC,
+                  "mac chanctx add freq %hu width %d ptr %pK\n",
+                  ctx->def.chan->center_freq, ctx->def.width, ctx);
+
+       mutex_lock(&ar->conf_mutex);
+
+       spin_lock_bh(&ar->data_lock);
+       /* TODO: In case of multiple channel context, populate rx_channel from
+        * Rx PPDU desc information.
+        */
+       ar->rx_channel = ctx->def.chan;
+       spin_unlock_bh(&ar->data_lock);
+
+       mutex_unlock(&ar->conf_mutex);
+
+       return 0;
+}
+
+static void ath11k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
+                                        struct ieee80211_chanctx_conf *ctx)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_base *ab = ar->ab;
+
+       ath11k_dbg(ab, ATH11K_DBG_MAC,
+                  "mac chanctx remove freq %hu width %d ptr %pK\n",
+                  ctx->def.chan->center_freq, ctx->def.width, ctx);
+
+       mutex_lock(&ar->conf_mutex);
+
+       spin_lock_bh(&ar->data_lock);
+       /* TODO: In case of there is one more channel context left, populate
+        * rx_channel with the channel of that remaining channel context.
+        */
+       ar->rx_channel = NULL;
+       spin_unlock_bh(&ar->data_lock);
+
+       mutex_unlock(&ar->conf_mutex);
+}
+
+static inline int ath11k_mac_vdev_setup_sync(struct ath11k *ar)
+{
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
+               return -ESHUTDOWN;
+
+       if (!wait_for_completion_timeout(&ar->vdev_setup_done,
+                                        ATH11K_VDEV_SETUP_TIMEOUT_HZ))
+               return -ETIMEDOUT;
+
+       return ar->last_wmi_vdev_start_status ? -EINVAL : 0;
+}
+
+static int
+ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif,
+                             const struct cfg80211_chan_def *chandef,
+                             bool restart)
+{
+       struct ath11k *ar = arvif->ar;
+       struct ath11k_base *ab = ar->ab;
+       struct wmi_vdev_start_req_arg arg = {};
+       int he_support = arvif->vif->bss_conf.he_support;
+       int ret = 0;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       reinit_completion(&ar->vdev_setup_done);
+
+       arg.vdev_id = arvif->vdev_id;
+       arg.dtim_period = arvif->dtim_period;
+       arg.bcn_intval = arvif->beacon_interval;
+
+       arg.channel.freq = chandef->chan->center_freq;
+       arg.channel.band_center_freq1 = chandef->center_freq1;
+       arg.channel.band_center_freq2 = chandef->center_freq2;
+       arg.channel.mode =
+               ath11k_phymodes[chandef->chan->band][chandef->width];
+
+       arg.channel.min_power = 0;
+       arg.channel.max_power = chandef->chan->max_power * 2;
+       arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
+       arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
+
+       arg.pref_tx_streams = ar->num_tx_chains;
+       arg.pref_rx_streams = ar->num_rx_chains;
+
+       if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+               arg.ssid = arvif->u.ap.ssid;
+               arg.ssid_len = arvif->u.ap.ssid_len;
+               arg.hidden_ssid = arvif->u.ap.hidden_ssid;
+
+               /* For now allow DFS for AP mode */
+               arg.channel.chan_radar =
+                       !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
+
+               arg.channel.passive = arg.channel.chan_radar;
+
+               spin_lock_bh(&ab->base_lock);
+               arg.regdomain = ar->ab->dfs_region;
+               spin_unlock_bh(&ab->base_lock);
+
+               /* TODO: Notify if secondary 80Mhz also needs radar detection */
+               if (he_support) {
+                       ret = ath11k_set_he_mu_sounding_mode(ar, arvif);
+                       if (ret) {
+                               ath11k_warn(ar->ab, "failed to set he mode vdev %i\n",
+                                           arg.vdev_id);
+                               return ret;
+                       }
+               }
+       }
+
+       arg.channel.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR);
+
+       ath11k_dbg(ab, ATH11K_DBG_MAC,
+                  "mac vdev %d start center_freq %d phymode %s\n",
+                  arg.vdev_id, arg.channel.freq,
+                  ath11k_wmi_phymode_str(arg.channel.mode));
+
+       ret = ath11k_wmi_vdev_start(ar, &arg, restart);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to %s WMI vdev %i\n",
+                           restart ? "restart" : "start", arg.vdev_id);
+               return ret;
+       }
+
+       ret = ath11k_mac_vdev_setup_sync(ar);
+       if (ret) {
+               ath11k_warn(ab, "failed to synchronize setup for vdev %i %s: %d\n",
+                           arg.vdev_id, restart ? "restart" : "start", ret);
+               return ret;
+       }
+
+       ar->num_started_vdevs++;
+
+       /* Enable CAC Flag in the driver by checking the channel DFS cac time,
+        * i.e dfs_cac_ms value which will be valid only for radar channels
+        * and state as NL80211_DFS_USABLE which indicates CAC needs to be
+        * done before channel usage. This flags is used to drop rx packets.
+        * during CAC.
+        */
+       /* TODO Set the flag for other interface types as required */
+       if (arvif->vdev_type == WMI_VDEV_TYPE_AP &&
+           chandef->chan->dfs_cac_ms &&
+           chandef->chan->dfs_state == NL80211_DFS_USABLE) {
+               set_bit(ATH11K_CAC_RUNNING, &ar->dev_flags);
+               ath11k_dbg(ab, ATH11K_DBG_MAC,
+                          "CAC Started in chan_freq %d for vdev %d\n",
+                          arg.channel.freq, arg.vdev_id);
+       }
+
+       return 0;
+}
+
+static int ath11k_mac_vdev_stop(struct ath11k_vif *arvif)
+{
+       struct ath11k *ar = arvif->ar;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       reinit_completion(&ar->vdev_setup_done);
+
+       spin_lock_bh(&ar->data_lock);
+
+       ar->vdev_stop_status.stop_in_progress = true;
+       ar->vdev_stop_status.vdev_id = arvif->vdev_id;
+
+       spin_unlock_bh(&ar->data_lock);
+
+       ret = ath11k_wmi_vdev_stop(ar, arvif->vdev_id);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               goto err;
+       }
+
+       ret = ath11k_mac_vdev_setup_sync(ar);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to synchronize setup for vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               goto err;
+       }
+
+       WARN_ON(ar->num_started_vdevs == 0);
+
+       ar->num_started_vdevs--;
+
+       if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) {
+               clear_bit(ATH11K_CAC_RUNNING, &ar->dev_flags);
+               ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "CAC Stopped for vdev %d\n",
+                          arvif->vdev_id);
+       }
+
+       return 0;
+err:
+       spin_lock_bh(&ar->data_lock);
+       ar->vdev_stop_status.stop_in_progress = false;
+       spin_unlock_bh(&ar->data_lock);
+
+       return ret;
+}
+
+static int ath11k_mac_vdev_start(struct ath11k_vif *arvif,
+                                const struct cfg80211_chan_def *chandef)
+{
+       return ath11k_mac_vdev_start_restart(arvif, chandef, false);
+}
+
+static int ath11k_mac_vdev_restart(struct ath11k_vif *arvif,
+                                  const struct cfg80211_chan_def *chandef)
+{
+       return ath11k_mac_vdev_start_restart(arvif, chandef, true);
+}
+
+struct ath11k_mac_change_chanctx_arg {
+       struct ieee80211_chanctx_conf *ctx;
+       struct ieee80211_vif_chanctx_switch *vifs;
+       int n_vifs;
+       int next_vif;
+};
+
+static void
+ath11k_mac_change_chanctx_cnt_iter(void *data, u8 *mac,
+                                  struct ieee80211_vif *vif)
+{
+       struct ath11k_mac_change_chanctx_arg *arg = data;
+
+       if (rcu_access_pointer(vif->chanctx_conf) != arg->ctx)
+               return;
+
+       arg->n_vifs++;
+}
+
+static void
+ath11k_mac_change_chanctx_fill_iter(void *data, u8 *mac,
+                                   struct ieee80211_vif *vif)
+{
+       struct ath11k_mac_change_chanctx_arg *arg = data;
+       struct ieee80211_chanctx_conf *ctx;
+
+       ctx = rcu_access_pointer(vif->chanctx_conf);
+       if (ctx != arg->ctx)
+               return;
+
+       if (WARN_ON(arg->next_vif == arg->n_vifs))
+               return;
+
+       arg->vifs[arg->next_vif].vif = vif;
+       arg->vifs[arg->next_vif].old_ctx = ctx;
+       arg->vifs[arg->next_vif].new_ctx = ctx;
+       arg->next_vif++;
+}
+
+static void
+ath11k_mac_update_vif_chan(struct ath11k *ar,
+                          struct ieee80211_vif_chanctx_switch *vifs,
+                          int n_vifs)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_vif *arvif;
+       int ret;
+       int i;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       for (i = 0; i < n_vifs; i++) {
+               arvif = (void *)vifs[i].vif->drv_priv;
+
+               ath11k_dbg(ab, ATH11K_DBG_MAC,
+                          "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
+                          arvif->vdev_id,
+                          vifs[i].old_ctx->def.chan->center_freq,
+                          vifs[i].new_ctx->def.chan->center_freq,
+                          vifs[i].old_ctx->def.width,
+                          vifs[i].new_ctx->def.width);
+
+               if (WARN_ON(!arvif->is_started))
+                       continue;
+
+               if (WARN_ON(!arvif->is_up))
+                       continue;
+
+               ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id);
+               if (ret) {
+                       ath11k_warn(ab, "failed to down vdev %d: %d\n",
+                                   arvif->vdev_id, ret);
+                       continue;
+               }
+       }
+
+       /* All relevant vdevs are downed and associated channel resources
+        * should be available for the channel switch now.
+        */
+
+       /* TODO: Update ar->rx_channel */
+
+       for (i = 0; i < n_vifs; i++) {
+               arvif = (void *)vifs[i].vif->drv_priv;
+
+               if (WARN_ON(!arvif->is_started))
+                       continue;
+
+               if (WARN_ON(!arvif->is_up))
+                       continue;
+
+               ret = ath11k_mac_setup_bcn_tmpl(arvif);
+               if (ret)
+                       ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n",
+                                   ret);
+
+               ret = ath11k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def);
+               if (ret) {
+                       ath11k_warn(ab, "failed to restart vdev %d: %d\n",
+                                   arvif->vdev_id, ret);
+                       continue;
+               }
+
+               ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
+                                        arvif->bssid);
+               if (ret) {
+                       ath11k_warn(ab, "failed to bring vdev up %d: %d\n",
+                                   arvif->vdev_id, ret);
+                       continue;
+               }
+       }
+}
+
+static void
+ath11k_mac_update_active_vif_chan(struct ath11k *ar,
+                                 struct ieee80211_chanctx_conf *ctx)
+{
+       struct ath11k_mac_change_chanctx_arg arg = { .ctx = ctx };
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ieee80211_iterate_active_interfaces_atomic(ar->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
+                                                  ath11k_mac_change_chanctx_cnt_iter,
+                                                  &arg);
+       if (arg.n_vifs == 0)
+               return;
+
+       arg.vifs = kcalloc(arg.n_vifs, sizeof(arg.vifs[0]), GFP_KERNEL);
+       if (!arg.vifs)
+               return;
+
+       ieee80211_iterate_active_interfaces_atomic(ar->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
+                                                  ath11k_mac_change_chanctx_fill_iter,
+                                                  &arg);
+
+       ath11k_mac_update_vif_chan(ar, arg.vifs, arg.n_vifs);
+
+       kfree(arg.vifs);
+}
+
+static void ath11k_mac_op_change_chanctx(struct ieee80211_hw *hw,
+                                        struct ieee80211_chanctx_conf *ctx,
+                                        u32 changed)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_base *ab = ar->ab;
+
+       mutex_lock(&ar->conf_mutex);
+
+       ath11k_dbg(ab, ATH11K_DBG_MAC,
+                  "mac chanctx change freq %hu width %d ptr %pK changed %x\n",
+                  ctx->def.chan->center_freq, ctx->def.width, ctx, changed);
+
+       /* This shouldn't really happen because channel switching should use
+        * switch_vif_chanctx().
+        */
+       if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL))
+               goto unlock;
+
+       if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH)
+               ath11k_mac_update_active_vif_chan(ar, ctx);
+
+       /* TODO: Recalc radar detection */
+
+unlock:
+       mutex_unlock(&ar->conf_mutex);
+}
+
+static int
+ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_chanctx_conf *ctx)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       int ret;
+
+       mutex_lock(&ar->conf_mutex);
+
+       ath11k_dbg(ab, ATH11K_DBG_MAC,
+                  "mac chanctx assign ptr %pK vdev_id %i\n",
+                  ctx, arvif->vdev_id);
+
+       if (WARN_ON(arvif->is_started)) {
+               mutex_unlock(&ar->conf_mutex);
+               return -EBUSY;
+       }
+
+       ret = ath11k_mac_vdev_start(arvif, &ctx->def);
+       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 err;
+       }
+       if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
+               ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id);
+               if (ret)
+                       goto err;
+       }
+
+       arvif->is_started = true;
+
+       /* TODO: Setup ps and cts/rts protection */
+
+       mutex_unlock(&ar->conf_mutex);
+
+       return 0;
+
+err:
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static void
+ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_chanctx_conf *ctx)
+{
+       struct ath11k *ar = hw->priv;
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       int ret;
+
+       mutex_lock(&ar->conf_mutex);
+
+       ath11k_dbg(ab, ATH11K_DBG_MAC,
+                  "mac chanctx unassign ptr %pK vdev_id %i\n",
+                  ctx, arvif->vdev_id);
+
+       WARN_ON(!arvif->is_started);
+
+       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;
+
+       mutex_unlock(&ar->conf_mutex);
+}
+
+static int
+ath11k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
+                                struct ieee80211_vif_chanctx_switch *vifs,
+                                int n_vifs,
+                                enum ieee80211_chanctx_switch_mode mode)
+{
+       struct ath11k *ar = hw->priv;
+
+       mutex_lock(&ar->conf_mutex);
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                  "mac chanctx switch n_vifs %d mode %d\n",
+                  n_vifs, mode);
+       ath11k_mac_update_vif_chan(ar, vifs, n_vifs);
+
+       mutex_unlock(&ar->conf_mutex);
+
+       return 0;
+}
+
+static int
+ath11k_set_vdev_param_to_all_vifs(struct ath11k *ar, int param, u32 value)
+{
+       struct ath11k_vif *arvif;
+       int ret = 0;
+
+       mutex_lock(&ar->conf_mutex);
+       list_for_each_entry(arvif, &ar->arvifs, list) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "setting mac vdev %d param %d value %d\n",
+                          param, arvif->vdev_id, value);
+
+               ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                                   param, value);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to set param %d for vdev %d: %d\n",
+                                   param, arvif->vdev_id, ret);
+                       break;
+               }
+       }
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+/* mac80211 stores device specific RTS/Fragmentation threshold value,
+ * this is set interface specific to firmware from ath11k driver
+ */
+static int ath11k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+       struct ath11k *ar = hw->priv;
+       int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
+
+       return ath11k_set_vdev_param_to_all_vifs(ar, param_id, value);
+}
+
+static int ath11k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
+{
+       /* Even though there's a WMI vdev param for fragmentation threshold no
+        * known firmware actually implements it. Moreover it is not possible to
+        * rely frame fragmentation to mac80211 because firmware clears the
+        * "more fragments" bit in frame control making it impossible for remote
+        * devices to reassemble frames.
+        *
+        * Hence implement a dummy callback just to say fragmentation isn't
+        * supported. This effectively prevents mac80211 from doing frame
+        * fragmentation in software.
+        */
+       return -EOPNOTSUPP;
+}
+
+static void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                               u32 queues, bool drop)
+{
+       struct ath11k *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),
+                                      ATH11K_FLUSH_TIMEOUT);
+       if (time_left == 0)
+               ath11k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left);
+}
+
+static int
+ath11k_mac_bitrate_mask_num_ht_rates(struct ath11k *ar,
+                                    enum nl80211_band band,
+                                    const struct cfg80211_bitrate_mask *mask)
+{
+       int num_rates = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
+               num_rates += hweight16(mask->control[band].ht_mcs[i]);
+
+       return num_rates;
+}
+
+static bool
+ath11k_mac_has_single_legacy_rate(struct ath11k *ar,
+                                 enum nl80211_band band,
+                                 const struct cfg80211_bitrate_mask *mask)
+{
+       int num_rates = 0;
+
+       num_rates = hweight32(mask->control[band].legacy);
+
+       if (ath11k_mac_bitrate_mask_num_ht_rates(ar, band, mask))
+               return false;
+
+       if (ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask))
+               return false;
+
+       return num_rates == 1;
+}
+
+static bool
+ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar,
+                                      enum nl80211_band band,
+                                      const struct cfg80211_bitrate_mask *mask,
+                                      int *nss)
+{
+       struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
+       u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+       u8 ht_nss_mask = 0;
+       u8 vht_nss_mask = 0;
+       int i;
+
+       /* No need to consider legacy here. Basic rates are always present
+        * in bitrate mask
+        */
+
+       for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
+               if (mask->control[band].ht_mcs[i] == 0)
+                       continue;
+               else if (mask->control[band].ht_mcs[i] ==
+                        sband->ht_cap.mcs.rx_mask[i])
+                       ht_nss_mask |= BIT(i);
+               else
+                       return false;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
+               if (mask->control[band].vht_mcs[i] == 0)
+                       continue;
+               else if (mask->control[band].vht_mcs[i] ==
+                        ath11k_mac_get_max_vht_mcs_map(vht_mcs_map, i))
+                       vht_nss_mask |= BIT(i);
+               else
+                       return false;
+       }
+
+       if (ht_nss_mask != vht_nss_mask)
+               return false;
+
+       if (ht_nss_mask == 0)
+               return false;
+
+       if (BIT(fls(ht_nss_mask)) - 1 != ht_nss_mask)
+               return false;
+
+       *nss = fls(ht_nss_mask);
+
+       return true;
+}
+
+static int
+ath11k_mac_get_single_legacy_rate(struct ath11k *ar,
+                                 enum nl80211_band band,
+                                 const struct cfg80211_bitrate_mask *mask,
+                                 u32 *rate, u8 *nss)
+{
+       int rate_idx;
+       u16 bitrate;
+       u8 preamble;
+       u8 hw_rate;
+
+       if (hweight32(mask->control[band].legacy) != 1)
+               return -EINVAL;
+
+       rate_idx = ffs(mask->control[band].legacy) - 1;
+
+       if (band == NL80211_BAND_5GHZ)
+               rate_idx += ATH11K_MAC_FIRST_OFDM_RATE_IDX;
+
+       hw_rate = ath11k_legacy_rates[rate_idx].hw_value;
+       bitrate = ath11k_legacy_rates[rate_idx].bitrate;
+
+       if (ath11k_mac_bitrate_is_cck(bitrate))
+               preamble = WMI_RATE_PREAMBLE_CCK;
+       else
+               preamble = WMI_RATE_PREAMBLE_OFDM;
+
+       *nss = 1;
+       *rate = ATH11K_HW_RATE_CODE(hw_rate, 0, preamble);
+
+       return 0;
+}
+
+static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif,
+                                           u32 rate, u8 nss, u8 sgi, u8 ldpc)
+{
+       struct ath11k *ar = arvif->ar;
+       u32 vdev_param;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02hhx nss %hhu sgi %hhu\n",
+                  arvif->vdev_id, rate, nss, sgi);
+
+       vdev_param = WMI_VDEV_PARAM_FIXED_RATE;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                           vdev_param, rate);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n",
+                           rate, ret);
+               return ret;
+       }
+
+       vdev_param = WMI_VDEV_PARAM_NSS;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                           vdev_param, nss);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set nss param %d: %d\n",
+                           nss, ret);
+               return ret;
+       }
+
+       vdev_param = WMI_VDEV_PARAM_SGI;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                           vdev_param, sgi);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set sgi param %d: %d\n",
+                           sgi, ret);
+               return ret;
+       }
+
+       vdev_param = WMI_VDEV_PARAM_LDPC;
+       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+                                           vdev_param, ldpc);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set ldpc param %d: %d\n",
+                           ldpc, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static bool
+ath11k_mac_vht_mcs_range_present(struct ath11k *ar,
+                                enum nl80211_band band,
+                                const struct cfg80211_bitrate_mask *mask)
+{
+       int i;
+       u16 vht_mcs;
+
+       for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
+               vht_mcs = mask->control[band].vht_mcs[i];
+
+               switch (vht_mcs) {
+               case 0:
+               case BIT(8) - 1:
+               case BIT(9) - 1:
+               case BIT(10) - 1:
+                       break;
+               default:
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+static void ath11k_mac_set_bitrate_mask_iter(void *data,
+                                            struct ieee80211_sta *sta)
+{
+       struct ath11k_vif *arvif = data;
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+       struct ath11k *ar = arvif->ar;
+
+       spin_lock_bh(&ar->data_lock);
+       arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
+       spin_unlock_bh(&ar->data_lock);
+
+       ieee80211_queue_work(ar->hw, &arsta->update_wk);
+}
+
+static void ath11k_mac_disable_peer_fixed_rate(void *data,
+                                              struct ieee80211_sta *sta)
+{
+       struct ath11k_vif *arvif = data;
+       struct ath11k *ar = arvif->ar;
+       int ret;
+
+       ret = ath11k_wmi_set_peer_param(ar, sta->addr,
+                                       arvif->vdev_id,
+                                       WMI_PEER_PARAM_FIXED_RATE,
+                                       WMI_FIXED_RATE_NONE);
+       if (ret)
+               ath11k_warn(ar->ab,
+                           "failed to disable peer fixed rate for STA %pM ret %d\n",
+                           sta->addr, ret);
+}
+
+static int
+ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              const struct cfg80211_bitrate_mask *mask)
+{
+       struct ath11k_vif *arvif = (void *)vif->drv_priv;
+       struct cfg80211_chan_def def;
+       struct ath11k *ar = arvif->ar;
+       enum nl80211_band band;
+       const u8 *ht_mcs_mask;
+       const u16 *vht_mcs_mask;
+       u32 rate;
+       u8 nss;
+       u8 sgi;
+       u8 ldpc;
+       int single_nss;
+       int ret;
+       int num_rates;
+
+       if (ath11k_mac_vif_chan(vif, &def))
+               return -EPERM;
+
+       band = def.chan->band;
+       ht_mcs_mask = mask->control[band].ht_mcs;
+       vht_mcs_mask = mask->control[band].vht_mcs;
+       ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC);
+
+       sgi = mask->control[band].gi;
+       if (sgi == NL80211_TXRATE_FORCE_LGI)
+               return -EINVAL;
+
+       /* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it
+        * requires passing atleast one of used basic rates along with them.
+        * Fixed rate setting across different preambles(legacy, HT, VHT) is
+        * not supported by the FW. Hence use of FIXED_RATE vdev param is not
+        * suitable for setting single HT/VHT rates.
+        * But, there could be a single basic rate passed from userspace which
+        * can be done through the FIXED_RATE param.
+        */
+       if (ath11k_mac_has_single_legacy_rate(ar, band, mask)) {
+               ret = ath11k_mac_get_single_legacy_rate(ar, band, mask, &rate,
+                                                       &nss);
+               if (ret) {
+                       ath11k_warn(ar->ab, "failed to get single legacy rate for vdev %i: %d\n",
+                                   arvif->vdev_id, ret);
+                       return ret;
+               }
+               ieee80211_iterate_stations_atomic(ar->hw,
+                                                 ath11k_mac_disable_peer_fixed_rate,
+                                                 arvif);
+       } else if (ath11k_mac_bitrate_mask_get_single_nss(ar, band, mask,
+                                                         &single_nss)) {
+               rate = WMI_FIXED_RATE_NONE;
+               nss = single_nss;
+       } else {
+               rate = WMI_FIXED_RATE_NONE;
+               nss = min_t(u32, ar->num_tx_chains,
+                           max(ath11k_mac_max_ht_nss(ht_mcs_mask),
+                               ath11k_mac_max_vht_nss(vht_mcs_mask)));
+
+               /* If multiple rates across different preambles are given
+                * we can reconfigure this info with all peers using PEER_ASSOC
+                * command with the below exception cases.
+                * - Single VHT Rate : peer_assoc command accommodates only MCS
+                * range values i.e 0-7, 0-8, 0-9 for VHT. Though mac80211
+                * mandates passing basic rates along with HT/VHT rates, FW
+                * doesn't allow switching from VHT to Legacy. Hence instead of
+                * setting legacy and VHT rates using RATEMASK_CMD vdev cmd,
+                * we could set this VHT rate as peer fixed rate param, which
+                * will override FIXED rate and FW rate control algorithm.
+                * If single VHT rate is passed along with HT rates, we select
+                * the VHT rate as fixed rate for vht peers.
+                * - Multiple VHT Rates : When Multiple VHT rates are given,this
+                * can be set using RATEMASK CMD which uses FW rate-ctl alg.
+                * TODO: Setting multiple VHT MCS and replacing peer_assoc with
+                * RATEMASK_CMDID can cover all use cases of setting rates
+                * across multiple preambles and rates within same type.
+                * But requires more validation of the command at this point.
+                */
+
+               num_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band,
+                                                                 mask);
+
+               if (!ath11k_mac_vht_mcs_range_present(ar, band, mask) &&
+                   num_rates > 1) {
+                       /* TODO: Handle multiple VHT MCS values setting using
+                        * RATEMASK CMD
+                        */
+                       ath11k_warn(ar->ab,
+                                   "Setting more than one MCS Value in bitrate mask not supported\n");
+                       return -EINVAL;
+               }
+
+               ieee80211_iterate_stations_atomic(ar->hw,
+                                                 ath11k_mac_disable_peer_fixed_rate,
+                                                 arvif);
+
+               mutex_lock(&ar->conf_mutex);
+
+               arvif->bitrate_mask = *mask;
+               ieee80211_iterate_stations_atomic(ar->hw,
+                                                 ath11k_mac_set_bitrate_mask_iter,
+                                                 arvif);
+
+               mutex_unlock(&ar->conf_mutex);
+       }
+
+       mutex_lock(&ar->conf_mutex);
+
+       ret = ath11k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+       }
+
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static void
+ath11k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
+                               enum ieee80211_reconfig_type reconfig_type)
+{
+       struct ath11k *ar = hw->priv;
+
+       if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
+               return;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state == ATH11K_STATE_RESTARTED) {
+               ath11k_warn(ar->ab, "pdev %d successfully recovered\n",
+                           ar->pdev->pdev_id);
+               ar->state = ATH11K_STATE_ON;
+               ieee80211_wake_queues(ar->hw);
+       }
+
+       mutex_unlock(&ar->conf_mutex);
+}
+
+static void
+ath11k_mac_update_bss_chan_survey(struct ath11k *ar,
+                                 struct ieee80211_channel *channel)
+{
+       int ret;
+       enum wmi_bss_chan_info_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (!test_bit(WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64, ar->ab->wmi_sc.svc_map) ||
+           ar->rx_channel != channel)
+               return;
+
+       if (ar->scan.state != ATH11K_SCAN_IDLE) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                          "ignoring bss chan info req while scanning..\n");
+               return;
+       }
+
+       reinit_completion(&ar->bss_survey_done);
+
+       ret = ath11k_wmi_pdev_bss_chan_info_request(ar, type);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send pdev bss chan info request\n");
+               return;
+       }
+
+       ret = wait_for_completion_timeout(&ar->bss_survey_done, 3 * HZ);
+       if (ret == 0)
+               ath11k_warn(ar->ab, "bss channel survey timed out\n");
+}
+
+static int ath11k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
+                                   struct survey_info *survey)
+{
+       struct ath11k *ar = hw->priv;
+       struct ieee80211_supported_band *sband;
+       struct survey_info *ar_survey;
+       int ret = 0;
+
+       if (idx >= ATH11K_NUM_CHANS)
+               return -ENOENT;
+
+       ar_survey = &ar->survey[idx];
+
+       mutex_lock(&ar->conf_mutex);
+
+       sband = hw->wiphy->bands[NL80211_BAND_2GHZ];
+       if (sband && idx >= sband->n_channels) {
+               idx -= sband->n_channels;
+               sband = NULL;
+       }
+
+       if (!sband)
+               sband = hw->wiphy->bands[NL80211_BAND_5GHZ];
+
+       if (!sband || idx >= sband->n_channels) {
+               ret = -ENOENT;
+               goto exit;
+       }
+
+       ath11k_mac_update_bss_chan_survey(ar, &sband->channels[idx]);
+
+       spin_lock_bh(&ar->data_lock);
+       memcpy(survey, ar_survey, sizeof(*survey));
+       spin_unlock_bh(&ar->data_lock);
+
+       survey->channel = &sband->channels[idx];
+
+       if (ar->rx_channel == survey->channel)
+               survey->filled |= SURVEY_INFO_IN_USE;
+
+exit:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw,
+                                        struct ieee80211_vif *vif,
+                                        struct ieee80211_sta *sta,
+                                        struct station_info *sinfo)
+{
+       struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
+
+       sinfo->rx_duration = arsta->rx_duration;
+       sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
+
+       if (!arsta->txrate.legacy && !arsta->txrate.nss)
+               return;
+
+       if (arsta->txrate.legacy) {
+               sinfo->txrate.legacy = arsta->txrate.legacy;
+       } else {
+               sinfo->txrate.mcs = arsta->txrate.mcs;
+               sinfo->txrate.nss = arsta->txrate.nss;
+               sinfo->txrate.bw = arsta->txrate.bw;
+               sinfo->txrate.he_gi = arsta->txrate.he_gi;
+               sinfo->txrate.he_dcm = arsta->txrate.he_dcm;
+               sinfo->txrate.he_ru_alloc = arsta->txrate.he_ru_alloc;
+       }
+       sinfo->txrate.flags = arsta->txrate.flags;
+       sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
+
+       /* TODO: Use real NF instead of default one. */
+       sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR;
+}
+
+static const struct ieee80211_ops ath11k_ops = {
+       .tx                             = ath11k_mac_op_tx,
+       .start                          = ath11k_mac_op_start,
+       .stop                           = ath11k_mac_op_stop,
+       .reconfig_complete              = ath11k_mac_op_reconfig_complete,
+       .add_interface                  = ath11k_mac_op_add_interface,
+       .remove_interface               = ath11k_mac_op_remove_interface,
+       .config                         = ath11k_mac_op_config,
+       .bss_info_changed               = ath11k_mac_op_bss_info_changed,
+       .configure_filter               = ath11k_mac_op_configure_filter,
+       .hw_scan                        = ath11k_mac_op_hw_scan,
+       .cancel_hw_scan                 = ath11k_mac_op_cancel_hw_scan,
+       .set_key                        = ath11k_mac_op_set_key,
+       .sta_state                      = ath11k_mac_op_sta_state,
+       .sta_rc_update                  = ath11k_mac_op_sta_rc_update,
+       .conf_tx                        = ath11k_mac_op_conf_tx,
+       .set_antenna                    = ath11k_mac_op_set_antenna,
+       .get_antenna                    = ath11k_mac_op_get_antenna,
+       .ampdu_action                   = ath11k_mac_op_ampdu_action,
+       .add_chanctx                    = ath11k_mac_op_add_chanctx,
+       .remove_chanctx                 = ath11k_mac_op_remove_chanctx,
+       .change_chanctx                 = ath11k_mac_op_change_chanctx,
+       .assign_vif_chanctx             = ath11k_mac_op_assign_vif_chanctx,
+       .unassign_vif_chanctx           = ath11k_mac_op_unassign_vif_chanctx,
+       .switch_vif_chanctx             = ath11k_mac_op_switch_vif_chanctx,
+       .set_rts_threshold              = ath11k_mac_op_set_rts_threshold,
+       .set_frag_threshold             = ath11k_mac_op_set_frag_threshold,
+       .set_bitrate_mask               = ath11k_mac_op_set_bitrate_mask,
+       .get_survey                     = ath11k_mac_op_get_survey,
+       .flush                          = ath11k_mac_op_flush,
+       .sta_statistics                 = ath11k_mac_op_sta_statistics,
+       CFG80211_TESTMODE_CMD(ath11k_tm_cmd)
+#ifdef CONFIG_MAC80211_DEBUGFS
+       .sta_add_debugfs                = ath11k_sta_add_debugfs,
+#endif
+};
+
+static const struct ieee80211_iface_limit ath11k_if_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max    = 16,
+               .types  = BIT(NL80211_IFTYPE_AP)
+#ifdef CONFIG_MAC80211_MESH
+                       | BIT(NL80211_IFTYPE_MESH_POINT)
+#endif
+       },
+};
+
+static const struct ieee80211_iface_combination ath11k_if_comb[] = {
+       {
+               .limits = ath11k_if_limits,
+               .n_limits = ARRAY_SIZE(ath11k_if_limits),
+               .max_interfaces = 16,
+               .num_different_channels = 1,
+               .beacon_int_infra_match = true,
+               .beacon_int_min_gcd = 100,
+               .radar_detect_widths =  BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+                                       BIT(NL80211_CHAN_WIDTH_20) |
+                                       BIT(NL80211_CHAN_WIDTH_40) |
+                                       BIT(NL80211_CHAN_WIDTH_80),
+       },
+};
+
+static void ath11k_mac_update_ch_list(struct ath11k *ar,
+                                     struct ieee80211_supported_band *band,
+                                     u32 freq_low, u32 freq_high)
+{
+       int i;
+
+       if (!(freq_low && freq_high))
+               return;
+
+       for (i = 0; i < band->n_channels; i++) {
+               if (band->channels[i].center_freq < freq_low ||
+                   band->channels[i].center_freq > freq_high)
+                       band->channels[i].flags |= IEEE80211_CHAN_DISABLED;
+       }
+}
+
+static int ath11k_mac_setup_channels_rates(struct ath11k *ar,
+                                          u32 supported_bands)
+{
+       struct ieee80211_supported_band *band;
+       struct ath11k_hal_reg_capabilities_ext *reg_cap;
+       void *channels;
+
+       BUILD_BUG_ON((ARRAY_SIZE(ath11k_2ghz_channels) +
+                     ARRAY_SIZE(ath11k_5ghz_channels)) !=
+                    ATH11K_NUM_CHANS);
+
+       reg_cap = &ar->ab->hal_reg_cap[ar->pdev_idx];
+
+       if (supported_bands & WMI_HOST_WLAN_2G_CAP) {
+               channels = kmemdup(ath11k_2ghz_channels,
+                                  sizeof(ath11k_2ghz_channels),
+                                  GFP_KERNEL);
+               if (!channels)
+                       return -ENOMEM;
+
+               band = &ar->mac.sbands[NL80211_BAND_2GHZ];
+               band->n_channels = ARRAY_SIZE(ath11k_2ghz_channels);
+               band->channels = channels;
+               band->n_bitrates = ath11k_g_rates_size;
+               band->bitrates = ath11k_g_rates;
+               ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band;
+               ath11k_mac_update_ch_list(ar, band,
+                                         reg_cap->low_2ghz_chan,
+                                         reg_cap->high_2ghz_chan);
+       }
+
+       if (supported_bands & WMI_HOST_WLAN_5G_CAP) {
+               channels = kmemdup(ath11k_5ghz_channels,
+                                  sizeof(ath11k_5ghz_channels),
+                                  GFP_KERNEL);
+               if (!channels) {
+                       kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
+                       return -ENOMEM;
+               }
+
+               band = &ar->mac.sbands[NL80211_BAND_5GHZ];
+               band->n_channels = ARRAY_SIZE(ath11k_5ghz_channels);
+               band->channels = channels;
+               band->n_bitrates = ath11k_a_rates_size;
+               band->bitrates = ath11k_a_rates;
+               ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band;
+               ath11k_mac_update_ch_list(ar, band,
+                                         reg_cap->low_5ghz_chan,
+                                         reg_cap->high_5ghz_chan);
+       }
+
+       return 0;
+}
+
+static const u8 ath11k_if_types_ext_capa[] = {
+       [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+       [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
+};
+
+static const u8 ath11k_if_types_ext_capa_sta[] = {
+       [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+       [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
+       [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT,
+};
+
+static const u8 ath11k_if_types_ext_capa_ap[] = {
+       [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+       [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
+       [9] = WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT,
+};
+
+static const struct wiphy_iftype_ext_capab ath11k_iftypes_ext_capa[] = {
+       {
+               .extended_capabilities = ath11k_if_types_ext_capa,
+               .extended_capabilities_mask = ath11k_if_types_ext_capa,
+               .extended_capabilities_len = sizeof(ath11k_if_types_ext_capa),
+       }, {
+               .iftype = NL80211_IFTYPE_STATION,
+               .extended_capabilities = ath11k_if_types_ext_capa_sta,
+               .extended_capabilities_mask = ath11k_if_types_ext_capa_sta,
+               .extended_capabilities_len =
+                               sizeof(ath11k_if_types_ext_capa_sta),
+       }, {
+               .iftype = NL80211_IFTYPE_AP,
+               .extended_capabilities = ath11k_if_types_ext_capa_ap,
+               .extended_capabilities_mask = ath11k_if_types_ext_capa_ap,
+               .extended_capabilities_len =
+                               sizeof(ath11k_if_types_ext_capa_ap),
+       },
+};
+
+static int ath11k_mac_register(struct ath11k *ar)
+{
+       struct ath11k_base *ab = ar->ab;
+       struct ath11k_pdev_cap *cap = &ar->pdev->cap;
+       static const u32 cipher_suites[] = {
+               WLAN_CIPHER_SUITE_TKIP,
+               WLAN_CIPHER_SUITE_CCMP,
+               WLAN_CIPHER_SUITE_AES_CMAC,
+               WLAN_CIPHER_SUITE_BIP_CMAC_256,
+               WLAN_CIPHER_SUITE_BIP_GMAC_128,
+               WLAN_CIPHER_SUITE_BIP_GMAC_256,
+               WLAN_CIPHER_SUITE_GCMP,
+               WLAN_CIPHER_SUITE_GCMP_256,
+               WLAN_CIPHER_SUITE_CCMP_256,
+       };
+       int ret;
+       u32 ht_cap = 0;
+
+       ath11k_pdev_caps_update(ar);
+
+       SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr);
+
+       SET_IEEE80211_DEV(ar->hw, ab->dev);
+
+       ret = ath11k_mac_setup_channels_rates(ar,
+                                             cap->supported_bands);
+       if (ret)
+               goto err_free;
+
+       ath11k_mac_setup_ht_vht_cap(ar, cap, &ht_cap);
+
+       ar->hw->wiphy->available_antennas_rx = cap->rx_chain_mask;
+       ar->hw->wiphy->available_antennas_tx = cap->tx_chain_mask;
+
+       ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                        BIT(NL80211_IFTYPE_AP) |
+                                        BIT(NL80211_IFTYPE_MESH_POINT);
+
+       ieee80211_hw_set(ar->hw, SIGNAL_DBM);
+       ieee80211_hw_set(ar->hw, SUPPORTS_PS);
+       ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS);
+       ieee80211_hw_set(ar->hw, MFP_CAPABLE);
+       ieee80211_hw_set(ar->hw, REPORTS_TX_ACK_STATUS);
+       ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL);
+       ieee80211_hw_set(ar->hw, AP_LINK_PS);
+       ieee80211_hw_set(ar->hw, SPECTRUM_MGMT);
+       ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT);
+       ieee80211_hw_set(ar->hw, CONNECTION_MONITOR);
+       ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK);
+       ieee80211_hw_set(ar->hw, WANT_MONITOR_VIF);
+       ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA);
+       ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
+       ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
+       ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
+       if (ht_cap & WMI_HT_CAP_ENABLED) {
+               ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
+               ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);
+               ieee80211_hw_set(ar->hw, SUPPORTS_REORDERING_BUFFER);
+               ieee80211_hw_set(ar->hw, SUPPORTS_AMSDU_IN_AMPDU);
+       }
+
+       ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
+       ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
+       /* TODO: Check if HT capability advertised from firmware is different
+        * for each band for a dual band capable radio. It will be tricky to
+        * handle it when the ht capability different for each band.
+        */
+       if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS)
+               ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
+
+       ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID;
+       ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
+
+       ar->hw->max_listen_interval = ATH11K_MAX_HW_LISTEN_INTERVAL;
+
+       ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+       ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+       ar->hw->wiphy->max_remain_on_channel_duration = 5000;
+
+       ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
+       ar->hw->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;
+
+       ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations;
+
+       ar->hw->queues = ATH11K_HW_MAX_QUEUES;
+       ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1;
+       ar->hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
+
+       ar->hw->vif_data_size = sizeof(struct ath11k_vif);
+       ar->hw->sta_data_size = sizeof(struct ath11k_sta);
+
+       ar->hw->wiphy->iface_combinations = ath11k_if_comb;
+       ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath11k_if_comb);
+
+       wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+
+       ar->hw->wiphy->cipher_suites = cipher_suites;
+       ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+       ar->hw->wiphy->iftype_ext_capab = ath11k_iftypes_ext_capa;
+       ar->hw->wiphy->num_iftype_ext_capab =
+               ARRAY_SIZE(ath11k_iftypes_ext_capa);
+
+       ath11k_reg_init(ar);
+
+       /* advertise HW checksum offload capabilities */
+       ar->hw->netdev_features = NETIF_F_HW_CSUM;
+
+       ret = ieee80211_register_hw(ar->hw);
+       if (ret) {
+               ath11k_err(ar->ab, "ieee80211 registration failed: %d\n", ret);
+               goto err_free;
+       }
+
+       /* Apply the regd received during initialization */
+       ret = ath11k_regd_update(ar, true);
+       if (ret) {
+               ath11k_err(ar->ab, "ath11k regd update failed: %d\n", ret);
+               goto err_free;
+       }
+
+       ret = ath11k_debug_register(ar);
+       if (ret) {
+               ath11k_err(ar->ab, "debugfs registration failed: %d\n", ret);
+               goto err_free;
+       }
+
+       return 0;
+
+err_free:
+       kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
+       kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels);
+
+       SET_IEEE80211_DEV(ar->hw, NULL);
+       return ret;
+}
+
+void ath11k_mac_unregister(struct ath11k_base *ab)
+{
+       struct ath11k *ar;
+       struct ath11k_pdev *pdev;
+       int i;
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = &ab->pdevs[i];
+               ar = pdev->ar;
+               if (!ar)
+                       continue;
+               cancel_work_sync(&ar->regd_update_work);
+
+               ieee80211_unregister_hw(ar->hw);
+
+               idr_for_each(&ar->txmgmt_idr, ath11k_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);
+
+               SET_IEEE80211_DEV(ar->hw, NULL);
+       }
+}
+
+int ath11k_mac_create(struct ath11k_base *ab)
+{
+       struct ieee80211_hw *hw;
+       struct ath11k *ar;
+       struct ath11k_pdev *pdev;
+       int ret;
+       int i;
+
+       if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
+               return 0;
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = &ab->pdevs[i];
+               hw = ieee80211_alloc_hw(sizeof(struct ath11k), &ath11k_ops);
+               if (!hw) {
+                       ath11k_warn(ab, "failed to allocate mac80211 hw device\n");
+                       ret = -ENOMEM;
+                       goto err_destroy_mac;
+               }
+
+               ar = hw->priv;
+               ar->hw = hw;
+               ar->ab = ab;
+               ar->pdev = pdev;
+               ar->pdev_idx = i;
+               ar->lmac_id = ath11k_core_get_hw_mac_id(ab, i);
+
+               ar->wmi = &ab->wmi_sc.wmi[i];
+               /* FIXME wmi[0] is already initialized during attach,
+                * Should we do this again?
+                */
+               ath11k_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 = get_num_chains(pdev->cap.tx_chain_mask);
+               ar->num_rx_chains = get_num_chains(pdev->cap.rx_chain_mask);
+
+               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;
+               }
+
+               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->peer_assoc_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, ath11k_scan_timeout_work);
+               INIT_WORK(&ar->regd_update_work, ath11k_regd_update_work);
+
+               INIT_WORK(&ar->wmi_mgmt_tx_work, ath11k_mgmt_over_wmi_tx_work);
+               skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
+               clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
+
+               ret = ath11k_mac_register(ar);
+               if (ret) {
+                       ath11k_warn(ab, "failed to register hw device\n");
+                       pdev->ar = NULL;
+                       ieee80211_free_hw(hw);
+                       goto err_destroy_mac;
+               }
+
+               idr_init(&ar->txmgmt_idr);
+               spin_lock_init(&ar->txmgmt_idr_lock);
+       }
+
+       /* Initialize channel counters frequency value in hertz */
+       ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ;
+       ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
+
+       return 0;
+
+err_destroy_mac:
+       ath11k_mac_destroy(ab);
+
+       return ret;
+}
+
+void ath11k_mac_destroy(struct ath11k_base *ab)
+{
+       struct ath11k *ar;
+       struct ath11k_pdev *pdev;
+       int i;
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = &ab->pdevs[i];
+               ar = pdev->ar;
+               if (!ar)
+                       continue;
+
+               ieee80211_free_hw(ar->hw);
+               pdev->ar = NULL;
+       }
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_MAC_H
+#define ATH11K_MAC_H
+
+#include <net/mac80211.h>
+#include <net/cfg80211.h>
+
+struct ath11k;
+struct ath11k_base;
+
+struct ath11k_generic_iter {
+       struct ath11k *ar;
+       int ret;
+};
+
+/* number of failed packets (20 packets with 16 sw reties each) */
+#define ATH11K_KICKOUT_THRESHOLD               (20 * 16)
+
+/* Use insanely high numbers to make sure that the firmware implementation
+ * won't start, we have the same functionality already in hostapd. Unit
+ * is seconds.
+ */
+#define ATH11K_KEEPALIVE_MIN_IDLE              3747
+#define ATH11K_KEEPALIVE_MAX_IDLE              3895
+#define ATH11K_KEEPALIVE_MAX_UNRESPONSIVE      3900
+
+#define WMI_HOST_RC_DS_FLAG                    0x01
+#define WMI_HOST_RC_CW40_FLAG                  0x02
+#define WMI_HOST_RC_SGI_FLAG                   0x04
+#define WMI_HOST_RC_HT_FLAG                    0x08
+#define WMI_HOST_RC_RTSCTS_FLAG                        0x10
+#define WMI_HOST_RC_TX_STBC_FLAG               0x20
+#define WMI_HOST_RC_RX_STBC_FLAG               0xC0
+#define WMI_HOST_RC_RX_STBC_FLAG_S             6
+#define WMI_HOST_RC_WEP_TKIP_FLAG              0x100
+#define WMI_HOST_RC_TS_FLAG                    0x200
+#define WMI_HOST_RC_UAPSD_FLAG                 0x400
+
+#define WMI_HT_CAP_ENABLED                     0x0001
+#define WMI_HT_CAP_HT20_SGI                    0x0002
+#define WMI_HT_CAP_DYNAMIC_SMPS                        0x0004
+#define WMI_HT_CAP_TX_STBC                     0x0008
+#define WMI_HT_CAP_TX_STBC_MASK_SHIFT          3
+#define WMI_HT_CAP_RX_STBC                     0x0030
+#define WMI_HT_CAP_RX_STBC_MASK_SHIFT          4
+#define WMI_HT_CAP_LDPC                                0x0040
+#define WMI_HT_CAP_L_SIG_TXOP_PROT             0x0080
+#define WMI_HT_CAP_MPDU_DENSITY                        0x0700
+#define WMI_HT_CAP_MPDU_DENSITY_MASK_SHIFT     8
+#define WMI_HT_CAP_HT40_SGI                    0x0800
+#define WMI_HT_CAP_RX_LDPC                     0x1000
+#define WMI_HT_CAP_TX_LDPC                     0x2000
+#define WMI_HT_CAP_IBF_BFER                    0x4000
+
+/* These macros should be used when we wish to advertise STBC support for
+ * only 1SS or 2SS or 3SS.
+ */
+#define WMI_HT_CAP_RX_STBC_1SS                 0x0010
+#define WMI_HT_CAP_RX_STBC_2SS                 0x0020
+#define WMI_HT_CAP_RX_STBC_3SS                 0x0030
+
+#define WMI_HT_CAP_DEFAULT_ALL (WMI_HT_CAP_ENABLED    | \
+                               WMI_HT_CAP_HT20_SGI   | \
+                               WMI_HT_CAP_HT40_SGI   | \
+                               WMI_HT_CAP_TX_STBC    | \
+                               WMI_HT_CAP_RX_STBC    | \
+                               WMI_HT_CAP_LDPC)
+
+#define WMI_VHT_CAP_MAX_MPDU_LEN_MASK          0x00000003
+#define WMI_VHT_CAP_RX_LDPC                    0x00000010
+#define WMI_VHT_CAP_SGI_80MHZ                  0x00000020
+#define WMI_VHT_CAP_SGI_160MHZ                 0x00000040
+#define WMI_VHT_CAP_TX_STBC                    0x00000080
+#define WMI_VHT_CAP_RX_STBC_MASK               0x00000300
+#define WMI_VHT_CAP_RX_STBC_MASK_SHIFT         8
+#define WMI_VHT_CAP_SU_BFER                    0x00000800
+#define WMI_VHT_CAP_SU_BFEE                    0x00001000
+#define WMI_VHT_CAP_MAX_CS_ANT_MASK            0x0000E000
+#define WMI_VHT_CAP_MAX_CS_ANT_MASK_SHIFT      13
+#define WMI_VHT_CAP_MAX_SND_DIM_MASK           0x00070000
+#define WMI_VHT_CAP_MAX_SND_DIM_MASK_SHIFT     16
+#define WMI_VHT_CAP_MU_BFER                    0x00080000
+#define WMI_VHT_CAP_MU_BFEE                    0x00100000
+#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP          0x03800000
+#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIT     23
+#define WMI_VHT_CAP_RX_FIXED_ANT               0x10000000
+#define WMI_VHT_CAP_TX_FIXED_ANT               0x20000000
+
+#define WMI_VHT_CAP_MAX_MPDU_LEN_11454         0x00000002
+
+/* These macros should be used when we wish to advertise STBC support for
+ * only 1SS or 2SS or 3SS.
+ */
+#define WMI_VHT_CAP_RX_STBC_1SS                        0x00000100
+#define WMI_VHT_CAP_RX_STBC_2SS                        0x00000200
+#define WMI_VHT_CAP_RX_STBC_3SS                        0x00000300
+
+#define WMI_VHT_CAP_DEFAULT_ALL (WMI_VHT_CAP_MAX_MPDU_LEN_11454  | \
+                                WMI_VHT_CAP_SGI_80MHZ      |       \
+                                WMI_VHT_CAP_TX_STBC        |       \
+                                WMI_VHT_CAP_RX_STBC_MASK   |       \
+                                WMI_VHT_CAP_RX_LDPC        |       \
+                                WMI_VHT_CAP_MAX_AMPDU_LEN_EXP   |  \
+                                WMI_VHT_CAP_RX_FIXED_ANT   |       \
+                                WMI_VHT_CAP_TX_FIXED_ANT)
+
+/* FIXME: should these be in ieee80211.h? */
+#define IEEE80211_VHT_MCS_SUPPORT_0_11_MASK    GENMASK(23, 16)
+#define IEEE80211_DISABLE_VHT_MCS_SUPPORT_0_11 BIT(24)
+
+#define WMI_MAX_SPATIAL_STREAM                 3
+
+#define ATH11K_CHAN_WIDTH_NUM                  8
+
+extern const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default;
+
+int ath11k_mac_create(struct ath11k_base *ab);
+void ath11k_mac_destroy(struct ath11k_base *ab);
+void ath11k_mac_unregister(struct ath11k_base *ab);
+int ath11k_mac_hw_ratecode_to_legacy_rate(u8 hw_rc, u8 preamble, u8 *rateidx,
+                                         u16 *rate);
+u8 ath11k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
+                            u32 bitrate);
+u8 ath11k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
+                            u8 hw_rate, bool cck);
+
+void __ath11k_mac_scan_finish(struct ath11k *ar);
+void ath11k_mac_scan_finish(struct ath11k *ar);
+
+struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id);
+struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab,
+                                                  u32 vdev_id);
+struct ath11k *ath11k_mac_get_ar_by_vdev_id(struct ath11k_base *ab, u32 vdev_id);
+struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id);
+struct ath11k *ath11k_mac_get_ar_vdev_stop_status(struct ath11k_base *ab,
+                                                 u32 vdev_id);
+
+void ath11k_mac_drain_tx(struct ath11k *ar);
+void ath11k_mac_peer_cleanup_all(struct ath11k *ar);
+int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
+#endif
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include "core.h"
+#include "peer.h"
+#include "debug.h"
+
+struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
+                                    const u8 *addr)
+{
+       struct ath11k_peer *peer;
+
+       lockdep_assert_held(&ab->base_lock);
+
+       list_for_each_entry(peer, &ab->peers, list) {
+               if (peer->vdev_id != vdev_id)
+                       continue;
+               if (memcmp(peer->addr, addr, ETH_ALEN))
+                       continue;
+
+               return peer;
+       }
+
+       return NULL;
+}
+
+struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
+                                            const u8 *addr)
+{
+       struct ath11k_peer *peer;
+
+       lockdep_assert_held(&ab->base_lock);
+
+       list_for_each_entry(peer, &ab->peers, list) {
+               if (memcmp(peer->addr, addr, ETH_ALEN))
+                       continue;
+
+               return peer;
+       }
+
+       return NULL;
+}
+
+struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab,
+                                          int peer_id)
+{
+       struct ath11k_peer *peer;
+
+       lockdep_assert_held(&ab->base_lock);
+
+       list_for_each_entry(peer, &ab->peers, list)
+               if (peer_id == peer->peer_id)
+                       return peer;
+
+       return NULL;
+}
+
+void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
+{
+       struct ath11k_peer *peer;
+
+       spin_lock_bh(&ab->base_lock);
+
+       peer = ath11k_peer_find_by_id(ab, peer_id);
+       if (!peer) {
+               ath11k_warn(ab, "peer-unmap-event: unknown peer id %d\n",
+                           peer_id);
+               goto exit;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
+                  peer->vdev_id, peer->addr, peer_id);
+
+       list_del(&peer->list);
+       kfree(peer);
+       wake_up(&ab->peer_mapping_wq);
+
+exit:
+       spin_unlock_bh(&ab->base_lock);
+}
+
+void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
+                          u8 *mac_addr, u16 ast_hash)
+{
+       struct ath11k_peer *peer;
+
+       spin_lock_bh(&ab->base_lock);
+       peer = ath11k_peer_find(ab, vdev_id, mac_addr);
+       if (!peer) {
+               peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
+               if (!peer)
+                       goto exit;
+
+               peer->vdev_id = vdev_id;
+               peer->peer_id = peer_id;
+               peer->ast_hash = ast_hash;
+               ether_addr_copy(peer->addr, mac_addr);
+               list_add(&peer->list, &ab->peers);
+               wake_up(&ab->peer_mapping_wq);
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d\n",
+                  vdev_id, mac_addr, peer_id);
+
+exit:
+       spin_unlock_bh(&ab->base_lock);
+}
+
+static int ath11k_wait_for_peer_common(struct ath11k_base *ab, int vdev_id,
+                                      const u8 *addr, bool expect_mapped)
+{
+       int ret;
+
+       ret = wait_event_timeout(ab->peer_mapping_wq, ({
+                               bool mapped;
+
+                               spin_lock_bh(&ab->base_lock);
+                               mapped = !!ath11k_peer_find(ab, vdev_id, addr);
+                               spin_unlock_bh(&ab->base_lock);
+
+                               (mapped == expect_mapped ||
+                                test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags));
+                               }), 3 * HZ);
+
+       if (ret <= 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id)
+{
+       struct ath11k_peer *peer, *tmp;
+       struct ath11k_base *ab = ar->ab;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       spin_lock_bh(&ab->base_lock);
+       list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
+               if (peer->vdev_id != vdev_id)
+                       continue;
+
+               ath11k_warn(ab, "removing stale peer %pM from vdev_id %d\n",
+                           peer->addr, vdev_id);
+
+               list_del(&peer->list);
+               kfree(peer);
+               ar->num_peers--;
+       }
+
+       spin_unlock_bh(&ab->base_lock);
+}
+
+static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 *addr)
+{
+       return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, false);
+}
+
+int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
+{
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to delete peer vdev_id %d addr %pM ret %d\n",
+                           vdev_id, addr, ret);
+               return ret;
+       }
+
+       ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr);
+       if (ret)
+               return ret;
+
+       ar->num_peers--;
+
+       return 0;
+}
+
+static int ath11k_wait_for_peer_created(struct ath11k *ar, int vdev_id, const u8 *addr)
+{
+       return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
+}
+
+int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
+                      struct ieee80211_sta *sta, struct peer_create_params *param)
+{
+       struct ath11k_peer *peer;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (ar->num_peers > (ar->max_num_peers - 1)) {
+               ath11k_warn(ar->ab,
+                           "failed to create peer due to insufficient peer entry resource in firmware\n");
+               return -ENOBUFS;
+       }
+
+       ret = ath11k_wmi_send_peer_create_cmd(ar, param);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send peer create vdev_id %d ret %d\n",
+                           param->vdev_id, ret);
+               return ret;
+       }
+
+       ret = ath11k_wait_for_peer_created(ar, param->vdev_id,
+                                          param->peer_addr);
+       if (ret)
+               return ret;
+
+       spin_lock_bh(&ar->ab->base_lock);
+
+       peer = ath11k_peer_find(ar->ab, param->vdev_id, param->peer_addr);
+       if (!peer) {
+               spin_unlock_bh(&ar->ab->base_lock);
+               ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
+                           param->peer_addr, param->vdev_id);
+               ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr,
+                                               param->vdev_id);
+               return -ENOENT;
+       }
+
+       peer->sta = sta;
+       arvif->ast_hash = peer->ast_hash;
+
+       ar->num_peers++;
+
+       spin_unlock_bh(&ar->ab->base_lock);
+
+       return 0;
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_PEER_H
+#define ATH11K_PEER_H
+
+struct ath11k_peer {
+       struct list_head list;
+       struct ieee80211_sta *sta;
+       int vdev_id;
+       u8 addr[ETH_ALEN];
+       int peer_id;
+       u16 ast_hash;
+
+       /* protected by ab->data_lock */
+       struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
+       struct dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
+};
+
+void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id);
+void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
+                          u8 *mac_addr, u16 ast_hash);
+struct ath11k_peer *ath11k_peer_find(struct ath11k_base *ab, int vdev_id,
+                                    const u8 *addr);
+struct ath11k_peer *ath11k_peer_find_by_addr(struct ath11k_base *ab,
+                                            const u8 *addr);
+struct ath11k_peer *ath11k_peer_find_by_id(struct ath11k_base *ab, int peer_id);
+void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id);
+int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr);
+int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
+                      struct ieee80211_sta *sta, struct peer_create_params *param);
+
+#endif /* _PEER_H_ */
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include "qmi.h"
+#include "core.h"
+#include "debug.h"
+#include <linux/of.h>
+#include <linux/firmware.h>
+
+static struct qmi_elem_info qmi_wlanfw_host_cap_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_host_cap_req_msg_v01,
+                                          num_clients_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          num_clients),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          wake_msi_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_host_cap_req_msg_v01,
+                                          wake_msi),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          gpios_valid),
+       },
+       {
+               .data_type      = QMI_DATA_LEN,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          gpios_len),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = QMI_WLFW_MAX_NUM_GPIO_V01,
+               .elem_size      = sizeof(u32),
+               .array_type     = VAR_LEN_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          gpios),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          nm_modem_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          nm_modem),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          bdf_support_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          bdf_support),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x15,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          bdf_cache_support_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x15,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          bdf_cache_support),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x16,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          m3_support_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x16,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          m3_support),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x17,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          m3_cache_support_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x17,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          m3_cache_support),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x18,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          cal_filesys_support_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x18,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          cal_filesys_support),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x19,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          cal_cache_support_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x19,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          cal_cache_support),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x1A,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          cal_done_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x1A,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          cal_done),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x1B,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          mem_bucket_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x1B,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          mem_bucket),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x1C,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          mem_cfg_mode_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x1C,
+               .offset         = offsetof(struct qmi_wlanfw_host_cap_req_msg_v01,
+                                          mem_cfg_mode),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_host_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_host_cap_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 struct qmi_elem_info qmi_wlanfw_ind_register_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_ind_register_req_msg_v01,
+                                          fw_ready_enable_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_ind_register_req_msg_v01,
+                                          fw_ready_enable),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          initiate_cal_download_enable_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          initiate_cal_download_enable),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          initiate_cal_update_enable_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          initiate_cal_update_enable),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          msa_ready_enable_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          msa_ready_enable),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          pin_connect_result_enable_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          pin_connect_result_enable),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x15,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          client_id_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x15,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          client_id),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x16,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          request_mem_enable_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x16,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          request_mem_enable),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x17,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          fw_mem_ready_enable_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x17,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          fw_mem_ready_enable),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x18,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          fw_init_done_enable_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x18,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          fw_init_done_enable),
+       },
+
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x19,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          rejuvenate_enable_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x19,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          rejuvenate_enable),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x1A,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          xo_cal_enable_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x1A,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          xo_cal_enable),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x1B,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          cal_done_enable_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x1B,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_req_msg_v01,
+                                          cal_done_enable),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_ind_register_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_ind_register_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_ind_register_resp_msg_v01,
+                                          fw_status_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_8_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u64),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_ind_register_resp_msg_v01,
+                                          fw_status),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_8_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u64),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_cfg_s_v01, offset),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_cfg_s_v01, size),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_cfg_s_v01, secure_flag),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_seg_s_v01,
+                                 size),
+       },
+       {
+               .data_type      = QMI_SIGNED_4_BYTE_ENUM,
+               .elem_len       = 1,
+               .elem_size      = sizeof(enum qmi_wlanfw_mem_type_enum_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_seg_s_v01, type),
+       },
+       {
+               .data_type      = QMI_DATA_LEN,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_seg_s_v01, mem_cfg_len),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = QMI_WLANFW_MAX_NUM_MEM_CFG_V01,
+               .elem_size      = sizeof(struct qmi_wlanfw_mem_cfg_s_v01),
+               .array_type     = VAR_LEN_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_seg_s_v01, mem_cfg),
+               .ei_array       = qmi_wlanfw_mem_cfg_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_DATA_LEN,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x01,
+               .offset         = offsetof(struct qmi_wlanfw_request_mem_ind_msg_v01,
+                                          mem_seg_len),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01,
+               .elem_size      = sizeof(struct qmi_wlanfw_mem_seg_s_v01),
+               .array_type     = VAR_LEN_ARRAY,
+               .tlv_type       = 0x01,
+               .offset         = offsetof(struct qmi_wlanfw_request_mem_ind_msg_v01,
+                                          mem_seg),
+               .ei_array       = qmi_wlanfw_mem_seg_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_8_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u64),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_seg_resp_s_v01, addr),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_seg_resp_s_v01, size),
+       },
+       {
+               .data_type      = QMI_SIGNED_4_BYTE_ENUM,
+               .elem_len       = 1,
+               .elem_size      = sizeof(enum qmi_wlanfw_mem_type_enum_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_seg_resp_s_v01, type),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_mem_seg_resp_s_v01, restore),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_DATA_LEN,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x01,
+               .offset         = offsetof(struct qmi_wlanfw_respond_mem_req_msg_v01,
+                                          mem_seg_len),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01,
+               .elem_size      = sizeof(struct qmi_wlanfw_mem_seg_resp_s_v01),
+               .array_type     = VAR_LEN_ARRAY,
+               .tlv_type       = 0x01,
+               .offset         = offsetof(struct qmi_wlanfw_respond_mem_req_msg_v01,
+                                          mem_seg),
+               .ei_array       = qmi_wlanfw_mem_seg_resp_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_respond_mem_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_respond_mem_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 struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_rf_chip_info_s_v01,
+                                          chip_id),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_rf_chip_info_s_v01,
+                                          chip_family),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_rf_board_info_s_v01,
+                                          board_id),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_soc_info_s_v01, soc_id),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_fw_version_info_s_v01,
+                                          fw_version),
+       },
+       {
+               .data_type      = QMI_STRING,
+               .elem_len       = ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01 + 1,
+               .elem_size      = sizeof(char),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_fw_version_info_s_v01,
+                                          fw_build_timestamp),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_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_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_cap_resp_msg_v01,
+                                          chip_info_valid),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = 1,
+               .elem_size      = sizeof(struct qmi_wlanfw_rf_chip_info_s_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          chip_info),
+               .ei_array       = qmi_wlanfw_rf_chip_info_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          board_info_valid),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = 1,
+               .elem_size      = sizeof(struct qmi_wlanfw_rf_board_info_s_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          board_info),
+               .ei_array       = qmi_wlanfw_rf_board_info_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          soc_info_valid),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = 1,
+               .elem_size      = sizeof(struct qmi_wlanfw_soc_info_s_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          soc_info),
+               .ei_array       = qmi_wlanfw_soc_info_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          fw_version_info_valid),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = 1,
+               .elem_size      = sizeof(struct qmi_wlanfw_fw_version_info_s_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          fw_version_info),
+               .ei_array       = qmi_wlanfw_fw_version_info_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          fw_build_id_valid),
+       },
+       {
+               .data_type      = QMI_STRING,
+               .elem_len       = ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1,
+               .elem_size      = sizeof(char),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          fw_build_id),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x15,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          num_macs_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x15,
+               .offset         = offsetof(struct qmi_wlanfw_cap_resp_msg_v01,
+                                          num_macs),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x01,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          valid),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          file_id_valid),
+       },
+       {
+               .data_type      = QMI_SIGNED_4_BYTE_ENUM,
+               .elem_len       = 1,
+               .elem_size      = sizeof(enum qmi_wlanfw_cal_temp_id_enum_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          file_id),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          total_size_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_bdf_download_req_msg_v01,
+                                          total_size),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          seg_id_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          seg_id),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          data_valid),
+       },
+       {
+               .data_type      = QMI_DATA_LEN,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u16),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          data_len),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = QMI_WLANFW_MAX_DATA_SIZE_V01,
+               .elem_size      = sizeof(u8),
+               .array_type     = VAR_LEN_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          data),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          end_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          end),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x15,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          bdf_type_valid),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_1_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x15,
+               .offset         = offsetof(struct qmi_wlanfw_bdf_download_req_msg_v01,
+                                          bdf_type),
+       },
+
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_bdf_download_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_bdf_download_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 struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_8_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u64),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x01,
+               .offset         = offsetof(struct qmi_wlanfw_m3_info_req_msg_v01, addr),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x02,
+               .offset         = offsetof(struct qmi_wlanfw_m3_info_req_msg_v01, size),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_m3_info_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_m3_info_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 struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01,
+                                          pipe_num),
+       },
+       {
+               .data_type      = QMI_SIGNED_4_BYTE_ENUM,
+               .elem_len       = 1,
+               .elem_size      = sizeof(enum qmi_wlanfw_pipedir_enum_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01,
+                                          pipe_dir),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01,
+                                          nentries),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01,
+                                          nbytes_max),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01,
+                                          flags),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_ce_svc_pipe_cfg_s_v01,
+                                          service_id),
+       },
+       {
+               .data_type      = QMI_SIGNED_4_BYTE_ENUM,
+               .elem_len       = 1,
+               .elem_size      = sizeof(enum qmi_wlanfw_pipedir_enum_v01),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_ce_svc_pipe_cfg_s_v01,
+                                          pipe_dir),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_ce_svc_pipe_cfg_s_v01,
+                                          pipe_num),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_2_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u16),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_shadow_reg_cfg_s_v01, id),
+       },
+       {
+               .data_type      = QMI_UNSIGNED_2_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u16),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_shadow_reg_cfg_s_v01,
+                                          offset),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_shadow_reg_v2_cfg_s_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0,
+               .offset         = offsetof(struct qmi_wlanfw_shadow_reg_v2_cfg_s_v01,
+                                          addr),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = {
+       {
+               .data_type      = QMI_UNSIGNED_4_BYTE,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u32),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x01,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_mode_req_msg_v01,
+                                          mode),
+       },
+       {
+               .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_mode_req_msg_v01,
+                                          hw_debug_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_mode_req_msg_v01,
+                                          hw_debug),
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_wlan_mode_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_mode_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 struct qmi_elem_info qmi_wlanfw_wlan_cfg_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_cfg_req_msg_v01,
+                                          host_version_valid),
+       },
+       {
+               .data_type      = QMI_STRING,
+               .elem_len       = QMI_WLANFW_MAX_STR_LEN_V01 + 1,
+               .elem_size      = sizeof(char),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x10,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          host_version),
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          tgt_cfg_valid),
+       },
+       {
+               .data_type      = QMI_DATA_LEN,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          tgt_cfg_len),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = QMI_WLANFW_MAX_NUM_CE_V01,
+               .elem_size      = sizeof(
+                               struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01),
+               .array_type     = VAR_LEN_ARRAY,
+               .tlv_type       = 0x11,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          tgt_cfg),
+               .ei_array       = qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          svc_cfg_valid),
+       },
+       {
+               .data_type      = QMI_DATA_LEN,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          svc_cfg_len),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = QMI_WLANFW_MAX_NUM_SVC_V01,
+               .elem_size      = sizeof(struct qmi_wlanfw_ce_svc_pipe_cfg_s_v01),
+               .array_type     = VAR_LEN_ARRAY,
+               .tlv_type       = 0x12,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          svc_cfg),
+               .ei_array       = qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          shadow_reg_valid),
+       },
+       {
+               .data_type      = QMI_DATA_LEN,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          shadow_reg_len),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = QMI_WLANFW_MAX_NUM_SHADOW_REG_V01,
+               .elem_size      = sizeof(struct qmi_wlanfw_shadow_reg_cfg_s_v01),
+               .array_type     = VAR_LEN_ARRAY,
+               .tlv_type       = 0x13,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          shadow_reg),
+               .ei_array       = qmi_wlanfw_shadow_reg_cfg_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_OPT_FLAG,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          shadow_reg_v2_valid),
+       },
+       {
+               .data_type      = QMI_DATA_LEN,
+               .elem_len       = 1,
+               .elem_size      = sizeof(u8),
+               .array_type     = NO_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          shadow_reg_v2_len),
+       },
+       {
+               .data_type      = QMI_STRUCT,
+               .elem_len       = QMI_WLANFW_MAX_NUM_SHADOW_REG_V2_V01,
+               .elem_size      = sizeof(struct qmi_wlanfw_shadow_reg_v2_cfg_s_v01),
+               .array_type     = VAR_LEN_ARRAY,
+               .tlv_type       = 0x14,
+               .offset         = offsetof(struct qmi_wlanfw_wlan_cfg_req_msg_v01,
+                                          shadow_reg_v2),
+               .ei_array       = qmi_wlanfw_shadow_reg_v2_cfg_s_v01_ei,
+       },
+       {
+               .data_type      = QMI_EOTI,
+               .array_type     = NO_ARRAY,
+               .tlv_type       = QMI_COMMON_TLV_TYPE,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_wlan_cfg_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_cfg_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 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[] = {
+       {
+               .data_type = QMI_EOTI,
+               .array_type = NO_ARRAY,
+       },
+};
+
+static struct qmi_elem_info qmi_wlanfw_cold_boot_cal_done_ind_msg_v01_ei[] = {
+       {
+               .data_type = QMI_EOTI,
+               .array_type = NO_ARRAY,
+       },
+};
+
+static int ath11k_qmi_host_cap_send(struct ath11k_base *ab)
+{
+       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;
+       req.mem_cfg_mode_valid = 1;
+       req.bdf_support_valid = 1;
+       req.bdf_support = 1;
+
+       req.m3_support_valid = 0;
+       req.m3_support = 0;
+
+       req.m3_cache_support_valid = 0;
+       req.m3_cache_support = 0;
+
+       req.cal_done_valid = 1;
+       req.cal_done = ab->qmi.cal_done;
+
+       ret = qmi_txn_init(&ab->qmi.handle, &txn,
+                          qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp);
+       if (ret < 0)
+               goto out;
+
+       ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                              QMI_WLANFW_HOST_CAP_REQ_V01,
+                              QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN,
+                              qmi_wlanfw_host_cap_req_msg_v01_ei, &req);
+       if (ret < 0) {
+               ath11k_warn(ab, "Failed to send host capability request,err = %d\n", ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
+       if (ret < 0)
+               goto out;
+
+       if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+               ath11k_warn(ab, "Host capability request failed, result: %d, err: %d\n",
+                           resp.resp.result, resp.resp.error);
+               ret = -EINVAL;
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
+static int ath11k_qmi_fw_ind_register_send(struct ath11k_base *ab)
+{
+       struct qmi_wlanfw_ind_register_req_msg_v01 *req;
+       struct qmi_wlanfw_ind_register_resp_msg_v01 *resp;
+       struct qmi_handle *handle = &ab->qmi.handle;
+       struct qmi_txn txn;
+       int ret = 0;
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
+
+       resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+       if (!resp)
+               goto resp_out;
+
+       req->client_id_valid = 1;
+       req->client_id = QMI_WLANFW_CLIENT_ID;
+       req->fw_ready_enable_valid = 1;
+       req->fw_ready_enable = 1;
+       req->request_mem_enable_valid = 1;
+       req->request_mem_enable = 1;
+       req->fw_mem_ready_enable_valid = 1;
+       req->fw_mem_ready_enable = 1;
+       req->cal_done_enable_valid = 1;
+       req->cal_done_enable = 1;
+       req->fw_init_done_enable_valid = 1;
+       req->fw_init_done_enable = 1;
+
+       req->pin_connect_result_enable_valid = 0;
+       req->pin_connect_result_enable = 0;
+
+       ret = qmi_txn_init(handle, &txn,
+                          qmi_wlanfw_ind_register_resp_msg_v01_ei, resp);
+       if (ret < 0)
+               goto out;
+
+       ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                              QMI_WLANFW_IND_REGISTER_REQ_V01,
+                              QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN,
+                              qmi_wlanfw_ind_register_req_msg_v01_ei, req);
+       if (ret < 0) {
+               ath11k_warn(ab, "Failed to send indication register request, err = %d\n",
+                           ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
+       if (ret < 0) {
+               ath11k_warn(ab, "failed to register fw indication %d\n", ret);
+               goto out;
+       }
+
+       if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+               ath11k_warn(ab, "FW Ind register request failed, result: %d, err: %d\n",
+                           resp->resp.result, resp->resp.error);
+               ret = -EINVAL;
+               goto out;
+       }
+
+out:
+       kfree(resp);
+resp_out:
+       kfree(req);
+       return ret;
+}
+
+static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab)
+{
+       struct qmi_wlanfw_respond_mem_req_msg_v01 *req;
+       struct qmi_wlanfw_respond_mem_resp_msg_v01 resp;
+       struct qmi_txn txn = {};
+       int ret = 0, i;
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
+
+       memset(&resp, 0, sizeof(resp));
+
+       req->mem_seg_len = ab->qmi.mem_seg_count;
+
+       ret = qmi_txn_init(&ab->qmi.handle, &txn,
+                          qmi_wlanfw_respond_mem_resp_msg_v01_ei, &resp);
+       if (ret < 0)
+               goto out;
+
+       for (i = 0; i < req->mem_seg_len ; i++) {
+               req->mem_seg[i].addr = ab->qmi.target_mem[i].paddr;
+               req->mem_seg[i].size = ab->qmi.target_mem[i].size;
+               req->mem_seg[i].type = ab->qmi.target_mem[i].type;
+       }
+
+       ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                              QMI_WLANFW_RESPOND_MEM_REQ_V01,
+                              QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN,
+                              qmi_wlanfw_respond_mem_req_msg_v01_ei, req);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to respond memory request, err = %d\n",
+                           ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed memory request, err = %d\n", ret);
+               goto out;
+       }
+
+       if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+               ath11k_warn(ab, "Respond mem req failed, result: %d, err: %d\n",
+                           resp.resp.result, resp.resp.error);
+               ret = -EINVAL;
+               goto out;
+       }
+out:
+       kfree(req);
+       return ret;
+}
+
+static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab)
+{
+       int i, idx;
+
+       for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) {
+               switch (ab->qmi.target_mem[i].type) {
+               case BDF_MEM_REGION_TYPE:
+                       ab->qmi.target_mem[idx].paddr = ATH11K_QMI_BDF_ADDRESS;
+                       ab->qmi.target_mem[idx].vaddr = ATH11K_QMI_BDF_ADDRESS;
+                       ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
+                       ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
+                       idx++;
+                       break;
+               case CALDB_MEM_REGION_TYPE:
+                       if (ab->qmi.target_mem[i].size > ATH11K_QMI_CALDB_SIZE) {
+                               ath11k_warn(ab, "qmi mem size is low to load caldata\n");
+                               return -EINVAL;
+                       }
+                       /* TODO ath11k does not support cold boot calibration */
+                       ab->qmi.target_mem[idx].paddr = 0;
+                       ab->qmi.target_mem[idx].vaddr = 0;
+                       ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
+                       ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
+                       idx++;
+                       break;
+               default:
+                       ath11k_warn(ab, "qmi ignore invalid mem req type %d\n",
+                                   ab->qmi.target_mem[i].type);
+                       break;
+               }
+       }
+       ab->qmi.mem_seg_count = idx;
+
+       return 0;
+}
+
+static int ath11k_qmi_request_target_cap(struct ath11k_base *ab)
+{
+       struct qmi_wlanfw_cap_req_msg_v01 req;
+       struct qmi_wlanfw_cap_resp_msg_v01 resp;
+       struct qmi_txn txn = {};
+       int ret = 0;
+
+       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)
+               goto out;
+
+       ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                              QMI_WLANFW_CAP_REQ_V01,
+                              QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN,
+                              qmi_wlanfw_cap_req_msg_v01_ei, &req);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send target cap request, err = %d\n",
+                           ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed target cap request %d\n", ret);
+               goto out;
+       }
+
+       if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+               ath11k_warn(ab, "qmi targetcap req failed, result: %d, err: %d\n",
+                           resp.resp.result, resp.resp.error);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (resp.chip_info_valid) {
+               ab->qmi.target.chip_id = resp.chip_info.chip_id;
+               ab->qmi.target.chip_family = resp.chip_info.chip_family;
+       }
+
+       if (resp.board_info_valid)
+               ab->qmi.target.board_id = resp.board_info.board_id;
+       else
+               ab->qmi.target.board_id = 0xFF;
+
+       if (resp.soc_info_valid)
+               ab->qmi.target.soc_id = resp.soc_info.soc_id;
+
+       if (resp.fw_version_info_valid) {
+               ab->qmi.target.fw_version = resp.fw_version_info.fw_version;
+               strlcpy(ab->qmi.target.fw_build_timestamp,
+                       resp.fw_version_info.fw_build_timestamp,
+                       sizeof(ab->qmi.target.fw_build_timestamp));
+       }
+
+       if (resp.fw_build_id_valid)
+               strlcpy(ab->qmi.target.fw_build_id, resp.fw_build_id,
+                       sizeof(ab->qmi.target.fw_build_id));
+
+       ath11k_info(ab, "qmi target: chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x\n",
+                   ab->qmi.target.chip_id, ab->qmi.target.chip_family,
+                   ab->qmi.target.board_id, ab->qmi.target.soc_id);
+
+       ath11k_info(ab, "qmi fw_version: 0x%x fw_build_timestamp: %s fw_build_id: %s",
+                   ab->qmi.target.fw_version,
+                   ab->qmi.target.fw_build_timestamp,
+                   ab->qmi.target.fw_build_id);
+
+out:
+       return ret;
+}
+
+static int
+ath11k_qmi_prepare_bdf_download(struct ath11k_base *ab, int type,
+                               struct qmi_wlanfw_bdf_download_req_msg_v01 *req,
+                               void __iomem *bdf_addr)
+{
+       struct device *dev = ab->dev;
+       char filename[ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE];
+       const struct firmware *fw_entry;
+       struct ath11k_board_data bd;
+       u32 fw_size;
+       int ret = 0;
+
+       memset(&bd, 0, sizeof(bd));
+
+       switch (type) {
+       case ATH11K_QMI_FILE_TYPE_BDF_GOLDEN:
+               ret = ath11k_core_fetch_bdf(ab, &bd);
+               if (ret) {
+                       ath11k_warn(ab, "qmi failed to load BDF\n");
+                       goto out;
+               }
+
+               fw_size = min_t(u32, ab->hw_params.fw.board_size, bd.len);
+               memcpy_toio(bdf_addr, bd.data, fw_size);
+               ath11k_core_free_bdf(ab, &bd);
+               break;
+       case ATH11K_QMI_FILE_TYPE_CALDATA:
+               snprintf(filename, sizeof(filename),
+                        "%s/%s", ab->hw_params.fw.dir, ATH11K_QMI_DEFAULT_CAL_FILE_NAME);
+               ret = request_firmware(&fw_entry, filename, dev);
+               if (ret) {
+                       ath11k_warn(ab, "qmi failed to load CAL: %s\n", filename);
+                       goto out;
+               }
+
+               fw_size = min_t(u32, ab->hw_params.fw.board_size,
+                               fw_entry->size);
+
+               memcpy_toio(bdf_addr + ATH11K_QMI_CALDATA_OFFSET,
+                           fw_entry->data, fw_size);
+               ath11k_info(ab, "qmi downloading BDF: %s, size: %zu\n",
+                           filename, fw_entry->size);
+
+               release_firmware(fw_entry);
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+
+       req->total_size = fw_size;
+
+out:
+       return ret;
+}
+
+static int ath11k_qmi_load_bdf(struct ath11k_base *ab)
+{
+       struct qmi_wlanfw_bdf_download_req_msg_v01 *req;
+       struct qmi_wlanfw_bdf_download_resp_msg_v01 resp;
+       struct qmi_txn txn = {};
+       void __iomem *bdf_addr = NULL;
+       int type, ret;
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
+       memset(&resp, 0, sizeof(resp));
+
+       bdf_addr = ioremap(ATH11K_QMI_BDF_ADDRESS, ATH11K_QMI_BDF_MAX_SIZE);
+       if (!bdf_addr) {
+               ath11k_warn(ab, "qmi ioremap error for BDF\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       for (type = 0; type < ATH11K_QMI_MAX_FILE_TYPE; type++) {
+               req->valid = 1;
+               req->file_id_valid = 1;
+               req->file_id = ab->qmi.target.board_id;
+               req->total_size_valid = 1;
+               req->seg_id_valid = 1;
+               req->seg_id = type;
+               req->data_valid = 0;
+               req->data_len = ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE;
+               req->bdf_type = 0;
+               req->bdf_type_valid = 0;
+               req->end_valid = 1;
+               req->end = 1;
+
+               ret = ath11k_qmi_prepare_bdf_download(ab, type, req, bdf_addr);
+               if (ret < 0)
+                       goto out_qmi_bdf;
+
+               ret = qmi_txn_init(&ab->qmi.handle, &txn,
+                                  qmi_wlanfw_bdf_download_resp_msg_v01_ei,
+                                  &resp);
+               if (ret < 0)
+                       goto out_qmi_bdf;
+
+               ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                                      QMI_WLANFW_BDF_DOWNLOAD_REQ_V01,
+                                      QMI_WLANFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_LEN,
+                                      qmi_wlanfw_bdf_download_req_msg_v01_ei, req);
+               if (ret < 0) {
+                       qmi_txn_cancel(&txn);
+                       goto out_qmi_bdf;
+               }
+
+               ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
+               if (ret < 0)
+                       goto out_qmi_bdf;
+
+               if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+                       ath11k_warn(ab, "qmi BDF download failed, result: %d, err: %d\n",
+                                   resp.resp.result, resp.resp.error);
+                       ret = -EINVAL;
+                       goto out_qmi_bdf;
+               }
+       }
+       ath11k_info(ab, "qmi BDF downloaded\n");
+
+out_qmi_bdf:
+       iounmap(bdf_addr);
+out:
+       kfree(req);
+       return ret;
+}
+
+static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab)
+{
+       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));
+       req.addr = 0;
+       req.size = 0;
+
+       ret = qmi_txn_init(&ab->qmi.handle, &txn,
+                          qmi_wlanfw_m3_info_resp_msg_v01_ei, &resp);
+       if (ret < 0)
+               goto out;
+
+       ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                              QMI_WLANFW_M3_INFO_REQ_V01,
+                              QMI_WLANFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN,
+                              qmi_wlanfw_m3_info_req_msg_v01_ei, &req);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send M3 information request, err = %d\n",
+                           ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed M3 information request %d\n", ret);
+               goto out;
+       }
+
+       if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+               ath11k_warn(ab, "qmi M3 info request failed, result: %d, err: %d\n",
+                           resp.resp.result, resp.resp.error);
+               ret = -EINVAL;
+               goto out;
+       }
+out:
+       return ret;
+}
+
+static int ath11k_qmi_wlanfw_mode_send(struct ath11k_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 = {};
+       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;
+
+       ret = qmi_txn_init(&ab->qmi.handle, &txn,
+                          qmi_wlanfw_wlan_mode_resp_msg_v01_ei, &resp);
+       if (ret < 0)
+               goto out;
+
+       ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                              QMI_WLANFW_WLAN_MODE_REQ_V01,
+                              QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN,
+                              qmi_wlanfw_wlan_mode_req_msg_v01_ei, &req);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send mode request, mode: %d, err = %d\n",
+                           mode, ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
+       if (ret < 0) {
+               if (mode == ATH11K_FIRMWARE_MODE_OFF && ret == -ENETRESET) {
+                       ath11k_warn(ab, "WLFW service is dis-connected\n");
+                       return 0;
+               }
+               ath11k_warn(ab, "qmi failed set mode request, mode: %d, err = %d\n",
+                           mode, ret);
+               goto out;
+       }
+
+       if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+               ath11k_warn(ab, "Mode request failed, mode: %d, result: %d err: %d\n",
+                           mode, resp.resp.result, resp.resp.error);
+               ret = -EINVAL;
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
+static int ath11k_qmi_wlanfw_wlan_cfg_send(struct ath11k_base *ab)
+{
+       struct qmi_wlanfw_wlan_cfg_req_msg_v01 *req;
+       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 = {};
+       int ret = 0;
+
+       ce_cfg  = (struct ce_pipe_config *)ab->qmi.ce_cfg.tgt_ce;
+       svc_cfg = (struct service_to_pipe *)ab->qmi.ce_cfg.svc_to_ce_map;
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
+
+       memset(&resp, 0, sizeof(resp));
+
+       req->host_version_valid = 1;
+       strlcpy(req->host_version, ATH11K_HOST_VERSION_STRING,
+               sizeof(req->host_version));
+
+       req->tgt_cfg_valid = 1;
+       /* This is number of CE configs */
+       req->tgt_cfg_len = ((ab->qmi.ce_cfg.tgt_ce_len) /
+                               (sizeof(struct ce_pipe_config))) - 1;
+       for (ret = 0; ret <= req->tgt_cfg_len ; ret++) {
+               req->tgt_cfg[ret].pipe_num = ce_cfg[ret].pipenum;
+               req->tgt_cfg[ret].pipe_dir = ce_cfg[ret].pipedir;
+               req->tgt_cfg[ret].nentries = ce_cfg[ret].nentries;
+               req->tgt_cfg[ret].nbytes_max = ce_cfg[ret].nbytes_max;
+               req->tgt_cfg[ret].flags = ce_cfg[ret].flags;
+       }
+
+       req->svc_cfg_valid = 1;
+       /* This is number of Service/CE configs */
+       req->svc_cfg_len = (ab->qmi.ce_cfg.svc_to_ce_map_len) /
+                               (sizeof(struct service_to_pipe));
+       for (ret = 0; ret < req->svc_cfg_len; ret++) {
+               req->svc_cfg[ret].service_id = svc_cfg[ret].service_id;
+               req->svc_cfg[ret].pipe_dir = svc_cfg[ret].pipedir;
+               req->svc_cfg[ret].pipe_num = svc_cfg[ret].pipenum;
+       }
+       req->shadow_reg_valid = 0;
+       req->shadow_reg_v2_valid = 0;
+
+       ret = qmi_txn_init(&ab->qmi.handle, &txn,
+                          qmi_wlanfw_wlan_cfg_resp_msg_v01_ei, &resp);
+       if (ret < 0)
+               goto out;
+
+       ret = qmi_send_request(&ab->qmi.handle, NULL, &txn,
+                              QMI_WLANFW_WLAN_CFG_REQ_V01,
+                              QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN,
+                              qmi_wlanfw_wlan_cfg_req_msg_v01_ei, req);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send wlan config request, err = %d\n",
+                           ret);
+               goto out;
+       }
+
+       ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH11K_QMI_WLANFW_TIMEOUT_MS));
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed wlan config request, err = %d\n", ret);
+               goto out;
+       }
+
+       if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+               ath11k_warn(ab, "qmi wlan config request failed, result: %d, err: %d\n",
+                           resp.resp.result, resp.resp.error);
+               ret = -EINVAL;
+               goto out;
+       }
+
+out:
+       kfree(req);
+       return ret;
+}
+
+void ath11k_qmi_firmware_stop(struct ath11k_base *ab)
+{
+       int ret;
+
+       ret = ath11k_qmi_wlanfw_mode_send(ab, ATH11K_FIRMWARE_MODE_OFF);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send wlan mode off\n");
+               return;
+       }
+}
+
+int ath11k_qmi_firmware_start(struct ath11k_base *ab,
+                             u32 mode)
+{
+       int ret;
+
+       ret = ath11k_qmi_wlanfw_wlan_cfg_send(ab);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send wlan cfg:%d\n", ret);
+               return ret;
+       }
+
+       ret = ath11k_qmi_wlanfw_mode_send(ab, mode);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send wlan fw mode:%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int
+ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi,
+                            enum ath11k_qmi_event_type type,
+                            void *data)
+{
+       struct ath11k_qmi_driver_event *event;
+
+       event = kzalloc(sizeof(*event), GFP_ATOMIC);
+       if (!event)
+               return -ENOMEM;
+
+       event->type = type;
+       event->data = data;
+
+       spin_lock(&qmi->event_lock);
+       list_add_tail(&event->list, &qmi->event_list);
+       spin_unlock(&qmi->event_lock);
+
+       queue_work(qmi->event_wq, &qmi->event_work);
+
+       return 0;
+}
+
+static void ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi)
+{
+       struct ath11k_base *ab = qmi->ab;
+       int ret;
+
+       ret = ath11k_qmi_fw_ind_register_send(ab);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send FW indication QMI:%d\n", ret);
+               return;
+       }
+
+       ret = ath11k_qmi_host_cap_send(ab);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send host cap QMI:%d\n", ret);
+               return;
+       }
+}
+
+static void ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi)
+{
+       struct ath11k_base *ab = qmi->ab;
+       int ret;
+
+       ret = ath11k_qmi_respond_fw_mem_request(ab);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to respond fw mem req:%d\n", ret);
+               return;
+       }
+}
+
+static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
+{
+       struct ath11k_base *ab = qmi->ab;
+       int ret;
+
+       ret = ath11k_qmi_request_target_cap(ab);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to req target capabilities:%d\n", ret);
+               return;
+       }
+
+       ret = ath11k_qmi_load_bdf(ab);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to load board data file:%d\n", ret);
+               return;
+       }
+
+       ret = ath11k_qmi_wlanfw_m3_info_send(ab);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to send m3 info req:%d\n", ret);
+               return;
+       }
+}
+
+static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl,
+                                         struct sockaddr_qrtr *sq,
+                                         struct qmi_txn *txn,
+                                         const void *data)
+{
+       struct ath11k_qmi *qmi = container_of(qmi_hdl, struct ath11k_qmi, handle);
+       struct ath11k_base *ab = qmi->ab;
+       const struct qmi_wlanfw_request_mem_ind_msg_v01 *msg = data;
+       int i, ret;
+
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware request memory request\n");
+
+       if (msg->mem_seg_len == 0 ||
+           msg->mem_seg_len > ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01)
+               ath11k_warn(ab, "Invalid memory segment length: %u\n",
+                           msg->mem_seg_len);
+
+       ab->qmi.mem_seg_count = msg->mem_seg_len;
+
+       for (i = 0; i < qmi->mem_seg_count ; i++) {
+               ab->qmi.target_mem[i].type = msg->mem_seg[i].type;
+               ab->qmi.target_mem[i].size = msg->mem_seg[i].size;
+               ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi mem seg type %d size %d\n",
+                          msg->mem_seg[i].type, msg->mem_seg[i].size);
+       }
+
+       ret = ath11k_qmi_alloc_target_mem_chunk(ab);
+       if (ret < 0) {
+               ath11k_warn(ab, "qmi failed to alloc target memory:%d\n", ret);
+               return;
+       }
+
+       ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_REQUEST_MEM, NULL);
+}
+
+static void ath11k_qmi_msg_mem_ready_cb(struct qmi_handle *qmi_hdl,
+                                       struct sockaddr_qrtr *sq,
+                                       struct qmi_txn *txn,
+                                       const void *decoded)
+{
+       struct ath11k_qmi *qmi = container_of(qmi_hdl, struct ath11k_qmi, handle);
+       struct ath11k_base *ab = qmi->ab;
+
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware memory ready indication\n");
+       ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_FW_MEM_READY, NULL);
+}
+
+static void ath11k_qmi_msg_fw_ready_cb(struct qmi_handle *qmi_hdl,
+                                      struct sockaddr_qrtr *sq,
+                                      struct qmi_txn *txn,
+                                      const void *decoded)
+{
+       struct ath11k_qmi *qmi = container_of(qmi_hdl, struct ath11k_qmi, handle);
+       struct ath11k_base *ab = qmi->ab;
+
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware ready\n");
+       ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_FW_READY, NULL);
+}
+
+static void ath11k_qmi_msg_cold_boot_cal_done_cb(struct qmi_handle *qmi,
+                                                struct sockaddr_qrtr *sq,
+                                                struct qmi_txn *txn,
+                                                const void *decoded)
+{
+}
+
+static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = {
+       {
+               .type = QMI_INDICATION,
+               .msg_id = QMI_WLFW_REQUEST_MEM_IND_V01,
+               .ei = qmi_wlanfw_request_mem_ind_msg_v01_ei,
+               .decoded_size = sizeof(qmi_wlanfw_request_mem_ind_msg_v01_ei),
+               .fn = ath11k_qmi_msg_mem_request_cb,
+       },
+       {
+               .type = QMI_INDICATION,
+               .msg_id = QMI_WLFW_FW_MEM_READY_IND_V01,
+               .ei = qmi_wlanfw_mem_ready_ind_msg_v01_ei,
+               .decoded_size = sizeof(qmi_wlanfw_mem_ready_ind_msg_v01_ei),
+               .fn = ath11k_qmi_msg_mem_ready_cb,
+       },
+       {
+               .type = QMI_INDICATION,
+               .msg_id = QMI_WLFW_FW_READY_IND_V01,
+               .ei = qmi_wlanfw_fw_ready_ind_msg_v01_ei,
+               .decoded_size = sizeof(qmi_wlanfw_fw_ready_ind_msg_v01_ei),
+               .fn = ath11k_qmi_msg_fw_ready_cb,
+       },
+       {
+               .type = QMI_INDICATION,
+               .msg_id = QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01,
+               .ei = qmi_wlanfw_cold_boot_cal_done_ind_msg_v01_ei,
+               .decoded_size =
+                       sizeof(qmi_wlanfw_cold_boot_cal_done_ind_msg_v01_ei),
+               .fn = ath11k_qmi_msg_cold_boot_cal_done_cb,
+       },
+};
+
+static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl,
+                                    struct qmi_service *service)
+{
+       struct ath11k_qmi *qmi = container_of(qmi_hdl, struct ath11k_qmi, handle);
+       struct ath11k_base *ab = qmi->ab;
+       struct sockaddr_qrtr *sq = &qmi->sq;
+       int ret;
+
+       sq->sq_family = AF_QIPCRTR;
+       sq->sq_node = service->node;
+       sq->sq_port = service->port;
+
+       ret = kernel_connect(qmi_hdl->sock, (struct sockaddr *)sq,
+                            sizeof(*sq), 0);
+       if (ret) {
+               ath11k_warn(ab, "qmi failed to connect to remote service %d\n", ret);
+               return ret;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wifi fw qmi service connected\n");
+       ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_SERVER_ARRIVE, NULL);
+
+       return 0;
+}
+
+static void ath11k_qmi_ops_del_server(struct qmi_handle *qmi_hdl,
+                                     struct qmi_service *service)
+{
+       struct ath11k_qmi *qmi = container_of(qmi_hdl, struct ath11k_qmi, handle);
+       struct ath11k_base *ab = qmi->ab;
+
+       ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wifi fw del server\n");
+       ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_SERVER_EXIT, NULL);
+}
+
+static const struct qmi_ops ath11k_qmi_ops = {
+       .new_server = ath11k_qmi_ops_new_server,
+       .del_server = ath11k_qmi_ops_del_server,
+};
+
+static void ath11k_qmi_driver_event_work(struct work_struct *work)
+{
+       struct ath11k_qmi *qmi = container_of(work, struct ath11k_qmi,
+                                             event_work);
+       struct ath11k_qmi_driver_event *event;
+       struct ath11k_base *ab = qmi->ab;
+
+       spin_lock(&qmi->event_lock);
+       while (!list_empty(&qmi->event_list)) {
+               event = list_first_entry(&qmi->event_list,
+                                        struct ath11k_qmi_driver_event, list);
+               list_del(&event->list);
+               spin_unlock(&qmi->event_lock);
+
+               if (test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags))
+                       return;
+
+               switch (event->type) {
+               case ATH11K_QMI_EVENT_SERVER_ARRIVE:
+                       ath11k_qmi_event_server_arrive(qmi);
+                       break;
+               case ATH11K_QMI_EVENT_SERVER_EXIT:
+                       set_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags);
+                       set_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
+                       break;
+               case ATH11K_QMI_EVENT_REQUEST_MEM:
+                       ath11k_qmi_event_mem_request(qmi);
+                       break;
+               case ATH11K_QMI_EVENT_FW_MEM_READY:
+                       ath11k_qmi_event_load_bdf(qmi);
+                       break;
+               case ATH11K_QMI_EVENT_FW_READY:
+                       if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
+                               queue_work(ab->workqueue, &ab->restart_work);
+                               break;
+                       }
+
+                       ath11k_core_qmi_firmware_ready(ab);
+                       ab->qmi.cal_done = 1;
+                       set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
+
+                       break;
+               case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE:
+                       break;
+               default:
+                       ath11k_warn(ab, "invalid event type: %d", event->type);
+                       break;
+               }
+               kfree(event);
+               spin_lock(&qmi->event_lock);
+       }
+       spin_unlock(&qmi->event_lock);
+}
+
+int ath11k_qmi_init_service(struct ath11k_base *ab)
+{
+       int ret;
+
+       memset(&ab->qmi.target, 0, sizeof(struct target_info));
+       memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk));
+       ab->qmi.ab = ab;
+
+       ab->qmi.target_mem_mode = ATH11K_QMI_TARGET_MEM_MODE_DEFAULT;
+       ret = qmi_handle_init(&ab->qmi.handle, ATH11K_QMI_RESP_LEN_MAX,
+                             &ath11k_qmi_ops, ath11k_qmi_msg_handlers);
+       if (ret < 0) {
+               ath11k_warn(ab, "failed to initialize qmi handle\n");
+               return ret;
+       }
+
+       ab->qmi.event_wq = alloc_workqueue("ath11k_qmi_driver_event",
+                                          WQ_UNBOUND, 1);
+       if (!ab->qmi.event_wq) {
+               ath11k_err(ab, "failed to allocate workqueue\n");
+               return -EFAULT;
+       }
+
+       INIT_LIST_HEAD(&ab->qmi.event_list);
+       spin_lock_init(&ab->qmi.event_lock);
+       INIT_WORK(&ab->qmi.event_work, ath11k_qmi_driver_event_work);
+
+       ret = qmi_add_lookup(&ab->qmi.handle, ATH11K_QMI_WLFW_SERVICE_ID_V01,
+                            ATH11K_QMI_WLFW_SERVICE_VERS_V01,
+                            ATH11K_QMI_WLFW_SERVICE_INS_ID_V01);
+       if (ret < 0) {
+               ath11k_warn(ab, "failed to add qmi lookup\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+void ath11k_qmi_deinit_service(struct ath11k_base *ab)
+{
+       qmi_handle_release(&ab->qmi.handle);
+       cancel_work_sync(&ab->qmi.event_work);
+       destroy_workqueue(ab->qmi.event_wq);
+}
+
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_QMI_H
+#define ATH11K_QMI_H
+
+#include <linux/mutex.h>
+#include <linux/soc/qcom/qmi.h>
+
+#define ATH11K_HOST_VERSION_STRING             "WIN"
+#define ATH11K_QMI_WLANFW_TIMEOUT_MS           5000
+#define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE      64
+#define ATH11K_QMI_BDF_ADDRESS                 0x4B0C0000
+#define ATH11K_QMI_BDF_MAX_SIZE                        (256 * 1024)
+#define ATH11K_QMI_CALDATA_OFFSET              (128 * 1024)
+#define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128
+#define ATH11K_QMI_WLFW_SERVICE_ID_V01         0x45
+#define ATH11K_QMI_WLFW_SERVICE_VERS_V01       0x01
+#define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01     0x02
+#define ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01        32
+#define ATH11K_QMI_RESP_LEN_MAX                        8192
+#define ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01  32
+#define ATH11K_QMI_CALDB_SIZE                  0x480000
+#define ATH11K_QMI_DEFAULT_CAL_FILE_NAME       "caldata.bin"
+
+#define QMI_WLFW_REQUEST_MEM_IND_V01           0x0035
+#define QMI_WLFW_FW_MEM_READY_IND_V01          0x0037
+#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01    0x0021
+#define QMI_WLFW_FW_READY_IND_V01              0x0038
+
+#define QMI_WLANFW_MAX_DATA_SIZE_V01           6144
+#define ATH11K_FIRMWARE_MODE_OFF               4
+#define ATH11K_QMI_TARGET_MEM_MODE_DEFAULT     0
+
+struct ath11k_base;
+
+enum ath11k_qmi_file_type {
+       ATH11K_QMI_FILE_TYPE_BDF_GOLDEN,
+       ATH11K_QMI_FILE_TYPE_CALDATA,
+       ATH11K_QMI_MAX_FILE_TYPE,
+};
+
+enum ath11k_qmi_event_type {
+       ATH11K_QMI_EVENT_SERVER_ARRIVE,
+       ATH11K_QMI_EVENT_SERVER_EXIT,
+       ATH11K_QMI_EVENT_REQUEST_MEM,
+       ATH11K_QMI_EVENT_FW_MEM_READY,
+       ATH11K_QMI_EVENT_FW_READY,
+       ATH11K_QMI_EVENT_COLD_BOOT_CAL_START,
+       ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE,
+       ATH11K_QMI_EVENT_REGISTER_DRIVER,
+       ATH11K_QMI_EVENT_UNREGISTER_DRIVER,
+       ATH11K_QMI_EVENT_RECOVERY,
+       ATH11K_QMI_EVENT_FORCE_FW_ASSERT,
+       ATH11K_QMI_EVENT_POWER_UP,
+       ATH11K_QMI_EVENT_POWER_DOWN,
+       ATH11K_QMI_EVENT_MAX,
+};
+
+struct ath11k_qmi_driver_event {
+       struct list_head list;
+       enum ath11k_qmi_event_type type;
+       void *data;
+};
+
+struct ath11k_qmi_ce_cfg {
+       const u8 *tgt_ce;
+       int tgt_ce_len;
+       const u8 *svc_to_ce_map;
+       int svc_to_ce_map_len;
+       const u8 *shadow_reg;
+       int shadow_reg_len;
+       u8 *shadow_reg_v2;
+       int shadow_reg_v2_len;
+};
+
+struct ath11k_qmi_event_msg {
+       struct list_head list;
+       enum ath11k_qmi_event_type type;
+};
+
+struct target_mem_chunk {
+       u32 size;
+       u32 type;
+       dma_addr_t paddr;
+       u32 vaddr;
+};
+
+struct target_info {
+       u32 chip_id;
+       u32 chip_family;
+       u32 board_id;
+       u32 soc_id;
+       u32 fw_version;
+       char fw_build_timestamp[ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01 + 1];
+       char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1];
+};
+
+struct ath11k_qmi {
+       struct ath11k_base *ab;
+       struct qmi_handle handle;
+       struct sockaddr_qrtr sq;
+       struct work_struct event_work;
+       struct workqueue_struct *event_wq;
+       struct list_head event_list;
+       spinlock_t event_lock; /* spinlock for qmi event list */
+       struct ath11k_qmi_ce_cfg ce_cfg;
+       struct target_mem_chunk target_mem[ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01];
+       u32 mem_seg_count;
+       u32 target_mem_mode;
+       u8 cal_done;
+       struct target_info target;
+};
+
+#define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN                189
+#define QMI_WLANFW_HOST_CAP_REQ_V01                    0x0034
+#define QMI_WLANFW_HOST_CAP_RESP_MSG_V01_MAX_LEN       7
+#define QMI_WLFW_HOST_CAP_RESP_V01                     0x0034
+#define QMI_WLFW_MAX_NUM_GPIO_V01                      32
+#define QMI_IPQ8074_FW_MEM_MODE                                0xFF
+#define HOST_DDR_REGION_TYPE                           0x1
+#define BDF_MEM_REGION_TYPE                            0x2
+#define CALDB_MEM_REGION_TYPE                          0x4
+
+struct qmi_wlanfw_host_cap_req_msg_v01 {
+       u8 num_clients_valid;
+       u32 num_clients;
+       u8 wake_msi_valid;
+       u32 wake_msi;
+       u8 gpios_valid;
+       u32 gpios_len;
+       u32 gpios[QMI_WLFW_MAX_NUM_GPIO_V01];
+       u8 nm_modem_valid;
+       u8 nm_modem;
+       u8 bdf_support_valid;
+       u8 bdf_support;
+       u8 bdf_cache_support_valid;
+       u8 bdf_cache_support;
+       u8 m3_support_valid;
+       u8 m3_support;
+       u8 m3_cache_support_valid;
+       u8 m3_cache_support;
+       u8 cal_filesys_support_valid;
+       u8 cal_filesys_support;
+       u8 cal_cache_support_valid;
+       u8 cal_cache_support;
+       u8 cal_done_valid;
+       u8 cal_done;
+       u8 mem_bucket_valid;
+       u32 mem_bucket;
+       u8 mem_cfg_mode_valid;
+       u8 mem_cfg_mode;
+};
+
+struct qmi_wlanfw_host_cap_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+};
+
+#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
+#define QMI_WLANFW_IND_REGISTER_RESP_V01                       0x0020
+#define QMI_WLANFW_CLIENT_ID                                   0x4b4e454c
+
+struct qmi_wlanfw_ind_register_req_msg_v01 {
+       u8 fw_ready_enable_valid;
+       u8 fw_ready_enable;
+       u8 initiate_cal_download_enable_valid;
+       u8 initiate_cal_download_enable;
+       u8 initiate_cal_update_enable_valid;
+       u8 initiate_cal_update_enable;
+       u8 msa_ready_enable_valid;
+       u8 msa_ready_enable;
+       u8 pin_connect_result_enable_valid;
+       u8 pin_connect_result_enable;
+       u8 client_id_valid;
+       u32 client_id;
+       u8 request_mem_enable_valid;
+       u8 request_mem_enable;
+       u8 fw_mem_ready_enable_valid;
+       u8 fw_mem_ready_enable;
+       u8 fw_init_done_enable_valid;
+       u8 fw_init_done_enable;
+       u8 rejuvenate_enable_valid;
+       u32 rejuvenate_enable;
+       u8 xo_cal_enable_valid;
+       u8 xo_cal_enable;
+       u8 cal_done_enable_valid;
+       u8 cal_done_enable;
+};
+
+struct qmi_wlanfw_ind_register_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+       u8 fw_status_valid;
+       u64 fw_status;
+};
+
+#define QMI_WLANFW_REQUEST_MEM_IND_MSG_V01_MAX_LEN     1124
+#define QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN     548
+#define QMI_WLANFW_RESPOND_MEM_RESP_MSG_V01_MAX_LEN    7
+#define QMI_WLANFW_REQUEST_MEM_IND_V01                 0x0035
+#define QMI_WLANFW_RESPOND_MEM_REQ_V01                 0x0036
+#define QMI_WLANFW_RESPOND_MEM_RESP_V01                        0x0036
+#define QMI_WLANFW_MAX_NUM_MEM_CFG_V01                 2
+
+struct qmi_wlanfw_mem_cfg_s_v01 {
+       u64 offset;
+       u32 size;
+       u8 secure_flag;
+};
+
+enum qmi_wlanfw_mem_type_enum_v01 {
+       WLANFW_MEM_TYPE_ENUM_MIN_VAL_V01 = INT_MIN,
+       QMI_WLANFW_MEM_TYPE_MSA_V01 = 0,
+       QMI_WLANFW_MEM_TYPE_DDR_V01 = 1,
+       QMI_WLANFW_MEM_BDF_V01 = 2,
+       QMI_WLANFW_MEM_M3_V01 = 3,
+       QMI_WLANFW_MEM_CAL_V01 = 4,
+       QMI_WLANFW_MEM_DPD_V01 = 5,
+       WLANFW_MEM_TYPE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+struct qmi_wlanfw_mem_seg_s_v01 {
+       u32 size;
+       enum qmi_wlanfw_mem_type_enum_v01 type;
+       u32 mem_cfg_len;
+       struct qmi_wlanfw_mem_cfg_s_v01 mem_cfg[QMI_WLANFW_MAX_NUM_MEM_CFG_V01];
+};
+
+struct qmi_wlanfw_request_mem_ind_msg_v01 {
+       u32 mem_seg_len;
+       struct qmi_wlanfw_mem_seg_s_v01 mem_seg[ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01];
+};
+
+struct qmi_wlanfw_mem_seg_resp_s_v01 {
+       u64 addr;
+       u32 size;
+       enum qmi_wlanfw_mem_type_enum_v01 type;
+       u8 restore;
+};
+
+struct qmi_wlanfw_respond_mem_req_msg_v01 {
+       u32 mem_seg_len;
+       struct qmi_wlanfw_mem_seg_resp_s_v01 mem_seg[ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01];
+};
+
+struct qmi_wlanfw_respond_mem_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+};
+
+struct qmi_wlanfw_fw_mem_ready_ind_msg_v01 {
+       char placeholder;
+};
+
+#define QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN     0
+#define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN    207
+#define QMI_WLANFW_CAP_REQ_V01                 0x0024
+#define QMI_WLANFW_CAP_RESP_V01                        0x0024
+
+enum qmi_wlanfw_pipedir_enum_v01 {
+       QMI_WLFW_PIPEDIR_NONE_V01 = 0,
+       QMI_WLFW_PIPEDIR_IN_V01 = 1,
+       QMI_WLFW_PIPEDIR_OUT_V01 = 2,
+       QMI_WLFW_PIPEDIR_INOUT_V01 = 3,
+};
+
+struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01 {
+       __le32 pipe_num;
+       __le32 pipe_dir;
+       __le32 nentries;
+       __le32 nbytes_max;
+       __le32 flags;
+};
+
+struct qmi_wlanfw_ce_svc_pipe_cfg_s_v01 {
+       __le32 service_id;
+       __le32 pipe_dir;
+       __le32 pipe_num;
+};
+
+struct qmi_wlanfw_shadow_reg_cfg_s_v01 {
+       u16 id;
+       u16 offset;
+};
+
+struct qmi_wlanfw_shadow_reg_v2_cfg_s_v01 {
+       u32 addr;
+};
+
+struct qmi_wlanfw_memory_region_info_s_v01 {
+       u64 region_addr;
+       u32 size;
+       u8 secure_flag;
+};
+
+struct qmi_wlanfw_rf_chip_info_s_v01 {
+       u32 chip_id;
+       u32 chip_family;
+};
+
+struct qmi_wlanfw_rf_board_info_s_v01 {
+       u32 board_id;
+};
+
+struct qmi_wlanfw_soc_info_s_v01 {
+       u32 soc_id;
+};
+
+struct qmi_wlanfw_fw_version_info_s_v01 {
+       u32 fw_version;
+       char fw_build_timestamp[ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01 + 1];
+};
+
+enum qmi_wlanfw_cal_temp_id_enum_v01 {
+       QMI_WLANFW_CAL_TEMP_IDX_0_V01 = 0,
+       QMI_WLANFW_CAL_TEMP_IDX_1_V01 = 1,
+       QMI_WLANFW_CAL_TEMP_IDX_2_V01 = 2,
+       QMI_WLANFW_CAL_TEMP_IDX_3_V01 = 3,
+       QMI_WLANFW_CAL_TEMP_IDX_4_V01 = 4,
+       QMI_WLANFW_CAL_TEMP_ID_MAX_V01 = 0xFF,
+};
+
+struct qmi_wlanfw_cap_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+       u8 chip_info_valid;
+       struct qmi_wlanfw_rf_chip_info_s_v01 chip_info;
+       u8 board_info_valid;
+       struct qmi_wlanfw_rf_board_info_s_v01 board_info;
+       u8 soc_info_valid;
+       struct qmi_wlanfw_soc_info_s_v01 soc_info;
+       u8 fw_version_info_valid;
+       struct qmi_wlanfw_fw_version_info_s_v01 fw_version_info;
+       u8 fw_build_id_valid;
+       char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1];
+       u8 num_macs_valid;
+       u8 num_macs;
+};
+
+struct qmi_wlanfw_cap_req_msg_v01 {
+       char placeholder;
+};
+
+#define QMI_WLANFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_LEN    6182
+#define QMI_WLANFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_LEN   7
+#define QMI_WLANFW_BDF_DOWNLOAD_RESP_V01               0x0025
+#define QMI_WLANFW_BDF_DOWNLOAD_REQ_V01                        0x0025
+/* TODO: Need to check with MCL and FW team that data can be pointer and
+ * can be last element in structure
+ */
+struct qmi_wlanfw_bdf_download_req_msg_v01 {
+       u8 valid;
+       u8 file_id_valid;
+       enum qmi_wlanfw_cal_temp_id_enum_v01 file_id;
+       u8 total_size_valid;
+       u32 total_size;
+       u8 seg_id_valid;
+       u32 seg_id;
+       u8 data_valid;
+       u32 data_len;
+       u8 data[QMI_WLANFW_MAX_DATA_SIZE_V01];
+       u8 end_valid;
+       u8 end;
+       u8 bdf_type_valid;
+       u8 bdf_type;
+
+};
+
+struct qmi_wlanfw_bdf_download_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+};
+
+#define QMI_WLANFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN     18
+#define QMI_WLANFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN    7
+#define QMI_WLANFW_M3_INFO_RESP_V01            0x003C
+#define QMI_WLANFW_M3_INFO_REQ_V01             0x003C
+
+struct qmi_wlanfw_m3_info_req_msg_v01 {
+       u64 addr;
+       u32 size;
+};
+
+struct qmi_wlanfw_m3_info_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+};
+
+#define QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN       11
+#define QMI_WLANFW_WLAN_MODE_RESP_MSG_V01_MAX_LEN      7
+#define QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN                803
+#define QMI_WLANFW_WLAN_CFG_RESP_MSG_V01_MAX_LEN       7
+#define QMI_WLANFW_WLAN_MODE_REQ_V01                   0x0022
+#define QMI_WLANFW_WLAN_MODE_RESP_V01                  0x0022
+#define QMI_WLANFW_WLAN_CFG_REQ_V01                    0x0023
+#define QMI_WLANFW_WLAN_CFG_RESP_V01                   0x0023
+#define QMI_WLANFW_MAX_STR_LEN_V01                     16
+#define QMI_WLANFW_MAX_NUM_CE_V01                      12
+#define QMI_WLANFW_MAX_NUM_SVC_V01                     24
+#define QMI_WLANFW_MAX_NUM_SHADOW_REG_V01              24
+#define QMI_WLANFW_MAX_NUM_SHADOW_REG_V2_V01           36
+
+struct qmi_wlanfw_wlan_mode_req_msg_v01 {
+       u32 mode;
+       u8 hw_debug_valid;
+       u8 hw_debug;
+};
+
+struct qmi_wlanfw_wlan_mode_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+};
+
+struct qmi_wlanfw_wlan_cfg_req_msg_v01 {
+       u8 host_version_valid;
+       char host_version[QMI_WLANFW_MAX_STR_LEN_V01 + 1];
+       u8  tgt_cfg_valid;
+       u32  tgt_cfg_len;
+       struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01
+                       tgt_cfg[QMI_WLANFW_MAX_NUM_CE_V01];
+       u8  svc_cfg_valid;
+       u32 svc_cfg_len;
+       struct qmi_wlanfw_ce_svc_pipe_cfg_s_v01
+                       svc_cfg[QMI_WLANFW_MAX_NUM_SVC_V01];
+       u8 shadow_reg_valid;
+       u32 shadow_reg_len;
+       struct qmi_wlanfw_shadow_reg_cfg_s_v01
+               shadow_reg[QMI_WLANFW_MAX_NUM_SHADOW_REG_V01];
+       u8 shadow_reg_v2_valid;
+       u32 shadow_reg_v2_len;
+       struct qmi_wlanfw_shadow_reg_v2_cfg_s_v01
+               shadow_reg_v2[QMI_WLANFW_MAX_NUM_SHADOW_REG_V2_V01];
+};
+
+struct qmi_wlanfw_wlan_cfg_resp_msg_v01 {
+       struct qmi_response_type_v01 resp;
+};
+
+int ath11k_qmi_firmware_start(struct ath11k_base *ab,
+                             u32 mode);
+void ath11k_qmi_firmware_stop(struct ath11k_base *ab);
+void ath11k_qmi_event_work(struct work_struct *work);
+void ath11k_qmi_msg_recv_work(struct work_struct *work);
+void ath11k_qmi_deinit_service(struct ath11k_base *ab);
+int ath11k_qmi_init_service(struct ath11k_base *ab);
+
+#endif
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+#include "core.h"
+#include "debug.h"
+
+/* World regdom to be used in case default regd from fw is unavailable */
+#define ATH11K_2GHZ_CH01_11      REG_RULE(2412 - 10, 2462 + 10, 40, 0, 20, 0)
+#define ATH11K_5GHZ_5150_5350    REG_RULE(5150 - 10, 5350 + 10, 80, 0, 30,\
+                                         NL80211_RRF_NO_IR)
+#define ATH11K_5GHZ_5725_5850    REG_RULE(5725 - 10, 5850 + 10, 80, 0, 30,\
+                                         NL80211_RRF_NO_IR)
+
+#define ETSI_WEATHER_RADAR_BAND_LOW            5590
+#define ETSI_WEATHER_RADAR_BAND_HIGH           5650
+#define ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT    600000
+
+static const struct ieee80211_regdomain ath11k_world_regd = {
+       .n_reg_rules = 3,
+       .alpha2 =  "00",
+       .reg_rules = {
+               ATH11K_2GHZ_CH01_11,
+               ATH11K_5GHZ_5150_5350,
+               ATH11K_5GHZ_5725_5850,
+       }
+};
+
+static bool ath11k_regdom_changes(struct ath11k *ar, char *alpha2)
+{
+       const struct ieee80211_regdomain *regd;
+
+       regd = rcu_dereference_rtnl(ar->hw->wiphy->regd);
+       /* This can happen during wiphy registration where the previous
+        * user request is received before we update the regd received
+        * from firmware.
+        */
+       if (!regd)
+               return true;
+
+       return memcmp(regd->alpha2, alpha2, 2) != 0;
+}
+
+static void
+ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+{
+       struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+       struct wmi_init_country_params init_country_param;
+       struct ath11k *ar = hw->priv;
+       int ret;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_REG,
+                  "Regulatory Notification received for %s\n", wiphy_name(wiphy));
+
+       /* Currently supporting only General User Hints. Cell base user
+        * hints to be handled later.
+        * Hints from other sources like Core, Beacons are not expected for
+        * self managed wiphy's
+        */
+       if (!(request->initiator == NL80211_REGDOM_SET_BY_USER &&
+             request->user_reg_hint_type == NL80211_USER_REG_HINT_USER)) {
+               ath11k_warn(ar->ab, "Unexpected Regulatory event for this wiphy\n");
+               return;
+       }
+
+       if (!IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS)) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_REG,
+                          "Country Setting is not allowed\n");
+               return;
+       }
+
+       if (!ath11k_regdom_changes(ar, request->alpha2)) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_REG, "Country is already set\n");
+               return;
+       }
+
+       /* Set the country code to the firmware and wait for
+        * the WMI_REG_CHAN_LIST_CC EVENT for updating the
+        * reg info
+        */
+       init_country_param.flags = ALPHA_IS_SET;
+       memcpy(&init_country_param.cc_info.alpha2, request->alpha2, 2);
+
+       ret = ath11k_wmi_send_init_country_cmd(ar, init_country_param);
+       if (ret)
+               ath11k_warn(ar->ab,
+                           "INIT Country code set to fw failed : %d\n", ret);
+}
+
+int ath11k_reg_update_chan_list(struct ath11k *ar)
+{
+       struct ieee80211_supported_band **bands;
+       struct scan_chan_list_params *params;
+       struct ieee80211_channel *channel;
+       struct ieee80211_hw *hw = ar->hw;
+       struct channel_param *ch;
+       enum nl80211_band band;
+       int num_channels = 0;
+       int params_len;
+       int i, ret;
+
+       bands = hw->wiphy->bands;
+       for (band = 0; band < NUM_NL80211_BANDS; band++) {
+               if (!bands[band])
+                       continue;
+
+               for (i = 0; i < bands[band]->n_channels; i++) {
+                       if (bands[band]->channels[i].flags &
+                           IEEE80211_CHAN_DISABLED)
+                               continue;
+
+                       num_channels++;
+               }
+       }
+
+       if (WARN_ON(!num_channels))
+               return -EINVAL;
+
+       params_len = sizeof(struct scan_chan_list_params) +
+                       num_channels * sizeof(struct channel_param);
+       params = kzalloc(params_len, GFP_KERNEL);
+
+       if (!params)
+               return -ENOMEM;
+
+       params->pdev_id = ar->pdev->pdev_id;
+       params->nallchans = num_channels;
+
+       ch = params->ch_param;
+
+       for (band = 0; band < NUM_NL80211_BANDS; band++) {
+               if (!bands[band])
+                       continue;
+
+               for (i = 0; i < bands[band]->n_channels; i++) {
+                       channel = &bands[band]->channels[i];
+
+                       if (channel->flags & IEEE80211_CHAN_DISABLED)
+                               continue;
+
+                       /* TODO: Set to true/false based on some condition? */
+                       ch->allow_ht = true;
+                       ch->allow_vht = true;
+
+                       ch->dfs_set =
+                               !!(channel->flags & IEEE80211_CHAN_RADAR);
+                       ch->is_chan_passive = !!(channel->flags &
+                                               IEEE80211_CHAN_NO_IR);
+                       ch->is_chan_passive |= ch->dfs_set;
+                       ch->mhz = channel->center_freq;
+                       ch->cfreq1 = channel->center_freq;
+                       ch->minpower = 0;
+                       ch->maxpower = channel->max_power * 2;
+                       ch->maxregpower = channel->max_reg_power * 2;
+                       ch->antennamax = channel->max_antenna_gain * 2;
+
+                       /* TODO: Use appropriate phymodes */
+                       if (channel->band == NL80211_BAND_2GHZ)
+                               ch->phy_mode = MODE_11G;
+                       else
+                               ch->phy_mode = MODE_11A;
+
+                       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                                  "mac channel [%d/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n",
+                                  i, params->nallchans,
+                                  ch->mhz, ch->maxpower, ch->maxregpower,
+                                  ch->antennamax, ch->phy_mode);
+
+                       ch++;
+                       /* TODO: use quarrter/half rate, cfreq12, dfs_cfreq2
+                        * set_agile, reg_class_idx
+                        */
+               }
+       }
+
+       ret = ath11k_wmi_send_scan_chan_list_cmd(ar, params);
+       kfree(params);
+
+       return ret;
+}
+
+static void ath11k_copy_regd(struct ieee80211_regdomain *regd_orig,
+                            struct ieee80211_regdomain *regd_copy)
+{
+       u8 i;
+
+       /* The caller should have checked error conditions */
+       memcpy(regd_copy, regd_orig, sizeof(*regd_orig));
+
+       for (i = 0; i < regd_orig->n_reg_rules; i++)
+               memcpy(®d_copy->reg_rules[i], ®d_orig->reg_rules[i],
+                      sizeof(struct ieee80211_reg_rule));
+}
+
+int ath11k_regd_update(struct ath11k *ar, bool init)
+{
+       struct ieee80211_regdomain *regd, *regd_copy = NULL;
+       int ret, regd_len, pdev_id;
+       struct ath11k_base *ab;
+
+       ab = ar->ab;
+       pdev_id = ar->pdev_idx;
+
+       spin_lock(&ab->base_lock);
+
+       if (init) {
+               /* Apply the regd received during init through
+                * WMI_REG_CHAN_LIST_CC event. In case of failure to
+                * receive the regd, initialize with a default world
+                * regulatory.
+                */
+               if (ab->default_regd[pdev_id]) {
+                       regd = ab->default_regd[pdev_id];
+               } else {
+                       ath11k_warn(ab,
+                                   "failed to receive default regd during init\n");
+                       regd = (struct ieee80211_regdomain *)&ath11k_world_regd;
+               }
+       } else {
+               regd = ab->new_regd[pdev_id];
+       }
+
+       if (!regd) {
+               ret = -EINVAL;
+               spin_unlock(&ab->base_lock);
+               goto err;
+       }
+
+       regd_len = sizeof(*regd) + (regd->n_reg_rules *
+               sizeof(struct ieee80211_reg_rule));
+
+       regd_copy = kzalloc(regd_len, GFP_ATOMIC);
+       if (regd_copy)
+               ath11k_copy_regd(regd, regd_copy);
+
+       spin_unlock(&ab->base_lock);
+
+       if (!regd_copy) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       rtnl_lock();
+       ret = regulatory_set_wiphy_regd_sync_rtnl(ar->hw->wiphy, regd_copy);
+       rtnl_unlock();
+
+       kfree(regd_copy);
+
+       if (ret)
+               goto err;
+
+       if (ar->state == ATH11K_STATE_ON) {
+               ret = ath11k_reg_update_chan_list(ar);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+err:
+       ath11k_warn(ab, "failed to perform regd update : %d\n", ret);
+       return ret;
+}
+
+static enum nl80211_dfs_regions
+ath11k_map_fw_dfs_region(enum ath11k_dfs_region dfs_region)
+{
+       switch (dfs_region) {
+       case ATH11K_DFS_REG_FCC:
+       case ATH11K_DFS_REG_CN:
+               return NL80211_DFS_FCC;
+       case ATH11K_DFS_REG_ETSI:
+       case ATH11K_DFS_REG_KR:
+               return NL80211_DFS_ETSI;
+       case ATH11K_DFS_REG_MKK:
+               return NL80211_DFS_JP;
+       default:
+               return NL80211_DFS_UNSET;
+       }
+}
+
+static u32 ath11k_map_fw_reg_flags(u16 reg_flags)
+{
+       u32 flags = 0;
+
+       if (reg_flags & REGULATORY_CHAN_NO_IR)
+               flags = NL80211_RRF_NO_IR;
+
+       if (reg_flags & REGULATORY_CHAN_RADAR)
+               flags |= NL80211_RRF_DFS;
+
+       if (reg_flags & REGULATORY_CHAN_NO_OFDM)
+               flags |= NL80211_RRF_NO_OFDM;
+
+       if (reg_flags & REGULATORY_CHAN_INDOOR_ONLY)
+               flags |= NL80211_RRF_NO_OUTDOOR;
+
+       if (reg_flags & REGULATORY_CHAN_NO_HT40)
+               flags |= NL80211_RRF_NO_HT40;
+
+       if (reg_flags & REGULATORY_CHAN_NO_80MHZ)
+               flags |= NL80211_RRF_NO_80MHZ;
+
+       if (reg_flags & REGULATORY_CHAN_NO_160MHZ)
+               flags |= NL80211_RRF_NO_160MHZ;
+
+       return flags;
+}
+
+static bool
+ath11k_reg_can_intersect(struct ieee80211_reg_rule *rule1,
+                        struct ieee80211_reg_rule *rule2)
+{
+       u32 start_freq1, end_freq1;
+       u32 start_freq2, end_freq2;
+
+       start_freq1 = rule1->freq_range.start_freq_khz;
+       start_freq2 = rule2->freq_range.start_freq_khz;
+
+       end_freq1 = rule1->freq_range.end_freq_khz;
+       end_freq2 = rule2->freq_range.end_freq_khz;
+
+       if ((start_freq1 >= start_freq2 &&
+            start_freq1 < end_freq2) ||
+           (start_freq2 > start_freq1 &&
+            start_freq2 < end_freq1))
+               return true;
+
+       /* TODO: Should we restrict intersection feasibility
+        *  based on min bandwidth of the intersected region also,
+        *  say the intersected rule should have a  min bandwidth
+        * of 20MHz?
+        */
+
+       return false;
+}
+
+static void ath11k_reg_intersect_rules(struct ieee80211_reg_rule *rule1,
+                                      struct ieee80211_reg_rule *rule2,
+                                      struct ieee80211_reg_rule *new_rule)
+{
+       u32 start_freq1, end_freq1;
+       u32 start_freq2, end_freq2;
+       u32 freq_diff, max_bw;
+
+       start_freq1 = rule1->freq_range.start_freq_khz;
+       start_freq2 = rule2->freq_range.start_freq_khz;
+
+       end_freq1 = rule1->freq_range.end_freq_khz;
+       end_freq2 = rule2->freq_range.end_freq_khz;
+
+       new_rule->freq_range.start_freq_khz = max_t(u32, start_freq1,
+                                                   start_freq2);
+       new_rule->freq_range.end_freq_khz = min_t(u32, end_freq1, end_freq2);
+
+       freq_diff = new_rule->freq_range.end_freq_khz -
+                       new_rule->freq_range.start_freq_khz;
+       max_bw = min_t(u32, rule1->freq_range.max_bandwidth_khz,
+                      rule2->freq_range.max_bandwidth_khz);
+       new_rule->freq_range.max_bandwidth_khz = min_t(u32, max_bw, freq_diff);
+
+       new_rule->power_rule.max_antenna_gain =
+               min_t(u32, rule1->power_rule.max_antenna_gain,
+                     rule2->power_rule.max_antenna_gain);
+
+       new_rule->power_rule.max_eirp = min_t(u32, rule1->power_rule.max_eirp,
+                                             rule2->power_rule.max_eirp);
+
+       /* Use the flags of both the rules */
+       new_rule->flags = rule1->flags | rule2->flags;
+
+       /* 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);
+}
+
+static struct ieee80211_regdomain *
+ath11k_regd_intersect(struct ieee80211_regdomain *default_regd,
+                     struct ieee80211_regdomain *curr_regd)
+{
+       u8 num_old_regd_rules, num_curr_regd_rules, num_new_regd_rules;
+       struct ieee80211_reg_rule *old_rule, *curr_rule, *new_rule;
+       struct ieee80211_regdomain *new_regd = NULL;
+       u8 i, j, k;
+
+       num_old_regd_rules = default_regd->n_reg_rules;
+       num_curr_regd_rules = curr_regd->n_reg_rules;
+       num_new_regd_rules = 0;
+
+       /* Find the number of intersecting rules to allocate new regd memory */
+       for (i = 0; i < num_old_regd_rules; i++) {
+               old_rule = default_regd->reg_rules + i;
+               for (j = 0; j < num_curr_regd_rules; j++) {
+                       curr_rule = curr_regd->reg_rules + j;
+
+                       if (ath11k_reg_can_intersect(old_rule, curr_rule))
+                               num_new_regd_rules++;
+               }
+       }
+
+       if (!num_new_regd_rules)
+               return NULL;
+
+       new_regd = kzalloc(sizeof(*new_regd) + (num_new_regd_rules *
+                       sizeof(struct ieee80211_reg_rule)),
+                       GFP_ATOMIC);
+
+       if (!new_regd)
+               return NULL;
+
+       /* We set the new country and dfs region directly and only trim
+        * the freq, power, antenna gain by intersecting with the
+        * default regdomain. Also MAX of the dfs cac timeout is selected.
+        */
+       new_regd->n_reg_rules = num_new_regd_rules;
+       memcpy(new_regd->alpha2, curr_regd->alpha2, sizeof(new_regd->alpha2));
+       new_regd->dfs_region = curr_regd->dfs_region;
+       new_rule = new_regd->reg_rules;
+
+       for (i = 0, k = 0; i < num_old_regd_rules; i++) {
+               old_rule = default_regd->reg_rules + i;
+               for (j = 0; j < num_curr_regd_rules; j++) {
+                       curr_rule = curr_regd->reg_rules + j;
+
+                       if (ath11k_reg_can_intersect(old_rule, curr_rule))
+                               ath11k_reg_intersect_rules(old_rule, curr_rule,
+                                                          (new_rule + k++));
+               }
+       }
+       return new_regd;
+}
+
+static const char *
+ath11k_reg_get_regdom_str(enum nl80211_dfs_regions dfs_region)
+{
+       switch (dfs_region) {
+       case NL80211_DFS_FCC:
+               return "FCC";
+       case NL80211_DFS_ETSI:
+               return "ETSI";
+       case NL80211_DFS_JP:
+               return "JP";
+       default:
+               return "UNSET";
+       }
+}
+
+static u16
+ath11k_reg_adjust_bw(u16 start_freq, u16 end_freq, u16 max_bw)
+{
+       u16 bw;
+
+       bw = end_freq - start_freq;
+       bw = min_t(u16, bw, max_bw);
+
+       if (bw >= 80 && bw < 160)
+               bw = 80;
+       else if (bw >= 40 && bw < 80)
+               bw = 40;
+       else if (bw < 40)
+               bw = 20;
+
+       return 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)
+{
+       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->flags = reg_flags;
+}
+
+static void
+ath11k_reg_update_weather_radar_band(struct ath11k_base *ab,
+                                    struct ieee80211_regdomain *regd,
+                                    struct cur_reg_rule *reg_rule,
+                                    u8 *rule_idx, u32 flags, u16 max_bw)
+{
+       u32 end_freq;
+       u16 bw;
+       u8 i;
+
+       i = *rule_idx;
+
+       bw = ath11k_reg_adjust_bw(reg_rule->start_freq,
+                                 ETSI_WEATHER_RADAR_BAND_LOW, max_bw);
+
+       ath11k_reg_update_rule(regd->reg_rules + i, reg_rule->start_freq,
+                              ETSI_WEATHER_RADAR_BAND_LOW, bw,
+                              reg_rule->ant_gain, reg_rule->reg_power,
+                              flags);
+
+       ath11k_dbg(ab, ATH11K_DBG_REG,
+                  "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
+                  i + 1, reg_rule->start_freq, ETSI_WEATHER_RADAR_BAND_LOW,
+                  bw, reg_rule->ant_gain, reg_rule->reg_power,
+                  regd->reg_rules[i].dfs_cac_ms,
+                  flags);
+
+       if (reg_rule->end_freq > ETSI_WEATHER_RADAR_BAND_HIGH)
+               end_freq = ETSI_WEATHER_RADAR_BAND_HIGH;
+       else
+               end_freq = reg_rule->end_freq;
+
+       bw = ath11k_reg_adjust_bw(ETSI_WEATHER_RADAR_BAND_LOW, end_freq,
+                                 max_bw);
+
+       i++;
+
+       ath11k_reg_update_rule(regd->reg_rules + i,
+                              ETSI_WEATHER_RADAR_BAND_LOW, end_freq, bw,
+                              reg_rule->ant_gain, reg_rule->reg_power,
+                              flags);
+
+       regd->reg_rules[i].dfs_cac_ms = ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT;
+
+       ath11k_dbg(ab, ATH11K_DBG_REG,
+                  "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
+                  i + 1, ETSI_WEATHER_RADAR_BAND_LOW, end_freq,
+                  bw, reg_rule->ant_gain, reg_rule->reg_power,
+                  regd->reg_rules[i].dfs_cac_ms,
+                  flags);
+
+       if (end_freq == reg_rule->end_freq) {
+               regd->n_reg_rules--;
+               *rule_idx = i;
+               return;
+       }
+
+       bw = ath11k_reg_adjust_bw(ETSI_WEATHER_RADAR_BAND_HIGH,
+                                 reg_rule->end_freq, max_bw);
+
+       i++;
+
+       ath11k_reg_update_rule(regd->reg_rules + i, ETSI_WEATHER_RADAR_BAND_HIGH,
+                              reg_rule->end_freq, bw,
+                              reg_rule->ant_gain, reg_rule->reg_power,
+                              flags);
+
+       ath11k_dbg(ab, ATH11K_DBG_REG,
+                  "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
+                  i + 1, ETSI_WEATHER_RADAR_BAND_HIGH, reg_rule->end_freq,
+                  bw, reg_rule->ant_gain, reg_rule->reg_power,
+                  regd->reg_rules[i].dfs_cac_ms,
+                  flags);
+
+       *rule_idx = i;
+}
+
+struct ieee80211_regdomain *
+ath11k_reg_build_regd(struct ath11k_base *ab,
+                     struct cur_regulatory_info *reg_info, bool intersect)
+{
+       struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
+       struct cur_reg_rule *reg_rule;
+       u8 i = 0, j = 0;
+       u8 num_rules;
+       u16 max_bw;
+       u32 flags;
+       char alpha2[3];
+
+       num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules;
+
+       if (!num_rules)
+               goto ret;
+
+       /* Add max additional rules to accommodate weather radar band */
+       if (reg_info->dfs_region == ATH11K_DFS_REG_ETSI)
+               num_rules += 2;
+
+       tmp_regd =  kzalloc(sizeof(*tmp_regd) +
+                       (num_rules * sizeof(struct ieee80211_reg_rule)),
+                       GFP_ATOMIC);
+       if (!tmp_regd)
+               goto ret;
+
+       tmp_regd->n_reg_rules = num_rules;
+       memcpy(tmp_regd->alpha2, reg_info->alpha2, REG_ALPHA2_LEN + 1);
+       memcpy(alpha2, reg_info->alpha2, REG_ALPHA2_LEN + 1);
+       alpha2[2] = '\0';
+       tmp_regd->dfs_region = ath11k_map_fw_dfs_region(reg_info->dfs_region);
+
+       ath11k_dbg(ab, ATH11K_DBG_REG,
+                  "\r\nCountry %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n",
+                  alpha2, ath11k_reg_get_regdom_str(tmp_regd->dfs_region),
+                  reg_info->dfs_region, num_rules);
+       /* Update reg_rules[] below. Firmware is expected to
+        * send these rules in order(2G rules first and then 5G)
+        */
+       for (; i < tmp_regd->n_reg_rules; i++) {
+               if (reg_info->num_2g_reg_rules &&
+                   (i < reg_info->num_2g_reg_rules)) {
+                       reg_rule = reg_info->reg_rules_2g_ptr + i;
+                       max_bw = min_t(u16, reg_rule->max_bw,
+                                      reg_info->max_bw_2g);
+                       flags = 0;
+               } else if (reg_info->num_5g_reg_rules &&
+                          (j < reg_info->num_5g_reg_rules)) {
+                       reg_rule = reg_info->reg_rules_5g_ptr + j++;
+                       max_bw = min_t(u16, reg_rule->max_bw,
+                                      reg_info->max_bw_5g);
+
+                       /* FW doesn't pass NL80211_RRF_AUTO_BW flag for
+                        * BW Auto correction, we can enable this by default
+                        * for all 5G rules here. The regulatory core performs
+                        * BW correction if required and applies flags as
+                        * per other BW rule flags we pass from here
+                        */
+                       flags = NL80211_RRF_AUTO_BW;
+               } else {
+                       break;
+               }
+
+               flags |= ath11k_map_fw_reg_flags(reg_rule->flags);
+
+               ath11k_reg_update_rule(tmp_regd->reg_rules + i,
+                                      reg_rule->start_freq,
+                                      reg_rule->end_freq, max_bw,
+                                      reg_rule->ant_gain, reg_rule->reg_power,
+                                      flags);
+
+               /* Update dfs cac timeout if the dfs domain is ETSI and the
+                * new rule covers weather radar band.
+                * Default value of '0' corresponds to 60s timeout, so no
+                * need to update that for other rules.
+                */
+               if (flags & NL80211_RRF_DFS &&
+                   reg_info->dfs_region == ATH11K_DFS_REG_ETSI &&
+                   (reg_rule->end_freq > ETSI_WEATHER_RADAR_BAND_LOW &&
+                   reg_rule->start_freq < ETSI_WEATHER_RADAR_BAND_HIGH)){
+                       ath11k_reg_update_weather_radar_band(ab, tmp_regd,
+                                                            reg_rule, &i,
+                                                            flags, max_bw);
+                       continue;
+               }
+
+               ath11k_dbg(ab, ATH11K_DBG_REG,
+                          "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
+                          i + 1, reg_rule->start_freq, reg_rule->end_freq,
+                          max_bw, reg_rule->ant_gain, reg_rule->reg_power,
+                          tmp_regd->reg_rules[i].dfs_cac_ms,
+                          flags);
+       }
+
+       if (intersect) {
+               default_regd = ab->default_regd[reg_info->phy_id];
+
+               /* Get a new regd by intersecting the received regd with
+                * our default regd.
+                */
+               new_regd = ath11k_regd_intersect(default_regd, tmp_regd);
+               kfree(tmp_regd);
+               if (!new_regd) {
+                       ath11k_warn(ab, "Unable to create intersected regdomain\n");
+                       goto ret;
+               }
+       } else {
+               new_regd = tmp_regd;
+       }
+
+ret:
+       return new_regd;
+}
+
+void ath11k_regd_update_work(struct work_struct *work)
+{
+       struct ath11k *ar = container_of(work, struct ath11k,
+                                        regd_update_work);
+       int ret;
+
+       ret = ath11k_regd_update(ar, false);
+       if (ret) {
+               /* Firmware has already moved to the new regd. We need
+                * to maintain channel consistency across FW, Host driver
+                * and userspace. Hence as a fallback mechanism we can set
+                * the prev or default country code to the firmware.
+                */
+               /* TODO: Implement Fallback Mechanism */
+       }
+}
+
+void ath11k_reg_init(struct ath11k *ar)
+{
+       ar->hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED;
+       ar->hw->wiphy->reg_notifier = ath11k_reg_notifier;
+}
+
+void ath11k_reg_free(struct ath11k_base *ab)
+{
+       int i;
+
+       for (i = 0; i < MAX_RADIOS; i++) {
+               kfree(ab->default_regd[i]);
+               kfree(ab->new_regd[i]);
+       }
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_REG_H
+#define ATH11K_REG_H
+
+#include <linux/kernel.h>
+#include <net/regulatory.h>
+
+struct ath11k_base;
+struct ath11k;
+
+/* DFS regdomains supported by Firmware */
+enum ath11k_dfs_region {
+       ATH11K_DFS_REG_UNSET,
+       ATH11K_DFS_REG_FCC,
+       ATH11K_DFS_REG_ETSI,
+       ATH11K_DFS_REG_MKK,
+       ATH11K_DFS_REG_CN,
+       ATH11K_DFS_REG_KR,
+       ATH11K_DFS_REG_UNDEF,
+};
+
+/* ATH11K Regulatory API's */
+void ath11k_reg_init(struct ath11k *ar);
+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);
+int ath11k_regd_update(struct ath11k *ar, bool init);
+int ath11k_reg_update_chan_list(struct ath11k *ar);
+#endif
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+#ifndef ATH11K_RX_DESC_H
+#define ATH11K_RX_DESC_H
+
+enum rx_desc_rxpcu_filter {
+       RX_DESC_RXPCU_FILTER_PASS,
+       RX_DESC_RXPCU_FILTER_MONITOR_CLIENT,
+       RX_DESC_RXPCU_FILTER_MONITOR_OTHER,
+};
+
+/* rxpcu_filter_pass
+ *             This MPDU passed the normal frame filter programming of rxpcu.
+ *
+ * rxpcu_filter_monitor_client
+ *              This MPDU did not pass the regular frame filter and would
+ *              have been dropped, were it not for the frame fitting into the
+ *              'monitor_client' category.
+ *
+ * rxpcu_filter_monitor_other
+ *             This MPDU did not pass the regular frame filter and also did
+ *             not pass the rxpcu_monitor_client filter. It would have been
+ *             dropped accept that it did pass the 'monitor_other' category.
+ */
+
+#define RX_DESC_INFO0_RXPCU_MPDU_FITLER        GENMASK(1, 0)
+#define RX_DESC_INFO0_SW_FRAME_GRP_ID  GENMASK(8, 2)
+
+enum rx_desc_sw_frame_grp_id {
+       RX_DESC_SW_FRAME_GRP_ID_NDP_FRAME,
+       RX_DESC_SW_FRAME_GRP_ID_MCAST_DATA,
+       RX_DESC_SW_FRAME_GRP_ID_UCAST_DATA,
+       RX_DESC_SW_FRAME_GRP_ID_NULL_DATA,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_0000,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_0001,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_0010,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_0011,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_0100,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_0101,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_0110,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_0111,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_1000,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_1001,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_1010,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_1011,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_1100,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_1101,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_1110,
+       RX_DESC_SW_FRAME_GRP_ID_MGMT_1111,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_0000,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_0001,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_0010,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_0011,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_0100,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_0101,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_0110,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_0111,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_1000,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_1001,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_1010,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_1011,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_1100,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_1101,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_1110,
+       RX_DESC_SW_FRAME_GRP_ID_CTRL_1111,
+       RX_DESC_SW_FRAME_GRP_ID_UNSUPPORTED,
+       RX_DESC_SW_FRAME_GRP_ID_PHY_ERR,
+};
+
+enum rx_desc_decap_type {
+       RX_DESC_DECAP_TYPE_RAW,
+       RX_DESC_DECAP_TYPE_NATIVE_WIFI,
+       RX_DESC_DECAP_TYPE_ETHERNET2_DIX,
+       RX_DESC_DECAP_TYPE_8023,
+};
+
+enum rx_desc_decrypt_status_code {
+       RX_DESC_DECRYPT_STATUS_CODE_OK,
+       RX_DESC_DECRYPT_STATUS_CODE_UNPROTECTED_FRAME,
+       RX_DESC_DECRYPT_STATUS_CODE_DATA_ERR,
+       RX_DESC_DECRYPT_STATUS_CODE_KEY_INVALID,
+       RX_DESC_DECRYPT_STATUS_CODE_PEER_ENTRY_INVALID,
+       RX_DESC_DECRYPT_STATUS_CODE_OTHER,
+};
+
+#define RX_ATTENTION_INFO1_FIRST_MPDU          BIT(0)
+#define RX_ATTENTION_INFO1_RSVD_1A             BIT(1)
+#define RX_ATTENTION_INFO1_MCAST_BCAST         BIT(2)
+#define RX_ATTENTION_INFO1_AST_IDX_NOT_FOUND   BIT(3)
+#define RX_ATTENTION_INFO1_AST_IDX_TIMEDOUT    BIT(4)
+#define RX_ATTENTION_INFO1_POWER_MGMT          BIT(5)
+#define RX_ATTENTION_INFO1_NON_QOS             BIT(6)
+#define RX_ATTENTION_INFO1_NULL_DATA           BIT(7)
+#define RX_ATTENTION_INFO1_MGMT_TYPE           BIT(8)
+#define RX_ATTENTION_INFO1_CTRL_TYPE           BIT(9)
+#define RX_ATTENTION_INFO1_MORE_DATA           BIT(10)
+#define RX_ATTENTION_INFO1_EOSP                        BIT(11)
+#define RX_ATTENTION_INFO1_A_MSDU_ERROR                BIT(12)
+#define RX_ATTENTION_INFO1_FRAGMENT            BIT(13)
+#define RX_ATTENTION_INFO1_ORDER               BIT(14)
+#define RX_ATTENTION_INFO1_CCE_MATCH           BIT(15)
+#define RX_ATTENTION_INFO1_OVERFLOW_ERR                BIT(16)
+#define RX_ATTENTION_INFO1_MSDU_LEN_ERR                BIT(17)
+#define RX_ATTENTION_INFO1_TCP_UDP_CKSUM_FAIL  BIT(18)
+#define RX_ATTENTION_INFO1_IP_CKSUM_FAIL       BIT(19)
+#define RX_ATTENTION_INFO1_SA_IDX_INVALID      BIT(20)
+#define RX_ATTENTION_INFO1_DA_IDX_INVALID      BIT(21)
+#define RX_ATTENTION_INFO1_RSVD_1B             BIT(22)
+#define RX_ATTENTION_INFO1_RX_IN_TX_DECRYPT_BYP        BIT(23)
+#define RX_ATTENTION_INFO1_ENCRYPT_REQUIRED    BIT(24)
+#define RX_ATTENTION_INFO1_DIRECTED            BIT(25)
+#define RX_ATTENTION_INFO1_BUFFER_FRAGMENT     BIT(26)
+#define RX_ATTENTION_INFO1_MPDU_LEN_ERR                BIT(27)
+#define RX_ATTENTION_INFO1_TKIP_MIC_ERR                BIT(28)
+#define RX_ATTENTION_INFO1_DECRYPT_ERR         BIT(29)
+#define RX_ATTENTION_INFO1_UNDECRYPT_FRAME_ERR BIT(30)
+#define RX_ATTENTION_INFO1_FCS_ERR             BIT(31)
+
+#define RX_ATTENTION_INFO2_FLOW_IDX_TIMEOUT    BIT(0)
+#define RX_ATTENTION_INFO2_FLOW_IDX_INVALID    BIT(1)
+#define RX_ATTENTION_INFO2_WIFI_PARSER_ERR     BIT(2)
+#define RX_ATTENTION_INFO2_AMSDU_PARSER_ERR    BIT(3)
+#define RX_ATTENTION_INFO2_SA_IDX_TIMEOUT      BIT(4)
+#define RX_ATTENTION_INFO2_DA_IDX_TIMEOUT      BIT(5)
+#define RX_ATTENTION_INFO2_MSDU_LIMIT_ERR      BIT(6)
+#define RX_ATTENTION_INFO2_DA_IS_VALID         BIT(7)
+#define RX_ATTENTION_INFO2_DA_IS_MCBC          BIT(8)
+#define RX_ATTENTION_INFO2_SA_IS_VALID         BIT(9)
+#define RX_ATTENTION_INFO2_DCRYPT_STATUS_CODE  GENMASK(12, 10)
+#define RX_ATTENTION_INFO2_RX_BITMAP_NOT_UPDED BIT(13)
+#define RX_ATTENTION_INFO2_MSDU_DONE           BIT(31)
+
+struct rx_attention {
+       __le16 info0;
+       __le16 phy_ppdu_id;
+       __le32 info1;
+       __le32 info2;
+} __packed;
+
+/* rx_attention
+ *
+ * rxpcu_mpdu_filter_in_category
+ *             Field indicates what the reason was that this mpdu frame
+ *             was allowed to come into the receive path by rxpcu. Values
+ *             are defined in enum %RX_DESC_RXPCU_FILTER_*.
+ *
+ * sw_frame_group_id
+ *             SW processes frames based on certain classifications. Values
+ *             are defined in enum %RX_DESC_SW_FRAME_GRP_ID_*.
+ *
+ * phy_ppdu_id
+ *             A ppdu counter value that PHY increments for every PPDU
+ *             received. The counter value wraps around.
+ *
+ * first_mpdu
+ *             Indicates the first MSDU of the PPDU.  If both first_mpdu
+ *             and last_mpdu are set in the MSDU then this is a not an
+ *             A-MPDU frame but a stand alone MPDU.  Interior MPDU in an
+ *             A-MPDU shall have both first_mpdu and last_mpdu bits set to
+ *             0.  The PPDU start status will only be valid when this bit
+ *             is set.
+ *
+ * mcast_bcast
+ *             Multicast / broadcast indicator.  Only set when the MAC
+ *             address 1 bit 0 is set indicating mcast/bcast and the BSSID
+ *             matches one of the 4 BSSID registers. Only set when
+ *             first_msdu is set.
+ *
+ * ast_index_not_found
+ *             Only valid when first_msdu is set. Indicates no AST matching
+ *             entries within the the max search count.
+ *
+ * ast_index_timeout
+ *             Only valid when first_msdu is set. Indicates an unsuccessful
+ *             search in the address search table due to timeout.
+ *
+ * power_mgmt
+ *             Power management bit set in the 802.11 header.  Only set
+ *             when first_msdu is set.
+ *
+ * non_qos
+ *             Set if packet is not a non-QoS data frame.  Only set when
+ *             first_msdu is set.
+ *
+ * null_data
+ *             Set if frame type indicates either null data or QoS null
+ *             data format.  Only set when first_msdu is set.
+ *
+ * mgmt_type
+ *             Set if packet is a management packet.  Only set when
+ *             first_msdu is set.
+ *
+ * ctrl_type
+ *             Set if packet is a control packet.  Only set when first_msdu
+ *             is set.
+ *
+ * more_data
+ *             Set if more bit in frame control is set.  Only set when
+ *             first_msdu is set.
+ *
+ * eosp
+ *             Set if the EOSP (end of service period) bit in the QoS
+ *             control field is set.  Only set when first_msdu is set.
+ *
+ * a_msdu_error
+ *             Set if number of MSDUs in A-MSDU is above a threshold or if the
+ *             size of the MSDU is invalid. This receive buffer will contain
+ *             all of the remainder of MSDUs in this MPDU w/o decapsulation.
+ *
+ * fragment
+ *             Indicates that this is an 802.11 fragment frame.  This is
+ *             set when either the more_frag bit is set in the frame
+ *             control or the fragment number is not zero.  Only set when
+ *             first_msdu is set.
+ *
+ * order
+ *             Set if the order bit in the frame control is set.  Only set
+ *             when first_msdu is set.
+ *
+ * cce_match
+ *             Indicates that this status has a corresponding MSDU that
+ *             requires FW processing. The OLE will have classification
+ *             ring mask registers which will indicate the ring(s) for
+ *             packets and descriptors which need FW attention.
+ *
+ * overflow_err
+ *             PCU Receive FIFO does not have enough space to store the
+ *             full receive packet.  Enough space is reserved in the
+ *             receive FIFO for the status is written.  This MPDU remaining
+ *             packets in the PPDU will be filtered and no Ack response
+ *             will be transmitted.
+ *
+ * msdu_length_err
+ *             Indicates that the MSDU length from the 802.3 encapsulated
+ *             length field extends beyond the MPDU boundary.
+ *
+ * tcp_udp_chksum_fail
+ *             Indicates that the computed checksum (tcp_udp_chksum) did
+ *             not match the checksum in the TCP/UDP header.
+ *
+ * ip_chksum_fail
+ *             Indicates that the computed checksum did not match the
+ *             checksum in the IP header.
+ *
+ * sa_idx_invalid
+ *             Indicates no matching entry was found in the address search
+ *             table for the source MAC address.
+ *
+ * da_idx_invalid
+ *             Indicates no matching entry was found in the address search
+ *             table for the destination MAC address.
+ *
+ * rx_in_tx_decrypt_byp
+ *             Indicates that RX packet is not decrypted as Crypto is busy
+ *             with TX packet processing.
+ *
+ * encrypt_required
+ *             Indicates that this data type frame is not encrypted even if
+ *             the policy for this MPDU requires encryption as indicated in
+ *             the peer table key type.
+ *
+ * directed
+ *             MPDU is a directed packet which means that the RA matched
+ *             our STA addresses.  In proxySTA it means that the TA matched
+ *             an entry in our address search table with the corresponding
+ *             'no_ack' bit is the address search entry cleared.
+ *
+ * buffer_fragment
+ *             Indicates that at least one of the rx buffers has been
+ *             fragmented.  If set the FW should look at the rx_frag_info
+ *             descriptor described below.
+ *
+ * mpdu_length_err
+ *             Indicates that the MPDU was pre-maturely terminated
+ *             resulting in a truncated MPDU.  Don't trust the MPDU length
+ *             field.
+ *
+ * tkip_mic_err
+ *             Indicates that the MPDU Michael integrity check failed
+ *
+ * decrypt_err
+ *             Indicates that the MPDU decrypt integrity check failed
+ *
+ * fcs_err
+ *             Indicates that the MPDU FCS check failed
+ *
+ * flow_idx_timeout
+ *             Indicates an unsuccessful flow search due to the expiring of
+ *             the search timer.
+ *
+ * flow_idx_invalid
+ *             flow id is not valid.
+ *
+ * amsdu_parser_error
+ *             A-MSDU could not be properly de-agregated.
+ *
+ * sa_idx_timeout
+ *             Indicates an unsuccessful search for the source MAC address
+ *             due to the expiring of the search timer.
+ *
+ * da_idx_timeout
+ *             Indicates an unsuccessful search for the destination MAC
+ *             address due to the expiring of the search timer.
+ *
+ * msdu_limit_error
+ *             Indicates that the MSDU threshold was exceeded and thus
+ *             all the rest of the MSDUs will not be scattered and will not
+ *             be decasulated but will be DMA'ed in RAW format as a single
+ *             MSDU buffer.
+ *
+ * da_is_valid
+ *             Indicates that OLE found a valid DA entry.
+ *
+ * da_is_mcbc
+ *             Field Only valid if da_is_valid is set. Indicates the DA address
+ *             was a Multicast or Broadcast address.
+ *
+ * sa_is_valid
+ *             Indicates that OLE found a valid SA entry.
+ *
+ * decrypt_status_code
+ *             Field provides insight into the decryption performed. Values are
+ *             defined in enum %RX_DESC_DECRYPT_STATUS_CODE*.
+ *
+ * rx_bitmap_not_updated
+ *             Frame is received, but RXPCU could not update the receive bitmap
+ *             due to (temporary) fifo constraints.
+ *
+ * msdu_done
+ *             If set indicates that the RX packet data, RX header data, RX
+ *             PPDU start descriptor, RX MPDU start/end descriptor, RX MSDU
+ *             start/end descriptors and RX Attention descriptor are all
+ *             valid.  This bit must be in the last octet of the
+ *             descriptor.
+ */
+
+#define RX_MPDU_START_INFO0_NDP_FRAME          BIT(9)
+#define RX_MPDU_START_INFO0_PHY_ERR            BIT(10)
+#define RX_MPDU_START_INFO0_PHY_ERR_MPDU_HDR   BIT(11)
+#define RX_MPDU_START_INFO0_PROTO_VER_ERR      BIT(12)
+#define RX_MPDU_START_INFO0_AST_LOOKUP_VALID   BIT(13)
+
+#define RX_MPDU_START_INFO1_MPDU_CTRL_VALID    BIT(0)
+#define RX_MPDU_START_INFO1_MPDU_DUR_VALID     BIT(1)
+#define RX_MPDU_START_INFO1_MAC_ADDR1_VALID    BIT(2)
+#define RX_MPDU_START_INFO1_MAC_ADDR2_VALID    BIT(3)
+#define RX_MPDU_START_INFO1_MAC_ADDR3_VALID    BIT(4)
+#define RX_MPDU_START_INFO1_MAC_ADDR4_VALID    BIT(5)
+#define RX_MPDU_START_INFO1_MPDU_SEQ_CTRL_VALID        BIT(6)
+#define RX_MPDU_START_INFO1_MPDU_QOS_CTRL_VALID        BIT(7)
+#define RX_MPDU_START_INFO1_MPDU_HT_CTRL_VALID BIT(8)
+#define RX_MPDU_START_INFO1_ENCRYPT_INFO_VALID BIT(9)
+#define RX_MPDU_START_INFO1_MPDU_FRAG_NUMBER   GENMASK(13, 10)
+#define RX_MPDU_START_INFO1_MORE_FRAG_FLAG     BIT(14)
+#define RX_MPDU_START_INFO1_FROM_DS            BIT(16)
+#define RX_MPDU_START_INFO1_TO_DS              BIT(17)
+#define RX_MPDU_START_INFO1_ENCRYPTED          BIT(18)
+#define RX_MPDU_START_INFO1_MPDU_RETRY         BIT(19)
+#define RX_MPDU_START_INFO1_MPDU_SEQ_NUM       GENMASK(31, 20)
+
+#define RX_MPDU_START_INFO2_EPD_EN             BIT(0)
+#define RX_MPDU_START_INFO2_ALL_FRAME_ENCPD    BIT(1)
+#define RX_MPDU_START_INFO2_ENC_TYPE           GENMASK(5, 2)
+#define RX_MPDU_START_INFO2_VAR_WEP_KEY_WIDTH  GENMASK(7, 6)
+#define RX_MPDU_START_INFO2_MESH_STA           BIT(8)
+#define RX_MPDU_START_INFO2_BSSID_HIT          BIT(9)
+#define RX_MPDU_START_INFO2_BSSID_NUM          GENMASK(13, 10)
+#define RX_MPDU_START_INFO2_TID                        GENMASK(17, 14)
+
+#define RX_MPDU_START_INFO3_REO_DEST_IND               GENMASK(4, 0)
+#define RX_MPDU_START_INFO3_FLOW_ID_TOEPLITZ           BIT(7)
+#define RX_MPDU_START_INFO3_PKT_SEL_FP_UCAST_DATA      BIT(8)
+#define RX_MPDU_START_INFO3_PKT_SEL_FP_MCAST_DATA      BIT(9)
+#define RX_MPDU_START_INFO3_PKT_SEL_FP_CTRL_BAR                BIT(10)
+#define RX_MPDU_START_INFO3_RXDMA0_SRC_RING_SEL                GENMASK(12, 11)
+#define RX_MPDU_START_INFO3_RXDMA0_DST_RING_SEL                GENMASK(14, 13)
+
+#define RX_MPDU_START_INFO4_REO_QUEUE_DESC_HI  GENMASK(7, 0)
+#define RX_MPDU_START_INFO4_RECV_QUEUE_NUM     GENMASK(23, 8)
+#define RX_MPDU_START_INFO4_PRE_DELIM_ERR_WARN BIT(24)
+#define RX_MPDU_START_INFO4_FIRST_DELIM_ERR    BIT(25)
+
+#define RX_MPDU_START_INFO5_KEY_ID             GENMASK(7, 0)
+#define RX_MPDU_START_INFO5_NEW_PEER_ENTRY     BIT(8)
+#define RX_MPDU_START_INFO5_DECRYPT_NEEDED     BIT(9)
+#define RX_MPDU_START_INFO5_DECAP_TYPE         GENMASK(11, 10)
+#define RX_MPDU_START_INFO5_VLAN_TAG_C_PADDING BIT(12)
+#define RX_MPDU_START_INFO5_VLAN_TAG_S_PADDING BIT(13)
+#define RX_MPDU_START_INFO5_STRIP_VLAN_TAG_C   BIT(14)
+#define RX_MPDU_START_INFO5_STRIP_VLAN_TAG_S   BIT(15)
+#define RX_MPDU_START_INFO5_PRE_DELIM_COUNT    GENMASK(27, 16)
+#define RX_MPDU_START_INFO5_AMPDU_FLAG         BIT(28)
+#define RX_MPDU_START_INFO5_BAR_FRAME          BIT(29)
+
+#define RX_MPDU_START_INFO6_MPDU_LEN           GENMASK(13, 0)
+#define RX_MPDU_START_INFO6_FIRST_MPDU         BIT(14)
+#define RX_MPDU_START_INFO6_MCAST_BCAST                BIT(15)
+#define RX_MPDU_START_INFO6_AST_IDX_NOT_FOUND  BIT(16)
+#define RX_MPDU_START_INFO6_AST_IDX_TIMEOUT    BIT(17)
+#define RX_MPDU_START_INFO6_POWER_MGMT         BIT(18)
+#define RX_MPDU_START_INFO6_NON_QOS            BIT(19)
+#define RX_MPDU_START_INFO6_NULL_DATA          BIT(20)
+#define RX_MPDU_START_INFO6_MGMT_TYPE          BIT(21)
+#define RX_MPDU_START_INFO6_CTRL_TYPE          BIT(22)
+#define RX_MPDU_START_INFO6_MORE_DATA          BIT(23)
+#define RX_MPDU_START_INFO6_EOSP               BIT(24)
+#define RX_MPDU_START_INFO6_FRAGMENT           BIT(25)
+#define RX_MPDU_START_INFO6_ORDER              BIT(26)
+#define RX_MPDU_START_INFO6_UAPSD_TRIGGER      BIT(27)
+#define RX_MPDU_START_INFO6_ENCRYPT_REQUIRED   BIT(28)
+#define RX_MPDU_START_INFO6_DIRECTED           BIT(29)
+
+#define RX_MPDU_START_RAW_MPDU                 BIT(0)
+
+struct rx_mpdu_start {
+       __le16 info0;
+       __le16 phy_ppdu_id;
+       __le16 ast_index;
+       __le16 sw_peer_id;
+       __le32 info1;
+       __le32 info2;
+       __le32 pn[4];
+       __le32 peer_meta_data;
+       __le32 info3;
+       __le32 reo_queue_desc_lo;
+       __le32 info4;
+       __le32 info5;
+       __le32 info6;
+       __le16 frame_ctrl;
+       __le16 duration;
+       u8 addr1[ETH_ALEN];
+       u8 addr2[ETH_ALEN];
+       u8 addr3[ETH_ALEN];
+       __le16 seq_ctrl;
+       u8 addr4[ETH_ALEN];
+       __le16 qos_ctrl;
+       __le32 ht_ctrl;
+       __le32 raw;
+} __packed;
+
+/* rx_mpdu_start
+ *
+ * rxpcu_mpdu_filter_in_category
+ *             Field indicates what the reason was that this mpdu frame
+ *             was allowed to come into the receive path by rxpcu. Values
+ *             are defined in enum %RX_DESC_RXPCU_FILTER_*.
+ *             Note: for ndp frame, if it was expected because the preceding
+ *             NDPA was filter_pass, the setting rxpcu_filter_pass will be
+ *             used. This setting will also be used for every ndp frame in
+ *             case Promiscuous mode is enabled.
+ *
+ * sw_frame_group_id
+ *             SW processes frames based on certain classifications. Values
+ *             are defined in enum %RX_DESC_SW_FRAME_GRP_ID_*.
+ *
+ * ndp_frame
+ *             Indicates that the received frame was an NDP frame.
+ *
+ * phy_err
+ *             Indicates that PHY error was received before MAC received data.
+ *
+ * phy_err_during_mpdu_header
+ *             PHY error was received before MAC received the complete MPDU
+ *             header which was needed for proper decoding.
+ *
+ * protocol_version_err
+ *             RXPCU detected a version error in the frame control field.
+ *
+ * ast_based_lookup_valid
+ *             AST based lookup for this frame has found a valid result.
+ *
+ * phy_ppdu_id
+ *             A ppdu counter value that PHY increments for every PPDU
+ *             received. The counter value wraps around.
+ *
+ * ast_index
+ *             This field indicates the index of the AST entry corresponding
+ *             to this MPDU. It is provided by the GSE module instantiated in
+ *             RXPCU. A value of 0xFFFF indicates an invalid AST index.
+ *
+ * sw_peer_id
+ *             This field indicates a unique peer identifier. It is set equal
+ *             to field 'sw_peer_id' from the AST entry.
+ *
+ * mpdu_frame_control_valid, mpdu_duration_valid, mpdu_qos_control_valid,
+ * mpdu_ht_control_valid, frame_encryption_info_valid
+ *             Indicates that each fields have valid entries.
+ *
+ * mac_addr_adx_valid
+ *             Corresponding mac_addr_adx_{lo/hi} has valid entries.
+ *
+ * from_ds, to_ds
+ *             Valid only when mpdu_frame_control_valid is set. Indicates that
+ *             frame is received from DS and sent to DS.
+ *
+ * encrypted
+ *             Protected bit from the frame control.
+ *
+ * mpdu_retry
+ *             Retry bit from frame control. Only valid when first_msdu is set.
+ *
+ * mpdu_sequence_number
+ *             The sequence number from the 802.11 header.
+ *
+ * epd_en
+ *             If set, use EPD instead of LPD.
+ *
+ * all_frames_shall_be_encrypted
+ *             If set, all frames (data only?) shall be encrypted. If not,
+ *             RX CRYPTO shall set an error flag.
+ *
+ * encrypt_type
+ *             Values are defined in enum %HAL_ENCRYPT_TYPE_.
+ *
+ * mesh_sta
+ *             Indicates a Mesh (11s) STA.
+ *
+ * bssid_hit
+ *              BSSID of the incoming frame matched one of the 8 BSSID
+ *              register values.
+ *
+ * bssid_number
+ *             This number indicates which one out of the 8 BSSID register
+ *             values matched the incoming frame.
+ *
+ * tid
+ *             TID field in the QoS control field
+ *
+ * pn
+ *             The PN number.
+ *
+ * peer_meta_data
+ *             Meta data that SW has programmed in the Peer table entry
+ *             of the transmitting STA.
+ *
+ * rx_reo_queue_desc_addr_lo
+ *             Address (lower 32 bits) of the REO queue descriptor.
+ *
+ * rx_reo_queue_desc_addr_hi
+ *             Address (upper 8 bits) of the REO queue descriptor.
+ *
+ * receive_queue_number
+ *             Indicates the MPDU queue ID to which this MPDU link
+ *             descriptor belongs.
+ *
+ * pre_delim_err_warning
+ *             Indicates that a delimiter FCS error was found in between the
+ *             previous MPDU and this MPDU. Note that this is just a warning,
+ *             and does not mean that this MPDU is corrupted in any way. If
+ *             it is, there will be other errors indicated such as FCS or
+ *             decrypt errors.
+ *
+ * first_delim_err
+ *             Indicates that the first delimiter had a FCS failure.
+ *
+ * key_id
+ *             The key ID octet from the IV.
+ *
+ * new_peer_entry
+ *             Set if new RX_PEER_ENTRY TLV follows. If clear, RX_PEER_ENTRY
+ *             doesn't follow so RX DECRYPTION module either uses old peer
+ *             entry or not decrypt.
+ *
+ * decrypt_needed
+ *             When RXPCU sets bit 'ast_index_not_found or ast_index_timeout',
+ *             RXPCU will also ensure that this bit is NOT set. CRYPTO for that
+ *             reason only needs to evaluate this bit and non of the other ones
+ *
+ * decap_type
+ *             Used by the OLE during decapsulation. Values are defined in
+ *             enum %MPDU_START_DECAP_TYPE_*.
+ *
+ * rx_insert_vlan_c_tag_padding
+ * rx_insert_vlan_s_tag_padding
+ *             Insert 4 byte of all zeros as VLAN tag or double VLAN tag if
+ *             the rx payload does not have VLAN.
+ *
+ * strip_vlan_c_tag_decap
+ * strip_vlan_s_tag_decap
+ *             Strip VLAN or double VLAN during decapsulation.
+ *
+ * pre_delim_count
+ *             The number of delimiters before this MPDU. Note that this
+ *             number is cleared at PPDU start. If this MPDU is the first
+ *             received MPDU in the PPDU and this MPDU gets filtered-in,
+ *             this field will indicate the number of delimiters located
+ *             after the last MPDU in the previous PPDU.
+ *
+ *             If this MPDU is located after the first received MPDU in
+ *             an PPDU, this field will indicate the number of delimiters
+ *             located between the previous MPDU and this MPDU.
+ *
+ * ampdu_flag
+ *             Received frame was part of an A-MPDU.
+ *
+ * bar_frame
+ *             Received frame is a BAR frame
+ *
+ * mpdu_length
+ *             MPDU length before decapsulation.
+ *
+ * first_mpdu..directed
+ *             See definition in RX attention descriptor
+ *
+ */
+
+enum rx_msdu_start_pkt_type {
+       RX_MSDU_START_PKT_TYPE_11A,
+       RX_MSDU_START_PKT_TYPE_11B,
+       RX_MSDU_START_PKT_TYPE_11N,
+       RX_MSDU_START_PKT_TYPE_11AC,
+       RX_MSDU_START_PKT_TYPE_11AX,
+};
+
+enum rx_msdu_start_sgi {
+       RX_MSDU_START_SGI_0_8_US,
+       RX_MSDU_START_SGI_0_4_US,
+       RX_MSDU_START_SGI_1_6_US,
+       RX_MSDU_START_SGI_3_2_US,
+};
+
+enum rx_msdu_start_recv_bw {
+       RX_MSDU_START_RECV_BW_20MHZ,
+       RX_MSDU_START_RECV_BW_40MHZ,
+       RX_MSDU_START_RECV_BW_80MHZ,
+       RX_MSDU_START_RECV_BW_160MHZ,
+};
+
+enum rx_msdu_start_reception_type {
+       RX_MSDU_START_RECEPTION_TYPE_SU,
+       RX_MSDU_START_RECEPTION_TYPE_DL_MU_MIMO,
+       RX_MSDU_START_RECEPTION_TYPE_DL_MU_OFDMA,
+       RX_MSDU_START_RECEPTION_TYPE_DL_MU_OFDMA_MIMO,
+       RX_MSDU_START_RECEPTION_TYPE_UL_MU_MIMO,
+       RX_MSDU_START_RECEPTION_TYPE_UL_MU_OFDMA,
+       RX_MSDU_START_RECEPTION_TYPE_UL_MU_OFDMA_MIMO,
+};
+
+#define RX_MSDU_START_INFO1_MSDU_LENGTH                GENMASK(13, 0)
+#define RX_MSDU_START_INFO1_RSVD_1A            BIT(14)
+#define RX_MSDU_START_INFO1_IPSEC_ESP          BIT(15)
+#define RX_MSDU_START_INFO1_L3_OFFSET          GENMASK(22, 16)
+#define RX_MSDU_START_INFO1_IPSEC_AH           BIT(23)
+#define RX_MSDU_START_INFO1_L4_OFFSET          GENMASK(31, 24)
+
+#define RX_MSDU_START_INFO2_MSDU_NUMBER                GENMASK(7, 0)
+#define RX_MSDU_START_INFO2_DECAP_TYPE         GENMASK(9, 8)
+#define RX_MSDU_START_INFO2_IPV4               BIT(10)
+#define RX_MSDU_START_INFO2_IPV6               BIT(11)
+#define RX_MSDU_START_INFO2_TCP                        BIT(12)
+#define RX_MSDU_START_INFO2_UDP                        BIT(13)
+#define RX_MSDU_START_INFO2_IP_FRAG            BIT(14)
+#define RX_MSDU_START_INFO2_TCP_ONLY_ACK       BIT(15)
+#define RX_MSDU_START_INFO2_DA_IS_BCAST_MCAST  BIT(16)
+#define RX_MSDU_START_INFO2_SELECTED_TOEPLITZ_HASH     GENMASK(18, 17)
+#define RX_MSDU_START_INFO2_IP_FIXED_HDR_VALID         BIT(19)
+#define RX_MSDU_START_INFO2_IP_EXTN_HDR_VALID          BIT(20)
+#define RX_MSDU_START_INFO2_IP_TCP_UDP_HDR_VALID       BIT(21)
+#define RX_MSDU_START_INFO2_MESH_CTRL_PRESENT          BIT(22)
+#define RX_MSDU_START_INFO2_LDPC                       BIT(23)
+#define RX_MSDU_START_INFO2_IP4_IP6_NXT_HDR            GENMASK(31, 24)
+#define RX_MSDU_START_INFO2_DECAP_FORMAT               GENMASK(9, 8)
+
+#define RX_MSDU_START_INFO3_USER_RSSI          GENMASK(7, 0)
+#define RX_MSDU_START_INFO3_PKT_TYPE           GENMASK(11, 8)
+#define RX_MSDU_START_INFO3_STBC               BIT(12)
+#define RX_MSDU_START_INFO3_SGI                        GENMASK(14, 13)
+#define RX_MSDU_START_INFO3_RATE_MCS           GENMASK(18, 15)
+#define RX_MSDU_START_INFO3_RECV_BW            GENMASK(20, 19)
+#define RX_MSDU_START_INFO3_RECEPTION_TYPE     GENMASK(23, 21)
+#define RX_MSDU_START_INFO3_MIMO_SS_BITMAP     GENMASK(31, 24)
+
+struct rx_msdu_start {
+       __le16 info0;
+       __le16 phy_ppdu_id;
+       __le32 info1;
+       __le32 info2;
+       __le32 toeplitz_hash;
+       __le32 flow_id_toeplitz;
+       __le32 info3;
+       __le32 ppdu_start_timestamp;
+       __le32 phy_meta_data;
+} __packed;
+
+/* rx_msdu_start
+ *
+ * rxpcu_mpdu_filter_in_category
+ *             Field indicates what the reason was that this mpdu frame
+ *             was allowed to come into the receive path by rxpcu. Values
+ *             are defined in enum %RX_DESC_RXPCU_FILTER_*.
+ *
+ * sw_frame_group_id
+ *             SW processes frames based on certain classifications. Values
+ *             are defined in enum %RX_DESC_SW_FRAME_GRP_ID_*.
+ *
+ * phy_ppdu_id
+ *             A ppdu counter value that PHY increments for every PPDU
+ *             received. The counter value wraps around.
+ *
+ * msdu_length
+ *             MSDU length in bytes after decapsulation.
+ *
+ * ipsec_esp
+ *             Set if IPv4/v6 packet is using IPsec ESP.
+ *
+ * l3_offset
+ *             Depending upon mode bit, this field either indicates the
+ *             L3 offset in bytes from the start of the RX_HEADER or the IP
+ *             offset in bytes from the start of the packet after
+ *             decapsulation. The latter is only valid if ipv4_proto or
+ *             ipv6_proto is set.
+ *
+ * ipsec_ah
+ *             Set if IPv4/v6 packet is using IPsec AH
+ *
+ * l4_offset
+ *             Depending upon mode bit, this field either indicates the
+ *             L4 offset nin bytes from the start of RX_HEADER (only valid
+ *             if either ipv4_proto or ipv6_proto is set to 1) or indicates
+ *             the offset in bytes to the start of TCP or UDP header from
+ *             the start of the IP header after decapsulation (Only valid if
+ *             tcp_proto or udp_proto is set). The value 0 indicates that
+ *             the offset is longer than 127 bytes.
+ *
+ * msdu_number
+ *             Indicates the MSDU number within a MPDU.  This value is
+ *             reset to zero at the start of each MPDU.  If the number of
+ *             MSDU exceeds 255 this number will wrap using modulo 256.
+ *
+ * decap_type
+ *             Indicates the format after decapsulation. Values are defined in
+ *             enum %MPDU_START_DECAP_TYPE_*.
+ *
+ * ipv4_proto
+ *             Set if L2 layer indicates IPv4 protocol.
+ *
+ * ipv6_proto
+ *             Set if L2 layer indicates IPv6 protocol.
+ *
+ * tcp_proto
+ *             Set if the ipv4_proto or ipv6_proto are set and the IP protocol
+ *             indicates TCP.
+ *
+ * udp_proto
+ *             Set if the ipv4_proto or ipv6_proto are set and the IP protocol
+ *             indicates UDP.
+ *
+ * ip_frag
+ *             Indicates that either the IP More frag bit is set or IP frag
+ *             number is non-zero.  If set indicates that this is a fragmented
+ *             IP packet.
+ *
+ * tcp_only_ack
+ *             Set if only the TCP Ack bit is set in the TCP flags and if
+ *             the TCP payload is 0.
+ *
+ * da_is_bcast_mcast
+ *             The destination address is broadcast or multicast.
+ *
+ * toeplitz_hash
+ *             Actual chosen Hash.
+ *             0 - Toeplitz hash of 2-tuple (IP source address, IP
+ *                 destination address)
+ *             1 - Toeplitz hash of 4-tuple (IP source address,
+ *                 IP destination address, L4 (TCP/UDP) source port,
+ *                 L4 (TCP/UDP) destination port)
+ *             2 - Toeplitz of flow_id
+ *             3 - Zero is used
+ *
+ * ip_fixed_header_valid
+ *             Fixed 20-byte IPv4 header or 40-byte IPv6 header parsed
+ *             fully within first 256 bytes of the packet
+ *
+ * ip_extn_header_valid
+ *             IPv6/IPv6 header, including IPv4 options and
+ *             recognizable extension headers parsed fully within first 256
+ *             bytes of the packet
+ *
+ * tcp_udp_header_valid
+ *             Fixed 20-byte TCP (excluding TCP options) or 8-byte UDP
+ *             header parsed fully within first 256 bytes of the packet
+ *
+ * mesh_control_present
+ *             When set, this MSDU includes the 'Mesh Control' field
+ *
+ * ldpc
+ *
+ * ip4_protocol_ip6_next_header
+ *             For IPv4, this is the 8 bit protocol field set). For IPv6 this
+ *             is the 8 bit next_header field.
+ *
+ * toeplitz_hash_2_or_4
+ *             Controlled by RxOLE register - If register bit set to 0,
+ *             Toeplitz hash is computed over 2-tuple IPv4 or IPv6 src/dest
+ *             addresses; otherwise, toeplitz hash is computed over 4-tuple
+ *             IPv4 or IPv6 src/dest addresses and src/dest ports.
+ *
+ * flow_id_toeplitz
+ *             Toeplitz hash of 5-tuple
+ *             {IP source address, IP destination address, IP source port, IP
+ *             destination port, L4 protocol}  in case of non-IPSec.
+ *
+ *             In case of IPSec - Toeplitz hash of 4-tuple
+ *             {IP source address, IP destination address, SPI, L4 protocol}
+ *
+ *             The relevant Toeplitz key registers are provided in RxOLE's
+ *             instance of common parser module. These registers are separate
+ *             from the Toeplitz keys used by ASE/FSE modules inside RxOLE.
+ *             The actual value will be passed on from common parser module
+ *             to RxOLE in one of the WHO_* TLVs.
+ *
+ * user_rssi
+ *             RSSI for this user
+ *
+ * pkt_type
+ *             Values are defined in enum %RX_MSDU_START_PKT_TYPE_*.
+ *
+ * stbc
+ *             When set, use STBC transmission rates.
+ *
+ * sgi
+ *             Field only valid when pkt type is HT, VHT or HE. Values are
+ *             defined in enum %RX_MSDU_START_SGI_*.
+ *
+ * rate_mcs
+ *             MCS Rate used.
+ *
+ * receive_bandwidth
+ *             Full receive Bandwidth. Values are defined in enum
+ *             %RX_MSDU_START_RECV_*.
+ *
+ * reception_type
+ *             Indicates what type of reception this is and defined in enum
+ *             %RX_MSDU_START_RECEPTION_TYPE_*.
+ *
+ * mimo_ss_bitmap
+ *             Field only valid when
+ *             Reception_type is RX_MSDU_START_RECEPTION_TYPE_DL_MU_MIMO or
+ *             RX_MSDU_START_RECEPTION_TYPE_DL_MU_OFDMA_MIMO.
+ *
+ *             Bitmap, with each bit indicating if the related spatial
+ *             stream is used for this STA
+ *
+ *             LSB related to SS 0
+ *
+ *             0 - spatial stream not used for this reception
+ *             1 - spatial stream used for this reception
+ *
+ * ppdu_start_timestamp
+ *             Timestamp that indicates when the PPDU that contained this MPDU
+ *             started on the medium.
+ *
+ * phy_meta_data
+ *             SW programmed Meta data provided by the PHY. Can be used for SW
+ *             to indicate the channel the device is on.
+ */
+
+#define RX_MSDU_END_INFO0_RXPCU_MPDU_FITLER    GENMASK(1, 0)
+#define RX_MSDU_END_INFO0_SW_FRAME_GRP_ID      GENMASK(8, 2)
+
+#define RX_MSDU_END_INFO1_KEY_ID               GENMASK(7, 0)
+#define RX_MSDU_END_INFO1_CCE_SUPER_RULE       GENMASK(13, 8)
+#define RX_MSDU_END_INFO1_CCND_TRUNCATE                BIT(14)
+#define RX_MSDU_END_INFO1_CCND_CCE_DIS         BIT(15)
+#define RX_MSDU_END_INFO1_EXT_WAPI_PN          GENMASK(31, 16)
+
+#define RX_MSDU_END_INFO2_REPORTED_MPDU_LEN    GENMASK(13, 0)
+#define RX_MSDU_END_INFO2_FIRST_MSDU           BIT(14)
+#define RX_MSDU_END_INFO2_LAST_MSDU            BIT(15)
+#define RX_MSDU_END_INFO2_SA_IDX_TIMEOUT       BIT(16)
+#define RX_MSDU_END_INFO2_DA_IDX_TIMEOUT       BIT(17)
+#define RX_MSDU_END_INFO2_MSDU_LIMIT_ERR       BIT(18)
+#define RX_MSDU_END_INFO2_FLOW_IDX_TIMEOUT     BIT(19)
+#define RX_MSDU_END_INFO2_FLOW_IDX_INVALID     BIT(20)
+#define RX_MSDU_END_INFO2_WIFI_PARSER_ERR      BIT(21)
+#define RX_MSDU_END_INFO2_AMSDU_PARSET_ERR     BIT(22)
+#define RX_MSDU_END_INFO2_SA_IS_VALID          BIT(23)
+#define RX_MSDU_END_INFO2_DA_IS_VALID          BIT(24)
+#define RX_MSDU_END_INFO2_DA_IS_MCBC           BIT(25)
+#define RX_MSDU_END_INFO2_L3_HDR_PADDING       GENMASK(27, 26)
+
+#define RX_MSDU_END_INFO3_TCP_FLAG             GENMASK(8, 0)
+#define RX_MSDU_END_INFO3_LRO_ELIGIBLE         BIT(9)
+
+#define RX_MSDU_END_INFO4_DA_OFFSET            GENMASK(5, 0)
+#define RX_MSDU_END_INFO4_SA_OFFSET            GENMASK(11, 6)
+#define RX_MSDU_END_INFO4_DA_OFFSET_VALID      BIT(12)
+#define RX_MSDU_END_INFO4_SA_OFFSET_VALID      BIT(13)
+#define RX_MSDU_END_INFO4_L3_TYPE              GENMASK(31, 16)
+
+#define RX_MSDU_END_INFO5_MSDU_DROP            BIT(0)
+#define RX_MSDU_END_INFO5_REO_DEST_IND         GENMASK(5, 1)
+#define RX_MSDU_END_INFO5_FLOW_IDX             GENMASK(25, 6)
+
+struct rx_msdu_end {
+       __le16 info0;
+       __le16 phy_ppdu_id;
+       __le16 ip_hdr_cksum;
+       __le16 tcp_udp_cksum;
+       __le32 info1;
+       __le32 ext_wapi_pn[2];
+       __le32 info2;
+       __le32 ipv6_options_crc;
+       __le32 tcp_seq_num;
+       __le32 tcp_ack_num;
+       __le16 info3;
+       __le16 window_size;
+       __le32 info4;
+       __le32 rule_indication[2];
+       __le16 sa_idx;
+       __le16 da_idx;
+       __le32 info5;
+       __le32 fse_metadata;
+       __le16 cce_metadata;
+       __le16 sa_sw_peer_id;
+} __packed;
+
+/* rx_msdu_end
+ *
+ * rxpcu_mpdu_filter_in_category
+ *             Field indicates what the reason was that this mpdu frame
+ *             was allowed to come into the receive path by rxpcu. Values
+ *             are defined in enum %RX_DESC_RXPCU_FILTER_*.
+ *
+ * sw_frame_group_id
+ *             SW processes frames based on certain classifications. Values
+ *             are defined in enum %RX_DESC_SW_FRAME_GRP_ID_*.
+ *
+ * phy_ppdu_id
+ *             A ppdu counter value that PHY increments for every PPDU
+ *             received. The counter value wraps around.
+ *
+ * ip_hdr_cksum
+ *             This can include the IP header checksum or the pseudo
+ *             header checksum used by TCP/UDP checksum.
+ *
+ * tcp_udp_chksum
+ *             The value of the computed TCP/UDP checksum.  A mode bit
+ *             selects whether this checksum is the full checksum or the
+ *             partial checksum which does not include the pseudo header.
+ *
+ * key_id
+ *             The key ID octet from the IV. Only valid when first_msdu is set.
+ *
+ * cce_super_rule
+ *             Indicates the super filter rule.
+ *
+ * cce_classify_not_done_truncate
+ *             Classification failed due to truncated frame.
+ *
+ * cce_classify_not_done_cce_dis
+ *             Classification failed due to CCE global disable
+ *
+ * ext_wapi_pn*
+ *             Extension PN (packet number) which is only used by WAPI.
+ *
+ * reported_mpdu_length
+ *             MPDU length before decapsulation. Only valid when first_msdu is
+ *             set. This field is taken directly from the length field of the
+ *             A-MPDU delimiter or the preamble length field for non-A-MPDU
+ *             frames.
+ *
+ * first_msdu
+ *             Indicates the first MSDU of A-MSDU. If both first_msdu and
+ *             last_msdu are set in the MSDU then this is a non-aggregated MSDU
+ *             frame: normal MPDU. Interior MSDU in an A-MSDU shall have both
+ *             first_mpdu and last_mpdu bits set to 0.
+ *
+ * last_msdu
+ *             Indicates the last MSDU of the A-MSDU. MPDU end status is only
+ *             valid when last_msdu is set.
+ *
+ * sa_idx_timeout
+ *             Indicates an unsuccessful MAC source address search due to the
+ *             expiring of the search timer.
+ *
+ * da_idx_timeout
+ *             Indicates an unsuccessful MAC destination address search due to
+ *             the expiring of the search timer.
+ *
+ * msdu_limit_error
+ *             Indicates that the MSDU threshold was exceeded and thus all the
+ *             rest of the MSDUs will not be scattered and will not be
+ *             decapsulated but will be DMA'ed in RAW format as a single MSDU.
+ *
+ * flow_idx_timeout
+ *             Indicates an unsuccessful flow search due to the expiring of
+ *             the search timer.
+ *
+ * flow_idx_invalid
+ *             flow id is not valid.
+ *
+ * amsdu_parser_error
+ *             A-MSDU could not be properly de-agregated.
+ *
+ * sa_is_valid
+ *             Indicates that OLE found a valid SA entry.
+ *
+ * da_is_valid
+ *             Indicates that OLE found a valid DA entry.
+ *
+ * da_is_mcbc
+ *             Field Only valid if da_is_valid is set. Indicates the DA address
+ *             was a Multicast of Broadcast address.
+ *
+ * l3_header_padding
+ *             Number of bytes padded  to make sure that the L3 header will
+ *             always start of a Dword boundary.
+ *
+ * ipv6_options_crc
+ *             32 bit CRC computed out of  IP v6 extension headers.
+ *
+ * tcp_seq_number
+ *             TCP sequence number.
+ *
+ * tcp_ack_number
+ *             TCP acknowledge number.
+ *
+ * tcp_flag
+ *             TCP flags {NS, CWR, ECE, URG, ACK, PSH, RST, SYN, FIN}.
+ *
+ * lro_eligible
+ *             Computed out of TCP and IP fields to indicate that this
+ *             MSDU is eligible for LRO.
+ *
+ * window_size
+ *             TCP receive window size.
+ *
+ * da_offset
+ *             Offset into MSDU buffer for DA.
+ *
+ * sa_offset
+ *             Offset into MSDU buffer for SA.
+ *
+ * da_offset_valid
+ *             da_offset field is valid. This will be set to 0 in case
+ *             of a dynamic A-MSDU when DA is compressed.
+ *
+ * sa_offset_valid
+ *             sa_offset field is valid. This will be set to 0 in case
+ *             of a dynamic A-MSDU when SA is compressed.
+ *
+ * l3_type
+ *             The 16-bit type value indicating the type of L3 later
+ *             extracted from LLC/SNAP, set to zero if SNAP is not
+ *             available.
+ *
+ * rule_indication
+ *             Bitmap indicating which of rules have matched.
+ *
+ * sa_idx
+ *             The offset in the address table which matches MAC source address
+ *
+ * da_idx
+ *             The offset in the address table which matches MAC destination
+ *             address.
+ *
+ * msdu_drop
+ *             REO shall drop this MSDU and not forward it to any other ring.
+ *
+ * reo_destination_indication
+ *             The id of the reo exit ring where the msdu frame shall push
+ *             after (MPDU level) reordering has finished. Values are defined
+ *             in enum %HAL_RX_MSDU_DESC_REO_DEST_IND_.
+ *
+ * flow_idx
+ *             Flow table index.
+ *
+ * fse_metadata
+ *             FSE related meta data.
+ *
+ * cce_metadata
+ *             CCE related meta data.
+ *
+ * sa_sw_peer_id
+ *             sw_peer_id from the address search entry corresponding to the
+ *             source address of the MSDU.
+ */
+
+enum rx_mpdu_end_rxdma_dest_ring {
+       RX_MPDU_END_RXDMA_DEST_RING_RELEASE,
+       RX_MPDU_END_RXDMA_DEST_RING_FW,
+       RX_MPDU_END_RXDMA_DEST_RING_SW,
+       RX_MPDU_END_RXDMA_DEST_RING_REO,
+};
+
+#define RX_MPDU_END_INFO1_UNSUP_KTYPE_SHORT_FRAME      BIT(11)
+#define RX_MPDU_END_INFO1_RX_IN_TX_DECRYPT_BYT         BIT(12)
+#define RX_MPDU_END_INFO1_OVERFLOW_ERR                 BIT(13)
+#define RX_MPDU_END_INFO1_MPDU_LEN_ERR                 BIT(14)
+#define RX_MPDU_END_INFO1_TKIP_MIC_ERR                 BIT(15)
+#define RX_MPDU_END_INFO1_DECRYPT_ERR                  BIT(16)
+#define RX_MPDU_END_INFO1_UNENCRYPTED_FRAME_ERR                BIT(17)
+#define RX_MPDU_END_INFO1_PN_FIELDS_VALID              BIT(18)
+#define RX_MPDU_END_INFO1_FCS_ERR                      BIT(19)
+#define RX_MPDU_END_INFO1_MSDU_LEN_ERR                 BIT(20)
+#define RX_MPDU_END_INFO1_RXDMA0_DEST_RING             GENMASK(22, 21)
+#define RX_MPDU_END_INFO1_RXDMA1_DEST_RING             GENMASK(24, 23)
+#define RX_MPDU_END_INFO1_DECRYPT_STATUS_CODE          GENMASK(27, 25)
+#define RX_MPDU_END_INFO1_RX_BITMAP_NOT_UPD            BIT(28)
+
+struct rx_mpdu_end {
+       __le16 info0;
+       __le16 phy_ppdu_id;
+       __le32 info1;
+} __packed;
+
+/* rx_mpdu_end
+ *
+ * rxpcu_mpdu_filter_in_category
+ *             Field indicates what the reason was that this mpdu frame
+ *             was allowed to come into the receive path by rxpcu. Values
+ *             are defined in enum %RX_DESC_RXPCU_FILTER_*.
+ *
+ * sw_frame_group_id
+ *             SW processes frames based on certain classifications. Values
+ *             are defined in enum %RX_DESC_SW_FRAME_GRP_ID_*.
+ *
+ * phy_ppdu_id
+ *             A ppdu counter value that PHY increments for every PPDU
+ *             received. The counter value wraps around.
+ *
+ * unsup_ktype_short_frame
+ *             This bit will be '1' when WEP or TKIP or WAPI key type is
+ *             received for 11ah short frame. Crypto will bypass the received
+ *             packet without decryption to RxOLE after setting this bit.
+ *
+ * rx_in_tx_decrypt_byp
+ *             Indicates that RX packet is not decrypted as Crypto is
+ *             busy with TX packet processing.
+ *
+ * overflow_err
+ *             RXPCU Receive FIFO ran out of space to receive the full MPDU.
+ *             Therefore this MPDU is terminated early and is thus corrupted.
+ *
+ *             This MPDU will not be ACKed.
+ *
+ *             RXPCU might still be able to correctly receive the following
+ *             MPDUs in the PPDU if enough fifo space became available in time.
+ *
+ * mpdu_length_err
+ *             Set by RXPCU if the expected MPDU length does not correspond
+ *             with the actually received number of bytes in the MPDU.
+ *
+ * tkip_mic_err
+ *             Set by Rx crypto when crypto detected a TKIP MIC error for
+ *             this MPDU.
+ *
+ * decrypt_err
+ *             Set by RX CRYPTO when CRYPTO detected a decrypt error for this
+ *             MPDU or CRYPTO received an encrypted frame, but did not get a
+ *             valid corresponding key id in the peer entry.
+ *
+ * unencrypted_frame_err
+ *             Set by RX CRYPTO when CRYPTO detected an unencrypted frame while
+ *             in the peer entry field 'All_frames_shall_be_encrypted' is set.
+ *
+ * pn_fields_contain_valid_info
+ *             Set by RX CRYPTO to indicate that there is a valid PN field
+ *             present in this MPDU.
+ *
+ * fcs_err
+ *             Set by RXPCU when there is an FCS error detected for this MPDU.
+ *
+ * msdu_length_err
+ *             Set by RXOLE when there is an msdu length error detected
+ *             in at least 1 of the MSDUs embedded within the MPDU.
+ *
+ * rxdma0_destination_ring
+ * rxdma1_destination_ring
+ *             The ring to which RXDMA0/1 shall push the frame, assuming
+ *             no MPDU level errors are detected. In case of MPDU level
+ *             errors, RXDMA0/1 might change the RXDMA0/1 destination. Values
+ *             are defined in %enum RX_MPDU_END_RXDMA_DEST_RING_*.
+ *
+ * decrypt_status_code
+ *             Field provides insight into the decryption performed. Values
+ *             are defined in enum %RX_DESC_DECRYPT_STATUS_CODE_*.
+ *
+ * rx_bitmap_not_updated
+ *             Frame is received, but RXPCU could not update the receive bitmap
+ *             due to (temporary) fifo constraints.
+ */
+
+/* Padding bytes to avoid TLV's spanning across 128 byte boundary */
+#define HAL_RX_DESC_PADDING0_BYTES     4
+#define HAL_RX_DESC_PADDING1_BYTES     16
+
+#define HAL_RX_DESC_HDR_STATUS_LEN     120
+
+struct hal_rx_desc {
+       __le32 msdu_end_tag;
+       struct rx_msdu_end msdu_end;
+       __le32 rx_attn_tag;
+       struct rx_attention attention;
+       __le32 msdu_start_tag;
+       struct rx_msdu_start msdu_start;
+       u8 rx_padding0[HAL_RX_DESC_PADDING0_BYTES];
+       __le32 mpdu_start_tag;
+       struct rx_mpdu_start mpdu_start;
+       __le32 mpdu_end_tag;
+       struct rx_mpdu_end mpdu_end;
+       u8 rx_padding1[HAL_RX_DESC_PADDING1_BYTES];
+       __le32 hdr_status_tag;
+       __le32 phy_ppdu_id;
+       u8 hdr_status[HAL_RX_DESC_HDR_STATUS_LEN];
+       u8 msdu_payload[0];
+} __packed;
+
+#endif /* ATH11K_RX_DESC_H */
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include "testmode.h"
+#include <net/netlink.h>
+#include "debug.h"
+#include "wmi.h"
+#include "hw.h"
+#include "core.h"
+#include "testmode_i.h"
+
+static const struct nla_policy ath11k_tm_policy[ATH11K_TM_ATTR_MAX + 1] = {
+       [ATH11K_TM_ATTR_CMD]            = { .type = NLA_U32 },
+       [ATH11K_TM_ATTR_DATA]           = { .type = NLA_BINARY,
+                                           .len = ATH11K_TM_DATA_MAX_LEN },
+       [ATH11K_TM_ATTR_WMI_CMDID]      = { .type = NLA_U32 },
+       [ATH11K_TM_ATTR_VERSION_MAJOR]  = { .type = NLA_U32 },
+       [ATH11K_TM_ATTR_VERSION_MINOR]  = { .type = NLA_U32 },
+};
+
+/* Returns true if callee consumes the skb and the skb should be discarded.
+ * Returns false if skb is not used. Does not sleep.
+ */
+bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb)
+{
+       struct sk_buff *nl_skb;
+       bool consumed;
+       int ret;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
+                  "testmode event wmi cmd_id %d skb %pK skb->len %d\n",
+                  cmd_id, skb, skb->len);
+
+       ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
+
+       spin_lock_bh(&ar->data_lock);
+
+       consumed = true;
+
+       nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
+                                                  2 * sizeof(u32) + skb->len,
+                                                  GFP_ATOMIC);
+       if (!nl_skb) {
+               ath11k_warn(ar->ab,
+                           "failed to allocate skb for testmode wmi event\n");
+               goto out;
+       }
+
+       ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to to put testmode wmi event cmd attribute: %d\n",
+                           ret);
+               kfree_skb(nl_skb);
+               goto out;
+       }
+
+       ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to to put testmode wmi even cmd_id: %d\n",
+                           ret);
+               kfree_skb(nl_skb);
+               goto out;
+       }
+
+       ret = nla_put(nl_skb, ATH11K_TM_ATTR_DATA, skb->len, skb->data);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to copy skb to testmode wmi event: %d\n",
+                           ret);
+               kfree_skb(nl_skb);
+               goto out;
+       }
+
+       cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
+
+out:
+       spin_unlock_bh(&ar->data_lock);
+
+       return consumed;
+}
+
+static int ath11k_tm_cmd_get_version(struct ath11k *ar, struct nlattr *tb[])
+{
+       struct sk_buff *skb;
+       int ret;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
+                  "testmode cmd get version_major %d version_minor %d\n",
+                  ATH11K_TESTMODE_VERSION_MAJOR,
+                  ATH11K_TESTMODE_VERSION_MINOR);
+
+       skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
+                                               nla_total_size(sizeof(u32)));
+       if (!skb)
+               return -ENOMEM;
+
+       ret = nla_put_u32(skb, ATH11K_TM_ATTR_VERSION_MAJOR,
+                         ATH11K_TESTMODE_VERSION_MAJOR);
+       if (ret) {
+               kfree_skb(skb);
+               return ret;
+       }
+
+       ret = nla_put_u32(skb, ATH11K_TM_ATTR_VERSION_MINOR,
+                         ATH11K_TESTMODE_VERSION_MINOR);
+       if (ret) {
+               kfree_skb(skb);
+               return ret;
+       }
+
+       return cfg80211_testmode_reply(skb);
+}
+
+static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[])
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct sk_buff *skb;
+       u32 cmd_id, buf_len;
+       int ret;
+       void *buf;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH11K_STATE_ON) {
+               ret = -ENETDOWN;
+               goto out;
+       }
+
+       if (!tb[ATH11K_TM_ATTR_DATA]) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!tb[ATH11K_TM_ATTR_WMI_CMDID]) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       buf = nla_data(tb[ATH11K_TM_ATTR_DATA]);
+       buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]);
+       cmd_id = nla_get_u32(tb[ATH11K_TM_ATTR_WMI_CMDID]);
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
+                  "testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",
+                  cmd_id, buf, buf_len);
+
+       ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len);
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, buf_len);
+       if (!skb) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       memcpy(skb->data, buf, buf_len);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, cmd_id);
+       if (ret) {
+               dev_kfree_skb(skb);
+               ath11k_warn(ar->ab, "failed to transmit wmi command (testmode): %d\n",
+                           ret);
+               goto out;
+       }
+
+       ret = 0;
+
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                 void *data, int len)
+{
+       struct ath11k *ar = hw->priv;
+       struct nlattr *tb[ATH11K_TM_ATTR_MAX + 1];
+       int ret;
+
+       ret = nla_parse(tb, ATH11K_TM_ATTR_MAX, data, len, ath11k_tm_policy,
+                       NULL);
+       if (ret)
+               return ret;
+
+       if (!tb[ATH11K_TM_ATTR_CMD])
+               return -EINVAL;
+
+       switch (nla_get_u32(tb[ATH11K_TM_ATTR_CMD])) {
+       case ATH11K_TM_CMD_GET_VERSION:
+               return ath11k_tm_cmd_get_version(ar, tb);
+       case ATH11K_TM_CMD_WMI:
+               return ath11k_tm_cmd_wmi(ar, tb);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#include "core.h"
+
+#ifdef CONFIG_NL80211_TESTMODE
+
+bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb);
+int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                 void *data, int len);
+
+#else
+
+static inline bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id,
+                                      struct sk_buff *skb)
+{
+       return false;
+}
+
+static inline int ath11k_tm_cmd(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
+                               void *data, int len)
+{
+       return 0;
+}
+
+#endif
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+/* "API" level of the ath11k testmode interface. Bump it after every
+ * incompatible interface change.
+ */
+#define ATH11K_TESTMODE_VERSION_MAJOR 1
+
+/* Bump this after every _compatible_ interface change, for example
+ * addition of a new command or an attribute.
+ */
+#define ATH11K_TESTMODE_VERSION_MINOR 0
+
+#define ATH11K_TM_DATA_MAX_LEN         5000
+
+enum ath11k_tm_attr {
+       __ATH11K_TM_ATTR_INVALID                = 0,
+       ATH11K_TM_ATTR_CMD                      = 1,
+       ATH11K_TM_ATTR_DATA                     = 2,
+       ATH11K_TM_ATTR_WMI_CMDID                = 3,
+       ATH11K_TM_ATTR_VERSION_MAJOR            = 4,
+       ATH11K_TM_ATTR_VERSION_MINOR            = 5,
+       ATH11K_TM_ATTR_WMI_OP_VERSION           = 6,
+
+       /* keep last */
+       __ATH11K_TM_ATTR_AFTER_LAST,
+       ATH11K_TM_ATTR_MAX              = __ATH11K_TM_ATTR_AFTER_LAST - 1,
+};
+
+/* All ath11k testmode interface commands specified in
+ * ATH11K_TM_ATTR_CMD
+ */
+enum ath11k_tm_cmd {
+       /* Returns the supported ath11k testmode interface version in
+        * ATH11K_TM_ATTR_VERSION. Always guaranteed to work. User space
+        * uses this to verify it's using the correct version of the
+        * testmode interface
+        */
+       ATH11K_TM_CMD_GET_VERSION = 0,
+
+       /* The command used to transmit a WMI command to the firmware and
+        * the event to receive WMI events from the firmware. Without
+        * struct wmi_cmd_hdr header, only the WMI payload. Command id is
+        * provided with ATH11K_TM_ATTR_WMI_CMDID and payload in
+        * ATH11K_TM_ATTR_DATA.
+        */
+       ATH11K_TM_CMD_WMI = 1,
+};
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ */
+
+#if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+
+#include <linux/tracepoint.h>
+#include "core.h"
+
+#define _TRACE_H_
+
+/* create empty functions when tracing is disabled */
+#if !defined(CONFIG_ATH11K_TRACING)
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#endif /* !CONFIG_ATH11K_TRACING || __CHECKER__ */
+
+TRACE_EVENT(ath11k_htt_pktlog,
+           TP_PROTO(struct ath11k *ar, const void *buf, u16 buf_len),
+
+       TP_ARGS(ar, buf, buf_len),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(ar->ab->dev))
+               __string(driver, dev_driver_string(ar->ab->dev))
+               __field(u16, buf_len)
+               __dynamic_array(u8, pktlog, buf_len)
+       ),
+
+       TP_fast_assign(
+               __assign_str(device, dev_name(ar->ab->dev));
+               __assign_str(driver, dev_driver_string(ar->ab->dev));
+               __entry->buf_len = buf_len;
+               memcpy(__get_dynamic_array(pktlog), buf, buf_len);
+       ),
+
+       TP_printk(
+               "%s %s size %hu",
+               __get_str(driver),
+               __get_str(device),
+               __entry->buf_len
+        )
+);
+
+TRACE_EVENT(ath11k_htt_ppdu_stats,
+           TP_PROTO(struct ath11k *ar, const void *data, size_t len),
+
+       TP_ARGS(ar, data, len),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(ar->ab->dev))
+               __string(driver, dev_driver_string(ar->ab->dev))
+               __field(u16, len)
+               __dynamic_array(u8, ppdu, len)
+       ),
+
+       TP_fast_assign(
+               __assign_str(device, dev_name(ar->ab->dev));
+               __assign_str(driver, dev_driver_string(ar->ab->dev));
+               __entry->len = len;
+               memcpy(__get_dynamic_array(ppdu), data, len);
+       ),
+
+       TP_printk(
+               "%s %s ppdu len %d",
+               __get_str(driver),
+               __get_str(device),
+               __entry->len
+        )
+);
+
+TRACE_EVENT(ath11k_htt_rxdesc,
+           TP_PROTO(struct ath11k *ar, const void *data, size_t len),
+
+       TP_ARGS(ar, data, len),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(ar->ab->dev))
+               __string(driver, dev_driver_string(ar->ab->dev))
+               __field(u16, len)
+               __dynamic_array(u8, rxdesc, len)
+       ),
+
+       TP_fast_assign(
+               __assign_str(device, dev_name(ar->ab->dev));
+               __assign_str(driver, dev_driver_string(ar->ab->dev));
+               __entry->len = len;
+               memcpy(__get_dynamic_array(rxdesc), data, len);
+       ),
+
+       TP_printk(
+               "%s %s rxdesc 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 */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
 
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+#include <linux/skbuff.h>
+#include <linux/ctype.h>
+#include <net/mac80211.h>
+#include <net/cfg80211.h>
+#include <linux/completion.h>
+#include <linux/if_ether.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/uuid.h>
+#include <linux/time.h>
+#include <linux/of.h>
+#include "core.h"
+#include "debug.h"
+#include "mac.h"
+#include "hw.h"
+#include "peer.h"
+
+struct wmi_tlv_policy {
+       size_t min_len;
+};
+
+struct wmi_tlv_svc_ready_parse {
+       bool wmi_svc_bitmap_done;
+};
+
+struct wmi_tlv_svc_rdy_ext_parse {
+       struct ath11k_service_ext_param param;
+       struct wmi_soc_mac_phy_hw_mode_caps *hw_caps;
+       struct wmi_hw_mode_capabilities *hw_mode_caps;
+       u32 n_hw_mode_caps;
+       u32 tot_phy_id;
+       struct wmi_hw_mode_capabilities pref_hw_mode_caps;
+       struct wmi_mac_phy_capabilities *mac_phy_caps;
+       u32 n_mac_phy_caps;
+       struct wmi_soc_hal_reg_capabilities *soc_hal_reg_caps;
+       struct wmi_hal_reg_capabilities_ext *ext_hal_reg_caps;
+       u32 n_ext_hal_reg_caps;
+       bool hw_mode_done;
+       bool mac_phy_done;
+       bool ext_hal_reg_done;
+};
+
+struct wmi_tlv_rdy_parse {
+       u32 num_extra_mac_addr;
+};
+
+static const struct wmi_tlv_policy wmi_tlv_policies[] = {
+       [WMI_TAG_ARRAY_BYTE]
+               = { .min_len = 0 },
+       [WMI_TAG_ARRAY_UINT32]
+               = { .min_len = 0 },
+       [WMI_TAG_SERVICE_READY_EVENT]
+               = { .min_len = sizeof(struct wmi_service_ready_event) },
+       [WMI_TAG_SERVICE_READY_EXT_EVENT]
+               = { .min_len =  sizeof(struct wmi_service_ready_ext_event) },
+       [WMI_TAG_SOC_MAC_PHY_HW_MODE_CAPS]
+               = { .min_len = sizeof(struct wmi_soc_mac_phy_hw_mode_caps) },
+       [WMI_TAG_SOC_HAL_REG_CAPABILITIES]
+               = { .min_len = sizeof(struct wmi_soc_hal_reg_capabilities) },
+       [WMI_TAG_VDEV_START_RESPONSE_EVENT]
+               = { .min_len = sizeof(struct wmi_vdev_start_resp_event) },
+       [WMI_TAG_PEER_DELETE_RESP_EVENT]
+               = { .min_len = sizeof(struct wmi_peer_delete_resp_event) },
+       [WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT]
+               = { .min_len = sizeof(struct wmi_bcn_tx_status_event) },
+       [WMI_TAG_VDEV_STOPPED_EVENT]
+               = { .min_len = sizeof(struct wmi_vdev_stopped_event) },
+       [WMI_TAG_REG_CHAN_LIST_CC_EVENT]
+               = { .min_len = sizeof(struct wmi_reg_chan_list_cc_event) },
+       [WMI_TAG_MGMT_RX_HDR]
+               = { .min_len = sizeof(struct wmi_mgmt_rx_hdr) },
+       [WMI_TAG_MGMT_TX_COMPL_EVENT]
+               = { .min_len = sizeof(struct wmi_mgmt_tx_compl_event) },
+       [WMI_TAG_SCAN_EVENT]
+               = { .min_len = sizeof(struct wmi_scan_event) },
+       [WMI_TAG_PEER_STA_KICKOUT_EVENT]
+               = { .min_len = sizeof(struct wmi_peer_sta_kickout_event) },
+       [WMI_TAG_ROAM_EVENT]
+               = { .min_len = sizeof(struct wmi_roam_event) },
+       [WMI_TAG_CHAN_INFO_EVENT]
+               = { .min_len = sizeof(struct wmi_chan_info_event) },
+       [WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT]
+               = { .min_len = sizeof(struct wmi_pdev_bss_chan_info_event) },
+       [WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT]
+               = { .min_len = sizeof(struct wmi_vdev_install_key_compl_event) },
+       [WMI_TAG_READY_EVENT]
+               = {.min_len = sizeof(struct wmi_ready_event) },
+       [WMI_TAG_SERVICE_AVAILABLE_EVENT]
+               = {.min_len = sizeof(struct wmi_service_available_event) },
+       [WMI_TAG_PEER_ASSOC_CONF_EVENT]
+               = { .min_len = sizeof(struct wmi_peer_assoc_conf_event) },
+       [WMI_TAG_STATS_EVENT]
+               = { .min_len = sizeof(struct wmi_stats_event) },
+       [WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT]
+               = { .min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) },
+};
+
+#define PRIMAP(_hw_mode_) \
+       [_hw_mode_] = _hw_mode_##_PRI
+
+static const int ath11k_hw_mode_pri_map[] = {
+       PRIMAP(WMI_HOST_HW_MODE_SINGLE),
+       PRIMAP(WMI_HOST_HW_MODE_DBS),
+       PRIMAP(WMI_HOST_HW_MODE_SBS_PASSIVE),
+       PRIMAP(WMI_HOST_HW_MODE_SBS),
+       PRIMAP(WMI_HOST_HW_MODE_DBS_SBS),
+       PRIMAP(WMI_HOST_HW_MODE_DBS_OR_SBS),
+       /* keep last */
+       PRIMAP(WMI_HOST_HW_MODE_MAX),
+};
+
+static int
+ath11k_wmi_tlv_iter(struct ath11k_base *ab, const void *ptr, size_t len,
+                   int (*iter)(struct ath11k_base *ab, u16 tag, u16 len,
+                               const void *ptr, void *data),
+                   void *data)
+{
+       const void *begin = ptr;
+       const struct wmi_tlv *tlv;
+       u16 tlv_tag, tlv_len;
+       int ret;
+
+       while (len > 0) {
+               if (len < sizeof(*tlv)) {
+                       ath11k_err(ab, "wmi tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n",
+                                  ptr - begin, len, sizeof(*tlv));
+                       return -EINVAL;
+               }
+
+               tlv = ptr;
+               tlv_tag = FIELD_GET(WMI_TLV_TAG, tlv->header);
+               tlv_len = FIELD_GET(WMI_TLV_LEN, tlv->header);
+               ptr += sizeof(*tlv);
+               len -= sizeof(*tlv);
+
+               if (tlv_len > len) {
+                       ath11k_err(ab, "wmi tlv parse failure of tag %hhu at byte %zd (%zu bytes left, %hhu expected)\n",
+                                  tlv_tag, ptr - begin, len, tlv_len);
+                       return -EINVAL;
+               }
+
+               if (tlv_tag < ARRAY_SIZE(wmi_tlv_policies) &&
+                   wmi_tlv_policies[tlv_tag].min_len &&
+                   wmi_tlv_policies[tlv_tag].min_len > tlv_len) {
+                       ath11k_err(ab, "wmi tlv parse failure of tag %hhu at byte %zd (%hhu bytes is less than min length %zu)\n",
+                                  tlv_tag, ptr - begin, tlv_len,
+                                  wmi_tlv_policies[tlv_tag].min_len);
+                       return -EINVAL;
+               }
+
+               ret = iter(ab, tlv_tag, tlv_len, ptr, data);
+               if (ret)
+                       return ret;
+
+               ptr += tlv_len;
+               len -= tlv_len;
+       }
+
+       return 0;
+}
+
+static int ath11k_wmi_tlv_iter_parse(struct ath11k_base *ab, u16 tag, u16 len,
+                                    const void *ptr, void *data)
+{
+       const void **tb = data;
+
+       if (tag < WMI_TAG_MAX)
+               tb[tag] = ptr;
+
+       return 0;
+}
+
+static int ath11k_wmi_tlv_parse(struct ath11k_base *ar, const void **tb,
+                               const void *ptr, size_t len)
+{
+       return ath11k_wmi_tlv_iter(ar, ptr, len, ath11k_wmi_tlv_iter_parse,
+                                  (void *)tb);
+}
+
+static const void **
+ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
+                          size_t len, gfp_t gfp)
+{
+       const void **tb;
+       int ret;
+
+       tb = kcalloc(WMI_TAG_MAX, sizeof(*tb), gfp);
+       if (!tb)
+               return ERR_PTR(-ENOMEM);
+
+       ret = ath11k_wmi_tlv_parse(ab, tb, ptr, len);
+       if (ret) {
+               kfree(tb);
+               return ERR_PTR(ret);
+       }
+
+       return tb;
+}
+
+static int ath11k_wmi_cmd_send_nowait(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
+                                     u32 cmd_id)
+{
+       struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
+       struct ath11k_base *ab = wmi->wmi_sc->ab;
+       struct wmi_cmd_hdr *cmd_hdr;
+       int ret;
+       u32 cmd = 0;
+
+       if (skb_push(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+               return -ENOMEM;
+
+       cmd |= FIELD_PREP(WMI_CMD_HDR_CMD_ID, cmd_id);
+
+       cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
+       cmd_hdr->cmd_id = cmd;
+
+       memset(skb_cb, 0, sizeof(*skb_cb));
+       ret = ath11k_htc_send(&ab->htc, wmi->eid, skb);
+
+       if (ret)
+               goto err_pull;
+
+       return 0;
+
+err_pull:
+       skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+       return ret;
+}
+
+int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
+                       u32 cmd_id)
+{
+       struct ath11k_wmi_base *wmi_sc = wmi->wmi_sc;
+       int ret = -EOPNOTSUPP;
+
+       might_sleep();
+
+       wait_event_timeout(wmi_sc->tx_credits_wq, ({
+               ret = ath11k_wmi_cmd_send_nowait(wmi, skb, cmd_id);
+
+               if (ret && test_bit(ATH11K_FLAG_CRASH_FLUSH, &wmi_sc->ab->dev_flags))
+                       ret = -ESHUTDOWN;
+
+               (ret != -EAGAIN);
+       }), WMI_SEND_TIMEOUT_HZ);
+
+       if (ret == -EAGAIN)
+               ath11k_warn(wmi_sc->ab, "wmi command %d timeout\n", cmd_id);
+
+       return ret;
+}
+
+static int ath11k_pull_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle,
+                                    const void *ptr,
+                                    struct ath11k_service_ext_param *param)
+{
+       const struct wmi_service_ready_ext_event *ev = ptr;
+
+       if (!ev)
+               return -EINVAL;
+
+       /* Move this to host based bitmap */
+       param->default_conc_scan_config_bits = ev->default_conc_scan_config_bits;
+       param->default_fw_config_bits = ev->default_fw_config_bits;
+       param->he_cap_info = ev->he_cap_info;
+       param->mpdu_density = ev->mpdu_density;
+       param->max_bssid_rx_filters = ev->max_bssid_rx_filters;
+       memcpy(¶m->ppet, &ev->ppet, sizeof(param->ppet));
+
+       return 0;
+}
+
+static int
+ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle,
+                                     struct wmi_soc_mac_phy_hw_mode_caps *hw_caps,
+                                     struct wmi_hw_mode_capabilities *wmi_hw_mode_caps,
+                                     struct wmi_soc_hal_reg_capabilities *hal_reg_caps,
+                                     struct wmi_mac_phy_capabilities *wmi_mac_phy_caps,
+                                     u8 hw_mode_id, u8 phy_id,
+                                     struct ath11k_pdev *pdev)
+{
+       struct wmi_mac_phy_capabilities *mac_phy_caps;
+       struct ath11k_band_cap *cap_band;
+       struct ath11k_pdev_cap *pdev_cap = &pdev->cap;
+       u32 phy_map;
+       u32 hw_idx, phy_idx = 0;
+
+       if (!hw_caps || !wmi_hw_mode_caps || !hal_reg_caps)
+               return -EINVAL;
+
+       for (hw_idx = 0; hw_idx < hw_caps->num_hw_modes; hw_idx++) {
+               if (hw_mode_id == wmi_hw_mode_caps[hw_idx].hw_mode_id)
+                       break;
+
+               phy_map = wmi_hw_mode_caps[hw_idx].phy_id_map;
+               while (phy_map) {
+                       phy_map >>= 1;
+                       phy_idx++;
+               }
+       }
+
+       if (hw_idx == hw_caps->num_hw_modes)
+               return -EINVAL;
+
+       phy_idx += phy_id;
+       if (phy_id >= hal_reg_caps->num_phy)
+               return -EINVAL;
+
+       mac_phy_caps = &wmi_mac_phy_caps[phy_idx];
+
+       pdev->pdev_id = mac_phy_caps->pdev_id;
+       pdev_cap->supported_bands = mac_phy_caps->supported_bands;
+       pdev_cap->ampdu_density = mac_phy_caps->ampdu_density;
+
+       /* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from
+        * band to band for a single radio, need to see how this should be
+        * handled.
+        */
+       if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_2G_CAP) {
+               pdev_cap->tx_chain_mask = mac_phy_caps->tx_chain_mask_2g;
+               pdev_cap->rx_chain_mask = mac_phy_caps->rx_chain_mask_2g;
+       } else if (mac_phy_caps->supported_bands & WMI_HOST_WLAN_5G_CAP) {
+               pdev_cap->vht_cap = mac_phy_caps->vht_cap_info_5g;
+               pdev_cap->vht_mcs = mac_phy_caps->vht_supp_mcs_5g;
+               pdev_cap->he_mcs = mac_phy_caps->he_supp_mcs_5g;
+               pdev_cap->tx_chain_mask = mac_phy_caps->tx_chain_mask_5g;
+               pdev_cap->rx_chain_mask = mac_phy_caps->rx_chain_mask_5g;
+       } else {
+               return -EINVAL;
+       }
+
+       /* tx/rx chainmask reported from fw depends on the actual hw chains used,
+        * For example, for 4x4 capable macphys, first 4 chains can be used for first
+        * mac and the remaing 4 chains can be used for the second mac or vice-versa.
+        * In this case, tx/rx chainmask 0xf will be advertised for first mac and 0xf0
+        * will be advertised for second mac or vice-versa. Compute the shift value for
+        * for tx/rx chainmask which will be used to advertise supported ht/vht rates to
+        * mac80211.
+        */
+       pdev_cap->tx_chain_mask_shift =
+                       find_first_bit((unsigned long *)&pdev_cap->tx_chain_mask, 32);
+       pdev_cap->rx_chain_mask_shift =
+                       find_first_bit((unsigned long *)&pdev_cap->rx_chain_mask, 32);
+
+       cap_band = &pdev_cap->band[NL80211_BAND_2GHZ];
+       cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_2g;
+       cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_2g;
+       cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_2g;
+       cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_2g_ext;
+       cap_band->he_mcs = mac_phy_caps->he_supp_mcs_2g;
+       memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_2g,
+              sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE);
+       memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet2g,
+              sizeof(struct ath11k_ppe_threshold));
+
+       cap_band = &pdev_cap->band[NL80211_BAND_5GHZ];
+       cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g;
+       cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g;
+       cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g;
+       cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext;
+       cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g;
+       memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g,
+              sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE);
+       memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g,
+              sizeof(struct ath11k_ppe_threshold));
+
+       return 0;
+}
+
+static int
+ath11k_pull_reg_cap_svc_rdy_ext(struct ath11k_pdev_wmi *wmi_handle,
+                               struct wmi_soc_hal_reg_capabilities *reg_caps,
+                               struct wmi_hal_reg_capabilities_ext *wmi_ext_reg_cap,
+                               u8 phy_idx,
+                               struct ath11k_hal_reg_capabilities_ext *param)
+{
+       struct wmi_hal_reg_capabilities_ext *ext_reg_cap;
+
+       if (!reg_caps || !wmi_ext_reg_cap)
+               return -EINVAL;
+
+       if (phy_idx >= reg_caps->num_phy)
+               return -EINVAL;
+
+       ext_reg_cap = &wmi_ext_reg_cap[phy_idx];
+
+       param->phy_id = ext_reg_cap->phy_id;
+       param->eeprom_reg_domain = ext_reg_cap->eeprom_reg_domain;
+       param->eeprom_reg_domain_ext =
+                             ext_reg_cap->eeprom_reg_domain_ext;
+       param->regcap1 = ext_reg_cap->regcap1;
+       param->regcap2 = ext_reg_cap->regcap2;
+       /* check if param->wireless_mode is needed */
+       param->low_2ghz_chan = ext_reg_cap->low_2ghz_chan;
+       param->high_2ghz_chan = ext_reg_cap->high_2ghz_chan;
+       param->low_5ghz_chan = ext_reg_cap->low_5ghz_chan;
+       param->high_5ghz_chan = ext_reg_cap->high_5ghz_chan;
+
+       return 0;
+}
+
+static int ath11k_pull_service_ready_tlv(struct ath11k_base *ab,
+                                        const void *evt_buf,
+                                        struct ath11k_targ_cap *cap)
+{
+       const struct wmi_service_ready_event *ev = evt_buf;
+
+       if (!ev) {
+               ath11k_err(ab, "%s: failed by NULL param\n",
+                          __func__);
+               return -EINVAL;
+       }
+
+       cap->phy_capability = ev->phy_capability;
+       cap->max_frag_entry = ev->max_frag_entry;
+       cap->num_rf_chains = ev->num_rf_chains;
+       cap->ht_cap_info = ev->ht_cap_info;
+       cap->vht_cap_info = ev->vht_cap_info;
+       cap->vht_supp_mcs = ev->vht_supp_mcs;
+       cap->hw_min_tx_power = ev->hw_min_tx_power;
+       cap->hw_max_tx_power = ev->hw_max_tx_power;
+       cap->sys_cap_info = ev->sys_cap_info;
+       cap->min_pkt_size_enable = ev->min_pkt_size_enable;
+       cap->max_bcn_ie_size = ev->max_bcn_ie_size;
+       cap->max_num_scan_channels = ev->max_num_scan_channels;
+       cap->max_supported_macs = ev->max_supported_macs;
+       cap->wmi_fw_sub_feat_caps = ev->wmi_fw_sub_feat_caps;
+       cap->txrx_chainmask = ev->txrx_chainmask;
+       cap->default_dbs_hw_mode_index = ev->default_dbs_hw_mode_index;
+       cap->num_msdu_desc = ev->num_msdu_desc;
+
+       return 0;
+}
+
+/* Save the wmi_service_bitmap into a linear bitmap. The wmi_services in
+ * wmi_service ready event are advertised in b0-b3 (LSB 4-bits) of each
+ * 4-byte word.
+ */
+static void ath11k_wmi_service_bitmap_copy(struct ath11k_pdev_wmi *wmi,
+                                          const u32 *wmi_svc_bm)
+{
+       int i, j;
+
+       for (i = 0, j = 0; i < WMI_SERVICE_BM_SIZE && j < WMI_MAX_SERVICE; i++) {
+               do {
+                       if (wmi_svc_bm[i] & BIT(j % WMI_SERVICE_BITS_IN_SIZE32))
+                               set_bit(j, wmi->wmi_sc->svc_map);
+               } while (++j % WMI_SERVICE_BITS_IN_SIZE32);
+       }
+}
+
+static int ath11k_wmi_tlv_svc_rdy_parse(struct ath11k_base *ab, u16 tag, u16 len,
+                                       const void *ptr, void *data)
+{
+       struct wmi_tlv_svc_ready_parse *svc_ready = data;
+       struct ath11k_pdev_wmi *wmi_handle = &ab->wmi_sc.wmi[0];
+       u16 expect_len;
+
+       switch (tag) {
+       case WMI_TAG_SERVICE_READY_EVENT:
+               if (ath11k_pull_service_ready_tlv(ab, ptr, &ab->target_caps))
+                       return -EINVAL;
+               break;
+
+       case WMI_TAG_ARRAY_UINT32:
+               if (!svc_ready->wmi_svc_bitmap_done) {
+                       expect_len = WMI_SERVICE_BM_SIZE * sizeof(u32);
+                       if (len < expect_len) {
+                               ath11k_warn(ab, "invalid len %d for the tag 0x%x\n",
+                                           len, tag);
+                               return -EINVAL;
+                       }
+
+                       ath11k_wmi_service_bitmap_copy(wmi_handle, ptr);
+
+                       svc_ready->wmi_svc_bitmap_done = true;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int ath11k_service_ready_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_tlv_svc_ready_parse svc_ready = { };
+       int ret;
+
+       ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len,
+                                 ath11k_wmi_tlv_svc_rdy_parse,
+                                 &svc_ready);
+       if (ret) {
+               ath11k_warn(ab, "failed to parse tlv %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len)
+{
+       struct sk_buff *skb;
+       struct ath11k_base *ab = wmi_sc->ab;
+       u32 round_len = roundup(len, 4);
+
+       skb = ath11k_htc_alloc_skb(ab, WMI_SKB_HEADROOM + round_len);
+       if (!skb)
+               return NULL;
+
+       skb_reserve(skb, WMI_SKB_HEADROOM);
+       if (!IS_ALIGNED((unsigned long)skb->data, 4))
+               ath11k_warn(ab, "unaligned WMI skb data\n");
+
+       skb_put(skb, round_len);
+       memset(skb->data, 0, round_len);
+
+       return skb;
+}
+
+int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id,
+                        struct sk_buff *frame)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_mgmt_send_cmd *cmd;
+       struct wmi_tlv *frame_tlv;
+       struct sk_buff *skb;
+       u32 buf_len;
+       int ret, len;
+
+       buf_len = frame->len < WMI_MGMT_SEND_DOWNLD_LEN ?
+                 frame->len : WMI_MGMT_SEND_DOWNLD_LEN;
+
+       len = sizeof(*cmd) + sizeof(*frame_tlv) + roundup(buf_len, 4);
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_mgmt_send_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_MGMT_TX_SEND_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       cmd->desc_id = buf_id;
+       cmd->chanfreq = 0;
+       cmd->paddr_lo = lower_32_bits(ATH11K_SKB_CB(frame)->paddr);
+       cmd->paddr_hi = upper_32_bits(ATH11K_SKB_CB(frame)->paddr);
+       cmd->frame_len = frame->len;
+       cmd->buf_len = buf_len;
+       cmd->tx_params_valid = 0;
+
+       frame_tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd));
+       frame_tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
+                           FIELD_PREP(WMI_TLV_LEN, buf_len);
+
+       memcpy(frame_tlv->value, frame->data, buf_len);
+
+       ath11k_ce_byte_swap(frame_tlv->value, buf_len);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_MGMT_TX_SEND_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to submit WMI_MGMT_TX_SEND_CMDID cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_vdev_create(struct ath11k *ar, u8 *macaddr,
+                          struct vdev_create_params *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_vdev_create_cmd *cmd;
+       struct sk_buff *skb;
+       struct wmi_vdev_txrx_streams *txrx_streams;
+       struct wmi_tlv *tlv;
+       int ret, len;
+       void *ptr;
+
+       /* It can be optimized my sending tx/rx chain configuration
+        * only for supported bands instead of always sending it for
+        * both the bands.
+        */
+       len = sizeof(*cmd) + TLV_HDR_SIZE +
+               (WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams));
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_create_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_CREATE_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->vdev_id = param->if_id;
+       cmd->vdev_type = param->type;
+       cmd->vdev_subtype = param->subtype;
+       cmd->num_cfg_txrx_streams = WMI_NUM_SUPPORTED_BAND_MAX;
+       cmd->pdev_id = param->pdev_id;
+       ether_addr_copy(cmd->vdev_macaddr.addr, macaddr);
+
+       ptr = skb->data + sizeof(*cmd);
+       len = WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams);
+
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+                     FIELD_PREP(WMI_TLV_LEN, len);
+
+       ptr += TLV_HDR_SIZE;
+       txrx_streams = ptr;
+       len = sizeof(*txrx_streams);
+       txrx_streams->tlv_header =
+               FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_TXRX_STREAMS) |
+               FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
+       txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_2G;
+       txrx_streams->supported_tx_streams =
+                                param->chains[NL80211_BAND_2GHZ].tx;
+       txrx_streams->supported_rx_streams =
+                                param->chains[NL80211_BAND_2GHZ].rx;
+
+       txrx_streams++;
+       txrx_streams->tlv_header =
+               FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_TXRX_STREAMS) |
+               FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
+       txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_5G;
+       txrx_streams->supported_tx_streams =
+                                param->chains[NL80211_BAND_5GHZ].tx;
+       txrx_streams->supported_rx_streams =
+                                param->chains[NL80211_BAND_5GHZ].rx;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_CREATE_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to submit WMI_VDEV_CREATE_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI vdev create: id %d type %d subtype %d macaddr %pM pdevid %d\n",
+                  param->if_id, param->type, param->subtype,
+                  macaddr, param->pdev_id);
+
+       return ret;
+}
+
+int ath11k_wmi_vdev_delete(struct ath11k *ar, u8 vdev_id)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_vdev_delete_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_delete_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_DELETE_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_DELETE_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to submit WMI_VDEV_DELETE_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "WMI vdev delete id %d\n", vdev_id);
+
+       return ret;
+}
+
+int ath11k_wmi_vdev_stop(struct ath11k *ar, u8 vdev_id)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_vdev_stop_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_stop_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_STOP_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_STOP_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to submit WMI_VDEV_STOP cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "WMI vdev stop id 0x%x\n", vdev_id);
+
+       return ret;
+}
+
+int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_vdev_down_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_down_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_DOWN_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_DOWN_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to submit WMI_VDEV_DOWN cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "WMI vdev down id 0x%x\n", vdev_id);
+
+       return ret;
+}
+
+static void ath11k_wmi_put_wmi_channel(struct wmi_channel *chan,
+                                      struct wmi_vdev_start_req_arg *arg)
+{
+       memset(chan, 0, sizeof(*chan));
+
+       chan->mhz = arg->channel.freq;
+       chan->band_center_freq1 = arg->channel.band_center_freq1;
+       if (arg->channel.mode == MODE_11AC_VHT80_80)
+               chan->band_center_freq2 = arg->channel.band_center_freq2;
+       else
+               chan->band_center_freq2 = 0;
+
+       chan->info |= FIELD_PREP(WMI_CHAN_INFO_MODE, arg->channel.mode);
+       if (arg->channel.passive)
+               chan->info |= WMI_CHAN_INFO_PASSIVE;
+       if (arg->channel.allow_ibss)
+               chan->info |= WMI_CHAN_INFO_ADHOC_ALLOWED;
+       if (arg->channel.allow_ht)
+               chan->info |= WMI_CHAN_INFO_ALLOW_HT;
+       if (arg->channel.allow_vht)
+               chan->info |= WMI_CHAN_INFO_ALLOW_VHT;
+       if (arg->channel.ht40plus)
+               chan->info |= WMI_CHAN_INFO_HT40_PLUS;
+       if (arg->channel.chan_radar)
+               chan->info |= WMI_CHAN_INFO_DFS;
+       if (arg->channel.freq2_radar)
+               chan->info |= WMI_CHAN_INFO_DFS_FREQ2;
+
+       chan->reg_info_1 = FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_PWR,
+                                     arg->channel.max_power) |
+               FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_REG_PWR,
+                          arg->channel.max_reg_power);
+
+       chan->reg_info_2 = FIELD_PREP(WMI_CHAN_REG_INFO2_ANT_MAX,
+                                     arg->channel.max_antenna_gain) |
+               FIELD_PREP(WMI_CHAN_REG_INFO2_MAX_TX_PWR,
+                          arg->channel.max_power);
+}
+
+int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg,
+                         bool restart)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_vdev_start_request_cmd *cmd;
+       struct sk_buff *skb;
+       struct wmi_channel *chan;
+       struct wmi_tlv *tlv;
+       void *ptr;
+       int ret, len;
+
+       if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
+               return -EINVAL;
+
+       len = sizeof(*cmd) + sizeof(*chan) + TLV_HDR_SIZE;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_start_request_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                    WMI_TAG_VDEV_START_REQUEST_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = arg->vdev_id;
+       cmd->beacon_interval = arg->bcn_intval;
+       cmd->bcn_tx_rate = arg->bcn_tx_rate;
+       cmd->dtim_period = arg->dtim_period;
+       cmd->num_noa_descriptors = arg->num_noa_descriptors;
+       cmd->preferred_rx_streams = arg->pref_rx_streams;
+       cmd->preferred_tx_streams = arg->pref_tx_streams;
+       cmd->cac_duration_ms = arg->cac_duration_ms;
+       cmd->regdomain = arg->regdomain;
+       cmd->he_ops = arg->he_ops;
+
+       if (!restart) {
+               if (arg->ssid) {
+                       cmd->ssid.ssid_len = arg->ssid_len;
+                       memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
+               }
+               if (arg->hidden_ssid)
+                       cmd->flags |= WMI_VDEV_START_HIDDEN_SSID;
+               if (arg->pmf_enabled)
+                       cmd->flags |= WMI_VDEV_START_PMF_ENABLED;
+       }
+
+       cmd->flags |= WMI_VDEV_START_LDPC_RX_ENABLED;
+
+       ptr = skb->data + sizeof(*cmd);
+       chan = ptr;
+
+       ath11k_wmi_put_wmi_channel(chan, arg);
+
+       chan->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_CHANNEL) |
+                          FIELD_PREP(WMI_TLV_LEN,
+                                     sizeof(*chan) - TLV_HDR_SIZE);
+       ptr += sizeof(*chan);
+
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+                     FIELD_PREP(WMI_TLV_LEN, 0);
+
+       /* Note: This is a nested TLV containing:
+        * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv]..
+        */
+
+       ptr += sizeof(*tlv);
+
+       if (restart)
+               ret = ath11k_wmi_cmd_send(wmi, skb,
+                                         WMI_VDEV_RESTART_REQUEST_CMDID);
+       else
+               ret = ath11k_wmi_cmd_send(wmi, skb,
+                                         WMI_VDEV_START_REQUEST_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to submit vdev_%s cmd\n",
+                           restart ? "restart" : "start");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "vdev %s id 0x%x freq 0x%x mode 0x%x\n",
+                  restart ? "restart" : "start", arg->vdev_id,
+                  arg->channel.freq, arg->channel.mode);
+
+       return ret;
+}
+
+int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_vdev_up_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_up_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_UP_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       cmd->vdev_assoc_id = aid;
+
+       ether_addr_copy(cmd->vdev_bssid.addr, bssid);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_UP_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to submit WMI_VDEV_UP cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI mgmt vdev up id 0x%x assoc id %d bssid %pM\n",
+                  vdev_id, aid, bssid);
+
+       return ret;
+}
+
+int ath11k_wmi_send_peer_create_cmd(struct ath11k *ar,
+                                   struct peer_create_params *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_peer_create_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_peer_create_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PEER_CREATE_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       ether_addr_copy(cmd->peer_macaddr.addr, param->peer_addr);
+       cmd->peer_type = param->peer_type;
+       cmd->vdev_id = param->vdev_id;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_CREATE_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to submit WMI_PEER_CREATE cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI peer create vdev_id %d peer_addr %pM\n",
+                  param->vdev_id, param->peer_addr);
+
+       return ret;
+}
+
+int ath11k_wmi_send_peer_delete_cmd(struct ath11k *ar,
+                                   const u8 *peer_addr, u8 vdev_id)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_peer_delete_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_peer_delete_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PEER_DELETE_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+       cmd->vdev_id = vdev_id;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI peer delete vdev_id %d peer_addr %pM\n",
+                  vdev_id,  peer_addr);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_DELETE_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_PEER_DELETE cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_send_pdev_set_regdomain(struct ath11k *ar,
+                                      struct pdev_set_regdomain_params *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_pdev_set_regdomain_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                    WMI_TAG_PDEV_SET_REGDOMAIN_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->reg_domain = param->current_rd_in_use;
+       cmd->reg_domain_2g = param->current_rd_2g;
+       cmd->reg_domain_5g = param->current_rd_5g;
+       cmd->conformance_test_limit_2g = param->ctl_2g;
+       cmd->conformance_test_limit_5g = param->ctl_5g;
+       cmd->dfs_domain = param->dfs_domain;
+       cmd->pdev_id = param->pdev_id;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI pdev regd rd %d rd2g %d rd5g %d domain %d pdev id %d\n",
+                  param->current_rd_in_use, param->current_rd_2g,
+                  param->current_rd_5g, param->dfs_domain, param->pdev_id);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_REGDOMAIN_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_PDEV_SET_REGDOMAIN cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_set_peer_param(struct ath11k *ar, const u8 *peer_addr,
+                             u32 vdev_id, u32 param_id, u32 param_val)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_peer_set_param_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_peer_set_param_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PEER_SET_PARAM_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+       cmd->vdev_id = vdev_id;
+       cmd->param_id = param_id;
+       cmd->param_value = param_val;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_SET_PARAM_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_PEER_SET_PARAM cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI vdev %d peer 0x%pM set param %d value %d\n",
+                  vdev_id, peer_addr, param_id, param_val);
+
+       return ret;
+}
+
+int ath11k_wmi_send_peer_flush_tids_cmd(struct ath11k *ar,
+                                       u8 peer_addr[ETH_ALEN],
+                                       struct peer_flush_params *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_peer_flush_tids_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_peer_flush_tids_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PEER_FLUSH_TIDS_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+       cmd->peer_tid_bitmap = param->peer_tid_bitmap;
+       cmd->vdev_id = param->vdev_id;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_FLUSH_TIDS_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_PEER_FLUSH_TIDS cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI peer flush vdev_id %d peer_addr %pM tids %08x\n",
+                  param->vdev_id, peer_addr, param->peer_tid_bitmap);
+
+       return ret;
+}
+
+int ath11k_wmi_peer_rx_reorder_queue_setup(struct ath11k *ar,
+                                          int vdev_id, const u8 *addr,
+                                          dma_addr_t paddr, u8 tid,
+                                          u8 ba_window_size_valid,
+                                          u32 ba_window_size)
+{
+       struct wmi_peer_reorder_queue_setup_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_peer_reorder_queue_setup_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                    WMI_TAG_REORDER_QUEUE_SETUP_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       ether_addr_copy(cmd->peer_macaddr.addr, addr);
+       cmd->vdev_id = vdev_id;
+       cmd->tid = tid;
+       cmd->queue_ptr_lo = lower_32_bits(paddr);
+       cmd->queue_ptr_hi = upper_32_bits(paddr);
+       cmd->queue_no = tid;
+       cmd->ba_window_size_valid = ba_window_size_valid;
+       cmd->ba_window_size = ba_window_size;
+
+       ret = ath11k_wmi_cmd_send(ar->wmi, skb,
+                                 WMI_PEER_REORDER_QUEUE_SETUP_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_PEER_REORDER_QUEUE_SETUP\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "wmi rx reorder queue setup addr %pM vdev_id %d tid %d\n",
+                  addr, vdev_id, tid);
+
+       return ret;
+}
+
+int
+ath11k_wmi_rx_reord_queue_remove(struct ath11k *ar,
+                                struct rx_reorder_queue_remove_params *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_peer_reorder_queue_remove_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_peer_reorder_queue_remove_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                    WMI_TAG_REORDER_QUEUE_REMOVE_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       ether_addr_copy(cmd->peer_macaddr.addr, param->peer_macaddr);
+       cmd->vdev_id = param->vdev_id;
+       cmd->tid_mask = param->peer_tid_bitmap;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "%s: peer_macaddr %pM vdev_id %d, tid_map %d", __func__,
+                  param->peer_macaddr, param->vdev_id, param->peer_tid_bitmap);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb,
+                                 WMI_PEER_REORDER_QUEUE_REMOVE_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_PEER_REORDER_QUEUE_REMOVE_CMDID");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id,
+                             u32 param_value, u8 pdev_id)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_pdev_set_param_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_pdev_set_param_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_SET_PARAM_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->pdev_id = pdev_id;
+       cmd->param_id = param_id;
+       cmd->param_value = param_value;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_PARAM_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_PDEV_SET_PARAM cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI pdev set param %d pdev id %d value %d\n",
+                  param_id, pdev_id, param_value);
+
+       return ret;
+}
+
+int ath11k_wmi_pdev_suspend(struct ath11k *ar, u32 suspend_opt,
+                           u32 pdev_id)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_pdev_suspend_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_pdev_suspend_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_SUSPEND_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->suspend_opt = suspend_opt;
+       cmd->pdev_id = pdev_id;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SUSPEND_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_PDEV_SUSPEND cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI pdev suspend pdev_id %d\n", pdev_id);
+
+       return ret;
+}
+
+int ath11k_wmi_pdev_resume(struct ath11k *ar, u32 pdev_id)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_pdev_resume_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_pdev_resume_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_RESUME_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->pdev_id = pdev_id;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI pdev resume pdev id %d\n", pdev_id);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_RESUME_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_PDEV_RESUME cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+/* TODO FW Support for the cmd is not available yet.
+ * Can be tested once the command and corresponding
+ * event is implemented in FW
+ */
+int ath11k_wmi_pdev_bss_chan_info_request(struct ath11k *ar,
+                                         enum wmi_bss_chan_info_req_type type)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_pdev_bss_chan_info_req_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_pdev_bss_chan_info_req_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                    WMI_TAG_PDEV_BSS_CHAN_INFO_REQUEST) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->req_type = type;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI bss chan info req type %d\n", type);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb,
+                                 WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_PDEV_BSS_CHAN_INFO_REQUEST cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_send_set_ap_ps_param_cmd(struct ath11k *ar, u8 *peer_addr,
+                                       struct ap_ps_params *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_ap_ps_peer_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_ap_ps_peer_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_AP_PS_PEER_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->vdev_id = param->vdev_id;
+       ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+       cmd->param = param->param;
+       cmd->value = param->value;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_AP_PS_PEER_PARAM_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_AP_PS_PEER_PARAM_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI set ap ps vdev id %d peer %pM param %d value %d\n",
+                  param->vdev_id, peer_addr, param->param, param->value);
+
+       return ret;
+}
+
+int ath11k_wmi_set_sta_ps_param(struct ath11k *ar, u32 vdev_id,
+                               u32 param, u32 param_value)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_sta_powersave_param_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_sta_powersave_param_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                    WMI_TAG_STA_POWERSAVE_PARAM_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->vdev_id = vdev_id;
+       cmd->param = param;
+       cmd->value = param_value;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI set sta ps vdev_id %d param %d value %d\n",
+                  vdev_id, param, param_value);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_PARAM_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_STA_POWERSAVE_PARAM_CMDID");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_force_fw_hang_cmd(struct ath11k *ar, u32 type, u32 delay_time_ms)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_force_fw_hang_cmd *cmd;
+       struct sk_buff *skb;
+       int ret, len;
+
+       len = sizeof(*cmd);
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_force_fw_hang_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_FORCE_FW_HANG_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
+
+       cmd->type = type;
+       cmd->delay_time_ms = delay_time_ms;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_FORCE_FW_HANG_CMDID);
+
+       if (ret) {
+               ath11k_warn(ar->ab, "Failed to send WMI_FORCE_FW_HANG_CMDID");
+               dev_kfree_skb(skb);
+       }
+       return ret;
+}
+
+int ath11k_wmi_vdev_set_param_cmd(struct ath11k *ar, u32 vdev_id,
+                                 u32 param_id, u32 param_value)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_vdev_set_param_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_set_param_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_SET_PARAM_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->vdev_id = vdev_id;
+       cmd->param_id = param_id;
+       cmd->param_value = param_value;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_SET_PARAM_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_VDEV_SET_PARAM_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI vdev id 0x%x set param %d value %d\n",
+                  vdev_id, param_id, param_value);
+
+       return ret;
+}
+
+int ath11k_wmi_send_stats_request_cmd(struct ath11k *ar,
+                                     struct stats_request_params *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_request_stats_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_request_stats_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_REQUEST_STATS_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->stats_id = param->stats_id;
+       cmd->vdev_id = param->vdev_id;
+       cmd->pdev_id = param->pdev_id;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_REQUEST_STATS_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_REQUEST_STATS cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI request stats 0x%x vdev id %d pdev id %d\n",
+                  param->stats_id, param->vdev_id, param->pdev_id);
+
+       return ret;
+}
+
+int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar,
+                                           u32 vdev_id, u32 bcn_ctrl_op)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_bcn_offload_ctrl_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_bcn_offload_ctrl_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                    WMI_TAG_BCN_OFFLOAD_CTRL_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->vdev_id = vdev_id;
+       cmd->bcn_ctrl_op = bcn_ctrl_op;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI bcn ctrl offload vdev id %d ctrl_op %d\n",
+                  vdev_id, bcn_ctrl_op);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_BCN_OFFLOAD_CTRL_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_BCN_OFFLOAD_CTRL_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id,
+                       struct ieee80211_mutable_offsets *offs,
+                       struct sk_buff *bcn)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_bcn_tmpl_cmd *cmd;
+       struct wmi_bcn_prb_info *bcn_prb_info;
+       struct wmi_tlv *tlv;
+       struct sk_buff *skb;
+       void *ptr;
+       int ret, len;
+       size_t aligned_len = roundup(bcn->len, 4);
+
+       len = sizeof(*cmd) + sizeof(*bcn_prb_info) + TLV_HDR_SIZE + aligned_len;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_bcn_tmpl_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_BCN_TMPL_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = vdev_id;
+       cmd->tim_ie_offset = offs->tim_offset;
+       cmd->csa_switch_count_offset = offs->csa_counter_offs[0];
+       cmd->ext_csa_switch_count_offset = offs->csa_counter_offs[1];
+       cmd->buf_len = bcn->len;
+
+       ptr = skb->data + sizeof(*cmd);
+
+       bcn_prb_info = ptr;
+       len = sizeof(*bcn_prb_info);
+       bcn_prb_info->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                             WMI_TAG_BCN_PRB_INFO) |
+                                  FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
+       bcn_prb_info->caps = 0;
+       bcn_prb_info->erp = 0;
+
+       ptr += sizeof(*bcn_prb_info);
+
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
+                     FIELD_PREP(WMI_TLV_LEN, aligned_len);
+       memcpy(tlv->value, bcn->data, bcn->len);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_BCN_TMPL_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_BCN_TMPL_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_vdev_install_key(struct ath11k *ar,
+                               struct wmi_vdev_install_key_arg *arg)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_vdev_install_key_cmd *cmd;
+       struct wmi_tlv *tlv;
+       struct sk_buff *skb;
+       int ret, len;
+       int key_len_aligned = roundup(arg->key_len, sizeof(uint32_t));
+
+       len = sizeof(*cmd) + TLV_HDR_SIZE + key_len_aligned;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_install_key_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VDEV_INSTALL_KEY_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+       cmd->vdev_id = arg->vdev_id;
+       ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr);
+       cmd->key_idx = arg->key_idx;
+       cmd->key_flags = arg->key_flags;
+       cmd->key_cipher = arg->key_cipher;
+       cmd->key_len = arg->key_len;
+       cmd->key_txmic_len = arg->key_txmic_len;
+       cmd->key_rxmic_len = arg->key_rxmic_len;
+
+       if (arg->key_rsc_counter)
+               memcpy(&cmd->key_rsc_counter, &arg->key_rsc_counter,
+                      sizeof(struct wmi_key_seq_counter));
+
+       tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd));
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
+                     FIELD_PREP(WMI_TLV_LEN, key_len_aligned);
+       memcpy(tlv->value, (u8 *)arg->key_data, key_len_aligned);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_INSTALL_KEY_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_VDEV_INSTALL_KEY cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI vdev install key idx %d cipher %d len %d\n",
+                  arg->key_idx, arg->key_cipher, arg->key_len);
+
+       return ret;
+}
+
+static inline void
+ath11k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
+                          struct peer_assoc_params *param)
+{
+       cmd->peer_flags = 0;
+
+       if (param->is_wme_set) {
+               if (param->qos_flag)
+                       cmd->peer_flags |= WMI_PEER_QOS;
+               if (param->apsd_flag)
+                       cmd->peer_flags |= WMI_PEER_APSD;
+               if (param->ht_flag)
+                       cmd->peer_flags |= WMI_PEER_HT;
+               if (param->bw_40)
+                       cmd->peer_flags |= WMI_PEER_40MHZ;
+               if (param->bw_80)
+                       cmd->peer_flags |= WMI_PEER_80MHZ;
+               if (param->bw_160)
+                       cmd->peer_flags |= WMI_PEER_160MHZ;
+
+               /* Typically if STBC is enabled for VHT it should be enabled
+                * for HT as well
+                **/
+               if (param->stbc_flag)
+                       cmd->peer_flags |= WMI_PEER_STBC;
+
+               /* Typically if LDPC is enabled for VHT it should be enabled
+                * for HT as well
+                **/
+               if (param->ldpc_flag)
+                       cmd->peer_flags |= WMI_PEER_LDPC;
+
+               if (param->static_mimops_flag)
+                       cmd->peer_flags |= WMI_PEER_STATIC_MIMOPS;
+               if (param->dynamic_mimops_flag)
+                       cmd->peer_flags |= WMI_PEER_DYN_MIMOPS;
+               if (param->spatial_mux_flag)
+                       cmd->peer_flags |= WMI_PEER_SPATIAL_MUX;
+               if (param->vht_flag)
+                       cmd->peer_flags |= WMI_PEER_VHT;
+               if (param->he_flag)
+                       cmd->peer_flags |= WMI_PEER_HE;
+       }
+
+       /* Suppress authorization for all AUTH modes that need 4-way handshake
+        * (during re-association).
+        * Authorization will be done for these modes on key installation.
+        */
+       if (param->auth_flag)
+               cmd->peer_flags |= WMI_PEER_AUTH;
+       if (param->need_ptk_4_way)
+               cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
+       else
+               cmd->peer_flags &= ~WMI_PEER_NEED_PTK_4_WAY;
+       if (param->need_gtk_2_way)
+               cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
+       /* safe mode bypass the 4-way handshake */
+       if (param->safe_mode_enabled)
+               cmd->peer_flags &= ~(WMI_PEER_NEED_PTK_4_WAY |
+                                    WMI_PEER_NEED_GTK_2_WAY);
+
+       if (param->is_pmf_enabled)
+               cmd->peer_flags |= WMI_PEER_PMF;
+
+       /* Disable AMSDU for station transmit, if user configures it */
+       /* Disable AMSDU for AP transmit to 11n Stations, if user configures
+        * it
+        * if (param->amsdu_disable) Add after FW support
+        **/
+
+       /* Target asserts if node is marked HT and all MCS is set to 0.
+        * Mark the node as non-HT if all the mcs rates are disabled through
+        * iwpriv
+        **/
+       if (param->peer_ht_rates.num_rates == 0)
+               cmd->peer_flags &= ~WMI_PEER_HT;
+}
+
+int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar,
+                                  struct peer_assoc_params *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_peer_assoc_complete_cmd *cmd;
+       struct wmi_vht_rate_set *mcs;
+       struct wmi_he_rate_set *he_mcs;
+       struct sk_buff *skb;
+       struct wmi_tlv *tlv;
+       void *ptr;
+       u32 peer_legacy_rates_align;
+       u32 peer_ht_rates_align;
+       int i, ret, len;
+
+       peer_legacy_rates_align = roundup(param->peer_legacy_rates.num_rates,
+                                         sizeof(u32));
+       peer_ht_rates_align = roundup(param->peer_ht_rates.num_rates,
+                                     sizeof(u32));
+
+       len = sizeof(*cmd) +
+             TLV_HDR_SIZE + (peer_legacy_rates_align * sizeof(u8)) +
+             TLV_HDR_SIZE + (peer_ht_rates_align * sizeof(u8)) +
+             sizeof(*mcs) + TLV_HDR_SIZE +
+             (sizeof(*he_mcs) * param->peer_he_mcs_count);
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       ptr = skb->data;
+
+       cmd = ptr;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                    WMI_TAG_PEER_ASSOC_COMPLETE_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->vdev_id = param->vdev_id;
+
+       cmd->peer_new_assoc = param->peer_new_assoc;
+       cmd->peer_associd = param->peer_associd;
+
+       ath11k_wmi_copy_peer_flags(cmd, param);
+
+       ether_addr_copy(cmd->peer_macaddr.addr, param->peer_mac);
+
+       cmd->peer_rate_caps = param->peer_rate_caps;
+       cmd->peer_caps = param->peer_caps;
+       cmd->peer_listen_intval = param->peer_listen_intval;
+       cmd->peer_ht_caps = param->peer_ht_caps;
+       cmd->peer_max_mpdu = param->peer_max_mpdu;
+       cmd->peer_mpdu_density = param->peer_mpdu_density;
+       cmd->peer_vht_caps = param->peer_vht_caps;
+       cmd->peer_phymode = param->peer_phymode;
+
+       /* Update 11ax capabilities */
+       cmd->peer_he_cap_info = param->peer_he_cap_macinfo[0];
+       cmd->peer_he_cap_info_ext = param->peer_he_cap_macinfo[1];
+       cmd->peer_he_cap_info_internal = param->peer_he_cap_macinfo_internal;
+       cmd->peer_he_ops = param->peer_he_ops;
+       memcpy(&cmd->peer_he_cap_phy, ¶m->peer_he_cap_phyinfo,
+              sizeof(param->peer_he_cap_phyinfo));
+       memcpy(&cmd->peer_ppet, ¶m->peer_ppet,
+              sizeof(param->peer_ppet));
+
+       /* Update peer legacy rate information */
+       ptr += sizeof(*cmd);
+
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
+                     FIELD_PREP(WMI_TLV_LEN, peer_legacy_rates_align);
+
+       ptr += TLV_HDR_SIZE;
+
+       cmd->num_peer_legacy_rates = param->peer_legacy_rates.num_rates;
+       memcpy(ptr, param->peer_legacy_rates.rates,
+              param->peer_legacy_rates.num_rates);
+
+       /* Update peer HT rate information */
+       ptr += peer_legacy_rates_align;
+
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
+                     FIELD_PREP(WMI_TLV_LEN, peer_ht_rates_align);
+       ptr += TLV_HDR_SIZE;
+       cmd->num_peer_ht_rates = param->peer_ht_rates.num_rates;
+       memcpy(ptr, param->peer_ht_rates.rates,
+              param->peer_ht_rates.num_rates);
+
+       /* VHT Rates */
+       ptr += peer_ht_rates_align;
+
+       mcs = ptr;
+
+       mcs->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_VHT_RATE_SET) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*mcs) - TLV_HDR_SIZE);
+
+       cmd->peer_nss = param->peer_nss;
+
+       /* Update bandwidth-NSS mapping */
+       cmd->peer_bw_rxnss_override = 0;
+       cmd->peer_bw_rxnss_override |= param->peer_bw_rxnss_override;
+
+       if (param->vht_capable) {
+               mcs->rx_max_rate = param->rx_max_rate;
+               mcs->rx_mcs_set = param->rx_mcs_set;
+               mcs->tx_max_rate = param->tx_max_rate;
+               mcs->tx_mcs_set = param->tx_mcs_set;
+       }
+
+       /* HE Rates */
+       cmd->peer_he_mcs = param->peer_he_mcs_count;
+
+       ptr += sizeof(*mcs);
+
+       len = param->peer_he_mcs_count * sizeof(*he_mcs);
+
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+                     FIELD_PREP(WMI_TLV_LEN, len);
+       ptr += TLV_HDR_SIZE;
+
+       /* Loop through the HE rate set */
+       for (i = 0; i < param->peer_he_mcs_count; i++) {
+               he_mcs = ptr;
+               he_mcs->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                               WMI_TAG_HE_RATE_SET) |
+                                    FIELD_PREP(WMI_TLV_LEN,
+                                               sizeof(*he_mcs) - TLV_HDR_SIZE);
+
+               he_mcs->rx_mcs_set = param->peer_he_rx_mcs_set[i];
+               he_mcs->tx_mcs_set = param->peer_he_tx_mcs_set[i];
+               ptr += sizeof(*he_mcs);
+       }
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_ASSOC_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_PEER_ASSOC_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI peer assoc vdev id %d assoc id %d peer mac %pM\n",
+                  param->vdev_id, param->peer_associd, param->peer_mac);
+
+       return ret;
+}
+
+void ath11k_wmi_start_scan_init(struct ath11k *ar,
+                               struct scan_req_params *arg)
+{
+       /* setup commonly used values */
+       arg->scan_req_id = 1;
+       arg->scan_priority = WMI_SCAN_PRIORITY_LOW;
+       arg->dwell_time_active = 50;
+       arg->dwell_time_active_2g = 0;
+       arg->dwell_time_passive = 150;
+       arg->min_rest_time = 50;
+       arg->max_rest_time = 500;
+       arg->repeat_probe_time = 0;
+       arg->probe_spacing_time = 0;
+       arg->idle_time = 0;
+       arg->max_scan_time = 20000;
+       arg->probe_delay = 5;
+       arg->notify_scan_events = WMI_SCAN_EVENT_STARTED |
+                                 WMI_SCAN_EVENT_COMPLETED |
+                                 WMI_SCAN_EVENT_BSS_CHANNEL |
+                                 WMI_SCAN_EVENT_FOREIGN_CHAN |
+                                 WMI_SCAN_EVENT_DEQUEUED;
+       arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT;
+       arg->num_bssid = 1;
+}
+
+static inline void
+ath11k_wmi_copy_scan_event_cntrl_flags(struct wmi_start_scan_cmd *cmd,
+                                      struct scan_req_params *param)
+{
+       /* Scan events subscription */
+       if (param->scan_ev_started)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_STARTED;
+       if (param->scan_ev_completed)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_COMPLETED;
+       if (param->scan_ev_bss_chan)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_BSS_CHANNEL;
+       if (param->scan_ev_foreign_chan)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_FOREIGN_CHAN;
+       if (param->scan_ev_dequeued)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_DEQUEUED;
+       if (param->scan_ev_preempted)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_PREEMPTED;
+       if (param->scan_ev_start_failed)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_START_FAILED;
+       if (param->scan_ev_restarted)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_RESTARTED;
+       if (param->scan_ev_foreign_chn_exit)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT;
+       if (param->scan_ev_suspended)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_SUSPENDED;
+       if (param->scan_ev_resumed)
+               cmd->notify_scan_events |=  WMI_SCAN_EVENT_RESUMED;
+
+       /** Set scan control flags */
+       cmd->scan_ctrl_flags = 0;
+       if (param->scan_f_passive)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_FLAG_PASSIVE;
+       if (param->scan_f_strict_passive_pch)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_FLAG_STRICT_PASSIVE_ON_PCHN;
+       if (param->scan_f_promisc_mode)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_FILTER_PROMISCUOS;
+       if (param->scan_f_capture_phy_err)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_CAPTURE_PHY_ERROR;
+       if (param->scan_f_half_rate)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_FLAG_HALF_RATE_SUPPORT;
+       if (param->scan_f_quarter_rate)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_FLAG_QUARTER_RATE_SUPPORT;
+       if (param->scan_f_cck_rates)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_ADD_CCK_RATES;
+       if (param->scan_f_ofdm_rates)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_ADD_OFDM_RATES;
+       if (param->scan_f_chan_stat_evnt)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_CHAN_STAT_EVENT;
+       if (param->scan_f_filter_prb_req)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_FILTER_PROBE_REQ;
+       if (param->scan_f_bcast_probe)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_ADD_BCAST_PROBE_REQ;
+       if (param->scan_f_offchan_mgmt_tx)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_OFFCHAN_MGMT_TX;
+       if (param->scan_f_offchan_data_tx)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_OFFCHAN_DATA_TX;
+       if (param->scan_f_force_active_dfs_chn)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS;
+       if (param->scan_f_add_tpc_ie_in_probe)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_ADD_TPC_IE_IN_PROBE_REQ;
+       if (param->scan_f_add_ds_ie_in_probe)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ;
+       if (param->scan_f_add_spoofed_mac_in_probe)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_ADD_SPOOF_MAC_IN_PROBE_REQ;
+       if (param->scan_f_add_rand_seq_in_probe)
+               cmd->scan_ctrl_flags |=  WMI_SCAN_RANDOM_SEQ_NO_IN_PROBE_REQ;
+       if (param->scan_f_en_ie_whitelist_in_probe)
+               cmd->scan_ctrl_flags |=
+                        WMI_SCAN_ENABLE_IE_WHTELIST_IN_PROBE_REQ;
+
+       /* for adaptive scan mode using 3 bits (21 - 23 bits) */
+       WMI_SCAN_SET_DWELL_MODE(cmd->scan_ctrl_flags,
+                               param->adaptive_dwell_time_mode);
+}
+
+int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
+                                  struct scan_req_params *params)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_start_scan_cmd *cmd;
+       struct wmi_ssid *ssid = NULL;
+       struct wmi_mac_addr *bssid;
+       struct sk_buff *skb;
+       struct wmi_tlv *tlv;
+       void *ptr;
+       int i, ret, len;
+       u32 *tmp_ptr;
+       u8 extraie_len_with_pad = 0;
+
+       len = sizeof(*cmd);
+
+       len += TLV_HDR_SIZE;
+       if (params->num_chan)
+               len += params->num_chan * sizeof(u32);
+
+       len += TLV_HDR_SIZE;
+       if (params->num_ssids)
+               len += params->num_ssids * sizeof(*ssid);
+
+       len += TLV_HDR_SIZE;
+       if (params->num_bssid)
+               len += sizeof(*bssid) * params->num_bssid;
+
+       len += TLV_HDR_SIZE;
+       if (params->extraie.len)
+               extraie_len_with_pad =
+                       roundup(params->extraie.len, sizeof(u32));
+       len += extraie_len_with_pad;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       ptr = skb->data;
+
+       cmd = ptr;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_START_SCAN_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->scan_id = params->scan_id;
+       cmd->scan_req_id = params->scan_req_id;
+       cmd->vdev_id = params->vdev_id;
+       cmd->scan_priority = params->scan_priority;
+       cmd->notify_scan_events = params->notify_scan_events;
+
+       ath11k_wmi_copy_scan_event_cntrl_flags(cmd, params);
+
+       cmd->dwell_time_active = params->dwell_time_active;
+       cmd->dwell_time_active_2g = params->dwell_time_active_2g;
+       cmd->dwell_time_passive = params->dwell_time_passive;
+       cmd->min_rest_time = params->min_rest_time;
+       cmd->max_rest_time = params->max_rest_time;
+       cmd->repeat_probe_time = params->repeat_probe_time;
+       cmd->probe_spacing_time = params->probe_spacing_time;
+       cmd->idle_time = params->idle_time;
+       cmd->max_scan_time = params->max_scan_time;
+       cmd->probe_delay = params->probe_delay;
+       cmd->burst_duration = params->burst_duration;
+       cmd->num_chan = params->num_chan;
+       cmd->num_bssid = params->num_bssid;
+       cmd->num_ssids = params->num_ssids;
+       cmd->ie_len = params->extraie.len;
+       cmd->n_probes = params->n_probes;
+
+       ptr += sizeof(*cmd);
+
+       len = params->num_chan * sizeof(u32);
+
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_UINT32) |
+                     FIELD_PREP(WMI_TLV_LEN, len);
+       ptr += TLV_HDR_SIZE;
+       tmp_ptr = (u32 *)ptr;
+
+       for (i = 0; i < params->num_chan; ++i)
+               tmp_ptr[i] = params->chan_list[i];
+
+       ptr += len;
+
+       len = params->num_ssids * sizeof(*ssid);
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) |
+                     FIELD_PREP(WMI_TLV_LEN, len);
+
+       ptr += TLV_HDR_SIZE;
+
+       if (params->num_ssids) {
+               ssid = ptr;
+               for (i = 0; i < params->num_ssids; ++i) {
+                       ssid->ssid_len = params->ssid[i].length;
+                       memcpy(ssid->ssid, params->ssid[i].ssid,
+                              params->ssid[i].length);
+                       ssid++;
+               }
+       }
+
+       ptr += (params->num_ssids * sizeof(*ssid));
+       len = params->num_bssid * sizeof(*bssid);
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) |
+                     FIELD_PREP(WMI_TLV_LEN, len);
+
+       ptr += TLV_HDR_SIZE;
+       bssid = ptr;
+
+       if (params->num_bssid) {
+               for (i = 0; i < params->num_bssid; ++i) {
+                       ether_addr_copy(bssid->addr,
+                                       params->bssid_list[i].addr);
+                       bssid++;
+               }
+       }
+
+       ptr += params->num_bssid * sizeof(*bssid);
+
+       len = extraie_len_with_pad;
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
+                     FIELD_PREP(WMI_TLV_LEN, len);
+       ptr += TLV_HDR_SIZE;
+
+       if (params->extraie.len)
+               memcpy(ptr, params->extraie.ptr,
+                      params->extraie.len);
+
+       ptr += extraie_len_with_pad;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb,
+                                 WMI_START_SCAN_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_START_SCAN_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_send_scan_stop_cmd(struct ath11k *ar,
+                                 struct scan_cancel_param *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_stop_scan_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_stop_scan_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_STOP_SCAN_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->vdev_id = param->vdev_id;
+       cmd->requestor = param->requester;
+       cmd->scan_id = param->scan_id;
+       cmd->pdev_id = param->pdev_id;
+       /* stop the scan with the corresponding scan_id */
+       if (param->req_type == WLAN_SCAN_CANCEL_PDEV_ALL) {
+               /* Cancelling all scans */
+               cmd->req_type =  WMI_SCAN_STOP_ALL;
+       } else if (param->req_type == WLAN_SCAN_CANCEL_VDEV_ALL) {
+               /* Cancelling VAP scans */
+               cmd->req_type =  WMI_SCN_STOP_VAP_ALL;
+       } else if (param->req_type == WLAN_SCAN_CANCEL_SINGLE) {
+               /* Cancelling specific scan */
+               cmd->req_type =  WMI_SCAN_STOP_ONE;
+       } else {
+               ath11k_warn(ar->ab, "invalid scan cancel param %d",
+                           param->req_type);
+               dev_kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       ret = ath11k_wmi_cmd_send(wmi, skb,
+                                 WMI_STOP_SCAN_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_STOP_SCAN_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
+                                      struct scan_chan_list_params *chan_list)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_scan_chan_list_cmd *cmd;
+       struct sk_buff *skb;
+       struct wmi_channel *chan_info;
+       struct channel_param *tchan_info;
+       struct wmi_tlv *tlv;
+       void *ptr;
+       int i, ret, len;
+       u32 *reg1, *reg2;
+
+       len = sizeof(*cmd) + TLV_HDR_SIZE +
+                sizeof(*chan_info) * chan_list->nallchans;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_scan_chan_list_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SCAN_CHAN_LIST_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI no.of chan = %d len = %d\n", chan_list->nallchans, len);
+       cmd->pdev_id = chan_list->pdev_id;
+       cmd->num_scan_chans = chan_list->nallchans;
+
+       ptr = skb->data + sizeof(*cmd);
+
+       len = sizeof(*chan_info) * chan_list->nallchans;
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+                     FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
+       ptr += TLV_HDR_SIZE;
+
+       tchan_info = &chan_list->ch_param[0];
+
+       for (i = 0; i < chan_list->nallchans; ++i) {
+               chan_info = ptr;
+               memset(chan_info, 0, sizeof(*chan_info));
+               len = sizeof(*chan_info);
+               chan_info->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                                  WMI_TAG_CHANNEL) |
+                                       FIELD_PREP(WMI_TLV_LEN,
+                                                  len - TLV_HDR_SIZE);
+
+               reg1 = &chan_info->reg_info_1;
+               reg2 = &chan_info->reg_info_2;
+               chan_info->mhz = tchan_info->mhz;
+               chan_info->band_center_freq1 = tchan_info->cfreq1;
+               chan_info->band_center_freq2 = tchan_info->cfreq2;
+
+               if (tchan_info->is_chan_passive)
+                       chan_info->info |= WMI_CHAN_INFO_PASSIVE;
+               if (tchan_info->allow_vht)
+                       chan_info->info |= WMI_CHAN_INFO_ALLOW_VHT;
+               else if (tchan_info->allow_ht)
+                       chan_info->info |= WMI_CHAN_INFO_ALLOW_HT;
+               if (tchan_info->half_rate)
+                       chan_info->info |= WMI_CHAN_INFO_HALF_RATE;
+               if (tchan_info->quarter_rate)
+                       chan_info->info |= WMI_CHAN_INFO_QUARTER_RATE;
+
+               chan_info->info |= FIELD_PREP(WMI_CHAN_INFO_MODE,
+                                             tchan_info->phy_mode);
+               *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MIN_PWR,
+                                   tchan_info->minpower);
+               *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_PWR,
+                                   tchan_info->maxpower);
+               *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_REG_PWR,
+                                   tchan_info->maxregpower);
+               *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_REG_CLS,
+                                   tchan_info->reg_class_id);
+               *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_ANT_MAX,
+                                   tchan_info->antennamax);
+
+               ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                          "WMI chan scan list chan[%d] = %u\n",
+                          i, chan_info->mhz);
+
+               ptr += sizeof(*chan_info);
+
+               tchan_info++;
+       }
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SCAN_CHAN_LIST_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_SCAN_CHAN_LIST cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
+                                      struct wmi_wmm_params_all_arg *param)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_vdev_set_wmm_params_cmd *cmd;
+       struct wmi_wmm_params *wmm_param;
+       struct wmi_wmm_params_arg *wmi_wmm_arg;
+       struct sk_buff *skb;
+       int ret, ac;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_set_wmm_params_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                    WMI_TAG_VDEV_SET_WMM_PARAMS_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->vdev_id = vdev_id;
+       cmd->wmm_param_type = 0;
+
+       for (ac = 0; ac < WME_NUM_AC; ac++) {
+               switch (ac) {
+               case WME_AC_BE:
+                       wmi_wmm_arg = ¶m->ac_be;
+                       break;
+               case WME_AC_BK:
+                       wmi_wmm_arg = ¶m->ac_bk;
+                       break;
+               case WME_AC_VI:
+                       wmi_wmm_arg = ¶m->ac_vi;
+                       break;
+               case WME_AC_VO:
+                       wmi_wmm_arg = ¶m->ac_vo;
+                       break;
+               }
+
+               wmm_param = (struct wmi_wmm_params *)&cmd->wmm_params[ac];
+               wmm_param->tlv_header =
+                               FIELD_PREP(WMI_TLV_TAG,
+                                          WMI_TAG_VDEV_SET_WMM_PARAMS_CMD) |
+                               FIELD_PREP(WMI_TLV_LEN,
+                                          sizeof(*wmm_param) - TLV_HDR_SIZE);
+
+               wmm_param->aifs = wmi_wmm_arg->aifs;
+               wmm_param->cwmin = wmi_wmm_arg->cwmin;
+               wmm_param->cwmax = wmi_wmm_arg->cwmax;
+               wmm_param->txoplimit = wmi_wmm_arg->txop;
+               wmm_param->acm = wmi_wmm_arg->acm;
+               wmm_param->no_ack = wmi_wmm_arg->no_ack;
+
+               ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                          "wmi wmm set ac %d aifs %d cwmin %d cwmax %d txop %d acm %d no_ack %d\n",
+                          ac, wmm_param->aifs, wmm_param->cwmin,
+                          wmm_param->cwmax, wmm_param->txoplimit,
+                          wmm_param->acm, wmm_param->no_ack);
+       }
+       ret = ath11k_wmi_cmd_send(wmi, skb,
+                                 WMI_VDEV_SET_WMM_PARAMS_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_VDEV_SET_WMM_PARAMS_CMDID");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath11k *ar,
+                                                 u32 pdev_id)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_dfs_phyerr_offload_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_dfs_phyerr_offload_cmd *)skb->data;
+       cmd->tlv_header =
+               FIELD_PREP(WMI_TLV_TAG,
+                          WMI_TAG_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMD) |
+               FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->pdev_id = pdev_id;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI dfs phy err offload enable pdev id %d\n", pdev_id);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb,
+                                 WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE cmd\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_pdev_peer_pktlog_filter(struct ath11k *ar, u8 *addr, u8 enable)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_pdev_pktlog_filter_cmd *cmd;
+       struct wmi_pdev_pktlog_filter_info *info;
+       struct sk_buff *skb;
+       struct wmi_tlv *tlv;
+       void *ptr;
+       int ret, len;
+
+       len = sizeof(*cmd) + sizeof(*info) + TLV_HDR_SIZE;
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_pdev_pktlog_filter_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_PEER_PKTLOG_FILTER_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->pdev_id = ar->pdev->pdev_id;
+       cmd->num_mac = 1;
+       cmd->enable = enable;
+
+       ptr = skb->data + sizeof(*cmd);
+
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+                     FIELD_PREP(WMI_TLV_LEN, 0);
+
+       ptr += TLV_HDR_SIZE;
+       info = ptr;
+
+       ether_addr_copy(info->peer_macaddr.addr, addr);
+       info->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_PEER_PKTLOG_FILTER_INFO) |
+                          FIELD_PREP(WMI_TLV_LEN,
+                                     sizeof(*info) - TLV_HDR_SIZE);
+
+       ret = ath11k_wmi_cmd_send(wmi, skb,
+                                 WMI_PDEV_PKTLOG_FILTER_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_PDEV_PKTLOG_ENABLE_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int
+ath11k_wmi_send_init_country_cmd(struct ath11k *ar,
+                                struct wmi_init_country_params init_cc_params)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_init_country_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_init_country_cmd *)skb->data;
+       cmd->tlv_header =
+               FIELD_PREP(WMI_TLV_TAG,
+                          WMI_TAG_SET_INIT_COUNTRY_CMD) |
+               FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->pdev_id = ar->pdev->pdev_id;
+
+       switch (init_cc_params.flags) {
+       case ALPHA_IS_SET:
+               cmd->init_cc_type = WMI_COUNTRY_INFO_TYPE_ALPHA;
+               memcpy((u8 *)&cmd->cc_info.alpha2,
+                      init_cc_params.cc_info.alpha2, 3);
+               break;
+       case CC_IS_SET:
+               cmd->init_cc_type = WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE;
+               cmd->cc_info.country_code = init_cc_params.cc_info.country_code;
+               break;
+       case REGDMN_IS_SET:
+               cmd->init_cc_type = WMI_COUNTRY_INFO_TYPE_REGDOMAIN;
+               cmd->cc_info.regdom_id = init_cc_params.cc_info.regdom_id;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = ath11k_wmi_cmd_send(wmi, skb,
+                                 WMI_SET_INIT_COUNTRY_CMDID);
+
+out:
+       if (ret) {
+               ath11k_warn(ar->ab,
+                           "failed to send WMI_SET_INIT_COUNTRY CMD :%d\n",
+                           ret);
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_pktlog_enable_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_pktlog_enable_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_PKTLOG_ENABLE_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->pdev_id = ar->pdev->pdev_id;
+       cmd->evlist = pktlog_filter;
+       cmd->enable = ATH11K_WMI_PKTLOG_ENABLE_FORCE;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb,
+                                 WMI_PDEV_PKTLOG_ENABLE_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_PDEV_PKTLOG_ENABLE_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_pdev_pktlog_disable(struct ath11k *ar)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_pktlog_disable_cmd *cmd;
+       struct sk_buff *skb;
+       int ret;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_pktlog_disable_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_PKTLOG_DISABLE_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       cmd->pdev_id = ar->pdev->pdev_id;
+
+       ret = ath11k_wmi_cmd_send(wmi, skb,
+                                 WMI_PDEV_PKTLOG_DISABLE_CMDID);
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_PDEV_PKTLOG_ENABLE_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+static void
+ath11k_fill_band_to_mac_param(struct ath11k_base  *soc,
+                             struct wmi_host_pdev_band_to_mac *band_to_mac)
+{
+       u8 i;
+       struct ath11k_hal_reg_capabilities_ext *hal_reg_cap;
+       struct ath11k_pdev *pdev;
+
+       for (i = 0; i < soc->num_radios; i++) {
+               pdev = &soc->pdevs[i];
+               hal_reg_cap = &soc->hal_reg_cap[i];
+               band_to_mac[i].pdev_id = pdev->pdev_id;
+
+               switch (pdev->cap.supported_bands) {
+               case WMI_HOST_WLAN_2G_5G_CAP:
+                       band_to_mac[i].start_freq = hal_reg_cap->low_2ghz_chan;
+                       band_to_mac[i].end_freq = hal_reg_cap->high_5ghz_chan;
+                       break;
+               case WMI_HOST_WLAN_2G_CAP:
+                       band_to_mac[i].start_freq = hal_reg_cap->low_2ghz_chan;
+                       band_to_mac[i].end_freq = hal_reg_cap->high_2ghz_chan;
+                       break;
+               case WMI_HOST_WLAN_5G_CAP:
+                       band_to_mac[i].start_freq = hal_reg_cap->low_5ghz_chan;
+                       band_to_mac[i].end_freq = hal_reg_cap->high_5ghz_chan;
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void
+ath11k_wmi_copy_resource_config(struct wmi_resource_config *wmi_cfg,
+                               struct target_resource_config *tg_cfg)
+{
+       wmi_cfg->num_vdevs = tg_cfg->num_vdevs;
+       wmi_cfg->num_peers = tg_cfg->num_peers;
+       wmi_cfg->num_offload_peers = tg_cfg->num_offload_peers;
+       wmi_cfg->num_offload_reorder_buffs = tg_cfg->num_offload_reorder_buffs;
+       wmi_cfg->num_peer_keys = tg_cfg->num_peer_keys;
+       wmi_cfg->num_tids = tg_cfg->num_tids;
+       wmi_cfg->ast_skid_limit = tg_cfg->ast_skid_limit;
+       wmi_cfg->tx_chain_mask = tg_cfg->tx_chain_mask;
+       wmi_cfg->rx_chain_mask = tg_cfg->rx_chain_mask;
+       wmi_cfg->rx_timeout_pri[0] = tg_cfg->rx_timeout_pri[0];
+       wmi_cfg->rx_timeout_pri[1] = tg_cfg->rx_timeout_pri[1];
+       wmi_cfg->rx_timeout_pri[2] = tg_cfg->rx_timeout_pri[2];
+       wmi_cfg->rx_timeout_pri[3] = tg_cfg->rx_timeout_pri[3];
+       wmi_cfg->rx_decap_mode = tg_cfg->rx_decap_mode;
+       wmi_cfg->scan_max_pending_req = tg_cfg->scan_max_pending_req;
+       wmi_cfg->bmiss_offload_max_vdev = tg_cfg->bmiss_offload_max_vdev;
+       wmi_cfg->roam_offload_max_vdev = tg_cfg->roam_offload_max_vdev;
+       wmi_cfg->roam_offload_max_ap_profiles =
+               tg_cfg->roam_offload_max_ap_profiles;
+       wmi_cfg->num_mcast_groups = tg_cfg->num_mcast_groups;
+       wmi_cfg->num_mcast_table_elems = tg_cfg->num_mcast_table_elems;
+       wmi_cfg->mcast2ucast_mode = tg_cfg->mcast2ucast_mode;
+       wmi_cfg->tx_dbg_log_size = tg_cfg->tx_dbg_log_size;
+       wmi_cfg->num_wds_entries = tg_cfg->num_wds_entries;
+       wmi_cfg->dma_burst_size = tg_cfg->dma_burst_size;
+       wmi_cfg->mac_aggr_delim = tg_cfg->mac_aggr_delim;
+       wmi_cfg->rx_skip_defrag_timeout_dup_detection_check =
+               tg_cfg->rx_skip_defrag_timeout_dup_detection_check;
+       wmi_cfg->vow_config = tg_cfg->vow_config;
+       wmi_cfg->gtk_offload_max_vdev = tg_cfg->gtk_offload_max_vdev;
+       wmi_cfg->num_msdu_desc = tg_cfg->num_msdu_desc;
+       wmi_cfg->max_frag_entries = tg_cfg->max_frag_entries;
+       wmi_cfg->num_tdls_vdevs = tg_cfg->num_tdls_vdevs;
+       wmi_cfg->num_tdls_conn_table_entries =
+               tg_cfg->num_tdls_conn_table_entries;
+       wmi_cfg->beacon_tx_offload_max_vdev =
+               tg_cfg->beacon_tx_offload_max_vdev;
+       wmi_cfg->num_multicast_filter_entries =
+               tg_cfg->num_multicast_filter_entries;
+       wmi_cfg->num_wow_filters = tg_cfg->num_wow_filters;
+       wmi_cfg->num_keep_alive_pattern = tg_cfg->num_keep_alive_pattern;
+       wmi_cfg->keep_alive_pattern_size = tg_cfg->keep_alive_pattern_size;
+       wmi_cfg->max_tdls_concurrent_sleep_sta =
+               tg_cfg->max_tdls_concurrent_sleep_sta;
+       wmi_cfg->max_tdls_concurrent_buffer_sta =
+               tg_cfg->max_tdls_concurrent_buffer_sta;
+       wmi_cfg->wmi_send_separate = tg_cfg->wmi_send_separate;
+       wmi_cfg->num_ocb_vdevs = tg_cfg->num_ocb_vdevs;
+       wmi_cfg->num_ocb_channels = tg_cfg->num_ocb_channels;
+       wmi_cfg->num_ocb_schedules = tg_cfg->num_ocb_schedules;
+       wmi_cfg->bpf_instruction_size = tg_cfg->bpf_instruction_size;
+       wmi_cfg->max_bssid_rx_filters = tg_cfg->max_bssid_rx_filters;
+       wmi_cfg->use_pdev_id = tg_cfg->use_pdev_id;
+       wmi_cfg->flag1 = tg_cfg->atf_config;
+       wmi_cfg->peer_map_unmap_v2_support = tg_cfg->peer_map_unmap_v2_support;
+}
+
+static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi,
+                               struct wmi_init_cmd_param *param)
+{
+       struct ath11k_base *ab = wmi->wmi_sc->ab;
+       struct sk_buff *skb;
+       struct wmi_init_cmd *cmd;
+       struct wmi_resource_config *cfg;
+       struct wmi_pdev_set_hw_mode_cmd_param *hw_mode;
+       struct wmi_pdev_band_to_mac *band_to_mac;
+       struct wlan_host_mem_chunk *host_mem_chunks;
+       struct wmi_tlv *tlv;
+       size_t ret, len;
+       void *ptr;
+       u32 hw_mode_len = 0;
+       u16 idx;
+
+       if (param->hw_mode_id != WMI_HOST_HW_MODE_MAX)
+               hw_mode_len = sizeof(*hw_mode) + TLV_HDR_SIZE +
+                             (param->num_band_to_mac * sizeof(*band_to_mac));
+
+       len = sizeof(*cmd) + TLV_HDR_SIZE + sizeof(*cfg) + hw_mode_len +
+             (sizeof(*host_mem_chunks) * WMI_MAX_MEM_REQS);
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_init_cmd *)skb->data;
+
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_INIT_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
+
+       ptr = skb->data + sizeof(*cmd);
+       cfg = ptr;
+
+       ath11k_wmi_copy_resource_config(cfg, param->res_cfg);
+
+       cfg->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_RESOURCE_CONFIG) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(*cfg) - TLV_HDR_SIZE);
+
+       ptr += sizeof(*cfg);
+       host_mem_chunks = ptr + TLV_HDR_SIZE;
+       len = sizeof(struct wlan_host_mem_chunk);
+
+       for (idx = 0; idx < param->num_mem_chunks; ++idx) {
+               host_mem_chunks[idx].tlv_header =
+                               FIELD_PREP(WMI_TLV_TAG,
+                                          WMI_TAG_WLAN_HOST_MEMORY_CHUNK) |
+                               FIELD_PREP(WMI_TLV_LEN, len);
+
+               host_mem_chunks[idx].ptr = param->mem_chunks[idx].paddr;
+               host_mem_chunks[idx].size = param->mem_chunks[idx].len;
+               host_mem_chunks[idx].req_id = param->mem_chunks[idx].req_id;
+
+               ath11k_dbg(ab, ATH11K_DBG_WMI,
+                          "WMI host mem chunk req_id %d paddr 0x%llx len %d\n",
+                          param->mem_chunks[idx].req_id,
+                          (u64)param->mem_chunks[idx].paddr,
+                          param->mem_chunks[idx].len);
+       }
+       cmd->num_host_mem_chunks = param->num_mem_chunks;
+       len = sizeof(struct wlan_host_mem_chunk) * param->num_mem_chunks;
+
+       /* num_mem_chunks is zero */
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+                     FIELD_PREP(WMI_TLV_LEN, len);
+       ptr += TLV_HDR_SIZE + len;
+
+       if (param->hw_mode_id != WMI_HOST_HW_MODE_MAX) {
+               hw_mode = (struct wmi_pdev_set_hw_mode_cmd_param *)ptr;
+               hw_mode->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                                WMI_TAG_PDEV_SET_HW_MODE_CMD) |
+                                     FIELD_PREP(WMI_TLV_LEN,
+                                                sizeof(*hw_mode) - TLV_HDR_SIZE);
+
+               hw_mode->hw_mode_index = param->hw_mode_id;
+               hw_mode->num_band_to_mac = param->num_band_to_mac;
+
+               ptr += sizeof(*hw_mode);
+
+               len = param->num_band_to_mac * sizeof(*band_to_mac);
+               tlv = ptr;
+               tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+                             FIELD_PREP(WMI_TLV_LEN, len);
+
+               ptr += TLV_HDR_SIZE;
+               len = sizeof(*band_to_mac);
+
+               for (idx = 0; idx < param->num_band_to_mac; idx++) {
+                       band_to_mac = (void *)ptr;
+
+                       band_to_mac->tlv_header = FIELD_PREP(WMI_TLV_TAG,
+                                                            WMI_TAG_PDEV_BAND_TO_MAC) |
+                                                 FIELD_PREP(WMI_TLV_LEN,
+                                                            len - TLV_HDR_SIZE);
+                       band_to_mac->pdev_id = param->band_to_mac[idx].pdev_id;
+                       band_to_mac->start_freq =
+                               param->band_to_mac[idx].start_freq;
+                       band_to_mac->end_freq =
+                               param->band_to_mac[idx].end_freq;
+                       ptr += sizeof(*band_to_mac);
+               }
+       }
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_INIT_CMDID);
+       if (ret) {
+               ath11k_warn(ab, "failed to send WMI_INIT_CMDID\n");
+               dev_kfree_skb(skb);
+       }
+
+       return ret;
+}
+
+int ath11k_wmi_wait_for_service_ready(struct ath11k_base *ab)
+{
+       unsigned long time_left;
+
+       time_left = wait_for_completion_timeout(&ab->wmi_sc.service_ready,
+                                               WMI_SERVICE_READY_TIMEOUT_HZ);
+       if (!time_left)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+int ath11k_wmi_wait_for_unified_ready(struct ath11k_base *ab)
+{
+       unsigned long time_left;
+
+       time_left = wait_for_completion_timeout(&ab->wmi_sc.unified_ready,
+                                               WMI_SERVICE_READY_TIMEOUT_HZ);
+       if (!time_left)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+int ath11k_wmi_cmd_init(struct ath11k_base *ab)
+{
+       struct ath11k_wmi_base *wmi_sc = &ab->wmi_sc;
+       struct wmi_init_cmd_param init_param;
+       struct target_resource_config  config;
+
+       memset(&init_param, 0, sizeof(init_param));
+       memset(&config, 0, sizeof(config));
+
+       config.num_vdevs = ab->num_radios * TARGET_NUM_VDEVS;
+
+       if (ab->num_radios == 2) {
+               config.num_peers = TARGET_NUM_PEERS(DBS);
+               config.num_tids = TARGET_NUM_TIDS(DBS);
+       } else if (ab->num_radios == 3) {
+               config.num_peers = TARGET_NUM_PEERS(DBS_SBS);
+               config.num_tids = TARGET_NUM_TIDS(DBS_SBS);
+       } else {
+               /* Control should not reach here */
+               config.num_peers = TARGET_NUM_PEERS(SINGLE);
+               config.num_tids = TARGET_NUM_TIDS(SINGLE);
+       }
+       config.num_offload_peers = TARGET_NUM_OFFLD_PEERS;
+       config.num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS;
+       config.num_peer_keys = TARGET_NUM_PEER_KEYS;
+       config.ast_skid_limit = TARGET_AST_SKID_LIMIT;
+       config.tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
+       config.rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
+       config.rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI;
+       config.rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI;
+       config.rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI;
+       config.rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI;
+       config.rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI;
+       config.scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS;
+       config.bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV;
+       config.roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV;
+       config.roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES;
+       config.num_mcast_groups = TARGET_NUM_MCAST_GROUPS;
+       config.num_mcast_table_elems = TARGET_NUM_MCAST_TABLE_ELEMS;
+       config.mcast2ucast_mode = TARGET_MCAST2UCAST_MODE;
+       config.tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE;
+       config.num_wds_entries = TARGET_NUM_WDS_ENTRIES;
+       config.dma_burst_size = TARGET_DMA_BURST_SIZE;
+       config.rx_skip_defrag_timeout_dup_detection_check =
+               TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
+       config.vow_config = TARGET_VOW_CONFIG;
+       config.gtk_offload_max_vdev = TARGET_GTK_OFFLOAD_MAX_VDEV;
+       config.num_msdu_desc = TARGET_NUM_MSDU_DESC;
+       config.beacon_tx_offload_max_vdev = ab->num_radios * TARGET_MAX_BCN_OFFLD;
+       config.rx_batchmode = TARGET_RX_BATCHMODE;
+       config.peer_map_unmap_v2_support = 1;
+
+       memcpy(&wmi_sc->wlan_resource_config, &config, sizeof(config));
+
+       init_param.res_cfg = &wmi_sc->wlan_resource_config;
+       init_param.num_mem_chunks = wmi_sc->num_mem_chunks;
+       init_param.hw_mode_id = wmi_sc->preferred_hw_mode;
+       init_param.mem_chunks = wmi_sc->mem_chunks;
+
+       if (wmi_sc->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE)
+               init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX;
+
+       init_param.num_band_to_mac = ab->num_radios;
+
+       ath11k_fill_band_to_mac_param(ab, init_param.band_to_mac);
+
+       return ath11k_init_cmd_send(&wmi_sc->wmi[0], &init_param);
+}
+
+static int ath11k_wmi_tlv_hw_mode_caps_parse(struct ath11k_base *soc,
+                                            u16 tag, u16 len,
+                                            const void *ptr, void *data)
+{
+       struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data;
+       struct wmi_hw_mode_capabilities *hw_mode_cap;
+       u32 phy_map = 0;
+
+       if (tag != WMI_TAG_HW_MODE_CAPABILITIES)
+               return -EPROTO;
+
+       if (svc_rdy_ext->n_hw_mode_caps >= svc_rdy_ext->param.num_hw_modes)
+               return -ENOBUFS;
+
+       hw_mode_cap = container_of(ptr, struct wmi_hw_mode_capabilities,
+                                  hw_mode_id);
+       svc_rdy_ext->n_hw_mode_caps++;
+
+       phy_map = hw_mode_cap->phy_id_map;
+       while (phy_map) {
+               svc_rdy_ext->tot_phy_id++;
+               phy_map = phy_map >> 1;
+       }
+
+       return 0;
+}
+
+static int ath11k_wmi_tlv_hw_mode_caps(struct ath11k_base *soc,
+                                      u16 len, const void *ptr, void *data)
+{
+       struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data;
+       struct wmi_hw_mode_capabilities *hw_mode_caps;
+       enum wmi_host_hw_mode_config_type mode, pref;
+       u32 i;
+       int ret;
+
+       svc_rdy_ext->n_hw_mode_caps = 0;
+       svc_rdy_ext->hw_mode_caps = (struct wmi_hw_mode_capabilities *)ptr;
+
+       ret = ath11k_wmi_tlv_iter(soc, ptr, len,
+                                 ath11k_wmi_tlv_hw_mode_caps_parse,
+                                 svc_rdy_ext);
+       if (ret) {
+               ath11k_warn(soc, "failed to parse tlv %d\n", ret);
+               return ret;
+       }
+
+       i = 0;
+       while (i < svc_rdy_ext->n_hw_mode_caps) {
+               hw_mode_caps = &svc_rdy_ext->hw_mode_caps[i];
+               mode = hw_mode_caps->hw_mode_id;
+               pref = soc->wmi_sc.preferred_hw_mode;
+
+               if (ath11k_hw_mode_pri_map[mode] < ath11k_hw_mode_pri_map[pref]) {
+                       svc_rdy_ext->pref_hw_mode_caps = *hw_mode_caps;
+                       soc->wmi_sc.preferred_hw_mode = mode;
+               }
+               i++;
+       }
+
+       if (soc->wmi_sc.preferred_hw_mode == WMI_HOST_HW_MODE_MAX)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int ath11k_wmi_tlv_mac_phy_caps_parse(struct ath11k_base *soc,
+                                            u16 tag, u16 len,
+                                            const void *ptr, void *data)
+{
+       struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data;
+
+       if (tag != WMI_TAG_MAC_PHY_CAPABILITIES)
+               return -EPROTO;
+
+       if (svc_rdy_ext->n_mac_phy_caps >= svc_rdy_ext->tot_phy_id)
+               return -ENOBUFS;
+
+       svc_rdy_ext->n_mac_phy_caps++;
+       return 0;
+}
+
+static int ath11k_wmi_tlv_ext_hal_reg_caps_parse(struct ath11k_base *soc,
+                                                u16 tag, u16 len,
+                                                const void *ptr, void *data)
+{
+       struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data;
+
+       if (tag != WMI_TAG_HAL_REG_CAPABILITIES_EXT)
+               return -EPROTO;
+
+       if (svc_rdy_ext->n_ext_hal_reg_caps >= svc_rdy_ext->param.num_phy)
+               return -ENOBUFS;
+
+       svc_rdy_ext->n_ext_hal_reg_caps++;
+       return 0;
+}
+
+static int ath11k_wmi_tlv_ext_hal_reg_caps(struct ath11k_base *soc,
+                                          u16 len, const void *ptr, void *data)
+{
+       struct ath11k_pdev_wmi *wmi_handle = &soc->wmi_sc.wmi[0];
+       struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data;
+       struct ath11k_hal_reg_capabilities_ext reg_cap;
+       int ret;
+       u32 i;
+
+       svc_rdy_ext->n_ext_hal_reg_caps = 0;
+       svc_rdy_ext->ext_hal_reg_caps = (struct wmi_hal_reg_capabilities_ext *)ptr;
+       ret = ath11k_wmi_tlv_iter(soc, ptr, len,
+                                 ath11k_wmi_tlv_ext_hal_reg_caps_parse,
+                                 svc_rdy_ext);
+       if (ret) {
+               ath11k_warn(soc, "failed to parse tlv %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < svc_rdy_ext->param.num_phy; i++) {
+               ret = ath11k_pull_reg_cap_svc_rdy_ext(wmi_handle,
+                                                     svc_rdy_ext->soc_hal_reg_caps,
+                                                     svc_rdy_ext->ext_hal_reg_caps, i,
+                                                     ®_cap);
+               if (ret) {
+                       ath11k_warn(soc, "failed to extract reg cap %d\n", i);
+                       return ret;
+               }
+
+               memcpy(&soc->hal_reg_cap[reg_cap.phy_id],
+                      ®_cap, sizeof(reg_cap));
+       }
+       return 0;
+}
+
+static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc,
+                                                    u16 len, const void *ptr,
+                                                    void *data)
+{
+       struct ath11k_pdev_wmi *wmi_handle = &soc->wmi_sc.wmi[0];
+       struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data;
+       u8 hw_mode_id = svc_rdy_ext->pref_hw_mode_caps.hw_mode_id;
+       u32 phy_id_map;
+       int ret;
+
+       svc_rdy_ext->soc_hal_reg_caps = (struct wmi_soc_hal_reg_capabilities *)ptr;
+       svc_rdy_ext->param.num_phy = svc_rdy_ext->soc_hal_reg_caps->num_phy;
+
+       soc->num_radios = 0;
+       phy_id_map = svc_rdy_ext->pref_hw_mode_caps.phy_id_map;
+
+       while (phy_id_map && soc->num_radios < MAX_RADIOS) {
+               ret = ath11k_pull_mac_phy_cap_svc_ready_ext(wmi_handle,
+                                                           svc_rdy_ext->hw_caps,
+                                                           svc_rdy_ext->hw_mode_caps,
+                                                           svc_rdy_ext->soc_hal_reg_caps,
+                                                           svc_rdy_ext->mac_phy_caps,
+                                                           hw_mode_id, soc->num_radios,
+                                                           &soc->pdevs[soc->num_radios]);
+               if (ret) {
+                       ath11k_warn(soc, "failed to extract mac caps, idx :%d\n",
+                                   soc->num_radios);
+                       return ret;
+               }
+
+               soc->num_radios++;
+
+               /* TODO: mac_phy_cap prints */
+               phy_id_map >>= 1;
+       }
+       return 0;
+}
+
+static int ath11k_wmi_tlv_svc_rdy_ext_parse(struct ath11k_base *ab,
+                                           u16 tag, u16 len,
+                                           const void *ptr, void *data)
+{
+       struct ath11k_pdev_wmi *wmi_handle = &ab->wmi_sc.wmi[0];
+       struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data;
+       int ret;
+
+       switch (tag) {
+       case WMI_TAG_SERVICE_READY_EXT_EVENT:
+               ret = ath11k_pull_svc_ready_ext(wmi_handle, ptr,
+                                               &svc_rdy_ext->param);
+               if (ret) {
+                       ath11k_warn(ab, "unable to extract ext params\n");
+                       return ret;
+               }
+               break;
+
+       case WMI_TAG_SOC_MAC_PHY_HW_MODE_CAPS:
+               svc_rdy_ext->hw_caps = (struct wmi_soc_mac_phy_hw_mode_caps *)ptr;
+               svc_rdy_ext->param.num_hw_modes = svc_rdy_ext->hw_caps->num_hw_modes;
+               break;
+
+       case WMI_TAG_SOC_HAL_REG_CAPABILITIES:
+               ret = ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(ab, len, ptr,
+                                                               svc_rdy_ext);
+               if (ret)
+                       return ret;
+               break;
+
+       case WMI_TAG_ARRAY_STRUCT:
+               if (!svc_rdy_ext->hw_mode_done) {
+                       ret = ath11k_wmi_tlv_hw_mode_caps(ab, len, ptr,
+                                                         svc_rdy_ext);
+                       if (ret)
+                               return ret;
+
+                       svc_rdy_ext->hw_mode_done = true;
+               } else if (!svc_rdy_ext->mac_phy_done) {
+                       svc_rdy_ext->n_mac_phy_caps = 0;
+                       svc_rdy_ext->mac_phy_caps =
+                                       (struct wmi_mac_phy_capabilities *)ptr;
+                       ret = ath11k_wmi_tlv_iter(ab, ptr, len,
+                                                 ath11k_wmi_tlv_mac_phy_caps_parse,
+                                                 svc_rdy_ext);
+                       if (ret) {
+                               ath11k_warn(ab, "failed to parse tlv %d\n", ret);
+                               return ret;
+                       }
+
+                       svc_rdy_ext->mac_phy_done = true;
+               } else if (!svc_rdy_ext->ext_hal_reg_done) {
+                       ret = ath11k_wmi_tlv_ext_hal_reg_caps(ab, len, ptr,
+                                                             svc_rdy_ext);
+                       if (ret)
+                               return ret;
+
+                       svc_rdy_ext->ext_hal_reg_done = true;
+                       complete(&ab->wmi_sc.service_ready);
+               }
+               break;
+
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int ath11k_service_ready_ext_event(struct ath11k_base *ab,
+                                         struct sk_buff *skb)
+{
+       struct wmi_tlv_svc_rdy_ext_parse svc_rdy_ext = { };
+       int ret;
+
+       ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len,
+                                 ath11k_wmi_tlv_svc_rdy_ext_parse,
+                                 &svc_rdy_ext);
+       if (ret) {
+               ath11k_warn(ab, "failed to parse tlv %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buff *skb,
+                                          struct wmi_vdev_start_resp_event *vdev_rsp)
+{
+       const void **tb;
+       const struct wmi_vdev_start_resp_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_VDEV_START_RESPONSE_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch vdev start resp ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       memset(vdev_rsp, 0, sizeof(*vdev_rsp));
+
+       vdev_rsp->vdev_id = ev->vdev_id;
+       vdev_rsp->requestor_id = ev->requestor_id;
+       vdev_rsp->resp_type = ev->resp_type;
+       vdev_rsp->status = ev->status;
+       vdev_rsp->chain_mask = ev->chain_mask;
+       vdev_rsp->smps_mode = ev->smps_mode;
+       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;
+
+       kfree(tb);
+       return 0;
+}
+
+static struct cur_reg_rule
+*create_reg_rules_from_wmi(u32 num_reg_rules,
+                          struct wmi_regulatory_rule_struct *wmi_reg_rule)
+{
+       struct cur_reg_rule *reg_rule_ptr;
+       u32 count;
+
+       reg_rule_ptr =  kzalloc((num_reg_rules * sizeof(*reg_rule_ptr)),
+                               GFP_ATOMIC);
+
+       if (!reg_rule_ptr)
+               return NULL;
+
+       for (count = 0; count < num_reg_rules; count++) {
+               reg_rule_ptr[count].start_freq =
+                       FIELD_GET(REG_RULE_START_FREQ,
+                                 wmi_reg_rule[count].freq_info);
+               reg_rule_ptr[count].end_freq =
+                       FIELD_GET(REG_RULE_END_FREQ,
+                                 wmi_reg_rule[count].freq_info);
+               reg_rule_ptr[count].max_bw =
+                       FIELD_GET(REG_RULE_MAX_BW,
+                                 wmi_reg_rule[count].bw_pwr_info);
+               reg_rule_ptr[count].reg_power =
+                       FIELD_GET(REG_RULE_REG_PWR,
+                                 wmi_reg_rule[count].bw_pwr_info);
+               reg_rule_ptr[count].ant_gain =
+                       FIELD_GET(REG_RULE_ANT_GAIN,
+                                 wmi_reg_rule[count].bw_pwr_info);
+               reg_rule_ptr[count].flags =
+                       FIELD_GET(REG_RULE_FLAGS,
+                                 wmi_reg_rule[count].flag_info);
+       }
+
+       return reg_rule_ptr;
+}
+
+static int ath11k_pull_reg_chan_list_update_ev(struct ath11k_base *ab,
+                                              struct sk_buff *skb,
+                                              struct cur_regulatory_info *reg_info)
+{
+       const void **tb;
+       const struct wmi_reg_chan_list_cc_event *chan_list_event_hdr;
+       struct wmi_regulatory_rule_struct *wmi_reg_rule;
+       u32 num_2g_reg_rules, num_5g_reg_rules;
+       int ret;
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI, "processing regulatory channel list\n");
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       chan_list_event_hdr = tb[WMI_TAG_REG_CHAN_LIST_CC_EVENT];
+       if (!chan_list_event_hdr) {
+               ath11k_warn(ab, "failed to fetch reg chan list update ev\n");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       reg_info->num_2g_reg_rules = chan_list_event_hdr->num_2g_reg_rules;
+       reg_info->num_5g_reg_rules = chan_list_event_hdr->num_5g_reg_rules;
+
+       if (!(reg_info->num_2g_reg_rules + reg_info->num_5g_reg_rules)) {
+               ath11k_warn(ab, "No regulatory rules available in the event info\n");
+               kfree(tb);
+               return -EINVAL;
+       }
+
+       memcpy(reg_info->alpha2, &chan_list_event_hdr->alpha2,
+              REG_ALPHA2_LEN);
+       reg_info->dfs_region = chan_list_event_hdr->dfs_region;
+       reg_info->phybitmap = chan_list_event_hdr->phybitmap;
+       reg_info->num_phy = chan_list_event_hdr->num_phy;
+       reg_info->phy_id = chan_list_event_hdr->phy_id;
+       reg_info->ctry_code = chan_list_event_hdr->country_id;
+       reg_info->reg_dmn_pair = chan_list_event_hdr->domain_code;
+       if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_PASS)
+               reg_info->status_code = REG_SET_CC_STATUS_PASS;
+       else if (chan_list_event_hdr->status_code == WMI_REG_CURRENT_ALPHA2_NOT_FOUND)
+               reg_info->status_code = REG_CURRENT_ALPHA2_NOT_FOUND;
+       else if (chan_list_event_hdr->status_code == WMI_REG_INIT_ALPHA2_NOT_FOUND)
+               reg_info->status_code = REG_INIT_ALPHA2_NOT_FOUND;
+       else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_CHANGE_NOT_ALLOWED)
+               reg_info->status_code = REG_SET_CC_CHANGE_NOT_ALLOWED;
+       else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_NO_MEMORY)
+               reg_info->status_code = REG_SET_CC_STATUS_NO_MEMORY;
+       else if (chan_list_event_hdr->status_code == WMI_REG_SET_CC_STATUS_FAIL)
+               reg_info->status_code = REG_SET_CC_STATUS_FAIL;
+
+       reg_info->min_bw_2g = chan_list_event_hdr->min_bw_2g;
+       reg_info->max_bw_2g = chan_list_event_hdr->max_bw_2g;
+       reg_info->min_bw_5g = chan_list_event_hdr->min_bw_5g;
+       reg_info->max_bw_5g = chan_list_event_hdr->max_bw_5g;
+
+       num_2g_reg_rules = reg_info->num_2g_reg_rules;
+       num_5g_reg_rules = reg_info->num_5g_reg_rules;
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "%s:cc %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d",
+                  __func__, reg_info->alpha2, reg_info->dfs_region,
+                  reg_info->min_bw_2g, reg_info->max_bw_2g,
+                  reg_info->min_bw_5g, reg_info->max_bw_5g);
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "%s: num_2g_reg_rules %d num_5g_reg_rules %d", __func__,
+                  num_2g_reg_rules, num_5g_reg_rules);
+
+       wmi_reg_rule =
+               (struct wmi_regulatory_rule_struct *)((u8 *)chan_list_event_hdr
+                                               + sizeof(*chan_list_event_hdr)
+                                               + sizeof(struct wmi_tlv));
+
+       if (num_2g_reg_rules) {
+               reg_info->reg_rules_2g_ptr = create_reg_rules_from_wmi(num_2g_reg_rules,
+                                                                      wmi_reg_rule);
+               if (!reg_info->reg_rules_2g_ptr) {
+                       kfree(tb);
+                       ath11k_warn(ab, "Unable to Allocate memory for 2g rules\n");
+                       return -ENOMEM;
+               }
+       }
+
+       if (num_5g_reg_rules) {
+               wmi_reg_rule += num_2g_reg_rules;
+               reg_info->reg_rules_5g_ptr = create_reg_rules_from_wmi(num_5g_reg_rules,
+                                                                      wmi_reg_rule);
+               if (!reg_info->reg_rules_5g_ptr) {
+                       kfree(tb);
+                       ath11k_warn(ab, "Unable to Allocate memory for 5g rules\n");
+                       return -ENOMEM;
+               }
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI, "processed regulatory channel list\n");
+
+       kfree(tb);
+       return 0;
+}
+
+static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff *skb,
+                                       struct wmi_peer_delete_resp_event *peer_del_resp)
+{
+       const void **tb;
+       const struct wmi_peer_delete_resp_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_PEER_DELETE_RESP_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch peer delete resp ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       memset(peer_del_resp, 0, sizeof(*peer_del_resp));
+
+       peer_del_resp->vdev_id = ev->vdev_id;
+       ether_addr_copy(peer_del_resp->peer_macaddr.addr,
+                       ev->peer_macaddr.addr);
+
+       kfree(tb);
+       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)
+{
+       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);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch bcn tx status ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       *vdev_id   = ev->vdev_id;
+       *tx_status = ev->tx_status;
+
+       kfree(tb);
+       return 0;
+}
+
+static int ath11k_pull_vdev_stopped_param_tlv(struct ath11k_base *ab, struct sk_buff *skb,
+                                             u32 *vdev_id)
+{
+       const void **tb;
+       const struct wmi_vdev_stopped_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_VDEV_STOPPED_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch vdev stop ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       *vdev_id =  ev->vdev_id;
+
+       kfree(tb);
+       return 0;
+}
+
+static int ath11k_pull_mgmt_rx_params_tlv(struct ath11k_base *ab,
+                                         struct sk_buff *skb,
+                                         struct mgmt_rx_event_params *hdr)
+{
+       const void **tb;
+       const struct wmi_mgmt_rx_hdr *ev;
+       const u8 *frame;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_MGMT_RX_HDR];
+       frame = tb[WMI_TAG_ARRAY_BYTE];
+
+       if (!ev || !frame) {
+               ath11k_warn(ab, "failed to fetch mgmt rx hdr");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       hdr->pdev_id =  ev->pdev_id;
+       hdr->channel =  ev->channel;
+       hdr->snr =  ev->snr;
+       hdr->rate =  ev->rate;
+       hdr->phy_mode =  ev->phy_mode;
+       hdr->buf_len =  ev->buf_len;
+       hdr->status =  ev->status;
+       hdr->flags =  ev->flags;
+       hdr->rssi =  ev->rssi;
+       hdr->tsf_delta =  ev->tsf_delta;
+       memcpy(hdr->rssi_ctl, ev->rssi_ctl, sizeof(hdr->rssi_ctl));
+
+       if (skb->len < (frame - skb->data) + hdr->buf_len) {
+               ath11k_warn(ab, "invalid length in mgmt rx hdr ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       /* shift the sk_buff to point to `frame` */
+       skb_trim(skb, 0);
+       skb_put(skb, frame - skb->data);
+       skb_pull(skb, frame - skb->data);
+       skb_put(skb, hdr->buf_len);
+
+       ath11k_ce_byte_swap(skb->data, hdr->buf_len);
+
+       kfree(tb);
+       return 0;
+}
+
+static int wmi_process_mgmt_tx_comp(struct ath11k *ar, u32 desc_id,
+                                   u32 status)
+{
+       struct sk_buff *msdu;
+       struct ieee80211_tx_info *info;
+       struct ath11k_skb_cb *skb_cb;
+
+       spin_lock_bh(&ar->txmgmt_idr_lock);
+       msdu = idr_find(&ar->txmgmt_idr, desc_id);
+
+       if (!msdu) {
+               ath11k_warn(ar->ab, "received mgmt tx compl for invalid msdu_id: %d\n",
+                           desc_id);
+               spin_unlock_bh(&ar->txmgmt_idr_lock);
+               return -ENOENT;
+       }
+
+       idr_remove(&ar->txmgmt_idr, desc_id);
+       spin_unlock_bh(&ar->txmgmt_idr_lock);
+
+       skb_cb = ATH11K_SKB_CB(msdu);
+       dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
+
+       info = IEEE80211_SKB_CB(msdu);
+       if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status)
+               info->flags |= IEEE80211_TX_STAT_ACK;
+
+       ieee80211_tx_status_irqsafe(ar->hw, msdu);
+
+       WARN_ON_ONCE(atomic_read(&ar->num_pending_mgmt_tx) == 0);
+       atomic_dec(&ar->num_pending_mgmt_tx);
+
+       return 0;
+}
+
+static int ath11k_pull_mgmt_tx_compl_param_tlv(struct ath11k_base *ab,
+                                              struct sk_buff *skb,
+                                              struct wmi_mgmt_tx_compl_event *param)
+{
+       const void **tb;
+       const struct wmi_mgmt_tx_compl_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_MGMT_TX_COMPL_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch mgmt tx compl ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       param->pdev_id = ev->pdev_id;
+       param->desc_id = ev->desc_id;
+       param->status = ev->status;
+
+       kfree(tb);
+       return 0;
+}
+
+static void ath11k_wmi_event_scan_started(struct ath11k *ar)
+{
+       lockdep_assert_held(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH11K_SCAN_IDLE:
+       case ATH11K_SCAN_RUNNING:
+       case ATH11K_SCAN_ABORTING:
+               ath11k_warn(ar->ab, "received scan started event in an invalid scan state: %s (%d)\n",
+                           ath11k_scan_state_str(ar->scan.state),
+                           ar->scan.state);
+               break;
+       case ATH11K_SCAN_STARTING:
+               ar->scan.state = ATH11K_SCAN_RUNNING;
+               complete(&ar->scan.started);
+               break;
+       }
+}
+
+static void ath11k_wmi_event_scan_start_failed(struct ath11k *ar)
+{
+       lockdep_assert_held(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH11K_SCAN_IDLE:
+       case ATH11K_SCAN_RUNNING:
+       case ATH11K_SCAN_ABORTING:
+               ath11k_warn(ar->ab, "received scan start failed event in an invalid scan state: %s (%d)\n",
+                           ath11k_scan_state_str(ar->scan.state),
+                           ar->scan.state);
+               break;
+       case ATH11K_SCAN_STARTING:
+               complete(&ar->scan.started);
+               __ath11k_mac_scan_finish(ar);
+               break;
+       }
+}
+
+static void ath11k_wmi_event_scan_completed(struct ath11k *ar)
+{
+       lockdep_assert_held(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH11K_SCAN_IDLE:
+       case ATH11K_SCAN_STARTING:
+               /* One suspected reason scan can be completed while starting is
+                * if firmware fails to deliver all scan events to the host,
+                * e.g. when transport pipe is full. This has been observed
+                * with spectral scan phyerr events starving wmi transport
+                * pipe. In such case the "scan completed" event should be (and
+                * is) ignored by the host as it may be just firmware's scan
+                * state machine recovering.
+                */
+               ath11k_warn(ar->ab, "received scan completed event in an invalid scan state: %s (%d)\n",
+                           ath11k_scan_state_str(ar->scan.state),
+                           ar->scan.state);
+               break;
+       case ATH11K_SCAN_RUNNING:
+       case ATH11K_SCAN_ABORTING:
+               __ath11k_mac_scan_finish(ar);
+               break;
+       }
+}
+
+static void ath11k_wmi_event_scan_bss_chan(struct ath11k *ar)
+{
+       lockdep_assert_held(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH11K_SCAN_IDLE:
+       case ATH11K_SCAN_STARTING:
+               ath11k_warn(ar->ab, "received scan bss chan event in an invalid scan state: %s (%d)\n",
+                           ath11k_scan_state_str(ar->scan.state),
+                           ar->scan.state);
+               break;
+       case ATH11K_SCAN_RUNNING:
+       case ATH11K_SCAN_ABORTING:
+               ar->scan_channel = NULL;
+               break;
+       }
+}
+
+static void ath11k_wmi_event_scan_foreign_chan(struct ath11k *ar, u32 freq)
+{
+       lockdep_assert_held(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH11K_SCAN_IDLE:
+       case ATH11K_SCAN_STARTING:
+               ath11k_warn(ar->ab, "received scan foreign chan event in an invalid scan state: %s (%d)\n",
+                           ath11k_scan_state_str(ar->scan.state),
+                           ar->scan.state);
+               break;
+       case ATH11K_SCAN_RUNNING:
+       case ATH11K_SCAN_ABORTING:
+               ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
+               break;
+       }
+}
+
+static const char *
+ath11k_wmi_event_scan_type_str(enum wmi_scan_event_type type,
+                              enum wmi_scan_completion_reason reason)
+{
+       switch (type) {
+       case WMI_SCAN_EVENT_STARTED:
+               return "started";
+       case WMI_SCAN_EVENT_COMPLETED:
+               switch (reason) {
+               case WMI_SCAN_REASON_COMPLETED:
+                       return "completed";
+               case WMI_SCAN_REASON_CANCELLED:
+                       return "completed [cancelled]";
+               case WMI_SCAN_REASON_PREEMPTED:
+                       return "completed [preempted]";
+               case WMI_SCAN_REASON_TIMEDOUT:
+                       return "completed [timedout]";
+               case WMI_SCAN_REASON_INTERNAL_FAILURE:
+                       return "completed [internal err]";
+               case WMI_SCAN_REASON_MAX:
+                       break;
+               }
+               return "completed [unknown]";
+       case WMI_SCAN_EVENT_BSS_CHANNEL:
+               return "bss channel";
+       case WMI_SCAN_EVENT_FOREIGN_CHAN:
+               return "foreign channel";
+       case WMI_SCAN_EVENT_DEQUEUED:
+               return "dequeued";
+       case WMI_SCAN_EVENT_PREEMPTED:
+               return "preempted";
+       case WMI_SCAN_EVENT_START_FAILED:
+               return "start failed";
+       case WMI_SCAN_EVENT_RESTARTED:
+               return "restarted";
+       case WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT:
+               return "foreign channel exit";
+       default:
+               return "unknown";
+       }
+}
+
+static int ath11k_pull_scan_ev(struct ath11k_base *ab, struct sk_buff *skb,
+                              struct wmi_scan_event *scan_evt_param)
+{
+       const void **tb;
+       const struct wmi_scan_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_SCAN_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch scan ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       scan_evt_param->event_type = ev->event_type;
+       scan_evt_param->reason = ev->reason;
+       scan_evt_param->channel_freq = ev->channel_freq;
+       scan_evt_param->scan_req_id = ev->scan_req_id;
+       scan_evt_param->scan_id = ev->scan_id;
+       scan_evt_param->vdev_id = ev->vdev_id;
+       scan_evt_param->tsf_timestamp = ev->tsf_timestamp;
+
+       kfree(tb);
+       return 0;
+}
+
+static int ath11k_pull_peer_sta_kickout_ev(struct ath11k_base *ab, struct sk_buff *skb,
+                                          struct wmi_peer_sta_kickout_arg *arg)
+{
+       const void **tb;
+       const struct wmi_peer_sta_kickout_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_PEER_STA_KICKOUT_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch peer sta kickout ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       arg->mac_addr = ev->peer_macaddr.addr;
+
+       kfree(tb);
+       return 0;
+}
+
+static int ath11k_pull_roam_ev(struct ath11k_base *ab, struct sk_buff *skb,
+                              struct wmi_roam_event *roam_ev)
+{
+       const void **tb;
+       const struct wmi_roam_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_ROAM_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch roam ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       roam_ev->vdev_id = ev->vdev_id;
+       roam_ev->reason = ev->reason;
+       roam_ev->rssi = ev->rssi;
+
+       kfree(tb);
+       return 0;
+}
+
+static int freq_to_idx(struct ath11k *ar, int freq)
+{
+       struct ieee80211_supported_band *sband;
+       int band, ch, idx = 0;
+
+       for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
+               sband = ar->hw->wiphy->bands[band];
+               if (!sband)
+                       continue;
+
+               for (ch = 0; ch < sband->n_channels; ch++, idx++)
+                       if (sband->channels[ch].center_freq == freq)
+                               goto exit;
+       }
+
+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)
+{
+       const void **tb;
+       const struct wmi_chan_info_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_CHAN_INFO_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch chan info ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       ch_info_ev->err_code = ev->err_code;
+       ch_info_ev->freq = ev->freq;
+       ch_info_ev->cmd_flags = ev->cmd_flags;
+       ch_info_ev->noise_floor = ev->noise_floor;
+       ch_info_ev->rx_clear_count = ev->rx_clear_count;
+       ch_info_ev->cycle_count = ev->cycle_count;
+       ch_info_ev->chan_tx_pwr_range = ev->chan_tx_pwr_range;
+       ch_info_ev->chan_tx_pwr_tp = ev->chan_tx_pwr_tp;
+       ch_info_ev->rx_frame_count = ev->rx_frame_count;
+       ch_info_ev->tx_frame_cnt = ev->tx_frame_cnt;
+       ch_info_ev->mac_clk_mhz = ev->mac_clk_mhz;
+       ch_info_ev->vdev_id = ev->vdev_id;
+
+       kfree(tb);
+       return 0;
+}
+
+static int
+ath11k_pull_pdev_bss_chan_info_ev(struct ath11k_base *ab, struct sk_buff *skb,
+                                 struct wmi_pdev_bss_chan_info_event *bss_ch_info_ev)
+{
+       const void **tb;
+       const struct wmi_pdev_bss_chan_info_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch pdev bss chan info ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       bss_ch_info_ev->pdev_id = ev->pdev_id;
+       bss_ch_info_ev->freq = ev->freq;
+       bss_ch_info_ev->noise_floor = ev->noise_floor;
+       bss_ch_info_ev->rx_clear_count_low = ev->rx_clear_count_low;
+       bss_ch_info_ev->rx_clear_count_high = ev->rx_clear_count_high;
+       bss_ch_info_ev->cycle_count_low = ev->cycle_count_low;
+       bss_ch_info_ev->cycle_count_high = ev->cycle_count_high;
+       bss_ch_info_ev->tx_cycle_count_low = ev->tx_cycle_count_low;
+       bss_ch_info_ev->tx_cycle_count_high = ev->tx_cycle_count_high;
+       bss_ch_info_ev->rx_cycle_count_low = ev->rx_cycle_count_low;
+       bss_ch_info_ev->rx_cycle_count_high = ev->rx_cycle_count_high;
+       bss_ch_info_ev->rx_bss_cycle_count_low = ev->rx_bss_cycle_count_low;
+       bss_ch_info_ev->rx_bss_cycle_count_high = ev->rx_bss_cycle_count_high;
+
+       kfree(tb);
+       return 0;
+}
+
+static int
+ath11k_pull_vdev_install_key_compl_ev(struct ath11k_base *ab, struct sk_buff *skb,
+                                     struct wmi_vdev_install_key_complete_arg *arg)
+{
+       const void **tb;
+       const struct wmi_vdev_install_key_compl_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch vdev install key compl ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       arg->vdev_id = ev->vdev_id;
+       arg->macaddr = ev->peer_macaddr.addr;
+       arg->key_idx = ev->key_idx;
+       arg->key_flags = ev->key_flags;
+       arg->status = ev->status;
+
+       kfree(tb);
+       return 0;
+}
+
+static int ath11k_pull_peer_assoc_conf_ev(struct ath11k_base *ab, struct sk_buff *skb,
+                                         struct wmi_peer_assoc_conf_arg *peer_assoc_conf)
+{
+       const void **tb;
+       const struct wmi_peer_assoc_conf_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_PEER_ASSOC_CONF_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch peer assoc conf ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       peer_assoc_conf->vdev_id = ev->vdev_id;
+       peer_assoc_conf->macaddr = ev->peer_macaddr.addr;
+
+       kfree(tb);
+       return 0;
+}
+
+static void ath11k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src,
+                                           struct ath11k_fw_stats_pdev *dst)
+{
+       dst->ch_noise_floor = src->chan_nf;
+       dst->tx_frame_count = src->tx_frame_count;
+       dst->rx_frame_count = src->rx_frame_count;
+       dst->rx_clear_count = src->rx_clear_count;
+       dst->cycle_count = src->cycle_count;
+       dst->phy_err_count = src->phy_err_count;
+       dst->chan_tx_power = src->chan_tx_pwr;
+}
+
+static void
+ath11k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src,
+                             struct ath11k_fw_stats_pdev *dst)
+{
+       dst->comp_queued = src->comp_queued;
+       dst->comp_delivered = src->comp_delivered;
+       dst->msdu_enqued = src->msdu_enqued;
+       dst->mpdu_enqued = src->mpdu_enqued;
+       dst->wmm_drop = src->wmm_drop;
+       dst->local_enqued = src->local_enqued;
+       dst->local_freed = src->local_freed;
+       dst->hw_queued = src->hw_queued;
+       dst->hw_reaped = src->hw_reaped;
+       dst->underrun = src->underrun;
+       dst->tx_abort = src->tx_abort;
+       dst->mpdus_requed = src->mpdus_requed;
+       dst->tx_ko = src->tx_ko;
+       dst->data_rc = src->data_rc;
+       dst->self_triggers = src->self_triggers;
+       dst->sw_retry_failure = src->sw_retry_failure;
+       dst->illgl_rate_phy_err = src->illgl_rate_phy_err;
+       dst->pdev_cont_xretry = src->pdev_cont_xretry;
+       dst->pdev_tx_timeout = src->pdev_tx_timeout;
+       dst->pdev_resets = src->pdev_resets;
+       dst->stateless_tid_alloc_failure = src->stateless_tid_alloc_failure;
+       dst->phy_underrun = src->phy_underrun;
+       dst->txop_ovf = src->txop_ovf;
+}
+
+static void ath11k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src,
+                                         struct ath11k_fw_stats_pdev *dst)
+{
+       dst->mid_ppdu_route_change = src->mid_ppdu_route_change;
+       dst->status_rcvd = src->status_rcvd;
+       dst->r0_frags = src->r0_frags;
+       dst->r1_frags = src->r1_frags;
+       dst->r2_frags = src->r2_frags;
+       dst->r3_frags = src->r3_frags;
+       dst->htt_msdus = src->htt_msdus;
+       dst->htt_mpdus = src->htt_mpdus;
+       dst->loc_msdus = src->loc_msdus;
+       dst->loc_mpdus = src->loc_mpdus;
+       dst->oversize_amsdu = src->oversize_amsdu;
+       dst->phy_errs = src->phy_errs;
+       dst->phy_err_drop = src->phy_err_drop;
+       dst->mpdu_errs = src->mpdu_errs;
+}
+
+static void
+ath11k_wmi_pull_vdev_stats(const struct wmi_vdev_stats *src,
+                          struct ath11k_fw_stats_vdev *dst)
+{
+       int i;
+
+       dst->vdev_id = src->vdev_id;
+       dst->beacon_snr = src->beacon_snr;
+       dst->data_snr = src->data_snr;
+       dst->num_rx_frames = src->num_rx_frames;
+       dst->num_rts_fail = src->num_rts_fail;
+       dst->num_rts_success = src->num_rts_success;
+       dst->num_rx_err = src->num_rx_err;
+       dst->num_rx_discard = src->num_rx_discard;
+       dst->num_tx_not_acked = src->num_tx_not_acked;
+
+       for (i = 0; i < ARRAY_SIZE(src->num_tx_frames); i++)
+               dst->num_tx_frames[i] = src->num_tx_frames[i];
+
+       for (i = 0; i < ARRAY_SIZE(src->num_tx_frames_retries); i++)
+               dst->num_tx_frames_retries[i] = src->num_tx_frames_retries[i];
+
+       for (i = 0; i < ARRAY_SIZE(src->num_tx_frames_failures); i++)
+               dst->num_tx_frames_failures[i] = src->num_tx_frames_failures[i];
+
+       for (i = 0; i < ARRAY_SIZE(src->tx_rate_history); i++)
+               dst->tx_rate_history[i] = src->tx_rate_history[i];
+
+       for (i = 0; i < ARRAY_SIZE(src->beacon_rssi_history); i++)
+               dst->beacon_rssi_history[i] = src->beacon_rssi_history[i];
+}
+
+static void
+ath11k_wmi_pull_bcn_stats(const struct wmi_bcn_stats *src,
+                         struct ath11k_fw_stats_bcn *dst)
+{
+       dst->vdev_id = src->vdev_id;
+       dst->tx_bcn_succ_cnt = src->tx_bcn_succ_cnt;
+       dst->tx_bcn_outage_cnt = src->tx_bcn_outage_cnt;
+}
+
+int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb,
+                            struct ath11k_fw_stats *stats)
+{
+       const void **tb;
+       const struct wmi_stats_event *ev;
+       const void *data;
+       int i, ret;
+       u32 len = skb->len;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return ret;
+       }
+
+       ev = tb[WMI_TAG_STATS_EVENT];
+       data = tb[WMI_TAG_ARRAY_BYTE];
+       if (!ev || !data) {
+               ath11k_warn(ab, "failed to fetch update stats ev");
+               kfree(tb);
+               return -EPROTO;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "wmi stats update ev pdev_id %d pdev %i vdev %i bcn %i\n",
+                  ev->pdev_id,
+                  ev->num_pdev_stats, ev->num_vdev_stats,
+                  ev->num_bcn_stats);
+
+       stats->pdev_id = ev->pdev_id;
+       stats->stats_id = 0;
+
+       for (i = 0; i < ev->num_pdev_stats; i++) {
+               const struct wmi_pdev_stats *src;
+               struct ath11k_fw_stats_pdev *dst;
+
+               src = data;
+               if (len < sizeof(*src)) {
+                       kfree(tb);
+                       return -EPROTO;
+               }
+
+               stats->stats_id = WMI_REQUEST_PDEV_STAT;
+
+               data += sizeof(*src);
+               len -= sizeof(*src);
+
+               dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+               if (!dst)
+                       continue;
+
+               ath11k_wmi_pull_pdev_stats_base(&src->base, dst);
+               ath11k_wmi_pull_pdev_stats_tx(&src->tx, dst);
+               ath11k_wmi_pull_pdev_stats_rx(&src->rx, dst);
+               list_add_tail(&dst->list, &stats->pdevs);
+       }
+
+       for (i = 0; i < ev->num_vdev_stats; i++) {
+               const struct wmi_vdev_stats *src;
+               struct ath11k_fw_stats_vdev *dst;
+
+               src = data;
+               if (len < sizeof(*src)) {
+                       kfree(tb);
+                       return -EPROTO;
+               }
+
+               stats->stats_id = WMI_REQUEST_VDEV_STAT;
+
+               data += sizeof(*src);
+               len -= sizeof(*src);
+
+               dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+               if (!dst)
+                       continue;
+
+               ath11k_wmi_pull_vdev_stats(src, dst);
+               list_add_tail(&dst->list, &stats->vdevs);
+       }
+
+       for (i = 0; i < ev->num_bcn_stats; i++) {
+               const struct wmi_bcn_stats *src;
+               struct ath11k_fw_stats_bcn *dst;
+
+               src = data;
+               if (len < sizeof(*src)) {
+                       kfree(tb);
+                       return -EPROTO;
+               }
+
+               stats->stats_id = WMI_REQUEST_BCN_STAT;
+
+               data += sizeof(*src);
+               len -= sizeof(*src);
+
+               dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+               if (!dst)
+                       continue;
+
+               ath11k_wmi_pull_bcn_stats(src, dst);
+               list_add_tail(&dst->list, &stats->bcn);
+       }
+
+       kfree(tb);
+       return 0;
+}
+
+size_t ath11k_wmi_fw_stats_num_vdevs(struct list_head *head)
+{
+       struct ath11k_fw_stats_vdev *i;
+       size_t num = 0;
+
+       list_for_each_entry(i, head, list)
+               ++num;
+
+       return num;
+}
+
+static size_t ath11k_wmi_fw_stats_num_bcn(struct list_head *head)
+{
+       struct ath11k_fw_stats_bcn *i;
+       size_t num = 0;
+
+       list_for_each_entry(i, head, list)
+               ++num;
+
+       return num;
+}
+
+static void
+ath11k_wmi_fw_pdev_base_stats_fill(const struct ath11k_fw_stats_pdev *pdev,
+                                  char *buf, u32 *length)
+{
+       u32 len = *length;
+       u32 buf_len = ATH11K_FW_STATS_BUF_SIZE;
+
+       len += scnprintf(buf + len, buf_len - len, "\n");
+       len += scnprintf(buf + len, buf_len - len, "%30s\n",
+                       "ath11k PDEV stats");
+       len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+                       "=================");
+
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                       "Channel noise floor", pdev->ch_noise_floor);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                       "Channel TX power", pdev->chan_tx_power);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                       "TX frame count", pdev->tx_frame_count);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                       "RX frame count", pdev->rx_frame_count);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                       "RX clear count", pdev->rx_clear_count);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                       "Cycle count", pdev->cycle_count);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                       "PHY error count", pdev->phy_err_count);
+
+       *length = len;
+}
+
+static void
+ath11k_wmi_fw_pdev_tx_stats_fill(const struct ath11k_fw_stats_pdev *pdev,
+                                char *buf, u32 *length)
+{
+       u32 len = *length;
+       u32 buf_len = ATH11K_FW_STATS_BUF_SIZE;
+
+       len += scnprintf(buf + len, buf_len - len, "\n%30s\n",
+                        "ath11k PDEV TX stats");
+       len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+                        "====================");
+
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "HTT cookies queued", pdev->comp_queued);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "HTT cookies disp.", pdev->comp_delivered);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "MSDU queued", pdev->msdu_enqued);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "MPDU queued", pdev->mpdu_enqued);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "MSDUs dropped", pdev->wmm_drop);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "Local enqued", pdev->local_enqued);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "Local freed", pdev->local_freed);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "HW queued", pdev->hw_queued);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "PPDUs reaped", pdev->hw_reaped);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "Num underruns", pdev->underrun);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "PPDUs cleaned", pdev->tx_abort);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "MPDUs requed", pdev->mpdus_requed);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "Excessive retries", pdev->tx_ko);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "HW rate", pdev->data_rc);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "Sched self triggers", pdev->self_triggers);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "Dropped due to SW retries",
+                        pdev->sw_retry_failure);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "Illegal rate phy errors",
+                        pdev->illgl_rate_phy_err);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "PDEV continuous xretry", pdev->pdev_cont_xretry);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "TX timeout", pdev->pdev_tx_timeout);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "PDEV resets", pdev->pdev_resets);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "Stateless TIDs alloc failures",
+                        pdev->stateless_tid_alloc_failure);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "PHY underrun", pdev->phy_underrun);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
+                        "MPDU is more than txop limit", pdev->txop_ovf);
+       *length = len;
+}
+
+static void
+ath11k_wmi_fw_pdev_rx_stats_fill(const struct ath11k_fw_stats_pdev *pdev,
+                                char *buf, u32 *length)
+{
+       u32 len = *length;
+       u32 buf_len = ATH11K_FW_STATS_BUF_SIZE;
+
+       len += scnprintf(buf + len, buf_len - len, "\n%30s\n",
+                        "ath11k PDEV RX stats");
+       len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+                        "====================");
+
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "Mid PPDU route change",
+                        pdev->mid_ppdu_route_change);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "Tot. number of statuses", pdev->status_rcvd);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "Extra frags on rings 0", pdev->r0_frags);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "Extra frags on rings 1", pdev->r1_frags);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "Extra frags on rings 2", pdev->r2_frags);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "Extra frags on rings 3", pdev->r3_frags);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "MSDUs delivered to HTT", pdev->htt_msdus);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "MPDUs delivered to HTT", pdev->htt_mpdus);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "MSDUs delivered to stack", pdev->loc_msdus);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "MPDUs delivered to stack", pdev->loc_mpdus);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "Oversized AMSUs", pdev->oversize_amsdu);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "PHY errors", pdev->phy_errs);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "PHY errors drops", pdev->phy_err_drop);
+       len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+                        "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs);
+       *length = len;
+}
+
+static void
+ath11k_wmi_fw_vdev_stats_fill(struct ath11k *ar,
+                             const struct ath11k_fw_stats_vdev *vdev,
+                             char *buf, u32 *length)
+{
+       u32 len = *length;
+       u32 buf_len = ATH11K_FW_STATS_BUF_SIZE;
+       struct ath11k_vif *arvif = ath11k_mac_get_arvif(ar, vdev->vdev_id);
+       u8 *vif_macaddr;
+       int i;
+
+       /* VDEV stats has all the active VDEVs of other PDEVs as well,
+        * ignoring those not part of requested PDEV
+        */
+       if (!arvif)
+               return;
+
+       vif_macaddr = arvif->vif->addr;
+
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "VDEV ID", vdev->vdev_id);
+       len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
+                        "VDEV MAC address", vif_macaddr);
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "beacon snr", vdev->beacon_snr);
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "data snr", vdev->data_snr);
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "num rx frames", vdev->num_rx_frames);
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "num rts fail", vdev->num_rts_fail);
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "num rts success", vdev->num_rts_success);
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "num rx err", vdev->num_rx_err);
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "num rx discard", vdev->num_rx_discard);
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "num tx not acked", vdev->num_tx_not_acked);
+
+       for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames); i++)
+               len += scnprintf(buf + len, buf_len - len,
+                               "%25s [%02d] %u\n",
+                               "num tx frames", i,
+                               vdev->num_tx_frames[i]);
+
+       for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_retries); i++)
+               len += scnprintf(buf + len, buf_len - len,
+                               "%25s [%02d] %u\n",
+                               "num tx frames retries", i,
+                               vdev->num_tx_frames_retries[i]);
+
+       for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_failures); i++)
+               len += scnprintf(buf + len, buf_len - len,
+                               "%25s [%02d] %u\n",
+                               "num tx frames failures", i,
+                               vdev->num_tx_frames_failures[i]);
+
+       for (i = 0 ; i < ARRAY_SIZE(vdev->tx_rate_history); i++)
+               len += scnprintf(buf + len, buf_len - len,
+                               "%25s [%02d] 0x%08x\n",
+                               "tx rate history", i,
+                               vdev->tx_rate_history[i]);
+
+       for (i = 0 ; i < ARRAY_SIZE(vdev->beacon_rssi_history); i++)
+               len += scnprintf(buf + len, buf_len - len,
+                               "%25s [%02d] %u\n",
+                               "beacon rssi history", i,
+                               vdev->beacon_rssi_history[i]);
+
+       len += scnprintf(buf + len, buf_len - len, "\n");
+       *length = len;
+}
+
+static void
+ath11k_wmi_fw_bcn_stats_fill(struct ath11k *ar,
+                            const struct ath11k_fw_stats_bcn *bcn,
+                            char *buf, u32 *length)
+{
+       u32 len = *length;
+       u32 buf_len = ATH11K_FW_STATS_BUF_SIZE;
+       struct ath11k_vif *arvif = ath11k_mac_get_arvif(ar, bcn->vdev_id);
+       u8 *vdev_macaddr;
+
+       if (!arvif) {
+               ath11k_warn(ar->ab, "invalid vdev id %d in bcn stats",
+                           bcn->vdev_id);
+               return;
+       }
+
+       vdev_macaddr = arvif->vif->addr;
+
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "VDEV ID", bcn->vdev_id);
+       len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
+                        "VDEV MAC address", vdev_macaddr);
+       len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+                        "================");
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "Num of beacon tx success", bcn->tx_bcn_succ_cnt);
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                        "Num of beacon tx failures", bcn->tx_bcn_outage_cnt);
+
+       len += scnprintf(buf + len, buf_len - len, "\n");
+       *length = len;
+}
+
+void ath11k_wmi_fw_stats_fill(struct ath11k *ar,
+                             struct ath11k_fw_stats *fw_stats,
+                             u32 stats_id, char *buf)
+{
+       u32 len = 0;
+       u32 buf_len = ATH11K_FW_STATS_BUF_SIZE;
+       const struct ath11k_fw_stats_pdev *pdev;
+       const struct ath11k_fw_stats_vdev *vdev;
+       const struct ath11k_fw_stats_bcn *bcn;
+       size_t num_bcn;
+
+       spin_lock_bh(&ar->data_lock);
+
+       if (stats_id == WMI_REQUEST_PDEV_STAT) {
+               pdev = list_first_entry_or_null(&fw_stats->pdevs,
+                                               struct ath11k_fw_stats_pdev, list);
+               if (!pdev) {
+                       ath11k_warn(ar->ab, "failed to get pdev stats\n");
+                       goto unlock;
+               }
+
+               ath11k_wmi_fw_pdev_base_stats_fill(pdev, buf, &len);
+               ath11k_wmi_fw_pdev_tx_stats_fill(pdev, buf, &len);
+               ath11k_wmi_fw_pdev_rx_stats_fill(pdev, buf, &len);
+       }
+
+       if (stats_id == WMI_REQUEST_VDEV_STAT) {
+               len += scnprintf(buf + len, buf_len - len, "\n");
+               len += scnprintf(buf + len, buf_len - len, "%30s\n",
+                                "ath11k VDEV stats");
+               len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+                                "=================");
+
+               list_for_each_entry(vdev, &fw_stats->vdevs, list)
+                       ath11k_wmi_fw_vdev_stats_fill(ar, vdev, buf, &len);
+       }
+
+       if (stats_id == WMI_REQUEST_BCN_STAT) {
+               num_bcn = ath11k_wmi_fw_stats_num_bcn(&fw_stats->bcn);
+
+               len += scnprintf(buf + len, buf_len - len, "\n");
+               len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
+                                "ath11k Beacon stats", num_bcn);
+               len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
+                                "===================");
+
+               list_for_each_entry(bcn, &fw_stats->bcn, list)
+                       ath11k_wmi_fw_bcn_stats_fill(ar, bcn, buf, &len);
+       }
+
+unlock:
+       spin_unlock_bh(&ar->data_lock);
+
+       if (len >= buf_len)
+               buf[len - 1] = 0;
+       else
+               buf[len] = 0;
+}
+
+static void ath11k_wmi_op_ep_tx_credits(struct ath11k_base *ab)
+{
+       /* try to send pending beacons first. they take priority */
+       wake_up(&ab->wmi_sc.tx_credits_wq);
+}
+
+static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab,
+                                      struct sk_buff *skb)
+{
+       dev_kfree_skb(skb);
+}
+
+static bool ath11k_reg_is_world_alpha(char *alpha)
+{
+       return alpha[0] == '0' && alpha[1] == '0';
+}
+
+static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct cur_regulatory_info *reg_info = NULL;
+       struct ieee80211_regdomain *regd = NULL;
+       bool intersect = false;
+       int ret = 0, pdev_idx;
+       struct ath11k *ar;
+
+       reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
+       if (!reg_info) {
+               ret = -ENOMEM;
+               goto fallback;
+       }
+
+       ret = ath11k_pull_reg_chan_list_update_ev(ab, skb, reg_info);
+       if (ret) {
+               ath11k_warn(ab, "failed to extract regulatory info from received event\n");
+               goto fallback;
+       }
+
+       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;
+
+       if (pdev_idx >= ab->num_radios)
+               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))
+               return 0;
+
+       /* 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 (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
+               /* Once mac is registered, ar is valid and all CC events from
+                * fw is considered to be received due to user requests
+                * currently.
+                * 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;
+               ieee80211_queue_work(ar->hw, &ar->regd_update_work);
+       } else {
+               /* Multiple events for the same *ar is not expected. But we
+                * can still clear any previously stored default_regd if we
+                * are receiving this event for the same radio by mistake.
+                * NULL pointer handling will be taken care by kfree itself.
+                */
+               kfree(ab->default_regd[pdev_idx]);
+               /* This regd would be applied during mac registration */
+               ab->default_regd[pdev_idx] = regd;
+       }
+       ab->dfs_region = reg_info->dfs_region;
+       spin_unlock(&ab->base_lock);
+
+       goto mem_free;
+
+fallback:
+       /* Fallback to older reg (by sending previous country setting
+        * again if fw has succeded 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_2g_ptr);
+               kfree(reg_info->reg_rules_5g_ptr);
+               kfree(reg_info);
+       }
+       return ret;
+}
+
+static int ath11k_wmi_tlv_rdy_parse(struct ath11k_base *ab, u16 tag, u16 len,
+                                   const void *ptr, void *data)
+{
+       struct wmi_tlv_rdy_parse *rdy_parse = data;
+       struct wmi_ready_event *fixed_param;
+       struct wmi_mac_addr *addr_list;
+       struct ath11k_pdev *pdev;
+       u32 num_mac_addr;
+       int i;
+
+       switch (tag) {
+       case WMI_TAG_READY_EVENT:
+               fixed_param = (struct wmi_ready_event *)ptr;
+               ab->wlan_init_status = fixed_param->status;
+               rdy_parse->num_extra_mac_addr = fixed_param->num_extra_mac_addr;
+
+               ether_addr_copy(ab->mac_addr, fixed_param->mac_addr.addr);
+               ab->wmi_ready = true;
+               break;
+       case WMI_TAG_ARRAY_FIXED_STRUCT:
+               addr_list = (struct wmi_mac_addr *)ptr;
+               num_mac_addr = rdy_parse->num_extra_mac_addr;
+
+               if (!(ab->num_radios > 1 && num_mac_addr >= ab->num_radios))
+                       break;
+
+               for (i = 0; i < ab->num_radios; i++) {
+                       pdev = &ab->pdevs[i];
+                       ether_addr_copy(pdev->mac_addr, addr_list[i].addr);
+               }
+               ab->pdevs_macaddr_valid = true;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int ath11k_ready_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_tlv_rdy_parse rdy_parse = { };
+       int ret;
+
+       ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len,
+                                 ath11k_wmi_tlv_rdy_parse, &rdy_parse);
+       if (ret) {
+               ath11k_warn(ab, "failed to parse tlv %d\n", ret);
+               return ret;
+       }
+
+       complete(&ab->wmi_sc.unified_ready);
+       return 0;
+}
+
+static void ath11k_peer_delete_resp_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_peer_delete_resp_event peer_del_resp;
+
+       if (ath11k_pull_peer_del_resp_ev(ab, skb, &peer_del_resp) != 0) {
+               ath11k_warn(ab, "failed to extract peer delete resp");
+               return;
+       }
+
+       /* TODO: Do we need to validate whether ath11k_peer_find() return NULL
+        *       Why this is needed when there is HTT event for peer delete
+        */
+}
+
+static inline const char *ath11k_wmi_vdev_resp_print(u32 vdev_resp_status)
+{
+       switch (vdev_resp_status) {
+       case WMI_VDEV_START_RESPONSE_INVALID_VDEVID:
+               return "invalid vdev id";
+       case WMI_VDEV_START_RESPONSE_NOT_SUPPORTED:
+               return "not supported";
+       case WMI_VDEV_START_RESPONSE_DFS_VIOLATION:
+               return "dfs violation";
+       case WMI_VDEV_START_RESPONSE_INVALID_REGDOMAIN:
+               return "invalid regdomain";
+       default:
+               return "unknown";
+       }
+}
+
+static void ath11k_vdev_start_resp_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_vdev_start_resp_event vdev_start_resp;
+       struct ath11k *ar;
+       u32 status;
+
+       if (ath11k_pull_vdev_start_resp_tlv(ab, skb, &vdev_start_resp) != 0) {
+               ath11k_warn(ab, "failed to extract vdev start resp");
+               return;
+       }
+
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_start_resp.vdev_id);
+       if (!ar) {
+               ath11k_warn(ab, "invalid vdev id in vdev start resp ev %d",
+                           vdev_start_resp.vdev_id);
+               rcu_read_unlock();
+               return;
+       }
+
+       ar->last_wmi_vdev_start_status = 0;
+
+       status = vdev_start_resp.status;
+
+       if (WARN_ON_ONCE(status)) {
+               ath11k_warn(ab, "vdev start resp error status %d (%s)\n",
+                           status, ath11k_wmi_vdev_resp_print(status));
+               ar->last_wmi_vdev_start_status = status;
+       }
+
+       complete(&ar->vdev_setup_done);
+
+       rcu_read_unlock();
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI, "vdev start resp for vdev id %d",
+                  vdev_start_resp.vdev_id);
+}
+
+static void ath11k_bcn_tx_status_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       u32 vdev_id, tx_status;
+
+       if (ath11k_pull_bcn_tx_status_ev(ab, skb->data, skb->len,
+                                        &vdev_id, &tx_status) != 0) {
+               ath11k_warn(ab, "failed to extract bcn tx status");
+               return;
+       }
+}
+
+static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct ath11k *ar;
+       u32 vdev_id = 0;
+
+       if (ath11k_pull_vdev_stopped_param_tlv(ab, skb, &vdev_id) != 0) {
+               ath11k_warn(ab, "failed to extract vdev stopped event");
+               return;
+       }
+
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_vdev_stop_status(ab, vdev_id);
+       if (!ar) {
+               ath11k_warn(ab, "invalid vdev id in vdev stopped ev %d",
+                           vdev_id);
+               rcu_read_unlock();
+               return;
+       }
+
+       complete(&ar->vdev_setup_done);
+
+       rcu_read_unlock();
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI, "vdev stopped for vdev id %d", vdev_id);
+}
+
+static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct mgmt_rx_event_params rx_ev = {0};
+       struct ath11k *ar;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+       struct ieee80211_supported_band *sband;
+
+       if (ath11k_pull_mgmt_rx_params_tlv(ab, skb, &rx_ev) != 0) {
+               ath11k_warn(ab, "failed to extract mgmt rx event");
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       memset(status, 0, sizeof(*status));
+
+       ath11k_dbg(ab, ATH11K_DBG_MGMT, "mgmt rx event status %08x\n",
+                  rx_ev.status);
+
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_pdev_id(ab, rx_ev.pdev_id);
+
+       if (!ar) {
+               ath11k_warn(ab, "invalid pdev_id %d in mgmt_rx_event\n",
+                           rx_ev.pdev_id);
+               dev_kfree_skb(skb);
+               goto exit;
+       }
+
+       if ((test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) ||
+           (rx_ev.status & (WMI_RX_STATUS_ERR_DECRYPT |
+           WMI_RX_STATUS_ERR_KEY_CACHE_MISS | WMI_RX_STATUS_ERR_CRC))) {
+               dev_kfree_skb(skb);
+               goto exit;
+       }
+
+       if (rx_ev.status & WMI_RX_STATUS_ERR_MIC)
+               status->flag |= RX_FLAG_MMIC_ERROR;
+
+       if (rx_ev.channel >= 1 && rx_ev.channel <= 14) {
+               status->band = NL80211_BAND_2GHZ;
+       } else if (rx_ev.channel >= 36 && rx_ev.channel <= ATH11K_MAX_5G_CHAN) {
+               status->band = NL80211_BAND_5GHZ;
+       } else {
+               /* Shouldn't happen unless list of advertised channels to
+                * mac80211 has been changed.
+                */
+               WARN_ON_ONCE(1);
+               dev_kfree_skb(skb);
+               goto exit;
+       }
+
+       if (rx_ev.phy_mode == MODE_11B && status->band == NL80211_BAND_5GHZ)
+               ath11k_dbg(ab, ATH11K_DBG_WMI,
+                          "wmi mgmt rx 11b (CCK) on 5GHz\n");
+
+       sband = &ar->mac.sbands[status->band];
+
+       status->freq = ieee80211_channel_to_frequency(rx_ev.channel,
+                                                     status->band);
+       status->signal = rx_ev.snr + ATH11K_DEFAULT_NOISE_FLOOR;
+       status->rate_idx = ath11k_mac_bitrate_to_idx(sband, rx_ev.rate / 100);
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       fc = le16_to_cpu(hdr->frame_control);
+
+       /* Firmware is guaranteed to report all essential management frames via
+        * WMI while it can deliver some extra via HTT. Since there can be
+        * duplicates split the reporting wrt monitor/sniffing.
+        */
+       status->flag |= RX_FLAG_SKIP_MONITOR;
+
+       /* In case of PMF, FW delivers decrypted frames with Protected Bit set.
+        * Don't clear that. Also, FW delivers broadcast management frames
+        * (ex: group privacy action frames in mesh) as encrypted payload.
+        */
+       if (ieee80211_has_protected(hdr->frame_control) &&
+           !is_multicast_ether_addr(ieee80211_get_DA(hdr))) {
+               status->flag |= RX_FLAG_DECRYPTED;
+
+               if (!ieee80211_is_robust_mgmt_frame(skb)) {
+                       status->flag |= RX_FLAG_IV_STRIPPED |
+                                       RX_FLAG_MMIC_STRIPPED;
+                       hdr->frame_control = __cpu_to_le16(fc &
+                                            ~IEEE80211_FCTL_PROTECTED);
+               }
+       }
+
+       /* TODO: Pending handle beacon implementation
+        *if (ieee80211_is_beacon(hdr->frame_control))
+        *      ath11k_mac_handle_beacon(ar, skb);
+        */
+
+       ath11k_dbg(ab, ATH11K_DBG_MGMT,
+                  "event mgmt rx skb %pK len %d ftype %02x stype %02x\n",
+                  skb, skb->len,
+                  fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE);
+
+       ath11k_dbg(ab, ATH11K_DBG_MGMT,
+                  "event mgmt rx freq %d band %d snr %d, rate_idx %d\n",
+                  status->freq, status->band, status->signal,
+                  status->rate_idx);
+
+       ieee80211_rx_ni(ar->hw, skb);
+
+exit:
+       rcu_read_unlock();
+}
+
+static void ath11k_mgmt_tx_compl_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_mgmt_tx_compl_event tx_compl_param = {0};
+       struct ath11k *ar;
+
+       if (ath11k_pull_mgmt_tx_compl_param_tlv(ab, skb, &tx_compl_param) != 0) {
+               ath11k_warn(ab, "failed to extract mgmt tx compl event");
+               return;
+       }
+
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_pdev_id(ab, tx_compl_param.pdev_id);
+       if (!ar) {
+               ath11k_warn(ab, "invalid pdev id %d in mgmt_tx_compl_event\n",
+                           tx_compl_param.pdev_id);
+               goto exit;
+       }
+
+       wmi_process_mgmt_tx_comp(ar, tx_compl_param.desc_id,
+                                tx_compl_param.status);
+
+       ath11k_dbg(ab, ATH11K_DBG_MGMT,
+                  "mgmt tx compl ev pdev_id %d, desc_id %d, status %d",
+                  tx_compl_param.pdev_id, tx_compl_param.desc_id,
+                  tx_compl_param.status);
+
+exit:
+       rcu_read_unlock();
+}
+
+static struct ath11k *ath11k_get_ar_on_scan_abort(struct ath11k_base *ab,
+                                                 u32 vdev_id)
+{
+       int i;
+       struct ath11k_pdev *pdev;
+       struct ath11k *ar;
+
+       for (i = 0; i < ab->num_radios; i++) {
+               pdev = rcu_dereference(ab->pdevs_active[i]);
+               if (pdev && pdev->ar) {
+                       ar = pdev->ar;
+
+                       spin_lock_bh(&ar->data_lock);
+                       if (ar->scan.state == ATH11K_SCAN_ABORTING &&
+                           ar->scan.vdev_id == vdev_id) {
+                               spin_unlock_bh(&ar->data_lock);
+                               return ar;
+                       }
+                       spin_unlock_bh(&ar->data_lock);
+               }
+       }
+       return NULL;
+}
+
+static void ath11k_scan_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct ath11k *ar;
+       struct wmi_scan_event scan_ev = {0};
+
+       if (ath11k_pull_scan_ev(ab, skb, &scan_ev) != 0) {
+               ath11k_warn(ab, "failed to extract scan event");
+               return;
+       }
+
+       rcu_read_lock();
+
+       /* In case the scan was cancelled, ex. during interface teardown,
+        * the interface will not be found in active interfaces.
+        * Rather, in such scenarios, iterate over the active pdev's to
+        * search 'ar' if the corresponding 'ar' scan is ABORTING and the
+        * aborting scan's vdev id matches this event info.
+        */
+       if (scan_ev.event_type == WMI_SCAN_EVENT_COMPLETED &&
+           scan_ev.reason == WMI_SCAN_REASON_CANCELLED)
+               ar = ath11k_get_ar_on_scan_abort(ab, scan_ev.vdev_id);
+       else
+               ar = ath11k_mac_get_ar_by_vdev_id(ab, scan_ev.vdev_id);
+
+       if (!ar) {
+               ath11k_warn(ab, "Received scan event for unknown vdev");
+               rcu_read_unlock();
+               return;
+       }
+
+       spin_lock_bh(&ar->data_lock);
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n",
+                  ath11k_wmi_event_scan_type_str(scan_ev.event_type, scan_ev.reason),
+                  scan_ev.event_type, scan_ev.reason, scan_ev.channel_freq,
+                  scan_ev.scan_req_id, scan_ev.scan_id, scan_ev.vdev_id,
+                  ath11k_scan_state_str(ar->scan.state), ar->scan.state);
+
+       switch (scan_ev.event_type) {
+       case WMI_SCAN_EVENT_STARTED:
+               ath11k_wmi_event_scan_started(ar);
+               break;
+       case WMI_SCAN_EVENT_COMPLETED:
+               ath11k_wmi_event_scan_completed(ar);
+               break;
+       case WMI_SCAN_EVENT_BSS_CHANNEL:
+               ath11k_wmi_event_scan_bss_chan(ar);
+               break;
+       case WMI_SCAN_EVENT_FOREIGN_CHAN:
+               ath11k_wmi_event_scan_foreign_chan(ar, scan_ev.channel_freq);
+               break;
+       case WMI_SCAN_EVENT_START_FAILED:
+               ath11k_warn(ab, "received scan start failure event\n");
+               ath11k_wmi_event_scan_start_failed(ar);
+               break;
+       case WMI_SCAN_EVENT_DEQUEUED:
+       case WMI_SCAN_EVENT_PREEMPTED:
+       case WMI_SCAN_EVENT_RESTARTED:
+       case WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT:
+       default:
+               break;
+       }
+
+       spin_unlock_bh(&ar->data_lock);
+
+       rcu_read_unlock();
+}
+
+static void ath11k_peer_sta_kickout_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_peer_sta_kickout_arg arg = {};
+       struct ieee80211_sta *sta;
+       struct ath11k_peer *peer;
+       struct ath11k *ar;
+
+       if (ath11k_pull_peer_sta_kickout_ev(ab, skb, &arg) != 0) {
+               ath11k_warn(ab, "failed to extract peer sta kickout event");
+               return;
+       }
+
+       rcu_read_lock();
+
+       spin_lock_bh(&ab->base_lock);
+
+       peer = ath11k_peer_find_by_addr(ab, arg.mac_addr);
+
+       if (!peer) {
+               ath11k_warn(ab, "peer not found %pM\n",
+                           arg.mac_addr);
+               goto exit;
+       }
+
+       ar = ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id);
+       if (!ar) {
+               ath11k_warn(ab, "invalid vdev id in peer sta kickout ev %d",
+                           peer->vdev_id);
+               goto exit;
+       }
+
+       sta = ieee80211_find_sta_by_ifaddr(ar->hw,
+                                          arg.mac_addr, NULL);
+       if (!sta) {
+               ath11k_warn(ab, "Spurious quick kickout for STA %pM\n",
+                           arg.mac_addr);
+               goto exit;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI, "peer sta kickout event %pM",
+                  arg.mac_addr);
+
+       ieee80211_report_low_ack(sta, 10);
+
+exit:
+       spin_unlock_bh(&ab->base_lock);
+       rcu_read_unlock();
+}
+
+static void ath11k_roam_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_roam_event roam_ev = {};
+       struct ath11k *ar;
+
+       if (ath11k_pull_roam_ev(ab, skb, &roam_ev) != 0) {
+               ath11k_warn(ab, "failed to extract roam event");
+               return;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "wmi roam event vdev %u reason 0x%08x rssi %d\n",
+                  roam_ev.vdev_id, roam_ev.reason, roam_ev.rssi);
+
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_vdev_id(ab, roam_ev.vdev_id);
+       if (!ar) {
+               ath11k_warn(ab, "invalid vdev id in roam ev %d",
+                           roam_ev.vdev_id);
+               rcu_read_unlock();
+               return;
+       }
+
+       if (roam_ev.reason >= WMI_ROAM_REASON_MAX)
+               ath11k_warn(ab, "ignoring unknown roam event reason %d on vdev %i\n",
+                           roam_ev.reason, roam_ev.vdev_id);
+
+       switch (roam_ev.reason) {
+       case WMI_ROAM_REASON_BEACON_MISS:
+               /* TODO: Pending beacon miss and connection_loss_work
+                * implementation
+                * ath11k_mac_handle_beacon_miss(ar, vdev_id);
+                */
+               break;
+       case WMI_ROAM_REASON_BETTER_AP:
+       case WMI_ROAM_REASON_LOW_RSSI:
+       case WMI_ROAM_REASON_SUITABLE_AP_FOUND:
+       case WMI_ROAM_REASON_HO_FAILED:
+               ath11k_warn(ab, "ignoring not implemented roam event reason %d on vdev %i\n",
+                           roam_ev.reason, roam_ev.vdev_id);
+               break;
+       }
+
+       rcu_read_unlock();
+}
+
+static void ath11k_chan_info_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_chan_info_event ch_info_ev = {0};
+       struct ath11k *ar;
+       struct survey_info *survey;
+       int idx;
+       /* 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) {
+               ath11k_warn(ab, "failed to extract chan info event");
+               return;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "chan info vdev_id %d err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d mac_clk_mhz %d\n",
+                  ch_info_ev.vdev_id, ch_info_ev.err_code, ch_info_ev.freq,
+                  ch_info_ev.cmd_flags, ch_info_ev.noise_floor,
+                  ch_info_ev.rx_clear_count, ch_info_ev.cycle_count,
+                  ch_info_ev.mac_clk_mhz);
+
+       if (ch_info_ev.cmd_flags == WMI_CHAN_INFO_END_RESP) {
+               ath11k_dbg(ab, ATH11K_DBG_WMI, "chan info report completed\n");
+               return;
+       }
+
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_vdev_id(ab, ch_info_ev.vdev_id);
+       if (!ar) {
+               ath11k_warn(ab, "invalid vdev id in chan info ev %d",
+                           ch_info_ev.vdev_id);
+               rcu_read_unlock();
+               return;
+       }
+       spin_lock_bh(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH11K_SCAN_IDLE:
+       case ATH11K_SCAN_STARTING:
+               ath11k_warn(ab, "received chan info event without a scan request, ignoring\n");
+               goto exit;
+       case ATH11K_SCAN_RUNNING:
+       case ATH11K_SCAN_ABORTING:
+               break;
+       }
+
+       idx = freq_to_idx(ar, ch_info_ev.freq);
+       if (idx >= ARRAY_SIZE(ar->survey)) {
+               ath11k_warn(ab, "chan info: invalid frequency %d (idx %d out of bounds)\n",
+                           ch_info_ev.freq, idx);
+               goto exit;
+       }
+
+       /* If FW provides MAC clock frequency in Mhz, overriding the initialized
+        * HW channel counters frequency value
+        */
+       if (ch_info_ev.mac_clk_mhz)
+               cc_freq_hz = (ch_info_ev.mac_clk_mhz * 1000);
+
+       if (ch_info_ev.cmd_flags == WMI_CHAN_INFO_START_RESP) {
+               survey = &ar->survey[idx];
+               memset(survey, 0, sizeof(*survey));
+               survey->noise = ch_info_ev.noise_floor;
+               survey->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_TIME |
+                                SURVEY_INFO_TIME_BUSY;
+               survey->time = div_u64(ch_info_ev.cycle_count, cc_freq_hz);
+               survey->time_busy = div_u64(ch_info_ev.rx_clear_count, cc_freq_hz);
+       }
+exit:
+       spin_unlock_bh(&ar->data_lock);
+       rcu_read_unlock();
+}
+
+static void
+ath11k_pdev_bss_chan_info_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_pdev_bss_chan_info_event bss_ch_info_ev = {};
+       struct survey_info *survey;
+       struct ath11k *ar;
+       u32 cc_freq_hz = ab->cc_freq_hz;
+       u64 busy, total, tx, rx, rx_bss;
+       int idx;
+
+       if (ath11k_pull_pdev_bss_chan_info_ev(ab, skb, &bss_ch_info_ev) != 0) {
+               ath11k_warn(ab, "failed to extract pdev bss chan info event");
+               return;
+       }
+
+       busy = (u64)(bss_ch_info_ev.rx_clear_count_high) << 32 |
+                       bss_ch_info_ev.rx_clear_count_low;
+
+       total = (u64)(bss_ch_info_ev.cycle_count_high) << 32 |
+                       bss_ch_info_ev.cycle_count_low;
+
+       tx = (u64)(bss_ch_info_ev.tx_cycle_count_high) << 32 |
+                       bss_ch_info_ev.tx_cycle_count_low;
+
+       rx = (u64)(bss_ch_info_ev.rx_cycle_count_high) << 32 |
+                       bss_ch_info_ev.rx_cycle_count_low;
+
+       rx_bss = (u64)(bss_ch_info_ev.rx_bss_cycle_count_high) << 32 |
+                       bss_ch_info_ev.rx_bss_cycle_count_low;
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "pdev bss chan info:\n pdev_id: %d freq: %d noise: %d cycle: busy %llu total %llu tx %llu rx %llu rx_bss %llu\n",
+                  bss_ch_info_ev.pdev_id, bss_ch_info_ev.freq,
+                  bss_ch_info_ev.noise_floor, busy, total,
+                  tx, rx, rx_bss);
+
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_pdev_id(ab, bss_ch_info_ev.pdev_id);
+
+       if (!ar) {
+               ath11k_warn(ab, "invalid pdev id %d in bss_chan_info event\n",
+                           bss_ch_info_ev.pdev_id);
+               rcu_read_unlock();
+               return;
+       }
+
+       spin_lock_bh(&ar->data_lock);
+       idx = freq_to_idx(ar, bss_ch_info_ev.freq);
+       if (idx >= ARRAY_SIZE(ar->survey)) {
+               ath11k_warn(ab, "bss chan info: invalid frequency %d (idx %d out of bounds)\n",
+                           bss_ch_info_ev.freq, idx);
+               goto exit;
+       }
+
+       survey = &ar->survey[idx];
+
+       survey->noise     = bss_ch_info_ev.noise_floor;
+       survey->time      = div_u64(total, cc_freq_hz);
+       survey->time_busy = div_u64(busy, cc_freq_hz);
+       survey->time_rx   = div_u64(rx_bss, cc_freq_hz);
+       survey->time_tx   = div_u64(tx, cc_freq_hz);
+       survey->filled   |= (SURVEY_INFO_NOISE_DBM |
+                            SURVEY_INFO_TIME |
+                            SURVEY_INFO_TIME_BUSY |
+                            SURVEY_INFO_TIME_RX |
+                            SURVEY_INFO_TIME_TX);
+exit:
+       spin_unlock_bh(&ar->data_lock);
+       complete(&ar->bss_survey_done);
+
+       rcu_read_unlock();
+}
+
+static void ath11k_vdev_install_key_compl_event(struct ath11k_base *ab,
+                                               struct sk_buff *skb)
+{
+       struct wmi_vdev_install_key_complete_arg install_key_compl = {0};
+       struct ath11k *ar;
+
+       if (ath11k_pull_vdev_install_key_compl_ev(ab, skb, &install_key_compl) != 0) {
+               ath11k_warn(ab, "failed to extract install key compl event");
+               return;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "vdev install key ev idx %d flags %08x macaddr %pM status %d\n",
+                  install_key_compl.key_idx, install_key_compl.key_flags,
+                  install_key_compl.macaddr, install_key_compl.status);
+
+       rcu_read_lock();
+       ar = ath11k_mac_get_ar_by_vdev_id(ab, install_key_compl.vdev_id);
+       if (!ar) {
+               ath11k_warn(ab, "invalid vdev id in install key compl ev %d",
+                           install_key_compl.vdev_id);
+               rcu_read_unlock();
+               return;
+       }
+
+       ar->install_key_status = 0;
+
+       if (install_key_compl.status != WMI_VDEV_INSTALL_KEY_COMPL_STATUS_SUCCESS) {
+               ath11k_warn(ab, "install key failed for %pM status %d\n",
+                           install_key_compl.macaddr, install_key_compl.status);
+               ar->install_key_status = install_key_compl.status;
+       }
+
+       complete(&ar->install_key_done);
+       rcu_read_unlock();
+}
+
+static void ath11k_service_available_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       const void **tb;
+       const struct wmi_service_available_event *ev;
+       int ret;
+       int i, j;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return;
+       }
+
+       ev = tb[WMI_TAG_SERVICE_AVAILABLE_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch svc available ev");
+               kfree(tb);
+               return;
+       }
+
+       /* TODO: Use wmi_service_segment_offset information to get the service
+        * especially when more services are advertised in multiple sevice
+        * available events.
+        */
+       for (i = 0, j = WMI_MAX_SERVICE;
+            i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT_SERVICE;
+            i++) {
+               do {
+                       if (ev->wmi_service_segment_bitmap[i] &
+                           BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32))
+                               set_bit(j, ab->wmi_sc.svc_map);
+               } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32);
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "wmi_ext_service_bitmap 0:0x%x, 1:0x%x, 2:0x%x, 3:0x%x",
+                  ev->wmi_service_segment_bitmap[0], ev->wmi_service_segment_bitmap[1],
+                  ev->wmi_service_segment_bitmap[2], ev->wmi_service_segment_bitmap[3]);
+
+       kfree(tb);
+}
+
+static void ath11k_peer_assoc_conf_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_peer_assoc_conf_arg peer_assoc_conf = {0};
+       struct ath11k *ar;
+
+       if (ath11k_pull_peer_assoc_conf_ev(ab, skb, &peer_assoc_conf) != 0) {
+               ath11k_warn(ab, "failed to extract peer assoc conf event");
+               return;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "peer assoc conf ev vdev id %d macaddr %pM\n",
+                  peer_assoc_conf.vdev_id, peer_assoc_conf.macaddr);
+
+       ar = ath11k_mac_get_ar_by_vdev_id(ab, peer_assoc_conf.vdev_id);
+
+       if (!ar) {
+               ath11k_warn(ab, "invalid vdev id in peer assoc conf ev %d",
+                           peer_assoc_conf.vdev_id);
+               return;
+       }
+
+       complete(&ar->peer_assoc_done);
+}
+
+static void ath11k_update_stats_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       ath11k_debug_fw_stats_process(ab, skb);
+}
+
+/* PDEV_CTL_FAILSAFE_CHECK_EVENT is received from FW when the frequency scanned
+ * is not part of BDF CTL(Conformance test limits) table entries.
+ */
+static void ath11k_pdev_ctl_failsafe_check_event(struct ath11k_base *ab,
+                                                struct sk_buff *skb)
+{
+       const void **tb;
+       const struct wmi_pdev_ctl_failsafe_chk_event *ev;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return;
+       }
+
+       ev = tb[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT];
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch pdev ctl failsafe check ev");
+               kfree(tb);
+               return;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "pdev ctl failsafe check ev status %d\n",
+                  ev->ctl_failsafe_status);
+
+       /* If ctl_failsafe_status is set to 1 FW will max out the Transmit power
+        * to 10 dBm else the CTL power entry in the BDF would be picked up.
+        */
+       if (ev->ctl_failsafe_status != 0)
+               ath11k_warn(ab, "pdev ctl failsafe failure status %d",
+                           ev->ctl_failsafe_status);
+
+       kfree(tb);
+}
+
+static void
+ath11k_wmi_process_csa_switch_count_event(struct ath11k_base *ab,
+                                         const struct wmi_pdev_csa_switch_ev *ev,
+                                         const u32 *vdev_ids)
+{
+       int i;
+       struct ath11k_vif *arvif;
+
+       /* Finish CSA once the switch count becomes NULL */
+       if (ev->current_switch_count)
+               return;
+
+       rcu_read_lock();
+       for (i = 0; i < ev->num_vdevs; i++) {
+               arvif = ath11k_mac_get_arvif_by_vdev_id(ab, vdev_ids[i]);
+
+               if (!arvif) {
+                       ath11k_warn(ab, "Recvd csa status for unknown vdev %d",
+                                   vdev_ids[i]);
+                       continue;
+               }
+
+               if (arvif->is_up && arvif->vif->csa_active)
+                       ieee80211_csa_finish(arvif->vif);
+       }
+       rcu_read_unlock();
+}
+
+static void
+ath11k_wmi_pdev_csa_switch_count_status_event(struct ath11k_base *ab,
+                                             struct sk_buff *skb)
+{
+       const void **tb;
+       const struct wmi_pdev_csa_switch_ev *ev;
+       const u32 *vdev_ids;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return;
+       }
+
+       ev = tb[WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT];
+       vdev_ids = tb[WMI_TAG_ARRAY_UINT32];
+
+       if (!ev || !vdev_ids) {
+               ath11k_warn(ab, "failed to fetch pdev csa switch count ev");
+               kfree(tb);
+               return;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "pdev csa switch count %d for pdev %d, num_vdevs %d",
+                  ev->current_switch_count, ev->pdev_id,
+                  ev->num_vdevs);
+
+       ath11k_wmi_process_csa_switch_count_event(ab, ev, vdev_ids);
+
+       kfree(tb);
+}
+
+static void
+ath11k_wmi_pdev_dfs_radar_detected_event(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       const void **tb;
+       const struct wmi_pdev_radar_ev *ev;
+       struct ath11k *ar;
+       int ret;
+
+       tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+       if (IS_ERR(tb)) {
+               ret = PTR_ERR(tb);
+               ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
+               return;
+       }
+
+       ev = tb[WMI_TAG_PDEV_DFS_RADAR_DETECTION_EVENT];
+
+       if (!ev) {
+               ath11k_warn(ab, "failed to fetch pdev dfs radar detected ev");
+               kfree(tb);
+               return;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_WMI,
+                  "pdev dfs radar detected on pdev %d, detection mode %d, chan freq %d, chan_width %d, detector id %d, seg id %d, timestamp %d, chirp %d, freq offset %d, sidx %d",
+                  ev->pdev_id, ev->detection_mode, ev->chan_freq, ev->chan_width,
+                  ev->detector_id, ev->segment_id, ev->timestamp, ev->is_chirp,
+                  ev->freq_offset, ev->sidx);
+
+       ar = ath11k_mac_get_ar_by_pdev_id(ab, ev->pdev_id);
+
+       if (!ar) {
+               ath11k_warn(ab, "radar detected in invalid pdev %d\n",
+                           ev->pdev_id);
+               goto exit;
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_REG, "DFS Radar Detected in pdev %d\n",
+                  ev->pdev_id);
+
+       if (ar->dfs_block_radar_events)
+               ath11k_info(ab, "DFS Radar detected, but ignored as requested\n");
+       else
+               ieee80211_radar_detected(ar->hw);
+
+exit:
+       kfree(tb);
+}
+
+static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
+{
+       struct wmi_cmd_hdr *cmd_hdr;
+       enum wmi_tlv_event_id id;
+
+       cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
+       id = FIELD_GET(WMI_CMD_HDR_CMD_ID, (cmd_hdr->cmd_id));
+
+       if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+               goto out;
+
+       switch (id) {
+               /* Process all the WMI events here */
+       case WMI_SERVICE_READY_EVENTID:
+               ath11k_service_ready_event(ab, skb);
+               break;
+       case WMI_SERVICE_READY_EXT_EVENTID:
+               ath11k_service_ready_ext_event(ab, skb);
+               break;
+       case WMI_REG_CHAN_LIST_CC_EVENTID:
+               ath11k_reg_chan_list_event(ab, skb);
+               break;
+       case WMI_READY_EVENTID:
+               ath11k_ready_event(ab, skb);
+               break;
+       case WMI_PEER_DELETE_RESP_EVENTID:
+               ath11k_peer_delete_resp_event(ab, skb);
+               break;
+       case WMI_VDEV_START_RESP_EVENTID:
+               ath11k_vdev_start_resp_event(ab, skb);
+               break;
+       case WMI_OFFLOAD_BCN_TX_STATUS_EVENTID:
+               ath11k_bcn_tx_status_event(ab, skb);
+               break;
+       case WMI_VDEV_STOPPED_EVENTID:
+               ath11k_vdev_stopped_event(ab, skb);
+               break;
+       case WMI_MGMT_RX_EVENTID:
+               ath11k_mgmt_rx_event(ab, skb);
+               /* mgmt_rx_event() owns the skb now! */
+               return;
+       case WMI_MGMT_TX_COMPLETION_EVENTID:
+               ath11k_mgmt_tx_compl_event(ab, skb);
+               break;
+       case WMI_SCAN_EVENTID:
+               ath11k_scan_event(ab, skb);
+               break;
+       case WMI_PEER_STA_KICKOUT_EVENTID:
+               ath11k_peer_sta_kickout_event(ab, skb);
+               break;
+       case WMI_ROAM_EVENTID:
+               ath11k_roam_event(ab, skb);
+               break;
+       case WMI_CHAN_INFO_EVENTID:
+               ath11k_chan_info_event(ab, skb);
+               break;
+       case WMI_PDEV_BSS_CHAN_INFO_EVENTID:
+               ath11k_pdev_bss_chan_info_event(ab, skb);
+               break;
+       case WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID:
+               ath11k_vdev_install_key_compl_event(ab, skb);
+               break;
+       case WMI_SERVICE_AVAILABLE_EVENTID:
+               ath11k_service_available_event(ab, skb);
+               break;
+       case WMI_PEER_ASSOC_CONF_EVENTID:
+               ath11k_peer_assoc_conf_event(ab, skb);
+               break;
+       case WMI_UPDATE_STATS_EVENTID:
+               ath11k_update_stats_event(ab, skb);
+               break;
+       case WMI_PDEV_CTL_FAILSAFE_CHECK_EVENTID:
+               ath11k_pdev_ctl_failsafe_check_event(ab, skb);
+               break;
+       case WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID:
+               ath11k_wmi_pdev_csa_switch_count_status_event(ab, skb);
+               break;
+       /* add Unsupported events here */
+       case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
+       case WMI_VDEV_DELETE_RESP_EVENTID:
+               ath11k_dbg(ab, ATH11K_DBG_WMI,
+                          "ignoring unsupported event 0x%x\n", id);
+               break;
+       case WMI_PDEV_DFS_RADAR_DETECTION_EVENTID:
+               ath11k_wmi_pdev_dfs_radar_detected_event(ab, skb);
+               break;
+       /* TODO: Add remaining events */
+       default:
+               ath11k_warn(ab, "Unknown eventid: 0x%x\n", id);
+               break;
+       }
+
+out:
+       dev_kfree_skb(skb);
+}
+
+static int ath11k_connect_pdev_htc_service(struct ath11k_base *ab,
+                                          u32 pdev_idx)
+{
+       int status;
+       u32 svc_id[] = { ATH11K_HTC_SVC_ID_WMI_CONTROL,
+                        ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1,
+                        ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2 };
+
+       struct ath11k_htc_svc_conn_req conn_req;
+       struct ath11k_htc_svc_conn_resp conn_resp;
+
+       memset(&conn_req, 0, sizeof(conn_req));
+       memset(&conn_resp, 0, sizeof(conn_resp));
+
+       /* these fields are the same for all service endpoints */
+       conn_req.ep_ops.ep_tx_complete = ath11k_wmi_htc_tx_complete;
+       conn_req.ep_ops.ep_rx_complete = ath11k_wmi_tlv_op_rx;
+       conn_req.ep_ops.ep_tx_credits = ath11k_wmi_op_ep_tx_credits;
+
+       /* connect to control service */
+       conn_req.service_id = svc_id[pdev_idx];
+
+       status = ath11k_htc_connect_service(&ab->htc, &conn_req, &conn_resp);
+       if (status) {
+               ath11k_warn(ab, "failed to connect to WMI CONTROL service status: %d\n",
+                           status);
+               return status;
+       }
+
+       ab->wmi_sc.wmi_endpoint_id[pdev_idx] = conn_resp.eid;
+       ab->wmi_sc.wmi[pdev_idx].eid = conn_resp.eid;
+       ab->wmi_sc.max_msg_len[pdev_idx] = conn_resp.max_msg_len;
+
+       return 0;
+}
+
+static int
+ath11k_wmi_send_unit_test_cmd(struct ath11k *ar,
+                             struct wmi_unit_test_cmd ut_cmd,
+                             u32 *test_args)
+{
+       struct ath11k_pdev_wmi *wmi = ar->wmi;
+       struct wmi_unit_test_cmd *cmd;
+       struct sk_buff *skb;
+       struct wmi_tlv *tlv;
+       void *ptr;
+       u32 *ut_cmd_args;
+       int buf_len, arg_len;
+       int ret;
+       int i;
+
+       arg_len = sizeof(u32) * ut_cmd.num_args;
+       buf_len = sizeof(ut_cmd) + arg_len + TLV_HDR_SIZE;
+
+       skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, buf_len);
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_unit_test_cmd *)skb->data;
+       cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_UNIT_TEST_CMD) |
+                         FIELD_PREP(WMI_TLV_LEN, sizeof(ut_cmd) - TLV_HDR_SIZE);
+
+       cmd->vdev_id = ut_cmd.vdev_id;
+       cmd->module_id = ut_cmd.module_id;
+       cmd->num_args = ut_cmd.num_args;
+       cmd->diag_token = ut_cmd.diag_token;
+
+       ptr = skb->data + sizeof(ut_cmd);
+
+       tlv = ptr;
+       tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_UINT32) |
+                     FIELD_PREP(WMI_TLV_LEN, arg_len);
+
+       ptr += TLV_HDR_SIZE;
+
+       ut_cmd_args = ptr;
+       for (i = 0; i < ut_cmd.num_args; i++)
+               ut_cmd_args[i] = test_args[i];
+
+       ret = ath11k_wmi_cmd_send(wmi, skb, WMI_UNIT_TEST_CMDID);
+
+       if (ret) {
+               ath11k_warn(ar->ab, "failed to send WMI_UNIT_TEST CMD :%d\n",
+                           ret);
+               dev_kfree_skb(skb);
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
+                  "WMI unit test : module %d vdev %d n_args %d token %d\n",
+                  cmd->module_id, cmd->vdev_id, cmd->num_args,
+                  cmd->diag_token);
+
+       return ret;
+}
+
+int ath11k_wmi_simulate_radar(struct ath11k *ar)
+{
+       struct ath11k_vif *arvif;
+       u32 dfs_args[DFS_MAX_TEST_ARGS];
+       struct wmi_unit_test_cmd wmi_ut;
+       bool arvif_found = false;
+
+       list_for_each_entry(arvif, &ar->arvifs, list) {
+               if (arvif->is_started && arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+                       arvif_found = true;
+                       break;
+               }
+       }
+
+       if (!arvif_found)
+               return -EINVAL;
+
+       dfs_args[DFS_TEST_CMDID] = 0;
+       dfs_args[DFS_TEST_PDEV_ID] = ar->pdev->pdev_id;
+       /* Currently we could pass segment_id(b0 - b1), chirp(b2)
+        * freq offset (b3 - b10) to unit test. For simulation
+        * purpose this can be set to 0 which is valid.
+        */
+       dfs_args[DFS_TEST_RADAR_PARAM] = 0;
+
+       wmi_ut.vdev_id = arvif->vdev_id;
+       wmi_ut.module_id = DFS_UNIT_TEST_MODULE;
+       wmi_ut.num_args = DFS_MAX_TEST_ARGS;
+       wmi_ut.diag_token = DFS_UNIT_TEST_TOKEN;
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_REG, "Triggering Radar Simulation\n");
+
+       return ath11k_wmi_send_unit_test_cmd(ar, wmi_ut, dfs_args);
+}
+
+int ath11k_wmi_connect(struct ath11k_base *ab)
+{
+       u32 i;
+       u8 wmi_ep_count;
+
+       wmi_ep_count = ab->htc.wmi_ep_count;
+       if (wmi_ep_count > MAX_RADIOS)
+               return -1;
+
+       for (i = 0; i < wmi_ep_count; i++)
+               ath11k_connect_pdev_htc_service(ab, i);
+
+       return 0;
+}
+
+static void ath11k_wmi_pdev_detach(struct ath11k_base *ab, u8 pdev_id)
+{
+       if (WARN_ON(pdev_id >= MAX_RADIOS))
+               return;
+
+       /* TODO: Deinit any pdev specific wmi resource */
+}
+
+int ath11k_wmi_pdev_attach(struct ath11k_base *ab,
+                          u8 pdev_id)
+{
+       struct ath11k_pdev_wmi *wmi_handle;
+
+       if (pdev_id >= MAX_RADIOS)
+               return -EINVAL;
+
+       wmi_handle = &ab->wmi_sc.wmi[pdev_id];
+
+       wmi_handle->wmi_sc = &ab->wmi_sc;
+
+       ab->wmi_sc.ab = ab;
+       /* TODO: Init remaining resource specific to pdev */
+
+       return 0;
+}
+
+int ath11k_wmi_attach(struct ath11k_base *ab)
+{
+       int ret;
+
+       ret = ath11k_wmi_pdev_attach(ab, 0);
+       if (ret)
+               return ret;
+
+       ab->wmi_sc.ab = ab;
+       ab->wmi_sc.preferred_hw_mode = WMI_HOST_HW_MODE_MAX;
+
+       /* TODO: Init remaining wmi soc resources required */
+       init_completion(&ab->wmi_sc.service_ready);
+       init_completion(&ab->wmi_sc.unified_ready);
+
+       return 0;
+}
+
+void ath11k_wmi_detach(struct ath11k_base *ab)
+{
+       int i;
+
+       /* TODO: Deinit wmi resource specific to SOC as required */
+
+       for (i = 0; i < ab->htc.wmi_ep_count; i++)
+               ath11k_wmi_pdev_detach(ab, i);
+}
 
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef ATH11K_WMI_H
+#define ATH11K_WMI_H
+
+#include <net/mac80211.h>
+#include "htc.h"
+
+struct ath11k_base;
+struct ath11k;
+struct ath11k_fw_stats;
+
+#define PSOC_HOST_MAX_NUM_SS (8)
+
+/* defines to set Packet extension values whic can be 0 us, 8 usec or 16 usec */
+#define MAX_HE_NSS               8
+#define MAX_HE_MODULATION        8
+#define MAX_HE_RU                4
+#define HE_MODULATION_NONE       7
+#define HE_PET_0_USEC            0
+#define HE_PET_8_USEC            1
+#define HE_PET_16_USEC           2
+
+#define WMI_MAX_NUM_SS                    MAX_HE_NSS
+#define WMI_MAX_NUM_RU                    MAX_HE_RU
+
+#define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1)
+#define WMI_TLV_EV(grp_id) (((grp_id) << 12) | 0x1)
+#define WMI_TLV_CMD_UNSUPPORTED 0
+#define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0
+#define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0
+
+struct wmi_cmd_hdr {
+       u32 cmd_id;
+} __packed;
+
+struct wmi_tlv {
+       u32 header;
+       u8 value[0];
+} __packed;
+
+#define WMI_TLV_LEN    GENMASK(15, 0)
+#define WMI_TLV_TAG    GENMASK(31, 16)
+#define TLV_HDR_SIZE   FIELD_SIZEOF(struct wmi_tlv, header)
+
+#define WMI_CMD_HDR_CMD_ID      GENMASK(23, 0)
+#define WMI_MAX_MEM_REQS        32
+#define ATH11K_MAX_HW_LISTEN_INTERVAL 5
+
+#define WLAN_SCAN_PARAMS_MAX_SSID    16
+#define WLAN_SCAN_PARAMS_MAX_BSSID   4
+#define WLAN_SCAN_PARAMS_MAX_IE_LEN  256
+
+/*
+ * HW mode config type replicated from FW header
+ * @WMI_HOST_HW_MODE_SINGLE: Only one PHY is active.
+ * @WMI_HOST_HW_MODE_DBS: Both PHYs are active in different bands,
+ *                        one in 2G and another in 5G.
+ * @WMI_HOST_HW_MODE_SBS_PASSIVE: Both PHYs are in passive mode (only rx) in
+ *                        same band; no tx allowed.
+ * @WMI_HOST_HW_MODE_SBS: Both PHYs are active in the same band.
+ *                        Support for both PHYs within one band is planned
+ *                        for 5G only(as indicated in WMI_MAC_PHY_CAPABILITIES),
+ *                        but could be extended to other bands in the future.
+ *                        The separation of the band between the two PHYs needs
+ *                        to be communicated separately.
+ * @WMI_HOST_HW_MODE_DBS_SBS: 3 PHYs, with 2 on the same band doing SBS
+ *                           as in WMI_HW_MODE_SBS, and 3rd on the other band
+ * @WMI_HOST_HW_MODE_DBS_OR_SBS: Two PHY with one PHY capabale of both 2G and
+ *                        5G. It can support SBS (5G + 5G) OR DBS (5G + 2G).
+ * @WMI_HOST_HW_MODE_MAX: Max hw_mode_id. Used to indicate invalid mode.
+ */
+enum wmi_host_hw_mode_config_type {
+       WMI_HOST_HW_MODE_SINGLE       = 0,
+       WMI_HOST_HW_MODE_DBS          = 1,
+       WMI_HOST_HW_MODE_SBS_PASSIVE  = 2,
+       WMI_HOST_HW_MODE_SBS          = 3,
+       WMI_HOST_HW_MODE_DBS_SBS      = 4,
+       WMI_HOST_HW_MODE_DBS_OR_SBS   = 5,
+
+       /* keep last */
+       WMI_HOST_HW_MODE_MAX
+};
+
+/* HW mode priority values used to detect the preferred HW mode
+ * on the available modes.
+ */
+enum wmi_host_hw_mode_priority {
+       WMI_HOST_HW_MODE_DBS_SBS_PRI,
+       WMI_HOST_HW_MODE_DBS_PRI,
+       WMI_HOST_HW_MODE_DBS_OR_SBS_PRI,
+       WMI_HOST_HW_MODE_SBS_PRI,
+       WMI_HOST_HW_MODE_SBS_PASSIVE_PRI,
+       WMI_HOST_HW_MODE_SINGLE_PRI,
+
+       /* keep last the lowest priority */
+       WMI_HOST_HW_MODE_MAX_PRI
+};
+
+enum {
+       WMI_HOST_WLAN_2G_CAP    = 0x1,
+       WMI_HOST_WLAN_5G_CAP    = 0x2,
+       WMI_HOST_WLAN_2G_5G_CAP = 0x3,
+};
+
+/*
+ * wmi command groups.
+ */
+enum wmi_cmd_group {
+       /* 0 to 2 are reserved */
+       WMI_GRP_START = 0x3,
+       WMI_GRP_SCAN = WMI_GRP_START,
+       WMI_GRP_PDEV            = 0x4,
+       WMI_GRP_VDEV           = 0x5,
+       WMI_GRP_PEER           = 0x6,
+       WMI_GRP_MGMT           = 0x7,
+       WMI_GRP_BA_NEG         = 0x8,
+       WMI_GRP_STA_PS         = 0x9,
+       WMI_GRP_DFS            = 0xa,
+       WMI_GRP_ROAM           = 0xb,
+       WMI_GRP_OFL_SCAN       = 0xc,
+       WMI_GRP_P2P            = 0xd,
+       WMI_GRP_AP_PS          = 0xe,
+       WMI_GRP_RATE_CTRL      = 0xf,
+       WMI_GRP_PROFILE        = 0x10,
+       WMI_GRP_SUSPEND        = 0x11,
+       WMI_GRP_BCN_FILTER     = 0x12,
+       WMI_GRP_WOW            = 0x13,
+       WMI_GRP_RTT            = 0x14,
+       WMI_GRP_SPECTRAL       = 0x15,
+       WMI_GRP_STATS          = 0x16,
+       WMI_GRP_ARP_NS_OFL     = 0x17,
+       WMI_GRP_NLO_OFL        = 0x18,
+       WMI_GRP_GTK_OFL        = 0x19,
+       WMI_GRP_CSA_OFL        = 0x1a,
+       WMI_GRP_CHATTER        = 0x1b,
+       WMI_GRP_TID_ADDBA      = 0x1c,
+       WMI_GRP_MISC           = 0x1d,
+       WMI_GRP_GPIO           = 0x1e,
+       WMI_GRP_FWTEST         = 0x1f,
+       WMI_GRP_TDLS           = 0x20,
+       WMI_GRP_RESMGR         = 0x21,
+       WMI_GRP_STA_SMPS       = 0x22,
+       WMI_GRP_WLAN_HB        = 0x23,
+       WMI_GRP_RMC            = 0x24,
+       WMI_GRP_MHF_OFL        = 0x25,
+       WMI_GRP_LOCATION_SCAN  = 0x26,
+       WMI_GRP_OEM            = 0x27,
+       WMI_GRP_NAN            = 0x28,
+       WMI_GRP_COEX           = 0x29,
+       WMI_GRP_OBSS_OFL       = 0x2a,
+       WMI_GRP_LPI            = 0x2b,
+       WMI_GRP_EXTSCAN        = 0x2c,
+       WMI_GRP_DHCP_OFL       = 0x2d,
+       WMI_GRP_IPA            = 0x2e,
+       WMI_GRP_MDNS_OFL       = 0x2f,
+       WMI_GRP_SAP_OFL        = 0x30,
+       WMI_GRP_OCB            = 0x31,
+       WMI_GRP_SOC            = 0x32,
+       WMI_GRP_PKT_FILTER     = 0x33,
+       WMI_GRP_MAWC           = 0x34,
+       WMI_GRP_PMF_OFFLOAD    = 0x35,
+       WMI_GRP_BPF_OFFLOAD    = 0x36,
+       WMI_GRP_NAN_DATA       = 0x37,
+       WMI_GRP_PROTOTYPE      = 0x38,
+       WMI_GRP_MONITOR        = 0x39,
+       WMI_GRP_REGULATORY     = 0x3a,
+       WMI_GRP_HW_DATA_FILTER = 0x3b,
+};
+
+#define WMI_CMD_GRP(grp_id) (((grp_id) << 12) | 0x1)
+#define WMI_EVT_GRP_START_ID(grp_id) (((grp_id) << 12) | 0x1)
+
+#define WMI_CMD_UNSUPPORTED 0
+
+enum wmi_tlv_cmd_id {
+       WMI_INIT_CMDID = 0x1,
+       WMI_START_SCAN_CMDID = WMI_TLV_CMD(WMI_GRP_SCAN),
+       WMI_STOP_SCAN_CMDID,
+       WMI_SCAN_CHAN_LIST_CMDID,
+       WMI_SCAN_SCH_PRIO_TBL_CMDID,
+       WMI_SCAN_UPDATE_REQUEST_CMDID,
+       WMI_SCAN_PROB_REQ_OUI_CMDID,
+       WMI_SCAN_ADAPTIVE_DWELL_CONFIG_CMDID,
+       WMI_PDEV_SET_REGDOMAIN_CMDID = WMI_TLV_CMD(WMI_GRP_PDEV),
+       WMI_PDEV_SET_CHANNEL_CMDID,
+       WMI_PDEV_SET_PARAM_CMDID,
+       WMI_PDEV_PKTLOG_ENABLE_CMDID,
+       WMI_PDEV_PKTLOG_DISABLE_CMDID,
+       WMI_PDEV_SET_WMM_PARAMS_CMDID,
+       WMI_PDEV_SET_HT_CAP_IE_CMDID,
+       WMI_PDEV_SET_VHT_CAP_IE_CMDID,
+       WMI_PDEV_SET_DSCP_TID_MAP_CMDID,
+       WMI_PDEV_SET_QUIET_MODE_CMDID,
+       WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+       WMI_PDEV_GET_TPC_CONFIG_CMDID,
+       WMI_PDEV_SET_BASE_MACADDR_CMDID,
+       WMI_PDEV_DUMP_CMDID,
+       WMI_PDEV_SET_LED_CONFIG_CMDID,
+       WMI_PDEV_GET_TEMPERATURE_CMDID,
+       WMI_PDEV_SET_LED_FLASHING_CMDID,
+       WMI_PDEV_SMART_ANT_ENABLE_CMDID,
+       WMI_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID,
+       WMI_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID,
+       WMI_PDEV_SET_CTL_TABLE_CMDID,
+       WMI_PDEV_SET_MIMOGAIN_TABLE_CMDID,
+       WMI_PDEV_FIPS_CMDID,
+       WMI_PDEV_GET_ANI_CCK_CONFIG_CMDID,
+       WMI_PDEV_GET_ANI_OFDM_CONFIG_CMDID,
+       WMI_PDEV_GET_NFCAL_POWER_CMDID,
+       WMI_PDEV_GET_TPC_CMDID,
+       WMI_MIB_STATS_ENABLE_CMDID,
+       WMI_PDEV_SET_PCL_CMDID,
+       WMI_PDEV_SET_HW_MODE_CMDID,
+       WMI_PDEV_SET_MAC_CONFIG_CMDID,
+       WMI_PDEV_SET_ANTENNA_MODE_CMDID,
+       WMI_SET_PERIODIC_CHANNEL_STATS_CONFIG_CMDID,
+       WMI_PDEV_WAL_POWER_DEBUG_CMDID,
+       WMI_PDEV_SET_REORDER_TIMEOUT_VAL_CMDID,
+       WMI_PDEV_SET_WAKEUP_CONFIG_CMDID,
+       WMI_PDEV_GET_ANTDIV_STATUS_CMDID,
+       WMI_PDEV_GET_CHIP_POWER_STATS_CMDID,
+       WMI_PDEV_SET_STATS_THRESHOLD_CMDID,
+       WMI_PDEV_MULTIPLE_VDEV_RESTART_REQUEST_CMDID,
+       WMI_PDEV_UPDATE_PKT_ROUTING_CMDID,
+       WMI_PDEV_CHECK_CAL_VERSION_CMDID,
+       WMI_PDEV_SET_DIVERSITY_GAIN_CMDID,
+       WMI_PDEV_DIV_GET_RSSI_ANTID_CMDID,
+       WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
+       WMI_PDEV_UPDATE_PMK_CACHE_CMDID,
+       WMI_PDEV_UPDATE_FILS_HLP_PKT_CMDID,
+       WMI_PDEV_UPDATE_CTLTABLE_REQUEST_CMDID,
+       WMI_PDEV_CONFIG_VENDOR_OUI_ACTION_CMDID,
+       WMI_PDEV_SET_AC_TX_QUEUE_OPTIMIZED_CMDID,
+       WMI_PDEV_SET_RX_FILTER_PROMISCUOUS_CMDID,
+       WMI_PDEV_DMA_RING_CFG_REQ_CMDID,
+       WMI_PDEV_HE_TB_ACTION_FRM_CMDID,
+       WMI_PDEV_PKTLOG_FILTER_CMDID,
+       WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
+       WMI_VDEV_DELETE_CMDID,
+       WMI_VDEV_START_REQUEST_CMDID,
+       WMI_VDEV_RESTART_REQUEST_CMDID,
+       WMI_VDEV_UP_CMDID,
+       WMI_VDEV_STOP_CMDID,
+       WMI_VDEV_DOWN_CMDID,
+       WMI_VDEV_SET_PARAM_CMDID,
+       WMI_VDEV_INSTALL_KEY_CMDID,
+       WMI_VDEV_WNM_SLEEPMODE_CMDID,
+       WMI_VDEV_WMM_ADDTS_CMDID,
+       WMI_VDEV_WMM_DELTS_CMDID,
+       WMI_VDEV_SET_WMM_PARAMS_CMDID,
+       WMI_VDEV_SET_GTX_PARAMS_CMDID,
+       WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID,
+       WMI_VDEV_PLMREQ_START_CMDID,
+       WMI_VDEV_PLMREQ_STOP_CMDID,
+       WMI_VDEV_TSF_TSTAMP_ACTION_CMDID,
+       WMI_VDEV_SET_IE_CMDID,
+       WMI_VDEV_RATEMASK_CMDID,
+       WMI_VDEV_ATF_REQUEST_CMDID,
+       WMI_VDEV_SET_DSCP_TID_MAP_CMDID,
+       WMI_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID,
+       WMI_VDEV_SET_QUIET_MODE_CMDID,
+       WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID,
+       WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID,
+       WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID,
+       WMI_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_PEER),
+       WMI_PEER_DELETE_CMDID,
+       WMI_PEER_FLUSH_TIDS_CMDID,
+       WMI_PEER_SET_PARAM_CMDID,
+       WMI_PEER_ASSOC_CMDID,
+       WMI_PEER_ADD_WDS_ENTRY_CMDID,
+       WMI_PEER_REMOVE_WDS_ENTRY_CMDID,
+       WMI_PEER_MCAST_GROUP_CMDID,
+       WMI_PEER_INFO_REQ_CMDID,
+       WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID,
+       WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID,
+       WMI_PEER_UPDATE_WDS_ENTRY_CMDID,
+       WMI_PEER_ADD_PROXY_STA_ENTRY_CMDID,
+       WMI_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID,
+       WMI_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID,
+       WMI_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID,
+       WMI_PEER_ATF_REQUEST_CMDID,
+       WMI_PEER_BWF_REQUEST_CMDID,
+       WMI_PEER_REORDER_QUEUE_SETUP_CMDID,
+       WMI_PEER_REORDER_QUEUE_REMOVE_CMDID,
+       WMI_PEER_SET_RX_BLOCKSIZE_CMDID,
+       WMI_PEER_ANTDIV_INFO_REQ_CMDID,
+       WMI_PEER_OPER_MODE_CHANGE_EVENTID,
+       WMI_BCN_TX_CMDID = WMI_TLV_CMD(WMI_GRP_MGMT),
+       WMI_PDEV_SEND_BCN_CMDID,
+       WMI_BCN_TMPL_CMDID,
+       WMI_BCN_FILTER_RX_CMDID,
+       WMI_PRB_REQ_FILTER_RX_CMDID,
+       WMI_MGMT_TX_CMDID,
+       WMI_PRB_TMPL_CMDID,
+       WMI_MGMT_TX_SEND_CMDID,
+       WMI_OFFCHAN_DATA_TX_SEND_CMDID,
+       WMI_PDEV_SEND_FD_CMDID,
+       WMI_BCN_OFFLOAD_CTRL_CMDID,
+       WMI_BSS_COLOR_CHANGE_ENABLE_CMDID,
+       WMI_VDEV_BCN_OFFLOAD_QUIET_CONFIG_CMDID,
+       WMI_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_GRP_BA_NEG),
+       WMI_ADDBA_SEND_CMDID,
+       WMI_ADDBA_STATUS_CMDID,
+       WMI_DELBA_SEND_CMDID,
+       WMI_ADDBA_SET_RESP_CMDID,
+       WMI_SEND_SINGLEAMSDU_CMDID,
+       WMI_STA_POWERSAVE_MODE_CMDID = WMI_TLV_CMD(WMI_GRP_STA_PS),
+       WMI_STA_POWERSAVE_PARAM_CMDID,
+       WMI_STA_MIMO_PS_MODE_CMDID,
+       WMI_PDEV_DFS_ENABLE_CMDID = WMI_TLV_CMD(WMI_GRP_DFS),
+       WMI_PDEV_DFS_DISABLE_CMDID,
+       WMI_DFS_PHYERR_FILTER_ENA_CMDID,
+       WMI_DFS_PHYERR_FILTER_DIS_CMDID,
+       WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMDID,
+       WMI_PDEV_DFS_PHYERR_OFFLOAD_DISABLE_CMDID,
+       WMI_VDEV_ADFS_CH_CFG_CMDID,
+       WMI_VDEV_ADFS_OCAC_ABORT_CMDID,
+       WMI_ROAM_SCAN_MODE = WMI_TLV_CMD(WMI_GRP_ROAM),
+       WMI_ROAM_SCAN_RSSI_THRESHOLD,
+       WMI_ROAM_SCAN_PERIOD,
+       WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+       WMI_ROAM_AP_PROFILE,
+       WMI_ROAM_CHAN_LIST,
+       WMI_ROAM_SCAN_CMD,
+       WMI_ROAM_SYNCH_COMPLETE,
+       WMI_ROAM_SET_RIC_REQUEST_CMDID,
+       WMI_ROAM_INVOKE_CMDID,
+       WMI_ROAM_FILTER_CMDID,
+       WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID,
+       WMI_ROAM_CONFIGURE_MAWC_CMDID,
+       WMI_ROAM_SET_MBO_PARAM_CMDID,
+       WMI_ROAM_PER_CONFIG_CMDID,
+       WMI_OFL_SCAN_ADD_AP_PROFILE = WMI_TLV_CMD(WMI_GRP_OFL_SCAN),
+       WMI_OFL_SCAN_REMOVE_AP_PROFILE,
+       WMI_OFL_SCAN_PERIOD,
+       WMI_P2P_DEV_SET_DEVICE_INFO = WMI_TLV_CMD(WMI_GRP_P2P),
+       WMI_P2P_DEV_SET_DISCOVERABILITY,
+       WMI_P2P_GO_SET_BEACON_IE,
+       WMI_P2P_GO_SET_PROBE_RESP_IE,
+       WMI_P2P_SET_VENDOR_IE_DATA_CMDID,
+       WMI_P2P_DISC_OFFLOAD_CONFIG_CMDID,
+       WMI_P2P_DISC_OFFLOAD_APPIE_CMDID,
+       WMI_P2P_DISC_OFFLOAD_PATTERN_CMDID,
+       WMI_P2P_SET_OPPPS_PARAM_CMDID,
+       WMI_P2P_LISTEN_OFFLOAD_START_CMDID,
+       WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID,
+       WMI_AP_PS_PEER_PARAM_CMDID = WMI_TLV_CMD(WMI_GRP_AP_PS),
+       WMI_AP_PS_PEER_UAPSD_COEX_CMDID,
+       WMI_AP_PS_EGAP_PARAM_CMDID,
+       WMI_PEER_RATE_RETRY_SCHED_CMDID = WMI_TLV_CMD(WMI_GRP_RATE_CTRL),
+       WMI_WLAN_PROFILE_TRIGGER_CMDID = WMI_TLV_CMD(WMI_GRP_PROFILE),
+       WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+       WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+       WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+       WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+       WMI_PDEV_SUSPEND_CMDID = WMI_TLV_CMD(WMI_GRP_SUSPEND),
+       WMI_PDEV_RESUME_CMDID,
+       WMI_ADD_BCN_FILTER_CMDID = WMI_TLV_CMD(WMI_GRP_BCN_FILTER),
+       WMI_RMV_BCN_FILTER_CMDID,
+       WMI_WOW_ADD_WAKE_PATTERN_CMDID = WMI_TLV_CMD(WMI_GRP_WOW),
+       WMI_WOW_DEL_WAKE_PATTERN_CMDID,
+       WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+       WMI_WOW_ENABLE_CMDID,
+       WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+       WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID,
+       WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID,
+       WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID,
+       WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID,
+       WMI_D0_WOW_ENABLE_DISABLE_CMDID,
+       WMI_EXTWOW_ENABLE_CMDID,
+       WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID,
+       WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID,
+       WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID,
+       WMI_WOW_UDP_SVC_OFLD_CMDID,
+       WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID,
+       WMI_WOW_SET_ACTION_WAKE_UP_CMDID,
+       WMI_RTT_MEASREQ_CMDID = WMI_TLV_CMD(WMI_GRP_RTT),
+       WMI_RTT_TSF_CMDID,
+       WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID = WMI_TLV_CMD(WMI_GRP_SPECTRAL),
+       WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
+       WMI_REQUEST_STATS_CMDID = WMI_TLV_CMD(WMI_GRP_STATS),
+       WMI_MCC_SCHED_TRAFFIC_STATS_CMDID,
+       WMI_REQUEST_STATS_EXT_CMDID,
+       WMI_REQUEST_LINK_STATS_CMDID,
+       WMI_START_LINK_STATS_CMDID,
+       WMI_CLEAR_LINK_STATS_CMDID,
+       WMI_GET_FW_MEM_DUMP_CMDID,
+       WMI_DEBUG_MESG_FLUSH_CMDID,
+       WMI_DIAG_EVENT_LOG_CONFIG_CMDID,
+       WMI_REQUEST_WLAN_STATS_CMDID,
+       WMI_REQUEST_RCPI_CMDID,
+       WMI_REQUEST_PEER_STATS_INFO_CMDID,
+       WMI_REQUEST_RADIO_CHAN_STATS_CMDID,
+       WMI_SET_ARP_NS_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_GRP_ARP_NS_OFL),
+       WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID,
+       WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID,
+       WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID = WMI_TLV_CMD(WMI_GRP_NLO_OFL),
+       WMI_APFIND_CMDID,
+       WMI_PASSPOINT_LIST_CONFIG_CMDID,
+       WMI_NLO_CONFIGURE_MAWC_CMDID,
+       WMI_GTK_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_GRP_GTK_OFL),
+       WMI_CSA_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_GRP_CSA_OFL),
+       WMI_CSA_OFFLOAD_CHANSWITCH_CMDID,
+       WMI_CHATTER_SET_MODE_CMDID = WMI_TLV_CMD(WMI_GRP_CHATTER),
+       WMI_CHATTER_ADD_COALESCING_FILTER_CMDID,
+       WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID,
+       WMI_CHATTER_COALESCING_QUERY_CMDID,
+       WMI_PEER_TID_ADDBA_CMDID = WMI_TLV_CMD(WMI_GRP_TID_ADDBA),
+       WMI_PEER_TID_DELBA_CMDID,
+       WMI_STA_DTIM_PS_METHOD_CMDID,
+       WMI_STA_UAPSD_AUTO_TRIG_CMDID,
+       WMI_STA_KEEPALIVE_CMDID,
+       WMI_BA_REQ_SSN_CMDID,
+       WMI_ECHO_CMDID = WMI_TLV_CMD(WMI_GRP_MISC),
+       WMI_PDEV_UTF_CMDID,
+       WMI_DBGLOG_CFG_CMDID,
+       WMI_PDEV_QVIT_CMDID,
+       WMI_PDEV_FTM_INTG_CMDID,
+       WMI_VDEV_SET_KEEPALIVE_CMDID,
+       WMI_VDEV_GET_KEEPALIVE_CMDID,
+       WMI_FORCE_FW_HANG_CMDID,
+       WMI_SET_MCASTBCAST_FILTER_CMDID,
+       WMI_THERMAL_MGMT_CMDID,
+       WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID,
+       WMI_TPC_CHAINMASK_CONFIG_CMDID,
+       WMI_SET_ANTENNA_DIVERSITY_CMDID,
+       WMI_OCB_SET_SCHED_CMDID,
+       WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID,
+       WMI_LRO_CONFIG_CMDID,
+       WMI_TRANSFER_DATA_TO_FLASH_CMDID,
+       WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID,
+       WMI_VDEV_WISA_CMDID,
+       WMI_DBGLOG_TIME_STAMP_SYNC_CMDID,
+       WMI_SET_MULTIPLE_MCAST_FILTER_CMDID,
+       WMI_READ_DATA_FROM_FLASH_CMDID,
+       WMI_GPIO_CONFIG_CMDID = WMI_TLV_CMD(WMI_GRP_GPIO),
+       WMI_GPIO_OUTPUT_CMDID,
+       WMI_TXBF_CMDID,
+       WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID = WMI_TLV_CMD(WMI_GRP_FWTEST),
+       WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID,
+       WMI_UNIT_TEST_CMDID,
+       WMI_FWTEST_CMDID,
+       WMI_QBOOST_CFG_CMDID,
+       WMI_TDLS_SET_STATE_CMDID = WMI_TLV_CMD(WMI_GRP_TDLS),
+       WMI_TDLS_PEER_UPDATE_CMDID,
+       WMI_TDLS_SET_OFFCHAN_MODE_CMDID,
+       WMI_RESMGR_ADAPTIVE_OCS_EN_DIS_CMDID = WMI_TLV_CMD(WMI_GRP_RESMGR),
+       WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID,
+       WMI_RESMGR_SET_CHAN_LATENCY_CMDID,
+       WMI_STA_SMPS_FORCE_MODE_CMDID = WMI_TLV_CMD(WMI_GRP_STA_SMPS),
+       WMI_STA_SMPS_PARAM_CMDID,
+       WMI_HB_SET_ENABLE_CMDID = WMI_TLV_CMD(WMI_GRP_WLAN_HB),
+       WMI_HB_SET_TCP_PARAMS_CMDID,
+       WMI_HB_SET_TCP_PKT_FILTER_CMDID,
+       WMI_HB_SET_UDP_PARAMS_CMDID,
+       WMI_HB_SET_UDP_PKT_FILTER_CMDID,
+       WMI_RMC_SET_MODE_CMDID = WMI_TLV_CMD(WMI_GRP_RMC),
+       WMI_RMC_SET_ACTION_PERIOD_CMDID,
+       WMI_RMC_CONFIG_CMDID,
+       WMI_RMC_SET_MANUAL_LEADER_CMDID,
+       WMI_MHF_OFFLOAD_SET_MODE_CMDID = WMI_TLV_CMD(WMI_GRP_MHF_OFL),
+       WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID,
+       WMI_BATCH_SCAN_ENABLE_CMDID = WMI_TLV_CMD(WMI_GRP_LOCATION_SCAN),
+       WMI_BATCH_SCAN_DISABLE_CMDID,
+       WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID,
+       WMI_OEM_REQ_CMDID = WMI_TLV_CMD(WMI_GRP_OEM),
+       WMI_OEM_REQUEST_CMDID,
+       WMI_LPI_OEM_REQ_CMDID,
+       WMI_NAN_CMDID = WMI_TLV_CMD(WMI_GRP_NAN),
+       WMI_MODEM_POWER_STATE_CMDID = WMI_TLV_CMD(WMI_GRP_COEX),
+       WMI_CHAN_AVOID_UPDATE_CMDID,
+       WMI_COEX_CONFIG_CMDID,
+       WMI_CHAN_AVOID_RPT_ALLOW_CMDID,
+       WMI_COEX_GET_ANTENNA_ISOLATION_CMDID,
+       WMI_SAR_LIMITS_CMDID,
+       WMI_OBSS_SCAN_ENABLE_CMDID = WMI_TLV_CMD(WMI_GRP_OBSS_OFL),
+       WMI_OBSS_SCAN_DISABLE_CMDID,
+       WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID = WMI_TLV_CMD(WMI_GRP_LPI),
+       WMI_LPI_START_SCAN_CMDID,
+       WMI_LPI_STOP_SCAN_CMDID,
+       WMI_EXTSCAN_START_CMDID = WMI_TLV_CMD(WMI_GRP_EXTSCAN),
+       WMI_EXTSCAN_STOP_CMDID,
+       WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID,
+       WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID,
+       WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID,
+       WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID,
+       WMI_EXTSCAN_SET_CAPABILITIES_CMDID,
+       WMI_EXTSCAN_GET_CAPABILITIES_CMDID,
+       WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID,
+       WMI_EXTSCAN_CONFIGURE_MAWC_CMDID,
+       WMI_SET_DHCP_SERVER_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_GRP_DHCP_OFL),
+       WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID = WMI_TLV_CMD(WMI_GRP_IPA),
+       WMI_MDNS_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_GRP_MDNS_OFL),
+       WMI_MDNS_SET_FQDN_CMDID,
+       WMI_MDNS_SET_RESPONSE_CMDID,
+       WMI_MDNS_GET_STATS_CMDID,
+       WMI_SAP_OFL_ENABLE_CMDID = WMI_TLV_CMD(WMI_GRP_SAP_OFL),
+       WMI_SAP_SET_BLACKLIST_PARAM_CMDID,
+       WMI_OCB_SET_CONFIG_CMDID = WMI_TLV_CMD(WMI_GRP_OCB),
+       WMI_OCB_SET_UTC_TIME_CMDID,
+       WMI_OCB_START_TIMING_ADVERT_CMDID,
+       WMI_OCB_STOP_TIMING_ADVERT_CMDID,
+       WMI_OCB_GET_TSF_TIMER_CMDID,
+       WMI_DCC_GET_STATS_CMDID,
+       WMI_DCC_CLEAR_STATS_CMDID,
+       WMI_DCC_UPDATE_NDL_CMDID,
+       WMI_SOC_SET_PCL_CMDID = WMI_TLV_CMD(WMI_GRP_SOC),
+       WMI_SOC_SET_HW_MODE_CMDID,
+       WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID,
+       WMI_SOC_SET_ANTENNA_MODE_CMDID,
+       WMI_PACKET_FILTER_CONFIG_CMDID = WMI_TLV_CMD(WMI_GRP_PKT_FILTER),
+       WMI_PACKET_FILTER_ENABLE_CMDID,
+       WMI_MAWC_SENSOR_REPORT_IND_CMDID = WMI_TLV_CMD(WMI_GRP_MAWC),
+       WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID = WMI_TLV_CMD(WMI_GRP_PMF_OFFLOAD),
+       WMI_BPF_GET_CAPABILITY_CMDID = WMI_TLV_CMD(WMI_GRP_BPF_OFFLOAD),
+       WMI_BPF_GET_VDEV_STATS_CMDID,
+       WMI_BPF_SET_VDEV_INSTRUCTIONS_CMDID,
+       WMI_BPF_DEL_VDEV_INSTRUCTIONS_CMDID,
+       WMI_BPF_SET_VDEV_ACTIVE_MODE_CMDID,
+       WMI_MNT_FILTER_CMDID = WMI_TLV_CMD(WMI_GRP_MONITOR),
+       WMI_SET_CURRENT_COUNTRY_CMDID = WMI_TLV_CMD(WMI_GRP_REGULATORY),
+       WMI_11D_SCAN_START_CMDID,
+       WMI_11D_SCAN_STOP_CMDID,
+       WMI_SET_INIT_COUNTRY_CMDID,
+       WMI_NDI_GET_CAP_REQ_CMDID = WMI_TLV_CMD(WMI_GRP_PROTOTYPE),
+       WMI_NDP_INITIATOR_REQ_CMDID,
+       WMI_NDP_RESPONDER_REQ_CMDID,
+       WMI_NDP_END_REQ_CMDID,
+       WMI_HW_DATA_FILTER_CMDID = WMI_TLV_CMD(WMI_GRP_HW_DATA_FILTER),
+};
+
+enum wmi_tlv_event_id {
+       WMI_SERVICE_READY_EVENTID = 0x1,
+       WMI_READY_EVENTID,
+       WMI_SERVICE_AVAILABLE_EVENTID,
+       WMI_SCAN_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SCAN),
+       WMI_PDEV_TPC_CONFIG_EVENTID = WMI_TLV_CMD(WMI_GRP_PDEV),
+       WMI_CHAN_INFO_EVENTID,
+       WMI_PHYERR_EVENTID,
+       WMI_PDEV_DUMP_EVENTID,
+       WMI_TX_PAUSE_EVENTID,
+       WMI_DFS_RADAR_EVENTID,
+       WMI_PDEV_L1SS_TRACK_EVENTID,
+       WMI_PDEV_TEMPERATURE_EVENTID,
+       WMI_SERVICE_READY_EXT_EVENTID,
+       WMI_PDEV_FIPS_EVENTID,
+       WMI_PDEV_CHANNEL_HOPPING_EVENTID,
+       WMI_PDEV_ANI_CCK_LEVEL_EVENTID,
+       WMI_PDEV_ANI_OFDM_LEVEL_EVENTID,
+       WMI_PDEV_TPC_EVENTID,
+       WMI_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID,
+       WMI_PDEV_SET_HW_MODE_RESP_EVENTID,
+       WMI_PDEV_HW_MODE_TRANSITION_EVENTID,
+       WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID,
+       WMI_PDEV_ANTDIV_STATUS_EVENTID,
+       WMI_PDEV_CHIP_POWER_STATS_EVENTID,
+       WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID,
+       WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID,
+       WMI_PDEV_CHECK_CAL_VERSION_EVENTID,
+       WMI_PDEV_DIV_RSSI_ANTID_EVENTID,
+       WMI_PDEV_BSS_CHAN_INFO_EVENTID,
+       WMI_PDEV_UPDATE_CTLTABLE_EVENTID,
+       WMI_PDEV_DMA_RING_CFG_RSP_EVENTID,
+       WMI_PDEV_DMA_RING_BUF_RELEASE_EVENTID,
+       WMI_PDEV_CTL_FAILSAFE_CHECK_EVENTID,
+       WMI_VDEV_START_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_VDEV),
+       WMI_VDEV_STOPPED_EVENTID,
+       WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
+       WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID,
+       WMI_VDEV_TSF_REPORT_EVENTID,
+       WMI_VDEV_DELETE_RESP_EVENTID,
+       WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID,
+       WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID,
+       WMI_PEER_STA_KICKOUT_EVENTID = WMI_TLV_CMD(WMI_GRP_PEER),
+       WMI_PEER_INFO_EVENTID,
+       WMI_PEER_TX_FAIL_CNT_THR_EVENTID,
+       WMI_PEER_ESTIMATED_LINKSPEED_EVENTID,
+       WMI_PEER_STATE_EVENTID,
+       WMI_PEER_ASSOC_CONF_EVENTID,
+       WMI_PEER_DELETE_RESP_EVENTID,
+       WMI_PEER_RATECODE_LIST_EVENTID,
+       WMI_WDS_PEER_EVENTID,
+       WMI_PEER_STA_PS_STATECHG_EVENTID,
+       WMI_PEER_ANTDIV_INFO_EVENTID,
+       WMI_MGMT_RX_EVENTID = WMI_TLV_CMD(WMI_GRP_MGMT),
+       WMI_HOST_SWBA_EVENTID,
+       WMI_TBTTOFFSET_UPDATE_EVENTID,
+       WMI_OFFLOAD_BCN_TX_STATUS_EVENTID,
+       WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID,
+       WMI_MGMT_TX_COMPLETION_EVENTID,
+       WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID,
+       WMI_TBTTOFFSET_EXT_UPDATE_EVENTID,
+       WMI_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_CMD(WMI_GRP_BA_NEG),
+       WMI_TX_ADDBA_COMPLETE_EVENTID,
+       WMI_BA_RSP_SSN_EVENTID,
+       WMI_AGGR_STATE_TRIG_EVENTID,
+       WMI_ROAM_EVENTID = WMI_TLV_CMD(WMI_GRP_ROAM),
+       WMI_PROFILE_MATCH,
+       WMI_ROAM_SYNCH_EVENTID,
+       WMI_P2P_DISC_EVENTID = WMI_TLV_CMD(WMI_GRP_P2P),
+       WMI_P2P_NOA_EVENTID,
+       WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID,
+       WMI_AP_PS_EGAP_INFO_EVENTID = WMI_TLV_CMD(WMI_GRP_AP_PS),
+       WMI_PDEV_RESUME_EVENTID = WMI_TLV_CMD(WMI_GRP_SUSPEND),
+       WMI_WOW_WAKEUP_HOST_EVENTID = WMI_TLV_CMD(WMI_GRP_WOW),
+       WMI_D0_WOW_DISABLE_ACK_EVENTID,
+       WMI_WOW_INITIAL_WAKEUP_EVENTID,
+       WMI_RTT_MEASUREMENT_REPORT_EVENTID = WMI_TLV_CMD(WMI_GRP_RTT),
+       WMI_TSF_MEASUREMENT_REPORT_EVENTID,
+       WMI_RTT_ERROR_REPORT_EVENTID,
+       WMI_STATS_EXT_EVENTID = WMI_TLV_CMD(WMI_GRP_STATS),
+       WMI_IFACE_LINK_STATS_EVENTID,
+       WMI_PEER_LINK_STATS_EVENTID,
+       WMI_RADIO_LINK_STATS_EVENTID,
+       WMI_UPDATE_FW_MEM_DUMP_EVENTID,
+       WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID,
+       WMI_INST_RSSI_STATS_EVENTID,
+       WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID,
+       WMI_REPORT_STATS_EVENTID,
+       WMI_UPDATE_RCPI_EVENTID,
+       WMI_PEER_STATS_INFO_EVENTID,
+       WMI_RADIO_CHAN_STATS_EVENTID,
+       WMI_NLO_MATCH_EVENTID = WMI_TLV_CMD(WMI_GRP_NLO_OFL),
+       WMI_NLO_SCAN_COMPLETE_EVENTID,
+       WMI_APFIND_EVENTID,
+       WMI_PASSPOINT_MATCH_EVENTID,
+       WMI_GTK_OFFLOAD_STATUS_EVENTID = WMI_TLV_CMD(WMI_GRP_GTK_OFL),
+       WMI_GTK_REKEY_FAIL_EVENTID,
+       WMI_CSA_HANDLING_EVENTID = WMI_TLV_CMD(WMI_GRP_CSA_OFL),
+       WMI_CHATTER_PC_QUERY_EVENTID = WMI_TLV_CMD(WMI_GRP_CHATTER),
+       WMI_PDEV_DFS_RADAR_DETECTION_EVENTID = WMI_TLV_CMD(WMI_GRP_DFS),
+       WMI_VDEV_DFS_CAC_COMPLETE_EVENTID,
+       WMI_VDEV_ADFS_OCAC_COMPLETE_EVENTID,
+       WMI_ECHO_EVENTID = WMI_TLV_CMD(WMI_GRP_MISC),
+       WMI_PDEV_UTF_EVENTID,
+       WMI_DEBUG_MESG_EVENTID,
+       WMI_UPDATE_STATS_EVENTID,
+       WMI_DEBUG_PRINT_EVENTID,
+       WMI_DCS_INTERFERENCE_EVENTID,
+       WMI_PDEV_QVIT_EVENTID,
+       WMI_WLAN_PROFILE_DATA_EVENTID,
+       WMI_PDEV_FTM_INTG_EVENTID,
+       WMI_WLAN_FREQ_AVOID_EVENTID,
+       WMI_VDEV_GET_KEEPALIVE_EVENTID,
+       WMI_THERMAL_MGMT_EVENTID,
+       WMI_DIAG_DATA_CONTAINER_EVENTID,
+       WMI_HOST_AUTO_SHUTDOWN_EVENTID,
+       WMI_UPDATE_WHAL_MIB_STATS_EVENTID,
+       WMI_UPDATE_VDEV_RATE_STATS_EVENTID,
+       WMI_DIAG_EVENTID,
+       WMI_OCB_SET_SCHED_EVENTID,
+       WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID,
+       WMI_RSSI_BREACH_EVENTID,
+       WMI_TRANSFER_DATA_TO_FLASH_COMPLETE_EVENTID,
+       WMI_PDEV_UTF_SCPC_EVENTID,
+       WMI_READ_DATA_FROM_FLASH_EVENTID,
+       WMI_REPORT_RX_AGGR_FAILURE_EVENTID,
+       WMI_PKGID_EVENTID,
+       WMI_GPIO_INPUT_EVENTID = WMI_TLV_CMD(WMI_GRP_GPIO),
+       WMI_UPLOADH_EVENTID,
+       WMI_CAPTUREH_EVENTID,
+       WMI_RFKILL_STATE_CHANGE_EVENTID,
+       WMI_TDLS_PEER_EVENTID = WMI_TLV_CMD(WMI_GRP_TDLS),
+       WMI_STA_SMPS_FORCE_MODE_COMPL_EVENTID = WMI_TLV_CMD(WMI_GRP_STA_SMPS),
+       WMI_BATCH_SCAN_ENABLED_EVENTID = WMI_TLV_CMD(WMI_GRP_LOCATION_SCAN),
+       WMI_BATCH_SCAN_RESULT_EVENTID,
+       WMI_OEM_CAPABILITY_EVENTID = WMI_TLV_CMD(WMI_GRP_OEM),
+       WMI_OEM_MEASUREMENT_REPORT_EVENTID,
+       WMI_OEM_ERROR_REPORT_EVENTID,
+       WMI_OEM_RESPONSE_EVENTID,
+       WMI_NAN_EVENTID = WMI_TLV_CMD(WMI_GRP_NAN),
+       WMI_NAN_DISC_IFACE_CREATED_EVENTID,
+       WMI_NAN_DISC_IFACE_DELETED_EVENTID,
+       WMI_NAN_STARTED_CLUSTER_EVENTID,
+       WMI_NAN_JOINED_CLUSTER_EVENTID,
+       WMI_COEX_REPORT_ANTENNA_ISOLATION_EVENTID = WMI_TLV_CMD(WMI_GRP_COEX),
+       WMI_LPI_RESULT_EVENTID = WMI_TLV_CMD(WMI_GRP_LPI),
+       WMI_LPI_STATUS_EVENTID,
+       WMI_LPI_HANDOFF_EVENTID,
+       WMI_EXTSCAN_START_STOP_EVENTID = WMI_TLV_CMD(WMI_GRP_EXTSCAN),
+       WMI_EXTSCAN_OPERATION_EVENTID,
+       WMI_EXTSCAN_TABLE_USAGE_EVENTID,
+       WMI_EXTSCAN_CACHED_RESULTS_EVENTID,
+       WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID,
+       WMI_EXTSCAN_HOTLIST_MATCH_EVENTID,
+       WMI_EXTSCAN_CAPABILITIES_EVENTID,
+       WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID,
+       WMI_MDNS_STATS_EVENTID = WMI_TLV_CMD(WMI_GRP_MDNS_OFL),
+       WMI_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_CMD(WMI_GRP_SAP_OFL),
+       WMI_SAP_OFL_DEL_STA_EVENTID,
+       WMI_OCB_SET_CONFIG_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_OCB),
+       WMI_OCB_GET_TSF_TIMER_RESP_EVENTID,
+       WMI_DCC_GET_STATS_RESP_EVENTID,
+       WMI_DCC_UPDATE_NDL_RESP_EVENTID,
+       WMI_DCC_STATS_EVENTID,
+       WMI_SOC_SET_HW_MODE_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_SOC),
+       WMI_SOC_HW_MODE_TRANSITION_EVENTID,
+       WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID,
+       WMI_MAWC_ENABLE_SENSOR_EVENTID = WMI_TLV_CMD(WMI_GRP_MAWC),
+       WMI_BPF_CAPABILIY_INFO_EVENTID = WMI_TLV_CMD(WMI_GRP_BPF_OFFLOAD),
+       WMI_BPF_VDEV_STATS_INFO_EVENTID,
+       WMI_RMC_NEW_LEADER_EVENTID = WMI_TLV_CMD(WMI_GRP_RMC),
+       WMI_REG_CHAN_LIST_CC_EVENTID = WMI_TLV_CMD(WMI_GRP_REGULATORY),
+       WMI_11D_NEW_COUNTRY_EVENTID,
+       WMI_NDI_CAP_RSP_EVENTID = WMI_TLV_CMD(WMI_GRP_PROTOTYPE),
+       WMI_NDP_INITIATOR_RSP_EVENTID,
+       WMI_NDP_RESPONDER_RSP_EVENTID,
+       WMI_NDP_END_RSP_EVENTID,
+       WMI_NDP_INDICATION_EVENTID,
+       WMI_NDP_CONFIRM_EVENTID,
+       WMI_NDP_END_INDICATION_EVENTID,
+};
+
+enum wmi_tlv_pdev_param {
+       WMI_PDEV_PARAM_TX_CHAIN_MASK = 0x1,
+       WMI_PDEV_PARAM_RX_CHAIN_MASK,
+       WMI_PDEV_PARAM_TXPOWER_LIMIT2G,
+       WMI_PDEV_PARAM_TXPOWER_LIMIT5G,
+       WMI_PDEV_PARAM_TXPOWER_SCALE,
+       WMI_PDEV_PARAM_BEACON_GEN_MODE,
+       WMI_PDEV_PARAM_BEACON_TX_MODE,
+       WMI_PDEV_PARAM_RESMGR_OFFCHAN_MODE,
+       WMI_PDEV_PARAM_PROTECTION_MODE,
+       WMI_PDEV_PARAM_DYNAMIC_BW,
+       WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
+       WMI_PDEV_PARAM_AGG_SW_RETRY_TH,
+       WMI_PDEV_PARAM_STA_KICKOUT_TH,
+       WMI_PDEV_PARAM_AC_AGGRSIZE_SCALING,
+       WMI_PDEV_PARAM_LTR_ENABLE,
+       WMI_PDEV_PARAM_LTR_AC_LATENCY_BE,
+       WMI_PDEV_PARAM_LTR_AC_LATENCY_BK,
+       WMI_PDEV_PARAM_LTR_AC_LATENCY_VI,
+       WMI_PDEV_PARAM_LTR_AC_LATENCY_VO,
+       WMI_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT,
+       WMI_PDEV_PARAM_LTR_SLEEP_OVERRIDE,
+       WMI_PDEV_PARAM_LTR_RX_OVERRIDE,
+       WMI_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT,
+       WMI_PDEV_PARAM_L1SS_ENABLE,
+       WMI_PDEV_PARAM_DSLEEP_ENABLE,
+       WMI_PDEV_PARAM_PCIELP_TXBUF_FLUSH,
+       WMI_PDEV_PARAM_PCIELP_TXBUF_WATERMARK,
+       WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_EN,
+       WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE,
+       WMI_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
+       WMI_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD,
+       WMI_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD,
+       WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
+       WMI_PDEV_PARAM_PMF_QOS,
+       WMI_PDEV_PARAM_ARP_AC_OVERRIDE,
+       WMI_PDEV_PARAM_DCS,
+       WMI_PDEV_PARAM_ANI_ENABLE,
+       WMI_PDEV_PARAM_ANI_POLL_PERIOD,
+       WMI_PDEV_PARAM_ANI_LISTEN_PERIOD,
+       WMI_PDEV_PARAM_ANI_OFDM_LEVEL,
+       WMI_PDEV_PARAM_ANI_CCK_LEVEL,
+       WMI_PDEV_PARAM_DYNTXCHAIN,
+       WMI_PDEV_PARAM_PROXY_STA,
+       WMI_PDEV_PARAM_IDLE_PS_CONFIG,
+       WMI_PDEV_PARAM_POWER_GATING_SLEEP,
+       WMI_PDEV_PARAM_RFKILL_ENABLE,
+       WMI_PDEV_PARAM_BURST_DUR,
+       WMI_PDEV_PARAM_BURST_ENABLE,
+       WMI_PDEV_PARAM_HW_RFKILL_CONFIG,
+       WMI_PDEV_PARAM_LOW_POWER_RF_ENABLE,
+       WMI_PDEV_PARAM_L1SS_TRACK,
+       WMI_PDEV_PARAM_HYST_EN,
+       WMI_PDEV_PARAM_POWER_COLLAPSE_ENABLE,
+       WMI_PDEV_PARAM_LED_SYS_STATE,
+       WMI_PDEV_PARAM_LED_ENABLE,
+       WMI_PDEV_PARAM_AUDIO_OVER_WLAN_LATENCY,
+       WMI_PDEV_PARAM_AUDIO_OVER_WLAN_ENABLE,
+       WMI_PDEV_PARAM_WHAL_MIB_STATS_UPDATE_ENABLE,
+       WMI_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD,
+       WMI_PDEV_PARAM_CTS_CBW,
+       WMI_PDEV_PARAM_WNTS_CONFIG,
+       WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_ENABLE,
+       WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_MIN_SLEEP_SLOP,
+       WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_INC_DEC_STEP,
+       WMI_PDEV_PARAM_EARLY_RX_FIX_SLEEP_SLOP,
+       WMI_PDEV_PARAM_BMISS_BASED_ADAPTIVE_BTO_ENABLE,
+       WMI_PDEV_PARAM_BMISS_BTO_MIN_BCN_TIMEOUT,
+       WMI_PDEV_PARAM_BMISS_BTO_INC_DEC_STEP,
+       WMI_PDEV_PARAM_BTO_FIX_BCN_TIMEOUT,
+       WMI_PDEV_PARAM_CE_BASED_ADAPTIVE_BTO_ENABLE,
+       WMI_PDEV_PARAM_CE_BTO_COMBO_CE_VALUE,
+       WMI_PDEV_PARAM_TX_CHAIN_MASK_2G,
+       WMI_PDEV_PARAM_RX_CHAIN_MASK_2G,
+       WMI_PDEV_PARAM_TX_CHAIN_MASK_5G,
+       WMI_PDEV_PARAM_RX_CHAIN_MASK_5G,
+       WMI_PDEV_PARAM_TX_CHAIN_MASK_CCK,
+       WMI_PDEV_PARAM_TX_CHAIN_MASK_1SS,
+       WMI_PDEV_PARAM_CTS2SELF_FOR_P2P_GO_CONFIG,
+       WMI_PDEV_PARAM_TXPOWER_DECR_DB,
+       WMI_PDEV_PARAM_AGGR_BURST,
+       WMI_PDEV_PARAM_RX_DECAP_MODE,
+       WMI_PDEV_PARAM_FAST_CHANNEL_RESET,
+       WMI_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA,
+       WMI_PDEV_PARAM_ANTENNA_GAIN,
+       WMI_PDEV_PARAM_RX_FILTER,
+       WMI_PDEV_SET_MCAST_TO_UCAST_TID,
+       WMI_PDEV_PARAM_PROXY_STA_MODE,
+       WMI_PDEV_PARAM_SET_MCAST2UCAST_MODE,
+       WMI_PDEV_PARAM_SET_MCAST2UCAST_BUFFER,
+       WMI_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER,
+       WMI_PDEV_PEER_STA_PS_STATECHG_ENABLE,
+       WMI_PDEV_PARAM_IGMPMLD_AC_OVERRIDE,
+       WMI_PDEV_PARAM_BLOCK_INTERBSS,
+       WMI_PDEV_PARAM_SET_DISABLE_RESET_CMDID,
+       WMI_PDEV_PARAM_SET_MSDU_TTL_CMDID,
+       WMI_PDEV_PARAM_SET_PPDU_DURATION_CMDID,
+       WMI_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID,
+       WMI_PDEV_PARAM_SET_PROMISC_MODE_CMDID,
+       WMI_PDEV_PARAM_SET_BURST_MODE_CMDID,
+       WMI_PDEV_PARAM_EN_STATS,
+       WMI_PDEV_PARAM_MU_GROUP_POLICY,
+       WMI_PDEV_PARAM_NOISE_DETECTION,
+       WMI_PDEV_PARAM_NOISE_THRESHOLD,
+       WMI_PDEV_PARAM_DPD_ENABLE,
+       WMI_PDEV_PARAM_SET_MCAST_BCAST_ECHO,
+       WMI_PDEV_PARAM_ATF_STRICT_SCH,
+       WMI_PDEV_PARAM_ATF_SCHED_DURATION,
+       WMI_PDEV_PARAM_ANT_PLZN,
+       WMI_PDEV_PARAM_MGMT_RETRY_LIMIT,
+       WMI_PDEV_PARAM_SENSITIVITY_LEVEL,
+       WMI_PDEV_PARAM_SIGNED_TXPOWER_2G,
+       WMI_PDEV_PARAM_SIGNED_TXPOWER_5G,
+       WMI_PDEV_PARAM_ENABLE_PER_TID_AMSDU,
+       WMI_PDEV_PARAM_ENABLE_PER_TID_AMPDU,
+       WMI_PDEV_PARAM_CCA_THRESHOLD,
+       WMI_PDEV_PARAM_RTS_FIXED_RATE,
+       WMI_PDEV_PARAM_PDEV_RESET,
+       WMI_PDEV_PARAM_WAPI_MBSSID_OFFSET,
+       WMI_PDEV_PARAM_ARP_DBG_SRCADDR,
+       WMI_PDEV_PARAM_ARP_DBG_DSTADDR,
+       WMI_PDEV_PARAM_ATF_OBSS_NOISE_SCH,
+       WMI_PDEV_PARAM_ATF_OBSS_NOISE_SCALING_FACTOR,
+       WMI_PDEV_PARAM_CUST_TXPOWER_SCALE,
+       WMI_PDEV_PARAM_ATF_DYNAMIC_ENABLE,
+       WMI_PDEV_PARAM_CTRL_RETRY_LIMIT,
+       WMI_PDEV_PARAM_PROPAGATION_DELAY,
+       WMI_PDEV_PARAM_ENA_ANT_DIV,
+       WMI_PDEV_PARAM_FORCE_CHAIN_ANT,
+       WMI_PDEV_PARAM_ANT_DIV_SELFTEST,
+       WMI_PDEV_PARAM_ANT_DIV_SELFTEST_INTVL,
+       WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD,
+       WMI_PDEV_PARAM_TX_PPDU_DELAY_BIN_SIZE_MS,
+       WMI_PDEV_PARAM_TX_PPDU_DELAY_ARRAY_LEN,
+       WMI_PDEV_PARAM_TX_MPDU_AGGR_ARRAY_LEN,
+       WMI_PDEV_PARAM_RX_MPDU_AGGR_ARRAY_LEN,
+       WMI_PDEV_PARAM_TX_SCH_DELAY,
+       WMI_PDEV_PARAM_ENABLE_RTS_SIFS_BURSTING,
+       WMI_PDEV_PARAM_MAX_MPDUS_IN_AMPDU,
+       WMI_PDEV_PARAM_PEER_STATS_INFO_ENABLE,
+       WMI_PDEV_PARAM_FAST_PWR_TRANSITION,
+       WMI_PDEV_PARAM_RADIO_CHAN_STATS_ENABLE,
+       WMI_PDEV_PARAM_RADIO_DIAGNOSIS_ENABLE,
+       WMI_PDEV_PARAM_MESH_MCAST_ENABLE,
+};
+
+enum wmi_tlv_vdev_param {
+       WMI_VDEV_PARAM_RTS_THRESHOLD = 0x1,
+       WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
+       WMI_VDEV_PARAM_BEACON_INTERVAL,
+       WMI_VDEV_PARAM_LISTEN_INTERVAL,
+       WMI_VDEV_PARAM_MULTICAST_RATE,
+       WMI_VDEV_PARAM_MGMT_TX_RATE,
+       WMI_VDEV_PARAM_SLOT_TIME,
+       WMI_VDEV_PARAM_PREAMBLE,
+       WMI_VDEV_PARAM_SWBA_TIME,
+       WMI_VDEV_STATS_UPDATE_PERIOD,
+       WMI_VDEV_PWRSAVE_AGEOUT_TIME,
+       WMI_VDEV_HOST_SWBA_INTERVAL,
+       WMI_VDEV_PARAM_DTIM_PERIOD,
+       WMI_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
+       WMI_VDEV_PARAM_WDS,
+       WMI_VDEV_PARAM_ATIM_WINDOW,
+       WMI_VDEV_PARAM_BMISS_COUNT_MAX,
+       WMI_VDEV_PARAM_BMISS_FIRST_BCNT,
+       WMI_VDEV_PARAM_BMISS_FINAL_BCNT,
+       WMI_VDEV_PARAM_FEATURE_WMM,
+       WMI_VDEV_PARAM_CHWIDTH,
+       WMI_VDEV_PARAM_CHEXTOFFSET,
+       WMI_VDEV_PARAM_DISABLE_HTPROTECTION,
+       WMI_VDEV_PARAM_STA_QUICKKICKOUT,
+       WMI_VDEV_PARAM_MGMT_RATE,
+       WMI_VDEV_PARAM_PROTECTION_MODE,
+       WMI_VDEV_PARAM_FIXED_RATE,
+       WMI_VDEV_PARAM_SGI,
+       WMI_VDEV_PARAM_LDPC,
+       WMI_VDEV_PARAM_TX_STBC,
+       WMI_VDEV_PARAM_RX_STBC,
+       WMI_VDEV_PARAM_INTRA_BSS_FWD,
+       WMI_VDEV_PARAM_DEF_KEYID,
+       WMI_VDEV_PARAM_NSS,
+       WMI_VDEV_PARAM_BCAST_DATA_RATE,
+       WMI_VDEV_PARAM_MCAST_DATA_RATE,
+       WMI_VDEV_PARAM_MCAST_INDICATE,
+       WMI_VDEV_PARAM_DHCP_INDICATE,
+       WMI_VDEV_PARAM_UNKNOWN_DEST_INDICATE,
+       WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
+       WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
+       WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
+       WMI_VDEV_PARAM_AP_ENABLE_NAWDS,
+       WMI_VDEV_PARAM_ENABLE_RTSCTS,
+       WMI_VDEV_PARAM_TXBF,
+       WMI_VDEV_PARAM_PACKET_POWERSAVE,
+       WMI_VDEV_PARAM_DROP_UNENCRY,
+       WMI_VDEV_PARAM_TX_ENCAP_TYPE,
+       WMI_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
+       WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE,
+       WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM,
+       WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE,
+       WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP,
+       WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP,
+       WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE,
+       WMI_VDEV_PARAM_TX_PWRLIMIT,
+       WMI_VDEV_PARAM_SNR_NUM_FOR_CAL,
+       WMI_VDEV_PARAM_ROAM_FW_OFFLOAD,
+       WMI_VDEV_PARAM_ENABLE_RMC,
+       WMI_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS,
+       WMI_VDEV_PARAM_MAX_RATE,
+       WMI_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE,
+       WMI_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR,
+       WMI_VDEV_PARAM_EBT_RESYNC_TIMEOUT,
+       WMI_VDEV_PARAM_AGGR_TRIG_EVENT_ENABLE,
+       WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED,
+       WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED,
+       WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED,
+       WMI_VDEV_PARAM_INACTIVITY_CNT,
+       WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS,
+       WMI_VDEV_PARAM_DTIM_POLICY,
+       WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS,
+       WMI_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE,
+       WMI_VDEV_PARAM_RX_LEAK_WINDOW,
+       WMI_VDEV_PARAM_STATS_AVG_FACTOR,
+       WMI_VDEV_PARAM_DISCONNECT_TH,
+       WMI_VDEV_PARAM_RTSCTS_RATE,
+       WMI_VDEV_PARAM_MCC_RTSCTS_PROTECTION_ENABLE,
+       WMI_VDEV_PARAM_MCC_BROADCAST_PROBE_ENABLE,
+       WMI_VDEV_PARAM_TXPOWER_SCALE,
+       WMI_VDEV_PARAM_TXPOWER_SCALE_DECR_DB,
+       WMI_VDEV_PARAM_MCAST2UCAST_SET,
+       WMI_VDEV_PARAM_RC_NUM_RETRIES,
+       WMI_VDEV_PARAM_CABQ_MAXDUR,
+       WMI_VDEV_PARAM_MFPTEST_SET,
+       WMI_VDEV_PARAM_RTS_FIXED_RATE,
+       WMI_VDEV_PARAM_VHT_SGIMASK,
+       WMI_VDEV_PARAM_VHT80_RATEMASK,
+       WMI_VDEV_PARAM_PROXY_STA,
+       WMI_VDEV_PARAM_VIRTUAL_CELL_MODE,
+       WMI_VDEV_PARAM_RX_DECAP_TYPE,
+       WMI_VDEV_PARAM_BW_NSS_RATEMASK,
+       WMI_VDEV_PARAM_SENSOR_AP,
+       WMI_VDEV_PARAM_BEACON_RATE,
+       WMI_VDEV_PARAM_DTIM_ENABLE_CTS,
+       WMI_VDEV_PARAM_STA_KICKOUT,
+       WMI_VDEV_PARAM_CAPABILITIES,
+       WMI_VDEV_PARAM_TSF_INCREMENT,
+       WMI_VDEV_PARAM_AMPDU_PER_AC,
+       WMI_VDEV_PARAM_RX_FILTER,
+       WMI_VDEV_PARAM_MGMT_TX_POWER,
+       WMI_VDEV_PARAM_NON_AGG_SW_RETRY_TH,
+       WMI_VDEV_PARAM_AGG_SW_RETRY_TH,
+       WMI_VDEV_PARAM_DISABLE_DYN_BW_RTS,
+       WMI_VDEV_PARAM_ATF_SSID_SCHED_POLICY,
+       WMI_VDEV_PARAM_HE_DCM,
+       WMI_VDEV_PARAM_HE_RANGE_EXT,
+       WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE,
+       WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME,
+       WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87,
+       WMI_VDEV_PARAM_PROTOTYPE = 0x8000,
+       WMI_VDEV_PARAM_BSS_COLOR,
+       WMI_VDEV_PARAM_SET_HEMU_MODE,
+       WMI_VDEV_PARAM_TX_OFDMA_CPLEN,
+};
+
+enum wmi_tlv_peer_flags {
+       WMI_TLV_PEER_AUTH = 0x00000001,
+       WMI_TLV_PEER_QOS = 0x00000002,
+       WMI_TLV_PEER_NEED_PTK_4_WAY = 0x00000004,
+       WMI_TLV_PEER_NEED_GTK_2_WAY = 0x00000010,
+       WMI_TLV_PEER_APSD = 0x00000800,
+       WMI_TLV_PEER_HT = 0x00001000,
+       WMI_TLV_PEER_40MHZ = 0x00002000,
+       WMI_TLV_PEER_STBC = 0x00008000,
+       WMI_TLV_PEER_LDPC = 0x00010000,
+       WMI_TLV_PEER_DYN_MIMOPS = 0x00020000,
+       WMI_TLV_PEER_STATIC_MIMOPS = 0x00040000,
+       WMI_TLV_PEER_SPATIAL_MUX = 0x00200000,
+       WMI_TLV_PEER_VHT = 0x02000000,
+       WMI_TLV_PEER_80MHZ = 0x04000000,
+       WMI_TLV_PEER_PMF = 0x08000000,
+       WMI_PEER_IS_P2P_CAPABLE = 0x20000000,
+       WMI_PEER_160MHZ         = 0x40000000,
+       WMI_PEER_SAFEMODE_EN    = 0x80000000,
+
+};
+
+/** Enum list of TLV Tags for each parameter structure type. */
+enum wmi_tlv_tag {
+       WMI_TAG_LAST_RESERVED = 15,
+       WMI_TAG_FIRST_ARRAY_ENUM,
+       WMI_TAG_ARRAY_UINT32 = WMI_TAG_FIRST_ARRAY_ENUM,
+       WMI_TAG_ARRAY_BYTE,
+       WMI_TAG_ARRAY_STRUCT,
+       WMI_TAG_ARRAY_FIXED_STRUCT,
+       WMI_TAG_LAST_ARRAY_ENUM = 31,
+       WMI_TAG_SERVICE_READY_EVENT,
+       WMI_TAG_HAL_REG_CAPABILITIES,
+       WMI_TAG_WLAN_HOST_MEM_REQ,
+       WMI_TAG_READY_EVENT,
+       WMI_TAG_SCAN_EVENT,
+       WMI_TAG_PDEV_TPC_CONFIG_EVENT,
+       WMI_TAG_CHAN_INFO_EVENT,
+       WMI_TAG_COMB_PHYERR_RX_HDR,
+       WMI_TAG_VDEV_START_RESPONSE_EVENT,
+       WMI_TAG_VDEV_STOPPED_EVENT,
+       WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT,
+       WMI_TAG_PEER_STA_KICKOUT_EVENT,
+       WMI_TAG_MGMT_RX_HDR,
+       WMI_TAG_TBTT_OFFSET_EVENT,
+       WMI_TAG_TX_DELBA_COMPLETE_EVENT,
+       WMI_TAG_TX_ADDBA_COMPLETE_EVENT,
+       WMI_TAG_ROAM_EVENT,
+       WMI_TAG_WOW_EVENT_INFO,
+       WMI_TAG_WOW_EVENT_INFO_SECTION_BITMAP,
+       WMI_TAG_RTT_EVENT_HEADER,
+       WMI_TAG_RTT_ERROR_REPORT_EVENT,
+       WMI_TAG_RTT_MEAS_EVENT,
+       WMI_TAG_ECHO_EVENT,
+       WMI_TAG_FTM_INTG_EVENT,
+       WMI_TAG_VDEV_GET_KEEPALIVE_EVENT,
+       WMI_TAG_GPIO_INPUT_EVENT,
+       WMI_TAG_CSA_EVENT,
+       WMI_TAG_GTK_OFFLOAD_STATUS_EVENT,
+       WMI_TAG_IGTK_INFO,
+       WMI_TAG_DCS_INTERFERENCE_EVENT,
+       WMI_TAG_ATH_DCS_CW_INT,
+       WMI_TAG_WLAN_DCS_CW_INT = /* ALIAS */
+               WMI_TAG_ATH_DCS_CW_INT,
+       WMI_TAG_ATH_DCS_WLAN_INT_STAT,
+       WMI_TAG_WLAN_DCS_IM_TGT_STATS_T = /* ALIAS */
+               WMI_TAG_ATH_DCS_WLAN_INT_STAT,
+       WMI_TAG_WLAN_PROFILE_CTX_T,
+       WMI_TAG_WLAN_PROFILE_T,
+       WMI_TAG_PDEV_QVIT_EVENT,
+       WMI_TAG_HOST_SWBA_EVENT,
+       WMI_TAG_TIM_INFO,
+       WMI_TAG_P2P_NOA_INFO,
+       WMI_TAG_STATS_EVENT,
+       WMI_TAG_AVOID_FREQ_RANGES_EVENT,
+       WMI_TAG_AVOID_FREQ_RANGE_DESC,
+       WMI_TAG_GTK_REKEY_FAIL_EVENT,
+       WMI_TAG_INIT_CMD,
+       WMI_TAG_RESOURCE_CONFIG,
+       WMI_TAG_WLAN_HOST_MEMORY_CHUNK,
+       WMI_TAG_START_SCAN_CMD,
+       WMI_TAG_STOP_SCAN_CMD,
+       WMI_TAG_SCAN_CHAN_LIST_CMD,
+       WMI_TAG_CHANNEL,
+       WMI_TAG_PDEV_SET_REGDOMAIN_CMD,
+       WMI_TAG_PDEV_SET_PARAM_CMD,
+       WMI_TAG_PDEV_SET_WMM_PARAMS_CMD,
+       WMI_TAG_WMM_PARAMS,
+       WMI_TAG_PDEV_SET_QUIET_CMD,
+       WMI_TAG_VDEV_CREATE_CMD,
+       WMI_TAG_VDEV_DELETE_CMD,
+       WMI_TAG_VDEV_START_REQUEST_CMD,
+       WMI_TAG_P2P_NOA_DESCRIPTOR,
+       WMI_TAG_P2P_GO_SET_BEACON_IE,
+       WMI_TAG_GTK_OFFLOAD_CMD,
+       WMI_TAG_VDEV_UP_CMD,
+       WMI_TAG_VDEV_STOP_CMD,
+       WMI_TAG_VDEV_DOWN_CMD,
+       WMI_TAG_VDEV_SET_PARAM_CMD,
+       WMI_TAG_VDEV_INSTALL_KEY_CMD,
+       WMI_TAG_PEER_CREATE_CMD,
+       WMI_TAG_PEER_DELETE_CMD,
+       WMI_TAG_PEER_FLUSH_TIDS_CMD,
+       WMI_TAG_PEER_SET_PARAM_CMD,
+       WMI_TAG_PEER_ASSOC_COMPLETE_CMD,
+       WMI_TAG_VHT_RATE_SET,
+       WMI_TAG_BCN_TMPL_CMD,
+       WMI_TAG_PRB_TMPL_CMD,
+       WMI_TAG_BCN_PRB_INFO,
+       WMI_TAG_PEER_TID_ADDBA_CMD,
+       WMI_TAG_PEER_TID_DELBA_CMD,
+       WMI_TAG_STA_POWERSAVE_MODE_CMD,
+       WMI_TAG_STA_POWERSAVE_PARAM_CMD,
+       WMI_TAG_STA_DTIM_PS_METHOD_CMD,
+       WMI_TAG_ROAM_SCAN_MODE,
+       WMI_TAG_ROAM_SCAN_RSSI_THRESHOLD,
+       WMI_TAG_ROAM_SCAN_PERIOD,
+       WMI_TAG_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+       WMI_TAG_PDEV_SUSPEND_CMD,
+       WMI_TAG_PDEV_RESUME_CMD,
+       WMI_TAG_ADD_BCN_FILTER_CMD,
+       WMI_TAG_RMV_BCN_FILTER_CMD,
+       WMI_TAG_WOW_ENABLE_CMD,
+       WMI_TAG_WOW_HOSTWAKEUP_FROM_SLEEP_CMD,
+       WMI_TAG_STA_UAPSD_AUTO_TRIG_CMD,
+       WMI_TAG_STA_UAPSD_AUTO_TRIG_PARAM,
+       WMI_TAG_SET_ARP_NS_OFFLOAD_CMD,
+       WMI_TAG_ARP_OFFLOAD_TUPLE,
+       WMI_TAG_NS_OFFLOAD_TUPLE,
+       WMI_TAG_FTM_INTG_CMD,
+       WMI_TAG_STA_KEEPALIVE_CMD,
+       WMI_TAG_STA_KEEPALVE_ARP_RESPONSE,
+       WMI_TAG_P2P_SET_VENDOR_IE_DATA_CMD,
+       WMI_TAG_AP_PS_PEER_CMD,
+       WMI_TAG_PEER_RATE_RETRY_SCHED_CMD,
+       WMI_TAG_WLAN_PROFILE_TRIGGER_CMD,
+       WMI_TAG_WLAN_PROFILE_SET_HIST_INTVL_CMD,
+       WMI_TAG_WLAN_PROFILE_GET_PROF_DATA_CMD,
+       WMI_TAG_WLAN_PROFILE_ENABLE_PROFILE_ID_CMD,
+       WMI_TAG_WOW_DEL_PATTERN_CMD,
+       WMI_TAG_WOW_ADD_DEL_EVT_CMD,
+       WMI_TAG_RTT_MEASREQ_HEAD,
+       WMI_TAG_RTT_MEASREQ_BODY,
+       WMI_TAG_RTT_TSF_CMD,
+       WMI_TAG_VDEV_SPECTRAL_CONFIGURE_CMD,
+       WMI_TAG_VDEV_SPECTRAL_ENABLE_CMD,
+       WMI_TAG_REQUEST_STATS_CMD,
+       WMI_TAG_NLO_CONFIG_CMD,
+       WMI_TAG_NLO_CONFIGURED_PARAMETERS,
+       WMI_TAG_CSA_OFFLOAD_ENABLE_CMD,
+       WMI_TAG_CSA_OFFLOAD_CHANSWITCH_CMD,
+       WMI_TAG_CHATTER_SET_MODE_CMD,
+       WMI_TAG_ECHO_CMD,
+       WMI_TAG_VDEV_SET_KEEPALIVE_CMD,
+       WMI_TAG_VDEV_GET_KEEPALIVE_CMD,
+       WMI_TAG_FORCE_FW_HANG_CMD,
+       WMI_TAG_GPIO_CONFIG_CMD,
+       WMI_TAG_GPIO_OUTPUT_CMD,
+       WMI_TAG_PEER_ADD_WDS_ENTRY_CMD,
+       WMI_TAG_PEER_REMOVE_WDS_ENTRY_CMD,
+       WMI_TAG_BCN_TX_HDR,
+       WMI_TAG_BCN_SEND_FROM_HOST_CMD,
+       WMI_TAG_MGMT_TX_HDR,
+       WMI_TAG_ADDBA_CLEAR_RESP_CMD,
+       WMI_TAG_ADDBA_SEND_CMD,
+       WMI_TAG_DELBA_SEND_CMD,
+       WMI_TAG_ADDBA_SETRESPONSE_CMD,
+       WMI_TAG_SEND_SINGLEAMSDU_CMD,
+       WMI_TAG_PDEV_PKTLOG_ENABLE_CMD,
+       WMI_TAG_PDEV_PKTLOG_DISABLE_CMD,
+       WMI_TAG_PDEV_SET_HT_IE_CMD,
+       WMI_TAG_PDEV_SET_VHT_IE_CMD,
+       WMI_TAG_PDEV_SET_DSCP_TID_MAP_CMD,
+       WMI_TAG_PDEV_GREEN_AP_PS_ENABLE_CMD,
+       WMI_TAG_PDEV_GET_TPC_CONFIG_CMD,
+       WMI_TAG_PDEV_SET_BASE_MACADDR_CMD,
+       WMI_TAG_PEER_MCAST_GROUP_CMD,
+       WMI_TAG_ROAM_AP_PROFILE,
+       WMI_TAG_AP_PROFILE,
+       WMI_TAG_SCAN_SCH_PRIORITY_TABLE_CMD,
+       WMI_TAG_PDEV_DFS_ENABLE_CMD,
+       WMI_TAG_PDEV_DFS_DISABLE_CMD,
+       WMI_TAG_WOW_ADD_PATTERN_CMD,
+       WMI_TAG_WOW_BITMAP_PATTERN_T,
+       WMI_TAG_WOW_IPV4_SYNC_PATTERN_T,
+       WMI_TAG_WOW_IPV6_SYNC_PATTERN_T,
+       WMI_TAG_WOW_MAGIC_PATTERN_CMD,
+       WMI_TAG_SCAN_UPDATE_REQUEST_CMD,
+       WMI_TAG_CHATTER_PKT_COALESCING_FILTER,
+       WMI_TAG_CHATTER_COALESCING_ADD_FILTER_CMD,
+       WMI_TAG_CHATTER_COALESCING_DELETE_FILTER_CMD,
+       WMI_TAG_CHATTER_COALESCING_QUERY_CMD,
+       WMI_TAG_TXBF_CMD,
+       WMI_TAG_DEBUG_LOG_CONFIG_CMD,
+       WMI_TAG_NLO_EVENT,
+       WMI_TAG_CHATTER_QUERY_REPLY_EVENT,
+       WMI_TAG_UPLOAD_H_HDR,
+       WMI_TAG_CAPTURE_H_EVENT_HDR,
+       WMI_TAG_VDEV_WNM_SLEEPMODE_CMD,
+       WMI_TAG_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD,
+       WMI_TAG_VDEV_WMM_ADDTS_CMD,
+       WMI_TAG_VDEV_WMM_DELTS_CMD,
+       WMI_TAG_VDEV_SET_WMM_PARAMS_CMD,
+       WMI_TAG_TDLS_SET_STATE_CMD,
+       WMI_TAG_TDLS_PEER_UPDATE_CMD,
+       WMI_TAG_TDLS_PEER_EVENT,
+       WMI_TAG_TDLS_PEER_CAPABILITIES,
+       WMI_TAG_VDEV_MCC_SET_TBTT_MODE_CMD,
+       WMI_TAG_ROAM_CHAN_LIST,
+       WMI_TAG_VDEV_MCC_BCN_INTVL_CHANGE_EVENT,
+       WMI_TAG_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMD,
+       WMI_TAG_RESMGR_SET_CHAN_TIME_QUOTA_CMD,
+       WMI_TAG_RESMGR_SET_CHAN_LATENCY_CMD,
+       WMI_TAG_BA_REQ_SSN_CMD,
+       WMI_TAG_BA_RSP_SSN_EVENT,
+       WMI_TAG_STA_SMPS_FORCE_MODE_CMD,
+       WMI_TAG_SET_MCASTBCAST_FILTER_CMD,
+       WMI_TAG_P2P_SET_OPPPS_CMD,
+       WMI_TAG_P2P_SET_NOA_CMD,
+       WMI_TAG_BA_REQ_SSN_CMD_SUB_STRUCT_PARAM,
+       WMI_TAG_BA_REQ_SSN_EVENT_SUB_STRUCT_PARAM,
+       WMI_TAG_STA_SMPS_PARAM_CMD,
+       WMI_TAG_VDEV_SET_GTX_PARAMS_CMD,
+       WMI_TAG_MCC_SCHED_TRAFFIC_STATS_CMD,
+       WMI_TAG_MCC_SCHED_STA_TRAFFIC_STATS,
+       WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT,
+       WMI_TAG_P2P_NOA_EVENT,
+       WMI_TAG_HB_SET_ENABLE_CMD,
+       WMI_TAG_HB_SET_TCP_PARAMS_CMD,
+       WMI_TAG_HB_SET_TCP_PKT_FILTER_CMD,
+       WMI_TAG_HB_SET_UDP_PARAMS_CMD,
+       WMI_TAG_HB_SET_UDP_PKT_FILTER_CMD,
+       WMI_TAG_HB_IND_EVENT,
+       WMI_TAG_TX_PAUSE_EVENT,
+       WMI_TAG_RFKILL_EVENT,
+       WMI_TAG_DFS_RADAR_EVENT,
+       WMI_TAG_DFS_PHYERR_FILTER_ENA_CMD,
+       WMI_TAG_DFS_PHYERR_FILTER_DIS_CMD,
+       WMI_TAG_BATCH_SCAN_RESULT_SCAN_LIST,
+       WMI_TAG_BATCH_SCAN_RESULT_NETWORK_INFO,
+       WMI_TAG_BATCH_SCAN_ENABLE_CMD,
+       WMI_TAG_BATCH_SCAN_DISABLE_CMD,
+       WMI_TAG_BATCH_SCAN_TRIGGER_RESULT_CMD,
+       WMI_TAG_BATCH_SCAN_ENABLED_EVENT,
+       WMI_TAG_BATCH_SCAN_RESULT_EVENT,
+       WMI_TAG_VDEV_PLMREQ_START_CMD,
+       WMI_TAG_VDEV_PLMREQ_STOP_CMD,
+       WMI_TAG_THERMAL_MGMT_CMD,
+       WMI_TAG_THERMAL_MGMT_EVENT,
+       WMI_TAG_PEER_INFO_REQ_CMD,
+       WMI_TAG_PEER_INFO_EVENT,
+       WMI_TAG_PEER_INFO,
+       WMI_TAG_PEER_TX_FAIL_CNT_THR_EVENT,
+       WMI_TAG_RMC_SET_MODE_CMD,
+       WMI_TAG_RMC_SET_ACTION_PERIOD_CMD,
+       WMI_TAG_RMC_CONFIG_CMD,
+       WMI_TAG_MHF_OFFLOAD_SET_MODE_CMD,
+       WMI_TAG_MHF_OFFLOAD_PLUMB_ROUTING_TABLE_CMD,
+       WMI_TAG_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD,
+       WMI_TAG_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD,
+       WMI_TAG_NAN_CMD_PARAM,
+       WMI_TAG_NAN_EVENT_HDR,
+       WMI_TAG_PDEV_L1SS_TRACK_EVENT,
+       WMI_TAG_DIAG_DATA_CONTAINER_EVENT,
+       WMI_TAG_MODEM_POWER_STATE_CMD_PARAM,
+       WMI_TAG_PEER_GET_ESTIMATED_LINKSPEED_CMD,
+       WMI_TAG_PEER_ESTIMATED_LINKSPEED_EVENT,
+       WMI_TAG_AGGR_STATE_TRIG_EVENT,
+       WMI_TAG_MHF_OFFLOAD_ROUTING_TABLE_ENTRY,
+       WMI_TAG_ROAM_SCAN_CMD,
+       WMI_TAG_REQ_STATS_EXT_CMD,
+       WMI_TAG_STATS_EXT_EVENT,
+       WMI_TAG_OBSS_SCAN_ENABLE_CMD,
+       WMI_TAG_OBSS_SCAN_DISABLE_CMD,
+       WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT,
+       WMI_TAG_PDEV_SET_LED_CONFIG_CMD,
+       WMI_TAG_HOST_AUTO_SHUTDOWN_CFG_CMD,
+       WMI_TAG_HOST_AUTO_SHUTDOWN_EVENT,
+       WMI_TAG_UPDATE_WHAL_MIB_STATS_EVENT,
+       WMI_TAG_CHAN_AVOID_UPDATE_CMD_PARAM,
+       WMI_TAG_WOW_IOAC_PKT_PATTERN_T,
+       WMI_TAG_WOW_IOAC_TMR_PATTERN_T,
+       WMI_TAG_WOW_IOAC_ADD_KEEPALIVE_CMD,
+       WMI_TAG_WOW_IOAC_DEL_KEEPALIVE_CMD,
+       WMI_TAG_WOW_IOAC_KEEPALIVE_T,
+       WMI_TAG_WOW_IOAC_ADD_PATTERN_CMD,
+       WMI_TAG_WOW_IOAC_DEL_PATTERN_CMD,
+       WMI_TAG_START_LINK_STATS_CMD,
+       WMI_TAG_CLEAR_LINK_STATS_CMD,
+       WMI_TAG_REQUEST_LINK_STATS_CMD,
+       WMI_TAG_IFACE_LINK_STATS_EVENT,
+       WMI_TAG_RADIO_LINK_STATS_EVENT,
+       WMI_TAG_PEER_STATS_EVENT,
+       WMI_TAG_CHANNEL_STATS,
+       WMI_TAG_RADIO_LINK_STATS,
+       WMI_TAG_RATE_STATS,
+       WMI_TAG_PEER_LINK_STATS,
+       WMI_TAG_WMM_AC_STATS,
+       WMI_TAG_IFACE_LINK_STATS,
+       WMI_TAG_LPI_MGMT_SNOOPING_CONFIG_CMD,
+       WMI_TAG_LPI_START_SCAN_CMD,
+       WMI_TAG_LPI_STOP_SCAN_CMD,
+       WMI_TAG_LPI_RESULT_EVENT,
+       WMI_TAG_PEER_STATE_EVENT,
+       WMI_TAG_EXTSCAN_BUCKET_CMD,
+       WMI_TAG_EXTSCAN_BUCKET_CHANNEL_EVENT,
+       WMI_TAG_EXTSCAN_START_CMD,
+       WMI_TAG_EXTSCAN_STOP_CMD,
+       WMI_TAG_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMD,
+       WMI_TAG_EXTSCAN_WLAN_CHANGE_BSSID_PARAM_CMD,
+       WMI_TAG_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMD,
+       WMI_TAG_EXTSCAN_GET_CACHED_RESULTS_CMD,
+       WMI_TAG_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMD,
+       WMI_TAG_EXTSCAN_SET_CAPABILITIES_CMD,
+       WMI_TAG_EXTSCAN_GET_CAPABILITIES_CMD,
+       WMI_TAG_EXTSCAN_OPERATION_EVENT,
+       WMI_TAG_EXTSCAN_START_STOP_EVENT,
+       WMI_TAG_EXTSCAN_TABLE_USAGE_EVENT,
+       WMI_TAG_EXTSCAN_WLAN_DESCRIPTOR_EVENT,
+       WMI_TAG_EXTSCAN_RSSI_INFO_EVENT,
+       WMI_TAG_EXTSCAN_CACHED_RESULTS_EVENT,
+       WMI_TAG_EXTSCAN_WLAN_CHANGE_RESULTS_EVENT,
+       WMI_TAG_EXTSCAN_WLAN_CHANGE_RESULT_BSSID_EVENT,
+       WMI_TAG_EXTSCAN_HOTLIST_MATCH_EVENT,
+       WMI_TAG_EXTSCAN_CAPABILITIES_EVENT,
+       WMI_TAG_EXTSCAN_CACHE_CAPABILITIES_EVENT,
+       WMI_TAG_EXTSCAN_WLAN_CHANGE_MONITOR_CAPABILITIES_EVENT,
+       WMI_TAG_EXTSCAN_HOTLIST_MONITOR_CAPABILITIES_EVENT,
+       WMI_TAG_D0_WOW_ENABLE_DISABLE_CMD,
+       WMI_TAG_D0_WOW_DISABLE_ACK_EVENT,
+       WMI_TAG_UNIT_TEST_CMD,
+       WMI_TAG_ROAM_OFFLOAD_TLV_PARAM,
+       WMI_TAG_ROAM_11I_OFFLOAD_TLV_PARAM,
+       WMI_TAG_ROAM_11R_OFFLOAD_TLV_PARAM,
+       WMI_TAG_ROAM_ESE_OFFLOAD_TLV_PARAM,
+       WMI_TAG_ROAM_SYNCH_EVENT,
+       WMI_TAG_ROAM_SYNCH_COMPLETE,
+       WMI_TAG_EXTWOW_ENABLE_CMD,
+       WMI_TAG_EXTWOW_SET_APP_TYPE1_PARAMS_CMD,
+       WMI_TAG_EXTWOW_SET_APP_TYPE2_PARAMS_CMD,
+       WMI_TAG_LPI_STATUS_EVENT,
+       WMI_TAG_LPI_HANDOFF_EVENT,
+       WMI_TAG_VDEV_RATE_STATS_EVENT,
+       WMI_TAG_VDEV_RATE_HT_INFO,
+       WMI_TAG_RIC_REQUEST,
+       WMI_TAG_PDEV_GET_TEMPERATURE_CMD,
+       WMI_TAG_PDEV_TEMPERATURE_EVENT,
+       WMI_TAG_SET_DHCP_SERVER_OFFLOAD_CMD,
+       WMI_TAG_TPC_CHAINMASK_CONFIG_CMD,
+       WMI_TAG_RIC_TSPEC,
+       WMI_TAG_TPC_CHAINMASK_CONFIG,
+       WMI_TAG_IPA_OFFLOAD_ENABLE_DISABLE_CMD,
+       WMI_TAG_SCAN_PROB_REQ_OUI_CMD,
+       WMI_TAG_KEY_MATERIAL,
+       WMI_TAG_TDLS_SET_OFFCHAN_MODE_CMD,
+       WMI_TAG_SET_LED_FLASHING_CMD,
+       WMI_TAG_MDNS_OFFLOAD_CMD,
+       WMI_TAG_MDNS_SET_FQDN_CMD,
+       WMI_TAG_MDNS_SET_RESP_CMD,
+       WMI_TAG_MDNS_GET_STATS_CMD,
+       WMI_TAG_MDNS_STATS_EVENT,
+       WMI_TAG_ROAM_INVOKE_CMD,
+       WMI_TAG_PDEV_RESUME_EVENT,
+       WMI_TAG_PDEV_SET_ANTENNA_DIVERSITY_CMD,
+       WMI_TAG_SAP_OFL_ENABLE_CMD,
+       WMI_TAG_SAP_OFL_ADD_STA_EVENT,
+       WMI_TAG_SAP_OFL_DEL_STA_EVENT,
+       WMI_TAG_APFIND_CMD_PARAM,
+       WMI_TAG_APFIND_EVENT_HDR,
+       WMI_TAG_OCB_SET_SCHED_CMD,
+       WMI_TAG_OCB_SET_SCHED_EVENT,
+       WMI_TAG_OCB_SET_CONFIG_CMD,
+       WMI_TAG_OCB_SET_CONFIG_RESP_EVENT,
+       WMI_TAG_OCB_SET_UTC_TIME_CMD,
+       WMI_TAG_OCB_START_TIMING_ADVERT_CMD,
+       WMI_TAG_OCB_STOP_TIMING_ADVERT_CMD,
+       WMI_TAG_OCB_GET_TSF_TIMER_CMD,
+       WMI_TAG_OCB_GET_TSF_TIMER_RESP_EVENT,
+       WMI_TAG_DCC_GET_STATS_CMD,
+       WMI_TAG_DCC_CHANNEL_STATS_REQUEST,
+       WMI_TAG_DCC_GET_STATS_RESP_EVENT,
+       WMI_TAG_DCC_CLEAR_STATS_CMD,
+       WMI_TAG_DCC_UPDATE_NDL_CMD,
+       WMI_TAG_DCC_UPDATE_NDL_RESP_EVENT,
+       WMI_TAG_DCC_STATS_EVENT,
+       WMI_TAG_OCB_CHANNEL,
+       WMI_TAG_OCB_SCHEDULE_ELEMENT,
+       WMI_TAG_DCC_NDL_STATS_PER_CHANNEL,
+       WMI_TAG_DCC_NDL_CHAN,
+       WMI_TAG_QOS_PARAMETER,
+       WMI_TAG_DCC_NDL_ACTIVE_STATE_CONFIG,
+       WMI_TAG_ROAM_SCAN_EXTENDED_THRESHOLD_PARAM,
+       WMI_TAG_ROAM_FILTER,
+       WMI_TAG_PASSPOINT_CONFIG_CMD,
+       WMI_TAG_PASSPOINT_EVENT_HDR,
+       WMI_TAG_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMD,
+       WMI_TAG_EXTSCAN_HOTLIST_SSID_MATCH_EVENT,
+       WMI_TAG_VDEV_TSF_TSTAMP_ACTION_CMD,
+       WMI_TAG_VDEV_TSF_REPORT_EVENT,
+       WMI_TAG_GET_FW_MEM_DUMP,
+       WMI_TAG_UPDATE_FW_MEM_DUMP,
+       WMI_TAG_FW_MEM_DUMP_PARAMS,
+       WMI_TAG_DEBUG_MESG_FLUSH,
+       WMI_TAG_DEBUG_MESG_FLUSH_COMPLETE,
+       WMI_TAG_PEER_SET_RATE_REPORT_CONDITION,
+       WMI_TAG_ROAM_SUBNET_CHANGE_CONFIG,
+       WMI_TAG_VDEV_SET_IE_CMD,
+       WMI_TAG_RSSI_BREACH_MONITOR_CONFIG,
+       WMI_TAG_RSSI_BREACH_EVENT,
+       WMI_TAG_WOW_EVENT_INITIAL_WAKEUP,
+       WMI_TAG_SOC_SET_PCL_CMD,
+       WMI_TAG_SOC_SET_HW_MODE_CMD,
+       WMI_TAG_SOC_SET_HW_MODE_RESPONSE_EVENT,
+       WMI_TAG_SOC_HW_MODE_TRANSITION_EVENT,
+       WMI_TAG_VDEV_TXRX_STREAMS,
+       WMI_TAG_SOC_SET_HW_MODE_RESPONSE_VDEV_MAC_ENTRY,
+       WMI_TAG_SOC_SET_DUAL_MAC_CONFIG_CMD,
+       WMI_TAG_SOC_SET_DUAL_MAC_CONFIG_RESPONSE_EVENT,
+       WMI_TAG_WOW_IOAC_SOCK_PATTERN_T,
+       WMI_TAG_WOW_ENABLE_ICMPV6_NA_FLT_CMD,
+       WMI_TAG_DIAG_EVENT_LOG_CONFIG,
+       WMI_TAG_DIAG_EVENT_LOG_SUPPORTED_EVENT_FIXED_PARAMS,
+       WMI_TAG_PACKET_FILTER_CONFIG,
+       WMI_TAG_PACKET_FILTER_ENABLE,
+       WMI_TAG_SAP_SET_BLACKLIST_PARAM_CMD,
+       WMI_TAG_MGMT_TX_SEND_CMD,
+       WMI_TAG_MGMT_TX_COMPL_EVENT,
+       WMI_TAG_SOC_SET_ANTENNA_MODE_CMD,
+       WMI_TAG_WOW_UDP_SVC_OFLD_CMD,
+       WMI_TAG_LRO_INFO_CMD,
+       WMI_TAG_ROAM_EARLYSTOP_RSSI_THRES_PARAM,
+       WMI_TAG_SERVICE_READY_EXT_EVENT,
+       WMI_TAG_MAWC_SENSOR_REPORT_IND_CMD,
+       WMI_TAG_MAWC_ENABLE_SENSOR_EVENT,
+       WMI_TAG_ROAM_CONFIGURE_MAWC_CMD,
+       WMI_TAG_NLO_CONFIGURE_MAWC_CMD,
+       WMI_TAG_EXTSCAN_CONFIGURE_MAWC_CMD,
+       WMI_TAG_PEER_ASSOC_CONF_EVENT,
+       WMI_TAG_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMD,
+       WMI_TAG_AP_PS_EGAP_PARAM_CMD,
+       WMI_TAG_AP_PS_EGAP_INFO_EVENT,
+       WMI_TAG_PMF_OFFLOAD_SET_SA_QUERY_CMD,
+       WMI_TAG_TRANSFER_DATA_TO_FLASH_CMD,
+       WMI_TAG_TRANSFER_DATA_TO_FLASH_COMPLETE_EVENT,
+       WMI_TAG_SCPC_EVENT,
+       WMI_TAG_AP_PS_EGAP_INFO_CHAINMASK_LIST,
+       WMI_TAG_STA_SMPS_FORCE_MODE_COMPLETE_EVENT,
+       WMI_TAG_BPF_GET_CAPABILITY_CMD,
+       WMI_TAG_BPF_CAPABILITY_INFO_EVT,
+       WMI_TAG_BPF_GET_VDEV_STATS_CMD,
+       WMI_TAG_BPF_VDEV_STATS_INFO_EVT,
+       WMI_TAG_BPF_SET_VDEV_INSTRUCTIONS_CMD,
+       WMI_TAG_BPF_DEL_VDEV_INSTRUCTIONS_CMD,
+       WMI_TAG_VDEV_DELETE_RESP_EVENT,
+       WMI_TAG_PEER_DELETE_RESP_EVENT,
+       WMI_TAG_ROAM_DENSE_THRES_PARAM,
+       WMI_TAG_ENLO_CANDIDATE_SCORE_PARAM,
+       WMI_TAG_PEER_UPDATE_WDS_ENTRY_CMD,
+       WMI_TAG_VDEV_CONFIG_RATEMASK,
+       WMI_TAG_PDEV_FIPS_CMD,
+       WMI_TAG_PDEV_SMART_ANT_ENABLE_CMD,
+       WMI_TAG_PDEV_SMART_ANT_SET_RX_ANTENNA_CMD,
+       WMI_TAG_PEER_SMART_ANT_SET_TX_ANTENNA_CMD,
+       WMI_TAG_PEER_SMART_ANT_SET_TRAIN_ANTENNA_CMD,
+       WMI_TAG_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMD,
+       WMI_TAG_PDEV_SET_ANT_SWITCH_TBL_CMD,
+       WMI_TAG_PDEV_SET_CTL_TABLE_CMD,
+       WMI_TAG_PDEV_SET_MIMOGAIN_TABLE_CMD,
+       WMI_TAG_FWTEST_SET_PARAM_CMD,
+       WMI_TAG_PEER_ATF_REQUEST,
+       WMI_TAG_VDEV_ATF_REQUEST,
+       WMI_TAG_PDEV_GET_ANI_CCK_CONFIG_CMD,
+       WMI_TAG_PDEV_GET_ANI_OFDM_CONFIG_CMD,
+       WMI_TAG_INST_RSSI_STATS_RESP,
+       WMI_TAG_MED_UTIL_REPORT_EVENT,
+       WMI_TAG_PEER_STA_PS_STATECHANGE_EVENT,
+       WMI_TAG_WDS_ADDR_EVENT,
+       WMI_TAG_PEER_RATECODE_LIST_EVENT,
+       WMI_TAG_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENT,
+       WMI_TAG_PDEV_TPC_EVENT,
+       WMI_TAG_ANI_OFDM_EVENT,
+       WMI_TAG_ANI_CCK_EVENT,
+       WMI_TAG_PDEV_CHANNEL_HOPPING_EVENT,
+       WMI_TAG_PDEV_FIPS_EVENT,
+       WMI_TAG_ATF_PEER_INFO,
+       WMI_TAG_PDEV_GET_TPC_CMD,
+       WMI_TAG_VDEV_FILTER_NRP_CONFIG_CMD,
+       WMI_TAG_QBOOST_CFG_CMD,
+       WMI_TAG_PDEV_SMART_ANT_GPIO_HANDLE,
+       WMI_TAG_PEER_SMART_ANT_SET_TX_ANTENNA_SERIES,
+       WMI_TAG_PEER_SMART_ANT_SET_TRAIN_ANTENNA_PARAM,
+       WMI_TAG_PDEV_SET_ANT_CTRL_CHAIN,
+       WMI_TAG_PEER_CCK_OFDM_RATE_INFO,
+       WMI_TAG_PEER_MCS_RATE_INFO,
+       WMI_TAG_PDEV_NFCAL_POWER_ALL_CHANNELS_NFDBR,
+       WMI_TAG_PDEV_NFCAL_POWER_ALL_CHANNELS_NFDBM,
+       WMI_TAG_PDEV_NFCAL_POWER_ALL_CHANNELS_FREQNUM,
+       WMI_TAG_MU_REPORT_TOTAL_MU,
+       WMI_TAG_VDEV_SET_DSCP_TID_MAP_CMD,
+       WMI_TAG_ROAM_SET_MBO,
+       WMI_TAG_MIB_STATS_ENABLE_CMD,
+       WMI_TAG_NAN_DISC_IFACE_CREATED_EVENT,
+       WMI_TAG_NAN_DISC_IFACE_DELETED_EVENT,
+       WMI_TAG_NAN_STARTED_CLUSTER_EVENT,
+       WMI_TAG_NAN_JOINED_CLUSTER_EVENT,
+       WMI_TAG_NDI_GET_CAP_REQ,
+       WMI_TAG_NDP_INITIATOR_REQ,
+       WMI_TAG_NDP_RESPONDER_REQ,
+       WMI_TAG_NDP_END_REQ,
+       WMI_TAG_NDI_CAP_RSP_EVENT,
+       WMI_TAG_NDP_INITIATOR_RSP_EVENT,
+       WMI_TAG_NDP_RESPONDER_RSP_EVENT,
+       WMI_TAG_NDP_END_RSP_EVENT,
+       WMI_TAG_NDP_INDICATION_EVENT,
+       WMI_TAG_NDP_CONFIRM_EVENT,
+       WMI_TAG_NDP_END_INDICATION_EVENT,
+       WMI_TAG_VDEV_SET_QUIET_CMD,
+       WMI_TAG_PDEV_SET_PCL_CMD,
+       WMI_TAG_PDEV_SET_HW_MODE_CMD,
+       WMI_TAG_PDEV_SET_MAC_CONFIG_CMD,
+       WMI_TAG_PDEV_SET_ANTENNA_MODE_CMD,
+       WMI_TAG_PDEV_SET_HW_MODE_RESPONSE_EVENT,
+       WMI_TAG_PDEV_HW_MODE_TRANSITION_EVENT,
+       WMI_TAG_PDEV_SET_HW_MODE_RESPONSE_VDEV_MAC_ENTRY,
+       WMI_TAG_PDEV_SET_MAC_CONFIG_RESPONSE_EVENT,
+       WMI_TAG_COEX_CONFIG_CMD,
+       WMI_TAG_CONFIG_ENHANCED_MCAST_FILTER,
+       WMI_TAG_CHAN_AVOID_RPT_ALLOW_CMD,
+       WMI_TAG_SET_PERIODIC_CHANNEL_STATS_CONFIG,
+       WMI_TAG_VDEV_SET_CUSTOM_AGGR_SIZE_CMD,
+       WMI_TAG_PDEV_WAL_POWER_DEBUG_CMD,
+       WMI_TAG_MAC_PHY_CAPABILITIES,
+       WMI_TAG_HW_MODE_CAPABILITIES,
+       WMI_TAG_SOC_MAC_PHY_HW_MODE_CAPS,
+       WMI_TAG_HAL_REG_CAPABILITIES_EXT,
+       WMI_TAG_SOC_HAL_REG_CAPABILITIES,
+       WMI_TAG_VDEV_WISA_CMD,
+       WMI_TAG_TX_POWER_LEVEL_STATS_EVT,
+       WMI_TAG_SCAN_ADAPTIVE_DWELL_PARAMETERS_TLV,
+       WMI_TAG_SCAN_ADAPTIVE_DWELL_CONFIG,
+       WMI_TAG_WOW_SET_ACTION_WAKE_UP_CMD,
+       WMI_TAG_NDP_END_RSP_PER_NDI,
+       WMI_TAG_PEER_BWF_REQUEST,
+       WMI_TAG_BWF_PEER_INFO,
+       WMI_TAG_DBGLOG_TIME_STAMP_SYNC_CMD,
+       WMI_TAG_RMC_SET_LEADER_CMD,
+       WMI_TAG_RMC_MANUAL_LEADER_EVENT,
+       WMI_TAG_PER_CHAIN_RSSI_STATS,
+       WMI_TAG_RSSI_STATS,
+       WMI_TAG_P2P_LO_START_CMD,
+       WMI_TAG_P2P_LO_STOP_CMD,
+       WMI_TAG_P2P_LO_STOPPED_EVENT,
+       WMI_TAG_REORDER_QUEUE_SETUP_CMD,
+       WMI_TAG_REORDER_QUEUE_REMOVE_CMD,
+       WMI_TAG_SET_MULTIPLE_MCAST_FILTER_CMD,
+       WMI_TAG_MGMT_TX_COMPL_BUNDLE_EVENT,
+       WMI_TAG_READ_DATA_FROM_FLASH_CMD,
+       WMI_TAG_READ_DATA_FROM_FLASH_EVENT,
+       WMI_TAG_PDEV_SET_REORDER_TIMEOUT_VAL_CMD,
+       WMI_TAG_PEER_SET_RX_BLOCKSIZE_CMD,
+       WMI_TAG_PDEV_SET_WAKEUP_CONFIG_CMDID,
+       WMI_TAG_TLV_BUF_LEN_PARAM,
+       WMI_TAG_SERVICE_AVAILABLE_EVENT,
+       WMI_TAG_PEER_ANTDIV_INFO_REQ_CMD,
+       WMI_TAG_PEER_ANTDIV_INFO_EVENT,
+       WMI_TAG_PEER_ANTDIV_INFO,
+       WMI_TAG_PDEV_GET_ANTDIV_STATUS_CMD,
+       WMI_TAG_PDEV_ANTDIV_STATUS_EVENT,
+       WMI_TAG_MNT_FILTER_CMD,
+       WMI_TAG_GET_CHIP_POWER_STATS_CMD,
+       WMI_TAG_PDEV_CHIP_POWER_STATS_EVENT,
+       WMI_TAG_COEX_GET_ANTENNA_ISOLATION_CMD,
+       WMI_TAG_COEX_REPORT_ISOLATION_EVENT,
+       WMI_TAG_CHAN_CCA_STATS,
+       WMI_TAG_PEER_SIGNAL_STATS,
+       WMI_TAG_TX_STATS,
+       WMI_TAG_PEER_AC_TX_STATS,
+       WMI_TAG_RX_STATS,
+       WMI_TAG_PEER_AC_RX_STATS,
+       WMI_TAG_REPORT_STATS_EVENT,
+       WMI_TAG_CHAN_CCA_STATS_THRESH,
+       WMI_TAG_PEER_SIGNAL_STATS_THRESH,
+       WMI_TAG_TX_STATS_THRESH,
+       WMI_TAG_RX_STATS_THRESH,
+       WMI_TAG_PDEV_SET_STATS_THRESHOLD_CMD,
+       WMI_TAG_REQUEST_WLAN_STATS_CMD,
+       WMI_TAG_RX_AGGR_FAILURE_EVENT,
+       WMI_TAG_RX_AGGR_FAILURE_INFO,
+       WMI_TAG_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMD,
+       WMI_TAG_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENT,
+       WMI_TAG_PDEV_BAND_TO_MAC,
+       WMI_TAG_TBTT_OFFSET_INFO,
+       WMI_TAG_TBTT_OFFSET_EXT_EVENT,
+       WMI_TAG_SAR_LIMITS_CMD,
+       WMI_TAG_SAR_LIMIT_CMD_ROW,
+       WMI_TAG_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMD,
+       WMI_TAG_PDEV_DFS_PHYERR_OFFLOAD_DISABLE_CMD,
+       WMI_TAG_VDEV_ADFS_CH_CFG_CMD,
+       WMI_TAG_VDEV_ADFS_OCAC_ABORT_CMD,
+       WMI_TAG_PDEV_DFS_RADAR_DETECTION_EVENT,
+       WMI_TAG_VDEV_ADFS_OCAC_COMPLETE_EVENT,
+       WMI_TAG_VDEV_DFS_CAC_COMPLETE_EVENT,
+       WMI_TAG_VENDOR_OUI,
+       WMI_TAG_REQUEST_RCPI_CMD,
+       WMI_TAG_UPDATE_RCPI_EVENT,
+       WMI_TAG_REQUEST_PEER_STATS_INFO_CMD,
+       WMI_TAG_PEER_STATS_INFO,
+       WMI_TAG_PEER_STATS_INFO_EVENT,
+       WMI_TAG_PKGID_EVENT,
+       WMI_TAG_CONNECTED_NLO_RSSI_PARAMS,
+       WMI_TAG_SET_CURRENT_COUNTRY_CMD,
+       WMI_TAG_REGULATORY_RULE_STRUCT,
+       WMI_TAG_REG_CHAN_LIST_CC_EVENT,
+       WMI_TAG_11D_SCAN_START_CMD,
+       WMI_TAG_11D_SCAN_STOP_CMD,
+       WMI_TAG_11D_NEW_COUNTRY_EVENT,
+       WMI_TAG_REQUEST_RADIO_CHAN_STATS_CMD,
+       WMI_TAG_RADIO_CHAN_STATS,
+       WMI_TAG_RADIO_CHAN_STATS_EVENT,
+       WMI_TAG_ROAM_PER_CONFIG,
+       WMI_TAG_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMD,
+       WMI_TAG_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENT,
+       WMI_TAG_BPF_SET_VDEV_ACTIVE_MODE_CMD,
+       WMI_TAG_HW_DATA_FILTER_CMD,
+       WMI_TAG_CONNECTED_NLO_BSS_BAND_RSSI_PREF,
+       WMI_TAG_PEER_OPER_MODE_CHANGE_EVENT,
+       WMI_TAG_CHIP_POWER_SAVE_FAILURE_DETECTED,
+       WMI_TAG_PDEV_MULTIPLE_VDEV_RESTART_REQUEST_CMD,
+       WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT,
+       WMI_TAG_PDEV_UPDATE_PKT_ROUTING_CMD,
+       WMI_TAG_PDEV_CHECK_CAL_VERSION_CMD,
+       WMI_TAG_PDEV_CHECK_CAL_VERSION_EVENT,
+       WMI_TAG_PDEV_SET_DIVERSITY_GAIN_CMD,
+       WMI_TAG_MAC_PHY_CHAINMASK_COMBO,
+       WMI_TAG_MAC_PHY_CHAINMASK_CAPABILITY,
+       WMI_TAG_VDEV_SET_ARP_STATS_CMD,
+       WMI_TAG_VDEV_GET_ARP_STATS_CMD,
+       WMI_TAG_VDEV_GET_ARP_STATS_EVENT,
+       WMI_TAG_IFACE_OFFLOAD_STATS,
+       WMI_TAG_REQUEST_STATS_CMD_SUB_STRUCT_PARAM,
+       WMI_TAG_RSSI_CTL_EXT,
+       WMI_TAG_SINGLE_PHYERR_EXT_RX_HDR,
+       WMI_TAG_COEX_BT_ACTIVITY_EVENT,
+       WMI_TAG_VDEV_GET_TX_POWER_CMD,
+       WMI_TAG_VDEV_TX_POWER_EVENT,
+       WMI_TAG_OFFCHAN_DATA_TX_COMPL_EVENT,
+       WMI_TAG_OFFCHAN_DATA_TX_SEND_CMD,
+       WMI_TAG_TX_SEND_PARAMS,
+       WMI_TAG_HE_RATE_SET,
+       WMI_TAG_CONGESTION_STATS,
+       WMI_TAG_SET_INIT_COUNTRY_CMD,
+       WMI_TAG_SCAN_DBS_DUTY_CYCLE,
+       WMI_TAG_SCAN_DBS_DUTY_CYCLE_PARAM_TLV,
+       WMI_TAG_PDEV_DIV_GET_RSSI_ANTID,
+       WMI_TAG_THERM_THROT_CONFIG_REQUEST,
+       WMI_TAG_THERM_THROT_LEVEL_CONFIG_INFO,
+       WMI_TAG_THERM_THROT_STATS_EVENT,
+       WMI_TAG_THERM_THROT_LEVEL_STATS_INFO,
+       WMI_TAG_PDEV_DIV_RSSI_ANTID_EVENT,
+       WMI_TAG_OEM_DMA_RING_CAPABILITIES,
+       WMI_TAG_OEM_DMA_RING_CFG_REQ,
+       WMI_TAG_OEM_DMA_RING_CFG_RSP,
+       WMI_TAG_OEM_INDIRECT_DATA,
+       WMI_TAG_OEM_DMA_BUF_RELEASE,
+       WMI_TAG_OEM_DMA_BUF_RELEASE_ENTRY,
+       WMI_TAG_PDEV_BSS_CHAN_INFO_REQUEST,
+       WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT,
+       WMI_TAG_ROAM_LCA_DISALLOW_CONFIG,
+       WMI_TAG_VDEV_LIMIT_OFFCHAN_CMD,
+       WMI_TAG_ROAM_RSSI_REJECTION_OCE_CONFIG,
+       WMI_TAG_UNIT_TEST_EVENT,
+       WMI_TAG_ROAM_FILS_OFFLOAD,
+       WMI_TAG_PDEV_UPDATE_PMK_CACHE_CMD,
+       WMI_TAG_PMK_CACHE,
+       WMI_TAG_PDEV_UPDATE_FILS_HLP_PKT_CMD,
+       WMI_TAG_ROAM_FILS_SYNCH,
+       WMI_TAG_GTK_OFFLOAD_EXTENDED,
+       WMI_TAG_ROAM_BG_SCAN_ROAMING,
+       WMI_TAG_OIC_PING_OFFLOAD_PARAMS_CMD,
+       WMI_TAG_OIC_PING_OFFLOAD_SET_ENABLE_CMD,
+       WMI_TAG_OIC_PING_HANDOFF_EVENT,
+       WMI_TAG_DHCP_LEASE_RENEW_OFFLOAD_CMD,
+       WMI_TAG_DHCP_LEASE_RENEW_EVENT,
+       WMI_TAG_BTM_CONFIG,
+       WMI_TAG_DEBUG_MESG_FW_DATA_STALL,
+       WMI_TAG_WLM_CONFIG_CMD,
+       WMI_TAG_PDEV_UPDATE_CTLTABLE_REQUEST,
+       WMI_TAG_PDEV_UPDATE_CTLTABLE_EVENT,
+       WMI_TAG_ROAM_CND_SCORING_PARAM,
+       WMI_TAG_PDEV_CONFIG_VENDOR_OUI_ACTION,
+       WMI_TAG_VENDOR_OUI_EXT,
+       WMI_TAG_ROAM_SYNCH_FRAME_EVENT,
+       WMI_TAG_FD_SEND_FROM_HOST_CMD,
+       WMI_TAG_ENABLE_FILS_CMD,
+       WMI_TAG_HOST_SWFDA_EVENT,
+       WMI_TAG_BCN_OFFLOAD_CTRL_CMD,
+       WMI_TAG_PDEV_SET_AC_TX_QUEUE_OPTIMIZED_CMD,
+       WMI_TAG_STATS_PERIOD,
+       WMI_TAG_NDL_SCHEDULE_UPDATE,
+       WMI_TAG_PEER_TID_MSDUQ_QDEPTH_THRESH_UPDATE_CMD,
+       WMI_TAG_MSDUQ_QDEPTH_THRESH_UPDATE,
+       WMI_TAG_PDEV_SET_RX_FILTER_PROMISCUOUS_CMD,
+       WMI_TAG_SAR2_RESULT_EVENT,
+       WMI_TAG_SAR_CAPABILITIES,
+       WMI_TAG_SAP_OBSS_DETECTION_CFG_CMD,
+       WMI_TAG_SAP_OBSS_DETECTION_INFO_EVT,
+       WMI_TAG_DMA_RING_CAPABILITIES,
+       WMI_TAG_DMA_RING_CFG_REQ,
+       WMI_TAG_DMA_RING_CFG_RSP,
+       WMI_TAG_DMA_BUF_RELEASE,
+       WMI_TAG_DMA_BUF_RELEASE_ENTRY,
+       WMI_TAG_SAR_GET_LIMITS_CMD,
+       WMI_TAG_SAR_GET_LIMITS_EVENT,
+       WMI_TAG_SAR_GET_LIMITS_EVENT_ROW,
+       WMI_TAG_OFFLOAD_11K_REPORT,
+       WMI_TAG_INVOKE_NEIGHBOR_REPORT,
+       WMI_TAG_NEIGHBOR_REPORT_OFFLOAD,
+       WMI_TAG_VDEV_SET_CONNECTIVITY_CHECK_STATS,
+       WMI_TAG_VDEV_GET_CONNECTIVITY_CHECK_STATS,
+       WMI_TAG_BPF_SET_VDEV_ENABLE_CMD,
+       WMI_TAG_BPF_SET_VDEV_WORK_MEMORY_CMD,
+       WMI_TAG_BPF_GET_VDEV_WORK_MEMORY_CMD,
+       WMI_TAG_BPF_GET_VDEV_WORK_MEMORY_RESP_EVT,
+       WMI_TAG_PDEV_GET_NFCAL_POWER,
+       WMI_TAG_BSS_COLOR_CHANGE_ENABLE,
+       WMI_TAG_OBSS_COLOR_COLLISION_DET_CONFIG,
+       WMI_TAG_OBSS_COLOR_COLLISION_EVT,
+       WMI_TAG_RUNTIME_DPD_RECAL_CMD,
+       WMI_TAG_TWT_ENABLE_CMD,
+       WMI_TAG_TWT_DISABLE_CMD,
+       WMI_TAG_TWT_ADD_DIALOG_CMD,
+       WMI_TAG_TWT_DEL_DIALOG_CMD,
+       WMI_TAG_TWT_PAUSE_DIALOG_CMD,
+       WMI_TAG_TWT_RESUME_DIALOG_CMD,
+       WMI_TAG_TWT_ENABLE_COMPLETE_EVENT,
+       WMI_TAG_TWT_DISABLE_COMPLETE_EVENT,
+       WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT,
+       WMI_TAG_TWT_DEL_DIALOG_COMPLETE_EVENT,
+       WMI_TAG_TWT_PAUSE_DIALOG_COMPLETE_EVENT,
+       WMI_TAG_TWT_RESUME_DIALOG_COMPLETE_EVENT,
+       WMI_TAG_REQUEST_ROAM_SCAN_STATS_CMD,
+       WMI_TAG_ROAM_SCAN_STATS_EVENT,
+       WMI_TAG_PEER_TID_CONFIGURATIONS_CMD,
+       WMI_TAG_VDEV_SET_CUSTOM_SW_RETRY_TH_CMD,
+       WMI_TAG_GET_TPC_POWER_CMD,
+       WMI_TAG_GET_TPC_POWER_EVENT,
+       WMI_TAG_DMA_BUF_RELEASE_SPECTRAL_META_DATA,
+       WMI_TAG_MOTION_DET_CONFIG_PARAMS_CMD,
+       WMI_TAG_MOTION_DET_BASE_LINE_CONFIG_PARAMS_CMD,
+       WMI_TAG_MOTION_DET_START_STOP_CMD,
+       WMI_TAG_MOTION_DET_BASE_LINE_START_STOP_CMD,
+       WMI_TAG_MOTION_DET_EVENT,
+       WMI_TAG_MOTION_DET_BASE_LINE_EVENT,
+       WMI_TAG_NDP_TRANSPORT_IP,
+       WMI_TAG_OBSS_SPATIAL_REUSE_SET_CMD,
+       WMI_TAG_ESP_ESTIMATE_EVENT,
+       WMI_TAG_NAN_HOST_CONFIG,
+       WMI_TAG_SPECTRAL_BIN_SCALING_PARAMS,
+       WMI_TAG_PEER_CFR_CAPTURE_CMD,
+       WMI_TAG_PEER_CHAN_WIDTH_SWITCH_CMD,
+       WMI_TAG_CHAN_WIDTH_PEER_LIST,
+       WMI_TAG_OBSS_SPATIAL_REUSE_SET_DEF_OBSS_THRESH_CMD,
+       WMI_TAG_PDEV_HE_TB_ACTION_FRM_CMD,
+       WMI_TAG_PEER_EXTD2_STATS,
+       WMI_TAG_HPCS_PULSE_START_CMD,
+       WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT,
+       WMI_TAG_VDEV_CHAINMASK_CONFIG_CMD,
+       WMI_TAG_VDEV_BCN_OFFLOAD_QUIET_CONFIG_CMD,
+       WMI_TAG_NAN_EVENT_INFO,
+       WMI_TAG_NDP_CHANNEL_INFO,
+       WMI_TAG_NDP_CMD,
+       WMI_TAG_NDP_EVENT,
+       /* TODO add all the missing cmds */
+       WMI_TAG_PDEV_PEER_PKTLOG_FILTER_CMD = 0x301,
+       WMI_TAG_PDEV_PEER_PKTLOG_FILTER_INFO,
+       WMI_TAG_MAX
+};
+
+enum wmi_tlv_service {
+       WMI_TLV_SERVICE_BEACON_OFFLOAD = 0,
+       WMI_TLV_SERVICE_SCAN_OFFLOAD = 1,
+       WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD = 2,
+       WMI_TLV_SERVICE_BCN_MISS_OFFLOAD = 3,
+       WMI_TLV_SERVICE_STA_PWRSAVE = 4,
+       WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE = 5,
+       WMI_TLV_SERVICE_AP_UAPSD = 6,
+       WMI_TLV_SERVICE_AP_DFS = 7,
+       WMI_TLV_SERVICE_11AC = 8,
+       WMI_TLV_SERVICE_BLOCKACK = 9,
+       WMI_TLV_SERVICE_PHYERR = 10,
+       WMI_TLV_SERVICE_BCN_FILTER = 11,
+       WMI_TLV_SERVICE_RTT = 12,
+       WMI_TLV_SERVICE_WOW = 13,
+       WMI_TLV_SERVICE_RATECTRL_CACHE = 14,
+       WMI_TLV_SERVICE_IRAM_TIDS = 15,
+       WMI_TLV_SERVICE_ARPNS_OFFLOAD = 16,
+       WMI_TLV_SERVICE_NLO = 17,
+       WMI_TLV_SERVICE_GTK_OFFLOAD = 18,
+       WMI_TLV_SERVICE_SCAN_SCH = 19,
+       WMI_TLV_SERVICE_CSA_OFFLOAD = 20,
+       WMI_TLV_SERVICE_CHATTER = 21,
+       WMI_TLV_SERVICE_COEX_FREQAVOID = 22,
+       WMI_TLV_SERVICE_PACKET_POWER_SAVE = 23,
+       WMI_TLV_SERVICE_FORCE_FW_HANG = 24,
+       WMI_TLV_SERVICE_GPIO = 25,
+       WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM = 26,
+       WMI_STA_UAPSD_BASIC_AUTO_TRIG = 27,
+       WMI_STA_UAPSD_VAR_AUTO_TRIG = 28,
+       WMI_TLV_SERVICE_STA_KEEP_ALIVE = 29,
+       WMI_TLV_SERVICE_TX_ENCAP = 30,
+       WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC = 31,
+       WMI_TLV_SERVICE_EARLY_RX = 32,
+       WMI_TLV_SERVICE_STA_SMPS = 33,
+       WMI_TLV_SERVICE_FWTEST = 34,
+       WMI_TLV_SERVICE_STA_WMMAC = 35,
+       WMI_TLV_SERVICE_TDLS = 36,
+       WMI_TLV_SERVICE_BURST = 37,
+       WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE = 38,
+       WMI_TLV_SERVICE_ADAPTIVE_OCS = 39,
+       WMI_TLV_SERVICE_BA_SSN_SUPPORT = 40,
+       WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE = 41,
+       WMI_TLV_SERVICE_WLAN_HB = 42,
+       WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT = 43,
+       WMI_TLV_SERVICE_BATCH_SCAN = 44,
+       WMI_TLV_SERVICE_QPOWER = 45,
+       WMI_TLV_SERVICE_PLMREQ = 46,
+       WMI_TLV_SERVICE_THERMAL_MGMT = 47,
+       WMI_TLV_SERVICE_RMC = 48,
+       WMI_TLV_SERVICE_MHF_OFFLOAD = 49,
+       WMI_TLV_SERVICE_COEX_SAR = 50,
+       WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE = 51,
+       WMI_TLV_SERVICE_NAN = 52,
+       WMI_TLV_SERVICE_L1SS_STAT = 53,
+       WMI_TLV_SERVICE_ESTIMATE_LINKSPEED = 54,
+       WMI_TLV_SERVICE_OBSS_SCAN = 55,
+       WMI_TLV_SERVICE_TDLS_OFFCHAN = 56,
+       WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA = 57,
+       WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA = 58,
+       WMI_TLV_SERVICE_IBSS_PWRSAVE = 59,
+       WMI_TLV_SERVICE_LPASS = 60,
+       WMI_TLV_SERVICE_EXTSCAN = 61,
+       WMI_TLV_SERVICE_D0WOW = 62,
+       WMI_TLV_SERVICE_HSOFFLOAD = 63,
+       WMI_TLV_SERVICE_ROAM_HO_OFFLOAD = 64,
+       WMI_TLV_SERVICE_RX_FULL_REORDER = 65,
+       WMI_TLV_SERVICE_DHCP_OFFLOAD = 66,
+       WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT = 67,
+       WMI_TLV_SERVICE_MDNS_OFFLOAD = 68,
+       WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD = 69,
+       WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT = 70,
+       WMI_TLV_SERVICE_OCB = 71,
+       WMI_TLV_SERVICE_AP_ARPNS_OFFLOAD = 72,
+       WMI_TLV_SERVICE_PER_BAND_CHAINMASK_SUPPORT = 73,
+       WMI_TLV_SERVICE_PACKET_FILTER_OFFLOAD = 74,
+       WMI_TLV_SERVICE_MGMT_TX_HTT = 75,
+       WMI_TLV_SERVICE_MGMT_TX_WMI = 76,
+       WMI_TLV_SERVICE_EXT_MSG = 77,
+       WMI_TLV_SERVICE_MAWC = 78,
+       WMI_TLV_SERVICE_PEER_ASSOC_CONF = 79,
+       WMI_TLV_SERVICE_EGAP = 80,
+       WMI_TLV_SERVICE_STA_PMF_OFFLOAD = 81,
+       WMI_TLV_SERVICE_UNIFIED_WOW_CAPABILITY = 82,
+       WMI_TLV_SERVICE_ENHANCED_PROXY_STA = 83,
+       WMI_TLV_SERVICE_ATF = 84,
+       WMI_TLV_SERVICE_COEX_GPIO = 85,
+       WMI_TLV_SERVICE_AUX_SPECTRAL_INTF = 86,
+       WMI_TLV_SERVICE_AUX_CHAN_LOAD_INTF = 87,
+       WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64 = 88,
+       WMI_TLV_SERVICE_ENTERPRISE_MESH = 89,
+       WMI_TLV_SERVICE_RESTRT_CHNL_SUPPORT = 90,
+       WMI_TLV_SERVICE_BPF_OFFLOAD = 91,
+       WMI_TLV_SERVICE_SYNC_DELETE_CMDS = 92,
+       WMI_TLV_SERVICE_SMART_ANTENNA_SW_SUPPORT = 93,
+       WMI_TLV_SERVICE_SMART_ANTENNA_HW_SUPPORT = 94,
+       WMI_TLV_SERVICE_RATECTRL_LIMIT_MAX_MIN_RATES = 95,
+       WMI_TLV_SERVICE_NAN_DATA = 96,
+       WMI_TLV_SERVICE_NAN_RTT = 97,
+       WMI_TLV_SERVICE_11AX = 98,
+       WMI_TLV_SERVICE_DEPRECATED_REPLACE = 99,
+       WMI_TLV_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE = 100,
+       WMI_TLV_SERVICE_ENHANCED_MCAST_FILTER = 101,
+       WMI_TLV_SERVICE_PERIODIC_CHAN_STAT_SUPPORT = 102,
+       WMI_TLV_SERVICE_MESH_11S = 103,
+       WMI_TLV_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT = 104,
+       WMI_TLV_SERVICE_VDEV_RX_FILTER = 105,
+       WMI_TLV_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT = 106,
+       WMI_TLV_SERVICE_MARK_FIRST_WAKEUP_PACKET = 107,
+       WMI_TLV_SERVICE_MULTIPLE_MCAST_FILTER_SET = 108,
+       WMI_TLV_SERVICE_HOST_MANAGED_RX_REORDER = 109,
+       WMI_TLV_SERVICE_FLASH_RDWR_SUPPORT = 110,
+       WMI_TLV_SERVICE_WLAN_STATS_REPORT = 111,
+       WMI_TLV_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT = 112,
+       WMI_TLV_SERVICE_DFS_PHYERR_OFFLOAD = 113,
+       WMI_TLV_SERVICE_RCPI_SUPPORT = 114,
+       WMI_TLV_SERVICE_FW_MEM_DUMP_SUPPORT = 115,
+       WMI_TLV_SERVICE_PEER_STATS_INFO = 116,
+       WMI_TLV_SERVICE_REGULATORY_DB = 117,
+       WMI_TLV_SERVICE_11D_OFFLOAD = 118,
+       WMI_TLV_SERVICE_HW_DATA_FILTERING = 119,
+       WMI_TLV_SERVICE_MULTIPLE_VDEV_RESTART = 120,
+       WMI_TLV_SERVICE_PKT_ROUTING = 121,
+       WMI_TLV_SERVICE_CHECK_CAL_VERSION = 122,
+       WMI_TLV_SERVICE_OFFCHAN_TX_WMI = 123,
+       WMI_TLV_SERVICE_8SS_TX_BFEE  =  124,
+       WMI_TLV_SERVICE_EXTENDED_NSS_SUPPORT = 125,
+       WMI_TLV_SERVICE_ACK_TIMEOUT = 126,
+       WMI_TLV_SERVICE_PDEV_BSS_CHANNEL_INFO_64 = 127,
+
+       WMI_MAX_SERVICE = 128,
+
+       WMI_TLV_SERVICE_CHAN_LOAD_INFO = 128,
+       WMI_TLV_SERVICE_TX_PPDU_INFO_STATS_SUPPORT = 129,
+       WMI_TLV_SERVICE_VDEV_LIMIT_OFFCHAN_SUPPORT = 130,
+       WMI_TLV_SERVICE_FILS_SUPPORT = 131,
+       WMI_TLV_SERVICE_WLAN_OIC_PING_OFFLOAD = 132,
+       WMI_TLV_SERVICE_WLAN_DHCP_RENEW = 133,
+       WMI_TLV_SERVICE_MAWC_SUPPORT = 134,
+       WMI_TLV_SERVICE_VDEV_LATENCY_CONFIG = 135,
+       WMI_TLV_SERVICE_PDEV_UPDATE_CTLTABLE_SUPPORT = 136,
+       WMI_TLV_SERVICE_PKTLOG_SUPPORT_OVER_HTT = 137,
+       WMI_TLV_SERVICE_VDEV_MULTI_GROUP_KEY_SUPPORT = 138,
+       WMI_TLV_SERVICE_SCAN_PHYMODE_SUPPORT = 139,
+       WMI_TLV_SERVICE_THERM_THROT = 140,
+       WMI_TLV_SERVICE_BCN_OFFLOAD_START_STOP_SUPPORT = 141,
+       WMI_TLV_SERVICE_WOW_WAKEUP_BY_TIMER_PATTERN = 142,
+       WMI_TLV_SERVICE_PEER_MAP_UNMAP_V2_SUPPORT = 143,
+       WMI_TLV_SERVICE_OFFCHAN_DATA_TID_SUPPORT = 144,
+       WMI_TLV_SERVICE_RX_PROMISC_ENABLE_SUPPORT = 145,
+       WMI_TLV_SERVICE_SUPPORT_DIRECT_DMA = 146,
+       WMI_TLV_SERVICE_AP_OBSS_DETECTION_OFFLOAD = 147,
+       WMI_TLV_SERVICE_11K_NEIGHBOUR_REPORT_SUPPORT = 148,
+       WMI_TLV_SERVICE_LISTEN_INTERVAL_OFFLOAD_SUPPORT = 149,
+       WMI_TLV_SERVICE_BSS_COLOR_OFFLOAD = 150,
+       WMI_TLV_SERVICE_RUNTIME_DPD_RECAL = 151,
+       WMI_TLV_SERVICE_STA_TWT = 152,
+       WMI_TLV_SERVICE_AP_TWT = 153,
+       WMI_TLV_SERVICE_GMAC_OFFLOAD_SUPPORT = 154,
+       WMI_TLV_SERVICE_SPOOF_MAC_SUPPORT = 155,
+       WMI_TLV_SERVICE_PEER_TID_CONFIGS_SUPPORT = 156,
+       WMI_TLV_SERVICE_VDEV_SWRETRY_PER_AC_CONFIG_SUPPORT = 157,
+       WMI_TLV_SERVICE_DUAL_BEACON_ON_SINGLE_MAC_SCC_SUPPORT = 158,
+       WMI_TLV_SERVICE_DUAL_BEACON_ON_SINGLE_MAC_MCC_SUPPORT = 159,
+       WMI_TLV_SERVICE_MOTION_DET = 160,
+       WMI_TLV_SERVICE_INFRA_MBSSID = 161,
+       WMI_TLV_SERVICE_OBSS_SPATIAL_REUSE = 162,
+       WMI_TLV_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT = 163,
+       WMI_TLV_SERVICE_NAN_DBS_SUPPORT = 164,
+       WMI_TLV_SERVICE_NDI_DBS_SUPPORT = 165,
+       WMI_TLV_SERVICE_NAN_SAP_SUPPORT = 166,
+       WMI_TLV_SERVICE_NDI_SAP_SUPPORT = 167,
+       WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT = 168,
+       WMI_TLV_SERVICE_CFR_CAPTURE_IND_MSG_TYPE_1 = 169,
+       WMI_TLV_SERVICE_ESP_SUPPORT = 170,
+       WMI_TLV_SERVICE_PEER_CHWIDTH_CHANGE = 171,
+       WMI_TLV_SERVICE_WLAN_HPCS_PULSE = 172,
+       WMI_TLV_SERVICE_PER_VDEV_CHAINMASK_CONFIG_SUPPORT = 173,
+       WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI = 174,
+       WMI_TLV_SERVICE_NAN_DISABLE_SUPPORT = 175,
+       WMI_TLV_SERVICE_HTT_H2T_NO_HTC_HDR_LEN_IN_MSG_LEN = 176,
+
+       WMI_MAX_EXT_SERVICE
+
+};
+
+enum {
+       WMI_SMPS_FORCED_MODE_NONE = 0,
+       WMI_SMPS_FORCED_MODE_DISABLED,
+       WMI_SMPS_FORCED_MODE_STATIC,
+       WMI_SMPS_FORCED_MODE_DYNAMIC
+};
+
+#define WMI_TPC_CHAINMASK_CONFIG_BAND_2G      0
+#define WMI_TPC_CHAINMASK_CONFIG_BAND_5G      1
+#define WMI_NUM_SUPPORTED_BAND_MAX 2
+
+#define WMI_PEER_MIMO_PS_STATE                          0x1
+#define WMI_PEER_AMPDU                                  0x2
+#define WMI_PEER_AUTHORIZE                              0x3
+#define WMI_PEER_CHWIDTH                                0x4
+#define WMI_PEER_NSS                                    0x5
+#define WMI_PEER_USE_4ADDR                              0x6
+#define WMI_PEER_MEMBERSHIP                             0x7
+#define WMI_PEER_USERPOS                                0x8
+#define WMI_PEER_CRIT_PROTO_HINT_ENABLED                0x9
+#define WMI_PEER_TX_FAIL_CNT_THR                        0xA
+#define WMI_PEER_SET_HW_RETRY_CTS2S                     0xB
+#define WMI_PEER_IBSS_ATIM_WINDOW_LENGTH                0xC
+#define WMI_PEER_PHYMODE                                0xD
+#define WMI_PEER_USE_FIXED_PWR                          0xE
+#define WMI_PEER_PARAM_FIXED_RATE                       0xF
+#define WMI_PEER_SET_MU_WHITELIST                       0x10
+#define WMI_PEER_SET_MAX_TX_RATE                        0x11
+#define WMI_PEER_SET_MIN_TX_RATE                        0x12
+#define WMI_PEER_SET_DEFAULT_ROUTING                    0x13
+
+/* slot time long */
+#define WMI_VDEV_SLOT_TIME_LONG         0x1
+/* slot time short */
+#define WMI_VDEV_SLOT_TIME_SHORT        0x2
+/* preablbe long */
+#define WMI_VDEV_PREAMBLE_LONG          0x1
+/* preablbe short */
+#define WMI_VDEV_PREAMBLE_SHORT         0x2
+
+enum wmi_peer_smps_state {
+       WMI_PEER_SMPS_PS_NONE = 0x0,
+       WMI_PEER_SMPS_STATIC  = 0x1,
+       WMI_PEER_SMPS_DYNAMIC = 0x2
+};
+
+enum wmi_peer_chwidth {
+       WMI_PEER_CHWIDTH_20MHZ = 0,
+       WMI_PEER_CHWIDTH_40MHZ = 1,
+       WMI_PEER_CHWIDTH_80MHZ = 2,
+       WMI_PEER_CHWIDTH_160MHZ = 3,
+};
+
+enum wmi_beacon_gen_mode {
+       WMI_BEACON_STAGGERED_MODE = 0,
+       WMI_BEACON_BURST_MODE = 1
+};
+
+struct wmi_host_pdev_band_to_mac {
+       u32 pdev_id;
+       u32 start_freq;
+       u32 end_freq;
+};
+
+struct ath11k_ppe_threshold {
+       u32 numss_m1;
+       u32 ru_bit_mask;
+       u32 ppet16_ppet8_ru3_ru0[PSOC_HOST_MAX_NUM_SS];
+};
+
+struct ath11k_service_ext_param {
+       u32 default_conc_scan_config_bits;
+       u32 default_fw_config_bits;
+       struct ath11k_ppe_threshold ppet;
+       u32 he_cap_info;
+       u32 mpdu_density;
+       u32 max_bssid_rx_filters;
+       u32 num_hw_modes;
+       u32 num_phy;
+};
+
+struct ath11k_hw_mode_caps {
+       u32 hw_mode_id;
+       u32 phy_id_map;
+       u32 hw_mode_config_type;
+};
+
+#define PSOC_HOST_MAX_PHY_SIZE (3)
+#define ATH11K_11B_SUPPORT                 BIT(0)
+#define ATH11K_11G_SUPPORT                 BIT(1)
+#define ATH11K_11A_SUPPORT                 BIT(2)
+#define ATH11K_11N_SUPPORT                 BIT(3)
+#define ATH11K_11AC_SUPPORT                BIT(4)
+#define ATH11K_11AX_SUPPORT                BIT(5)
+
+struct ath11k_hal_reg_capabilities_ext {
+       u32 phy_id;
+       u32 eeprom_reg_domain;
+       u32 eeprom_reg_domain_ext;
+       u32 regcap1;
+       u32 regcap2;
+       u32 wireless_modes;
+       u32 low_2ghz_chan;
+       u32 high_2ghz_chan;
+       u32 low_5ghz_chan;
+       u32 high_5ghz_chan;
+};
+
+#define WMI_HOST_MAX_PDEV 3
+
+struct wlan_host_mem_chunk {
+       u32 tlv_header;
+       u32 req_id;
+       u32 ptr;
+       u32 size;
+} __packed;
+
+struct wmi_host_mem_chunk {
+       void *vaddr;
+       dma_addr_t paddr;
+       u32 len;
+       u32 req_id;
+};
+
+struct wmi_init_cmd_param {
+       u32 tlv_header;
+       struct target_resource_config *res_cfg;
+       u8 num_mem_chunks;
+       struct wmi_host_mem_chunk *mem_chunks;
+       u32 hw_mode_id;
+       u32 num_band_to_mac;
+       struct wmi_host_pdev_band_to_mac band_to_mac[WMI_HOST_MAX_PDEV];
+};
+
+struct wmi_pdev_band_to_mac {
+       u32 tlv_header;
+       u32 pdev_id;
+       u32 start_freq;
+       u32 end_freq;
+} __packed;
+
+struct wmi_pdev_set_hw_mode_cmd_param {
+       u32 tlv_header;
+       u32 pdev_id;
+       u32 hw_mode_index;
+       u32 num_band_to_mac;
+} __packed;
+
+struct wmi_ppe_threshold {
+       u32 numss_m1; /** NSS - 1*/
+       union {
+               u32 ru_count;
+               u32 ru_mask;
+       } __packed;
+       u32 ppet16_ppet8_ru3_ru0[WMI_MAX_NUM_SS];
+} __packed;
+
+#define HW_BD_INFO_SIZE       5
+
+struct wmi_abi_version {
+       u32 abi_version_0;
+       u32 abi_version_1;
+       u32 abi_version_ns_0;
+       u32 abi_version_ns_1;
+       u32 abi_version_ns_2;
+       u32 abi_version_ns_3;
+} __packed;
+
+struct wmi_init_cmd {
+       u32 tlv_header;
+       struct wmi_abi_version host_abi_vers;
+       u32 num_host_mem_chunks;
+} __packed;
+
+struct wmi_resource_config {
+       u32 tlv_header;
+       u32 num_vdevs;
+       u32 num_peers;
+       u32 num_offload_peers;
+       u32 num_offload_reorder_buffs;
+       u32 num_peer_keys;
+       u32 num_tids;
+       u32 ast_skid_limit;
+       u32 tx_chain_mask;
+       u32 rx_chain_mask;
+       u32 rx_timeout_pri[4];
+       u32 rx_decap_mode;
+       u32 scan_max_pending_req;
+       u32 bmiss_offload_max_vdev;
+       u32 roam_offload_max_vdev;
+       u32 roam_offload_max_ap_profiles;
+       u32 num_mcast_groups;
+       u32 num_mcast_table_elems;
+       u32 mcast2ucast_mode;
+       u32 tx_dbg_log_size;
+       u32 num_wds_entries;
+       u32 dma_burst_size;
+       u32 mac_aggr_delim;
+       u32 rx_skip_defrag_timeout_dup_detection_check;
+       u32 vow_config;
+       u32 gtk_offload_max_vdev;
+       u32 num_msdu_desc;
+       u32 max_frag_entries;
+       u32 num_tdls_vdevs;
+       u32 num_tdls_conn_table_entries;
+       u32 beacon_tx_offload_max_vdev;
+       u32 num_multicast_filter_entries;
+       u32 num_wow_filters;
+       u32 num_keep_alive_pattern;
+       u32 keep_alive_pattern_size;
+       u32 max_tdls_concurrent_sleep_sta;
+       u32 max_tdls_concurrent_buffer_sta;
+       u32 wmi_send_separate;
+       u32 num_ocb_vdevs;
+       u32 num_ocb_channels;
+       u32 num_ocb_schedules;
+       u32 flag1;
+       u32 smart_ant_cap;
+       u32 bk_minfree;
+       u32 be_minfree;
+       u32 vi_minfree;
+       u32 vo_minfree;
+       u32 alloc_frag_desc_for_data_pkt;
+       u32 num_ns_ext_tuples_cfg;
+       u32 bpf_instruction_size;
+       u32 max_bssid_rx_filters;
+       u32 use_pdev_id;
+       u32 max_num_dbs_scan_duty_cycle;
+       u32 max_num_group_keys;
+       u32 peer_map_unmap_v2_support;
+} __packed;
+
+struct wmi_service_ready_event {
+       u32 fw_build_vers;
+       struct wmi_abi_version fw_abi_vers;
+       u32 phy_capability;
+       u32 max_frag_entry;
+       u32 num_rf_chains;
+       u32 ht_cap_info;
+       u32 vht_cap_info;
+       u32 vht_supp_mcs;
+       u32 hw_min_tx_power;
+       u32 hw_max_tx_power;
+       u32 sys_cap_info;
+       u32 min_pkt_size_enable;
+       u32 max_bcn_ie_size;
+       u32 num_mem_reqs;
+       u32 max_num_scan_channels;
+       u32 hw_bd_id;
+       u32 hw_bd_info[HW_BD_INFO_SIZE];
+       u32 max_supported_macs;
+       u32 wmi_fw_sub_feat_caps;
+       u32 num_dbs_hw_modes;
+       /* txrx_chainmask
+        *    [7:0]   - 2G band tx chain mask
+        *    [15:8]  - 2G band rx chain mask
+        *    [23:16] - 5G band tx chain mask
+        *    [31:24] - 5G band rx chain mask
+        */
+       u32 txrx_chainmask;
+       u32 default_dbs_hw_mode_index;
+       u32 num_msdu_desc;
+} __packed;
+
+#define WMI_SERVICE_BM_SIZE    ((WMI_MAX_SERVICE + sizeof(u32) - 1) / sizeof(u32))
+
+#define WMI_SERVICE_SEGMENT_BM_SIZE32 4 /* 4x u32 = 128 bits */
+#define WMI_SERVICE_EXT_BM_SIZE (WMI_SERVICE_SEGMENT_BM_SIZE32 * sizeof(u32))
+#define WMI_AVAIL_SERVICE_BITS_IN_SIZE32 32
+#define WMI_SERVICE_BITS_IN_SIZE32 4
+
+struct wmi_service_ready_ext_event {
+       u32 default_conc_scan_config_bits;
+       u32 default_fw_config_bits;
+       struct wmi_ppe_threshold ppet;
+       u32 he_cap_info;
+       u32 mpdu_density;
+       u32 max_bssid_rx_filters;
+       u32 fw_build_vers_ext;
+       u32 max_nlo_ssids;
+       u32 max_bssid_indicator;
+       u32 he_cap_info_ext;
+} __packed;
+
+struct wmi_soc_mac_phy_hw_mode_caps {
+       u32 num_hw_modes;
+       u32 num_chainmask_tables;
+} __packed;
+
+struct wmi_hw_mode_capabilities {
+       u32 tlv_header;
+       u32 hw_mode_id;
+       u32 phy_id_map;
+       u32 hw_mode_config_type;
+} __packed;
+
+#define WMI_MAX_HECAP_PHY_SIZE                 (3)
+
+struct wmi_mac_phy_capabilities {
+       u32 tlv_header;
+       u32 hw_mode_id;
+       u32 pdev_id;
+       u32 phy_id;
+       u32 supported_flags;
+       u32 supported_bands;
+       u32 ampdu_density;
+       u32 max_bw_supported_2g;
+       u32 ht_cap_info_2g;
+       u32 vht_cap_info_2g;
+       u32 vht_supp_mcs_2g;
+       u32 he_cap_info_2g;
+       u32 he_supp_mcs_2g;
+       u32 tx_chain_mask_2g;
+       u32 rx_chain_mask_2g;
+       u32 max_bw_supported_5g;
+       u32 ht_cap_info_5g;
+       u32 vht_cap_info_5g;
+       u32 vht_supp_mcs_5g;
+       u32 he_cap_info_5g;
+       u32 he_supp_mcs_5g;
+       u32 tx_chain_mask_5g;
+       u32 rx_chain_mask_5g;
+       u32 he_cap_phy_info_2g[WMI_MAX_HECAP_PHY_SIZE];
+       u32 he_cap_phy_info_5g[WMI_MAX_HECAP_PHY_SIZE];
+       struct wmi_ppe_threshold he_ppet2g;
+       struct wmi_ppe_threshold he_ppet5g;
+       u32 chainmask_table_id;
+       u32 lmac_id;
+       u32 he_cap_info_2g_ext;
+       u32 he_cap_info_5g_ext;
+       u32 he_cap_info_internal;
+} __packed;
+
+struct wmi_hal_reg_capabilities_ext {
+       u32 tlv_header;
+       u32 phy_id;
+       u32 eeprom_reg_domain;
+       u32 eeprom_reg_domain_ext;
+       u32 regcap1;
+       u32 regcap2;
+       u32 wireless_modes;
+       u32 low_2ghz_chan;
+       u32 high_2ghz_chan;
+       u32 low_5ghz_chan;
+       u32 high_5ghz_chan;
+} __packed;
+
+struct wmi_soc_hal_reg_capabilities {
+       u32 num_phy;
+} __packed;
+
+/* 2 word representation of MAC addr */
+struct wmi_mac_addr {
+       union {
+               u8 addr[6];
+               struct {
+                       u32 word0;
+                       u32 word1;
+               } __packed;
+       } __packed;
+} __packed;
+
+struct wmi_ready_event {
+       struct wmi_abi_version fw_abi_vers;
+       struct wmi_mac_addr mac_addr;
+       u32 status;
+       u32 num_dscp_table;
+       u32 num_extra_mac_addr;
+       u32 num_total_peers;
+       u32 num_extra_peers;
+} __packed;
+
+struct wmi_service_available_event {
+       u32 wmi_service_segment_offset;
+       u32 wmi_service_segment_bitmap[WMI_SERVICE_SEGMENT_BM_SIZE32];
+} __packed;
+
+struct ath11k_pdev_wmi {
+       struct ath11k_wmi_base *wmi_sc;
+       enum ath11k_htc_ep_id eid;
+       const struct wmi_peer_flags_map *peer_flags;
+       u32 rx_decap_mode;
+};
+
+struct vdev_create_params {
+       u8 if_id;
+       u32 type;
+       u32 subtype;
+       struct {
+               u8 tx;
+               u8 rx;
+       } chains[NUM_NL80211_BANDS];
+       u32 pdev_id;
+};
+
+struct wmi_vdev_create_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 vdev_type;
+       u32 vdev_subtype;
+       struct wmi_mac_addr vdev_macaddr;
+       u32 num_cfg_txrx_streams;
+       u32 pdev_id;
+} __packed;
+
+struct wmi_vdev_txrx_streams {
+       u32 tlv_header;
+       u32 band;
+       u32 supported_tx_streams;
+       u32 supported_rx_streams;
+} __packed;
+
+struct wmi_vdev_delete_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+} __packed;
+
+struct wmi_vdev_up_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 vdev_assoc_id;
+       struct wmi_mac_addr vdev_bssid;
+       struct wmi_mac_addr trans_bssid;
+       u32 profile_idx;
+       u32 profile_num;
+} __packed;
+
+struct wmi_vdev_stop_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+} __packed;
+
+struct wmi_vdev_down_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+} __packed;
+
+#define WMI_VDEV_START_HIDDEN_SSID  BIT(0)
+#define WMI_VDEV_START_PMF_ENABLED  BIT(1)
+#define WMI_VDEV_START_LDPC_RX_ENABLED BIT(3)
+
+struct wmi_ssid {
+       u32 ssid_len;
+       u32 ssid[8];
+} __packed;
+
+#define ATH11K_VDEV_SETUP_TIMEOUT_HZ (1 * HZ)
+
+struct wmi_vdev_start_request_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 requestor_id;
+       u32 beacon_interval;
+       u32 dtim_period;
+       u32 flags;
+       struct wmi_ssid ssid;
+       u32 bcn_tx_rate;
+       u32 bcn_txpower;
+       u32 num_noa_descriptors;
+       u32 disable_hw_ack;
+       u32 preferred_tx_streams;
+       u32 preferred_rx_streams;
+       u32 he_ops;
+       u32 cac_duration_ms;
+       u32 regdomain;
+} __packed;
+
+#define MGMT_TX_DL_FRM_LEN                  64
+#define WMI_MAC_MAX_SSID_LENGTH              32
+struct mac_ssid {
+       u8 length;
+       u8 mac_ssid[WMI_MAC_MAX_SSID_LENGTH];
+} __packed;
+
+struct wmi_p2p_noa_descriptor {
+       u32 type_count;
+       u32 duration;
+       u32 interval;
+       u32 start_time;
+};
+
+struct channel_param {
+       u8 chan_id;
+       u8 pwr;
+       u32 mhz;
+       u32 half_rate:1,
+           quarter_rate:1,
+           dfs_set:1,
+           dfs_set_cfreq2:1,
+           is_chan_passive:1,
+           allow_ht:1,
+           allow_vht:1,
+           set_agile:1;
+       u32 phy_mode;
+       u32 cfreq1;
+       u32 cfreq2;
+       char   maxpower;
+       char   minpower;
+       char   maxregpower;
+       u8  antennamax;
+       u8  reg_class_id;
+} __packed;
+
+enum wmi_phy_mode {
+       MODE_11A        = 0,
+       MODE_11G        = 1,   /* 11b/g Mode */
+       MODE_11B        = 2,   /* 11b Mode */
+       MODE_11GONLY    = 3,   /* 11g only Mode */
+       MODE_11NA_HT20   = 4,
+       MODE_11NG_HT20   = 5,
+       MODE_11NA_HT40   = 6,
+       MODE_11NG_HT40   = 7,
+       MODE_11AC_VHT20 = 8,
+       MODE_11AC_VHT40 = 9,
+       MODE_11AC_VHT80 = 10,
+       MODE_11AC_VHT20_2G = 11,
+       MODE_11AC_VHT40_2G = 12,
+       MODE_11AC_VHT80_2G = 13,
+       MODE_11AC_VHT80_80 = 14,
+       MODE_11AC_VHT160 = 15,
+       MODE_11AX_HE20 = 16,
+       MODE_11AX_HE40 = 17,
+       MODE_11AX_HE80 = 18,
+       MODE_11AX_HE80_80 = 19,
+       MODE_11AX_HE160 = 20,
+       MODE_11AX_HE20_2G = 21,
+       MODE_11AX_HE40_2G = 22,
+       MODE_11AX_HE80_2G = 23,
+       MODE_UNKNOWN = 24,
+       MODE_MAX = 24
+};
+
+static inline const char *ath11k_wmi_phymode_str(enum wmi_phy_mode mode)
+{
+       switch (mode) {
+       case MODE_11A:
+               return "11a";
+       case MODE_11G:
+               return "11g";
+       case MODE_11B:
+               return "11b";
+       case MODE_11GONLY:
+               return "11gonly";
+       case MODE_11NA_HT20:
+               return "11na-ht20";
+       case MODE_11NG_HT20:
+               return "11ng-ht20";
+       case MODE_11NA_HT40:
+               return "11na-ht40";
+       case MODE_11NG_HT40:
+               return "11ng-ht40";
+       case MODE_11AC_VHT20:
+               return "11ac-vht20";
+       case MODE_11AC_VHT40:
+               return "11ac-vht40";
+       case MODE_11AC_VHT80:
+               return "11ac-vht80";
+       case MODE_11AC_VHT160:
+               return "11ac-vht160";
+       case MODE_11AC_VHT80_80:
+               return "11ac-vht80+80";
+       case MODE_11AC_VHT20_2G:
+               return "11ac-vht20-2g";
+       case MODE_11AC_VHT40_2G:
+               return "11ac-vht40-2g";
+       case MODE_11AC_VHT80_2G:
+               return "11ac-vht80-2g";
+       case MODE_11AX_HE20:
+               return "11ax-he20";
+       case MODE_11AX_HE40:
+               return "11ax-he40";
+       case MODE_11AX_HE80:
+               return "11ax-he80";
+       case MODE_11AX_HE80_80:
+               return "11ax-he80+80";
+       case MODE_11AX_HE160:
+               return "11ax-he160";
+       case MODE_11AX_HE20_2G:
+               return "11ax-he20-2g";
+       case MODE_11AX_HE40_2G:
+               return "11ax-he40-2g";
+       case MODE_11AX_HE80_2G:
+               return "11ax-he80-2g";
+       case MODE_UNKNOWN:
+               /* skip */
+               break;
+
+               /* no default handler to allow compiler to check that the
+                * enum is fully handled
+                */
+       };
+
+       return "<unknown>";
+}
+
+struct wmi_channel_arg {
+       u32 freq;
+       u32 band_center_freq1;
+       u32 band_center_freq2;
+       bool passive;
+       bool allow_ibss;
+       bool allow_ht;
+       bool allow_vht;
+       bool ht40plus;
+       bool chan_radar;
+       bool freq2_radar;
+       bool allow_he;
+       u32 min_power;
+       u32 max_power;
+       u32 max_reg_power;
+       u32 max_antenna_gain;
+       enum wmi_phy_mode mode;
+};
+
+struct wmi_vdev_start_req_arg {
+       u32 vdev_id;
+       struct wmi_channel_arg channel;
+       u32 bcn_intval;
+       u32 dtim_period;
+       u8 *ssid;
+       u32 ssid_len;
+       u32 bcn_tx_rate;
+       u32 bcn_tx_power;
+       bool disable_hw_ack;
+       bool hidden_ssid;
+       bool pmf_enabled;
+       u32 he_ops;
+       u32 cac_duration_ms;
+       u32 regdomain;
+       u32 pref_rx_streams;
+       u32 pref_tx_streams;
+       u32 num_noa_descriptors;
+};
+
+struct peer_create_params {
+       const u8 *peer_addr;
+       u32 peer_type;
+       u32 vdev_id;
+};
+
+struct peer_delete_params {
+       u8 vdev_id;
+};
+
+struct peer_flush_params {
+       u32 peer_tid_bitmap;
+       u8 vdev_id;
+};
+
+struct pdev_set_regdomain_params {
+       u16 current_rd_in_use;
+       u16 current_rd_2g;
+       u16 current_rd_5g;
+       u32 ctl_2g;
+       u32 ctl_5g;
+       u8 dfs_domain;
+       u32 pdev_id;
+};
+
+struct rx_reorder_queue_remove_params {
+       u8 *peer_macaddr;
+       u16 vdev_id;
+       u32 peer_tid_bitmap;
+};
+
+#define WMI_HOST_PDEV_ID_SOC 0xFF
+#define WMI_HOST_PDEV_ID_0   0
+#define WMI_HOST_PDEV_ID_1   1
+#define WMI_HOST_PDEV_ID_2   2
+
+#define WMI_PDEV_ID_SOC         0
+#define WMI_PDEV_ID_1ST         1
+#define WMI_PDEV_ID_2ND         2
+#define WMI_PDEV_ID_3RD         3
+
+/* Freq units in MHz */
+#define REG_RULE_START_FREQ                    0x0000ffff
+#define REG_RULE_END_FREQ                      0xffff0000
+#define REG_RULE_FLAGS                         0x0000ffff
+#define REG_RULE_MAX_BW                                0x0000ffff
+#define REG_RULE_REG_PWR                       0x00ff0000
+#define REG_RULE_ANT_GAIN                      0xff000000
+
+#define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
+#define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)
+#define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2)
+#define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3)
+
+#define HECAP_PHYDWORD_0       0
+#define HECAP_PHYDWORD_1       1
+#define HECAP_PHYDWORD_2       2
+
+#define HECAP_PHY_SU_BFER              BIT(31)
+#define HECAP_PHY_SU_BFEE              BIT(0)
+#define HECAP_PHY_MU_BFER              BIT(1)
+#define HECAP_PHY_UL_MUMIMO            BIT(22)
+#define HECAP_PHY_UL_MUOFDMA           BIT(23)
+
+#define HECAP_PHY_SUBFMR_GET(hecap_phy) \
+       FIELD_GET(HECAP_PHY_SU_BFER, hecap_phy[HECAP_PHYDWORD_0])
+
+#define HECAP_PHY_SUBFME_GET(hecap_phy) \
+       FIELD_GET(HECAP_PHY_SU_BFEE, hecap_phy[HECAP_PHYDWORD_1])
+
+#define HECAP_PHY_MUBFMR_GET(hecap_phy) \
+       FIELD_GET(HECAP_PHY_MU_BFER, hecap_phy[HECAP_PHYDWORD_1])
+
+#define HECAP_PHY_ULMUMIMO_GET(hecap_phy) \
+       FIELD_GET(HECAP_PHY_UL_MUMIMO, hecap_phy[HECAP_PHYDWORD_0])
+
+#define HECAP_PHY_ULOFDMA_GET(hecap_phy) \
+       FIELD_GET(HECAP_PHY_UL_MUOFDMA, hecap_phy[HECAP_PHYDWORD_0])
+
+#define HE_MODE_SU_TX_BFEE     BIT(0)
+#define HE_MODE_SU_TX_BFER     BIT(1)
+#define HE_MODE_MU_TX_BFEE     BIT(2)
+#define HE_MODE_MU_TX_BFER     BIT(3)
+#define HE_MODE_DL_OFDMA       BIT(4)
+#define HE_MODE_UL_OFDMA       BIT(5)
+#define HE_MODE_UL_MUMIMO      BIT(6)
+
+#define HE_DL_MUOFDMA_ENABLE   1
+#define HE_UL_MUOFDMA_ENABLE   1
+#define HE_DL_MUMIMO_ENABLE    1
+#define HE_MU_BFEE_ENABLE      1
+#define HE_SU_BFEE_ENABLE      1
+
+#define HE_VHT_SOUNDING_MODE_ENABLE            1
+#define HE_SU_MU_SOUNDING_MODE_ENABLE          1
+#define HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE   1
+
+/* HE or VHT Sounding */
+#define HE_VHT_SOUNDING_MODE           BIT(0)
+/* SU or MU Sounding */
+#define HE_SU_MU_SOUNDING_MODE         BIT(2)
+/* Trig or Non-Trig Sounding */
+#define HE_TRIG_NONTRIG_SOUNDING_MODE  BIT(3)
+
+#define WMI_TXBF_STS_CAP_OFFSET_LSB    4
+#define WMI_TXBF_STS_CAP_OFFSET_MASK   0x70
+#define WMI_BF_SOUND_DIM_OFFSET_LSB    8
+#define WMI_BF_SOUND_DIM_OFFSET_MASK   0x700
+
+struct pdev_params {
+       u32 param_id;
+       u32 param_value;
+};
+
+enum wmi_peer_type {
+       WMI_PEER_TYPE_DEFAULT = 0,
+       WMI_PEER_TYPE_BSS = 1,
+       WMI_PEER_TYPE_TDLS = 2,
+};
+
+struct wmi_peer_create_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 peer_type;
+} __packed;
+
+struct wmi_peer_delete_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+} __packed;
+
+struct wmi_peer_reorder_queue_setup_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 tid;
+       u32 queue_ptr_lo;
+       u32 queue_ptr_hi;
+       u32 queue_no;
+       u32 ba_window_size_valid;
+       u32 ba_window_size;
+} __packed;
+
+struct wmi_peer_reorder_queue_remove_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 tid_mask;
+} __packed;
+
+struct gpio_config_params {
+       u32 gpio_num;
+       u32 input;
+       u32 pull_type;
+       u32 intr_mode;
+};
+
+enum wmi_gpio_type {
+       WMI_GPIO_PULL_NONE,
+       WMI_GPIO_PULL_UP,
+       WMI_GPIO_PULL_DOWN
+};
+
+enum wmi_gpio_intr_type {
+       WMI_GPIO_INTTYPE_DISABLE,
+       WMI_GPIO_INTTYPE_RISING_EDGE,
+       WMI_GPIO_INTTYPE_FALLING_EDGE,
+       WMI_GPIO_INTTYPE_BOTH_EDGE,
+       WMI_GPIO_INTTYPE_LEVEL_LOW,
+       WMI_GPIO_INTTYPE_LEVEL_HIGH
+};
+
+enum wmi_bss_chan_info_req_type {
+       WMI_BSS_SURVEY_REQ_TYPE_READ = 1,
+       WMI_BSS_SURVEY_REQ_TYPE_READ_CLEAR,
+};
+
+struct wmi_gpio_config_cmd_param {
+       u32 tlv_header;
+       u32 gpio_num;
+       u32 input;
+       u32 pull_type;
+       u32 intr_mode;
+};
+
+struct gpio_output_params {
+       u32 gpio_num;
+       u32 set;
+};
+
+struct wmi_gpio_output_cmd_param {
+       u32 tlv_header;
+       u32 gpio_num;
+       u32 set;
+};
+
+struct set_fwtest_params {
+       u32 arg;
+       u32 value;
+};
+
+struct wmi_fwtest_set_param_cmd_param {
+       u32 tlv_header;
+       u32 param_id;
+       u32 param_value;
+};
+
+struct wmi_pdev_set_param_cmd {
+       u32 tlv_header;
+       u32 pdev_id;
+       u32 param_id;
+       u32 param_value;
+} __packed;
+
+struct wmi_pdev_suspend_cmd {
+       u32 tlv_header;
+       u32 pdev_id;
+       u32 suspend_opt;
+} __packed;
+
+struct wmi_pdev_resume_cmd {
+       u32 tlv_header;
+       u32 pdev_id;
+} __packed;
+
+struct wmi_pdev_bss_chan_info_req_cmd {
+       u32 tlv_header;
+       /* ref wmi_bss_chan_info_req_type */
+       u32 req_type;
+} __packed;
+
+struct wmi_ap_ps_peer_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 param;
+       u32 value;
+} __packed;
+
+struct wmi_sta_powersave_param_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 param;
+       u32 value;
+} __packed;
+
+struct wmi_pdev_set_regdomain_cmd {
+       u32 tlv_header;
+       u32 pdev_id;
+       u32 reg_domain;
+       u32 reg_domain_2g;
+       u32 reg_domain_5g;
+       u32 conformance_test_limit_2g;
+       u32 conformance_test_limit_5g;
+       u32 dfs_domain;
+} __packed;
+
+struct wmi_peer_set_param_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 param_id;
+       u32 param_value;
+} __packed;
+
+struct wmi_peer_flush_tids_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 peer_tid_bitmap;
+} __packed;
+
+struct wmi_dfs_phyerr_offload_cmd {
+       u32 tlv_header;
+       u32 pdev_id;
+} __packed;
+
+struct wmi_bcn_offload_ctrl_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 bcn_ctrl_op;
+} __packed;
+
+enum scan_priority {
+       SCAN_PRIORITY_VERY_LOW,
+       SCAN_PRIORITY_LOW,
+       SCAN_PRIORITY_MEDIUM,
+       SCAN_PRIORITY_HIGH,
+       SCAN_PRIORITY_VERY_HIGH,
+       SCAN_PRIORITY_COUNT,
+};
+
+enum scan_dwelltime_adaptive_mode {
+       SCAN_DWELL_MODE_DEFAULT = 0,
+       SCAN_DWELL_MODE_CONSERVATIVE = 1,
+       SCAN_DWELL_MODE_MODERATE = 2,
+       SCAN_DWELL_MODE_AGGRESSIVE = 3,
+       SCAN_DWELL_MODE_STATIC = 4
+};
+
+#define WLAN_SCAN_MAX_NUM_SSID          10
+#define WLAN_SCAN_MAX_NUM_BSSID         10
+#define WLAN_SCAN_MAX_NUM_CHANNELS      40
+
+#define WLAN_SSID_MAX_LEN 32
+
+struct element_info {
+       u32 len;
+       u8 *ptr;
+};
+
+struct wlan_ssid {
+       u8 length;
+       u8 ssid[WLAN_SSID_MAX_LEN];
+};
+
+#define WMI_IE_BITMAP_SIZE             8
+
+#define WMI_SCAN_MAX_NUM_SSID                0x0A
+/* prefix used by scan requestor ids on the host */
+#define WMI_HOST_SCAN_REQUESTOR_ID_PREFIX 0xA000
+
+/* prefix used by scan request ids generated on the host */
+/* host cycles through the lower 12 bits to generate ids */
+#define WMI_HOST_SCAN_REQ_ID_PREFIX 0xA000
+
+#define WLAN_SCAN_PARAMS_MAX_SSID    16
+#define WLAN_SCAN_PARAMS_MAX_BSSID   4
+#define WLAN_SCAN_PARAMS_MAX_IE_LEN  256
+
+/* Values lower than this may be refused by some firmware revisions with a scan
+ * completion with a timedout reason.
+ */
+#define WMI_SCAN_CHAN_MIN_TIME_MSEC 40
+
+/* Scan priority numbers must be sequential, starting with 0 */
+enum wmi_scan_priority {
+       WMI_SCAN_PRIORITY_VERY_LOW = 0,
+       WMI_SCAN_PRIORITY_LOW,
+       WMI_SCAN_PRIORITY_MEDIUM,
+       WMI_SCAN_PRIORITY_HIGH,
+       WMI_SCAN_PRIORITY_VERY_HIGH,
+       WMI_SCAN_PRIORITY_COUNT   /* number of priorities supported */
+};
+
+enum wmi_scan_event_type {
+       WMI_SCAN_EVENT_STARTED              = BIT(0),
+       WMI_SCAN_EVENT_COMPLETED            = BIT(1),
+       WMI_SCAN_EVENT_BSS_CHANNEL          = BIT(2),
+       WMI_SCAN_EVENT_FOREIGN_CHAN         = BIT(3),
+       WMI_SCAN_EVENT_DEQUEUED             = BIT(4),
+       /* possibly by high-prio scan */
+       WMI_SCAN_EVENT_PREEMPTED            = BIT(5),
+       WMI_SCAN_EVENT_START_FAILED         = BIT(6),
+       WMI_SCAN_EVENT_RESTARTED            = BIT(7),
+       WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT    = BIT(8),
+       WMI_SCAN_EVENT_SUSPENDED            = BIT(9),
+       WMI_SCAN_EVENT_RESUMED              = BIT(10),
+       WMI_SCAN_EVENT_MAX                  = BIT(15),
+};
+
+enum wmi_scan_completion_reason {
+       WMI_SCAN_REASON_COMPLETED,
+       WMI_SCAN_REASON_CANCELLED,
+       WMI_SCAN_REASON_PREEMPTED,
+       WMI_SCAN_REASON_TIMEDOUT,
+       WMI_SCAN_REASON_INTERNAL_FAILURE,
+       WMI_SCAN_REASON_MAX,
+};
+
+struct  wmi_start_scan_cmd {
+       u32 tlv_header;
+       u32 scan_id;
+       u32 scan_req_id;
+       u32 vdev_id;
+       u32 scan_priority;
+       u32 notify_scan_events;
+       u32 dwell_time_active;
+       u32 dwell_time_passive;
+       u32 min_rest_time;
+       u32 max_rest_time;
+       u32 repeat_probe_time;
+       u32 probe_spacing_time;
+       u32 idle_time;
+       u32 max_scan_time;
+       u32 probe_delay;
+       u32 scan_ctrl_flags;
+       u32 burst_duration;
+       u32 num_chan;
+       u32 num_bssid;
+       u32 num_ssids;
+       u32 ie_len;
+       u32 n_probes;
+       struct wmi_mac_addr mac_addr;
+       struct wmi_mac_addr mac_mask;
+       u32 ie_bitmap[WMI_IE_BITMAP_SIZE];
+       u32 num_vendor_oui;
+       u32 scan_ctrl_flags_ext;
+       u32 dwell_time_active_2g;
+} __packed;
+
+#define WMI_SCAN_FLAG_PASSIVE        0x1
+#define WMI_SCAN_ADD_BCAST_PROBE_REQ 0x2
+#define WMI_SCAN_ADD_CCK_RATES       0x4
+#define WMI_SCAN_ADD_OFDM_RATES      0x8
+#define WMI_SCAN_CHAN_STAT_EVENT     0x10
+#define WMI_SCAN_FILTER_PROBE_REQ    0x20
+#define WMI_SCAN_BYPASS_DFS_CHN      0x40
+#define WMI_SCAN_CONTINUE_ON_ERROR   0x80
+#define WMI_SCAN_FILTER_PROMISCUOS   0x100
+#define WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS 0x200
+#define WMI_SCAN_ADD_TPC_IE_IN_PROBE_REQ  0x400
+#define WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ   0x800
+#define WMI_SCAN_ADD_SPOOF_MAC_IN_PROBE_REQ   0x1000
+#define WMI_SCAN_OFFCHAN_MGMT_TX    0x2000
+#define WMI_SCAN_OFFCHAN_DATA_TX    0x4000
+#define WMI_SCAN_CAPTURE_PHY_ERROR  0x8000
+#define WMI_SCAN_FLAG_STRICT_PASSIVE_ON_PCHN 0x10000
+#define WMI_SCAN_FLAG_HALF_RATE_SUPPORT      0x20000
+#define WMI_SCAN_FLAG_QUARTER_RATE_SUPPORT   0x40000
+#define WMI_SCAN_RANDOM_SEQ_NO_IN_PROBE_REQ 0x80000
+#define WMI_SCAN_ENABLE_IE_WHTELIST_IN_PROBE_REQ 0x100000
+
+#define WMI_SCAN_DWELL_MODE_MASK 0x00E00000
+#define WMI_SCAN_DWELL_MODE_SHIFT        21
+
+enum {
+       WMI_SCAN_DWELL_MODE_DEFAULT      = 0,
+       WMI_SCAN_DWELL_MODE_CONSERVATIVE = 1,
+       WMI_SCAN_DWELL_MODE_MODERATE     = 2,
+       WMI_SCAN_DWELL_MODE_AGGRESSIVE   = 3,
+       WMI_SCAN_DWELL_MODE_STATIC       = 4,
+};
+
+#define WMI_SCAN_SET_DWELL_MODE(flag, mode) \
+       ((flag) |= (((mode) << WMI_SCAN_DWELL_MODE_SHIFT) & \
+                   WMI_SCAN_DWELL_MODE_MASK))
+
+struct scan_req_params {
+       u32 scan_id;
+       u32 scan_req_id;
+       u32 vdev_id;
+       u32 pdev_id;
+       enum scan_priority scan_priority;
+       union {
+               struct {
+                       u32 scan_ev_started:1,
+                           scan_ev_completed:1,
+                           scan_ev_bss_chan:1,
+                           scan_ev_foreign_chan:1,
+                           scan_ev_dequeued:1,
+                           scan_ev_preempted:1,
+                           scan_ev_start_failed:1,
+                           scan_ev_restarted:1,
+                           scan_ev_foreign_chn_exit:1,
+                           scan_ev_invalid:1,
+                           scan_ev_gpio_timeout:1,
+                           scan_ev_suspended:1,
+                           scan_ev_resumed:1;
+               };
+               u32 scan_events;
+       };
+       u32 dwell_time_active;
+       u32 dwell_time_active_2g;
+       u32 dwell_time_passive;
+       u32 min_rest_time;
+       u32 max_rest_time;
+       u32 repeat_probe_time;
+       u32 probe_spacing_time;
+       u32 idle_time;
+       u32 max_scan_time;
+       u32 probe_delay;
+       union {
+               struct {
+                       u32 scan_f_passive:1,
+                           scan_f_bcast_probe:1,
+                           scan_f_cck_rates:1,
+                           scan_f_ofdm_rates:1,
+                           scan_f_chan_stat_evnt:1,
+                           scan_f_filter_prb_req:1,
+                           scan_f_bypass_dfs_chn:1,
+                           scan_f_continue_on_err:1,
+                           scan_f_offchan_mgmt_tx:1,
+                           scan_f_offchan_data_tx:1,
+                           scan_f_promisc_mode:1,
+                           scan_f_capture_phy_err:1,
+                           scan_f_strict_passive_pch:1,
+                           scan_f_half_rate:1,
+                           scan_f_quarter_rate:1,
+                           scan_f_force_active_dfs_chn:1,
+                           scan_f_add_tpc_ie_in_probe:1,
+                           scan_f_add_ds_ie_in_probe:1,
+                           scan_f_add_spoofed_mac_in_probe:1,
+                           scan_f_add_rand_seq_in_probe:1,
+                           scan_f_en_ie_whitelist_in_probe:1,
+                           scan_f_forced:1,
+                           scan_f_2ghz:1,
+                           scan_f_5ghz:1,
+                           scan_f_80mhz:1;
+               };
+               u32 scan_flags;
+       };
+       enum scan_dwelltime_adaptive_mode adaptive_dwell_time_mode;
+       u32 burst_duration;
+       u32 num_chan;
+       u32 num_bssid;
+       u32 num_ssids;
+       u32 n_probes;
+       u32 chan_list[WLAN_SCAN_MAX_NUM_CHANNELS];
+       u32 notify_scan_events;
+       struct wlan_ssid ssid[WLAN_SCAN_MAX_NUM_SSID];
+       struct wmi_mac_addr bssid_list[WLAN_SCAN_MAX_NUM_BSSID];
+       struct element_info extraie;
+       struct element_info htcap;
+       struct element_info vhtcap;
+};
+
+struct wmi_ssid_arg {
+       int len;
+       const u8 *ssid;
+};
+
+struct wmi_bssid_arg {
+       const u8 *bssid;
+};
+
+struct wmi_start_scan_arg {
+       u32 scan_id;
+       u32 scan_req_id;
+       u32 vdev_id;
+       u32 scan_priority;
+       u32 notify_scan_events;
+       u32 dwell_time_active;
+       u32 dwell_time_passive;
+       u32 min_rest_time;
+       u32 max_rest_time;
+       u32 repeat_probe_time;
+       u32 probe_spacing_time;
+       u32 idle_time;
+       u32 max_scan_time;
+       u32 probe_delay;
+       u32 scan_ctrl_flags;
+
+       u32 ie_len;
+       u32 n_channels;
+       u32 n_ssids;
+       u32 n_bssids;
+
+       u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN];
+       u32 channels[64];
+       struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID];
+       struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID];
+};
+
+#define WMI_SCAN_STOP_ONE       0x00000000
+#define WMI_SCN_STOP_VAP_ALL    0x01000000
+#define WMI_SCAN_STOP_ALL       0x04000000
+
+/* Prefix 0xA000 indicates that the scan request
+ * is trigger by HOST
+ */
+#define ATH11K_SCAN_ID          0xA000
+
+enum scan_cancel_req_type {
+       WLAN_SCAN_CANCEL_SINGLE = 1,
+       WLAN_SCAN_CANCEL_VDEV_ALL,
+       WLAN_SCAN_CANCEL_PDEV_ALL,
+};
+
+struct scan_cancel_param {
+       u32 requester;
+       u32 scan_id;
+       enum scan_cancel_req_type req_type;
+       u32 vdev_id;
+       u32 pdev_id;
+};
+
+struct  wmi_bcn_send_from_host_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 data_len;
+       union {
+               u32 frag_ptr;
+               u32 frag_ptr_lo;
+       };
+       u32 frame_ctrl;
+       u32 dtim_flag;
+       u32 bcn_antenna;
+       u32 frag_ptr_hi;
+};
+
+#define WMI_CHAN_INFO_MODE             GENMASK(5, 0)
+#define WMI_CHAN_INFO_HT40_PLUS                BIT(6)
+#define WMI_CHAN_INFO_PASSIVE          BIT(7)
+#define WMI_CHAN_INFO_ADHOC_ALLOWED    BIT(8)
+#define WMI_CHAN_INFO_AP_DISABLED      BIT(9)
+#define WMI_CHAN_INFO_DFS              BIT(10)
+#define WMI_CHAN_INFO_ALLOW_HT         BIT(11)
+#define WMI_CHAN_INFO_ALLOW_VHT                BIT(12)
+#define WMI_CHAN_INFO_CHAN_CHANGE_CAUSE_CSA    BIT(13)
+#define WMI_CHAN_INFO_HALF_RATE                BIT(14)
+#define WMI_CHAN_INFO_QUARTER_RATE     BIT(15)
+#define WMI_CHAN_INFO_DFS_FREQ2                BIT(16)
+#define WMI_CHAN_INFO_ALLOW_HE         BIT(17)
+
+#define WMI_CHAN_REG_INFO1_MIN_PWR     GENMASK(7, 0)
+#define WMI_CHAN_REG_INFO1_MAX_PWR     GENMASK(15, 8)
+#define WMI_CHAN_REG_INFO1_MAX_REG_PWR GENMASK(23, 16)
+#define WMI_CHAN_REG_INFO1_REG_CLS     GENMASK(31, 24)
+
+#define WMI_CHAN_REG_INFO2_ANT_MAX     GENMASK(7, 0)
+#define WMI_CHAN_REG_INFO2_MAX_TX_PWR  GENMASK(15, 8)
+
+struct wmi_channel {
+       u32 tlv_header;
+       u32 mhz;
+       u32 band_center_freq1;
+       u32 band_center_freq2;
+       u32 info;
+       u32 reg_info_1;
+       u32 reg_info_2;
+} __packed;
+
+struct wmi_mgmt_params {
+       void *tx_frame;
+       u16 frm_len;
+       u8 vdev_id;
+       u16 chanfreq;
+       void *pdata;
+       u16 desc_id;
+       u8 *macaddr;
+       void *qdf_ctx;
+};
+
+enum wmi_sta_ps_mode {
+       WMI_STA_PS_MODE_DISABLED = 0,
+       WMI_STA_PS_MODE_ENABLED = 1,
+};
+
+#define WMI_SMPS_MASK_LOWER_16BITS 0xFF
+#define WMI_SMPS_MASK_UPPER_3BITS 0x7
+#define WMI_SMPS_PARAM_VALUE_SHIFT 29
+
+#define ATH11K_WMI_FW_HANG_ASSERT_TYPE 1
+#define ATH11K_WMI_FW_HANG_DELAY 0
+
+/* type, 0:unused 1: ASSERT 2: not respond detect command
+ * delay_time_ms, the simulate will delay time
+ */
+
+struct wmi_force_fw_hang_cmd {
+       u32 tlv_header;
+       u32 type;
+       u32 delay_time_ms;
+};
+
+struct wmi_vdev_set_param_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 param_id;
+       u32 param_value;
+} __packed;
+
+enum wmi_stats_id {
+       WMI_REQUEST_PEER_STAT                   = BIT(0),
+       WMI_REQUEST_AP_STAT                     = BIT(1),
+       WMI_REQUEST_PDEV_STAT                   = BIT(2),
+       WMI_REQUEST_VDEV_STAT                   = BIT(3),
+       WMI_REQUEST_BCNFLT_STAT                 = BIT(4),
+       WMI_REQUEST_VDEV_RATE_STAT              = BIT(5),
+       WMI_REQUEST_INST_STAT                   = BIT(6),
+       WMI_REQUEST_MIB_STAT                    = BIT(7),
+       WMI_REQUEST_RSSI_PER_CHAIN_STAT         = BIT(8),
+       WMI_REQUEST_CONGESTION_STAT             = BIT(9),
+       WMI_REQUEST_PEER_EXTD_STAT              = BIT(10),
+       WMI_REQUEST_BCN_STAT                    = BIT(11),
+       WMI_REQUEST_BCN_STAT_RESET              = BIT(12),
+       WMI_REQUEST_PEER_EXTD2_STAT             = BIT(13),
+};
+
+struct wmi_request_stats_cmd {
+       u32 tlv_header;
+       enum wmi_stats_id stats_id;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 pdev_id;
+} __packed;
+
+#define WMI_BEACON_TX_BUFFER_SIZE      512
+
+struct wmi_bcn_tmpl_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 tim_ie_offset;
+       u32 buf_len;
+       u32 csa_switch_count_offset;
+       u32 ext_csa_switch_count_offset;
+       u32 csa_event_bitmap;
+       u32 mbssid_ie_offset;
+       u32 esp_ie_offset;
+} __packed;
+
+struct wmi_key_seq_counter {
+       u32 key_seq_counter_l;
+       u32 key_seq_counter_h;
+} __packed;
+
+struct wmi_vdev_install_key_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 key_idx;
+       u32 key_flags;
+       u32 key_cipher;
+       struct wmi_key_seq_counter key_rsc_counter;
+       struct wmi_key_seq_counter key_global_rsc_counter;
+       struct wmi_key_seq_counter key_tsc_counter;
+       u8 wpi_key_rsc_counter[16];
+       u8 wpi_key_tsc_counter[16];
+       u32 key_len;
+       u32 key_txmic_len;
+       u32 key_rxmic_len;
+       u32 is_group_key_id_valid;
+       u32 group_key_id;
+
+       /* Followed by key_data containing key followed by
+        * tx mic and then rx mic
+        */
+} __packed;
+
+struct wmi_vdev_install_key_arg {
+       u32 vdev_id;
+       const u8 *macaddr;
+       u32 key_idx;
+       u32 key_flags;
+       u32 key_cipher;
+       u32 key_len;
+       u32 key_txmic_len;
+       u32 key_rxmic_len;
+       u64 key_rsc_counter;
+       const void *key_data;
+};
+
+#define WMI_MAX_SUPPORTED_RATES                        128
+#define WMI_HOST_MAX_HECAP_PHY_SIZE            3
+#define WMI_HOST_MAX_HE_RATE_SET               1
+
+struct wmi_rate_set_arg {
+       u32 num_rates;
+       u8 rates[WMI_MAX_SUPPORTED_RATES];
+};
+
+struct peer_assoc_params {
+       struct wmi_mac_addr peer_macaddr;
+       u32 vdev_id;
+       u32 peer_new_assoc;
+       u32 peer_associd;
+       u32 peer_flags;
+       u32 peer_caps;
+       u32 peer_listen_intval;
+       u32 peer_ht_caps;
+       u32 peer_max_mpdu;
+       u32 peer_mpdu_density;
+       u32 peer_rate_caps;
+       u32 peer_nss;
+       u32 peer_vht_caps;
+       u32 peer_phymode;
+       u32 peer_ht_info[2];
+       struct wmi_rate_set_arg peer_legacy_rates;
+       struct wmi_rate_set_arg peer_ht_rates;
+       u32 rx_max_rate;
+       u32 rx_mcs_set;
+       u32 tx_max_rate;
+       u32 tx_mcs_set;
+       u8 vht_capable;
+       u32 tx_max_mcs_nss;
+       u32 peer_bw_rxnss_override;
+       bool is_pmf_enabled;
+       bool is_wme_set;
+       bool qos_flag;
+       bool apsd_flag;
+       bool ht_flag;
+       bool bw_40;
+       bool bw_80;
+       bool bw_160;
+       bool stbc_flag;
+       bool ldpc_flag;
+       bool static_mimops_flag;
+       bool dynamic_mimops_flag;
+       bool spatial_mux_flag;
+       bool vht_flag;
+       bool vht_ng_flag;
+       bool need_ptk_4_way;
+       bool need_gtk_2_way;
+       bool auth_flag;
+       bool safe_mode_enabled;
+       bool amsdu_disable;
+       /* Use common structure */
+       u8 peer_mac[ETH_ALEN];
+
+       bool he_flag;
+       u32 peer_he_cap_macinfo[2];
+       u32 peer_he_cap_macinfo_internal;
+       u32 peer_he_ops;
+       u32 peer_he_cap_phyinfo[WMI_HOST_MAX_HECAP_PHY_SIZE];
+       u32 peer_he_mcs_count;
+       u32 peer_he_rx_mcs_set[WMI_HOST_MAX_HE_RATE_SET];
+       u32 peer_he_tx_mcs_set[WMI_HOST_MAX_HE_RATE_SET];
+       struct ath11k_ppe_threshold peer_ppet;
+};
+
+struct  wmi_peer_assoc_complete_cmd {
+       u32 tlv_header;
+       struct wmi_mac_addr peer_macaddr;
+       u32 vdev_id;
+       u32 peer_new_assoc;
+       u32 peer_associd;
+       u32 peer_flags;
+       u32 peer_caps;
+       u32 peer_listen_intval;
+       u32 peer_ht_caps;
+       u32 peer_max_mpdu;
+       u32 peer_mpdu_density;
+       u32 peer_rate_caps;
+       u32 peer_nss;
+       u32 peer_vht_caps;
+       u32 peer_phymode;
+       u32 peer_ht_info[2];
+       u32 num_peer_legacy_rates;
+       u32 num_peer_ht_rates;
+       u32 peer_bw_rxnss_override;
+       struct  wmi_ppe_threshold peer_ppet;
+       u32 peer_he_cap_info;
+       u32 peer_he_ops;
+       u32 peer_he_cap_phy[WMI_MAX_HECAP_PHY_SIZE];
+       u32 peer_he_mcs;
+       u32 peer_he_cap_info_ext;
+       u32 peer_he_cap_info_internal;
+} __packed;
+
+struct wmi_stop_scan_cmd {
+       u32 tlv_header;
+       u32 requestor;
+       u32 scan_id;
+       u32 req_type;
+       u32 vdev_id;
+       u32 pdev_id;
+};
+
+struct scan_chan_list_params {
+       u32 pdev_id;
+       u16 nallchans;
+       struct channel_param ch_param[1];
+};
+
+struct wmi_scan_chan_list_cmd {
+       u32 tlv_header;
+       u32 num_scan_chans;
+       u32 flags;
+       u32 pdev_id;
+} __packed;
+
+#define WMI_MGMT_SEND_DOWNLD_LEN       64
+
+#define WMI_TX_PARAMS_DWORD0_POWER             GENMASK(7, 0)
+#define WMI_TX_PARAMS_DWORD0_MCS_MASK          GENMASK(19, 8)
+#define WMI_TX_PARAMS_DWORD0_NSS_MASK          GENMASK(27, 20)
+#define WMI_TX_PARAMS_DWORD0_RETRY_LIMIT       GENMASK(31, 28)
+
+#define WMI_TX_PARAMS_DWORD1_CHAIN_MASK                GENMASK(7, 0)
+#define WMI_TX_PARAMS_DWORD1_BW_MASK           GENMASK(14, 8)
+#define WMI_TX_PARAMS_DWORD1_PREAMBLE_TYPE     GENMASK(19, 15)
+#define WMI_TX_PARAMS_DWORD1_FRAME_TYPE                BIT(20)
+#define WMI_TX_PARAMS_DWORD1_RSVD              GENMASK(31, 21)
+
+struct wmi_mgmt_send_params {
+       u32 tlv_header;
+       u32 tx_params_dword0;
+       u32 tx_params_dword1;
+};
+
+struct wmi_mgmt_send_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 desc_id;
+       u32 chanfreq;
+       u32 paddr_lo;
+       u32 paddr_hi;
+       u32 frame_len;
+       u32 buf_len;
+       u32 tx_params_valid;
+
+       /* This TLV is followed by struct wmi_mgmt_frame */
+
+       /* Followed by struct wmi_mgmt_send_params */
+} __packed;
+
+struct wmi_sta_powersave_mode_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 sta_ps_mode;
+};
+
+struct wmi_sta_smps_force_mode_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 forced_mode;
+};
+
+struct wmi_sta_smps_param_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 param;
+       u32 value;
+};
+
+struct wmi_bcn_prb_info {
+       u32 tlv_header;
+       u32 caps;
+       u32 erp;
+} __packed;
+
+enum {
+       WMI_PDEV_SUSPEND,
+       WMI_PDEV_SUSPEND_AND_DISABLE_INTR,
+};
+
+struct green_ap_ps_params {
+       u32 value;
+};
+
+struct wmi_pdev_green_ap_ps_enable_cmd_param {
+       u32 tlv_header;
+       u32 pdev_id;
+       u32 enable;
+};
+
+struct ap_ps_params {
+       u32 vdev_id;
+       u32 param;
+       u32 value;
+};
+
+struct vdev_set_params {
+       u32 if_id;
+       u32 param_id;
+       u32 param_value;
+};
+
+struct stats_request_params {
+       u32 stats_id;
+       u32 vdev_id;
+       u32 pdev_id;
+};
+
+enum set_init_cc_type {
+       WMI_COUNTRY_INFO_TYPE_ALPHA,
+       WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE,
+       WMI_COUNTRY_INFO_TYPE_REGDOMAIN,
+};
+
+enum set_init_cc_flags {
+       INVALID_CC,
+       CC_IS_SET,
+       REGDMN_IS_SET,
+       ALPHA_IS_SET,
+};
+
+struct wmi_init_country_params {
+       union {
+               u16 country_code;
+               u16 regdom_id;
+               u8 alpha2[3];
+       } cc_info;
+       enum set_init_cc_flags flags;
+};
+
+struct wmi_init_country_cmd {
+       u32 tlv_header;
+       u32 pdev_id;
+       u32 init_cc_type;
+       union {
+               u32 country_code;
+               u32 regdom_id;
+               u32 alpha2;
+       } cc_info;
+} __packed;
+
+struct wmi_pdev_pktlog_filter_info {
+       u32 tlv_header;
+       struct wmi_mac_addr peer_macaddr;
+} __packed;
+
+struct wmi_pdev_pktlog_filter_cmd {
+       u32 tlv_header;
+       u32 pdev_id;
+       u32 enable;
+       u32 filter_type;
+       u32 num_mac;
+} __packed;
+
+enum ath11k_wmi_pktlog_enable {
+       ATH11K_WMI_PKTLOG_ENABLE_AUTO  = 0,
+       ATH11K_WMI_PKTLOG_ENABLE_FORCE = 1,
+};
+
+struct wmi_pktlog_enable_cmd {
+       u32 tlv_header;
+       u32 pdev_id;
+       u32 evlist; /* WMI_PKTLOG_EVENT */
+       u32 enable;
+} __packed;
+
+struct wmi_pktlog_disable_cmd {
+       u32 tlv_header;
+       u32 pdev_id;
+} __packed;
+
+#define DFS_PHYERR_UNIT_TEST_CMD 0
+#define DFS_UNIT_TEST_MODULE   0x2b
+#define DFS_UNIT_TEST_TOKEN    0xAA
+
+enum dfs_test_args_idx {
+       DFS_TEST_CMDID = 0,
+       DFS_TEST_PDEV_ID,
+       DFS_TEST_RADAR_PARAM,
+       DFS_MAX_TEST_ARGS,
+};
+
+struct wmi_dfs_unit_test_arg {
+       u32 cmd_id;
+       u32 pdev_id;
+       u32 radar_param;
+};
+
+struct wmi_unit_test_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       u32 module_id;
+       u32 num_args;
+       u32 diag_token;
+       /* Followed by test args*/
+} __packed;
+
+#define MAX_SUPPORTED_RATES 128
+
+#define WMI_PEER_AUTH          0x00000001
+#define WMI_PEER_QOS           0x00000002
+#define WMI_PEER_NEED_PTK_4_WAY        0x00000004
+#define WMI_PEER_NEED_GTK_2_WAY        0x00000010
+#define WMI_PEER_HE            0x00000400
+#define WMI_PEER_APSD          0x00000800
+#define WMI_PEER_HT            0x00001000
+#define WMI_PEER_40MHZ         0x00002000
+#define WMI_PEER_STBC          0x00008000
+#define WMI_PEER_LDPC          0x00010000
+#define WMI_PEER_DYN_MIMOPS    0x00020000
+#define WMI_PEER_STATIC_MIMOPS 0x00040000
+#define WMI_PEER_SPATIAL_MUX   0x00200000
+#define WMI_PEER_VHT           0x02000000
+#define WMI_PEER_80MHZ         0x04000000
+#define WMI_PEER_PMF           0x08000000
+/* TODO: Place holder for WLAN_PEER_F_PS_PRESEND_REQUIRED = 0x10000000.
+ * Need to be cleaned up
+ */
+#define WMI_PEER_IS_P2P_CAPABLE        0x20000000
+#define WMI_PEER_160MHZ                0x40000000
+#define WMI_PEER_SAFEMODE_EN   0x80000000
+
+struct beacon_tmpl_params {
+       u8 vdev_id;
+       u32 tim_ie_offset;
+       u32 tmpl_len;
+       u32 tmpl_len_aligned;
+       u32 csa_switch_count_offset;
+       u32 ext_csa_switch_count_offset;
+       u8 *frm;
+};
+
+struct wmi_rate_set {
+       u32 num_rates;
+       u32 rates[(MAX_SUPPORTED_RATES / 4) + 1];
+};
+
+struct wmi_vht_rate_set {
+       u32 tlv_header;
+       u32 rx_max_rate;
+       u32 rx_mcs_set;
+       u32 tx_max_rate;
+       u32 tx_mcs_set;
+       u32 tx_max_mcs_nss;
+} __packed;
+
+struct wmi_he_rate_set {
+       u32 tlv_header;
+       u32 rx_mcs_set;
+       u32 tx_mcs_set;
+} __packed;
+
+#define MAX_REG_RULES 10
+#define REG_ALPHA2_LEN 2
+
+enum wmi_start_event_param {
+       WMI_VDEV_START_RESP_EVENT = 0,
+       WMI_VDEV_RESTART_RESP_EVENT,
+};
+
+struct wmi_vdev_start_resp_event {
+       u32 vdev_id;
+       u32 requestor_id;
+       enum wmi_start_event_param resp_type;
+       u32 status;
+       u32 chain_mask;
+       u32 smps_mode;
+       union {
+               u32 mac_id;
+               u32 pdev_id;
+       };
+       u32 cfgd_tx_streams;
+       u32 cfgd_rx_streams;
+} __packed;
+
+/* VDEV start response status codes */
+enum wmi_vdev_start_resp_status_code {
+       WMI_VDEV_START_RESPONSE_STATUS_SUCCESS = 0,
+       WMI_VDEV_START_RESPONSE_INVALID_VDEVID = 1,
+       WMI_VDEV_START_RESPONSE_NOT_SUPPORTED = 2,
+       WMI_VDEV_START_RESPONSE_DFS_VIOLATION = 3,
+       WMI_VDEV_START_RESPONSE_INVALID_REGDOMAIN = 4,
+};
+
+;
+enum cc_setting_code {
+       REG_SET_CC_STATUS_PASS = 0,
+       REG_CURRENT_ALPHA2_NOT_FOUND = 1,
+       REG_INIT_ALPHA2_NOT_FOUND = 2,
+       REG_SET_CC_CHANGE_NOT_ALLOWED = 3,
+       REG_SET_CC_STATUS_NO_MEMORY = 4,
+       REG_SET_CC_STATUS_FAIL = 5,
+};
+
+/* Regaulatory Rule Flags Passed by FW */
+#define REGULATORY_CHAN_DISABLED     BIT(0)
+#define REGULATORY_CHAN_NO_IR        BIT(1)
+#define REGULATORY_CHAN_RADAR        BIT(3)
+#define REGULATORY_CHAN_NO_OFDM      BIT(6)
+#define REGULATORY_CHAN_INDOOR_ONLY  BIT(9)
+
+#define REGULATORY_CHAN_NO_HT40      BIT(4)
+#define REGULATORY_CHAN_NO_80MHZ     BIT(7)
+#define REGULATORY_CHAN_NO_160MHZ    BIT(8)
+#define REGULATORY_CHAN_NO_20MHZ     BIT(11)
+#define REGULATORY_CHAN_NO_10MHZ     BIT(12)
+
+enum {
+       WMI_REG_SET_CC_STATUS_PASS = 0,
+       WMI_REG_CURRENT_ALPHA2_NOT_FOUND = 1,
+       WMI_REG_INIT_ALPHA2_NOT_FOUND = 2,
+       WMI_REG_SET_CC_CHANGE_NOT_ALLOWED = 3,
+       WMI_REG_SET_CC_STATUS_NO_MEMORY = 4,
+       WMI_REG_SET_CC_STATUS_FAIL = 5,
+};
+
+struct cur_reg_rule {
+       u16 start_freq;
+       u16 end_freq;
+       u16 max_bw;
+       u8 reg_power;
+       u8 ant_gain;
+       u16 flags;
+};
+
+struct cur_regulatory_info {
+       enum cc_setting_code status_code;
+       u8 num_phy;
+       u8 phy_id;
+       u16 reg_dmn_pair;
+       u16 ctry_code;
+       u8 alpha2[REG_ALPHA2_LEN + 1];
+       u32 dfs_region;
+       u32 phybitmap;
+       u32 min_bw_2g;
+       u32 max_bw_2g;
+       u32 min_bw_5g;
+       u32 max_bw_5g;
+       u32 num_2g_reg_rules;
+       u32 num_5g_reg_rules;
+       struct cur_reg_rule *reg_rules_2g_ptr;
+       struct cur_reg_rule *reg_rules_5g_ptr;
+};
+
+struct wmi_reg_chan_list_cc_event {
+       u32 status_code;
+       u32 phy_id;
+       u32 alpha2;
+       u32 num_phy;
+       u32 country_id;
+       u32 domain_code;
+       u32 dfs_region;
+       u32 phybitmap;
+       u32 min_bw_2g;
+       u32 max_bw_2g;
+       u32 min_bw_5g;
+       u32 max_bw_5g;
+       u32 num_2g_reg_rules;
+       u32 num_5g_reg_rules;
+} __packed;
+
+struct wmi_regulatory_rule_struct {
+       u32  tlv_header;
+       u32  freq_info;
+       u32  bw_pwr_info;
+       u32  flag_info;
+};
+
+struct wmi_peer_delete_resp_event {
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+} __packed;
+
+struct wmi_bcn_tx_status_event {
+       u32 vdev_id;
+       u32 tx_status;
+} __packed;
+
+struct wmi_vdev_stopped_event {
+       u32 vdev_id;
+} __packed;
+
+struct wmi_pdev_bss_chan_info_event {
+       u32 pdev_id;
+       u32 freq;       /* Units in MHz */
+       u32 noise_floor;        /* units are dBm */
+       /* rx clear - how often the channel was unused */
+       u32 rx_clear_count_low;
+       u32 rx_clear_count_high;
+       /* cycle count - elapsed time during measured period, in clock ticks */
+       u32 cycle_count_low;
+       u32 cycle_count_high;
+       /* tx cycle count - elapsed time spent in tx, in clock ticks */
+       u32 tx_cycle_count_low;
+       u32 tx_cycle_count_high;
+       /* rx cycle count - elapsed time spent in rx, in clock ticks */
+       u32 rx_cycle_count_low;
+       u32 rx_cycle_count_high;
+       /*rx_cycle cnt for my bss in 64bits format */
+       u32 rx_bss_cycle_count_low;
+       u32 rx_bss_cycle_count_high;
+} __packed;
+
+#define WMI_VDEV_INSTALL_KEY_COMPL_STATUS_SUCCESS 0
+
+struct wmi_vdev_install_key_compl_event {
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 key_idx;
+       u32 key_flags;
+       u32 status;
+} __packed;
+
+struct wmi_vdev_install_key_complete_arg {
+       u32 vdev_id;
+       const u8 *macaddr;
+       u32 key_idx;
+       u32 key_flags;
+       u32 status;
+};
+
+struct wmi_peer_assoc_conf_event {
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+} __packed;
+
+struct wmi_peer_assoc_conf_arg {
+       u32 vdev_id;
+       const u8 *macaddr;
+};
+
+/*
+ * PDEV statistics
+ */
+struct wmi_pdev_stats_base {
+       s32 chan_nf;
+       u32 tx_frame_count; /* Cycles spent transmitting frames */
+       u32 rx_frame_count; /* Cycles spent receiving frames */
+       u32 rx_clear_count; /* Total channel busy time, evidently */
+       u32 cycle_count; /* Total on-channel time */
+       u32 phy_err_count;
+       u32 chan_tx_pwr;
+} __packed;
+
+struct wmi_pdev_stats_extra {
+       u32 ack_rx_bad;
+       u32 rts_bad;
+       u32 rts_good;
+       u32 fcs_bad;
+       u32 no_beacons;
+       u32 mib_int_count;
+} __packed;
+
+struct wmi_pdev_stats_tx {
+       /* Num HTT cookies queued to dispatch list */
+       s32 comp_queued;
+
+       /* Num HTT cookies dispatched */
+       s32 comp_delivered;
+
+       /* Num MSDU queued to WAL */
+       s32 msdu_enqued;
+
+       /* Num MPDU queue to WAL */
+       s32 mpdu_enqued;
+
+       /* Num MSDUs dropped by WMM limit */
+       s32 wmm_drop;
+
+       /* Num Local frames queued */
+       s32 local_enqued;
+
+       /* Num Local frames done */
+       s32 local_freed;
+
+       /* Num queued to HW */
+       s32 hw_queued;
+
+       /* Num PPDU reaped from HW */
+       s32 hw_reaped;
+
+       /* Num underruns */
+       s32 underrun;
+
+       /* Num PPDUs cleaned up in TX abort */
+       s32 tx_abort;
+
+       /* Num MPDUs requed by SW */
+       s32 mpdus_requed;
+
+       /* excessive retries */
+       u32 tx_ko;
+
+       /* data hw rate code */
+       u32 data_rc;
+
+       /* Scheduler self triggers */
+       u32 self_triggers;
+
+       /* frames dropped due to excessive sw retries */
+       u32 sw_retry_failure;
+
+       /* illegal rate phy errors  */
+       u32 illgl_rate_phy_err;
+
+       /* wal pdev continuous xretry */
+       u32 pdev_cont_xretry;
+
+       /* wal pdev tx timeouts */
+       u32 pdev_tx_timeout;
+
+       /* wal pdev resets  */
+       u32 pdev_resets;
+
+       /* frames dropped due to non-availability of stateless TIDs */
+       u32 stateless_tid_alloc_failure;
+
+       /* PhY/BB underrun */
+       u32 phy_underrun;
+
+       /* MPDU is more than txop limit */
+       u32 txop_ovf;
+} __packed;
+
+struct wmi_pdev_stats_rx {
+       /* Cnts any change in ring routing mid-ppdu */
+       s32 mid_ppdu_route_change;
+
+       /* Total number of statuses processed */
+       s32 status_rcvd;
+
+       /* Extra frags on rings 0-3 */
+       s32 r0_frags;
+       s32 r1_frags;
+       s32 r2_frags;
+       s32 r3_frags;
+
+       /* MSDUs / MPDUs delivered to HTT */
+       s32 htt_msdus;
+       s32 htt_mpdus;
+
+       /* MSDUs / MPDUs delivered to local stack */
+       s32 loc_msdus;
+       s32 loc_mpdus;
+
+       /* AMSDUs that have more MSDUs than the status ring size */
+       s32 oversize_amsdu;
+
+       /* Number of PHY errors */
+       s32 phy_errs;
+
+       /* Number of PHY errors drops */
+       s32 phy_err_drop;
+
+       /* Number of mpdu errors - FCS, MIC, ENC etc. */
+       s32 mpdu_errs;
+} __packed;
+
+struct wmi_pdev_stats {
+       struct wmi_pdev_stats_base base;
+       struct wmi_pdev_stats_tx tx;
+       struct wmi_pdev_stats_rx rx;
+} __packed;
+
+#define WLAN_MAX_AC 4
+#define MAX_TX_RATE_VALUES 10
+#define MAX_TX_RATE_VALUES 10
+
+struct wmi_vdev_stats {
+       u32 vdev_id;
+       u32 beacon_snr;
+       u32 data_snr;
+       u32 num_tx_frames[WLAN_MAX_AC];
+       u32 num_rx_frames;
+       u32 num_tx_frames_retries[WLAN_MAX_AC];
+       u32 num_tx_frames_failures[WLAN_MAX_AC];
+       u32 num_rts_fail;
+       u32 num_rts_success;
+       u32 num_rx_err;
+       u32 num_rx_discard;
+       u32 num_tx_not_acked;
+       u32 tx_rate_history[MAX_TX_RATE_VALUES];
+       u32 beacon_rssi_history[MAX_TX_RATE_VALUES];
+} __packed;
+
+struct wmi_bcn_stats {
+       u32 vdev_id;
+       u32 tx_bcn_succ_cnt;
+       u32 tx_bcn_outage_cnt;
+} __packed;
+
+struct wmi_stats_event {
+       u32 stats_id;
+       u32 num_pdev_stats;
+       u32 num_vdev_stats;
+       u32 num_peer_stats;
+       u32 num_bcnflt_stats;
+       u32 num_chan_stats;
+       u32 num_mib_stats;
+       u32 pdev_id;
+       u32 num_bcn_stats;
+       u32 num_peer_extd_stats;
+       u32 num_peer_extd2_stats;
+} __packed;
+
+struct wmi_pdev_ctl_failsafe_chk_event {
+       u32 pdev_id;
+       u32 ctl_failsafe_status;
+} __packed;
+
+struct wmi_pdev_csa_switch_ev {
+       u32 pdev_id;
+       u32 current_switch_count;
+       u32 num_vdevs;
+} __packed;
+
+struct wmi_pdev_radar_ev {
+       u32 pdev_id;
+       u32 detection_mode;
+       u32 chan_freq;
+       u32 chan_width;
+       u32 detector_id;
+       u32 segment_id;
+       u32 timestamp;
+       u32 is_chirp;
+       s32 freq_offset;
+       s32 sidx;
+} __packed;
+
+#define WMI_RX_STATUS_OK                       0x00
+#define WMI_RX_STATUS_ERR_CRC                  0x01
+#define WMI_RX_STATUS_ERR_DECRYPT              0x08
+#define WMI_RX_STATUS_ERR_MIC                  0x10
+#define WMI_RX_STATUS_ERR_KEY_CACHE_MISS       0x20
+
+#define WLAN_MGMT_TXRX_HOST_MAX_ANTENNA 4
+
+struct mgmt_rx_event_params {
+       u32 channel;
+       u32 snr;
+       u8 rssi_ctl[WLAN_MGMT_TXRX_HOST_MAX_ANTENNA];
+       u32 rate;
+       enum wmi_phy_mode phy_mode;
+       u32 buf_len;
+       int status;
+       u32 flags;
+       int rssi;
+       u32 tsf_delta;
+       u8 pdev_id;
+};
+
+#define ATH_MAX_ANTENNA 4
+
+struct wmi_mgmt_rx_hdr {
+       u32 channel;
+       u32 snr;
+       u32 rate;
+       u32 phy_mode;
+       u32 buf_len;
+       u32 status;
+       u32 rssi_ctl[ATH_MAX_ANTENNA];
+       u32 flags;
+       int rssi;
+       u32 tsf_delta;
+       u32 rx_tsf_l32;
+       u32 rx_tsf_u32;
+       u32 pdev_id;
+} __packed;
+
+#define MAX_ANTENNA_EIGHT 8
+
+struct wmi_rssi_ctl_ext {
+       u32 tlv_header;
+       u32 rssi_ctl_ext[MAX_ANTENNA_EIGHT - ATH_MAX_ANTENNA];
+};
+
+struct wmi_mgmt_tx_compl_event {
+       u32 desc_id;
+       u32 status;
+       u32 pdev_id;
+} __packed;
+
+struct wmi_scan_event {
+       u32 event_type; /* %WMI_SCAN_EVENT_ */
+       u32 reason; /* %WMI_SCAN_REASON_ */
+       u32 channel_freq; /* only valid for WMI_SCAN_EVENT_FOREIGN_CHANNEL */
+       u32 scan_req_id;
+       u32 scan_id;
+       u32 vdev_id;
+       /* TSF Timestamp when the scan event (%WMI_SCAN_EVENT_) is completed
+        * In case of AP it is TSF of the AP vdev
+        * In case of STA connected state, this is the TSF of the AP
+        * In case of STA not connected, it will be the free running HW timer
+        */
+       u32 tsf_timestamp;
+} __packed;
+
+struct wmi_peer_sta_kickout_arg {
+       const u8 *mac_addr;
+};
+
+struct wmi_peer_sta_kickout_event {
+       struct wmi_mac_addr peer_macaddr;
+} __packed;
+
+enum wmi_roam_reason {
+       WMI_ROAM_REASON_BETTER_AP = 1,
+       WMI_ROAM_REASON_BEACON_MISS = 2,
+       WMI_ROAM_REASON_LOW_RSSI = 3,
+       WMI_ROAM_REASON_SUITABLE_AP_FOUND = 4,
+       WMI_ROAM_REASON_HO_FAILED = 5,
+
+       /* keep last */
+       WMI_ROAM_REASON_MAX,
+};
+
+struct wmi_roam_event {
+       u32 vdev_id;
+       u32 reason;
+       u32 rssi;
+} __packed;
+
+#define WMI_CHAN_INFO_START_RESP 0
+#define WMI_CHAN_INFO_END_RESP 1
+
+struct wmi_chan_info_event {
+       u32 err_code;
+       u32 freq;
+       u32 cmd_flags;
+       u32 noise_floor;
+       u32 rx_clear_count;
+       u32 cycle_count;
+       u32 chan_tx_pwr_range;
+       u32 chan_tx_pwr_tp;
+       u32 rx_frame_count;
+       u32 my_bss_rx_cycle_count;
+       u32 rx_11b_mode_data_duration;
+       u32 tx_frame_cnt;
+       u32 mac_clk_mhz;
+       u32 vdev_id;
+} __packed;
+
+struct ath11k_targ_cap {
+       u32 phy_capability;
+       u32 max_frag_entry;
+       u32 num_rf_chains;
+       u32 ht_cap_info;
+       u32 vht_cap_info;
+       u32 vht_supp_mcs;
+       u32 hw_min_tx_power;
+       u32 hw_max_tx_power;
+       u32 sys_cap_info;
+       u32 min_pkt_size_enable;
+       u32 max_bcn_ie_size;
+       u32 max_num_scan_channels;
+       u32 max_supported_macs;
+       u32 wmi_fw_sub_feat_caps;
+       u32 txrx_chainmask;
+       u32 default_dbs_hw_mode_index;
+       u32 num_msdu_desc;
+};
+
+enum wmi_vdev_type {
+       WMI_VDEV_TYPE_AP      = 1,
+       WMI_VDEV_TYPE_STA     = 2,
+       WMI_VDEV_TYPE_IBSS    = 3,
+       WMI_VDEV_TYPE_MONITOR = 4,
+};
+
+enum wmi_vdev_subtype {
+       WMI_VDEV_SUBTYPE_NONE,
+       WMI_VDEV_SUBTYPE_P2P_DEVICE,
+       WMI_VDEV_SUBTYPE_P2P_CLIENT,
+       WMI_VDEV_SUBTYPE_P2P_GO,
+       WMI_VDEV_SUBTYPE_PROXY_STA,
+       WMI_VDEV_SUBTYPE_MESH_NON_11S,
+       WMI_VDEV_SUBTYPE_MESH_11S,
+};
+
+enum wmi_sta_powersave_param {
+       WMI_STA_PS_PARAM_RX_WAKE_POLICY = 0,
+       WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD = 1,
+       WMI_STA_PS_PARAM_PSPOLL_COUNT = 2,
+       WMI_STA_PS_PARAM_INACTIVITY_TIME = 3,
+       WMI_STA_PS_PARAM_UAPSD = 4,
+};
+
+#define WMI_UAPSD_AC_TYPE_DELI 0
+#define WMI_UAPSD_AC_TYPE_TRIG 1
+
+#define WMI_UAPSD_AC_BIT_MASK(ac, type) \
+       ((type ==  WMI_UAPSD_AC_TYPE_DELI) ? \
+        (1 << (ac << 1)) : (1 << ((ac << 1) + 1)))
+
+enum wmi_sta_ps_param_uapsd {
+       WMI_STA_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0),
+       WMI_STA_PS_UAPSD_AC0_TRIGGER_EN  = (1 << 1),
+       WMI_STA_PS_UAPSD_AC1_DELIVERY_EN = (1 << 2),
+       WMI_STA_PS_UAPSD_AC1_TRIGGER_EN  = (1 << 3),
+       WMI_STA_PS_UAPSD_AC2_DELIVERY_EN = (1 << 4),
+       WMI_STA_PS_UAPSD_AC2_TRIGGER_EN  = (1 << 5),
+       WMI_STA_PS_UAPSD_AC3_DELIVERY_EN = (1 << 6),
+       WMI_STA_PS_UAPSD_AC3_TRIGGER_EN  = (1 << 7),
+};
+
+#define WMI_STA_UAPSD_MAX_INTERVAL_MSEC UINT_MAX
+
+struct wmi_sta_uapsd_auto_trig_param {
+       u32 wmm_ac;
+       u32 user_priority;
+       u32 service_interval;
+       u32 suspend_interval;
+       u32 delay_interval;
+};
+
+struct wmi_sta_uapsd_auto_trig_cmd_fixed_param {
+       u32 vdev_id;
+       struct wmi_mac_addr peer_macaddr;
+       u32 num_ac;
+};
+
+struct wmi_sta_uapsd_auto_trig_arg {
+       u32 wmm_ac;
+       u32 user_priority;
+       u32 service_interval;
+       u32 suspend_interval;
+       u32 delay_interval;
+};
+
+enum wmi_sta_ps_param_tx_wake_threshold {
+       WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER = 0,
+       WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS = 1,
+
+       /* Values greater than one indicate that many TX attempts per beacon
+        * interval before the STA will wake up
+        */
+};
+
+/* The maximum number of PS-Poll frames the FW will send in response to
+ * traffic advertised in TIM before waking up (by sending a null frame with PS
+ * = 0). Value 0 has a special meaning: there is no maximum count and the FW
+ * will send as many PS-Poll as are necessary to retrieve buffered BU. This
+ * parameter is used when the RX wake policy is
+ * WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD and ignored when the RX wake
+ * policy is WMI_STA_PS_RX_WAKE_POLICY_WAKE.
+ */
+enum wmi_sta_ps_param_pspoll_count {
+       WMI_STA_PS_PSPOLL_COUNT_NO_MAX = 0,
+       /* Values greater than 0 indicate the maximum numer of PS-Poll frames
+        * FW will send before waking up.
+        */
+};
+
+/* U-APSD configuration of peer station from (re)assoc request and TSPECs */
+enum wmi_ap_ps_param_uapsd {
+       WMI_AP_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0),
+       WMI_AP_PS_UAPSD_AC0_TRIGGER_EN  = (1 << 1),
+       WMI_AP_PS_UAPSD_AC1_DELIVERY_EN = (1 << 2),
+       WMI_AP_PS_UAPSD_AC1_TRIGGER_EN  = (1 << 3),
+       WMI_AP_PS_UAPSD_AC2_DELIVERY_EN = (1 << 4),
+       WMI_AP_PS_UAPSD_AC2_TRIGGER_EN  = (1 << 5),
+       WMI_AP_PS_UAPSD_AC3_DELIVERY_EN = (1 << 6),
+       WMI_AP_PS_UAPSD_AC3_TRIGGER_EN  = (1 << 7),
+};
+
+/* U-APSD maximum service period of peer station */
+enum wmi_ap_ps_peer_param_max_sp {
+       WMI_AP_PS_PEER_PARAM_MAX_SP_UNLIMITED = 0,
+       WMI_AP_PS_PEER_PARAM_MAX_SP_2 = 1,
+       WMI_AP_PS_PEER_PARAM_MAX_SP_4 = 2,
+       WMI_AP_PS_PEER_PARAM_MAX_SP_6 = 3,
+       MAX_WMI_AP_PS_PEER_PARAM_MAX_SP,
+};
+
+enum wmi_ap_ps_peer_param {
+       /** Set uapsd configuration for a given peer.
+        *
+        * This include the delivery and trigger enabled state for each AC.
+        * The host MLME needs to set this based on AP capability and stations
+        * request Set in the association request  received from the station.
+        *
+        * Lower 8 bits of the value specify the UAPSD configuration.
+        *
+        * (see enum wmi_ap_ps_param_uapsd)
+        * The default value is 0.
+        */
+       WMI_AP_PS_PEER_PARAM_UAPSD = 0,
+
+       /**
+        * Set the service period for a UAPSD capable station
+        *
+        * The service period from wme ie in the (re)assoc request frame.
+        *
+        * (see enum wmi_ap_ps_peer_param_max_sp)
+        */
+       WMI_AP_PS_PEER_PARAM_MAX_SP = 1,
+
+       /** Time in seconds for aging out buffered frames
+        * for STA in power save
+        */
+       WMI_AP_PS_PEER_PARAM_AGEOUT_TIME = 2,
+
+       /** Specify frame types that are considered SIFS
+        * RESP trigger frame
+        */
+       WMI_AP_PS_PEER_PARAM_SIFS_RESP_FRMTYPE = 3,
+
+       /** Specifies the trigger state of TID.
+        * Valid only for UAPSD frame type
+        */
+       WMI_AP_PS_PEER_PARAM_SIFS_RESP_UAPSD = 4,
+
+       /* Specifies the WNM sleep state of a STA */
+       WMI_AP_PS_PEER_PARAM_WNM_SLEEP = 5,
+};
+
+#define DISABLE_SIFS_RESPONSE_TRIGGER 0
+
+#define WMI_MAX_KEY_INDEX   3
+#define WMI_MAX_KEY_LEN     32
+
+#define WMI_KEY_PAIRWISE 0x00
+#define WMI_KEY_GROUP    0x01
+
+#define WMI_CIPHER_NONE     0x0 /* clear key */
+#define WMI_CIPHER_WEP      0x1
+#define WMI_CIPHER_TKIP     0x2
+#define WMI_CIPHER_AES_OCB  0x3
+#define WMI_CIPHER_AES_CCM  0x4
+#define WMI_CIPHER_WAPI     0x5
+#define WMI_CIPHER_CKIP     0x6
+#define WMI_CIPHER_AES_CMAC 0x7
+#define WMI_CIPHER_ANY      0x8
+#define WMI_CIPHER_AES_GCM  0x9
+#define WMI_CIPHER_AES_GMAC 0xa
+
+/* Value to disable fixed rate setting */
+#define WMI_FIXED_RATE_NONE    (0xffff)
+
+#define ATH11K_RC_VERSION_OFFSET       28
+#define ATH11K_RC_PREAMBLE_OFFSET      8
+#define ATH11K_RC_NSS_OFFSET           5
+
+#define ATH11K_HW_RATE_CODE(rate, nss, preamble)       \
+       ((1 << ATH11K_RC_VERSION_OFFSET) |              \
+        ((nss) << ATH11K_RC_NSS_OFFSET) |              \
+        ((preamble) << ATH11K_RC_PREAMBLE_OFFSET) |    \
+        (rate))
+
+/* Preamble types to be used with VDEV fixed rate configuration */
+enum wmi_rate_preamble {
+       WMI_RATE_PREAMBLE_OFDM,
+       WMI_RATE_PREAMBLE_CCK,
+       WMI_RATE_PREAMBLE_HT,
+       WMI_RATE_PREAMBLE_VHT,
+       WMI_RATE_PREAMBLE_HE,
+};
+
+/**
+ * enum wmi_rtscts_prot_mode - Enable/Disable RTS/CTS and CTS2Self Protection.
+ * @WMI_RTS_CTS_DISABLED : RTS/CTS protection is disabled.
+ * @WMI_USE_RTS_CTS : RTS/CTS Enabled.
+ * @WMI_USE_CTS2SELF : CTS to self protection Enabled.
+ */
+enum wmi_rtscts_prot_mode {
+       WMI_RTS_CTS_DISABLED = 0,
+       WMI_USE_RTS_CTS = 1,
+       WMI_USE_CTS2SELF = 2,
+};
+
+/**
+ * enum wmi_rtscts_profile - Selection of RTS CTS profile along with enabling
+ *                           protection mode.
+ * @WMI_RTSCTS_FOR_NO_RATESERIES - Neither of rate-series should use RTS-CTS
+ * @WMI_RTSCTS_FOR_SECOND_RATESERIES - Only second rate-series will use RTS-CTS
+ * @WMI_RTSCTS_ACROSS_SW_RETRIES - Only the second rate-series will use RTS-CTS,
+ *                                 but if there's a sw retry, both the rate
+ *                                 series will use RTS-CTS.
+ * @WMI_RTSCTS_ERP - RTS/CTS used for ERP protection for every PPDU.
+ * @WMI_RTSCTS_FOR_ALL_RATESERIES - Enable RTS-CTS for all rate series.
+ */
+enum wmi_rtscts_profile {
+       WMI_RTSCTS_FOR_NO_RATESERIES = 0,
+       WMI_RTSCTS_FOR_SECOND_RATESERIES = 1,
+       WMI_RTSCTS_ACROSS_SW_RETRIES = 2,
+       WMI_RTSCTS_ERP = 3,
+       WMI_RTSCTS_FOR_ALL_RATESERIES = 4,
+};
+
+struct ath11k_hal_reg_cap {
+       u32 eeprom_rd;
+       u32 eeprom_rd_ext;
+       u32 regcap1;
+       u32 regcap2;
+       u32 wireless_modes;
+       u32 low_2ghz_chan;
+       u32 high_2ghz_chan;
+       u32 low_5ghz_chan;
+       u32 high_5ghz_chan;
+};
+
+struct ath11k_mem_chunk {
+       void *vaddr;
+       dma_addr_t paddr;
+       u32 len;
+       u32 req_id;
+};
+
+#define WMI_SKB_HEADROOM sizeof(struct wmi_cmd_hdr)
+
+enum wmi_sta_ps_param_rx_wake_policy {
+       WMI_STA_PS_RX_WAKE_POLICY_WAKE = 0,
+       WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD = 1,
+};
+
+enum ath11k_hw_txrx_mode {
+       ATH11K_HW_TXRX_RAW = 0,
+       ATH11K_HW_TXRX_NATIVE_WIFI = 1,
+       ATH11K_HW_TXRX_ETHERNET = 2,
+};
+
+struct wmi_wmm_params {
+       u32 tlv_header;
+       u32 cwmin;
+       u32 cwmax;
+       u32 aifs;
+       u32 txoplimit;
+       u32 acm;
+       u32 no_ack;
+} __packed;
+
+struct wmi_wmm_params_arg {
+       u8 acm;
+       u8 aifs;
+       u8 cwmin;
+       u8 cwmax;
+       u16 txop;
+       u8 no_ack;
+};
+
+struct wmi_vdev_set_wmm_params_cmd {
+       u32 tlv_header;
+       u32 vdev_id;
+       struct wmi_wmm_params wmm_params[4];
+       u32 wmm_param_type;
+} __packed;
+
+struct wmi_wmm_params_all_arg {
+       struct wmi_wmm_params_arg ac_be;
+       struct wmi_wmm_params_arg ac_bk;
+       struct wmi_wmm_params_arg ac_vi;
+       struct wmi_wmm_params_arg ac_vo;
+};
+
+struct target_resource_config {
+       u32 num_vdevs;
+       u32 num_peers;
+       u32 num_active_peers;
+       u32 num_offload_peers;
+       u32 num_offload_reorder_buffs;
+       u32 num_peer_keys;
+       u32 num_tids;
+       u32 ast_skid_limit;
+       u32 tx_chain_mask;
+       u32 rx_chain_mask;
+       u32 rx_timeout_pri[4];
+       u32 rx_decap_mode;
+       u32 scan_max_pending_req;
+       u32 bmiss_offload_max_vdev;
+       u32 roam_offload_max_vdev;
+       u32 roam_offload_max_ap_profiles;
+       u32 num_mcast_groups;
+       u32 num_mcast_table_elems;
+       u32 mcast2ucast_mode;
+       u32 tx_dbg_log_size;
+       u32 num_wds_entries;
+       u32 dma_burst_size;
+       u32 mac_aggr_delim;
+       u32 rx_skip_defrag_timeout_dup_detection_check;
+       u32 vow_config;
+       u32 gtk_offload_max_vdev;
+       u32 num_msdu_desc;
+       u32 max_frag_entries;
+       u32 max_peer_ext_stats;
+       u32 smart_ant_cap;
+       u32 bk_minfree;
+       u32 be_minfree;
+       u32 vi_minfree;
+       u32 vo_minfree;
+       u32 rx_batchmode;
+       u32 tt_support;
+       u32 atf_config;
+       u32 iphdr_pad_config;
+       u32 qwrap_config:16,
+           alloc_frag_desc_for_data_pkt:16;
+       u32 num_tdls_vdevs;
+       u32 num_tdls_conn_table_entries;
+       u32 beacon_tx_offload_max_vdev;
+       u32 num_multicast_filter_entries;
+       u32 num_wow_filters;
+       u32 num_keep_alive_pattern;
+       u32 keep_alive_pattern_size;
+       u32 max_tdls_concurrent_sleep_sta;
+       u32 max_tdls_concurrent_buffer_sta;
+       u32 wmi_send_separate;
+       u32 num_ocb_vdevs;
+       u32 num_ocb_channels;
+       u32 num_ocb_schedules;
+       u32 num_ns_ext_tuples_cfg;
+       u32 bpf_instruction_size;
+       u32 max_bssid_rx_filters;
+       u32 use_pdev_id;
+       u32 peer_map_unmap_v2_support;
+};
+
+#define WMI_MAX_MEM_REQS 32
+
+#define MAX_RADIOS 3
+
+#define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ)
+#define WMI_SEND_TIMEOUT_HZ (3 * HZ)
+
+struct ath11k_wmi_base {
+       struct ath11k_base *ab;
+       struct ath11k_pdev_wmi wmi[MAX_RADIOS];
+       enum ath11k_htc_ep_id wmi_endpoint_id[MAX_RADIOS];
+       u32 max_msg_len[MAX_RADIOS];
+
+       struct completion service_ready;
+       struct completion unified_ready;
+       DECLARE_BITMAP(svc_map, WMI_MAX_EXT_SERVICE);
+       wait_queue_head_t tx_credits_wq;
+       const struct wmi_peer_flags_map *peer_flags;
+       u32 num_mem_chunks;
+       u32 rx_decap_mode;
+       struct wmi_host_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];
+
+       enum wmi_host_hw_mode_config_type preferred_hw_mode;
+       struct target_resource_config  wlan_resource_config;
+
+       struct ath11k_targ_cap *targ_cap;
+};
+
+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);
+int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id,
+                        struct sk_buff *frame);
+int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id,
+                       struct ieee80211_mutable_offsets *offs,
+                       struct sk_buff *bcn);
+int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id);
+int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid,
+                      const u8 *bssid);
+int ath11k_wmi_vdev_stop(struct ath11k *ar, u8 vdev_id);
+int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg,
+                         bool restart);
+int ath11k_wmi_set_peer_param(struct ath11k *ar, const u8 *peer_addr,
+                             u32 vdev_id, u32 param_id, u32 param_val);
+int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id,
+                             u32 param_value, u8 pdev_id);
+int ath11k_wmi_wait_for_unified_ready(struct ath11k_base *ab);
+int ath11k_wmi_cmd_init(struct ath11k_base *ab);
+int ath11k_wmi_wait_for_service_ready(struct ath11k_base *ab);
+int ath11k_wmi_connect(struct ath11k_base *ab);
+int ath11k_wmi_pdev_attach(struct ath11k_base *ab,
+                          u8 pdev_id);
+int ath11k_wmi_attach(struct ath11k_base *ab);
+void ath11k_wmi_detach(struct ath11k_base *ab);
+int ath11k_wmi_vdev_create(struct ath11k *ar, u8 *macaddr,
+                          struct vdev_create_params *param);
+int ath11k_wmi_peer_rx_reorder_queue_setup(struct ath11k *ar, int vdev_id,
+                                          const u8 *addr, dma_addr_t paddr,
+                                          u8 tid, u8 ba_window_size_valid,
+                                          u32 ba_window_size);
+int ath11k_wmi_send_peer_create_cmd(struct ath11k *ar,
+                                   struct peer_create_params *param);
+int ath11k_wmi_vdev_set_param_cmd(struct ath11k *ar, u32 vdev_id,
+                                 u32 param_id, u32 param_value);
+
+int ath11k_wmi_set_sta_ps_param(struct ath11k *ar, u32 vdev_id,
+                               u32 param, u32 param_value);
+int ath11k_wmi_force_fw_hang_cmd(struct ath11k *ar, u32 type, u32 delay_time_ms);
+int ath11k_wmi_send_peer_delete_cmd(struct ath11k *ar,
+                                   const u8 *peer_addr, u8 vdev_id);
+int ath11k_wmi_vdev_delete(struct ath11k *ar, u8 vdev_id);
+void ath11k_wmi_start_scan_init(struct ath11k *ar, struct scan_req_params *arg);
+int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
+                                  struct scan_req_params *params);
+int ath11k_wmi_send_scan_stop_cmd(struct ath11k *ar,
+                                 struct scan_cancel_param *param);
+int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
+                                      struct wmi_wmm_params_all_arg *param);
+int ath11k_wmi_pdev_suspend(struct ath11k *ar, u32 suspend_opt,
+                           u32 pdev_id);
+int ath11k_wmi_pdev_resume(struct ath11k *ar, u32 pdev_id);
+
+int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar,
+                                  struct peer_assoc_params *param);
+int ath11k_wmi_vdev_install_key(struct ath11k *ar,
+                               struct wmi_vdev_install_key_arg *arg);
+int ath11k_wmi_pdev_bss_chan_info_request(struct ath11k *ar,
+                                         enum wmi_bss_chan_info_req_type type);
+int ath11k_wmi_send_stats_request_cmd(struct ath11k *ar,
+                                     struct stats_request_params *param);
+int ath11k_wmi_send_peer_flush_tids_cmd(struct ath11k *ar,
+                                       u8 peer_addr[ETH_ALEN],
+                                       struct peer_flush_params *param);
+int ath11k_wmi_send_set_ap_ps_param_cmd(struct ath11k *ar, u8 *peer_addr,
+                                       struct ap_ps_params *param);
+int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
+                                      struct scan_chan_list_params *chan_list);
+int ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath11k *ar,
+                                                 u32 pdev_id);
+int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar,
+                                           u32 vdev_id, u32 bcn_ctrl_op);
+int
+ath11k_wmi_send_init_country_cmd(struct ath11k *ar,
+                                struct wmi_init_country_params init_cc_param);
+int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter);
+int ath11k_wmi_pdev_pktlog_disable(struct ath11k *ar);
+int ath11k_wmi_pdev_peer_pktlog_filter(struct ath11k *ar, u8 *addr, u8 enable);
+int
+ath11k_wmi_rx_reord_queue_remove(struct ath11k *ar,
+                                struct rx_reorder_queue_remove_params *param);
+int ath11k_wmi_send_pdev_set_regdomain(struct ath11k *ar,
+                                      struct pdev_set_regdomain_params *param);
+int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb,
+                            struct ath11k_fw_stats *stats);
+size_t ath11k_wmi_fw_stats_num_peers(struct list_head *head);
+size_t ath11k_wmi_fw_stats_num_peers_extd(struct list_head *head);
+size_t ath11k_wmi_fw_stats_num_vdevs(struct list_head *head);
+void ath11k_wmi_fw_stats_fill(struct ath11k *ar,
+                             struct ath11k_fw_stats *fw_stats, u32 stats_id,
+                             char *buf);
+int ath11k_wmi_simulate_radar(struct ath11k *ar);
+#endif