From: "Yanli Yang" <yanli.yang@bedmex.com>
To: <linux-wireless@vger.kernel.org>
Cc: "Zhirun Liu" <zhirunliu@aicsemi.com>,
"Johannes Berg" <johannes@sipsolutions.net>,
"Dijia Xu" <dijiaxu@aicsemi.com>,
"Chunqiu Liu" <chunqiuliu@aicsemi.com>,
"Liheng Wei" <liheng.wei@bedmex.com>,
"Yanli Yang" <yanli.yang@bedmex.com>
Subject: [RFC PATCH wireless-next v4 2/4] wifi: aic: add FullMAC firmware and platform interface
Date: Sat, 29 Aug 2026 16:21:04 +0800 [thread overview]
Message-ID: <9d002f2a238c38ef40a3434ae47b4d91fa191840.1787991457.git.yanli.yang@bedmex.com> (raw)
In-Reply-To: <cover.1787991457.git.yanli.yang@bedmex.com>
From: Zhirun Liu <zhirunliu@aicsemi.com>
Add the LMAC message definitions, IPC host support, firmware command/event
handling and platform bring-up required by the AIC8800D80 U02 FullMAC
firmware.
The interface is scoped to the current in-tree kernel APIs and the SDIO
station baseline selected by the first patch.
Signed-off-by: Zhirun Liu <zhirunliu@aicsemi.com>
Signed-off-by: Yanli Yang <yanli.yang@bedmex.com>
---
.../aic/aic8800_fdrv/aic_bsp_export.h | 62 +
.../net/wireless/aic/aic8800_fdrv/aic_bus.h | 191 +
.../wireless/aic/aic8800_fdrv/aicwf_debug.h | 37 +
.../net/wireless/aic/aic8800_fdrv/hal_desc.h | 359 ++
.../wireless/aic/aic8800_fdrv/ipc_compat.h | 25 +
.../net/wireless/aic/aic8800_fdrv/ipc_host.c | 42 +
.../net/wireless/aic/aic8800_fdrv/ipc_host.h | 169 +
.../wireless/aic/aic8800_fdrv/ipc_shared.h | 770 ++++
.../net/wireless/aic/aic8800_fdrv/lmac_mac.h | 437 ++
.../net/wireless/aic/aic8800_fdrv/lmac_msg.h | 3101 ++++++++++++++
.../wireless/aic/aic8800_fdrv/lmac_types.h | 22 +
.../wireless/aic/aic8800_fdrv/reg_access.h | 146 +
.../net/wireless/aic/aic8800_fdrv/rwnx_cmds.c | 471 +++
.../net/wireless/aic/aic8800_fdrv/rwnx_cmds.h | 99 +
.../wireless/aic/aic8800_fdrv/rwnx_compat.h | 80 +
.../net/wireless/aic/aic8800_fdrv/rwnx_defs.h | 704 ++++
.../wireless/aic/aic8800_fdrv/rwnx_events.h | 938 +++++
.../net/wireless/aic/aic8800_fdrv/rwnx_irqs.c | 49 +
.../net/wireless/aic/aic8800_fdrv/rwnx_irqs.h | 12 +
.../wireless/aic/aic8800_fdrv/rwnx_msg_rx.c | 1614 ++++++++
.../wireless/aic/aic8800_fdrv/rwnx_msg_rx.h | 8 +
.../wireless/aic/aic8800_fdrv/rwnx_msg_tx.c | 3619 +++++++++++++++++
.../wireless/aic/aic8800_fdrv/rwnx_msg_tx.h | 266 ++
.../wireless/aic/aic8800_fdrv/rwnx_platform.c | 2868 +++++++++++++
.../wireless/aic/aic8800_fdrv/rwnx_platform.h | 183 +
.../net/wireless/aic/aic8800_fdrv/rwnx_prof.h | 142 +
.../net/wireless/aic/aic8800_fdrv/rwnx_strs.c | 269 ++
.../net/wireless/aic/aic8800_fdrv/rwnx_strs.h | 31 +
.../wireless/aic/aic8800_fdrv/rwnx_utils.c | 35 +
.../wireless/aic/aic8800_fdrv/rwnx_utils.h | 131 +
.../net/wireless/aic/aic8800_fdrv/rwnx_v7.c | 181 +
.../net/wireless/aic/aic8800_fdrv/rwnx_v7.h | 21 +
32 files changed, 17082 insertions(+)
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/aic_bsp_export.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/aic_bus.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/aicwf_debug.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/hal_desc.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/ipc_compat.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/ipc_host.c
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/ipc_host.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/ipc_shared.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/lmac_mac.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/lmac_msg.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/lmac_types.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/reg_access.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_cmds.c
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_cmds.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_compat.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_defs.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_events.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_irqs.c
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_irqs.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_rx.c
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_rx.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_tx.c
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_tx.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_platform.c
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_platform.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_prof.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_strs.c
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_strs.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_utils.c
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_utils.h
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_v7.c
create mode 100644 drivers/net/wireless/aic/aic8800_fdrv/rwnx_v7.h
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/aic_bsp_export.h b/drivers/net/wireless/aic/aic8800_fdrv/aic_bsp_export.h
new file mode 100644
index 0000000000000..11b414df42ce3
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/aic_bsp_export.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __AIC_BSP_EXPORT_H
+#define __AIC_BSP_EXPORT_H
+
+#include <linux/types.h>
+
+enum aicbsp_subsys {
+ AIC_BLUETOOTH,
+ AIC_WIFI,
+};
+
+enum aicbsp_pwr_state {
+ AIC_PWR_OFF,
+ AIC_PWR_ON,
+};
+
+struct aicbsp_feature_t {
+ int hwinfo;
+ u32 sdio_clock;
+ u8 sdio_phase;
+ int fwlog_en;
+ u8 irqf;
+ u8 cpmode;
+ int adapt;
+};
+
+enum skb_buff_id {
+ AIC_RESV_MEM_TXDATA,
+};
+
+#ifdef CONFIG_DPD
+struct rf_misc_ram_t {
+ u32 bit_mask[3];
+ u32 reserved;
+ u32 dpd_high[96];
+ u32 dpd_11b[96];
+ u32 dpd_low[96];
+ u32 idac_11b[48];
+ u32 idac_high[48];
+ u32 idac_low[48];
+ u32 loft_res[18];
+ u32 rx_iqim_res[16];
+};
+
+struct rf_misc_ram_lite_t {
+ u32 bit_mask[4];
+ u32 dpd_high[96];
+ u32 loft_res[18];
+};
+
+#define MEMBER_SIZE(type, member) sizeof_field(type, member)
+#define DPD_RESULT_SIZE_8800DC sizeof(struct rf_misc_ram_lite_t)
+
+extern struct rf_misc_ram_lite_t dpd_res;
+#endif
+
+int aicbsp_set_subsys(int, int);
+int aicbsp_get_feature(struct aicbsp_feature_t *feature);
+struct sk_buff *aicbsp_resv_mem_alloc_skb(unsigned int length, uint32_t id);
+void aicbsp_resv_mem_kfree_skb(struct sk_buff *skb, uint32_t id);
+
+#endif
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/aic_bus.h b/drivers/net/wireless/aic/aic8800_fdrv/aic_bus.h
new file mode 100644
index 0000000000000..2498d3d592b42
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/aic_bus.h
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2024 AIC semiconductor.
+ *
+ * @file aic_bus.h
+ * @brief Common bus abstraction layer for AIC8800 series.
+ *
+ * This header defines the bus-level operations that abstract the
+ * underlying transport (SDIO, USB, etc.) from the upper driver layers.
+ * The design follows the pattern used by silabs/wfx and broadcom/b43.
+ *
+ * Key principles:
+ * - struct aicwf_bus_ops provides a complete set of low-level bus
+ * primitives (read/write registers, send/recv packets, flow control,
+ * power management, interrupt handling).
+ * - Upper-layer code accesses the bus only through the ops table and
+ * inline wrappers defined here. It MUST NOT dereference the
+ * bus-private structure (aic_sdio_dev etc.) directly.
+ * - When a new transport (e.g. USB) is added, only the bus_ops
+ * implementation needs to change; upper layers are unaffected.
+ */
+
+#ifndef _AIC_BUS_H_
+#define _AIC_BUS_H_
+
+#include <linux/device.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+
+/* Bus operational state */
+enum aicwf_bus_state { BUS_DOWN_ST, BUS_UP_ST };
+
+struct aicwf_bus {
+ union {
+ struct aic_sdio_dev *sdio;
+ struct aic_usb_dev *usb;
+ } bus_priv;
+ struct device *dev;
+ struct aicwf_bus_ops *ops;
+ enum aicwf_bus_state state;
+ u8 *cmd_buf;
+ struct completion bustx_trgg;
+ struct completion busrx_trgg;
+ struct completion busirq_trgg; // new oob feature
+ struct task_struct *bustx_thread;
+ struct task_struct *busrx_thread;
+ struct task_struct *busirq_thread; // new oob feature
+};
+
+/* ================================================================
+ * Bus-level operation vectors
+ *
+ * Every transport (SDIO, USB, ...) provides one instance of this
+ * struct. The bus-private data pointer is carried inside
+ * struct aicwf_bus so that ops callbacks can retrieve it via
+ * bus->bus_priv.
+ * ================================================================
+ */
+
+struct aicwf_bus_ops {
+ /* ----- Lifecycle ----- */
+ int (*start)(struct device *dev);
+ void (*stop)(struct device *dev);
+
+ /* ----- Data / message transmission ----- */
+ int (*txdata)(struct device *dev, struct sk_buff *skb);
+ int (*txmsg)(struct device *dev, u8 *msg, uint len);
+
+ /* ----- Low-level register access -----
+ * These replace the direct aicwf_sdio_readb/writeb calls.
+ */
+ int (*read_reg)(struct device *dev, u32 regaddr, u8 *val);
+ int (*write_reg)(struct device *dev, u32 regaddr, u8 val);
+
+ /* ----- Bulk data transfer -----
+ * send_pkt – write a buffer to the chip's TX FIFO
+ * recv_pkt – read a buffer from the chip's RX FIFO
+ */
+ int (*send_pkt)(struct device *dev, u8 *buf, uint count);
+ int (*recv_pkt)(struct device *dev, u8 *buf, u32 size);
+
+ /* ----- Interrupt handling ----- */
+ int (*enable_irq)(struct device *dev);
+ void (*disable_irq)(struct device *dev);
+
+ /* ----- Flow control -----
+ * Returns true if the device is ready to accept more data.
+ */
+ bool (*flow_ctrl)(struct device *dev);
+
+ /* ----- Power management ----- */
+ int (*sleep_allow)(struct device *dev);
+ int (*wakeup)(struct device *dev);
+
+ /* ----- Chip-specific hardware info -----
+ * Returns a pointer to chip hardware properties (SDIO register
+ * layout, feature flags, etc.). The caller treats this as
+ * opaque; only the bus layer interprets it.
+ */
+ const void *(*get_hw_props)(struct device *dev);
+};
+
+/* ================================================================
+ * Inline wrappers – upper layers call these instead of touching
+ * bus_priv internals.
+ * ================================================================
+ */
+
+static inline int aicwf_bus_start(struct aicwf_bus *bus)
+{
+ return bus->ops->start(bus->dev);
+}
+
+static inline void aicwf_bus_stop(struct aicwf_bus *bus)
+{
+ bus->ops->stop(bus->dev);
+}
+
+static inline int aicwf_bus_txdata(struct aicwf_bus *bus, struct sk_buff *skb)
+{
+ return bus->ops->txdata(bus->dev, skb);
+}
+
+static inline int aicwf_bus_txmsg(struct aicwf_bus *bus, u8 *msg, uint len)
+{
+ return bus->ops->txmsg(bus->dev, msg, len);
+}
+
+static inline int aicwf_bus_read_reg(struct aicwf_bus *bus,
+ u32 regaddr, u8 *val)
+{
+ return bus->ops->read_reg(bus->dev, regaddr, val);
+}
+
+static inline int aicwf_bus_write_reg(struct aicwf_bus *bus,
+ u32 regaddr, u8 val)
+{
+ return bus->ops->write_reg(bus->dev, regaddr, val);
+}
+
+static inline int aicwf_bus_send_pkt(struct aicwf_bus *bus,
+ u8 *buf, uint count)
+{
+ return bus->ops->send_pkt(bus->dev, buf, count);
+}
+
+static inline int aicwf_bus_recv_pkt(struct aicwf_bus *bus,
+ u8 *buf, u32 size)
+{
+ return bus->ops->recv_pkt(bus->dev, buf, size);
+}
+
+static inline int aicwf_bus_enable_irq(struct aicwf_bus *bus)
+{
+ return bus->ops->enable_irq(bus->dev);
+}
+
+static inline void aicwf_bus_disable_irq(struct aicwf_bus *bus)
+{
+ bus->ops->disable_irq(bus->dev);
+}
+
+static inline bool aicwf_bus_flow_ctrl(struct aicwf_bus *bus)
+{
+ return bus->ops->flow_ctrl(bus->dev);
+}
+
+static inline int aicwf_bus_sleep_allow(struct aicwf_bus *bus)
+{
+ return bus->ops->sleep_allow(bus->dev);
+}
+
+static inline int aicwf_bus_wakeup(struct aicwf_bus *bus)
+{
+ return bus->ops->wakeup(bus->dev);
+}
+
+static inline const void *aicwf_bus_get_hw_props(struct aicwf_bus *bus)
+{
+ return bus->ops->get_hw_props(bus->dev);
+}
+
+/* ================================================================
+ * Bus-level init / deinit (shared across transports)
+ * ================================================================
+ */
+
+int aicwf_bus_init(uint bus_hdrlen, struct device *dev);
+void aicwf_bus_deinit(struct device *dev);
+
+#endif /* _AIC_BUS_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/aicwf_debug.h b/drivers/net/wireless/aic/aic8800_fdrv/aicwf_debug.h
new file mode 100644
index 0000000000000..4a49c16f15a31
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/aicwf_debug.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _AICWF_DEBUG_H_
+#define _AICWF_DEBUG_H_
+
+#define RWNX_FN_ENTRY_STR ">>> %s()\n", __func__
+
+/* message levels */
+#define LOGERROR 0x0001
+#define LOGINFO 0x0002
+#define LOGTRACE 0x0004
+#define LOGDEBUG 0x0008
+#define LOGDATA 0x0010
+#define LOGIRQ 0x0020
+#define LOGSDPWRC 0x0040
+#define LOGWAKELOCK 0x0080
+#define LOGRXPOLL 0x0100
+
+extern int aicwf_dbg_level;
+void rwnx_data_dump(char *tag, void *data, unsigned long len);
+
+#define AICWF_LOG "AICWFDBG("
+
+#define AICWFDBG(level, args, arg...) \
+ do { \
+ if (aicwf_dbg_level & (level)) { \
+ pr_debug(AICWF_LOG #level ")\t" args, ##arg); \
+ } \
+ } while (0)
+
+#define RWNX_DBG(fmt, ...) \
+ do { \
+ if (aicwf_dbg_level & LOGTRACE) { \
+ pr_debug(AICWF_LOG "LOGTRACE)\t" fmt, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#endif /* _AICWF_DEBUG_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/hal_desc.h b/drivers/net/wireless/aic/aic8800_fdrv/hal_desc.h
new file mode 100644
index 0000000000000..35809ccd5cef5
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/hal_desc.h
@@ -0,0 +1,359 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @file hal_desc.c
+ *
+ * @brief File containing the definition of HW descriptors
+ *
+ ******************************************************************************
+ */
+
+#ifndef _HAL_DESC_H_
+#define _HAL_DESC_H_
+
+#include "lmac_types.h"
+#include "rwnx_compat.h"
+
+/* Rate and policy table */
+
+#define N_CCK 8
+#define N_OFDM 8
+#define N_HT (8 * 2 * 2 * 4)
+#define N_VHT (10 * 4 * 2 * 8)
+#define N_HE_SU (12 * 4 * 3 * 8)
+#define N_HE_MU (12 * 6 * 3 * 8)
+#define N_HE_ER (3 * 3 + 3) // RU242 + RU106
+
+/* conversion table from NL80211 to MACHW enum */
+extern const int chnl2bw[];
+
+/* conversion table from MACHW to NL80211 enum */
+extern const int bw2chnl[];
+
+/* Values for formatModTx */
+#define FORMATMOD_NON_HT 0
+#define FORMATMOD_NON_HT_DUP_OFDM 1
+#define FORMATMOD_HT_MF 2
+#define FORMATMOD_HT_GF 3
+#define FORMATMOD_VHT 4
+#define FORMATMOD_HE_SU 5
+#define FORMATMOD_HE_MU 6
+#define FORMATMOD_HE_ER 7
+#define FORMATMOD_HE_TB 8
+
+/* Values for navProtFrmEx */
+#define NAV_PROT_NO_PROT_BIT 0
+#define NAV_PROT_SELF_CTS_BIT 1
+#define NAV_PROT_RTS_CTS_BIT 2
+#define NAV_PROT_RTS_CTS_WITH_QAP_BIT 3
+#define NAV_PROT_STBC_BIT 4
+
+/* THD MACCTRLINFO2 fields, used in struct umacdesc umac.flags */
+/// WhichDescriptor definition - contains aMPDU bit and position value
+/// Offset of WhichDescriptor field in the MAC CONTROL INFO 2 word
+#define WHICHDESC_OFT 19
+/// Mask of the WhichDescriptor field
+#define WHICHDESC_MSK (0x07 << WHICHDESC_OFT)
+/// Only 1 THD possible, describing an unfragmented MSDU
+#define WHICHDESC_UNFRAGMENTED_MSDU (0x00 << WHICHDESC_OFT)
+/// THD describing the first MPDU of a fragmented MSDU
+#define WHICHDESC_FRAGMENTED_MSDU_FIRST (0x01 << WHICHDESC_OFT)
+/// THD describing intermediate MPDUs of a fragmented MSDU
+#define WHICHDESC_FRAGMENTED_MSDU_INT (0x02 << WHICHDESC_OFT)
+/// THD describing the last MPDU of a fragmented MSDU
+#define WHICHDESC_FRAGMENTED_MSDU_LAST (0x03 << WHICHDESC_OFT)
+/// THD for extra descriptor starting an AMPDU
+#define WHICHDESC_AMPDU_EXTRA (0x04 << WHICHDESC_OFT)
+/// THD describing the first MPDU of an A-MPDU
+#define WHICHDESC_AMPDU_FIRST (0x05 << WHICHDESC_OFT)
+/// THD describing intermediate MPDUs of an A-MPDU
+#define WHICHDESC_AMPDU_INT (0x06 << WHICHDESC_OFT)
+/// THD describing the last MPDU of an A-MPDU
+#define WHICHDESC_AMPDU_LAST (0x07 << WHICHDESC_OFT)
+
+/// aMPDU bit offset
+#define AMPDU_OFT 21
+/// aMPDU bit
+#define AMPDU_BIT CO_BIT(AMPDU_OFT)
+
+union rwnx_mcs_index {
+ struct {
+ u32 mcs : 3;
+ u32 nss : 2;
+ } ht;
+ struct {
+ u32 mcs : 4;
+ u32 nss : 3;
+ } vht;
+ struct {
+ u32 mcs : 4;
+ u32 nss : 3;
+ } he;
+ u32 legacy : 7;
+};
+
+/* c.f RW-WLAN-nX-MAC-HW-UM */
+union rwnx_rate_ctrl_info {
+ struct {
+ u32 mcs_index_tx : 7;
+ u32 bw_tx : 2;
+ u32 gi_and_pre_type_tx : 2;
+ u32 format_mod_tx : 3;
+ u32 nav_prot_frm_ex : 3;
+ u32 mcs_index_prot_tx : 7;
+ u32 bw_prot_tx : 2;
+ u32 format_mod_prot_tx : 3;
+ u32 n_retry : 3;
+ };
+ u32 value;
+};
+
+/* c.f RW-WLAN-nX-MAC-HW-UM */
+struct rwnx_power_ctrl_info {
+ u32 tx_pwr_level_pt : 8;
+ u32 tx_pwr_level_prot_pt : 8;
+ u32 reserved : 16;
+};
+
+/* c.f RW-WLAN-nX-MAC-HW-UM */
+union rwnx_pol_phy_ctrl_info_1 {
+ struct {
+ u32 rsvd1 : 3;
+ u32 bf_frm_ex : 1;
+ u32 num_extn_ss : 2;
+ u32 fec_coding : 1;
+ u32 stbc : 2;
+ u32 rsvd2 : 5;
+ u32 n_tx : 3;
+ u32 n_tx_prot : 3;
+ };
+ u32 value;
+};
+
+/* c.f RW-WLAN-nX-MAC-HW-UM */
+union rwnx_pol_phy_ctrl_info_2 {
+ struct {
+ u32 antenna_set : 8;
+ u32 smm_index : 8;
+ u32 beam_formed : 1;
+ };
+ u32 value;
+};
+
+/* c.f RW-WLAN-nX-MAC-HW-UM */
+union rwnx_pol_mac_ctrl_info_1 {
+ struct {
+ u32 key_sram_index : 10;
+ u32 key_sram_index_ra : 10;
+ };
+ u32 value;
+};
+
+/* c.f RW-WLAN-nX-MAC-HW-UM */
+union rwnx_pol_mac_ctrl_info_2 {
+ struct {
+ u32 long_retry_limit : 8;
+ u32 short_retry_limit : 8;
+ u32 rts_threshold : 12;
+ };
+ u32 value;
+};
+
+#define POLICY_TABLE_PATTERN 0xBADCAB1E
+
+struct tx_policy_tbl {
+ /* Unique Pattern at the start of Policy Table */
+ u32 upatterntx;
+ /* PHY Control 1 Information used by MAC HW */
+ union rwnx_pol_phy_ctrl_info_1 phyctrlinfo_1;
+ /* PHY Control 2 Information used by MAC HW */
+ union rwnx_pol_phy_ctrl_info_2 phyctrlinfo_2;
+ /* MAC Control 1 Information used by MAC HW */
+ union rwnx_pol_mac_ctrl_info_1 macctrlinfo_1;
+ /* MAC Control 2 Information used by MAC HW */
+ union rwnx_pol_mac_ctrl_info_2 macctrlinfo_2;
+
+ union rwnx_rate_ctrl_info ratectrlinfos[NX_TX_MAX_RATES];
+ struct rwnx_power_ctrl_info powerctrlinfos[NX_TX_MAX_RATES];
+};
+
+#ifdef CONFIG_RWNX_FULLMAC
+
+/**
+ * union rwnx_hw_txstatus - Bitfield of confirmation status
+ *
+ * @tx_done: Packet has been processed by the firmware
+ * @retry_required: Packet was transmitted but not acknowledged and must be
+ * submitted again by the driver
+ * @sw_retry_required: Packet was not transmitted by the firmware and must be
+ * submitted again by the driver
+ * @acknowledged: Packet was acknowledged by the peer
+ * @reserved: Reserved status bits
+ * @value: Complete status word
+ */
+union rwnx_hw_txstatus {
+ struct {
+ u32 tx_done : 1;
+ u32 retry_required : 1;
+ u32 sw_retry_required : 1;
+ u32 acknowledged : 1;
+ u32 reserved : 28;
+ };
+ u32 value;
+};
+
+/**
+ * struct tx_cfm_tag - Structure indicating the status and other
+ * information about the transmission
+ *
+ * @credits: Number of credits returned to the TX queue (0 or 1)
+ * @ampdu_size: Number of frames in the A-MPDU when this was its last frame,
+ * 0 when this was not the last frame, or 1 for a singleton
+ * @amsdu_size: Maximum A-MSDU size in bytes
+ * @status: Transmission status
+ * @hostid: Host identifier of the transmitted buffer
+ */
+struct tx_cfm_tag {
+ /*
+ * u16 pn[4];
+ * u16 sn;
+ * u16 timestamp;
+ */
+ s8 credits;
+ u8 ampdu_size;
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+ u16 amsdu_size;
+#endif
+ union rwnx_hw_txstatus status;
+ u32 hostid;
+};
+
+/**
+ * struct rwnx_hw_txhdr - Hardware part of tx header
+ *
+ * @cfm: Information updated by fw/hardware after sending a frame
+ */
+struct rwnx_hw_txhdr {
+ struct tx_cfm_tag cfm;
+};
+
+#endif /* CONFIG_RWNX_FULLMAC */
+
+/* Modem */
+
+#define MDM_PHY_CONFIG_TRIDENT 0
+#define MDM_PHY_CONFIG_ELMA 1
+#define MDM_PHY_CONFIG_KARST 2
+
+// MODEM features (from reg_mdm_stat.h)
+/// MUMIMOTX field bit
+#define MDM_MUMIMOTX_BIT ((u32)0x80000000)
+/// MUMIMOTX field position
+#define MDM_MUMIMOTX_POS 31
+/// MUMIMORX field bit
+#define MDM_MUMIMORX_BIT ((u32)0x40000000)
+/// MUMIMORX field position
+#define MDM_MUMIMORX_POS 30
+/// BFMER field bit
+#define MDM_BFMER_BIT ((u32)0x20000000)
+/// BFMER field position
+#define MDM_BFMER_POS 29
+/// BFMEE field bit
+#define MDM_BFMEE_BIT ((u32)0x10000000)
+/// BFMEE field position
+#define MDM_BFMEE_POS 28
+/// LDPCDEC field bit
+#define MDM_LDPCDEC_BIT ((u32)0x08000000)
+/// LDPCDEC field position
+#define MDM_LDPCDEC_POS 27
+/// LDPCENC field bit
+#define MDM_LDPCENC_BIT ((u32)0x04000000)
+/// LDPCENC field position
+#define MDM_LDPCENC_POS 26
+/// CHBW field mask
+#define MDM_CHBW_MASK ((u32)0x03000000)
+/// CHBW field LSB position
+#define MDM_CHBW_LSB 24
+/// CHBW field width
+#define MDM_CHBW_WIDTH ((u32)0x00000002)
+/// DSSSCCK field bit
+#define MDM_DSSSCCK_BIT ((u32)0x00800000)
+/// DSSSCCK field position
+#define MDM_DSSSCCK_POS 23
+/// VHT field bit
+#define MDM_VHT_BIT ((u32)0x00400000)
+/// VHT field position
+#define MDM_VHT_POS 22
+/// HE field bit
+#define MDM_HE_BIT ((u32)0x00200000)
+/// HE field position
+#define MDM_HE_POS 21
+/// ESS field bit
+#define MDM_ESS_BIT ((u32)0x00100000)
+/// ESS field position
+#define MDM_ESS_POS 20
+/// RFMODE field mask
+#define MDM_RFMODE_MASK ((u32)0x000F0000)
+/// RFMODE field LSB position
+#define MDM_RFMODE_LSB 16
+/// RFMODE field width
+#define MDM_RFMODE_WIDTH ((u32)0x00000004)
+/// NSTS field mask
+#define MDM_NSTS_MASK ((u32)0x0000F000)
+/// NSTS field LSB position
+#define MDM_NSTS_LSB 12
+/// NSTS field width
+#define MDM_NSTS_WIDTH ((u32)0x00000004)
+/// NSS field mask
+#define MDM_NSS_MASK ((u32)0x00000F00)
+/// NSS field LSB position
+#define MDM_NSS_LSB 8
+/// NSS field width
+#define MDM_NSS_WIDTH ((u32)0x00000004)
+/// NTX field mask
+#define MDM_NTX_MASK ((u32)0x000000F0)
+/// NTX field LSB position
+#define MDM_NTX_LSB 4
+/// NTX field width
+#define MDM_NTX_WIDTH ((u32)0x00000004)
+/// NRX field mask
+#define MDM_NRX_MASK ((u32)0x0000000F)
+/// NRX field LSB position
+#define MDM_NRX_LSB 0
+/// NRX field width
+#define MDM_NRX_WIDTH ((u32)0x00000004)
+
+#define __MDM_PHYCFG_FROM_VERS(v) (((v) & MDM_RFMODE_MASK) >> MDM_RFMODE_LSB)
+
+#define RIU_FCU_PRESENT_MASK ((u32)0xFF000000)
+#define RIU_FCU_PRESENT_LSB 24
+
+#define __RIU_FCU_PRESENT(v) \
+ (((v) & RIU_FCU_PRESENT_MASK) >> RIU_FCU_PRESENT_LSB == 5)
+
+/// AGC load version field mask
+#define RIU_AGC_LOAD_MASK ((u32)0x00C00000)
+/// AGC load version field LSB position
+#define RIU_AGC_LOAD_LSB 22
+
+#define __RIU_AGCLOAD_FROM_VERS(v) \
+ (((v) & RIU_AGC_LOAD_MASK) >> RIU_AGC_LOAD_LSB)
+
+#define __FPGA_TYPE(v) (((v) & 0xFFFF0000) >> 16)
+
+#define __MDM_MAJOR_VERSION(v) (((v) & 0xFF000000) >> 24)
+#define __MDM_MINOR_VERSION(v) (((v) & 0x00FF0000) >> 16)
+/*
+ * #define __MDM_VERSION(v) \
+ * ((__MDM_MAJOR_VERSION(v) + 2) * 10 + __MDM_MINOR_VERSION(v))
+ */
+#define __MDM_VERSION(v) \
+({ \
+ u32 __v = (v); \
+ (__MDM_MAJOR_VERSION(__v) + 2) * 10 + __MDM_MINOR_VERSION(__v); \
+})
+
+#endif // _HAL_DESC_H_
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/ipc_compat.h b/drivers/net/wireless/aic/aic8800_fdrv/ipc_compat.h
new file mode 100644
index 0000000000000..cf1fe0d737b84
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/ipc_compat.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ****************************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ ****************************************************************************************
+ */
+
+#ifndef _IPC_H_
+#define _IPC_H_
+
+#define __INLINE inline
+
+#define __ALIGN4 __aligned(4)
+
+#define ASSERT_ERR(condition) \
+ do { \
+ if (unlikely(!(condition))) { \
+ pr_err("%s:%d:ASSERT_ERR(" #condition ")\n", __FILE__, \
+ __LINE__); \
+ } \
+ } while (0)
+
+#endif /* _IPC_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/ipc_host.c b/drivers/net/wireless/aic/aic8800_fdrv/ipc_host.c
new file mode 100644
index 0000000000000..5962d8b3fcf3f
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/ipc_host.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief IPC module
+ *
+ ******************************************************************************
+ */
+
+#ifndef __KERNEL__
+#include <stdio.h>
+#else
+#include "rwnx_defs.h"
+#include "rwnx_prof.h"
+#include <linux/spinlock.h>
+#endif
+
+#include "ipc_host.h"
+
+/*
+ * TYPES DEFINITION
+ ******************************************************************************
+ */
+
+const int nx_txdesc_cnt[] = {
+ NX_TXDESC_CNT0, NX_TXDESC_CNT1, NX_TXDESC_CNT2, NX_TXDESC_CNT3,
+#if NX_TXQ_CNT == 5
+ NX_TXDESC_CNT4,
+#endif
+};
+
+const int nx_txuser_cnt[] = {
+ CONFIG_USER_MAX,
+ CONFIG_USER_MAX,
+ CONFIG_USER_MAX,
+ CONFIG_USER_MAX,
+#if NX_TXQ_CNT == 5
+ 1,
+#endif
+};
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/ipc_host.h b/drivers/net/wireless/aic/aic8800_fdrv/ipc_host.h
new file mode 100644
index 0000000000000..b1cafbf30f73d
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/ipc_host.h
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief IPC module
+ *
+ ******************************************************************************
+ */
+
+#ifndef _IPC_HOST_H_
+#define _IPC_HOST_H_
+
+/*
+ * INCLUDE FILES
+ ******************************************************************************
+ */
+#include "ipc_shared.h"
+#ifndef __KERNEL__
+#include "arch.h"
+#else
+#include "ipc_compat.h"
+#endif
+
+/*
+ ******************************************************************************
+ * @brief This structure is used to initialize the MAC SW
+ *
+ * The WLAN device driver provides functions call-back with this structure
+ ******************************************************************************
+ */
+struct ipc_host_cb_tag {
+ /// WLAN driver call-back function: send_data_cfm
+ int (*send_data_cfm)(void *pthis, void *host_id);
+
+ /// WLAN driver call-back function: recv_data_ind
+ uint8_t (*recv_data_ind)(void *pthis, void *host_id);
+
+ /// WLAN driver call-back function: recv_radar_ind
+ uint8_t (*recv_radar_ind)(void *pthis, void *host_id);
+
+ /// WLAN driver call-back function: recv_unsup_rx_vec_ind
+ uint8_t (*recv_unsup_rx_vec_ind)(void *pthis, void *host_id);
+
+ /// WLAN driver call-back function: recv_msg_ind
+ uint8_t (*recv_msg_ind)(void *pthis, void *host_id);
+
+ /// WLAN driver call-back function: recv_msgack_ind
+ uint8_t (*recv_msgack_ind)(void *pthis, void *host_id);
+
+ /// WLAN driver call-back function: recv_dbg_ind
+ uint8_t (*recv_dbg_ind)(void *pthis, void *host_id);
+
+ /// WLAN driver call-back function: prim_tbtt_ind
+ void (*prim_tbtt_ind)(void *pthis);
+
+ /// WLAN driver call-back function: sec_tbtt_ind
+ void (*sec_tbtt_ind)(void *pthis);
+};
+
+/*
+ * Struct used to store information about host buffers (DMA Address and local
+ * pointer)
+ */
+struct ipc_hostbuf {
+ void *hostid; ///< ptr to hostbuf client (ipc_host client) structure
+ u32 dma_addr; ///< ptr to real hostbuf dma address
+};
+
+/// Definition of the IPC Host environment structure.
+struct ipc_host_env_tag {
+ /// Structure containing the callback pointers
+ struct ipc_host_cb_tag cb;
+
+ /// Pointer to the shared environment
+ struct ipc_shared_env_tag *shared;
+
+#ifdef CONFIG_RWNX_FULLMAC
+ // Array used to store the descriptor addresses
+ struct ipc_hostbuf ipc_host_rxdesc_array[IPC_RXDESC_CNT];
+ // Index of the host RX descriptor array (ipc_shared environment)
+ u8 ipc_host_rxdesc_idx;
+ /// Store the number of RX Descriptors
+ u8 rxdesc_nb;
+#endif //(CONFIG_RWNX_FULLMAC)
+
+ /// Fields for Data Rx handling
+ // Index used for ipc_host_rxbuf_array to point to current buffer
+ u8 ipc_host_rxbuf_idx;
+ // Store the number of Rx Data buffers
+ u32 rx_bufnb;
+ // Store the size of the Rx Data buffers
+ u32 rx_bufsz;
+
+ /// Fields for Radar events handling
+ // Global array used to store the hostid and hostbuf addresses
+ struct ipc_hostbuf ipc_host_radarbuf_array[IPC_RADARBUF_CNT];
+ // Index used for ipc_host_rxbuf_array to point to current buffer
+ u8 ipc_host_radarbuf_idx;
+ // Store the number of radar event buffers
+ u32 radar_bufnb;
+ // Store the size of the radar event buffers
+ u32 radar_bufsz;
+
+ /// Fields for Unsupported frame handling
+ // Global array used to store the hostid and hostbuf addresses
+ struct ipc_hostbuf ipc_host_unsuprxvecbuf_array[IPC_UNSUPRXVECBUF_CNT];
+ // Index used for ipc_host_unsuprxvecbuf_array to point to current buffer
+ u8 ipc_host_unsuprxvecbuf_idx;
+ // Store the number of unsupported rx vector buffers
+ u32 unsuprxvec_bufnb;
+ // Store the size of unsupported rx vector buffers
+ u32 unsuprxvec_bufsz;
+
+ // Index used that points to the first free TX desc
+ u32 txdesc_free_idx[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
+ // Index used that points to the first used TX desc
+ u32 txdesc_used_idx[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
+ // Array storing the currently pushed host ids for the BK queue
+ void *tx_host_id0[CONFIG_USER_MAX][NX_TXDESC_CNT0];
+ // Array storing the currently pushed host ids for the BE queue
+ void *tx_host_id1[CONFIG_USER_MAX][NX_TXDESC_CNT1];
+ // Array storing the currently pushed host ids for the VI queue
+ void *tx_host_id2[CONFIG_USER_MAX][NX_TXDESC_CNT2];
+ // Array storing the currently pushed host ids for the VO queue
+ void *tx_host_id3[CONFIG_USER_MAX][NX_TXDESC_CNT3];
+#if NX_TXQ_CNT == 5
+ // Array storing the currently pushed host ids for the BCN queue
+ void *tx_host_id4[1][NX_TXDESC_CNT4];
+#endif
+ // Pointer to the different host ids arrays, per IPC queue
+ void **tx_host_id[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
+ // Pointer to the different TX descriptor arrays, per IPC queue
+ struct txdesc_host *txdesc[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
+
+ /// Fields for Emb->App MSGs handling
+ // Global array used to store the hostid and hostbuf addresses for msg/ind
+ struct ipc_hostbuf ipc_host_msgbuf_array[IPC_MSGE2A_BUF_CNT];
+ // Index of the MSG E2A buffers array to point to current buffer
+ u8 ipc_host_msge2a_idx;
+ // Store the number of E2A MSG buffers
+ u32 ipc_e2amsg_bufnb;
+ // Store the size of the E2A MSG buffers
+ u32 ipc_e2amsg_bufsz;
+
+ /// E2A ACKs of A2E MSGs
+ u8 msga2e_cnt;
+ void *msga2e_hostid;
+
+ /// Fields for Debug MSGs handling
+ // Global array used to store the hostid and hostbuf addresses for Debug
+ // messages
+ struct ipc_hostbuf ipc_host_dbgbuf_array[IPC_DBGBUF_CNT];
+ // Index of the Debug messages buffers array to point to current buffer
+ u8 ipc_host_dbg_idx;
+ // Store the number of Debug messages buffers
+ u32 ipc_dbg_bufnb;
+ // Store the size of the Debug messages buffers
+ u32 ipc_dbg_bufsz;
+
+ /// Pointer to the attached object (used in callbacks and register accesses)
+ void *pthis;
+};
+
+extern const int nx_txdesc_cnt[];
+extern const int nx_txuser_cnt[];
+
+#endif // _IPC_HOST_H_
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/ipc_shared.h b/drivers/net/wireless/aic/aic8800_fdrv/ipc_shared.h
new file mode 100644
index 0000000000000..5773567c65adc
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/ipc_shared.h
@@ -0,0 +1,770 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief Shared data between both IPC modules
+ *
+ ******************************************************************************
+ */
+
+#ifndef _IPC_SHARED_H_
+#define _IPC_SHARED_H_
+
+/*
+ * INCLUDE FILES
+ ****************************************************************************************
+ */
+#include "ipc_compat.h"
+#include "lmac_mac.h"
+#include "rwnx_compat.h"
+
+/*
+ * DEFINES AND MACROS
+ ****************************************************************************************
+ */
+#define CO_BIT(pos) (1U << (pos))
+
+#define IPC_TXQUEUE_CNT NX_TXQ_CNT
+#define NX_TXDESC_CNT0 8
+#define NX_TXDESC_CNT1 64
+#define NX_TXDESC_CNT2 64
+#define NX_TXDESC_CNT3 32
+#if NX_TXQ_CNT == 5
+#define NX_TXDESC_CNT4 8
+#endif
+
+/*
+ * Number of Host buffers available for Data Rx handling (through DMA)
+ */
+#define IPC_RXBUF_CNT 128
+
+/*
+ * Number of shared descriptors available for Data RX handling
+ */
+#define IPC_RXDESC_CNT 128
+
+/*
+ * Number of Host buffers available for Radar events handling (through DMA)
+ */
+#define IPC_RADARBUF_CNT 16
+
+/*
+ * Number of Host buffers available for unsupported Rx vectors handling (through
+ * DMA)
+ */
+#define IPC_UNSUPRXVECBUF_CNT 8
+
+/*
+ * Size of RxVector
+ */
+#define IPC_RXVEC_SIZE 16
+
+/*
+ * Number of Host buffers available for Emb->App MSGs sending (through DMA)
+ */
+#ifdef CONFIG_RWNX_FULLMAC
+#define IPC_MSGE2A_BUF_CNT 64
+#endif
+/*
+ * Number of Host buffers available for Debug Messages sending (through DMA)
+ */
+#define IPC_DBGBUF_CNT 32
+
+/*
+ * Length used in MSGs structures
+ */
+#define IPC_A2E_MSG_BUF_SIZE 127 // size in 4-byte words
+#ifdef CONFIG_RWNX_FULLMAC
+#define IPC_E2A_MSG_SIZE_BASE 256 // size in 4-byte words
+#endif
+
+#define IPC_E2A_MSG_PARAM_SIZE IPC_E2A_MSG_SIZE_BASE
+
+/*
+ * Debug messages buffers size (in bytes)
+ */
+#define IPC_DBG_PARAM_SIZE 256
+
+/*
+ * Define used for Rx hostbuf validity.
+ * This value should appear only when hostbuf was used for a Reception.
+ */
+#define RX_DMA_OVER_PATTERN 0xAAAAAA00
+
+/*
+ * Define used for MSG buffers validity.
+ * This value will be written only when a MSG buffer is used for sending from
+ * Emb to App.
+ */
+#define IPC_MSGE2A_VALID_PATTERN 0xADDEDE2A
+
+/*
+ * Define used for Debug messages buffers validity.
+ * This value will be written only when a DBG buffer is used for sending from
+ * Emb to App.
+ */
+#define IPC_DBG_VALID_PATTERN 0x000CACA0
+
+/*
+ * Length of the receive vectors, in bytes
+ */
+#define DMA_HDR_PHYVECT_LEN 36
+
+/*
+ * Maximum number of payload addresses and lengths present in the descriptor
+ */
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+#define NX_TX_PAYLOAD_MAX 6
+#else
+#define NX_TX_PAYLOAD_MAX 1
+#endif
+
+/*
+ * Message struct/ID API version
+ */
+#define MSG_API_VER 33
+
+/*
+ ****************************************************************************************
+ */
+// c.f LMAC/src/tx/tx_swdesc.h
+/// Descriptor filled by the Host
+struct hostdesc {
+ /// Pointer to packet payload
+ // u32 packet_addr;
+ /// Size of the payload
+ u16 packet_len;
+ u16 flags_ext;
+
+ u32 hostid;
+#ifdef CONFIG_RWNX_FULLMAC
+ /// Address of the status descriptor in host memory (used for confirmation
+ /// upload)
+ // u32 status_desc_addr;
+ /// Destination Address
+ struct mac_addr eth_dest_addr;
+ /// Source Address
+ struct mac_addr eth_src_addr;
+ /// Ethernet Type
+ __be16 ethertype;
+#else /* ! CONFIG_RWNX_FULLMAC */
+#ifdef CONFIG_RWNX_AGG_TX
+ /// Sequence Number for AMPDU MPDUs - for quick check if it's allowed within
+ /// window
+ u16 sn;
+#endif /* CONFIG_RWNX_AGG_TX */
+ /// Padding between the buffer control structure and the MPDU in host memory
+ u8 padding;
+#endif /* CONFIG_RWNX_FULLMAC */
+ u8 ac;
+ /// Packet TID (0xFF if not a QoS frame)
+ u8 tid;
+ /// Interface Id
+ u8 vif_idx;
+ /// Station Id (0xFF if station is unknown)
+ u8 staid;
+#ifdef CONFIG_RWNX_MUMIMO_TX
+ /// MU-MIMO information (GroupId and User Position in the group) - The
+ /// GroupId is located on bits 0-5 and the User Position on bits 6-7. The
+ /// GroupId value is set to 63 if MU-MIMO shall not be used
+ u8 mumimo_info;
+#endif /* CONFIG_RWNX_MUMIMO_TX */
+#ifdef CONFIG_RWNX_FULLMAC
+ /// TX flags
+ u16 flags;
+#endif /* CONFIG_RWNX_FULLMAC */
+};
+
+/// Descriptor filled by the UMAC
+struct umacdesc {
+#ifdef CONFIG_RWNX_AGG_TX
+ /// First Sequence Number of the BlockAck window
+ u16 sn_win;
+ /// Flags from UMAC (match tx_hd.macctrlinfo2 format)
+ u32 flags;
+ /// PHY related flags field - rate, GI type, BW type - filled by driver
+ u32 phy_flags;
+#endif //(CONFIG_RWNX_AGG_TX)
+};
+
+struct txdesc_api {
+ /// Information provided by Host
+ struct hostdesc host;
+};
+
+struct txdesc_host {
+ u32 ready;
+
+ /// API of the embedded part
+ struct txdesc_api api;
+};
+
+/// Comes from ipc_dma.h
+/// Element in the pool of TX DMA bridge descriptors.
+struct dma_desc {
+ /* Application subsystem address which is used as source address for DMA
+ * payload transfer
+ */
+ u32 src;
+ /** Points to the start of the embedded data buffer associated with this
+ * descriptor. This address acts as the destination address for the DMA
+ * payload transfer
+ */
+ u32 dest;
+ /// Complete length of the buffer in memory
+ u16 length;
+ /// Control word for the DMA engine (e.g. for interrupt generation)
+ u16 ctrl;
+ /// Pointer to the next element of the chained list
+ u32 next;
+};
+
+// Comes from la.h
+/// Length of the configuration data of a logic analyzer
+#define LA_CONF_LEN 10
+
+/// Structure containing the configuration data of a logic analyzer
+struct la_conf_tag {
+ u32 conf[LA_CONF_LEN];
+ u32 trace_len;
+ u32 diag_conf;
+};
+
+/// Size of a logic analyzer memory
+#define LA_MEM_LEN (1024 * 1024)
+
+/// Type of errors
+enum {
+ /// Recoverable error, not requiring any action from Upper MAC
+ DBG_ERROR_RECOVERABLE = 0,
+ /// Fatal error, requiring Upper MAC to reset Lower MAC and HW and restart
+ /// operation
+ DBG_ERROR_FATAL
+};
+
+/// Maximum length of the SW diag trace
+#define DBG_SW_DIAG_MAX_LEN 1024
+
+/// Maximum length of the error trace
+#define DBG_ERROR_TRACE_SIZE 256
+
+/// Number of MAC diagnostic port banks
+#define DBG_DIAGS_MAC_MAX 48
+
+/// Number of PHY diagnostic port banks
+#define DBG_DIAGS_PHY_MAX 32
+
+/// Maximum size of the RX header descriptor information in the debug dump
+#define DBG_RHD_MEM_LEN (5 * 1024)
+
+/// Maximum size of the RX buffer descriptor information in the debug dump
+#define DBG_RBD_MEM_LEN (5 * 1024)
+
+/// Maximum size of the TX header descriptor information in the debug dump
+#define DBG_THD_MEM_LEN (10 * 1024)
+
+/// Structure containing the information about the PHY channel that is used
+struct phy_channel_info {
+ /// PHY channel information 1
+ u32 info1;
+ /// PHY channel information 2
+ u32 info2;
+};
+
+/// Debug information forwarded to host when an error occurs
+struct dbg_debug_info_tag {
+ /// Type of error (0: recoverable, 1: fatal)
+ u32 error_type;
+ /// Pointer to the first RX Header Descriptor chained to the MAC HW
+ u32 rhd;
+ /// Size of the RX header descriptor buffer
+ u32 rhd_len;
+ /// Pointer to the first RX Buffer Descriptor chained to the MAC HW
+ u32 rbd;
+ /// Size of the RX buffer descriptor buffer
+ u32 rbd_len;
+ /// Pointer to the first TX Header Descriptors chained to the MAC HW
+ u32 thd[NX_TXQ_CNT];
+ /// Size of the TX header descriptor buffer
+ u32 thd_len[NX_TXQ_CNT];
+ /// MAC HW diag configuration
+ u32 hw_diag;
+ /// Error message
+ u32 error[DBG_ERROR_TRACE_SIZE / 4];
+ /// SW diag configuration length
+ u32 sw_diag_len;
+ /// SW diag configuration
+ u32 sw_diag[DBG_SW_DIAG_MAX_LEN / 4];
+ /// PHY channel information
+ struct phy_channel_info chan_info;
+ /// Embedded LA configuration
+ struct la_conf_tag la_conf;
+ /// MAC diagnostic port state
+ u16 diags_mac[DBG_DIAGS_MAC_MAX];
+ /// PHY diagnostic port state
+ u16 diags_phy[DBG_DIAGS_PHY_MAX];
+ /// MAC HW RX Header descriptor pointer
+ u32 rhd_hw_ptr;
+ /// MAC HW RX Buffer descriptor pointer
+ u32 rbd_hw_ptr;
+};
+
+/// Full debug dump that is forwarded to host in case of error
+struct dbg_debug_dump_tag {
+ /// Debug information
+ struct dbg_debug_info_tag dbg_info;
+
+ /// RX header descriptor memory
+ u32 rhd_mem[DBG_RHD_MEM_LEN / 4];
+
+ /// RX buffer descriptor memory
+ u32 rbd_mem[DBG_RBD_MEM_LEN / 4];
+
+ /// TX header descriptor memory
+ u32 thd_mem[NX_TXQ_CNT][DBG_THD_MEM_LEN / 4];
+
+ /// Logic analyzer memory
+ u32 la_mem[LA_MEM_LEN / 4];
+};
+
+/// Number of pulses in a radar event structure
+#define RADAR_PULSE_MAX 4
+
+/// Definition of an array of radar pulses
+struct radar_pulse_array_desc {
+ /// Buffer containing the radar pulses
+ u32 pulse[RADAR_PULSE_MAX];
+ /// Index of the radar detection chain that detected those pulses
+ u32 idx;
+ /// Number of valid pulses in the buffer
+ u32 cnt;
+};
+
+/// Bit mapping inside a radar pulse element
+struct radar_pulse {
+ s32
+ freq : 6; /** Freq (resolution is 2Mhz range is [-Fadc/4 .. Fadc/4]) */
+ u32 fom : 4; /** Figure of Merit */
+ u32 len : 6; /** Length of the current radar pulse (resolution is 2us) */
+ u32 rep : 16; /* Time interval between the previous radar event
+ * and the current one (in us)
+ */
+};
+
+/// Definition of a RX vector descriptor
+struct rx_vector_desc {
+ /// PHY channel information
+ struct phy_channel_info phy_info;
+
+ /// RX vector 1
+ u32 rx_vect1[IPC_RXVEC_SIZE / 4];
+
+ /// Used to print a valid rx vector
+ u32 pattern;
+};
+
+///
+struct rxdesc_tag {
+ /// Host Buffer Address
+ u32 host_id;
+ /// Length
+ u32 frame_len;
+ /// Status
+ u16 status;
+};
+
+/*
+ ****************************************************************************************
+ * @addtogroup IPC_TX IPC Tx path
+ * @ingroup IPC
+ * @brief IPC Tx path structures and functions
+ *
+ * A typical use case of the IPC Tx path API:
+ * @msc
+ * hscale = "2";
+ *
+ * a [label=Driver],
+ * b [label="IPC host"],
+ * c [label="IPC emb"],
+ * d [label=Firmware];
+ *
+ * --- [label="Tx descriptor queue example"];
+ * a=>a [label="Driver receives a Tx packet from OS"];
+ * a=>b [label="ipc_host_txdesc_get()"];
+ * a<<b [label="struct txdesc_host *"];
+ * a=>a [label="Driver fill the descriptor"];
+ * a=>b [label="ipc_host_txdesc_push()"];
+ * ... [label="(several Tx desc can be pushed)"];
+ * b:>c [label="Tx desc queue filled IRQ"];
+ * c=>>d [label="EDCA sub-scheduler callback"];
+ * c<<d [label="Tx desc queue to pop"];
+ * c=>>d [label="UMAC Tx desc callback"];
+ * ... [label="(several Tx desc can be popped)"];
+ * d=>d [label="Packets are sent or discarded"];
+ * --- [label="Tx confirm queue example"];
+ * c<=d [label="ipc_emb_txcfm_push()"];
+ * c>>d [label="Request accepted"];
+ * ... [label="(several Tx cfm can be pushed)"];
+ * b<:c [label="Tx cfm queue filled IRQ"];
+ * a<<=b [label="Driver's Tx Confirm callback"];
+ * a=>b [label="ipc_host_txcfm_pop()"];
+ * a<<b [label="struct ipc_txcfm"];
+ * a<=a [label="Packets are freed by the driver"];
+ * @endmsc
+ *
+ * @{
+ ****************************************************************************************
+ */
+
+/// @} IPC_TX
+
+/*
+ ****************************************************************************************
+ * @defgroup IPC_RX IPC Rx path
+ * @ingroup IPC
+ * @brief IPC Rx path functions and structures
+ *
+ * A typical use case of the IPC Rx path API:
+ * @msc
+ * hscale = "2";
+ *
+ * a [label=Firmware],
+ * b [label="IPC emb"],
+ * c [label="IPC host"],
+ * d [label=Driver];
+ *
+ * --- [label="Rx buffer and desc queues usage example"];
+ * d=>c [label="ipc_host_rxbuf_push()"];
+ * d=>c [label="ipc_host_rxbuf_push()"];
+ * d=>c [label="ipc_host_rxbuf_push()"];
+ * ... [label="(several Rx buffer are pushed)"];
+ * a=>a [label=" Frame is received\n from the medium"];
+ * a<<b [label="struct ipc_rxbuf"];
+ * a=>a [label=" Firmware fill the buffer\n with received frame"];
+ * a<<b [label="Push accepted"];
+ * ... [label="(several Rx desc can be pushed)"];
+ * b:>c [label="Rx desc queue filled IRQ"];
+ * c=>>d [label="Driver Rx packet callback"];
+ * c<=d [label="ipc_host_rxdesc_pop()"];
+ * d=>d [label="Rx packet is handed\nover to the OS "];
+ * ... [label="(several Rx desc can be poped)"];
+ * --- [label="Rx buffer request exemple"];
+ * b:>c [label="Low Rx buffer count IRQ"];
+ * a<<b [label="struct ipc_rxbuf"];
+ * c=>>d [label="Driver Rx buffer callback"];
+ * d=>c [label="ipc_host_rxbuf_push()"];
+ * d=>c [label="ipc_host_rxbuf_push()"];
+ * d=>c [label="ipc_host_rxbuf_push()"];
+ * ... [label="(several Rx buffer are pushed)"];
+ * @endmsc
+ *
+ * @addtogroup IPC_RX
+ * @{
+ ****************************************************************************************
+ */
+
+/// @} IPC_RX
+
+/*
+ ****************************************************************************************
+ * @defgroup IPC_MISC IPC Misc
+ * @ingroup IPC
+ * @brief IPC miscellaneous functions
+ ****************************************************************************************
+ */
+/** IPC header structure. This structure is stored at the beginning of every
+ * IPC message.
+ * @warning This structure's size must NOT exceed 4 bytes in length.
+ */
+struct ipc_header {
+ /// IPC message type.
+ u16 type;
+ /// IPC message size in number of bytes.
+ u16 size;
+};
+
+struct ipc_msg_elt {
+ /// Message header (alignment forced on word size, see allocation in shared
+ /// env).
+ struct ipc_header header __ALIGN4;
+};
+
+/// Message structure for MSGs from Emb to App
+struct ipc_e2a_msg {
+ u16 id; ///< Message id.
+ u16 dummy_dest_id;
+ u16 dummy_src_id;
+ u16 param_len; ///< Parameter embedded struct length.
+ u32 pattern; ///< Used to stamp a valid MSG buffer
+ u32 param[IPC_E2A_MSG_PARAM_SIZE]; ///< Parameter embedded struct. Must be
+ ///< word-aligned.
+};
+
+/// Message structure for Debug messages from Emb to App
+struct ipc_dbg_msg {
+ u32 string[IPC_DBG_PARAM_SIZE / 4]; ///< Debug string
+ u32 pattern; ///< Used to stamp a valid buffer
+};
+
+/// Message structure for MSGs from App to Emb.
+/// Actually a sub-structure will be used when filling the messages.
+struct ipc_a2e_msg {
+ u32 dummy_word; // used to cope with kernel message structure
+ u32 msg[IPC_A2E_MSG_BUF_SIZE]; // body of the msg
+};
+
+struct ipc_shared_rx_buf {
+ /// < ptr to hostbuf client (ipc_host client) structure
+ u32 hostid;
+ /// < ptr to real hostbuf dma address
+ u32 dma_addr;
+};
+
+struct ipc_shared_rx_desc {
+ /// DMA Address
+ u32 dma_addr;
+};
+
+/// Structure containing FW characteristics for compatibility checking
+struct compatibility_tag {
+ /// Size of IPC shared memory
+ u16 ipc_shared_size;
+ /// Message struct/ID API version
+ u16 msg_api;
+ /// Version of IPC shared
+ u8 ipc_shared_version;
+ /// Number of host buffers available for Emb->App MSGs sending
+ u8 msge2a_buf_cnt;
+ /// Number of host buffers available for Debug Messages sending
+ u8 dbgbuf_cnt;
+ /// Number of host buffers available for Radar events handling
+ u8 radarbuf_cnt;
+ /// Number of host buffers available for unsupported Rx vectors handling
+ u8 unsuprxvecbuf_cnt;
+ /// Number of shared descriptors available for Data RX handling
+ u8 rxdesc_cnt;
+ /// Number of host buffers available for Data Rx handling
+ u8 rxbuf_cnt;
+ /// Number of descriptors in BK TX queue (power of 2, min 4, max 64)
+ u8 bk_txq;
+ /// Number of descriptors in BE TX queue (power of 2, min 4, max 64)
+ u8 be_txq;
+ /// Number of descriptors in VI TX queue (power of 2, min 4, max 64)
+ u8 vi_txq;
+ /// Number of descriptors in VO TX queue (power of 2, min 4, max 64)
+ u8 vo_txq;
+ /// Number of descriptors in BCN TX queue (power of 2, min 4, max 64)
+ u8 bcn_txq;
+};
+
+/*
+ * TYPE and STRUCT DEFINITIONS
+ ****************************************************************************************
+ */
+
+// Indexes are defined in the MIB shared structure
+struct ipc_shared_env_tag {
+ struct compatibility_tag comp_info; // FW characteristics
+
+ struct ipc_a2e_msg
+ msg_a2e_buf; // room for MSG to be sent from App to Emb
+
+ // Fields for MSGs sending from Emb to App
+ struct ipc_e2a_msg
+ msg_e2a_buf; // room to build the MSG to be DMA Xferred
+ struct dma_desc
+ msg_dma_desc; // DMA descriptor for Emb->App MSGs Xfers
+ u32 msg_e2a_hostbuf_addr[IPC_MSGE2A_BUF_CNT]; // buffers @ for DMA Xfers
+
+ // Fields for Debug MSGs sending from Emb to App
+ struct ipc_dbg_msg
+ dbg_buf; // room to build the MSG to be DMA Xferred
+ struct dma_desc
+ dbg_dma_desc; // DMA descriptor for Emb->App MSGs Xfers
+ u32 dbg_hostbuf_addr[IPC_DBGBUF_CNT]; // buffers @ for MSGs DMA Xfers
+ u32 la_dbginfo_addr; // Host buffer address for the debug information
+ u32 pattern_addr;
+
+ u32 radarbuf_hostbuf[IPC_RADARBUF_CNT]; // buffers @ for Radar Events
+ u32 unsuprxvecbuf_hostbuf[IPC_UNSUPRXVECBUF_CNT]; // buffers @ for
+ // unsupported Rx vectors
+ struct txdesc_host txdesc0[CONFIG_USER_MAX][NX_TXDESC_CNT0];
+ struct txdesc_host txdesc1[CONFIG_USER_MAX][NX_TXDESC_CNT1];
+ struct txdesc_host txdesc2[CONFIG_USER_MAX][NX_TXDESC_CNT2];
+ struct txdesc_host txdesc3[CONFIG_USER_MAX][NX_TXDESC_CNT3];
+#if NX_TXQ_CNT == 5
+ struct txdesc_host txdesc4[1][NX_TXDESC_CNT4];
+#endif
+#ifdef CONFIG_RWNX_FULLMAC
+ // RX Descriptors Array
+ struct ipc_shared_rx_desc host_rxdesc[IPC_RXDESC_CNT];
+ // RX Buffers Array
+ struct ipc_shared_rx_buf host_rxbuf[IPC_RXBUF_CNT];
+#else
+ // buffers @ for Data Rx
+ u32 host_rxbuf[IPC_RXBUF_CNT];
+#endif /* CONFIG_RWNX_FULLMAC */
+
+ u32 buffered[NX_REMOTE_STA_MAX][TID_MAX];
+
+ u16 trace_pattern;
+ u32 trace_start;
+ u32 trace_end;
+ u32 trace_size;
+ u32 trace_offset;
+ u32 trace_nb_compo;
+ u32 trace_offset_compo;
+};
+
+extern struct ipc_shared_env_tag ipc_shared_env;
+
+/*
+ * TYPE and STRUCT DEFINITIONS
+ ****************************************************************************************
+ */
+
+// IRQs from app to emb
+/// Interrupts bits used for the TX descriptors of the AC queues
+#ifdef CONFIG_RWNX_MUMIMO_TX
+/// Interrupts bits used
+#if CONFIG_USER_MAX > 3
+#define IPC_IRQ_A2E_USER_MSK 0xF
+#elif CONFIG_USER_MAX > 2
+#define IPC_IRQ_A2E_USER_MSK 0x7
+#else
+#define IPC_IRQ_A2E_USER_MSK 0x3
+#endif
+
+/// Offset of the interrupts for AC0
+#define IPC_IRQ_A2E_AC0_OFT 8
+/// Mask of the interrupts for AC0
+#define IPC_IRQ_A2E_AC0_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC0_OFT)
+/// Offset of the interrupts for AC1
+#define IPC_IRQ_A2E_AC1_OFT (IPC_IRQ_A2E_AC0_OFT + CONFIG_USER_MAX)
+/// Mask of the interrupts for AC1
+#define IPC_IRQ_A2E_AC1_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC1_OFT)
+/// Offset of the interrupts for AC2
+#define IPC_IRQ_A2E_AC2_OFT (IPC_IRQ_A2E_AC1_OFT + CONFIG_USER_MAX)
+/// Mask of the interrupts for AC2
+#define IPC_IRQ_A2E_AC2_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC2_OFT)
+/// Offset of the interrupts for AC3
+#define IPC_IRQ_A2E_AC3_OFT (IPC_IRQ_A2E_AC2_OFT + CONFIG_USER_MAX)
+/// Mask of the interrupts for AC3
+#define IPC_IRQ_A2E_AC3_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC3_OFT)
+/// Offset of the interrupts for BCN
+#define IPC_IRQ_A2E_BCN_OFT (IPC_IRQ_A2E_AC3_OFT + CONFIG_USER_MAX)
+/// Mask of the interrupts for BCN
+#define IPC_IRQ_A2E_BCN_MSK CO_BIT(IPC_IRQ_A2E_BCN_OFT)
+
+#define IPC_IRQ_A2E_AC_TXDESC \
+ (IPC_IRQ_A2E_AC0_MSK | IPC_IRQ_A2E_AC1_MSK | IPC_IRQ_A2E_AC2_MSK | \
+ IPC_IRQ_A2E_AC3_MSK)
+
+/// Interrupts bits used for the TX descriptors of the BCN queue
+#if NX_TXQ_CNT < 5
+#define IPC_IRQ_A2E_BCN_TXDESC 0
+#else
+#define IPC_IRQ_A2E_BCN_TXDESC (0x01 << IPC_IRQ_A2E_BCN_OFT)
+#endif
+
+/// IPC TX descriptor interrupt mask
+#define IPC_IRQ_A2E_TXDESC (IPC_IRQ_A2E_AC_TXDESC | IPC_IRQ_A2E_BCN_TXDESC)
+#else
+/// IPC TX descriptor interrupt mask
+#define IPC_IRQ_A2E_TXDESC 0xFF00
+#endif
+
+#define IPC_IRQ_A2E_TXDESC_FIRSTBIT (8)
+#define IPC_IRQ_A2E_RXBUF_BACK CO_BIT(5)
+#define IPC_IRQ_A2E_RXDESC_BACK CO_BIT(4)
+
+#define IPC_IRQ_A2E_MSG CO_BIT(1)
+#define IPC_IRQ_A2E_DBG CO_BIT(0)
+
+#define IPC_IRQ_A2E_ALL (IPC_IRQ_A2E_TXDESC | IPC_IRQ_A2E_MSG | IPC_IRQ_A2E_DBG)
+
+// IRQs from emb to app
+#define IPC_IRQ_E2A_TXCFM_POS 7
+
+#ifdef CONFIG_RWNX_MUMIMO_TX
+/// Interrupts bits used
+#if CONFIG_USER_MAX > 3
+#define IPC_IRQ_E2A_USER_MSK 0xF
+#elif CONFIG_USER_MAX > 2
+#define IPC_IRQ_E2A_USER_MSK 0x7
+#else
+#define IPC_IRQ_E2A_USER_MSK 0x3
+#endif
+
+/// Offset of the interrupts for AC0
+#define IPC_IRQ_E2A_AC0_OFT IPC_IRQ_E2A_TXCFM_POS
+/// Mask of the interrupts for AC0
+#define IPC_IRQ_E2A_AC0_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC0_OFT)
+/// Offset of the interrupts for AC1
+#define IPC_IRQ_E2A_AC1_OFT (IPC_IRQ_E2A_AC0_OFT + CONFIG_USER_MAX)
+/// Mask of the interrupts for AC1
+#define IPC_IRQ_E2A_AC1_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC1_OFT)
+/// Offset of the interrupts for AC2
+#define IPC_IRQ_E2A_AC2_OFT (IPC_IRQ_E2A_AC1_OFT + CONFIG_USER_MAX)
+/// Mask of the interrupts for AC2
+#define IPC_IRQ_E2A_AC2_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC2_OFT)
+/// Offset of the interrupts for AC3
+#define IPC_IRQ_E2A_AC3_OFT (IPC_IRQ_E2A_AC2_OFT + CONFIG_USER_MAX)
+/// Mask of the interrupts for AC3
+#define IPC_IRQ_E2A_AC3_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC3_OFT)
+/// Offset of the interrupts for BCN
+#define IPC_IRQ_E2A_BCN_OFT (IPC_IRQ_E2A_AC3_OFT + CONFIG_USER_MAX)
+/// Mask of the interrupts for BCN
+#define IPC_IRQ_E2A_BCN_MSK CO_BIT(IPC_IRQ_E2A_BCN_OFT)
+
+#define IPC_IRQ_E2A_AC_TXCFM \
+ (IPC_IRQ_E2A_AC0_MSK | IPC_IRQ_E2A_AC1_MSK | IPC_IRQ_E2A_AC2_MSK | \
+ IPC_IRQ_E2A_AC3_MSK)
+
+/// Interrupts bits used for the TX descriptors of the BCN queue
+#if NX_TXQ_CNT < 5
+#define IPC_IRQ_E2A_BCN_TXCFM 0
+#else
+#define IPC_IRQ_E2A_BCN_TXCFM (0x01 << IPC_IRQ_E2A_BCN_OFT)
+#endif
+
+/// IPC TX descriptor interrupt mask
+#define IPC_IRQ_E2A_TXCFM (IPC_IRQ_E2A_AC_TXCFM | IPC_IRQ_E2A_BCN_TXCFM)
+
+#else
+
+#define IPC_IRQ_E2A_TXCFM (((1 << NX_TXQ_CNT) - 1) << IPC_IRQ_E2A_TXCFM_POS)
+
+#endif /* CONFIG_RWNX_MUMIMO_TX */
+
+#define IPC_IRQ_E2A_UNSUP_RX_VEC CO_BIT(7)
+#define IPC_IRQ_E2A_RADAR CO_BIT(6)
+#define IPC_IRQ_E2A_TBTT_SEC CO_BIT(5)
+#define IPC_IRQ_E2A_TBTT_PRIM CO_BIT(4)
+#define IPC_IRQ_E2A_RXDESC CO_BIT(3)
+#define IPC_IRQ_E2A_MSG_ACK CO_BIT(2)
+#define IPC_IRQ_E2A_MSG CO_BIT(1)
+#define IPC_IRQ_E2A_DBG CO_BIT(0)
+
+#define IPC_IRQ_E2A_ALL \
+ (IPC_IRQ_E2A_TXCFM | IPC_IRQ_E2A_RXDESC | IPC_IRQ_E2A_MSG_ACK | \
+ IPC_IRQ_E2A_MSG | IPC_IRQ_E2A_DBG | IPC_IRQ_E2A_TBTT_PRIM | \
+ IPC_IRQ_E2A_TBTT_SEC | IPC_IRQ_E2A_RADAR | IPC_IRQ_E2A_UNSUP_RX_VEC)
+
+// FLAGS for RX desc
+#define IPC_RX_FORWARD CO_BIT(1)
+#define IPC_RX_INTRABSS CO_BIT(0)
+
+// IPC message TYPE
+enum {
+ IPC_MSG_NONE = 0,
+ IPC_MSG_WRAP,
+ IPC_MSG_KMSG,
+
+ IPC_DBG_STRING,
+
+};
+
+#endif // _IPC_SHARED_H_
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/lmac_mac.h b/drivers/net/wireless/aic/aic8800_fdrv/lmac_mac.h
new file mode 100644
index 0000000000000..114ed14f4ad55
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/lmac_mac.h
@@ -0,0 +1,437 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ****************************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief MAC related definitions.
+ *
+ * Adapted from mac_types.h to used lmac_types.h instead of standard types
+ * eg: perl -pi -e '$_ =~ s/uint(\d{1,2})_t/u$1_l/g; \
+ * $_ =~ s/int(\d{1,2})_t/s$1_l/g; \
+ * $_ =~ s/CO_BIT/BIT/g;'
+ *
+ ****************************************************************************************
+ */
+
+#ifndef LMAC_MAC_H_
+#define LMAC_MAC_H_
+
+#include "lmac_types.h"
+
+/// Interface types
+enum mac_vif_type {
+ /// ESS STA interface
+ VIF_STA,
+ /// IBSS STA interface
+ VIF_IBSS,
+ /// AP interface
+ VIF_AP,
+ /// Mesh Point interface
+ VIF_MESH_POINT,
+ /// Monitor interface
+ VIF_MONITOR,
+ /// Unknown type
+ VIF_UNKNOWN
+};
+
+/// MAC address length in bytes.
+#define MAC_ADDR_LEN 6
+
+/// MAC address structure.
+struct mac_addr {
+ /// Array of 16-bit words that make up the MAC address.
+ u16 array[MAC_ADDR_LEN / 2];
+};
+
+/// SSID maximum length.
+#define MAC_SSID_LEN 32
+
+/// SSID.
+struct mac_ssid {
+ /// Actual length of the SSID.
+ u8 length;
+ /// Array containing the SSID name.
+ u8 array[MAC_SSID_LEN];
+};
+
+/// BSS type
+enum mac_bss_type {
+ INFRASTRUCTURE_MODE = 1,
+ INDEPENDENT_BSS_MODE,
+ ANY_BSS_MODE
+};
+
+/// Channel Band
+enum mac_chan_band {
+ /// 2.4GHz Band
+ PHY_BAND_2G4,
+ /// 5GHz band
+ PHY_BAND_5G,
+ /// Number of bands
+ PHY_BAND_MAX,
+};
+
+/// Operating Channel Bandwidth
+enum mac_chan_bandwidth {
+ /// 20MHz BW
+ PHY_CHNL_BW_20,
+ /// 40MHz BW
+ PHY_CHNL_BW_40,
+ /// 80MHz BW
+ PHY_CHNL_BW_80,
+ /// 160MHz BW
+ PHY_CHNL_BW_160,
+ /// 80+80MHz BW
+ PHY_CHNL_BW_80P80,
+ /// Reserved BW
+ PHY_CHNL_BW_OTHER,
+};
+
+/// max number of channels in the 2.4 GHZ band
+#define MAC_DOMAINCHANNEL_24G_MAX 14
+
+/// max number of channels in the 5 GHZ band
+#define MAC_DOMAINCHANNEL_5G_MAX 28
+
+/// Channel Flag
+enum mac_chan_flags {
+ /// Cannot initiate radiation on this channel
+ CHAN_NO_IR = BIT(0),
+ /// Channel is not allowed
+ CHAN_DISABLED = BIT(1),
+ /// Radar detection required on this channel
+ CHAN_RADAR = BIT(2),
+};
+
+/// Primary Channel definition
+struct mac_chan_def {
+ /// Frequency of the channel (in MHz)
+ u16 freq;
+ /// RF band (@ref mac_chan_band)
+ u8 band;
+ /// Additional information (@ref mac_chan_flags)
+ u8 flags;
+ /// Max transmit power allowed on this channel (dBm)
+ s8 tx_power;
+};
+
+/// Operating Channel
+struct mac_chan_op {
+ /// Band (@ref mac_chan_band)
+ u8 band;
+ /// Channel type (@ref mac_chan_bandwidth)
+ u8 type;
+ /// Frequency for Primary 20MHz channel (in MHz)
+ u16 prim20_freq;
+ /// Frequency center of the contiguous channel or center of Primary 80+80
+ /// (in MHz)
+ u16 center1_freq;
+ /// Frequency center of the non-contiguous secondary 80+80 (in MHz)
+ u16 center2_freq;
+ /// Max transmit power allowed on this channel (dBm)
+ s8 tx_power;
+ /// Additional information (@ref mac_chan_flags)
+ u8 flags;
+};
+
+/// Cipher suites (order is important as it is used by MACHW)
+enum mac_cipher_suite {
+ /// 00-0F-AC 1
+ MAC_CIPHER_WEP40 = 0,
+ /// 00-0F-AC 2
+ MAC_CIPHER_TKIP = 1,
+ /// 00-0F-AC 4
+ MAC_CIPHER_CCMP = 2,
+ /// 00-0F-AC 5
+ MAC_CIPHER_WEP104 = 3,
+ /// 00-14-72 1
+ MAC_CIPHER_WPI_SMS4 = 4,
+ /// 00-0F-AC 6 (aka AES_CMAC)
+ MAC_CIPHER_BIP_CMAC_128 = 5,
+
+ // following cipher are not supported by MACHW
+ /// 00-0F-AC 08
+ MAC_CIPHER_GCMP_128,
+ /// 00-0F-AC 09
+ MAC_CIPHER_GCMP_256,
+ /// 00-0F-AC 10
+ MAC_CIPHER_CCMP_256,
+ /// 00-0F-AC 11
+ MAC_CIPHER_BIP_GMAC_128,
+ /// 00-0F-AC 12
+ MAC_CIPHER_BIP_GMAC_256,
+ /// 00-0F-AC 13
+ MAC_CIPHER_BIP_CMAC_256,
+
+ MAC_CIPHER_INVALID = 0xFF
+};
+
+/// Authentication and Key Management suite
+enum mac_akm_suite {
+ /// No security
+ MAC_AKM_NONE,
+ /// Pre RSN (WEP or WPA)
+ MAC_AKM_PRE_RSN,
+ /// 00-0F-AC 1
+ MAC_AKM_8021X,
+ /// 00-0F-AC 2
+ MAC_AKM_PSK,
+ /// 00-0F-AC 3
+ MAC_AKM_FT_8021X,
+ /// 00-0F-AC 4
+ MAC_AKM_FT_PSK,
+ /// 00-0F-AC 5
+ MAC_AKM_8021X_SHA256,
+ /// 00-0F-AC 6
+ MAC_AKM_PSK_SHA256,
+ /// 00-0F-AC 7
+ MAC_AKM_TDLS,
+ /// 00-0F-AC 8
+ MAC_AKM_SAE,
+ /// 00-0F-AC 9
+ MAC_AKM_FT_OVER_SAE,
+ /// 00-0F-AC 11
+ MAC_AKM_8021X_SUITE_B,
+ /// 00-0F-AC 12
+ MAC_AKM_8021X_SUITE_B_192,
+ /// 00-0F-AC 14
+ MAC_AKM_FILS_SHA256,
+ /// 00-0F-AC 15
+ MAC_AKM_FILS_SHA384,
+ /// 00-0F-AC 16
+ MAC_AKM_FT_FILS_SHA256,
+ /// 00-0F-AC 17
+ MAC_AKM_FT_FILS_SHA384,
+ /// 00-0F-AC 18
+ MAC_AKM_OWE,
+
+ /// 00-14-72 1
+ MAC_AKM_WAPI_CERT,
+ /// 00-14-72 2
+ MAC_AKM_WAPI_PSK,
+};
+
+/// Scan result element, parsed from beacon or probe response frames.
+struct mac_scan_result {
+ /// Scan result is valid
+ bool valid_flag;
+ /// Network BSSID.
+ struct mac_addr bssid;
+ /// Network name.
+ struct mac_ssid ssid;
+ /// Network type (@ref mac_bss_type).
+ u16 bsstype;
+ /// Network channel.
+ struct mac_chan_def *chan;
+ /// Network beacon period (in TU).
+ u16 beacon_period;
+ /// Capability information
+ u16 cap_info;
+ /// Supported AKM (bit-field of @ref mac_akm_suite)
+ u32 akm;
+ /// Group cipher (bit-field of @ref mac_cipher_suite)
+ u16 group_cipher;
+ /// Group cipher (bit-field of @ref mac_cipher_suite)
+ u16 pairwise_cipher;
+ /// RSSI of the scanned BSS (in dBm)
+ s8 rssi;
+};
+
+/// Legacy rate 802.11 definitions
+enum mac_legacy_rates {
+ /// DSSS/CCK 1Mbps
+ MAC_RATE_1MBPS = 2,
+ /// DSSS/CCK 2Mbps
+ MAC_RATE_2MBPS = 4,
+ /// DSSS/CCK 5.5Mbps
+ MAC_RATE_5_5MBPS = 11,
+ /// OFDM 6Mbps
+ MAC_RATE_6MBPS = 12,
+ /// OFDM 9Mbps
+ MAC_RATE_9MBPS = 18,
+ /// DSSS/CCK 11Mbps
+ MAC_RATE_11MBPS = 22,
+ /// OFDM 12Mbps
+ MAC_RATE_12MBPS = 24,
+ /// OFDM 18Mbps
+ MAC_RATE_18MBPS = 36,
+ /// OFDM 24Mbps
+ MAC_RATE_24MBPS = 48,
+ /// OFDM 36Mbps
+ MAC_RATE_36MBPS = 72,
+ /// OFDM 48Mbps
+ MAC_RATE_48MBPS = 96,
+ /// OFDM 54Mbps
+ MAC_RATE_54MBPS = 108
+};
+
+/// BSS Membership Selector definitions
+enum mac_bss_membership {
+ /// HT PHY
+ MAC_BSS_MEMBERSHIP_HT_PHY = 127,
+ /// VHT PHY
+ MAC_BSS_MEMBERSHIP_VHT_PHY = 126,
+};
+
+/// MAC rateset maximum length
+#define MAC_RATESET_LEN 12
+
+/// Structure containing the legacy rateset of a station
+struct mac_rateset {
+ /// Number of legacy rates supported
+ u8 length;
+ /// Array of legacy rates
+ u8 array[MAC_RATESET_LEN];
+};
+
+/// MAC Security Key maximum length
+#define MAC_SEC_KEY_LEN 32 // TKIP keys 256 bits (max length) with MIC keys
+
+/// Structure defining a security key
+struct mac_sec_key {
+ /// Key material length
+ u8 length;
+ /// Key material
+ u32 array[MAC_SEC_KEY_LEN / 4];
+};
+
+/// Access Category enumeration
+enum mac_ac {
+ /// Background
+ AC_BK = 0,
+ /// Best-effort
+ AC_BE,
+ /// Video
+ AC_VI,
+ /// Voice
+ AC_VO,
+ /// Number of access categories
+ AC_MAX
+};
+
+/// Traffic ID enumeration
+enum mac_tid {
+ /// TID_0. Mapped to @ref AC_BE as per 802.11 standard.
+ TID_0,
+ /// TID_1. Mapped to @ref AC_BK as per 802.11 standard.
+ TID_1,
+ /// TID_2. Mapped to @ref AC_BK as per 802.11 standard.
+ TID_2,
+ /// TID_3. Mapped to @ref AC_BE as per 802.11 standard.
+ TID_3,
+ /// TID_4. Mapped to @ref AC_VI as per 802.11 standard.
+ TID_4,
+ /// TID_5. Mapped to @ref AC_VI as per 802.11 standard.
+ TID_5,
+ /// TID_6. Mapped to @ref AC_VO as per 802.11 standard.
+ TID_6,
+ /// TID_7. Mapped to @ref AC_VO as per 802.11 standard.
+ TID_7,
+ /// Non standard Management TID used internally
+ TID_MGT,
+ /// Number of TID supported
+ TID_MAX
+};
+
+/// MCS bitfield maximum size (in bytes)
+#define MAX_MCS_LEN 16 // 16 * 8 = 128
+
+/// MAC HT capability information element
+struct mac_htcapability {
+ /// HT capability information
+ __le16 ht_capa_info;
+ /// A-MPDU parameters
+ u8 a_mpdu_param;
+ /// Supported MCS
+ u8 mcs_rate[MAX_MCS_LEN];
+ /// HT extended capability information
+ __le16 ht_extended_capa;
+ /// Beamforming capability information
+ __le32 tx_beamforming_capa;
+ /// Antenna selection capability information
+ u8 asel_capa;
+};
+
+/// MAC VHT capability information element
+struct mac_vhtcapability {
+ /// VHT capability information
+ __le32 vht_capa_info;
+ /// RX MCS map
+ __le16 rx_mcs_map;
+ /// RX highest data rate
+ __le16 rx_highest;
+ /// TX MCS map
+ __le16 tx_mcs_map;
+ /// TX highest data rate
+ __le16 tx_highest;
+};
+
+/// Length (in bytes) of the MAC HE capability field
+#define MAC_HE_MAC_CAPA_LEN 6
+/// Length (in bytes) of the PHY HE capability field
+#define MAC_HE_PHY_CAPA_LEN 11
+/// Maximum length (in bytes) of the PPE threshold data
+#define MAC_HE_PPE_THRES_MAX_LEN 25
+
+/// Structure listing the per-NSS, per-BW supported MCS combinations
+struct mac_he_mcs_nss_supp {
+ /// per-NSS supported MCS in RX, for BW <= 80MHz
+ __le16 rx_mcs_80;
+ /// per-NSS supported MCS in TX, for BW <= 80MHz
+ __le16 tx_mcs_80;
+ /// per-NSS supported MCS in RX, for BW = 160MHz
+ __le16 rx_mcs_160;
+ /// per-NSS supported MCS in TX, for BW = 160MHz
+ __le16 tx_mcs_160;
+ /// per-NSS supported MCS in RX, for BW = 80+80MHz
+ __le16 rx_mcs_80p80;
+ /// per-NSS supported MCS in TX, for BW = 80+80MHz
+ __le16 tx_mcs_80p80;
+};
+
+/// MAC HE capability information element
+struct mac_hecapability {
+ /// MAC HE capabilities
+ u8 mac_cap_info[MAC_HE_MAC_CAPA_LEN];
+ /// PHY HE capabilities
+ u8 phy_cap_info[MAC_HE_PHY_CAPA_LEN];
+ /// Supported MCS combinations
+ struct mac_he_mcs_nss_supp mcs_supp;
+ /// PPE Thresholds data
+ u8 ppe_thres[MAC_HE_PPE_THRES_MAX_LEN];
+};
+
+/// Station flags
+enum mac_sta_flags {
+ /// Bit indicating that a STA has QoS (WMM) capability
+ STA_QOS_CAPA = BIT(0),
+ /// Bit indicating that a STA has HT capability
+ STA_HT_CAPA = BIT(1),
+ /// Bit indicating that a STA has VHT capability
+ STA_VHT_CAPA = BIT(2),
+ /// Bit indicating that a STA has MFP capability
+ STA_MFP_CAPA = BIT(3),
+ /// Bit indicating that the STA included the Operation Notification IE
+ STA_OPMOD_NOTIF = BIT(4),
+ /// Bit indicating that a STA has HE capability
+ STA_HE_CAPA = BIT(5),
+};
+
+/// Connection flags
+enum mac_connection_flags {
+ /// Flag indicating whether the control port is controlled by host or not
+ CONTROL_PORT_HOST = BIT(0),
+ /// Flag indicating whether the control port frame shall be sent unencrypted
+ CONTROL_PORT_NO_ENC = BIT(1),
+ /// Flag indicating whether HT and VHT shall be disabled or not
+ DISABLE_HT = BIT(2),
+ /// Flag indicating whether WPA or WPA2 authentication is in use
+ WPA_WPA2_IN_USE = BIT(3),
+ /// Flag indicating whether MFP is in use
+ MFP_IN_USE = BIT(4),
+ // Flag indicating Roam
+ REASSOCIATION = BIT(5),
+};
+
+#endif // LMAC_MAC_H_
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/lmac_msg.h b/drivers/net/wireless/aic/aic8800_fdrv/lmac_msg.h
new file mode 100644
index 0000000000000..8253fd8152fd1
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/lmac_msg.h
@@ -0,0 +1,3101 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ****************************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief Main definitions for message exchanges with LMAC
+ *
+ ****************************************************************************************
+ */
+
+#ifndef LMAC_MSG_H_
+#define LMAC_MSG_H_
+
+#include "lmac_mac.h"
+
+/* Task identifiers for communication between LMAC and DRIVER */
+enum {
+ TASK_NONE = 0xff,
+
+ // MAC Management task.
+ TASK_MM = 0,
+ // DEBUG task
+ TASK_DBG,
+ /// SCAN task
+ TASK_SCAN,
+ /// TDLS task
+ TASK_TDLS,
+ /// SCANU task
+ TASK_SCANU,
+ /// ME task
+ TASK_ME,
+ /// SM task
+ TASK_SM,
+ /// APM task
+ TASK_APM,
+ /// BAM task
+ TASK_BAM,
+ /// MESH task
+ TASK_MESH,
+ /// RXU task
+ TASK_RXU,
+ /// RM_task
+ TASK_RM,
+ /// TWT task
+ TASK_TWT,
+#if defined CONFIG_RWNX_FULLMAC
+ // This is used to define the last task that is running on the EMB processor
+ TASK_LAST_EMB = TASK_TWT,
+#else
+#error "Need to define SOFTMAC or FULLMAC"
+#endif
+ // nX API task
+ TASK_API,
+ TASK_MAX,
+};
+
+/// For MAC HW States copied from "hal_machw.h"
+enum {
+ /// MAC HW IDLE State.
+ HW_IDLE = 0,
+ /// MAC HW RESERVED State.
+ HW_RESERVED,
+ /// MAC HW DOZE State.
+ HW_DOZE,
+ /// MAC HW ACTIVE State.
+ HW_ACTIVE
+};
+
+/// Power Save mode setting
+enum mm_ps_mode_state {
+ MM_PS_MODE_OFF,
+ MM_PS_MODE_ON,
+ MM_PS_MODE_ON_DYN,
+};
+
+/// Status/error codes used in the MAC software.
+enum {
+ CO_OK,
+ CO_FAIL,
+ CO_EMPTY,
+ CO_FULL,
+ CO_BAD_PARAM,
+ CO_NOT_FOUND,
+ CO_NO_MORE_ELT_AVAILABLE,
+ CO_NO_ELT_IN_USE,
+ CO_BUSY,
+ CO_OP_IN_PROGRESS,
+};
+
+/// Remain on channel operation codes
+enum mm_remain_on_channel_op {
+ MM_ROC_OP_START = 0,
+ MM_ROC_OP_CANCEL,
+};
+
+#define DRV_TASK_ID 100
+
+/// Message Identifier. The number of messages is limited to 0xFFFF.
+/// The message ID is divided in two parts:
+/// - bits[15..10] : task index (no more than 64 tasks supported).
+/// - bits[9..0] : message index (no more that 1024 messages per task).
+typedef u16 lmac_msg_id_t;
+
+typedef u16 lmac_task_id_t;
+
+/// Build the first message ID of a task.
+#define LMAC_FIRST_MSG(task) ((lmac_msg_id_t)((task) << 10))
+
+#define MSG_T(msg) ((lmac_task_id_t)((msg) >> 10))
+#define MSG_I(msg) ((msg) & ((1 << 10) - 1))
+
+/// Message structure.
+struct lmac_msg {
+ lmac_msg_id_t id; ///< Message id.
+ lmac_task_id_t dest_id; ///< Destination kernel identifier.
+ lmac_task_id_t src_id; ///< Source kernel identifier.
+ u16 param_len; ///< Parameter embedded struct length.
+ u32 param[]; ///< Parameter embedded struct. Must be word-aligned.
+};
+
+/// List of messages related to the task.
+enum mm_msg_tag {
+ /// RESET Request.
+ MM_RESET_REQ = LMAC_FIRST_MSG(TASK_MM),
+ /// RESET Confirmation.
+ MM_RESET_CFM,
+ /// START Request.
+ MM_START_REQ,
+ /// START Confirmation.
+ MM_START_CFM,
+ /// Read Version Request.
+ MM_VERSION_REQ,
+ /// Read Version Confirmation.
+ MM_VERSION_CFM,
+ /// ADD INTERFACE Request.
+ MM_ADD_IF_REQ,
+ /// ADD INTERFACE Confirmation.
+ MM_ADD_IF_CFM,
+ /// REMOVE INTERFACE Request.
+ MM_REMOVE_IF_REQ,
+ /// REMOVE INTERFACE Confirmation.
+ MM_REMOVE_IF_CFM,
+ /// STA ADD Request.
+ MM_STA_ADD_REQ,
+ /// STA ADD Confirm.
+ MM_STA_ADD_CFM,
+ /// STA DEL Request.
+ MM_STA_DEL_REQ,
+ /// STA DEL Confirm.
+ MM_STA_DEL_CFM,
+ /// RX FILTER CONFIGURATION Request.
+ MM_SET_FILTER_REQ,
+ /// RX FILTER CONFIGURATION Confirmation.
+ MM_SET_FILTER_CFM,
+ /// CHANNEL CONFIGURATION Request.
+ MM_SET_CHANNEL_REQ,
+ /// CHANNEL CONFIGURATION Confirmation.
+ MM_SET_CHANNEL_CFM,
+ /// DTIM PERIOD CONFIGURATION Request.
+ MM_SET_DTIM_REQ,
+ /// DTIM PERIOD CONFIGURATION Confirmation.
+ MM_SET_DTIM_CFM,
+ /// BEACON INTERVAL CONFIGURATION Request.
+ MM_SET_BEACON_INT_REQ,
+ /// BEACON INTERVAL CONFIGURATION Confirmation.
+ MM_SET_BEACON_INT_CFM,
+ /// BASIC RATES CONFIGURATION Request.
+ MM_SET_BASIC_RATES_REQ,
+ /// BASIC RATES CONFIGURATION Confirmation.
+ MM_SET_BASIC_RATES_CFM,
+ /// BSSID CONFIGURATION Request.
+ MM_SET_BSSID_REQ,
+ /// BSSID CONFIGURATION Confirmation.
+ MM_SET_BSSID_CFM,
+ /// EDCA PARAMETERS CONFIGURATION Request.
+ MM_SET_EDCA_REQ,
+ /// EDCA PARAMETERS CONFIGURATION Confirmation.
+ MM_SET_EDCA_CFM,
+ /// ABGN MODE CONFIGURATION Request.
+ MM_SET_MODE_REQ,
+ /// ABGN MODE CONFIGURATION Confirmation.
+ MM_SET_MODE_CFM,
+ /// Request setting the VIF active state (i.e associated or AP started)
+ MM_SET_VIF_STATE_REQ,
+ /// Confirmation of the @ref MM_SET_VIF_STATE_REQ message.
+ MM_SET_VIF_STATE_CFM,
+ /// SLOT TIME PARAMETERS CONFIGURATION Request.
+ MM_SET_SLOTTIME_REQ,
+ /// SLOT TIME PARAMETERS CONFIGURATION Confirmation.
+ MM_SET_SLOTTIME_CFM,
+ /// Power Mode Change Request.
+ MM_SET_IDLE_REQ,
+ /// Power Mode Change Confirm.
+ MM_SET_IDLE_CFM,
+ /// KEY ADD Request.
+ MM_KEY_ADD_REQ,
+ /// KEY ADD Confirm.
+ MM_KEY_ADD_CFM,
+ /// KEY DEL Request.
+ MM_KEY_DEL_REQ,
+ /// KEY DEL Confirm.
+ MM_KEY_DEL_CFM,
+ /// Block Ack agreement info addition
+ MM_BA_ADD_REQ,
+ /// Block Ack agreement info addition confirmation
+ MM_BA_ADD_CFM,
+ /// Block Ack agreement info deletion
+ MM_BA_DEL_REQ,
+ /// Block Ack agreement info deletion confirmation
+ MM_BA_DEL_CFM,
+ /// Indication of the primary TBTT to the upper MAC. Upon the reception of
+ /// this
+ // message the upper MAC has to push the beacon(s) to the beacon
+ // transmission queue.
+ MM_PRIMARY_TBTT_IND,
+ /// Indication of the secondary TBTT to the upper MAC. Upon the reception of
+ /// this
+ // message the upper MAC has to push the beacon(s) to the beacon
+ // transmission queue.
+ MM_SECONDARY_TBTT_IND,
+ /// Request for changing the TX power
+ MM_SET_POWER_REQ,
+ /// Confirmation of the TX power change
+ MM_SET_POWER_CFM,
+ /// Request to the LMAC to trigger the embedded logic analyzer and forward
+ /// the debug
+ /// dump.
+ MM_DBG_TRIGGER_REQ,
+ /// Set Power Save mode
+ MM_SET_PS_MODE_REQ,
+ /// Set Power Save mode confirmation
+ MM_SET_PS_MODE_CFM,
+ /// Request to add a channel context
+ MM_CHAN_CTXT_ADD_REQ,
+ /// Confirmation of the channel context addition
+ MM_CHAN_CTXT_ADD_CFM,
+ /// Request to delete a channel context
+ MM_CHAN_CTXT_DEL_REQ,
+ /// Confirmation of the channel context deletion
+ MM_CHAN_CTXT_DEL_CFM,
+ /// Request to link a channel context to a VIF
+ MM_CHAN_CTXT_LINK_REQ,
+ /// Confirmation of the channel context link
+ MM_CHAN_CTXT_LINK_CFM,
+ /// Request to unlink a channel context from a VIF
+ MM_CHAN_CTXT_UNLINK_REQ,
+ /// Confirmation of the channel context unlink
+ MM_CHAN_CTXT_UNLINK_CFM,
+ /// Request to update a channel context
+ MM_CHAN_CTXT_UPDATE_REQ,
+ /// Confirmation of the channel context update
+ MM_CHAN_CTXT_UPDATE_CFM,
+ /// Request to schedule a channel context
+ MM_CHAN_CTXT_SCHED_REQ,
+ /// Confirmation of the channel context scheduling
+ MM_CHAN_CTXT_SCHED_CFM,
+ /// Request to change the beacon template in LMAC
+ MM_BCN_CHANGE_REQ,
+ /// Confirmation of the beacon change
+ MM_BCN_CHANGE_CFM,
+ /// Request to update the TIM in the beacon (i.e to indicate traffic
+ /// bufferized at AP)
+ MM_TIM_UPDATE_REQ,
+ /// Confirmation of the TIM update
+ MM_TIM_UPDATE_CFM,
+ /// Connection loss indication
+ MM_CONNECTION_LOSS_IND,
+ /// Channel context switch indication to the upper layers
+ MM_CHANNEL_SWITCH_IND,
+ /// Channel context pre-switch indication to the upper layers
+ MM_CHANNEL_PRE_SWITCH_IND,
+ /// Request to remain on channel or cancel remain on channel
+ MM_REMAIN_ON_CHANNEL_REQ,
+ /// Confirmation of the (cancel) remain on channel request
+ MM_REMAIN_ON_CHANNEL_CFM,
+ /// Remain on channel expired indication
+ MM_REMAIN_ON_CHANNEL_EXP_IND,
+ /// Indication of a PS state change of a peer device
+ MM_PS_CHANGE_IND,
+ /// Indication that some buffered traffic should be sent to the peer device
+ MM_TRAFFIC_REQ_IND,
+ /// Request to modify the STA Power-save mode options
+ MM_SET_PS_OPTIONS_REQ,
+ /// Confirmation of the PS options setting
+ MM_SET_PS_OPTIONS_CFM,
+ /// Indication of PS state change for a P2P VIF
+ MM_P2P_VIF_PS_CHANGE_IND,
+ /// Indication that CSA counter has been updated
+ MM_CSA_COUNTER_IND,
+ /// Channel occupation report indication
+ MM_CHANNEL_SURVEY_IND,
+ /// Message containing Beamformer Information
+ MM_BFMER_ENABLE_REQ,
+ /// Request to Start/Stop/Update NOA - GO Only
+ MM_SET_P2P_NOA_REQ,
+ /// Request to Start/Stop/Update Opportunistic PS - GO Only
+ MM_SET_P2P_OPPPS_REQ,
+ /// Start/Stop/Update NOA Confirmation
+ MM_SET_P2P_NOA_CFM,
+ /// Start/Stop/Update Opportunistic PS Confirmation
+ MM_SET_P2P_OPPPS_CFM,
+ /// P2P NoA Update Indication - GO Only
+ MM_P2P_NOA_UPD_IND,
+ /// Request to set RSSI threshold and RSSI hysteresis
+ MM_CFG_RSSI_REQ,
+ /// Indication that RSSI level is below or above the threshold
+ MM_RSSI_STATUS_IND,
+ /// Indication that CSA is done
+ MM_CSA_FINISH_IND,
+ /// Indication that CSA is in prorgess (resp. done) and traffic must be
+ /// stopped (resp. restarted)
+ MM_CSA_TRAFFIC_IND,
+ /// Request to update the group information of a station
+ MM_MU_GROUP_UPDATE_REQ,
+ /// Confirmation of the @ref MM_MU_GROUP_UPDATE_REQ message
+ MM_MU_GROUP_UPDATE_CFM,
+ /// Request to initialize the antenna diversity algorithm
+ MM_ANT_DIV_INIT_REQ,
+ /// Request to stop the antenna diversity algorithm
+ MM_ANT_DIV_STOP_REQ,
+ /// Request to update the antenna switch status
+ MM_ANT_DIV_UPDATE_REQ,
+ /// Request to switch the antenna connected to path_0
+ MM_SWITCH_ANTENNA_REQ,
+ /// Indication that a packet loss has occurred
+ MM_PKTLOSS_IND,
+
+ MM_SET_ARPOFFLOAD_REQ,
+ MM_SET_ARPOFFLOAD_CFM,
+ MM_SET_AGG_DISABLE_REQ,
+ MM_SET_AGG_DISABLE_CFM,
+ MM_SET_COEX_REQ,
+ MM_SET_COEX_CFM,
+ MM_SET_RF_CONFIG_REQ,
+ MM_SET_RF_CONFIG_CFM,
+ MM_SET_RF_CALIB_REQ,
+ MM_SET_RF_CALIB_CFM,
+
+ /// MU EDCA PARAMETERS Configuration Request.
+ MM_SET_MU_EDCA_REQ,
+ /// MU EDCA PARAMETERS Configuration Confirmation.
+ MM_SET_MU_EDCA_CFM,
+ /// UORA PARAMETERS Configuration Request.
+ MM_SET_UORA_REQ,
+ /// UORA PARAMETERS Configuration Confirmation.
+ MM_SET_UORA_CFM,
+ /// TXOP RTS THRESHOLD Configuration Request.
+ MM_SET_TXOP_RTS_THRES_REQ,
+ /// TXOP RTS THRESHOLD Configuration Confirmation.
+ MM_SET_TXOP_RTS_THRES_CFM,
+ /// HE BSS Color Configuration Request.
+ MM_SET_BSS_COLOR_REQ,
+ /// HE BSS Color Configuration Confirmation.
+ MM_SET_BSS_COLOR_CFM,
+
+ MM_GET_MAC_ADDR_REQ,
+ MM_GET_MAC_ADDR_CFM,
+
+ MM_GET_STA_INFO_REQ,
+ MM_GET_STA_INFO_CFM,
+
+ MM_SET_TXPWR_IDX_LVL_REQ,
+ MM_SET_TXPWR_IDX_LVL_CFM,
+
+ MM_SET_TXPWR_OFST_REQ,
+ MM_SET_TXPWR_OFST_CFM,
+
+ MM_SET_STACK_START_REQ,
+ MM_SET_STACK_START_CFM,
+
+ MM_APM_STALOSS_IND,
+
+ MM_SET_VENDOR_HWCONFIG_REQ,
+ MM_SET_VENDOR_HWCONFIG_CFM,
+
+ MM_GET_FW_VERSION_REQ,
+ MM_GET_FW_VERSION_CFM,
+
+ MM_SET_RESUME_RESTORE_REQ,
+ MM_SET_RESUME_RESTORE_CFM,
+
+ MM_GET_WIFI_DISABLE_REQ,
+ MM_GET_WIFI_DISABLE_CFM,
+
+ MM_CFG_RSSI_CFM,
+
+ MM_SET_VENDOR_SWCONFIG_REQ,
+ MM_SET_VENDOR_SWCONFIG_CFM,
+
+ MM_SET_TXPWR_LVL_ADJ_REQ,
+ MM_SET_TXPWR_LVL_ADJ_CFM,
+
+ MM_RADAR_DETECT_IND,
+
+ MM_SET_APF_PROG_REQ,
+ MM_SET_APF_PROG_CFM,
+
+ MM_GET_APF_PROG_REQ,
+ MM_GET_APF_PROG_CFM,
+
+ /// arp announcement frame reception indication
+ MM_ARP_ANNOUNCEMENT_IND,
+
+ /// MAX number of messages
+ MM_MAX,
+};
+
+/// Interface types
+enum {
+ /// ESS STA interface
+ MM_STA,
+ /// IBSS STA interface
+ MM_IBSS,
+ /// AP interface
+ MM_AP,
+ // Mesh Point interface
+ MM_MESH_POINT,
+ // Monitor interface
+ MM_MONITOR,
+};
+
+/// BA agreement types
+enum {
+ /// BlockAck agreement for TX
+ BA_AGMT_TX,
+ /// BlockAck agreement for RX
+ BA_AGMT_RX,
+};
+
+/// BA agreement related status
+enum {
+ /// Correct BA agreement establishment
+ BA_AGMT_ESTABLISHED,
+ /// BA agreement already exists for STA+TID requested, cannot override it
+ /// (should have been deleted first)
+ BA_AGMT_ALREADY_EXISTS,
+ /// Correct BA agreement deletion
+ BA_AGMT_DELETED,
+ /// BA agreement for the (STA, TID) doesn't exist so nothing to delete
+ BA_AGMT_DOESNT_EXIST,
+};
+
+/// Features supported by LMAC - Positions
+enum mm_features {
+ /// Beaconing
+ MM_FEAT_BCN_BIT = 0,
+ /*
+ * /// Autonomous Beacon Transmission
+ * MM_FEAT_AUTOBCN_BIT,
+ * /// Scan in LMAC
+ * MM_FEAT_HWSCAN_BIT,
+ * /// Connection Monitoring
+ * MM_FEAT_CMON_BIT,
+ * /// Multi Role
+ * MM_FEAT_MROLE_BIT,
+ */
+ /// Radar Detection
+ MM_FEAT_RADAR_BIT,
+ /// Power Save
+ MM_FEAT_PS_BIT,
+ /// UAPSD
+ MM_FEAT_UAPSD_BIT,
+ /// DPSM
+ // MM_FEAT_DPSM_BIT,
+ /// A-MPDU
+ MM_FEAT_AMPDU_BIT,
+ /// A-MSDU
+ MM_FEAT_AMSDU_BIT,
+ /// Channel Context
+ // MM_FEAT_CHNL_CTXT_BIT,
+ /// Packet reordering
+ // MM_FEAT_REORD_BIT,
+ /// P2P
+ MM_FEAT_P2P_BIT,
+ /// P2P Go
+ MM_FEAT_P2P_GO_BIT,
+ /// UMAC Present
+ MM_FEAT_UMAC_BIT,
+ /// VHT support
+ MM_FEAT_VHT_BIT,
+ /// Beamformee
+ MM_FEAT_BFMEE_BIT,
+ /// Beamformer
+ MM_FEAT_BFMER_BIT,
+ /// WAPI
+ MM_FEAT_WAPI_BIT,
+ /// MFP
+ MM_FEAT_MFP_BIT,
+ /// Mu-MIMO RX support
+ MM_FEAT_MU_MIMO_RX_BIT,
+ /// Mu-MIMO TX support
+ MM_FEAT_MU_MIMO_TX_BIT,
+ /// Wireless Mesh Networking
+ MM_FEAT_MESH_BIT,
+ /// TDLS support
+ MM_FEAT_TDLS_BIT,
+ /// Antenna Diversity support
+ MM_FEAT_ANT_DIV_BIT,
+ /// UF support
+ MM_FEAT_UF_BIT,
+ /// A-MSDU maximum size (bit0)
+ MM_AMSDU_MAX_SIZE_BIT0,
+ /// A-MSDU maximum size (bit1)
+ MM_AMSDU_MAX_SIZE_BIT1,
+ /// MON_DATA support
+ MM_FEAT_MON_DATA_BIT,
+ /// HE (802.11ax) support
+ MM_FEAT_HE_BIT,
+ /// TWT support
+ MM_FEAT_TWT_BIT,
+};
+
+/// Maximum number of words in the configuration buffer
+#define PHY_CFG_BUF_SIZE 16
+
+/// Structure containing the parameters of the PHY configuration
+struct phy_cfg_tag {
+ /// Buffer containing the parameters specific for the PHY used
+ u32 parameters[PHY_CFG_BUF_SIZE];
+};
+
+/// Structure containing the parameters of the Trident PHY configuration
+struct phy_trd_cfg_tag {
+ /// MDM type(nxm)(upper nibble) and MDM2RF path mapping(lower nibble)
+ u8 path_mapping;
+ /// TX DC offset compensation
+ u32 tx_dc_off_comp;
+};
+
+/// Structure containing the parameters of the Karst PHY configuration
+struct phy_karst_cfg_tag {
+ /// TX IQ mismatch compensation in 2.4GHz
+ u32 tx_iq_comp_2_4G[2];
+ /// RX IQ mismatch compensation in 2.4GHz
+ u32 rx_iq_comp_2_4G[2];
+ /// TX IQ mismatch compensation in 5GHz
+ u32 tx_iq_comp_5G[2];
+ /// RX IQ mismatch compensation in 5GHz
+ u32 rx_iq_comp_5G[2];
+ /// RF path used by default (0 or 1)
+ u8 path_used;
+};
+
+/// Structure containing the parameters of the @ref MM_START_REQ message
+struct mm_start_req {
+ /// PHY configuration
+ struct phy_cfg_tag phy_cfg;
+ /// UAPSD timeout
+ u32 uapsd_timeout;
+ /// Local LP clock accuracy (in ppm)
+ u16 lp_clk_accuracy;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_CHANNEL_REQ message
+struct mm_set_channel_req {
+ /// Channel information
+ struct mac_chan_op chan;
+ /// Index of the RF for which the channel has to be set (0: operating
+ /// (primary), 1: secondary RF (used for additional radar detection). This
+ /// parameter is reserved if no secondary RF is available in the system
+ u8 index;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_CHANNEL_CFM message
+struct mm_set_channel_cfm {
+ /// Radio index to be used in policy table
+ u8 radio_idx;
+ /// TX power configured (in dBm)
+ s8 power;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_DTIM_REQ message
+struct mm_set_dtim_req {
+ /// DTIM period
+ u8 dtim_period;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_POWER_REQ message
+struct mm_set_power_req {
+ /// Index of the interface for which the parameter is configured
+ u8 inst_nbr;
+ /// TX power (in dBm)
+ s8 power;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_POWER_CFM message
+struct mm_set_power_cfm {
+ /// Radio index to be used in policy table
+ u8 radio_idx;
+ /// TX power configured (in dBm)
+ s8 power;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_BEACON_INT_REQ
+/// message
+struct mm_set_beacon_int_req {
+ /// Beacon interval
+ u16 beacon_int;
+ /// Index of the interface for which the parameter is configured
+ u8 inst_nbr;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_BASIC_RATES_REQ
+/// message
+struct mm_set_basic_rates_req {
+ /// Basic rate set (as expected by bssBasicRateSet field of Rates MAC HW
+ /// register)
+ u32 rates;
+ /// Index of the interface for which the parameter is configured
+ u8 inst_nbr;
+ /// Band on which the interface will operate
+ u8 band;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_BSSID_REQ message
+struct mm_set_bssid_req {
+ /// BSSID to be configured in HW
+ struct mac_addr bssid;
+ /// Index of the interface for which the parameter is configured
+ u8 inst_nbr;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_FILTER_REQ message
+struct mm_set_filter_req {
+ /// RX filter to be put into rxCntrlReg HW register
+ u32 filter;
+};
+
+/// Structure containing the parameters of the @ref MM_ADD_IF_REQ message.
+struct mm_add_if_req {
+ /// Type of the interface (AP, STA, ADHOC, ...)
+ u8 type;
+ /// MAC ADDR of the interface to start
+ struct mac_addr addr;
+ /// P2P Interface
+ bool p2p;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_EDCA_REQ message
+struct mm_set_edca_req {
+ /// EDCA parameters of the queue (as expected by edcaACxReg HW register)
+ u32 ac_param;
+ /// Flag indicating if UAPSD can be used on this queue
+ bool uapsd;
+ /// HW queue for which the parameters are configured
+ u8 hw_queue;
+ /// Index of the interface for which the parameters are configured
+ u8 inst_nbr;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_MU_EDCA_REQ message
+struct mm_set_mu_edca_req {
+ /// MU EDCA parameters of the different HE queues
+ u32 param[AC_MAX];
+};
+
+/// Structure containing the parameters of the @ref MM_SET_UORA_REQ message
+struct mm_set_uora_req {
+ /// Minimum exponent of OFDMA Contention Window.
+ u8 eocw_min;
+ /// Maximum exponent of OFDMA Contention Window.
+ u8 eocw_max;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_TXOP_RTS_THRES_REQ
+/// message
+struct mm_set_txop_rts_thres_req {
+ /// TXOP RTS threshold
+ u16 txop_dur_rts_thres;
+ /// Index of the interface for which the parameter is configured
+ u8 inst_nbr;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_BSS_COLOR_REQ message
+struct mm_set_bss_color_req {
+ /// HE BSS color, formatted as per BSS_COLOR MAC HW register
+ u32 bss_color;
+};
+
+struct mm_set_idle_req {
+ u8 hw_idle;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_SLOTTIME_REQ message
+struct mm_set_slottime_req {
+ /// Slot time expressed in us
+ u8 slottime;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_MODE_REQ message
+struct mm_set_mode_req {
+ /// abgnMode field of macCntrl1Reg register
+ u8 abgnmode;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_VIF_STATE_REQ message
+struct mm_set_vif_state_req {
+ /// Association Id received from the AP (valid only if the VIF is of STA
+ /// type)
+ __le16 aid;
+ /// Flag indicating if the VIF is active or not
+ bool active;
+ /// Interface index
+ u8 inst_nbr;
+};
+
+/// Structure containing the parameters of the @ref MM_ADD_IF_CFM message.
+struct mm_add_if_cfm {
+ /// Status of operation (different from 0 if unsuccessful)
+ u8 status;
+ /// Interface index assigned by the LMAC
+ u8 inst_nbr;
+};
+
+/// Structure containing the parameters of the @ref MM_REMOVE_IF_REQ message.
+struct mm_remove_if_req {
+ /// Interface index assigned by the LMAC
+ u8 inst_nbr;
+};
+
+/// Structure containing the parameters of the @ref MM_VERSION_CFM message.
+struct mm_version_cfm {
+ /// Version of the LMAC FW
+ u32 version_lmac;
+ /// Version1 of the MAC HW (as encoded in version1Reg MAC HW register)
+ u32 version_machw_1;
+ /// Version2 of the MAC HW (as encoded in version2Reg MAC HW register)
+ u32 version_machw_2;
+ /// Version1 of the PHY (depends on actual PHY)
+ u32 version_phy_1;
+ /// Version2 of the PHY (depends on actual PHY)
+ u32 version_phy_2;
+ /// Supported Features
+ u32 features;
+ /// Maximum number of supported stations
+ u16 max_sta_nb;
+ /// Maximum number of supported virtual interfaces
+ u8 max_vif_nb;
+};
+
+/// Structure containing the parameters of the @ref MM_STA_ADD_REQ message.
+struct mm_sta_add_req {
+ /// Bitfield showing some capabilities of the STA (@ref enum mac_sta_flags)
+ u32 capa_flags;
+ /// Maximum A-MPDU size, in bytes, for HE frames
+ u32 ampdu_size_max_he;
+ /// Maximum A-MPDU size, in bytes, for VHT frames
+ u32 ampdu_size_max_vht;
+ /// PAID/GID
+ u32 paid_gid;
+ /// Maximum A-MPDU size, in bytes, for HT frames
+ u16 ampdu_size_max_ht;
+ /// MAC address of the station to be added
+ struct mac_addr mac_addr;
+ /// A-MPDU spacing, in us
+ u8 ampdu_spacing_min;
+ /// Interface index
+ u8 inst_nbr;
+ /// TDLS station
+ bool tdls_sta;
+ /// Indicate if the station is TDLS link initiator station
+ bool tdls_sta_initiator;
+ /// Indicate if the TDLS Channel Switch is allowed
+ bool tdls_chsw_allowed;
+ /// nonTransmitted BSSID index, set to the BSSID index in case the STA added
+ /// is an AP that is a nonTransmitted BSSID. Should be set to 0 otherwise
+ u8 bssid_index;
+ /// Maximum BSSID indicator, valid if the STA added is an AP that is a
+ /// nonTransmitted BSSID
+ u8 max_bssid_ind;
+};
+
+/// Structure containing the parameters of the @ref MM_STA_ADD_CFM message.
+struct mm_sta_add_cfm {
+ /// Status of the operation (different from 0 if unsuccessful)
+ u8 status;
+ /// Index assigned by the LMAC to the newly added station
+ u8 sta_idx;
+ /// MAC HW index of the newly added station
+ u8 hw_sta_idx;
+};
+
+/// Structure containing the parameters of the @ref MM_STA_DEL_REQ message.
+struct mm_sta_del_req {
+ /// Index of the station to be deleted
+ u8 sta_idx;
+};
+
+/// Structure containing the parameters of the @ref MM_STA_DEL_CFM message.
+struct mm_sta_del_cfm {
+ /// Status of the operation (different from 0 if unsuccessful)
+ u8 status;
+};
+
+/// Structure containing the parameters of the SET_POWER_MODE REQ message.
+struct mm_setpowermode_req {
+ u8 mode;
+ u8 sta_idx;
+};
+
+/// Structure containing the parameters of the SET_POWER_MODE CFM message.
+struct mm_setpowermode_cfm {
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref MM_KEY_ADD REQ message.
+struct mm_key_add_req {
+ /// Key index (valid only for default keys)
+ u8 key_idx;
+ /// STA index (valid only for pairwise or mesh group keys)
+ u8 sta_idx;
+ /// Key material
+ struct mac_sec_key key;
+ /// Cipher suite (WEP64, WEP128, TKIP, CCMP)
+ u8 cipher_suite;
+ /// Index of the interface for which the key is set (valid only for default
+ /// keys or mesh group keys)
+ u8 inst_nbr;
+ /// A-MSDU SPP parameter
+ u8 spp;
+ /// Indicate if provided key is a pairwise key or not
+ bool pairwise;
+};
+
+/// Structure containing the parameters of the @ref MM_KEY_ADD_CFM message.
+struct mm_key_add_cfm {
+ /// Status of the operation (different from 0 if unsuccessful)
+ u8 status;
+ /// HW index of the key just added
+ u8 hw_key_idx;
+};
+
+/// Structure containing the parameters of the @ref MM_KEY_DEL_REQ message.
+struct mm_key_del_req {
+ /// HW index of the key to be deleted
+ u8 hw_key_idx;
+};
+
+/// Structure containing the parameters of the @ref MM_BA_ADD_REQ message.
+struct mm_ba_add_req {
+ /// Type of agreement (0: TX, 1: RX)
+ u8 type;
+ /// Index of peer station with which the agreement is made
+ u8 sta_idx;
+ /// TID for which the agreement is made with peer station
+ u8 tid;
+ /// Buffer size - number of MPDUs that can be held in its buffer per TID
+ u8 bufsz;
+ /// Start sequence number negotiated during BA setup - the one in first
+ /// aggregated MPDU counts more
+ u16 ssn;
+};
+
+/// Structure containing the parameters of the @ref MM_BA_ADD_CFM message.
+struct mm_ba_add_cfm {
+ /// Index of peer station for which the agreement is being confirmed
+ u8 sta_idx;
+ /// TID for which the agreement is being confirmed
+ u8 tid;
+ /// Status of ba establishment
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref MM_BA_DEL_REQ message.
+struct mm_ba_del_req {
+ /// Type of agreement (0: TX, 1: RX)
+ u8 type;
+ /// Index of peer station for which the agreement is being deleted
+ u8 sta_idx;
+ /// TID for which the agreement is being deleted
+ u8 tid;
+};
+
+/// Structure containing the parameters of the @ref MM_BA_DEL_CFM message.
+struct mm_ba_del_cfm {
+ /// Index of peer station for which the agreement deletion is being
+ /// confirmed
+ u8 sta_idx;
+ /// TID for which the agreement deletion is being confirmed
+ u8 tid;
+ /// Status of ba deletion
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref MM_CHAN_CTXT_ADD_REQ message
+struct mm_chan_ctxt_add_req {
+ /// Operating channel
+ struct mac_chan_op chan;
+};
+
+/// Structure containing the parameters of the @ref MM_CHAN_CTXT_ADD_REQ message
+struct mm_chan_ctxt_add_cfm {
+ /// Status of the addition
+ u8 status;
+ /// Index of the new channel context
+ u8 index;
+};
+
+/// Structure containing the parameters of the @ref MM_CHAN_CTXT_DEL_REQ message
+struct mm_chan_ctxt_del_req {
+ /// Index of the new channel context to be deleted
+ u8 index;
+};
+
+/// Structure containing the parameters of the @ref MM_CHAN_CTXT_LINK_REQ
+/// message
+struct mm_chan_ctxt_link_req {
+ /// VIF index
+ u8 vif_index;
+ /// Channel context index
+ u8 chan_index;
+ /// Indicate if this is a channel switch (unlink current ctx first if true)
+ u8 chan_switch;
+};
+
+/// Structure containing the parameters of the @ref MM_CHAN_CTXT_UNLINK_REQ
+/// message
+struct mm_chan_ctxt_unlink_req {
+ /// VIF index
+ u8 vif_index;
+};
+
+/// Structure containing the parameters of the @ref MM_CHAN_CTXT_UPDATE_REQ
+/// message
+struct mm_chan_ctxt_update_req {
+ /// Channel context index
+ u8 chan_index;
+ /// New channel information
+ struct mac_chan_op chan;
+};
+
+/// Structure containing the parameters of the @ref MM_CHAN_CTXT_SCHED_REQ
+/// message
+struct mm_chan_ctxt_sched_req {
+ /// VIF index
+ u8 vif_index;
+ /// Channel context index
+ u8 chan_index;
+ /// Type of the scheduling request (0: normal scheduling, 1: derogatory
+ /// scheduling)
+ u8 type;
+};
+
+/// Structure containing the parameters of the @ref MM_CHANNEL_SWITCH_IND
+/// message
+struct mm_channel_switch_ind {
+ /// Index of the channel context we will switch to
+ u8 chan_index;
+ /// Indicate if the switch has been triggered by a Remain on channel request
+ bool roc;
+ /// VIF on which remain on channel operation has been started (if roc == 1)
+ u8 vif_index;
+ /// Indicate if the switch has been triggered by a TDLS Remain on channel
+ /// request
+ bool roc_tdls;
+};
+
+/// Structure containing the parameters of the @ref MM_CHANNEL_PRE_SWITCH_IND
+/// message
+struct mm_channel_pre_switch_ind {
+ /// Index of the channel context we will switch to
+ u8 chan_index;
+};
+
+/// Structure containing the parameters of the @ref MM_CONNECTION_LOSS_IND
+/// message.
+struct mm_connection_loss_ind {
+ /// VIF instance number
+ u8 inst_nbr;
+};
+
+/// Structure containing the parameters of the @ref MM_DBG_TRIGGER_REQ message.
+struct mm_dbg_trigger_req {
+ /// Error trace to be reported by the LMAC
+ char error[64];
+};
+
+/// Structure containing the parameters of the @ref MM_SET_PS_MODE_REQ message.
+struct mm_set_ps_mode_req {
+ /// Power Save is activated or deactivated
+ u8 new_state;
+};
+
+/// Structure containing the parameters of the @ref MM_BCN_CHANGE_REQ message.
+#define BCN_MAX_CSA_CPT 2
+struct mm_bcn_change_req {
+ /// Pointer, in host memory, to the new beacon template
+ u32 bcn_ptr;
+ /// Length of the beacon template
+ u16 bcn_len;
+ /// Offset of the TIM IE in the beacon
+ u16 tim_oft;
+ /// Length of the TIM IE
+ u8 tim_len;
+ /// Index of the VIF for which the beacon is updated
+ u8 inst_nbr;
+ /// Offset of CSA (channel switch announcement) counters (0 means no
+ /// counter)
+ u8 csa_oft[BCN_MAX_CSA_CPT];
+};
+
+/// Structure containing the parameters of the @ref MM_TIM_UPDATE_REQ message.
+struct mm_tim_update_req {
+ /// Association ID of the STA the bit of which has to be updated (0 for
+ /// BC/MC traffic)
+ u16 aid;
+ /// Flag indicating the availability of data packets for the given STA
+ u8 tx_avail;
+ /// Index of the VIF for which the TIM is updated
+ u8 inst_nbr;
+};
+
+/// Structure containing the parameters of the @ref MM_REMAIN_ON_CHANNEL_REQ
+/// message.
+struct mm_remain_on_channel_req {
+ /// Operation Code
+ u8 op_code;
+ /// VIF Index
+ u8 vif_index;
+ /// Band (2.4GHz or 5GHz)
+ u8 band;
+ /// Channel type: 20,40,80,160 or 80+80 MHz
+ u8 type;
+ /// Frequency for Primary 20MHz channel (in MHz)
+ u16 prim20_freq;
+ /// Frequency for Center of the contiguous channel or center of Primary
+ /// 80+80
+ u16 center1_freq;
+ /// Frequency for Center of the non-contiguous secondary 80+80
+ u16 center2_freq;
+ /// Duration (in ms)
+ u32 duration_ms;
+ /// TX power (in dBm)
+ s8 tx_power;
+};
+
+/// Structure containing the parameters of the @ref MM_REMAIN_ON_CHANNEL_CFM
+/// message
+struct mm_remain_on_channel_cfm {
+ /// Operation Code
+ u8 op_code;
+ /// Status of the operation
+ u8 status;
+ /// Channel Context index
+ u8 chan_ctxt_index;
+};
+
+/// Structure containing the parameters of the @ref MM_REMAIN_ON_CHANNEL_EXP_IND
+/// message
+struct mm_remain_on_channel_exp_ind {
+ /// VIF Index
+ u8 vif_index;
+ /// Channel Context index
+ u8 chan_ctxt_index;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_UAPSD_TMR_REQ
+/// message.
+struct mm_set_uapsd_tmr_req {
+ /// action: Start or Stop the timer
+ u8 action;
+ /// timeout value, in milliseconds
+ u32 timeout;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_UAPSD_TMR_CFM
+/// message.
+struct mm_set_uapsd_tmr_cfm {
+ /// Status of the operation (different from 0 if unsuccessful)
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref MM_PS_CHANGE_IND message
+struct mm_ps_change_ind {
+ /// Index of the peer device that is switching its PS state
+ u8 sta_idx;
+ /// New PS state of the peer device (0: active, 1: sleeping)
+ u8 ps_state;
+};
+
+/// Structure containing the parameters of the @ref MM_P2P_VIF_PS_CHANGE_IND
+/// message
+struct mm_p2p_vif_ps_change_ind {
+ /// Index of the P2P VIF that is switching its PS state
+ u8 vif_index;
+ /// New PS state of the P2P VIF interface (0: active, 1: sleeping)
+ u8 ps_state;
+};
+
+/// Structure containing the parameters of the @ref MM_TRAFFIC_REQ_IND message
+struct mm_traffic_req_ind {
+ /// Index of the peer device that needs traffic
+ u8 sta_idx;
+ /// Number of packets that need to be sent (if 0, all buffered traffic shall
+ /// be sent and if set to @ref PS_SP_INTERRUPTED, it means that current
+ /// service period has been interrupted)
+ u8 pkt_cnt;
+ /// Flag indicating if the traffic request concerns U-APSD queues or not
+ bool uapsd;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_PS_OPTIONS_REQ
+/// message.
+struct mm_set_ps_options_req {
+ /// VIF Index
+ u8 vif_index;
+ /// Listen interval (0 if wake up shall be based on DTIM period)
+ u16 listen_interval;
+ /// Flag indicating if we shall listen the BC/MC traffic or not
+ bool dont_listen_bc_mc;
+};
+
+/// Structure containing the parameters of the @ref MM_CSA_COUNTER_IND message
+struct mm_csa_counter_ind {
+ /// Index of the VIF
+ u8 vif_index;
+ /// Updated CSA counter value
+ u8 csa_count;
+};
+
+/// Structure containing the parameters of the @ref MM_CHANNEL_SURVEY_IND
+/// message
+struct mm_channel_survey_ind {
+ /// Frequency of the channel
+ u16 freq;
+ /// Noise in dbm
+ s8 noise_dbm;
+ /// Amount of time spent of the channel (in ms)
+ u32 chan_time_ms;
+ /// Amount of time the primary channel was sensed busy
+ u32 chan_time_busy_ms;
+};
+
+/// Structure containing the parameters of the @ref MM_BFMER_ENABLE_REQ message.
+struct mm_bfmer_enable_req {
+ /**
+ * Address of the beamforming report space allocated in host memory
+ * (Valid only if vht_su_bfmee is true)
+ */
+ u32 host_bfr_addr;
+ /**
+ * Size of the beamforming report space allocated in host memory. This space
+ * should be twice the maximum size of the expected beamforming reports as
+ * the FW will divide it in two in order to be able to upload a new report
+ * while another one is used in transmission
+ */
+ u16 host_bfr_size;
+ /// AID
+ u16 aid;
+ /// Station Index
+ u8 sta_idx;
+ /// Maximum number of spatial streams the station can receive
+ u8 rx_nss;
+ /**
+ * Indicate if peer STA is MU Beamformee (VHT) capable
+ * (Valid only if vht_su_bfmee is true)
+ */
+ bool vht_mu_bfmee;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_P2P_NOA_REQ message.
+struct mm_set_p2p_noa_req {
+ /// VIF Index
+ u8 vif_index;
+ /// Allocated NOA Instance Number - Valid only if count = 0
+ u8 noa_inst_nb;
+ /// Count
+ u8 count;
+ /// Indicate if NoA can be paused for traffic reason
+ bool dyn_noa;
+ /// Duration (in us)
+ u32 duration_us;
+ /// Interval (in us)
+ u32 interval_us;
+ /// Start Time offset from next TBTT (in us)
+ u32 start_offset;
+};
+
+#ifdef AICWF_ARP_OFFLOAD
+struct mm_set_arpoffload_en_req {
+ u32 ipaddr;
+ u8 enable;
+ u8 vif_idx;
+};
+
+struct mm_set_arpoffload_en_cfm {
+ u8 status;
+};
+#endif
+
+struct mm_set_agg_disable_req {
+ u8 disable;
+ u8 staidx;
+ u8 disable_rx;
+};
+
+struct mm_set_coex_req {
+ u8 bt_on;
+ u8 disable_coexnull;
+ u8 enable_nullcts;
+ u8 enable_periodic_timer;
+ u8 coex_timeslot_set;
+ u32 coex_timeslot[2];
+};
+
+struct mm_set_rf_config_req {
+ u8 table_sel;
+ u8 table_ofst;
+ u8 table_num;
+ u8 deft_page;
+ u32 data[64];
+};
+
+struct mm_set_rf_calib_req {
+ u32 cal_cfg_24g;
+ u32 cal_cfg_5g;
+ u32 param_alpha;
+ u32 bt_calib_en;
+ u32 bt_calib_param;
+ u8 xtal_cap;
+ u8 xtal_cap_fine;
+};
+
+struct mm_set_rf_calib_cfm {
+ u32 rxgain_24g_addr;
+ u32 rxgain_5g_addr;
+ u32 txgain_24g_addr;
+ u32 txgain_5g_addr;
+};
+
+struct mm_get_mac_addr_req {
+ u32 get;
+};
+
+struct mm_get_mac_addr_cfm {
+ u8 mac_addr[6];
+};
+
+struct mm_get_sta_info_req {
+ u8 sta_idx;
+};
+
+struct mm_get_sta_info_cfm {
+ u32 rate_info;
+ u32 txfailed;
+ u8 rssi;
+};
+
+#define REGION_NUM_MAX 5
+
+struct txpwr_lvl_conf {
+ u8 enable;
+ u8 dsss;
+ u8 ofdmlowrate_2g4;
+ u8 ofdm64qam_2g4;
+ u8 ofdm256qam_2g4;
+ u8 ofdm1024qam_2g4;
+ u8 ofdmlowrate_5g;
+ u8 ofdm64qam_5g;
+ u8 ofdm256qam_5g;
+ u8 ofdm1024qam_5g;
+};
+
+struct txpwr_lvl_conf_v2 {
+ u8 enable;
+ s8 pwrlvl_11b_11ag_2g4[12];
+ s8 pwrlvl_11n_11ac_2g4[10];
+ s8 pwrlvl_11ax_2g4[12];
+};
+
+struct txpwr_lvl_conf_v3 {
+ u8 enable;
+ s8 pwrlvl_11b_11ag_2g4[12];
+ s8 pwrlvl_11n_11ac_2g4[10];
+ s8 pwrlvl_11ax_2g4[12];
+ s8 pwrlvl_11a_5g[12];
+ s8 pwrlvl_11n_11ac_5g[10];
+ s8 pwrlvl_11ax_5g[12];
+};
+
+struct txpwr_lvl_adj_conf {
+ u8 enable;
+ s8 pwrlvl_adj_tbl_2g4[3];
+ s8 pwrlvl_adj_tbl_5g[6];
+};
+
+struct txpwr_loss_conf {
+ u8 loss_enable_2g4;
+ s8 loss_value_2g4;
+ u8 loss_enable_5g;
+ s8 loss_value_5g;
+};
+
+struct mm_set_txpwr_lvl_req {
+ union {
+ struct txpwr_lvl_conf txpwr_lvl;
+ struct txpwr_lvl_conf_v2 txpwr_lvl_v2;
+ struct txpwr_lvl_conf_v3 txpwr_lvl_v3;
+ };
+};
+
+struct mm_set_txpwr_lvl_adj_req {
+ struct txpwr_lvl_adj_conf txpwr_lvl_adj;
+};
+
+struct txpwr_idx_conf {
+ u8 enable;
+ u8 dsss;
+ u8 ofdmlowrate_2g4;
+ u8 ofdm64qam_2g4;
+ u8 ofdm256qam_2g4;
+ u8 ofdm1024qam_2g4;
+ u8 ofdmlowrate_5g;
+ u8 ofdm64qam_5g;
+ u8 ofdm256qam_5g;
+ u8 ofdm1024qam_5g;
+};
+
+struct mm_set_txpwr_idx_req {
+ struct txpwr_idx_conf txpwr_idx;
+};
+
+struct txpwr_ofst_conf {
+ u8 enable;
+ s8 chan_1_4;
+ s8 chan_5_9;
+ s8 chan_10_13;
+ s8 chan_36_64;
+ s8 chan_100_120;
+ s8 chan_122_140;
+ s8 chan_142_165;
+};
+
+/*
+ * pwrofst2x_tbl_2g4[3][3]:
+ * +---------------+----------+----------+----------+
+ * | RateTyp\ChGrp | CH_1_4 | CH_5_9 | CH_10_13 |
+ * +---------------+----------+----------+----------+
+ * | DSSS | [0][0] | [0][1] | [0][2] |
+ * +---------------+----------+----------+----------+
+ * | OFDM_HIGHRATE | [1][0] | [1][1] | [1][2] |
+ * +---------------+----------+----------+----------+
+ * | OFDM_LOWRATE | [2][0] | [2][1] | [2][2] |
+ * +---------------+----------+----------+----------+
+ * pwrofst2x_tbl_5g[3][6]:
+ * +---------------+--------------+--------------+----------------+----------------+--+--+
+ * | RateTyp\ChGrp | CH_42(36~50) | CH_58(51~64) | CH_106(98~114) |
+ * CH_122(115~130)| CH_138(131~146)| CH_155(147~166)|
+ * +---------------+--------------+--------------+----------------+----------------+--+--+
+ * | OFDM_LOWRATE | [0][0] | [0][1] | [0][2] | [0][3]
+ * | [0][4] | [0][5] |
+ * +---------------+--------------+--------------+----------------+----------------+--+--+
+ * | OFDM_HIGHRATE | [1][0] | [1][1] | [1][2] | [1][3]
+ * | [1][4] | [1][5] |
+ * +---------------+--------------+--------------+----------------+----------------+--+--+
+ * | OFDM_MIDRATE | [2][0] | [2][1] | [2][2] | [2][3]
+ * | [2][4] | [2][5] |
+ * +---------------+--------------+--------------+----------------+----------------+--+--+
+ */
+
+struct txpwr_ofst2x_conf {
+ s8 enable;
+ s8 pwrofst2x_tbl_2g4[3][3];
+ s8 pwrofst2x_tbl_5g[3][6];
+};
+
+struct xtal_cap_conf {
+ u8 enable;
+ u8 xtal_cap;
+ u8 xtal_cap_fine;
+};
+
+struct mm_set_txpwr_ofst_req {
+ union {
+ struct txpwr_ofst_conf txpwr_ofst;
+ struct txpwr_ofst2x_conf txpwr_ofst2x;
+ };
+};
+
+struct mm_set_stack_start_req {
+ u8 is_stack_start;
+ u8 efuse_valid;
+ u8 set_vendor_info;
+ u8 fwtrace_redir;
+};
+
+struct mm_set_stack_start_cfm {
+ u8 is_5g_support;
+ u8 vendor_info;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_P2P_OPPPS_REQ
+/// message.
+struct mm_set_p2p_oppps_req {
+ /// VIF Index
+ u8 vif_index;
+ /// CTWindow
+ u8 ctwindow;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_P2P_NOA_CFM message.
+struct mm_set_p2p_noa_cfm {
+ /// Request status
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref MM_SET_P2P_OPPPS_CFM
+/// message.
+struct mm_set_p2p_oppps_cfm {
+ /// Request status
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref MM_P2P_NOA_UPD_IND message.
+struct mm_p2p_noa_upd_ind {
+ /// VIF Index
+ u8 vif_index;
+ /// NOA Instance Number
+ u8 noa_inst_nb;
+ /// NoA Type
+ u8 noa_type;
+ /// Count
+ u8 count;
+ /// Duration (in us)
+ u32 duration_us;
+ /// Interval (in us)
+ u32 interval_us;
+ /// Start Time
+ u32 start_time;
+};
+
+/// Structure containing the parameters of the @ref MM_CFG_RSSI_REQ message
+struct mm_cfg_rssi_req {
+ /// Index of the VIF
+ u8 vif_index;
+ /// RSSI threshold
+ s8 rssi_thold;
+ /// RSSI hysteresis
+ u8 rssi_hyst;
+};
+
+/// Structure containing the parameters of the @ref MM_RSSI_STATUS_IND message
+struct mm_rssi_status_ind {
+ /// Index of the VIF
+ u8 vif_index;
+ /// Status of the RSSI
+ bool rssi_status;
+ /// Current RSSI
+ s8 rssi;
+};
+
+/// Structure containing the parameters of the @ref MM_PKTLOSS_IND message
+struct mm_pktloss_ind {
+ /// Index of the VIF
+ u8 vif_index;
+ /// Address of the STA for which there is a packet loss
+ struct mac_addr mac_addr;
+ /// Number of packets lost
+ u32 num_packets;
+};
+
+/// Structure containing the parameters of the @ref MM_CSA_FINISH_IND message
+struct mm_csa_finish_ind {
+ /// Index of the VIF
+ u8 vif_index;
+ /// Status of the operation
+ u8 status;
+ /// New channel ctx index
+ u8 chan_idx;
+};
+
+/// Structure containing the parameters of the @ref MM_CSA_TRAFFIC_IND message
+struct mm_csa_traffic_ind {
+ /// Index of the VIF
+ u8 vif_index;
+ /// Is tx traffic enable or disable
+ bool enable;
+};
+
+/// Structure containing the parameters of the @ref MM_MU_GROUP_UPDATE_REQ
+/// message. Size allocated for the structure depends of the number of group
+struct mm_mu_group_update_req {
+ /// Station index
+ u8 sta_idx;
+ /// Number of groups the STA belongs to
+ u8 group_cnt;
+ /// Group information
+ struct {
+ /// Group Id
+ u8 group_id;
+ /// User position
+ u8 user_pos;
+ } groups[];
+};
+
+///////////////////////////////////////////////////////////////////////////////
+/////////// For Scan messages
+///////////////////////////////////////////////////////////////////////////////
+enum scan_msg_tag {
+ /// Scanning start Request.
+ SCAN_START_REQ = LMAC_FIRST_MSG(TASK_SCAN),
+ /// Scanning start Confirmation.
+ SCAN_START_CFM,
+ /// End of scanning indication.
+ SCAN_DONE_IND,
+ /// Cancel scan request
+ SCAN_CANCEL_REQ,
+ /// Cancel scan confirmation
+ SCAN_CANCEL_CFM,
+
+ /// MAX number of messages
+ SCAN_MAX,
+};
+
+/// Maximum number of SSIDs in a scan request
+#define SCAN_SSID_MAX 3
+
+/// Maximum number of channels in a scan request
+#define SCAN_CHANNEL_MAX (MAC_DOMAINCHANNEL_24G_MAX + MAC_DOMAINCHANNEL_5G_MAX)
+
+/// Maximum length of the ProbeReq IEs (SoftMAC mode)
+#define SCAN_MAX_IE_LEN 300
+
+/// Maximum number of PHY bands supported
+#define SCAN_BAND_MAX 2
+
+/// Structure containing the parameters of the @ref SCAN_START_REQ message
+struct scan_start_req {
+ /// List of channel to be scanned
+ struct mac_chan_def chan[SCAN_CHANNEL_MAX];
+ /// List of SSIDs to be scanned
+ struct mac_ssid ssid[SCAN_SSID_MAX];
+ /// BSSID to be scanned
+ struct mac_addr bssid;
+ /// Pointer (in host memory) to the additional IEs that need to be added to
+ /// the ProbeReq (following the SSID element)
+ u32 add_ies;
+ /// Length of the additional IEs
+ u16 add_ie_len;
+ /// Index of the VIF that is scanning
+ u8 vif_idx;
+ /// Number of channels to scan
+ u8 chan_cnt;
+ /// Number of SSIDs to scan for
+ u8 ssid_cnt;
+ /// no CCK - For P2P frames not being sent at CCK rate in 2GHz band.
+ bool no_cck;
+ /// Scan duration, in us
+ u32 duration;
+};
+
+/// Structure containing the parameters of the @ref SCAN_START_CFM message
+struct scan_start_cfm {
+ /// Status of the request
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref SCAN_CANCEL_REQ message
+struct scan_cancel_req {
+};
+
+/// Structure containing the parameters of the @ref SCAN_START_CFM message
+struct scan_cancel_cfm {
+ /// Status of the request
+ u8 status;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+/////////// For Scanu messages
+///////////////////////////////////////////////////////////////////////////////
+/// Messages that are logically related to the task.
+enum {
+ /// Scan request from host.
+ SCANU_START_REQ = LMAC_FIRST_MSG(TASK_SCANU),
+ /// Scanning start Confirmation.
+ SCANU_START_CFM,
+ /// Join request
+ SCANU_JOIN_REQ,
+ /// Join confirmation.
+ SCANU_JOIN_CFM,
+ /// Scan result indication.
+ SCANU_RESULT_IND,
+ /// Fast scan request from any other module.
+ SCANU_FAST_REQ,
+ /// Confirmation of fast scan request.
+ SCANU_FAST_CFM,
+
+ SCANU_VENDOR_IE_REQ,
+ SCANU_VENDOR_IE_CFM,
+ SCANU_START_CFM_ADDTIONAL,
+ SCANU_CANCEL_REQ,
+ SCANU_CANCEL_CFM,
+
+ /// MAX number of messages
+ SCANU_MAX,
+};
+
+/// Maximum length of the additional ProbeReq IEs (FullMAC mode)
+#define SCANU_MAX_IE_LEN 200
+
+/// Structure containing the parameters of the @ref SCANU_START_REQ message
+struct scanu_start_req {
+ /// List of channel to be scanned
+ struct mac_chan_def chan[SCAN_CHANNEL_MAX];
+ /// List of SSIDs to be scanned
+ struct mac_ssid ssid[SCAN_SSID_MAX];
+ /// BSSID to be scanned (or WILDCARD BSSID if no BSSID is searched in
+ /// particular)
+ struct mac_addr bssid;
+ /// Address (in host memory) of the additional IEs that need to be added to
+ /// the ProbeReq (following the SSID element)
+ u32 add_ies;
+ /// Length of the additional IEs
+ u16 add_ie_len;
+ /// Index of the VIF that is scanning
+ u8 vif_idx;
+ /// Number of channels to scan
+ u8 chan_cnt;
+ /// Number of SSIDs to scan for
+ u8 ssid_cnt;
+ /// no CCK - For P2P frames not being sent at CCK rate in 2GHz band.
+ bool no_cck;
+ /// Scan duration, in us
+ u32 duration;
+};
+
+struct scanu_vendor_ie_req {
+ u16 add_ie_len;
+ u8 vif_idx;
+ u8 ie[256];
+};
+
+/// Structure containing the parameters of the @ref SCANU_START_CFM message
+struct scanu_start_cfm {
+ /// Index of the VIF that was scanning
+ u8 vif_idx;
+ /// Status of the request
+ u8 status;
+ /// Number of scan results available
+ u8 result_cnt;
+};
+
+/// Parameters of the @SCANU_RESULT_IND message
+struct scanu_result_ind {
+ /// Length of the frame
+ u16 length;
+ /// Frame control field of the frame.
+ u16 framectrl;
+ /// Center frequency on which we received the packet
+ u16 center_freq;
+ /// PHY band
+ u8 band;
+ /// Index of the station that sent the frame. 0xFF if unknown.
+ u8 sta_idx;
+ /// Index of the VIF that received the frame. 0xFF if unknown.
+ u8 inst_nbr;
+ /// RSSI of the received frame.
+ s8 rssi;
+ /// Frame payload.
+ u32 payload[];
+};
+
+struct rxu_arp_announcement_ind {
+ /// index of the vif
+ u8 vif_index;
+ u8 offset;
+ /// length of the frame
+ u16 length;
+ u32 rx_status;
+ /// frame payload
+ u8 payload[];
+};
+
+/// Structure containing the parameters of the message.
+struct scanu_fast_req {
+ /// The SSID to scan in the channel.
+ struct mac_ssid ssid;
+ /// BSSID.
+ struct mac_addr bssid;
+ /// Probe delay.
+ u16 probe_delay;
+ /// Minimum channel time.
+ u16 minch_time;
+ /// Maximum channel time.
+ u16 maxch_time;
+ /// The channel number to scan.
+ u16 ch_nbr;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+/////////// For ME messages
+///////////////////////////////////////////////////////////////////////////////
+/// Messages that are logically related to the task.
+enum {
+ /// Configuration request from host.
+ ME_CONFIG_REQ = LMAC_FIRST_MSG(TASK_ME),
+ /// Configuration confirmation.
+ ME_CONFIG_CFM,
+ /// Configuration request from host.
+ ME_CHAN_CONFIG_REQ,
+ /// Configuration confirmation.
+ ME_CHAN_CONFIG_CFM,
+ /// Set control port state for a station.
+ ME_SET_CONTROL_PORT_REQ,
+ /// Control port setting confirmation.
+ ME_SET_CONTROL_PORT_CFM,
+ /// TKIP MIC failure indication.
+ ME_TKIP_MIC_FAILURE_IND,
+ /// Add a station to the FW (AP mode)
+ ME_STA_ADD_REQ,
+ /// Confirmation of the STA addition
+ ME_STA_ADD_CFM,
+ /// Delete a station from the FW (AP mode)
+ ME_STA_DEL_REQ,
+ /// Confirmation of the STA deletion
+ ME_STA_DEL_CFM,
+ /// Indication of a TX RA/TID queue credit update
+ ME_TX_CREDITS_UPDATE_IND,
+ /// Request indicating to the FW that there is traffic buffered on host
+ ME_TRAFFIC_IND_REQ,
+ /// Confirmation that the @ref ME_TRAFFIC_IND_REQ has been executed
+ ME_TRAFFIC_IND_CFM,
+ /// Request of RC statistics to a station
+ ME_RC_STATS_REQ,
+ /// RC statistics confirmation
+ ME_RC_STATS_CFM,
+ /// RC fixed rate request
+ ME_RC_SET_RATE_REQ,
+ /// Configure monitor interface
+ ME_CONFIG_MONITOR_REQ,
+ /// Configure monitor interface response
+ ME_CONFIG_MONITOR_CFM,
+ /// Setting power Save mode request from host
+ ME_SET_PS_MODE_REQ,
+ /// Set power Save mode confirmation
+ ME_SET_PS_MODE_CFM,
+ /// Setting Low Power level request from host
+ ME_SET_LP_LEVEL_REQ,
+ /// Set Low Power level confirmation
+ ME_SET_LP_LEVEL_CFM,
+ /// MAX number of messages
+ ME_MAX,
+};
+
+/// Structure containing the parameters of the @ref ME_START_REQ message
+struct me_config_req {
+ /// HT Capabilities
+ struct mac_htcapability ht_cap;
+ /// VHT Capabilities
+ struct mac_vhtcapability vht_cap;
+ /// HE capabilities
+ struct mac_hecapability he_cap;
+ /// Lifetime of packets sent under a BlockAck agreement (expressed in TUs)
+ u16 tx_lft;
+ /// Maximum supported BW
+ u8 phy_bw_max;
+ /// Boolean indicating if HT is supported or not
+ bool ht_supp;
+ /// Boolean indicating if VHT is supported or not
+ bool vht_supp;
+ /// Boolean indicating if HE is supported or not
+ bool he_supp;
+ /// Boolean indicating if HE OFDMA UL is enabled or not
+ bool he_ul_on;
+ /// Boolean indicating if PS mode shall be enabled or not
+ bool ps_on;
+ /// Boolean indicating if Antenna Diversity shall be enabled or not
+ bool ant_div_on;
+ /// Boolean indicating if Dynamic PS mode shall be used or not
+ bool dpsm;
+};
+
+/// Structure containing the parameters of the @ref ME_CHAN_CONFIG_REQ message
+struct me_chan_config_req {
+ /// List of 2.4GHz supported channels
+ struct mac_chan_def chan2G4[MAC_DOMAINCHANNEL_24G_MAX];
+ /// List of 5GHz supported channels
+ struct mac_chan_def chan5G[MAC_DOMAINCHANNEL_5G_MAX];
+ /// Number of 2.4GHz channels in the list
+ u8 chan2G4_cnt;
+ /// Number of 5GHz channels in the list
+ u8 chan5G_cnt;
+};
+
+/// Structure containing the parameters of the @ref ME_SET_CONTROL_PORT_REQ
+/// message
+struct me_set_control_port_req {
+ /// Index of the station for which the control port is opened
+ u8 sta_idx;
+ /// Control port state
+ bool control_port_open;
+};
+
+/// Structure containing the parameters of the @ref ME_TKIP_MIC_FAILURE_IND
+/// message
+struct me_tkip_mic_failure_ind {
+ /// Address of the sending STA
+ struct mac_addr addr;
+ /// TSC value
+ u64 tsc;
+ /// Boolean indicating if the packet was a group or unicast one (true if
+ /// group)
+ bool ga;
+ /// Key Id
+ u8 keyid;
+ /// VIF index
+ u8 vif_idx;
+};
+
+/// Structure containing the parameters of the @ref ME_STA_ADD_REQ message
+struct me_sta_add_req {
+ /// MAC address of the station to be added
+ struct mac_addr mac_addr;
+ /// Supported legacy rates
+ struct mac_rateset rate_set;
+ /// HT Capabilities
+ struct mac_htcapability ht_cap;
+ /// VHT Capabilities
+ struct mac_vhtcapability vht_cap;
+ /// HE capabilities
+ struct mac_hecapability he_cap;
+ /// Flags giving additional information about the station (@ref
+ /// mac_sta_flags)
+ u32 flags;
+ /// Association ID of the station
+ __le16 aid;
+ /// Bit field indicating which queues have U-APSD enabled
+ u8 uapsd_queues;
+ /// Maximum size, in frames, of a APSD service period
+ u8 max_sp_len;
+ /// Operation mode information (valid if bit @ref STA_OPMOD_NOTIF is
+ /// set in the flags)
+ u8 opmode;
+ /// Index of the VIF the station is attached to
+ u8 vif_idx;
+ /// Whether the station is TDLS station
+ bool tdls_sta;
+ /// Indicate if the station is TDLS link initiator station
+ bool tdls_sta_initiator;
+ /// Indicate if the TDLS Channel Switch is allowed
+ bool tdls_chsw_allowed;
+};
+
+/// Structure containing the parameters of the @ref ME_STA_ADD_CFM message
+struct me_sta_add_cfm {
+ /// Station index
+ u8 sta_idx;
+ /// Status of the station addition
+ u8 status;
+ /// PM state of the station
+ u8 pm_state;
+};
+
+/// Structure containing the parameters of the @ref ME_STA_DEL_REQ message.
+struct me_sta_del_req {
+ /// Index of the station to be deleted
+ u8 sta_idx;
+ /// Whether the station is TDLS station
+ bool tdls_sta;
+};
+
+/// Structure containing the parameters of the @ref ME_TX_CREDITS_UPDATE_IND
+/// message.
+struct me_tx_credits_update_ind {
+ /// Index of the station for which the credits are updated
+ u8 sta_idx;
+ /// TID for which the credits are updated
+ u8 tid;
+ /// Offset to be applied on the credit count
+ s8 credits;
+};
+
+/// Structure containing the parameters of the @ref ME_TRAFFIC_IND_REQ message.
+struct me_traffic_ind_req {
+ /// Index of the station for which UAPSD traffic is available on host
+ u8 sta_idx;
+ /// Flag indicating the availability of UAPSD packets for the given STA
+ u8 tx_avail;
+ /// Indicate if traffic is on uapsd-enabled queues
+ bool uapsd;
+};
+
+struct mm_apm_staloss_ind {
+ u8 sta_idx;
+ u8 vif_idx;
+ u8 mac_addr[6];
+};
+
+enum vendor_hwconfig_tag {
+ ACS_TXOP_REQ = 0,
+ CHANNEL_ACCESS_REQ,
+ MAC_TIMESCALE_REQ,
+ CCA_THRESHOLD_REQ,
+ BWMODE_REQ,
+ CHIP_TEMP_GET_REQ,
+ AP_PS_LEVEL_SET_REQ,
+ CUSTOMIZED_FREQ_REQ,
+ WAKEUP_INFO_REQ,
+ KEEPALIVE_PKT_REQ,
+};
+
+enum {
+ BWMODE20M = 0,
+ BWMODE10M,
+ BWMODE5M,
+};
+
+struct mm_set_acs_txop_req {
+ u32 hwconfig_id;
+ u16 txop_bk;
+ u16 txop_be;
+ u16 txop_vi;
+ u16 txop_vo;
+};
+
+struct mm_set_channel_access_req {
+ u32 hwconfig_id;
+ u32 edca[4];
+ u8 vif_idx;
+ u8 retry_cnt;
+ u8 rts_en;
+ u8 long_nav_en;
+ u8 cfe_en;
+ u8 rc_retry_cnt[3];
+ s8 ccademod_th;
+};
+
+struct mm_set_mac_timescale_req {
+ u32 hwconfig_id;
+ u8 sifs_a_time;
+ u8 sifs_b_time;
+ u8 slot_time;
+ u8 rx_startdelay_ofdm;
+ u8 rx_startdelay_long;
+ u8 rx_startdelay_short;
+};
+
+struct mm_set_cca_threshold_req {
+ u32 hwconfig_id;
+ u8 auto_cca_en;
+ s8 cca20p_rise_th;
+ s8 cca20s_rise_th;
+ s8 cca20p_fall_th;
+ s8 cca20s_fall_th;
+};
+
+struct mm_set_bwmode_req {
+ u32 hwconfig_id;
+ u8 bwmode;
+};
+
+struct mm_get_chip_temp_req {
+ u32 hwconfig_id;
+};
+
+struct mm_get_chip_temp_cfm {
+ /// Temp degree val
+ s8 degree;
+};
+
+struct mm_set_ap_ps_level_req {
+ u32 hwconfig_id;
+ u8 ap_ps_level;
+};
+
+struct mm_set_vendor_hwconfig_cfm {
+ u32 hwconfig_id;
+ union {
+ struct mm_get_chip_temp_cfm chip_temp_cfm;
+ };
+};
+
+struct mm_set_customized_freq_req {
+ u32 hwconfig_id;
+ u16 raw_freq[4];
+ u16 map_freq[4];
+};
+
+struct mm_set_keepalive_req {
+ u32 hwconfig_id;
+ u16 code;
+ u16 length;
+ u32 intv;
+ u8 payload[];
+};
+
+struct mm_set_txop_req {
+ u16 txop_bk;
+ u16 txop_be;
+ u16 txop_vi;
+ u16 txop_vo;
+ u8 long_nav_en;
+ u8 cfe_en;
+};
+
+struct mm_set_wakeup_info_req {
+ u32 hwconfig_id;
+ u16 code;
+ u16 offset;
+ u16 length;
+ u16 length_win;
+ u8 mask_and_pattern[];
+};
+
+struct mm_get_fw_version_cfm {
+ u8 fw_version_len;
+ u8 fw_version[63];
+};
+
+struct mm_get_wifi_disable_cfm {
+ u8 wifi_disable;
+};
+
+enum vendor_swconfig_tag {
+ BCN_CFG_REQ = 0,
+ TEMP_COMP_SET_REQ,
+ TEMP_COMP_GET_REQ,
+ EXT_FLAGS_SET_REQ,
+ EXT_FLAGS_GET_REQ,
+ EXT_FLAGS_MASK_SET_REQ,
+};
+
+struct mm_set_bcn_cfg_req {
+ /// Ignore or not bcn tim bcmc bit
+ bool tim_bcmc_ignored_enable;
+};
+
+struct mm_set_bcn_cfg_cfm {
+ /// Request status
+ bool tim_bcmc_ignored_status;
+};
+
+struct mm_set_temp_comp_req {
+ /// Enable or not temp comp
+ u8 enable;
+ u8 reserved[3];
+ u32 tmr_period_ms;
+};
+
+struct mm_set_temp_comp_cfm {
+ /// Request status
+ u8 status;
+};
+
+struct mm_get_temp_comp_cfm {
+ /// Request status
+ u8 status;
+ /// Temp degree val
+ s8 degree;
+};
+
+struct mm_set_ext_flags_req {
+ u32 user_flags;
+};
+
+struct mm_set_ext_flags_cfm {
+ u32 user_flags;
+};
+
+struct mm_get_ext_flags_cfm {
+ u32 user_flags;
+};
+
+struct mm_mask_set_ext_flags_req {
+ u32 user_flags_mask;
+ u32 user_flags_val;
+};
+
+struct mm_mask_set_ext_flags_cfm {
+ u32 user_flags;
+};
+
+struct mm_set_vendor_swconfig_req {
+ u32 swconfig_id;
+ union {
+ struct mm_set_bcn_cfg_req bcn_cfg_req;
+ struct mm_set_temp_comp_req temp_comp_set_req;
+ struct mm_set_ext_flags_req ext_flags_set_req;
+ struct mm_mask_set_ext_flags_req ext_flags_mask_set_req;
+ };
+};
+
+struct mm_set_vendor_swconfig_cfm {
+ u32 swconfig_id;
+ union {
+ struct mm_set_bcn_cfg_cfm bcn_cfg_cfm;
+ struct mm_set_temp_comp_cfm temp_comp_set_cfm;
+ struct mm_get_temp_comp_cfm temp_comp_get_cfm;
+ struct mm_set_ext_flags_cfm ext_flags_set_cfm;
+ struct mm_get_ext_flags_cfm ext_flags_get_cfm;
+ struct mm_mask_set_ext_flags_cfm ext_flags_mask_set_cfm;
+ };
+};
+
+/// Structure containing the parameters of the @ref ME_RC_STATS_REQ message.
+struct me_rc_stats_req {
+ /// Index of the station for which the RC statistics are requested
+ u8 sta_idx;
+};
+
+/// Structure containing the rate control statistics
+struct rc_rate_stats {
+ /// Number of attempts (per sampling interval)
+ u16 attempts;
+ /// Number of success (per sampling interval)
+ u16 success;
+ /// Estimated probability of success (EWMA)
+ u16 probability;
+ /// Rate configuration of the sample
+ u16 rate_config;
+ union {
+ struct {
+ /// Number of times the sample has been skipped (per sampling
+ /// interval)
+ u8 sample_skipped;
+ /// Whether the old probability is available
+ bool old_prob_available;
+ /// Whether the rate can be used in the retry chain
+ bool rate_allowed;
+ };
+ struct {
+ /// RU size and UL length received in the latest HE trigger frame
+ u16 ru_and_length;
+ };
+ };
+};
+
+/// Number of RC samples
+#define RC_MAX_N_SAMPLE 10
+/// Index of the HE statistics element in the table
+#define RC_HE_STATS_IDX RC_MAX_N_SAMPLE
+
+/// Structure containing the parameters of the @ref ME_RC_STATS_CFM message.
+struct me_rc_stats_cfm {
+ /// Index of the station for which the RC statistics are provided
+ u8 sta_idx;
+ /// Number of samples used in the RC algorithm
+ u16 no_samples;
+ /// Number of MPDUs transmitted (per sampling interval)
+ u16 ampdu_len;
+ /// Number of AMPDUs transmitted (per sampling interval)
+ u16 ampdu_packets;
+ /// Average number of MPDUs in each AMPDU frame (EWMA)
+ u32 avg_ampdu_len;
+ // Current step 0 of the retry chain
+ u8 sw_retry_step;
+ /// Trial transmission period
+ u8 sample_wait;
+ /// Retry chain steps
+ u16 retry_step_idx[4];
+ /// RC statistics - Max number of RC samples, plus one for the HE TB
+ /// statistics
+ struct rc_rate_stats rate_stats[RC_MAX_N_SAMPLE + 1];
+ /// Throughput - Max number of RC samples, plus one for the HE TB statistics
+ u32 tp[RC_MAX_N_SAMPLE + 1];
+};
+
+/// Structure containing the parameters of the @ref ME_RC_SET_RATE_REQ message.
+struct me_rc_set_rate_req {
+ /// Index of the station for which the fixed rate is set
+ u8 sta_idx;
+ /// Rate configuration to be set
+ u16 fixed_rate_cfg;
+};
+
+/// Structure containing the parameters of the @ref ME_CONFIG_MONITOR_REQ
+/// message.
+struct me_config_monitor_req {
+ /// Channel to configure
+ struct mac_chan_op chan;
+ /// Is channel data valid
+ bool chan_set;
+ /// Enable report of unsupported HT frames
+ bool uf;
+ /// Enable auto-reply as the mac_addr matches
+ bool auto_reply;
+};
+
+/// Structure containing the parameters of the @ref ME_CONFIG_MONITOR_CFM
+/// message.
+struct me_config_monitor_cfm {
+ /// Channel context index
+ u8 chan_index;
+ /// Channel parameters
+ struct mac_chan_op chan;
+};
+
+/// Structure containing the parameters of the @ref ME_SET_PS_MODE_REQ message.
+struct me_set_ps_mode_req {
+ /// Power Save is activated or deactivated
+ u8 ps_state;
+};
+
+/// Structure containing the parameters of the @ref ME_SET_LP_LEVEL_REQ message.
+struct me_set_lp_level_req {
+ /// Low Power level
+ u8 lp_level;
+ u8 disable_filter;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+/////////// For SM messages
+///////////////////////////////////////////////////////////////////////////////
+/// Message API of the SM task
+enum sm_msg_tag {
+ /// Request to connect to an AP
+ SM_CONNECT_REQ = LMAC_FIRST_MSG(TASK_SM),
+ /// Confirmation of connection
+ SM_CONNECT_CFM,
+ /// Indicates that the SM associated to the AP
+ SM_CONNECT_IND,
+ /// Request to disconnect
+ SM_DISCONNECT_REQ,
+ /// Confirmation of disconnection
+ SM_DISCONNECT_CFM,
+ /// Indicates that the SM disassociated the AP
+ SM_DISCONNECT_IND,
+ /// Request to start external authentication
+ SM_EXTERNAL_AUTH_REQUIRED_IND,
+ /// Response to external authentication request
+ SM_EXTERNAL_AUTH_REQUIRED_RSP,
+ /// Request to update assoc elements after FT over the air authentication
+ SM_FT_AUTH_IND,
+ /// Response to FT authentication with updated assoc elements
+ SM_FT_AUTH_RSP,
+
+ SM_RSP_TIMEOUT_IND,
+
+ SM_COEX_TS_TIMEOUT_IND,
+
+ SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM,
+ /// MAX number of messages
+ SM_MAX,
+};
+
+/// Structure containing the parameters of @ref SM_CONNECT_REQ message.
+struct sm_connect_req {
+ /// SSID to connect to
+ struct mac_ssid ssid;
+ /// BSSID to connect to (if not specified, set this field to WILDCARD BSSID)
+ struct mac_addr bssid;
+ /// Channel on which we have to connect (if not specified, set -1 in the
+ /// chan.freq field)
+ struct mac_chan_def chan;
+ /// Connection flags (see @ref mac_connection_flags)
+ u32 flags;
+ /// Control port Ethertype (in network endianness)
+ __be16 ctrl_port_ethertype;
+ /// Length of the association request IEs
+ u16 ie_len;
+ /// Listen interval to be used for this connection
+ u16 listen_interval;
+ /// Flag indicating if the we have to wait for the BC/MC traffic after
+ /// beacon or not
+ bool dont_wait_bcmc;
+ /// Authentication type
+ u8 auth_type;
+ /// UAPSD queues (bit0: VO, bit1: VI, bit2: BE, bit3: BK)
+ u8 uapsd_queues;
+ /// VIF index
+ u8 vif_idx;
+ /// Buffer containing the additional information elements to be put in the
+ /// association request
+ u32 ie_buf[64];
+};
+
+/// Structure containing the parameters of the @ref SM_CONNECT_CFM message.
+struct sm_connect_cfm {
+ /// Status. If 0, it means that the connection procedure will be performed
+ /// and that a subsequent @ref SM_CONNECT_IND message will be forwarded once
+ /// the procedure is completed
+ u8 status;
+};
+
+#define SM_ASSOC_IE_LEN 800
+/// Structure containing the parameters of the @ref SM_CONNECT_IND message.
+struct sm_connect_ind {
+ /// Status code of the connection procedure
+ u16 status_code;
+ /// BSSID
+ struct mac_addr bssid;
+ /// Flag indicating if the indication refers to an internal roaming or from
+ /// a host request
+ bool roamed;
+ /// Index of the VIF for which the association process is complete
+ u8 vif_idx;
+ /// Index of the STA entry allocated for the AP
+ u8 ap_idx;
+ /// Index of the LMAC channel context the connection is attached to
+ u8 ch_idx;
+ /// Flag indicating if the AP is supporting QoS
+ bool qos;
+ /// ACM bits set in the AP WMM parameter element
+ u8 acm;
+ /// Length of the AssocReq IEs
+ u16 assoc_req_ie_len;
+ /// Length of the AssocRsp IEs
+ u16 assoc_rsp_ie_len;
+ /// IE buffer
+ u32 assoc_ie_buf[SM_ASSOC_IE_LEN / 4];
+
+ u16 aid;
+ u8 band;
+ u16 center_freq;
+ u8 width;
+ u32 center_freq1;
+ u32 center_freq2;
+
+ /// EDCA parameters
+ u32 ac_param[AC_MAX];
+};
+
+/// Structure containing the parameters of the @ref SM_DISCONNECT_REQ message.
+struct sm_disconnect_req {
+ /// Reason of the deauthentication.
+ u16 reason_code;
+ /// Index of the VIF.
+ u8 vif_idx;
+};
+
+/// Structure containing the parameters of SM_ASSOCIATION_IND the message
+struct sm_association_ind {
+ // MAC ADDR of the STA
+ struct mac_addr me_mac_addr;
+};
+
+/// Structure containing the parameters of the @ref SM_DISCONNECT_IND message.
+struct sm_disconnect_ind {
+ /// Reason of the disconnection.
+ u16 reason_code;
+ /// Index of the VIF.
+ u8 vif_idx;
+ /// FT over DS is ongoing
+ bool ft_over_ds;
+ u8 reassoc;
+};
+
+/// Structure containing the parameters of the @ref
+/// SM_EXTERNAL_AUTH_REQUIRED_IND
+struct sm_external_auth_required_ind {
+ /// Index of the VIF.
+ u8 vif_idx;
+ /// SSID to authenticate to
+ struct mac_ssid ssid;
+ /// BSSID to authenticate to
+ struct mac_addr bssid;
+ /// AKM suite of the respective authentication
+ u32 akm;
+};
+
+/// Structure containing the parameters of the @ref
+/// SM_EXTERNAL_AUTH_REQUIRED_RSP
+struct sm_external_auth_required_rsp {
+ /// Index of the VIF.
+ u8 vif_idx;
+ /// Authentication status
+ u16 status;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+/////////// For APM messages
+///////////////////////////////////////////////////////////////////////////////
+/// Message API of the APM task
+enum apm_msg_tag {
+ /// Request to start the AP.
+ APM_START_REQ = LMAC_FIRST_MSG(TASK_APM),
+ /// Confirmation of the AP start.
+ APM_START_CFM,
+ /// Request to stop the AP.
+ APM_STOP_REQ,
+ /// Confirmation of the AP stop.
+ APM_STOP_CFM,
+ /// Request to start CAC
+ APM_START_CAC_REQ,
+ /// Confirmation of the CAC start
+ APM_START_CAC_CFM,
+ /// Request to stop CAC
+ APM_STOP_CAC_REQ,
+ /// Confirmation of the CAC stop
+ APM_STOP_CAC_CFM,
+
+ APM_SET_BEACON_IE_REQ,
+ APM_SET_BEACON_IE_CFM,
+
+ /// MAX number of messages
+ APM_MAX,
+};
+
+/// Structure containing the parameters of the @ref APM_START_REQ message.
+struct apm_start_req {
+ /// Basic rate set
+ struct mac_rateset basic_rates;
+ /// Control channel on which we have to enable the AP
+ struct mac_chan_def chan;
+ /// Center frequency of the first segment
+ u32 center_freq1;
+ /// Center frequency of the second segment (only in 80+80 configuration)
+ u32 center_freq2;
+ /// Width of channel
+ u8 ch_width;
+ /// Address, in host memory, to the beacon template
+ u32 bcn_addr;
+ /// Length of the beacon template
+ u16 bcn_len;
+ /// Offset of the TIM IE in the beacon
+ u16 tim_oft;
+ /// Beacon interval
+ u16 bcn_int;
+ /// Flags (@ref mac_connection_flags)
+ u32 flags;
+ /// Control port Ethertype
+ __be16 ctrl_port_ethertype;
+ /// Length of the TIM IE
+ u8 tim_len;
+ /// Index of the VIF for which the AP is started
+ u8 vif_idx;
+};
+
+struct apm_set_bcn_ie_req {
+ u8 vif_idx;
+ u16 bcn_ie_len;
+ u8 bcn_ie[512];
+};
+
+/// Structure containing the parameters of the @ref APM_START_CFM message.
+struct apm_start_cfm {
+ /// Status of the AP starting procedure
+ u8 status;
+ /// Index of the VIF for which the AP is started
+ u8 vif_idx;
+ /// Index of the channel context attached to the VIF
+ u8 ch_idx;
+ /// Index of the STA used for BC/MC traffic
+ u8 bcmc_idx;
+};
+
+/// Structure containing the parameters of the @ref APM_STOP_REQ message.
+struct apm_stop_req {
+ /// Index of the VIF for which the AP has to be stopped
+ u8 vif_idx;
+};
+
+/// Structure containing the parameters of the @ref APM_START_CAC_REQ message.
+struct apm_start_cac_req {
+ /// Control channel on which we have to start the CAC
+ struct mac_chan_def chan;
+ /// Center frequency of the first segment
+ u32 center_freq1;
+ /// Center frequency of the second segment (only in 80+80 configuration)
+ u32 center_freq2;
+ /// Width of channel
+ u8 ch_width;
+ /// Index of the VIF for which the CAC is started
+ u8 vif_idx;
+};
+
+/// Structure containing the parameters of the @ref APM_START_CAC_CFM message.
+struct apm_start_cac_cfm {
+ /// Status of the CAC starting procedure
+ u8 status;
+ /// Index of the channel context attached to the VIF for CAC
+ u8 ch_idx;
+};
+
+/// Structure containing the parameters of the @ref APM_STOP_CAC_REQ message.
+struct apm_stop_cac_req {
+ /// Index of the VIF for which the CAC has to be stopped
+ u8 vif_idx;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+/////////// For MESH messages
+///////////////////////////////////////////////////////////////////////////////
+
+/// Maximum length of the Mesh ID
+#define MESH_MESHID_MAX_LEN (32)
+
+/// Message API of the MESH task
+enum mesh_msg_tag {
+ /// Request to start the MP
+ MESH_START_REQ = LMAC_FIRST_MSG(TASK_MESH),
+ /// Confirmation of the MP start.
+ MESH_START_CFM,
+
+ /// Request to stop the MP.
+ MESH_STOP_REQ,
+ /// Confirmation of the MP stop.
+ MESH_STOP_CFM,
+
+ // Request to update the MP
+ MESH_UPDATE_REQ,
+ /// Confirmation of the MP update
+ MESH_UPDATE_CFM,
+
+ /// Request information about a given link
+ MESH_PEER_INFO_REQ,
+ /// Response to the MESH_PEER_INFO_REQ message
+ MESH_PEER_INFO_CFM,
+
+ /// Request automatic establishment of a path with a given mesh STA
+ MESH_PATH_CREATE_REQ,
+ /// Confirmation to the MESH_PATH_CREATE_REQ message
+ MESH_PATH_CREATE_CFM,
+
+ /// Request a path update (delete path, modify next hop mesh STA)
+ MESH_PATH_UPDATE_REQ,
+ /// Confirmation to the MESH_PATH_UPDATE_REQ message
+ MESH_PATH_UPDATE_CFM,
+
+ /// Indication from Host that the indicated Mesh Interface is a proxy for an
+ /// external STA
+ MESH_PROXY_ADD_REQ,
+
+ /// Indicate that a connection has been established or lost
+ MESH_PEER_UPDATE_IND,
+ /// Notification that a connection has been established or lost (when MPM
+ /// handled by userspace)
+ MESH_PEER_UPDATE_NTF = MESH_PEER_UPDATE_IND,
+
+ /// Indicate that a path is now active or inactive
+ MESH_PATH_UPDATE_IND,
+ /// Indicate that proxy information have been updated
+ MESH_PROXY_UPDATE_IND,
+
+ /// MAX number of messages
+ MESH_MAX,
+};
+
+/// Structure containing the parameters of the @ref MESH_START_REQ message.
+struct mesh_start_req {
+ /// Basic rate set
+ struct mac_rateset basic_rates;
+ /// Control channel on which we have to enable the AP
+ struct mac_chan_def chan;
+ /// Center frequency of the first segment
+ u32 center_freq1;
+ /// Center frequency of the second segment (only in 80+80 configuration)
+ u32 center_freq2;
+ /// Width of channel
+ u8 ch_width;
+ /// DTIM Period
+ u8 dtim_period;
+ /// Beacon Interval
+ u16 bcn_int;
+ /// Index of the VIF for which the MP is started
+ u8 vif_index;
+ /// Length of the Mesh ID
+ u8 mesh_id_len;
+ /// Mesh ID
+ u8 mesh_id[MESH_MESHID_MAX_LEN];
+ /// Address of the IEs to download
+ u32 ie_addr;
+ /// Length of the provided IEs
+ u8 ie_len;
+ /// Indicate if Mesh Peering Management (MPM) protocol is handled in
+ /// userspace
+ bool user_mpm;
+ /// Indicate if Mesh Point is using authentication
+ bool is_auth;
+ /// Indicate which authentication method is used
+ u8 auth_id;
+};
+
+/// Structure containing the parameters of the @ref MESH_START_CFM message.
+struct mesh_start_cfm {
+ /// Status of the MP starting procedure
+ u8 status;
+ /// Index of the VIF for which the MP is started
+ u8 vif_idx;
+ /// Index of the channel context attached to the VIF
+ u8 ch_idx;
+ /// Index of the STA used for BC/MC traffic
+ u8 bcmc_idx;
+};
+
+/// Structure containing the parameters of the @ref MESH_STOP_REQ message.
+struct mesh_stop_req {
+ /// Index of the VIF for which the MP has to be stopped
+ u8 vif_idx;
+};
+
+/// Structure containing the parameters of the @ref MESH_STOP_CFM message.
+struct mesh_stop_cfm {
+ /// Index of the VIF for which the MP has to be stopped
+ u8 vif_idx;
+ /// Status
+ u8 status;
+};
+
+/// Bit fields for mesh_update_req message's flags value
+enum mesh_update_flags_bit {
+ /// Root Mode
+ MESH_UPDATE_FLAGS_ROOT_MODE_BIT = 0,
+ /// Gate Mode
+ MESH_UPDATE_FLAGS_GATE_MODE_BIT,
+ /// Mesh Forwarding
+ MESH_UPDATE_FLAGS_MESH_FWD_BIT,
+ /// Local Power Save Mode
+ MESH_UPDATE_FLAGS_LOCAL_PSM_BIT,
+};
+
+/// Structure containing the parameters of the @ref MESH_UPDATE_REQ message.
+struct mesh_update_req {
+ /// Flags, indicate fields which have been updated
+ u8 flags;
+ /// VIF Index
+ u8 vif_idx;
+ /// Root Mode
+ u8 root_mode;
+ /// Gate Announcement
+ bool gate_announ;
+ /// Mesh Forwarding
+ bool mesh_forward;
+ /// Local PS Mode
+ u8 local_ps_mode;
+};
+
+/// Structure containing the parameters of the @ref MESH_UPDATE_CFM message.
+struct mesh_update_cfm {
+ /// Status
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref MESH_PEER_INFO_REQ message.
+struct mesh_peer_info_req {
+ /// Index of the station allocated for the peer
+ u8 sta_idx;
+};
+
+/// Structure containing the parameters of the @ref MESH_PEER_INFO_CFM message.
+struct mesh_peer_info_cfm {
+ /// Response status
+ u8 status;
+ /// Index of the station allocated for the peer
+ u8 sta_idx;
+ /// Local Link ID
+ u16 local_link_id;
+ /// Peer Link ID
+ u16 peer_link_id;
+ /// Local PS Mode
+ u8 local_ps_mode;
+ /// Peer PS Mode
+ u8 peer_ps_mode;
+ /// Non-peer PS Mode
+ u8 non_peer_ps_mode;
+ /// Link State
+ u8 link_state;
+};
+
+/// Structure containing the parameters of the @ref MESH_PATH_CREATE_REQ
+/// message.
+struct mesh_path_create_req {
+ /// Index of the interface on which path has to be created
+ u8 vif_idx;
+ /// Indicate if originator MAC Address is provided
+ bool has_orig_addr;
+ /// Path Target MAC Address
+ struct mac_addr tgt_mac_addr;
+ /// Originator MAC Address
+ struct mac_addr orig_mac_addr;
+};
+
+/// Structure containing the parameters of the @ref MESH_PATH_CREATE_CFM
+/// message.
+struct mesh_path_create_cfm {
+ /// Confirmation status
+ u8 status;
+ /// VIF Index
+ u8 vif_idx;
+};
+
+/// Structure containing the parameters of the @ref MESH_PATH_UPDATE_REQ
+/// message.
+struct mesh_path_update_req {
+ /// Indicate if path must be deleted
+ bool delete;
+ /// Index of the interface on which path has to be created
+ u8 vif_idx;
+ /// Path Target MAC Address
+ struct mac_addr tgt_mac_addr;
+ /// Next Hop MAC Address
+ struct mac_addr nhop_mac_addr;
+};
+
+/// Structure containing the parameters of the @ref MESH_PATH_UPDATE_CFM
+/// message.
+struct mesh_path_update_cfm {
+ /// Confirmation status
+ u8 status;
+ /// VIF Index
+ u8 vif_idx;
+};
+
+/// Structure containing the parameters of the @ref MESH_PROXY_ADD_REQ message.
+struct mesh_proxy_add_req {
+ /// VIF Index
+ u8 vif_idx;
+ /// MAC Address of the External STA
+ struct mac_addr ext_sta_addr;
+};
+
+/// Structure containing the parameters of the @ref MESH_PROXY_UPDATE_IND
+struct mesh_proxy_update_ind {
+ /// Indicate if proxy information has been added or deleted
+ bool delete;
+ /// Indicate if we are a proxy for the external STA
+ bool local;
+ /// VIF Index
+ u8 vif_idx;
+ /// MAC Address of the External STA
+ struct mac_addr ext_sta_addr;
+ /// MAC Address of the proxy (only valid if local is false)
+ struct mac_addr proxy_mac_addr;
+};
+
+/// Structure containing the parameters of the @ref MESH_PEER_UPDATE_IND
+/// message.
+struct mesh_peer_update_ind {
+ /// Indicate if connection has been established or lost
+ bool estab;
+ /// VIF Index
+ u8 vif_idx;
+ /// STA Index
+ u8 sta_idx;
+ /// Peer MAC Address
+ struct mac_addr peer_addr;
+};
+
+/// Structure containing the parameters of the @ref MESH_PEER_UPDATE_NTF
+/// message.
+struct mesh_peer_update_ntf {
+ /// VIF Index
+ u8 vif_idx;
+ /// STA Index
+ u8 sta_idx;
+ /// Mesh Link State
+ u8 state;
+};
+
+/// Structure containing the parameters of the @ref MESH_PATH_UPDATE_IND
+/// message.
+struct mesh_path_update_ind {
+ /// Indicate if path is deleted or not
+ bool delete;
+ /// Indicate if path is towards an external STA (not part of MBSS)
+ bool ext_sta;
+ /// VIF Index
+ u8 vif_idx;
+ /// Path Index
+ u8 path_idx;
+ /// Target MAC Address
+ struct mac_addr tgt_mac_addr;
+ /// External STA MAC Address (only if ext_sta is true)
+ struct mac_addr ext_sta_mac_addr;
+ /// Next Hop STA Index
+ u8 nhop_sta_idx;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+/////////// For Debug messages
+///////////////////////////////////////////////////////////////////////////////
+
+/// Messages related to Debug Task
+enum dbg_msg_tag {
+ /// Memory read request
+ DBG_MEM_READ_REQ = LMAC_FIRST_MSG(TASK_DBG),
+ /// Memory read confirm
+ DBG_MEM_READ_CFM,
+ /// Memory write request
+ DBG_MEM_WRITE_REQ,
+ /// Memory write confirm
+ DBG_MEM_WRITE_CFM,
+ /// Module filter request
+ DBG_SET_MOD_FILTER_REQ,
+ /// Module filter confirm
+ DBG_SET_MOD_FILTER_CFM,
+ /// Severity filter request
+ DBG_SET_SEV_FILTER_REQ,
+ /// Severity filter confirm
+ DBG_SET_SEV_FILTER_CFM,
+ /// LMAC/MAC HW fatal error indication
+ DBG_ERROR_IND,
+ /// Request to get system statistics
+ DBG_GET_SYS_STAT_REQ,
+ /// COnfirmation of system statistics
+ DBG_GET_SYS_STAT_CFM,
+ /// Memory block write request
+ DBG_MEM_BLOCK_WRITE_REQ,
+ /// Memory block write confirm
+ DBG_MEM_BLOCK_WRITE_CFM,
+ /// Start app request
+ DBG_START_APP_REQ,
+ /// Start app confirm
+ DBG_START_APP_CFM,
+ /// Start npc request
+ DBG_START_NPC_REQ,
+ /// Start npc confirm
+ DBG_START_NPC_CFM,
+ /// Memory mask write request
+ DBG_MEM_MASK_WRITE_REQ,
+ /// Memory mask write confirm
+ DBG_MEM_MASK_WRITE_CFM,
+
+ DBG_RFTEST_CMD_REQ,
+ DBG_RFTEST_CMD_CFM,
+ DBG_BINDING_REQ,
+ DBG_BINDING_CFM,
+ DBG_BINDING_IND,
+
+ DBG_CUSTOM_MSG_REQ,
+ DBG_CUSTOM_MSG_CFM,
+ DBG_CUSTOM_MSG_IND,
+
+ DBG_GPIO_WRITE_REQ,
+ DBG_GPIO_WRITE_CFM,
+ DBG_GPIO_READ_REQ,
+ DBG_GPIO_READ_CFM,
+ DBG_GPIO_INIT_REQ,
+ DBG_GPIO_INIT_CFM,
+
+ /// EF usrdata read request
+ DBG_EF_USRDATA_READ_REQ,
+ /// EF usrdata read confirm
+ DBG_EF_USRDATA_READ_CFM,
+ /// Memory block read request
+ DBG_MEM_BLOCK_READ_REQ,
+ /// Memory block read confirm
+ DBG_MEM_BLOCK_READ_CFM,
+
+ DBG_PWM_INIT_REQ,
+ DBG_PWM_INIT_CFM,
+ DBG_PWM_DEINIT_REQ,
+ DBG_PWM_DEINIT_CFM,
+
+ /// Max number of Debug messages
+ DBG_MAX,
+};
+
+/// Structure containing the parameters of the @ref DBG_MEM_READ_REQ message.
+struct dbg_mem_read_req {
+ u32 memaddr;
+};
+
+/// Structure containing the parameters of the @ref DBG_MEM_READ_CFM message.
+struct dbg_mem_read_cfm {
+ u32 memaddr;
+ u32 memdata;
+};
+
+/// Structure containing the parameters of the @ref DBG_MEM_WRITE_REQ message.
+struct dbg_mem_write_req {
+ u32 memaddr;
+ u32 memdata;
+};
+
+/// Structure containing the parameters of the @ref DBG_MEM_WRITE_CFM message.
+struct dbg_mem_write_cfm {
+ u32 memaddr;
+ u32 memdata;
+};
+
+/// Structure containing the parameters of the @ref DBG_MEM_MASK_WRITE_REQ
+/// message.
+struct dbg_mem_mask_write_req {
+ u32 memaddr;
+ u32 memmask;
+ u32 memdata;
+};
+
+/// Structure containing the parameters of the @ref DBG_MEM_MASK_WRITE_CFM
+/// message.
+struct dbg_mem_mask_write_cfm {
+ u32 memaddr;
+ u32 memdata;
+};
+
+struct dbg_rftest_cmd_req {
+ u32 cmd;
+ u32 argc;
+ u8 argv[30];
+};
+
+struct dbg_rftest_cmd_cfm {
+ u32 rftest_result[18];
+};
+
+struct dbg_gpio_write_req {
+ u8 gpio_idx;
+ u8 gpio_val;
+};
+
+struct dbg_gpio_read_req {
+ u8 gpio_idx;
+};
+
+struct dbg_gpio_read_cfm {
+ u8 gpio_idx;
+ u8 gpio_val;
+};
+
+struct dbg_gpio_init_req {
+ u8 gpio_idx;
+ u8 gpio_dir; // 1 output, 0 input;
+ u8 gpio_val; // for output, 1 high, 0 low;
+};
+
+/// Structure containing the parameters of the @ref DBG_SET_MOD_FILTER_REQ
+/// message.
+struct dbg_set_mod_filter_req {
+ /// Bit field indicating for each module if the traces are enabled or not
+ u32 mod_filter;
+};
+
+/// Structure containing the parameters of the @ref DBG_SEV_MOD_FILTER_REQ
+/// message.
+struct dbg_set_sev_filter_req {
+ /// Bit field indicating the severity threshold for the traces
+ u32 sev_filter;
+};
+
+/// Structure containing the parameters of the @ref DBG_GET_SYS_STAT_CFM
+/// message.
+struct dbg_get_sys_stat_cfm {
+ /// Time spent in CPU sleep since last reset of the system statistics
+ u32 cpu_sleep_time;
+ /// Time spent in DOZE since last reset of the system statistics
+ u32 doze_time;
+ /// Total time spent since last reset of the system statistics
+ u32 stats_time;
+};
+
+/// Structure containing the parameters of the @ref DBG_MEM_BLOCK_WRITE_REQ
+/// message.
+struct dbg_mem_block_write_req {
+ u32 memaddr;
+ u32 memsize;
+ u32 memdata[1024 / sizeof(u32)];
+};
+
+/// Structure containing the parameters of the @ref DBG_MEM_BLOCK_WRITE_CFM
+/// message.
+struct dbg_mem_block_write_cfm {
+ u32 wstatus;
+};
+
+/// Structure containing the parameters of the @ref DBG_START_APP_REQ message.
+struct dbg_start_app_req {
+ u32 bootaddr;
+ u32 boottype;
+};
+
+/// Structure containing the parameters of the @ref DBG_START_APP_CFM message.
+struct dbg_start_app_cfm {
+ u32 bootstatus;
+};
+
+enum {
+ HOST_START_APP_AUTO = 1,
+ HOST_START_APP_CUSTOM,
+ HOST_START_APP_FNCALL = 4,
+ HOST_START_APP_DUMMY = 5,
+};
+
+///////////////////////////////////////////////////////////////////////////////
+/////////// For TDLS messages
+///////////////////////////////////////////////////////////////////////////////
+
+/// List of messages related to the task.
+enum tdls_msg_tag {
+ /// TDLS channel Switch Request.
+ TDLS_CHAN_SWITCH_REQ = LMAC_FIRST_MSG(TASK_TDLS),
+ /// TDLS channel switch confirmation.
+ TDLS_CHAN_SWITCH_CFM,
+ /// TDLS channel switch indication.
+ TDLS_CHAN_SWITCH_IND,
+ /// TDLS channel switch to base channel indication.
+ TDLS_CHAN_SWITCH_BASE_IND,
+ /// TDLS cancel channel switch request.
+ TDLS_CANCEL_CHAN_SWITCH_REQ,
+ /// TDLS cancel channel switch confirmation.
+ TDLS_CANCEL_CHAN_SWITCH_CFM,
+ /// TDLS peer power save indication.
+ TDLS_PEER_PS_IND,
+ /// TDLS peer traffic indication request.
+ TDLS_PEER_TRAFFIC_IND_REQ,
+ /// TDLS peer traffic indication confirmation.
+ TDLS_PEER_TRAFFIC_IND_CFM,
+
+ /// MAX number of messages
+ TDLS_MAX
+};
+
+/// Structure containing the parameters of the @ref TDLS_CHAN_SWITCH_REQ message
+struct tdls_chan_switch_req {
+ /// Index of the VIF
+ u8 vif_index;
+ /// STA Index
+ u8 sta_idx;
+ /// MAC address of the TDLS station
+ struct mac_addr peer_mac_addr;
+ bool initiator;
+ /// Band (2.4GHz or 5GHz)
+ u8 band;
+ /// Channel type: 20,40,80,160 or 80+80 MHz
+ u8 type;
+ /// Frequency for Primary 20MHz channel (in MHz)
+ u16 prim20_freq;
+ /// Frequency for Center of the contiguous channel or center of Primary
+ /// 80+80
+ u16 center1_freq;
+ /// Frequency for Center of the non-contiguous secondary 80+80
+ u16 center2_freq;
+ /// TX power (in dBm)
+ s8 tx_power;
+ /// Operating class
+ u8 op_class;
+};
+
+/// Structure containing the parameters of the @ref TDLS_CANCEL_CHAN_SWITCH_REQ
+/// message
+struct tdls_cancel_chan_switch_req {
+ /// Index of the VIF
+ u8 vif_index;
+ /// STA Index
+ u8 sta_idx;
+ /// MAC address of the TDLS station
+ struct mac_addr peer_mac_addr;
+};
+
+/// Structure containing the parameters of the @ref TDLS_CHAN_SWITCH_CFM message
+struct tdls_chan_switch_cfm {
+ /// Status of the operation
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref TDLS_CANCEL_CHAN_SWITCH_CFM
+/// message
+struct tdls_cancel_chan_switch_cfm {
+ /// Status of the operation
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref TDLS_CHAN_SWITCH_IND message
+struct tdls_chan_switch_ind {
+ /// VIF Index
+ u8 vif_index;
+ /// Channel Context Index
+ u8 chan_ctxt_index;
+ /// Status of the operation
+ u8 status;
+};
+
+/// Structure containing the parameters of the @ref TDLS_CHAN_SWITCH_BASE_IND
+/// message
+struct tdls_chan_switch_base_ind {
+ /// VIF Index
+ u8 vif_index;
+ /// Channel Context index
+ u8 chan_ctxt_index;
+};
+
+/// Structure containing the parameters of the @ref TDLS_PEER_PS_IND message
+struct tdls_peer_ps_ind {
+ /// VIF Index
+ u8 vif_index;
+ /// STA Index
+ u8 sta_idx;
+ /// MAC ADDR of the TDLS STA
+ struct mac_addr peer_mac_addr;
+ /// Flag to indicate if the TDLS peer is going to sleep
+ bool ps_on;
+};
+
+/// Structure containing the parameters of the @ref TDLS_PEER_TRAFFIC_IND_REQ
+/// message
+struct tdls_peer_traffic_ind_req {
+ /// VIF Index
+ u8 vif_index;
+ /// STA Index
+ u8 sta_idx;
+ // MAC ADDR of the TDLS STA
+ struct mac_addr peer_mac_addr;
+ /// Dialog token
+ u8 dialog_token;
+ /// TID of the latest MPDU transmitted over the TDLS direct link to the TDLS
+ /// STA
+ u8 last_tid;
+ /// Sequence number of the latest MPDU transmitted over the TDLS direct link
+ /// to the TDLS STA
+ u16 last_sn;
+};
+
+/// Structure containing the parameters of the @ref TDLS_PEER_TRAFFIC_IND_CFM
+/// message
+struct tdls_peer_traffic_ind_cfm {
+ /// Status of the operation
+ u8 status;
+};
+
+#endif // LMAC_MSG_H_
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/lmac_types.h b/drivers/net/wireless/aic/aic8800_fdrv/lmac_types.h
new file mode 100644
index 0000000000000..76f251607a7b9
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/lmac_types.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ****************************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @file co_types.h
+ *
+ * @brief Provides the kernel fixed-width types used by LMAC interfaces.
+ *
+ ****************************************************************************************
+ */
+
+#ifndef _LMAC_INT_H_
+#define _LMAC_INT_H_
+
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/bits.h>
+
+/// @} CO_INT
+#endif // _LMAC_INT_H_
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/reg_access.h b/drivers/net/wireless/aic/aic8800_fdrv/reg_access.h
new file mode 100644
index 0000000000000..2654ab8523436
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/reg_access.h
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ******************************************************************************
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief Definitions and macros for MAC HW and platform register accesses
+ *
+ ******************************************************************************
+ */
+
+#ifndef REG_ACCESS_H_
+#define REG_ACCESS_H_
+
+/*****************************************************************************
+ * Addresses within RWNX_ADDR_SYSTEM
+ *****************************************************************************/
+/* Shard RAM */
+#define SHARED_RAM_START_ADDR 0x00000000
+
+/* IPC registers */
+#define IPC_REG_BASE_ADDR 0x00800000
+
+/* System Controller Registers */
+#define SYSCTRL_SIGNATURE_ADDR 0x00900000
+// old diag register name
+#define SYSCTRL_DIAG_CONF_ADDR 0x00900068
+#define SYSCTRL_PHYDIAG_CONF_ADDR 0x00900074
+#define SYSCTRL_RIUDIAG_CONF_ADDR 0x00900078
+// new diag register name
+#define SYSCTRL_DIAG_CONF0 0x00900064
+#define SYSCTRL_DIAG_CONF1 0x00900068
+#define SYSCTRL_DIAG_CONF2 0x00900074
+#define SYSCTRL_DIAG_CONF3 0x00900078
+#define SYSCTRL_MISC_CNTL_ADDR 0x009000E0
+#define BOOTROM_ENABLE BIT(4)
+#define FPGA_B_RESET BIT(1)
+#define SOFT_RESET BIT(0)
+
+/* MAC platform */
+#define NXMAC_VERSION_1_ADDR 0x00B00004
+#define NXMAC_MU_MIMO_TX_BIT BIT(19)
+#define NXMAC_BFMER_BIT BIT(18)
+#define NXMAC_BFMEE_BIT BIT(17)
+#define NXMAC_MAC_80211MH_FORMAT_BIT BIT(16)
+#define NXMAC_COEX_BIT BIT(14)
+#define NXMAC_WAPI_BIT BIT(13)
+#define NXMAC_TPC_BIT BIT(12)
+#define NXMAC_VHT_BIT BIT(11)
+#define NXMAC_HT_BIT BIT(10)
+#define NXMAC_RCE_BIT BIT(8)
+#define NXMAC_CCMP_BIT BIT(7)
+#define NXMAC_TKIP_BIT BIT(6)
+#define NXMAC_WEP_BIT BIT(5)
+#define NXMAC_SECURITY_BIT BIT(4)
+#define NXMAC_SME_BIT BIT(3)
+#define NXMAC_HCCA_BIT BIT(2)
+#define NXMAC_EDCA_BIT BIT(1)
+#define NXMAC_QOS_BIT BIT(0)
+
+#define NXMAC_RX_CNTRL_ADDR 0x00B00060
+#define NXMAC_EN_DUPLICATE_DETECTION_BIT BIT(31)
+#define NXMAC_ACCEPT_UNKNOWN_BIT BIT(30)
+#define NXMAC_ACCEPT_OTHER_DATA_FRAMES_BIT BIT(29)
+#define NXMAC_ACCEPT_QO_S_NULL_BIT BIT(28)
+#define NXMAC_ACCEPT_QCFWO_DATA_BIT BIT(27)
+#define NXMAC_ACCEPT_Q_DATA_BIT BIT(26)
+#define NXMAC_ACCEPT_CFWO_DATA_BIT BIT(25)
+#define NXMAC_ACCEPT_DATA_BIT BIT(24)
+#define NXMAC_ACCEPT_OTHER_CNTRL_FRAMES_BIT BIT(23)
+#define NXMAC_ACCEPT_CF_END_BIT BIT(22)
+#define NXMAC_ACCEPT_ACK_BIT BIT(21)
+#define NXMAC_ACCEPT_CTS_BIT BIT(20)
+#define NXMAC_ACCEPT_RTS_BIT BIT(19)
+#define NXMAC_ACCEPT_PS_POLL_BIT BIT(18)
+#define NXMAC_ACCEPT_BA_BIT BIT(17)
+#define NXMAC_ACCEPT_BAR_BIT BIT(16)
+#define NXMAC_ACCEPT_OTHER_MGMT_FRAMES_BIT BIT(15)
+#define NXMAC_ACCEPT_BFMEE_FRAMES_BIT BIT(14)
+#define NXMAC_ACCEPT_ALL_BEACON_BIT BIT(13)
+#define NXMAC_ACCEPT_NOT_EXPECTED_BA_BIT BIT(12)
+#define NXMAC_ACCEPT_DECRYPT_ERROR_FRAMES_BIT BIT(11)
+#define NXMAC_ACCEPT_BEACON_BIT BIT(10)
+#define NXMAC_ACCEPT_PROBE_RESP_BIT BIT(9)
+#define NXMAC_ACCEPT_PROBE_REQ_BIT BIT(8)
+#define NXMAC_ACCEPT_MY_UNICAST_BIT BIT(7)
+#define NXMAC_ACCEPT_UNICAST_BIT BIT(6)
+#define NXMAC_ACCEPT_ERROR_FRAMES_BIT BIT(5)
+#define NXMAC_ACCEPT_OTHER_BSSID_BIT BIT(4)
+#define NXMAC_ACCEPT_BROADCAST_BIT BIT(3)
+#define NXMAC_ACCEPT_MULTICAST_BIT BIT(2)
+#define NXMAC_DONT_DECRYPT_BIT BIT(1)
+#define NXMAC_EXC_UNENCRYPTED_BIT BIT(0)
+
+#define NXMAC_DEBUG_PORT_SEL_ADDR 0x00B00510
+#define NXMAC_SW_SET_PROFILING_ADDR 0x00B08564
+#define NXMAC_SW_CLEAR_PROFILING_ADDR 0x00B08568
+
+/* Modem Status */
+#define MDM_HDMCONFIG_ADDR 0x00C00000
+
+/* Clock gating configuration */
+#define MDM_MEMCLKCTRL0_ADDR 0x00C00848
+#define MDM_CLKGATEFCTRL0_ADDR 0x00C00874
+#define CRM_CLKGATEFCTRL0_ADDR 0x00940010
+
+/* AGC (trident) */
+#define AGC_RWNXAGCCNTL_ADDR 0x00C02060
+
+/* LDPC RAM*/
+#define PHY_LDPC_RAM_ADDR 0x00C09000
+
+/* FCU (elma )*/
+#define FCU_RWNXFCAGCCNTL_ADDR 0x00C09034
+
+/* AGC RAM */
+#define PHY_AGC_UCODE_ADDR 0x00C0A000
+
+/* RIU */
+#define RIU_RWNXVERSION_ADDR 0x00C0B000
+#define RIU_RWNXDYNAMICCONFIG_ADDR 0x00C0B008
+#define RIU_AGCMEMBISTSTAT_ADDR 0x00C0B238
+#define RIU_AGCMEMSIGNATURESTAT_ADDR 0x00C0B23C
+#define RIU_RWNXAGCCNTL_ADDR 0x00C0B390
+
+/* FCU RAM */
+#define PHY_FCU_UCODE_ADDR 0x00C0E000
+
+/* RF ITF */
+#define FPGAB_MPIF_SEL_ADDR 0x00C10030
+#define RF_V6_DIAGPORT_CONF1_ADDR 0x00C10010
+#define RF_v6_PHYDIAG_CONF1_ADDR 0x00C10018
+
+#define RF_V7_DIAGPORT_CONF1_ADDR 0x00F10010
+#define RF_v7_PHYDIAG_CONF1_ADDR 0x00F10018
+
+/*****************************************************************************
+ * Macros for generated register files
+ *****************************************************************************/
+/* Macros for IPC registers access (used in reg_ipc_app.h) */
+#define REG_IPC_APP_RD(env, INDEX) \
+ (*(u32 *)((u8 *)(env) + IPC_REG_BASE_ADDR + 4 * (INDEX)))
+
+#define REG_IPC_APP_WR(env, INDEX, value) \
+ (*(u32 *)((u8 *)(env) + IPC_REG_BASE_ADDR + 4 * (INDEX)) = value)
+
+#endif /* REG_ACCESS_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_cmds.c b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_cmds.c
new file mode 100644
index 0000000000000..2bb0c58dc984e
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_cmds.c
@@ -0,0 +1,471 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ ******************************************************************************
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief Handles queueing (push to IPC, ack/cfm from IPC) of commands issued to
+ * LMAC FW
+ *
+ ******************************************************************************
+ */
+
+#include "rwnx_cmds.h"
+#include "aicwf_txrxif.h"
+#include "rwnx_defs.h"
+#include "rwnx_events.h"
+#include "rwnx_strs.h"
+#include <linux/list.h>
+#ifdef AICWF_SDIO_SUPPORT
+#include "aicwf_sdio.h"
+#else
+#include "aicwf_usb.h"
+#endif
+
+static void cmd_dump(const struct rwnx_cmd *cmd)
+{
+ if (!cmd) {
+ AICWFDBG(LOGDEBUG, KERN_ERR "AICWF %s cmd is null\n", __func__);
+ return;
+ }
+ AICWFDBG(LOGDEBUG, KERN_CRIT
+ "tkn[%d] flags:%04x result:%3d cmd:%4d-%-24s - reqcfm(%4d-%-s)\n",
+ cmd->tkn, cmd->flags, cmd->result, cmd->id, RWNX_ID2STR(cmd->id),
+ cmd->reqid,
+ cmd->reqid != (lmac_msg_id_t)-1 ? RWNX_ID2STR(cmd->reqid) : "none");
+}
+
+static void cmd_complete(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
+{
+ // RWNX_DBG(RWNX_FN_ENTRY_STR); //debug trace
+ lockdep_assert_held(&cmd_mgr->lock);
+
+ list_del(&cmd->list);
+ cmd_mgr->queue_sz--;
+
+ cmd->flags |= RWNX_CMD_FLAG_DONE;
+ if (cmd->flags & RWNX_CMD_FLAG_NONBLOCK) {
+ rwnx_cmd_free(cmd); // kfree(cmd);
+ } else {
+ if (RWNX_CMD_WAIT_COMPLETE(cmd->flags)) {
+ cmd->result = 0;
+ complete(&cmd->complete);
+ }
+ }
+}
+
+int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr,
+ struct rwnx_cmd *cmd)
+{
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+#ifdef AIC8800_CREATE_TRACE_POINTS
+ trace_msg_send(cmd->id);
+#endif
+ spin_lock_bh(&cmd_mgr->lock);
+
+ if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
+ AICWFDBG(LOGDEBUG, KERN_CRIT "AICWF cmd queue crashed\n");
+ cmd->result = -EPIPE;
+ spin_unlock_bh(&cmd_mgr->lock);
+ return -EPIPE;
+ }
+
+ if (!list_empty(&cmd_mgr->cmds)) {
+ if (cmd_mgr->queue_sz == cmd_mgr->max_queue_sz) {
+ AICWFDBG(LOGDEBUG, KERN_CRIT "AICWF Too many cmds (%d) already queued\n",
+ cmd_mgr->max_queue_sz);
+ cmd->result = -ENOMEM;
+ spin_unlock_bh(&cmd_mgr->lock);
+ return -ENOMEM;
+ }
+ }
+
+ cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH;
+
+ if (cmd->flags & RWNX_CMD_FLAG_REQ_CFM)
+ cmd->flags |= RWNX_CMD_FLAG_WAIT_CFM;
+
+ cmd->tkn = cmd_mgr->next_tkn++;
+ cmd->result = -EINTR;
+
+ if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK))
+ init_completion(&cmd->complete);
+
+ list_add_tail(&cmd->list, &cmd_mgr->cmds);
+ cmd_mgr->queue_sz++;
+ spin_unlock_bh(&cmd_mgr->lock);
+
+ WAKE_CMD_WORK(cmd_mgr);
+ return 0;
+}
+
+static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
+{
+#ifdef AICWF_SDIO_SUPPORT
+ int ret;
+ struct aic_sdio_dev *sdiodev =
+ container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
+#endif
+ bool defer_push = false;
+
+ // RWNX_DBG(RWNX_FN_ENTRY_STR); //debug trace
+#ifdef AIC8800_CREATE_TRACE_POINTS
+ trace_msg_send(cmd->id);
+#endif
+ spin_lock_bh(&cmd_mgr->lock);
+
+ if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
+ AICWFDBG(LOGDEBUG, KERN_CRIT "AICWF cmd queue crashed\n");
+ cmd->result = -EPIPE;
+ spin_unlock_bh(&cmd_mgr->lock);
+ return -EPIPE;
+ }
+
+ if (!list_empty(&cmd_mgr->cmds)) {
+ struct rwnx_cmd *last;
+
+ if (cmd_mgr->queue_sz == cmd_mgr->max_queue_sz) {
+ AICWFDBG(LOGDEBUG, KERN_CRIT "AICWF Too many cmds (%d) already queued\n",
+ cmd_mgr->max_queue_sz);
+ cmd->result = -ENOMEM;
+ spin_unlock_bh(&cmd_mgr->lock);
+ return -ENOMEM;
+ }
+ last = list_entry(cmd_mgr->cmds.prev, struct rwnx_cmd, list);
+ if (last->flags & (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_PUSH |
+ RWNX_CMD_FLAG_WAIT_CFM)) {
+ cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH;
+ defer_push = true;
+ }
+ }
+
+ if (cmd->flags & RWNX_CMD_FLAG_REQ_CFM)
+ cmd->flags |= RWNX_CMD_FLAG_WAIT_CFM;
+
+ cmd->tkn = cmd_mgr->next_tkn++;
+ cmd->result = -EINTR;
+
+ if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK))
+ init_completion(&cmd->complete);
+
+ list_add_tail(&cmd->list, &cmd_mgr->cmds);
+ cmd_mgr->queue_sz++;
+
+#ifdef AICWF_ARP_OFFLOAD
+ if (cmd->a2e_msg->id == ME_TRAFFIC_IND_REQ ||
+ cmd->a2e_msg->id == MM_SET_ARPOFFLOAD_REQ) {
+#else
+ if (cmd->a2e_msg->id == ME_TRAFFIC_IND_REQ) {
+#endif
+ defer_push = true;
+ cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH;
+ }
+
+ spin_unlock_bh(&cmd_mgr->lock);
+ if (!defer_push) {
+#ifdef AICWF_SDIO_SUPPORT
+ aicwf_set_cmd_tx((void *)(sdiodev), cmd->a2e_msg,
+ sizeof(struct lmac_msg) + cmd->a2e_msg->param_len);
+#else
+ aicwf_set_cmd_tx((void *)(usbdev), cmd->a2e_msg,
+ sizeof(struct lmac_msg) + cmd->a2e_msg->param_len);
+#endif
+ kfree(cmd->a2e_msg);
+ } else {
+ if (cmd_mgr->queue_sz <= 1)
+ WAKE_CMD_WORK(cmd_mgr);
+ return 0;
+ }
+
+ if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK)) {
+ unsigned long tout =
+ msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz);
+ if (!wait_for_completion_timeout(&cmd->complete, tout)) {
+ AICWFDBG(LOGDEBUG, KERN_CRIT "AICWF cmd timed-out\n");
+#ifdef AICWF_SDIO_SUPPORT
+ ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, 2);
+ if (ret < 0) {
+ sdio_err("reg:%d write failed!\n",
+ sdiodev->sdio_reg.wakeup_reg);
+ }
+#endif
+
+ cmd_dump(cmd);
+ spin_lock_bh(&cmd_mgr->lock);
+ cmd_mgr->state = RWNX_CMD_MGR_STATE_CRASHED;
+ if (!(cmd->flags & RWNX_CMD_FLAG_DONE)) {
+ cmd->result = -ETIMEDOUT;
+ cmd_complete(cmd_mgr, cmd);
+ }
+ spin_unlock_bh(&cmd_mgr->lock);
+ } else {
+ rwnx_cmd_free(cmd); // kfree(cmd);
+ if (!list_empty(&cmd_mgr->cmds))
+ WAKE_CMD_WORK(cmd_mgr);
+ }
+ } else {
+ cmd->result = 0;
+ }
+
+ return 0;
+}
+
+static int cmd_mgr_llind(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
+{
+ struct rwnx_cmd *cur, *acked = NULL;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ spin_lock_bh(&cmd_mgr->lock);
+ list_for_each_entry(cur, &cmd_mgr->cmds, list) {
+ if (!acked) {
+ if (cur->tkn == cmd->tkn) {
+ if (WARN_ON_ONCE(cur != cmd))
+ cmd_dump(cmd);
+ acked = cur;
+ continue;
+ }
+ }
+ if (cur->flags & RWNX_CMD_FLAG_WAIT_PUSH)
+ break;
+ }
+ if (!acked) {
+ AICWFDBG(LOGDEBUG, KERN_CRIT "Error: acked cmd not found\n");
+ } else {
+ cmd->flags &= ~RWNX_CMD_FLAG_WAIT_ACK;
+ if (RWNX_CMD_WAIT_COMPLETE(cmd->flags))
+ cmd_complete(cmd_mgr, cmd);
+ }
+ spin_unlock(&cmd_mgr->lock);
+
+ return 0;
+}
+
+void cmd_mgr_task_process(struct work_struct *work)
+{
+ struct rwnx_cmd_mgr *cmd_mgr =
+ container_of(work, struct rwnx_cmd_mgr, cmd_work);
+ struct rwnx_cmd *cur, *next = NULL;
+ unsigned long tout;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ while (1) {
+ next = NULL;
+ spin_lock_bh(&cmd_mgr->lock);
+
+ list_for_each_entry(cur, &cmd_mgr->cmds, list) {
+ if (cur->flags & RWNX_CMD_FLAG_WAIT_PUSH)
+ next = cur;
+ break;
+ }
+ spin_unlock_bh(&cmd_mgr->lock);
+
+ if (!next)
+ break;
+
+ if (next) {
+#ifdef AICWF_SDIO_SUPPORT
+ struct aic_sdio_dev *sdiodev =
+ container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
+#endif
+ next->flags &= ~RWNX_CMD_FLAG_WAIT_PUSH;
+
+#ifdef AICWF_SDIO_SUPPORT
+ aicwf_set_cmd_tx((void *)(sdiodev), next->a2e_msg,
+ sizeof(struct lmac_msg) +
+ next->a2e_msg->param_len);
+#else
+ aicwf_set_cmd_tx((void *)(usbdev), next->a2e_msg,
+ sizeof(struct lmac_msg) +
+ next->a2e_msg->param_len);
+#endif
+ kfree(next->a2e_msg);
+
+ tout =
+ msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz);
+ if (!wait_for_completion_timeout(&next->complete, tout)) {
+ AICWFDBG(LOGDEBUG, KERN_CRIT "AICWF cmd timed-out\n");
+#ifdef AICWF_SDIO_SUPPORT
+ if (aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg,
+ 2) < 0) {
+ sdio_err("reg:%d write failed!\n",
+ sdiodev->sdio_reg.wakeup_reg);
+ }
+#endif
+ cmd_dump(next);
+ spin_lock_bh(&cmd_mgr->lock);
+ cmd_mgr->state = RWNX_CMD_MGR_STATE_CRASHED;
+ if (!(next->flags & RWNX_CMD_FLAG_DONE)) {
+ next->result = -ETIMEDOUT;
+ cmd_complete(cmd_mgr, next);
+ }
+ spin_unlock_bh(&cmd_mgr->lock);
+ } else {
+ rwnx_cmd_free(next); // kfree(next);
+ }
+ }
+ }
+}
+
+static int cmd_mgr_run_callback(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd,
+ struct rwnx_cmd_e2amsg *msg, msg_cb_fct cb)
+{
+ int res;
+
+ if (!cb)
+ return 0;
+
+ res = cb(rwnx_hw, cmd, msg);
+
+ return res;
+}
+
+static int cmd_mgr_msgind(struct rwnx_cmd_mgr *cmd_mgr,
+ struct rwnx_cmd_e2amsg *msg, msg_cb_fct cb)
+{
+#ifdef AICWF_SDIO_SUPPORT
+ struct aic_sdio_dev *sdiodev =
+ container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
+ struct rwnx_hw *rwnx_hw = sdiodev->rwnx_hw;
+#endif
+ struct rwnx_cmd *cmd, *pos;
+ bool found = false;
+
+ // RWNX_DBG(RWNX_FN_ENTRY_STR); //debug trace
+#ifdef AIC8800_CREATE_TRACE_POINTS
+ trace_msg_recv(msg->id);
+#endif
+ // AICWFDBG(LOGDEBUG, "cmd->id=%x\n", msg->id); //debug trace
+ spin_lock_bh(&cmd_mgr->lock);
+ list_for_each_entry_safe(cmd, pos, &cmd_mgr->cmds, list) {
+ if (cmd->reqid == msg->id && (cmd->flags & RWNX_CMD_FLAG_WAIT_CFM)) {
+ if (!cmd_mgr_run_callback(rwnx_hw, cmd, msg, cb)) {
+ found = true;
+ cmd->flags &= ~RWNX_CMD_FLAG_WAIT_CFM;
+ if (WARN(msg->param_len > RWNX_CMD_E2AMSG_LEN_MAX,
+ "Unexpect E2A msg len %d > %d\n", msg->param_len,
+ RWNX_CMD_E2AMSG_LEN_MAX))
+ msg->param_len = RWNX_CMD_E2AMSG_LEN_MAX;
+
+ if (cmd->e2a_msg && msg->param_len)
+ memcpy(cmd->e2a_msg, &msg->param, msg->param_len);
+
+ if (RWNX_CMD_WAIT_COMPLETE(cmd->flags))
+ cmd_complete(cmd_mgr, cmd);
+
+ break;
+ }
+ }
+ }
+ spin_unlock_bh(&cmd_mgr->lock);
+
+ if (!found)
+ cmd_mgr_run_callback(rwnx_hw, NULL, msg, cb);
+
+ return 0;
+}
+
+static void cmd_mgr_print(struct rwnx_cmd_mgr *cmd_mgr)
+{
+ struct rwnx_cmd *cur;
+
+ spin_lock_bh(&cmd_mgr->lock);
+ RWNX_DBG("q_sz/max: %2d / %2d - next tkn: %d\n", cmd_mgr->queue_sz,
+ cmd_mgr->max_queue_sz, cmd_mgr->next_tkn);
+ list_for_each_entry(cur, &cmd_mgr->cmds, list) {
+ cmd_dump(cur);
+ }
+ spin_unlock_bh(&cmd_mgr->lock);
+}
+
+static void cmd_mgr_drain(struct rwnx_cmd_mgr *cmd_mgr)
+{
+ struct rwnx_cmd *cur, *nxt;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ spin_lock_bh(&cmd_mgr->lock);
+ list_for_each_entry_safe(cur, nxt, &cmd_mgr->cmds, list) {
+ list_del(&cur->list);
+ cmd_mgr->queue_sz--;
+ if (!(cur->flags & RWNX_CMD_FLAG_NONBLOCK))
+ complete(&cur->complete);
+ }
+ spin_unlock_bh(&cmd_mgr->lock);
+}
+
+void rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr)
+{
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ INIT_LIST_HEAD(&cmd_mgr->cmds);
+ cmd_mgr->state = RWNX_CMD_MGR_STATE_INITED;
+ spin_lock_init(&cmd_mgr->lock);
+ cmd_mgr->max_queue_sz = RWNX_CMD_MAX_QUEUED;
+ cmd_mgr->queue = &cmd_mgr_queue;
+ cmd_mgr->print = &cmd_mgr_print;
+ cmd_mgr->drain = &cmd_mgr_drain;
+ cmd_mgr->llind = &cmd_mgr_llind;
+ cmd_mgr->msgind = &cmd_mgr_msgind;
+
+ INIT_WORK(&cmd_mgr->cmd_work, cmd_mgr_task_process);
+ cmd_mgr->cmd_wq = create_singlethread_workqueue("cmd_wq");
+ if (!cmd_mgr->cmd_wq) {
+ txrx_err("insufficient memory to create cmd workqueue.\n");
+ return;
+ }
+}
+
+void rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr)
+{
+ cmd_mgr->print(cmd_mgr);
+ cmd_mgr->drain(cmd_mgr);
+ cmd_mgr->print(cmd_mgr);
+ flush_workqueue(cmd_mgr->cmd_wq);
+ destroy_workqueue(cmd_mgr->cmd_wq);
+ memset(cmd_mgr, 0, sizeof(*cmd_mgr));
+}
+
+void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len)
+{
+ u8 *buffer = NULL;
+ u16 index = 0;
+#ifdef AICWF_SDIO_SUPPORT
+ struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)dev;
+ struct aicwf_bus *bus = sdiodev->bus_if;
+#else
+ struct aic_usb_dev *usbdev = (struct aic_usb_dev *)dev;
+ struct aicwf_bus *bus = NULL;
+
+ if (!usbdev->state) {
+ AICWFDBG(LOGDEBUG, "down msg\n");
+ return;
+ }
+ bus = usbdev->bus_if;
+#endif
+ buffer = bus->cmd_buf;
+
+ memset(buffer, 0, CMD_BUF_MAX);
+ buffer[0] = (len + 4) & 0x00ff;
+ buffer[1] = ((len + 4) >> 8) & 0x0f;
+ buffer[2] = 0x11;
+
+ buffer[3] = aic_chip_cmd_hdr_checksum(sdiodev->rwnx_hw, &buffer[0], 3);
+
+ index += 4;
+ // there is a dummy word
+ index += 4;
+
+ // make sure little endian
+ put_u16(&buffer[index], msg->id);
+ index += 2;
+ put_u16(&buffer[index], msg->dest_id);
+ index += 2;
+ put_u16(&buffer[index], msg->src_id);
+ index += 2;
+ put_u16(&buffer[index], msg->param_len);
+ index += 2;
+ memcpy(&buffer[index], (u8 *)msg->param, msg->param_len);
+
+ aicwf_bus_txmsg(bus, buffer, len + 8);
+}
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_cmds.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_cmds.h
new file mode 100644
index 0000000000000..adb4bc49c188a
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_cmds.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _RWNX_CMDS_H_
+#define _RWNX_CMDS_H_
+
+#include "lmac_msg.h"
+#include "ipc_shared.h"
+#include <linux/completion.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#define RWNX_80211_CMD_TIMEOUT_MS 6000
+
+#define RWNX_CMD_FLAG_NONBLOCK BIT(0)
+#define RWNX_CMD_FLAG_REQ_CFM BIT(1)
+#define RWNX_CMD_FLAG_WAIT_PUSH BIT(2)
+#define RWNX_CMD_FLAG_WAIT_ACK BIT(3)
+#define RWNX_CMD_FLAG_WAIT_CFM BIT(4)
+#define RWNX_CMD_FLAG_DONE BIT(5)
+/* ATM IPC design makes it possible to get the CFM before the ACK,
+ * otherwise this could have simply been a state enum
+ */
+#define RWNX_CMD_WAIT_COMPLETE(flags) \
+ (!((flags) & (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_CFM)))
+
+#define RWNX_CMD_MAX_QUEUED 16
+
+#define rwnx_cmd_e2amsg ipc_e2a_msg
+#define rwnx_cmd_a2emsg lmac_msg
+#define RWNX_CMD_A2EMSG_LEN(m) (sizeof(struct lmac_msg) + (m)->param_len)
+#define RWNX_CMD_E2AMSG_LEN_MAX (IPC_E2A_MSG_PARAM_SIZE * 4)
+
+struct rwnx_hw;
+struct rwnx_cmd;
+typedef int (*msg_cb_fct)(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd,
+ struct rwnx_cmd_e2amsg *msg);
+
+static inline void put_u16(u8 *buf, u16 data)
+{
+ buf[0] = (u8)(data & 0x00ff);
+ buf[1] = (u8)((data >> 8) & 0x00ff);
+}
+
+enum rwnx_cmd_mgr_state {
+ RWNX_CMD_MGR_STATE_DEINIT,
+ RWNX_CMD_MGR_STATE_INITED,
+ RWNX_CMD_MGR_STATE_CRASHED,
+};
+
+struct rwnx_cmd {
+ struct list_head list;
+ lmac_msg_id_t id;
+ lmac_msg_id_t reqid;
+ struct rwnx_cmd_a2emsg *a2e_msg;
+ char *e2a_msg;
+ u32 tkn;
+ u16 flags;
+
+ struct completion complete;
+ u32 result;
+ u8 used;
+ int array_id;
+};
+
+struct rwnx_cmd_mgr {
+ enum rwnx_cmd_mgr_state state;
+ spinlock_t lock; //
+ u32 next_tkn;
+ u32 queue_sz;
+ u32 max_queue_sz;
+
+ struct list_head cmds;
+
+ int (*queue)(struct rwnx_cmd_mgr *mgr, struct rwnx_cmd *cmd);
+ int (*llind)(struct rwnx_cmd_mgr *mgr, struct rwnx_cmd *cmd);
+ int (*msgind)(struct rwnx_cmd_mgr *mgr, struct rwnx_cmd_e2amsg *msg, msg_cb_fct cb);
+ void (*print)(struct rwnx_cmd_mgr *mgr);
+ void (*drain)(struct rwnx_cmd_mgr *mgr);
+
+ struct work_struct cmd_work;
+ struct workqueue_struct *cmd_wq;
+};
+
+#define WAKE_CMD_WORK(_cmd_mgr) \
+ do { \
+ struct rwnx_cmd_mgr *__mgr = (_cmd_mgr); \
+ queue_work((__mgr)->cmd_wq, &__mgr->cmd_work); \
+ } while (0)
+
+void rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr);
+void rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr);
+int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr,
+ struct rwnx_cmd *cmd);
+void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len);
+
+void cmd_mgr_task_process(struct work_struct *work);
+
+void rwnx_cmd_free(struct rwnx_cmd *cmd);
+
+#endif /* _RWNX_CMDS_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_compat.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_compat.h
new file mode 100644
index 0000000000000..9a127b659e2b6
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_compat.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief Ensure driver compilation for linux 3.16 to 3.19
+ * To avoid too many #if LINUX_VERSION_CODE if the code, when prototype change
+ * between different kernel version:
+ * - For external function, define a macro whose name is the function name with
+ * _compat suffix and prototype (actually the number of parameter) of the
+ * latest version. Then latest version this macro simply call the function
+ * and for older kernel version it call the function adapting the api.
+ * - For internal function (e.g. cfg80211_ops) do the same but the macro name
+ * doesn't need to have the _compat suffix when the function is not used
+ * directly by the driver
+ *
+ ******************************************************************************
+ */
+
+#ifndef _RWNX_COMPAT_H_
+#define _RWNX_COMPAT_H_
+#include <linux/version.h>
+
+#include <linux/bitfield.h>
+
+/* CFG80211 */
+
+#ifdef CONFIG_RWNX_MUMIMO_TX
+#define CONFIG_USER_MAX 2
+#else
+#define CONFIG_USER_MAX 1
+#endif
+
+#define NX_VIRT_DEV_MAX 4
+
+#define NX_REMOTE_STA_MAX_FOR_OLD_IC 10
+#define NX_REMOTE_STA_MAX 32
+
+#define NX_MU_GROUP_MAX 62
+#define NX_TXDESC_CNT 64
+#define NX_TX_MAX_RATES 4
+#define NX_CHAN_CTXT_CNT 3
+
+#ifdef CONFIG_RWNX_BCMC
+#define NX_TXQ_CNT 5
+#else
+#define NX_TXQ_CNT 4
+#endif
+
+#define IEEE80211_MAX_AMPDU_BUF IEEE80211_MAX_AMPDU_BUF_HE
+#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB \
+ IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB
+#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB \
+ IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB
+#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA \
+ IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU
+
+#define CCFS0(vht) ((vht)->center_freq_seg0_idx)
+#define CCFS1(vht) ((vht)->center_freq_seg1_idx)
+
+#define SURVEY_TIME(s) ((s)->time)
+#define SURVEY_TIME_BUSY(s) ((s)->time_busy)
+#define STA_TDLS_INITIATOR(sta) ((sta)->tdls_initiator)
+
+#define RX_ENC_HT(s) ((s)->encoding = RX_ENC_HT)
+#define RX_ENC_VHT(s) ((s)->encoding = RX_ENC_VHT)
+#define RX_ENC_HE(s) ((s)->encoding = RX_ENC_HE)
+#define RX_ENC_FLAG_SHORT_GI(s) ((s)->enc_flags |= RX_ENC_FLAG_SHORT_GI)
+#define RX_ENC_FLAG_SHORT_PRE(s) ((s)->enc_flags |= RX_ENC_FLAG_SHORTPRE)
+#define RX_ENC_FLAG_LDPC(s) ((s)->enc_flags |= RX_ENC_FLAG_LDPC)
+#define RX_BW_40MHZ(s) ((s)->bw = RATE_INFO_BW_40)
+#define RX_BW_80MHZ(s) ((s)->bw = RATE_INFO_BW_80)
+#define RX_BW_160MHZ(s) ((s)->bw = RATE_INFO_BW_160)
+#define RX_NSS(s) ((s)->nss)
+
+#ifndef CONFIG_VENDOR_RWNX_AMSDUS_TX
+#endif /* CONFIG_VENDOR_RWNX_AMSDUS_TX */
+
+#endif /* _RWNX_COMPAT_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_defs.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_defs.h
new file mode 100644
index 0000000000000..eae8d04bee9dd
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_defs.h
@@ -0,0 +1,704 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief Main driver structure declarations for fullmac driver
+ *
+ ******************************************************************************
+ */
+
+#ifndef _RWNX_DEFS_H_
+#define _RWNX_DEFS_H_
+
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <net/cfg80211.h>
+
+#include "rwnx_cmds.h"
+#include "rwnx_mod_params.h"
+#include "rwnx_mu_group.h"
+#include "rwnx_platform.h"
+#include "rwnx_radar.h"
+#include "rwnx_rx.h"
+#include "rwnx_tx.h"
+#include "rwnx_utils.h"
+#include "rwnx_compat.h"
+#ifdef CONFIG_AIC8800_FILTER_TCP_ACK
+#include "aicwf_tcp_ack.h"
+#endif
+
+#ifdef AICWF_SDIO_SUPPORT
+#include "aicwf_sdio.h"
+#include "sdio_host.h"
+#endif
+
+#include "lmac_mac.h"
+#include "aicwf_chip_ops.h"
+
+#define WPI_HDR_LEN 18
+#define WPI_PN_LEN 16
+#define WPI_PN_OFST 2
+#define WPI_MIC_LEN 16
+#define WPI_KEY_LEN 32
+#define WPI_SUBKEY_LEN 16 // WPI key is actually two 16bytes key
+
+#define LEGACY_PS_ID 0
+#define UAPSD_ID 1
+
+#define PS_SP_INTERRUPTED 255
+#define MAC_ADDR_LEN 6
+
+#ifdef CONFIG_AIC8800_AUTO_CUSTREG
+#define MAX_SEARCH_CNT 10
+
+/// Structure containing the parameters of the auto ccode
+struct scanu_ccode {
+ /// ccode auto/manual switch, auto--true, manual--false
+ bool auto_set;
+ /// ccode find
+ bool ccode_find;
+ /// ccode set
+ bool ccode_set;
+ /// ccode find cnt
+ u8 ccode_cnt;
+ /// ccode rssi
+ s8 ccode_rssi;
+ /// link scan
+ atomic_t link_scan;
+ /// record mac addr
+ struct mac_addr bssid;
+};
+#endif
+
+struct wf_bss_info {
+ u32 length;
+ s8 rssi;
+ u16 chan;
+ enum nl80211_band band; /* Band */
+ u8 width; /* Channel width 0/1/2--20/40/80 */
+ u16 center_freq; /* Center frequency */
+ u32 center_freq1; /* Center frequency 1 */
+ u32 center_freq2; /* Center frequency 2 */
+ bool ht;
+ bool vht;
+ u8 bssid[ETH_ALEN];
+ u8 ssid_len;
+ unsigned char ssid[33];
+};
+
+/**
+ * struct rwnx_bcn - Information of the beacon in used (AP mode)
+ *
+ * @head: head portion of beacon (before TIM IE)
+ * @tail: tail portion of beacon (after TIM IE)
+ * @ies: extra IEs (not used ?)
+ * @head_len: length of head data
+ * @tail_len: length of tail data
+ * @ies_len: length of extra IEs data
+ * @tim_len: length of TIM IE
+ * @len: Total beacon len (head + tim + tail + extra)
+ * @dtim: dtim period
+ */
+struct rwnx_bcn {
+ u8 *head;
+ u8 *tail;
+ u8 *ies;
+ size_t head_len;
+ size_t tail_len;
+ size_t ies_len;
+ size_t tim_len;
+ size_t len;
+ u8 dtim;
+};
+
+/**
+ * struct rwnx_key - Key information
+ *
+ * @hw_idx: Idx of the key from hardware point of view
+ */
+struct rwnx_key {
+ u8 hw_idx;
+};
+
+/*
+ * Structure containing information about a Mesh Path
+ */
+struct rwnx_mesh_path {
+ struct list_head list; /* For rwnx_vif.mesh_paths */
+ u8 path_idx; /* Path Index */
+ struct mac_addr tgt_mac_addr; /* Target MAC Address */
+ struct rwnx_sta *p_nhop_sta; /* Pointer to the Next Hop STA */
+};
+
+struct rwnx_mesh_proxy {
+ struct list_head list; /* For rwnx_vif.mesh_proxy */
+ struct mac_addr ext_sta_addr; /* Address of the External STA */
+ struct mac_addr proxy_addr; /* Proxy MAC Address */
+ bool local; /* Indicate if interface is a proxy for the device */
+};
+
+/**
+ * struct rwnx_csa - Information for CSA (Channel Switch Announcement)
+ *
+ * @vif: Pointer to the vif doing the CSA
+ * @bcn: Beacon to use after CSA
+ * @elem: IPC buffer to send the new beacon to the fw
+ * @chandef: defines the channel to use after the switch
+ * @count: Current csa counter
+ * @status: Status of the CSA at fw level
+ * @ch_idx: Index of the new channel context
+ * @work: work scheduled at the end of CSA
+ */
+struct rwnx_csa {
+ struct rwnx_vif *vif;
+ struct rwnx_bcn bcn;
+ struct rwnx_ipc_elem_var elem;
+ struct cfg80211_chan_def chandef;
+ int count;
+ int status;
+ int ch_idx;
+ struct work_struct work;
+};
+
+struct apm_probe_sta {
+ u8 sta_mac_addr[6];
+ u8 vif_idx;
+ u64 probe_id;
+ struct work_struct apmprobesta_work;
+ struct workqueue_struct *apmprobesta_wq;
+};
+
+/// Possible States of the TDLS link.
+enum tdls_status_tag {
+ /// TDLS link is not active (no TDLS peer connected)
+ TDLS_LINK_IDLE,
+ /// TDLS Setup Request transmitted
+ TDLS_SETUP_REQ_TX,
+ /// TDLS Setup Response transmitted
+ TDLS_SETUP_RSP_TX,
+ /// TDLS link is active (TDLS peer connected)
+ TDLS_LINK_ACTIVE,
+ /// TDLS Max Number of states.
+ TDLS_STATE_MAX
+};
+
+/*
+ * Structure used to save information relative to the TDLS peer.
+ * This is also linked within the rwnx_hw vifs list.
+ *
+ */
+struct rwnx_tdls {
+ bool active; /* Indicate if TDLS link is active */
+ bool initiator; /* Indicate if TDLS peer is the TDLS initiator */
+ bool chsw_en; /* Indicate if channel switch is enabled */
+ u8 last_tid; /* TID of the latest MPDU transmitted over the
+ * TDLS direct link to the TDLS STA
+ */
+ u16 last_sn; /* Sequence number of the latest MPDU transmitted
+ * over the TDLS direct link to the TDLS STA
+ */
+ bool ps_on; /* Indicate if the power save is enabled on the
+ * TDLS STA
+ */
+ bool chsw_allowed; /* Indicate if TDLS channel switch is allowed */
+};
+
+/**
+ * enum rwnx_ap_flags - AP flags
+ *
+ * @RWNX_AP_ISOLATE: Isolate clients (i.e. don't bridge packets transmitted by
+ * one client for another one)
+ */
+enum rwnx_ap_flags {
+ RWNX_AP_ISOLATE = BIT(0),
+};
+
+/*
+ * Structure used to save information relative to the managed interfaces.
+ * This is also linked within the rwnx_hw vifs list.
+ *
+ */
+struct rwnx_vif {
+ struct list_head list;
+ struct rwnx_hw *rwnx_hw;
+ struct wireless_dev wdev;
+ struct net_device *ndev;
+ struct net_device_stats net_stats;
+ struct rwnx_key key[6];
+ unsigned long drv_flags;
+ atomic_t drv_conn_state;
+ u8 drv_vif_index; /* Identifier of the VIF in driver */
+ u8 vif_index; /* Identifier of the station in FW */
+ u8 ch_index; /* Channel context identifier */
+ bool up; /* Indicate if associated netdev is up
+ * (i.e. Interface is created at fw level)
+ */
+ bool use_4addr; /* Should we use 4addresses mode */
+ bool is_resending; /* Indicate if a frame is being resent on this interface */
+ bool user_mpm; /* In case of Mesh Point VIF, indicate if MPM is handled by
+ * userspace
+ */
+ bool roc_tdls; /* Indicate if the ROC has been called by a
+ * TDLS station
+ */
+ u8 tdls_status; /* Status of the TDLS link */
+ bool tdls_chsw_prohibited; /* Indicate if TDLS Channel Switch is prohibited */
+ bool wep_enabled; /* 1 if WEP is enabled */
+ bool wep_auth_err; /* 1 if auth status code is not supported auth alg when
+ * WEP enabled
+ */
+ enum nl80211_auth_type
+ last_auth_type; /* Authentication type (algorithm) sent in the last
+ * connection when WEP enabled
+ */
+ union {
+ struct {
+ struct rwnx_sta *ap; /* Pointer to the peer STA entry allocated for
+ * the AP
+ */
+ struct rwnx_sta *tdls_sta; /* Pointer to the TDLS station */
+ bool external_auth; /* Indicate if external authentication is in
+ * progress
+ */
+ u32 group_cipher_type;
+ u32 paired_cipher_type;
+ // connected network info start
+ char ssid[32];
+ int ssid_len;
+ u8 bssid[ETH_ALEN];
+ u32 conn_owner_nlportid;
+ bool is_roam;
+ unsigned long link_time;
+ u16 b_interval;
+ u8 dtim_peroid;
+ u16 capability;
+ enum nl80211_auth_type auth_type;
+ // connected network info end
+ } sta;
+ struct {
+ u16 flags; /* see rwnx_ap_flags */
+ struct list_head sta_list; /* List of STA connected to the AP */
+ struct rwnx_bcn bcn; /* beacon */
+ u8 bcmc_index; /* Index of the BCMC sta to use */
+ struct rwnx_csa *csa;
+
+ struct list_head
+ mpath_list; /* List of Mesh Paths used on this interface */
+ struct list_head proxy_list; /* List of Proxies Information used on
+ * this interface
+ */
+ bool create_path; /* Indicate if we are waiting for a
+ * MESH_CREATE_PATH_CFM message
+ */
+ int generation; /* Increased each time the list of Mesh Paths is
+ * updated
+ */
+ enum nl80211_mesh_power_mode
+ mesh_pm; /* mesh power save mode currently set in firmware */
+ enum nl80211_mesh_power_mode
+ next_mesh_pm; /* mesh power save mode for next peer */
+ } ap;
+ struct {
+ struct rwnx_vif *master; /* pointer on master interface */
+ struct rwnx_sta *sta_4a;
+ } ap_vlan;
+ };
+
+ u8 key_has_add;
+ u8 is_p2p_vif;
+ struct apm_probe_sta sta_probe;
+
+};
+
+#define RWNX_VIF_TYPE(rwnx_vif) ((rwnx_vif)->wdev.iftype)
+
+/*
+ * Structure used to store information relative to PS mode.
+ *
+ * @active: True when the sta is in PS mode.
+ * If false, other values should be ignored
+ * @pkt_ready: Number of packets buffered for the sta in drv's txq
+ * (1 counter for Legacy PS and 1 for U-APSD)
+ * @sp_cnt: Number of packets that remain to be pushed in the service period.
+ * 0 means that no service period is in progress
+ * (1 counter for Legacy PS and 1 for U-APSD)
+ */
+struct rwnx_sta_ps {
+ bool active;
+ u16 pkt_ready[2];
+ u16 sp_cnt[2];
+};
+
+/**
+ * struct rwnx_rx_rate_stats - Store statistics for RX rates
+ *
+ * @table: Number of received frames for each rate index
+ * @size: Number of entries in @table
+ * @cpt: Total number of received frames
+ * @rate_cnt: Number of rate indexes with at least one received frame
+ */
+struct rwnx_rx_rate_stats {
+ int *table;
+ int size;
+ int cpt;
+ int rate_cnt;
+};
+
+/**
+ * struct rwnx_sta_stats - Structure Used to store statistics specific to a STA
+ *
+ * @last_rx: Hardware vector of the last received frame
+ * @rx_rate: Statistics of the received rates
+ */
+struct rwnx_sta_stats {
+ struct hw_vect last_rx;
+ struct rwnx_rx_rate_stats rx_rate;
+};
+
+/*
+ * Structure used to save information relative to the managed stations.
+ */
+struct rwnx_sta {
+ struct list_head list;
+ u16 aid; /* association ID */
+ u8 sta_idx; /* Identifier of the station */
+ u8 vif_idx; /* Identifier of the VIF (fw id) the station
+ * belongs to
+ */
+ u8 vlan_idx; /* Identifier of the VLAN VIF (fw id) the station
+ * belongs to (= vif_idx if no vlan in used)
+ */
+ enum nl80211_band band; /* Band */
+ enum nl80211_chan_width width; /* Channel width */
+ u16 center_freq; /* Center frequency */
+ u32 center_freq1; /* Center frequency 1 */
+ u32 center_freq2; /* Center frequency 2 */
+ u8 ch_idx; /* Identifier of the channel
+ * context the station belongs to
+ */
+ bool qos; /* Flag indicating if the station
+ * supports QoS
+ */
+ u8 acm; /* Bitfield indicating which queues
+ * have AC mandatory
+ */
+ u16 uapsd_tids; /* Bitfield indicating which tids are subject to
+ * UAPSD
+ */
+ u8 mac_addr[ETH_ALEN]; /* MAC address of the station */
+ struct rwnx_key key;
+ bool valid; /* Flag indicating if the entry is valid */
+ struct rwnx_sta_ps ps; /* Information when STA is in PS (AP only) */
+#ifdef CONFIG_RWNX_BFMER
+ struct rwnx_bfmer_report *bfm_report; /* Beamforming report to be used for
+ * VHT TX Beamforming
+ */
+#ifdef CONFIG_RWNX_MUMIMO_TX
+ struct rwnx_sta_group_info
+ group_info; /* MU grouping information for the STA */
+#endif /* CONFIG_RWNX_MUMIMO_TX */
+#endif /* CONFIG_RWNX_BFMER */
+
+ bool ht; /* Flag indicating if the station
+ * supports HT
+ */
+ bool vht; /* Flag indicating if the station
+ * supports VHT
+ */
+ u32 ac_param[AC_MAX]; /* EDCA parameters */
+ struct rwnx_tdls tdls; /* TDLS station information */
+ struct rwnx_sta_stats stats;
+ enum nl80211_mesh_power_mode
+ mesh_pm; /* link-specific mesh power save mode */
+};
+
+static inline const u8 *rwnx_sta_addr(struct rwnx_sta *rwnx_sta)
+{
+ return rwnx_sta->mac_addr;
+}
+
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+struct rwnx_amsdu_stats {
+ int done;
+ int failed;
+};
+#endif
+
+struct rwnx_stats {
+ int cfm_balance[NX_TXQ_CNT];
+ unsigned long last_rx, last_tx; /* jiffies */
+ int ampdus_tx[IEEE80211_MAX_AMPDU_BUF];
+ int ampdus_rx[IEEE80211_MAX_AMPDU_BUF];
+ int ampdus_rx_map[4];
+ int ampdus_rx_miss;
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+ struct rwnx_amsdu_stats amsdus[NX_TX_PAYLOAD_MAX];
+#endif
+ int amsdus_rx[64];
+};
+
+struct rwnx_sec_phy_chan {
+ u16 prim20_freq;
+ u16 center_freq1;
+ u16 center_freq2;
+ enum nl80211_band band;
+ u8 type;
+};
+
+/* Structure that will contains all RoC information received from cfg80211 */
+struct rwnx_roc_elem {
+ struct wireless_dev *wdev;
+ struct ieee80211_channel *chan;
+ unsigned int duration;
+ u64 cookie;
+ /* Used to avoid call of CFG80211 callback upon expiration of RoC */
+ bool mgmt_roc;
+ /* Indicate if we have switch on the RoC channel */
+ bool on_chan;
+};
+
+/* Structure containing channel survey information received from MAC */
+struct rwnx_survey_info {
+ // Filled
+ u32 filled;
+ // Amount of time in ms the radio spent on the channel
+ u32 chan_time_ms;
+ // Amount of time the primary channel was sensed busy
+ u32 chan_time_busy_ms;
+ // Noise in dbm
+ s8 noise_dbm;
+};
+
+#define RWNX_CH_NOT_SET 0xFF
+#define RWNX_INVALID_VIF 0xFF
+#define RWNX_INVALID_STA 0xFF
+
+/* Structure containing channel context information */
+struct rwnx_chanctx {
+ struct cfg80211_chan_def chan_def; /* channel description */
+ u8 count; /* number of vif using this ctxt */
+};
+
+/**
+ * struct rwnx_phy_info - PHY information
+ *
+ * @cnt: Number of PHY interfaces
+ * @cfg: Configuration sent to the firmware
+ * @sec_chan: Channel configuration of the second PHY interface, when present
+ * @limit_bw: Whether to limit the requested channel bandwidth for legacy PHYs
+ */
+struct rwnx_phy_info {
+ u8 cnt;
+ struct phy_cfg_tag cfg;
+ struct rwnx_sec_phy_chan sec_chan;
+ bool limit_bw;
+};
+
+struct defrag_ctrl_info {
+ struct list_head list;
+ u8 sta_idx;
+ u8 tid;
+ u16 sn;
+ u8 next_fn;
+ u16 frm_len;
+ struct sk_buff *skb;
+ struct timer_list defrag_timer;
+ struct rwnx_hw *rwnx_hw;
+};
+
+struct amsdu_subframe_hdr {
+ u8 da[6];
+ u8 sa[6];
+ u16 sublen;
+};
+
+/* rwnx driver status */
+void rwnx_set_conn_state(atomic_t *drv_conn_state, int state);
+
+enum rwnx_drv_connect_status {
+ RWNX_DRV_STATUS_DISCONNECTED = 0,
+ RWNX_DRV_STATUS_DISCONNECTING,
+ RWNX_DRV_STATUS_CONNECTING,
+ RWNX_DRV_STATUS_CONNECTED,
+ RWNX_DRV_STATUS_ROAMING,
+};
+
+struct rwnx_hw {
+ struct rwnx_mod_params *mod_params;
+ struct device *dev;
+#ifdef AICWF_SDIO_SUPPORT
+ struct aic_sdio_dev *sdiodev;
+#endif
+ struct wiphy *wiphy;
+ struct list_head vifs;
+ struct rwnx_vif *
+ vif_table[NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX]; /* indexed with fw id */
+ struct rwnx_sta sta_table[NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX];
+ struct rwnx_survey_info survey[SCAN_CHANNEL_MAX];
+ struct cfg80211_scan_request *scan_request;
+ /* The normal scan path owns one SDIO activity until its terminal event. */
+ atomic_t scan_activity_held;
+#ifdef CONFIG_AIC8800_SCHED_SCAN
+ struct cfg80211_sched_scan_request *sched_scan_req;
+#endif
+ struct rwnx_chanctx chanctx_table[NX_CHAN_CTXT_CNT];
+ u8 cur_chanctx;
+
+ u8 monitor_vif; /* FW id of the monitor interface, RWNX_INVALID_VIF if no
+ * monitor vif at fw level
+ */
+
+#ifdef CONFIG_AIC8800_FILTER_TCP_ACK
+ /* tcp ack management */
+ struct tcp_ack_manage ack_m;
+#endif
+
+ /* RoC Management */
+ struct rwnx_roc_elem *roc_elem; /* Information provided by cfg80211 in its
+ * remain on channel request
+ */
+
+ struct rwnx_cmd_mgr *cmd_mgr;
+
+ struct rwnx_plat *plat;
+
+ spinlock_t tx_lock; //
+ spinlock_t cb_lock; //
+ struct mutex mutex; /* per-device perimeter lock */
+
+ struct tasklet_struct task;
+ struct mm_version_cfm
+ version_cfm; /* Lower layers versions - obtained via MM_VERSION_REQ */
+
+ u32 tcp_pacing_shift;
+
+ /* IPC */
+ struct ipc_host_env_tag *ipc_env;
+#ifdef AICWF_SDIO_SUPPORT
+ struct sdio_host_env_tag sdio_env;
+#endif
+
+ struct rwnx_ipc_elem_pool e2amsgs_pool;
+ struct rwnx_ipc_elem_pool dbgmsgs_pool;
+ struct rwnx_ipc_elem_pool e2aradars_pool;
+ struct rwnx_ipc_elem_var pattern_elem;
+ struct rwnx_ipc_dbgdump_elem dbgdump_elem;
+ struct rwnx_ipc_elem_pool e2arxdesc_pool;
+ struct rwnx_ipc_skb_elem *e2aunsuprxvec_elems;
+ // struct rwnx_ipc_rxbuf_elems rxbuf_elems;
+ struct rwnx_ipc_elem_var scan_ie;
+
+ struct kmem_cache *sw_txhdr_cache;
+
+ struct rwnx_stats stats;
+
+#ifdef CONFIG_PREALLOC_TXQ
+ struct rwnx_txq *txq;
+#else
+ struct rwnx_txq txq[NX_NB_TXQ];
+#endif
+
+ struct rwnx_hwq hwq[NX_TXQ_CNT];
+
+ u64 avail_idx_map;
+ u8 vif_started;
+ bool adding_sta;
+ struct rwnx_phy_info phy;
+
+ struct rwnx_radar radar;
+
+ /* extended capabilities supported */
+ u8 ext_capa[8];
+
+#ifdef CONFIG_RWNX_MUMIMO_TX
+ struct rwnx_mu_info mu;
+#endif
+ u8 is_p2p_alive;
+ u8 is_p2p_connected;
+ struct timer_list p2p_alive_timer;
+ struct rwnx_vif *p2p_dev_vif;
+ atomic_t p2p_alive_timer_count;
+ bool band_5g_support;
+ u8 vendor_info;
+ bool fwlog_en;
+ int testmode;
+ u8 scanning;
+ char country_abbr[4];
+ const struct aic_chip_ops *chip_ops;
+
+ struct list_head defrag_list;
+ spinlock_t defrag_lock; //
+
+ struct work_struct apm_staloss_work;
+ struct workqueue_struct *apm_staloss_wq;
+ u8 apm_vif_idx;
+ u8 sta_mac_addr[6];
+
+ struct wakeup_source *ws_rx;
+ struct wakeup_source *ws_irqrx;
+ struct wakeup_source *ws_tx;
+ struct wakeup_source *ws_pwrctrl;
+ struct wakeup_source *ws_scan;
+
+#ifdef CONFIG_AIC8800_SCHED_SCAN
+ bool is_sched_scan;
+#endif
+
+#ifdef CONFIG_AIC8800_AUTO_CUSTREG
+ struct scanu_ccode ccode;
+#endif
+
+#ifdef CONFIG_AIC8800_TEMP_CONTROL
+ unsigned long started_jiffies;
+ s8 temp;
+#endif
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+ struct work_struct pwlt_wk;
+#endif
+#ifdef CONFIG_AIC8800_REGION_PW
+ struct work_struct region_wk;
+#endif
+ char fw_version[32];
+
+};
+
+u8 *rwnx_build_bcn(struct rwnx_bcn *bcn, struct cfg80211_beacon_data *new);
+
+void rwnx_chanctx_link(struct rwnx_vif *vif, u8 idx,
+ struct cfg80211_chan_def *chandef);
+void rwnx_chanctx_unlink(struct rwnx_vif *vif);
+int rwnx_chanctx_valid(struct rwnx_hw *rwnx_hw, u8 idx);
+
+extern u8 chip_id;
+
+static inline bool is_multicast_sta(int sta_idx)
+{
+ if (g_rwnx_plat->sdiodev->rwnx_hw->chip_ops->is_old_ic)
+ return (sta_idx >= NX_REMOTE_STA_MAX_FOR_OLD_IC);
+ else
+ return (sta_idx >= NX_REMOTE_STA_MAX);
+}
+
+struct rwnx_sta *rwnx_get_sta(struct rwnx_hw *rwnx_hw, const u8 *mac_addr);
+
+static inline uint8_t master_vif_idx(struct rwnx_vif *vif)
+{
+#if IS_ENABLED(CONFIG_AIC8800_STA_ONLY)
+ return vif->vif_index;
+#else
+ if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_AP_VLAN))
+ return vif->ap_vlan.master->vif_index;
+ else
+ return vif->vif_index;
+#endif
+}
+
+void rwnx_external_auth_enable(struct rwnx_vif *vif);
+void rwnx_external_auth_disable(struct rwnx_vif *vif);
+
+#endif /* _RWNX_DEFS_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_events.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_events.h
new file mode 100644
index 0000000000000..c40751ea8b980
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_events.h
@@ -0,0 +1,938 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief Trace events definition
+ *
+ ******************************************************************************
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM rwnx
+
+#if !defined(_RWNX_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _RWNX_EVENTS_H
+
+#include <linux/tracepoint.h>
+#include "rwnx_tx.h"
+
+#include "rwnx_compat.h"
+
+/*****************************************************************************
+ * TRACE function for MGMT TX (FULLMAC)
+ ****************************************************************************/
+#ifdef CONFIG_RWNX_FULLMAC
+#include "linux/ieee80211.h"
+#if defined(CONFIG_TRACEPOINTS) && defined(AIC8800_CREATE_TRACE_POINTS) && \
+ !defined(TRACE_HEADER_MULTI_READ)
+#include <linux/trace_seq.h>
+
+/* P2P Public Action Frames Definitions (see WiFi P2P Technical Specification,
+ * section 4.2.8)
+ */
+/* IEEE 802.11 Public Action Usage Category - Define P2P public action frames */
+#define MGMT_ACTION_PUBLIC_CAT (0x04)
+/* Offset of OUI Subtype field in P2P Action Frame format */
+#define MGMT_ACTION_OUI_SUBTYPE_OFFSET (6)
+/* P2P Public Action Frame Types */
+enum p2p_action_type {
+ P2P_ACTION_GO_NEG_REQ = 0, /* GO Negociation Request */
+ P2P_ACTION_GO_NEG_RSP, /* GO Negociation Response */
+ P2P_ACTION_GO_NEG_CFM, /* GO Negociation Confirmation */
+ P2P_ACTION_INVIT_REQ, /* P2P Invitation Request */
+ P2P_ACTION_INVIT_RSP, /* P2P Invitation Response */
+ P2P_ACTION_DEV_DISC_REQ, /* Device Discoverability Request */
+ P2P_ACTION_DEV_DISC_RSP, /* Device Discoverability Response */
+ P2P_ACTION_PROV_DISC_REQ, /* Provision Discovery Request */
+ P2P_ACTION_PROV_DISC_RSP, /* Provision Discovery Response */
+};
+
+static inline const char *ftrace_print_mgmt_info(struct trace_seq *p,
+ u16 frame_control, u8 cat, u8 type,
+ u8 p2p)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ switch (frame_control & IEEE80211_FCTL_STYPE) {
+ case (IEEE80211_STYPE_ASSOC_REQ):
+ trace_seq_printf(p, "Association Request");
+ break;
+ case (IEEE80211_STYPE_ASSOC_RESP):
+ trace_seq_printf(p, "Association Response");
+ break;
+ case (IEEE80211_STYPE_REASSOC_REQ):
+ trace_seq_printf(p, "Reassociation Request");
+ break;
+ case (IEEE80211_STYPE_REASSOC_RESP):
+ trace_seq_printf(p, "Reassociation Response");
+ break;
+ case (IEEE80211_STYPE_PROBE_REQ):
+ trace_seq_printf(p, "Probe Request");
+ break;
+ case (IEEE80211_STYPE_PROBE_RESP):
+ trace_seq_printf(p, "Probe Response");
+ break;
+ case (IEEE80211_STYPE_BEACON):
+ trace_seq_printf(p, "Beacon");
+ break;
+ case (IEEE80211_STYPE_ATIM):
+ trace_seq_printf(p, "ATIM");
+ break;
+ case (IEEE80211_STYPE_DISASSOC):
+ trace_seq_printf(p, "Disassociation");
+ break;
+ case (IEEE80211_STYPE_AUTH):
+ trace_seq_printf(p, "Authentication");
+ break;
+ case (IEEE80211_STYPE_DEAUTH):
+ trace_seq_printf(p, "Deauthentication");
+ break;
+ case (IEEE80211_STYPE_ACTION):
+ trace_seq_printf(p, "Action");
+ if (cat == MGMT_ACTION_PUBLIC_CAT && type == 0x9) {
+ switch (p2p) {
+ case (P2P_ACTION_GO_NEG_REQ):
+ trace_seq_printf(p, ": GO Negociation Request");
+ break;
+ case (P2P_ACTION_GO_NEG_RSP):
+ trace_seq_printf(p, ": GO Negociation Response");
+ break;
+ case (P2P_ACTION_GO_NEG_CFM):
+ trace_seq_printf(p, ": GO Negociation Confirmation");
+ break;
+ case (P2P_ACTION_INVIT_REQ):
+ trace_seq_printf(p, ": P2P Invitation Request");
+ break;
+ case (P2P_ACTION_INVIT_RSP):
+ trace_seq_printf(p, ": P2P Invitation Response");
+ break;
+ case (P2P_ACTION_DEV_DISC_REQ):
+ trace_seq_printf(p, ": Device Discoverability Request");
+ break;
+ case (P2P_ACTION_DEV_DISC_RSP):
+ trace_seq_printf(p, ": Device Discoverability Response");
+ break;
+ case (P2P_ACTION_PROV_DISC_REQ):
+ trace_seq_printf(p, ": Provision Discovery Request");
+ break;
+ case (P2P_ACTION_PROV_DISC_RSP):
+ trace_seq_printf(p, ": Provision Discovery Response");
+ break;
+ default:
+ trace_seq_printf(p, "Unknown p2p %d", p2p);
+ break;
+ }
+ } else {
+ switch (cat) {
+ case 0:
+ trace_seq_printf(p, ":Spectrum %d", type);
+ break;
+ case 1:
+ trace_seq_printf(p, ":QOS %d", type);
+ break;
+ case 2:
+ trace_seq_printf(p, ":DLS %d", type);
+ break;
+ case 3:
+ trace_seq_printf(p, ":BA %d", type);
+ break;
+ case 4:
+ trace_seq_printf(p, ":Public %d", type);
+ break;
+ case 5:
+ trace_seq_printf(p, ":Radio Measure %d", type);
+ break;
+ case 6:
+ trace_seq_printf(p, ":Fast BSS %d", type);
+ break;
+ case 7:
+ trace_seq_printf(p, ":HT Action %d", type);
+ break;
+ case 8:
+ trace_seq_printf(p, ":SA Query %d", type);
+ break;
+ case 9:
+ trace_seq_printf(p, ":Protected Public %d", type);
+ break;
+ case 10:
+ trace_seq_printf(p, ":WNM %d", type);
+ break;
+ case 11:
+ trace_seq_printf(p, ":Unprotected WNM %d", type);
+ break;
+ case 12:
+ trace_seq_printf(p, ":TDLS %d", type);
+ break;
+ case 13:
+ trace_seq_printf(p, ":Mesh %d", type);
+ break;
+ case 14:
+ trace_seq_printf(p, ":MultiHop %d", type);
+ break;
+ case 15:
+ trace_seq_printf(p, ":Self Protected %d", type);
+ break;
+ case 126:
+ trace_seq_printf(p, ":Vendor protected");
+ break;
+ case 127:
+ trace_seq_printf(p, ":Vendor");
+ break;
+ default:
+ trace_seq_printf(p, ":Unknown category %d", cat);
+ break;
+ }
+ }
+ break;
+ default:
+ trace_seq_printf(p, "Unknown subtype %d",
+ frame_control & IEEE80211_FCTL_STYPE);
+ break;
+ }
+
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+#endif /* defined(CONFIG_TRACEPOINTS) && defined(AIC8800_CREATE_TRACE_POINTS) */
+
+#undef __print_mgmt_info
+#define __print_mgmt_info(frame_control, cat, type, p2p) \
+ ftrace_print_mgmt_info(p, frame_control, cat, type, p2p)
+
+TRACE_EVENT(roc, TP_PROTO(u8 vif_idx, u16 freq, unsigned int duration),
+ TP_ARGS(vif_idx, freq, duration),
+ TP_STRUCT__entry(__field(u8, vif_idx) __field(u16, freq)
+ __field(unsigned int, duration)),
+ TP_fast_assign(__entry->vif_idx = vif_idx; __entry->freq = freq;
+ __entry->duration = duration;),
+ TP_printk("f=%d vif=%d dur=%d", __entry->freq, __entry->vif_idx,
+ __entry->duration));
+
+TRACE_EVENT(cancel_roc, TP_PROTO(u8 vif_idx), TP_ARGS(vif_idx),
+ TP_STRUCT__entry(__field(u8, vif_idx)),
+ TP_fast_assign(__entry->vif_idx = vif_idx;),
+ TP_printk("vif=%d", __entry->vif_idx));
+
+TRACE_EVENT(roc_exp, TP_PROTO(u8 vif_idx), TP_ARGS(vif_idx),
+ TP_STRUCT__entry(__field(u8, vif_idx)),
+ TP_fast_assign(__entry->vif_idx = vif_idx;),
+ TP_printk("vif=%d", __entry->vif_idx));
+
+TRACE_EVENT(switch_roc, TP_PROTO(u8 vif_idx), TP_ARGS(vif_idx),
+ TP_STRUCT__entry(__field(u8, vif_idx)),
+ TP_fast_assign(__entry->vif_idx = vif_idx;),
+ TP_printk("vif=%d", __entry->vif_idx));
+
+DECLARE_EVENT_CLASS(mgmt_template,
+ TP_PROTO(u16 freq, u8 vif_idx, u8 sta_idx, struct ieee80211_mgmt *mgmt),
+ TP_ARGS(freq, vif_idx, sta_idx, mgmt),
+ TP_STRUCT__entry(__field(u16, freq) __field(u8, vif_idx)
+ __field(u8, sta_idx) __field(u16, frame_control)
+ __field(u8, action_cat) __field(u8, action_type)
+ __field(u8, action_p2p)),
+ TP_fast_assign(__entry->freq = freq; __entry->vif_idx = vif_idx;
+ __entry->sta_idx = sta_idx;
+ __entry->frame_control = le16_to_cpu(mgmt->frame_control);
+ __entry->action_cat = mgmt->u.action.category;
+ __entry->action_type = mgmt->u.action.action_code;
+ __entry->action_p2p = *((u8 *)&mgmt->u.action.category +
+ MGMT_ACTION_OUI_SUBTYPE_OFFSET);),
+ TP_printk("f=%d vif=%d sta=%d -> %s", __entry->freq, __entry->vif_idx,
+ __entry->sta_idx,
+ __print_mgmt_info(__entry->frame_control, __entry->action_cat,
+ __entry->action_type, __entry->action_p2p)));
+
+DEFINE_EVENT(mgmt_template, mgmt_tx,
+ TP_PROTO(u16 freq, u8 vif_idx, u8 sta_idx,
+ struct ieee80211_mgmt *mgmt),
+ TP_ARGS(freq, vif_idx, sta_idx, mgmt));
+
+DEFINE_EVENT(mgmt_template, mgmt_rx,
+ TP_PROTO(u16 freq, u8 vif_idx, u8 sta_idx,
+ struct ieee80211_mgmt *mgmt),
+ TP_ARGS(freq, vif_idx, sta_idx, mgmt));
+
+TRACE_EVENT(mgmt_cfm, TP_PROTO(u8 vif_idx, u8 sta_idx, bool acked),
+ TP_ARGS(vif_idx, sta_idx, acked),
+ TP_STRUCT__entry(__field(u8, vif_idx) __field(u8, sta_idx)
+ __field(bool, acked)),
+ TP_fast_assign(__entry->vif_idx = vif_idx;
+ __entry->sta_idx = sta_idx; __entry->acked = acked;),
+ TP_printk("vif=%d sta=%d ack=%d", __entry->vif_idx,
+ __entry->sta_idx, __entry->acked));
+#endif /* CONFIG_RWNX_FULLMAC */
+
+/*****************************************************************************
+ * TRACE function for TXQ
+ ****************************************************************************/
+
+#if defined(CONFIG_TRACEPOINTS) && defined(AIC8800_CREATE_TRACE_POINTS) && \
+ !defined(TRACE_HEADER_MULTI_READ)
+
+#include <linux/trace_seq.h>
+#include <linux/trace_events.h>
+
+static inline const char *ftrace_print_txq(struct trace_seq *p, int txq_idx)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ if (txq_idx == TXQ_INACTIVE) {
+ trace_seq_printf(p, "[INACTIVE]");
+ } else if (txq_idx < NX_FIRST_VIF_TXQ_IDX) {
+ trace_seq_printf(p, "[STA %d/%d]", txq_idx / NX_NB_TXQ_PER_STA,
+ txq_idx % NX_NB_TXQ_PER_STA);
+#ifdef CONFIG_RWNX_FULLMAC
+ } else if (txq_idx < NX_FIRST_UNK_TXQ_IDX) {
+ trace_seq_printf(p, "[BC/MC %d]", txq_idx - NX_FIRST_BCMC_TXQ_IDX);
+ } else if (txq_idx < NX_OFF_CHAN_TXQ_IDX) {
+ trace_seq_printf(p, "[UNKNOWN %d]", txq_idx - NX_FIRST_UNK_TXQ_IDX);
+ } else if (txq_idx == NX_OFF_CHAN_TXQ_IDX) {
+ trace_seq_printf(p, "[OFFCHAN]");
+#else
+ } else if (txq_idx < NX_NB_TXQ) {
+ txq_idx -= NX_FIRST_VIF_TXQ_IDX;
+ trace_seq_printf(p, "[VIF %d/%d]", txq_idx / NX_NB_TXQ_PER_VIF,
+ txq_idx % NX_NB_TXQ_PER_VIF);
+#endif
+ } else {
+ trace_seq_printf(p, "[ERROR %d]", txq_idx);
+ }
+
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
+static inline const char *ftrace_print_sta(struct trace_seq *p, int sta_idx)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ if (sta_idx < NX_REMOTE_STA_MAX)
+ trace_seq_printf(p, "[STA %d]", sta_idx);
+ else
+ trace_seq_printf(p, "[BC/MC %d]", sta_idx - NX_REMOTE_STA_MAX);
+
+ trace_seq_putc(p, 0);
+
+ return ret;
+}
+
+static inline const char *ftrace_print_hwq(struct trace_seq *p, int hwq_idx)
+{
+ static const struct trace_print_flags symbols[] = {{RWNX_HWQ_BK, "BK"},
+ {RWNX_HWQ_BE, "BE"},
+ {RWNX_HWQ_VI, "VI"},
+ {RWNX_HWQ_VO, "VO"},
+#ifdef CONFIG_RWNX_FULLMAC
+ {RWNX_HWQ_BCMC, "BCMC"},
+#else
+ {RWNX_HWQ_BCN, "BCN"},
+#endif
+ {-1, NULL}};
+ return trace_print_symbols_seq(p, hwq_idx, symbols, ARRAY_SIZE(symbols));
+}
+
+static inline const char *ftrace_print_hwq_cred(struct trace_seq *p, u8 *cred)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+#if CONFIG_USER_MAX == 1
+ trace_seq_printf(p, "%d", cred[0]);
+#else
+ int i;
+
+ for (i = 0; i < CONFIG_USER_MAX - 1; i++)
+ trace_seq_printf(p, "%d-", cred[i]);
+ trace_seq_printf(p, "%d", cred[i]);
+#endif
+
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+static inline const char *ftrace_print_mu_info(struct trace_seq *p, u8 mu_info)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ if (mu_info)
+ trace_seq_printf(p, "MU: %d-%d", (mu_info & 0x3f), (mu_info >> 6));
+
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+static inline const char *ftrace_print_mu_group(struct trace_seq *p, int nb_user,
+ u8 *users)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+ int i;
+
+ if (users[0] != 0xff)
+ trace_seq_printf(p, "(%d", users[0]);
+ else
+ trace_seq_printf(p, "(-");
+ for (i = 1; i < CONFIG_USER_MAX; i++) {
+ if (users[i] != 0xff)
+ trace_seq_printf(p, ",%d", users[i]);
+ else
+ trace_seq_printf(p, ",-");
+ }
+
+ trace_seq_printf(p, ")");
+ trace_seq_putc(p, 0);
+ return ret;
+}
+
+static inline const char *ftrace_print_amsdu(struct trace_seq *p, u16 nb_pkt)
+{
+ const char *ret = trace_seq_buffer_ptr(p);
+
+ if (nb_pkt > 1)
+ trace_seq_printf(p, "(AMSDU %d)", nb_pkt);
+
+ trace_seq_putc(p, 0);
+ return ret;
+}
+#endif /* defined(CONFIG_TRACEPOINTS) && defined(AIC8800_CREATE_TRACE_POINTS) */
+
+#undef __print_txq
+#define __print_txq(txq_idx) ftrace_print_txq(p, txq_idx)
+
+#undef __print_sta
+#define __print_sta(sta_idx) ftrace_print_sta(p, sta_idx)
+
+#undef __print_hwq
+#define __print_hwq(hwq) ftrace_print_hwq(p, hwq)
+
+#undef __print_hwq_cred
+#define __print_hwq_cred(cred) ftrace_print_hwq_cred(p, cred)
+
+#undef __print_mu_info
+#define __print_mu_info(mu_info) ftrace_print_mu_info(p, mu_info)
+
+#undef __print_mu_group
+#define __print_mu_group(nb, users) ftrace_print_mu_group(p, nb, users)
+
+#undef __print_amsdu
+#define __print_amsdu(nb_pkt) ftrace_print_amsdu(p, nb_pkt)
+
+#ifdef CONFIG_RWNX_FULLMAC
+
+TRACE_EVENT(txq_select, TP_PROTO(int txq_idx, u16 pkt_ready_up, struct sk_buff *skb),
+ TP_ARGS(txq_idx, pkt_ready_up, skb),
+ TP_STRUCT__entry(__field(u16, txq_idx) __field(u16, pkt_ready)
+ __field(struct sk_buff *, skb)),
+ TP_fast_assign(__entry->txq_idx = txq_idx;
+ __entry->pkt_ready = pkt_ready_up; __entry->skb = skb;),
+ TP_printk("%s pkt_ready_up=%d skb=%p", __print_txq(__entry->txq_idx),
+ __entry->pkt_ready, __entry->skb));
+
+#endif /* CONFIG_RWNX_FULLMAC */
+
+DECLARE_EVENT_CLASS(hwq_template, TP_PROTO(u8 hwq_idx), TP_ARGS(hwq_idx),
+ TP_STRUCT__entry(__field(u8, hwq_idx)),
+ TP_fast_assign(__entry->hwq_idx = hwq_idx;),
+ TP_printk("%s", __print_hwq(__entry->hwq_idx)));
+
+DEFINE_EVENT(hwq_template, hwq_flowctrl_stop, TP_PROTO(u8 hwq_idx),
+ TP_ARGS(hwq_idx));
+
+DEFINE_EVENT(hwq_template, hwq_flowctrl_start, TP_PROTO(u8 hwq_idx),
+ TP_ARGS(hwq_idx));
+
+DECLARE_EVENT_CLASS(txq_template, TP_PROTO(struct rwnx_txq *txq), TP_ARGS(txq),
+ TP_STRUCT__entry(__field(u16, txq_idx)),
+ TP_fast_assign(__entry->txq_idx = txq->idx;),
+ TP_printk("%s", __print_txq(__entry->txq_idx)));
+
+DEFINE_EVENT(txq_template, txq_add_to_hw, TP_PROTO(struct rwnx_txq *txq),
+ TP_ARGS(txq));
+
+DEFINE_EVENT(txq_template, txq_del_from_hw, TP_PROTO(struct rwnx_txq *txq),
+ TP_ARGS(txq));
+
+#ifdef CONFIG_RWNX_FULLMAC
+
+DEFINE_EVENT(txq_template, txq_flowctrl_stop, TP_PROTO(struct rwnx_txq *txq),
+ TP_ARGS(txq));
+
+DEFINE_EVENT(txq_template, txq_flowctrl_restart, TP_PROTO(struct rwnx_txq *txq),
+ TP_ARGS(txq));
+
+#endif /* CONFIG_RWNX_FULLMAC */
+
+TRACE_EVENT(process_txq, TP_PROTO(struct rwnx_txq *txq), TP_ARGS(txq),
+ TP_STRUCT__entry(__field(u16, txq_idx) __field(u16, len)
+ __field(u16, len_retry) __field(s8, credit)
+#ifdef CONFIG_RWNX_FULLMAC
+ __field(u16, limit)
+#endif /* CONFIG_RWNX_FULLMAC */
+ ),
+ TP_fast_assign(__entry->txq_idx = txq->idx;
+ __entry->len = skb_queue_len(&txq->sk_list);
+#ifdef CONFIG_MAC80211_TXQ
+ __entry->len += txq->nb_ready_mac80211;
+#endif
+ __entry->len_retry = txq->nb_retry;
+ __entry->credit = txq->credits;
+#ifdef CONFIG_RWNX_FULLMAC
+ __entry->limit = txq->push_limit;
+#endif /* CONFIG_RWNX_FULLMAC */
+ ),
+#ifdef CONFIG_RWNX_FULLMAC
+ TP_printk("%s txq_credits=%d, len=%d, retry_len=%d, push_limit=%d",
+ __print_txq(__entry->txq_idx), __entry->credit,
+ __entry->len, __entry->len_retry, __entry->limit)
+#else
+ TP_printk("%s txq_credits=%d, len=%d, retry_len=%d",
+ __print_txq(__entry->txq_idx), __entry->credit,
+ __entry->len, __entry->len_retry)
+#endif /* CONFIG_RWNX_FULLMAC */
+);
+
+DECLARE_EVENT_CLASS(txq_reason_template, TP_PROTO(struct rwnx_txq *txq, u16 reason),
+ TP_ARGS(txq, reason),
+ TP_STRUCT__entry(__field(u16, txq_idx) __field(u16, reason)
+ __field(u16, status)),
+ TP_fast_assign(__entry->txq_idx = txq->idx; __entry->reason = reason;
+ __entry->status = txq->status;),
+ TP_printk("%s reason=%s status=%s", __print_txq(__entry->txq_idx),
+ __print_symbolic(__entry->reason, {RWNX_TXQ_STOP_FULL, "FULL"},
+ {RWNX_TXQ_STOP_CSA, "CSA"},
+ {RWNX_TXQ_STOP_STA_PS, "PS"},
+ {RWNX_TXQ_STOP_VIF_PS, "VPS"},
+ {RWNX_TXQ_STOP_CHAN, "CHAN"},
+ {RWNX_TXQ_STOP_MU_POS, "MU"}),
+ __print_flags(__entry->status, "|",
+ {RWNX_TXQ_IN_HWQ_LIST, "IN LIST"},
+ {RWNX_TXQ_STOP_FULL, "FULL"},
+ {RWNX_TXQ_STOP_CSA, "CSA"},
+ {RWNX_TXQ_STOP_STA_PS, "PS"},
+ {RWNX_TXQ_STOP_VIF_PS, "VPS"},
+ {RWNX_TXQ_STOP_CHAN, "CHAN"},
+ {RWNX_TXQ_STOP_MU_POS, "MU"},
+ {RWNX_TXQ_NDEV_FLOW_CTRL, "FLW_CTRL"})));
+
+DEFINE_EVENT(txq_reason_template, txq_start,
+ TP_PROTO(struct rwnx_txq *txq, u16 reason), TP_ARGS(txq, reason));
+
+DEFINE_EVENT(txq_reason_template, txq_stop,
+ TP_PROTO(struct rwnx_txq *txq, u16 reason), TP_ARGS(txq, reason));
+
+TRACE_EVENT(push_desc,
+ TP_PROTO(struct sk_buff *skb, struct rwnx_sw_txhdr *sw_txhdr, int push_flags),
+ TP_ARGS(skb, sw_txhdr, push_flags),
+ TP_STRUCT__entry(__field(struct sk_buff *, skb) __field(unsigned int, len)
+ __field(u16, tx_queue) __field(u8, hw_queue)
+ __field(u8, push_flag) __field(u32, flag)
+ __field(s8, txq_cred) __field(u8, hwq_cred)
+ __field(u16, pkt_cnt)
+ __field(u8, mu_info)),
+ TP_fast_assign(__entry->skb = skb; __entry->tx_queue = sw_txhdr->txq->idx;
+ __entry->push_flag = push_flags;
+ __entry->hw_queue = sw_txhdr->txq->hwq->id;
+ __entry->txq_cred = sw_txhdr->txq->credits;
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+ __entry->pkt_cnt = sw_txhdr->desc.host.packet_cnt;
+#endif
+#ifdef CONFIG_RWNX_FULLMAC
+ __entry->flag = sw_txhdr->desc.host.flags;
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+#ifdef CONFIG_RWNX_AMSDUS_TX
+ if (sw_txhdr->amsdu.len)
+ __entry->len = sw_txhdr->amsdu.len;
+ else
+#endif /* CONFIG_RWNX_AMSDUS_TX */
+ __entry->len = sw_txhdr->desc.host.packet_len[0];
+#else
+ __entry->len = sw_txhdr->desc.host.packet_len;
+#endif /* CONFIG_RWNX_SPLIT_TX_BUF */
+#else /* !CONFIG_RWNX_FULLMAC */
+ __entry->flag = sw_txhdr->desc.umac.flags;
+ __entry->len = sw_txhdr->frame_len;
+ __entry->sn = sw_txhdr->sn;
+#endif /* CONFIG_RWNX_FULLMAC */
+#ifdef CONFIG_RWNX_MUMIMO_TX
+ __entry->mu_info = sw_txhdr->desc.host.mumimo_info;
+#else
+ __entry->mu_info = 0;
+#endif
+ ),
+#ifdef CONFIG_RWNX_FULLMAC
+ TP_printk("%s skb=%p (len=%d) hw_queue=%s cred_txq=%d cred_hwq=%d %s flag=%s %s %s %s",
+ __print_txq(__entry->tx_queue), __entry->skb, __entry->len,
+ __print_hwq(__entry->hw_queue), __entry->txq_cred,
+ __entry->hwq_cred, __print_mu_info(__entry->mu_info),
+ __print_flags(__entry->flag, "|", {TXU_CNTRL_RETRY, "RETRY"},
+ {TXU_CNTRL_MORE_DATA, "MOREDATA"}, {TXU_CNTRL_MGMT, "MGMT"},
+ {TXU_CNTRL_MGMT_NO_CCK, "NO_CCK"},
+ {TXU_CNTRL_MGMT_ROBUST, "ROBUST"}, {TXU_CNTRL_AMSDU, "AMSDU"},
+ {TXU_CNTRL_USE_4ADDR, "4ADDR"}, {TXU_CNTRL_EOSP, "EOSP"},
+ {TXU_CNTRL_MESH_FWD, "MESH_FWD"}, {TXU_CNTRL_TDLS, "TDLS"}),
+ (__entry->push_flag & RWNX_PUSH_IMMEDIATE) ? "(IMMEDIATE)" : "",
+ (!(__entry->flag & TXU_CNTRL_RETRY) &&
+ (__entry->push_flag & RWNX_PUSH_RETRY))
+ ? "(SW_RETRY)" : "",
+ __print_amsdu(__entry->pkt_cnt))
+#else
+ TP_printk("%s skb=%p (len=%d) hw_queue=%s cred_txq=%d cred_hwq=%d %s flag=%x (%s) sn=%d %s",
+ __print_txq(__entry->tx_queue), __entry->skb, __entry->len,
+ __print_hwq(__entry->hw_queue), __entry->txq_cred,
+ __entry->hwq_cred, __print_mu_info(__entry->mu_info),
+ __entry->flag,
+ __print_flags(__entry->push_flag, "|", {RWNX_PUSH_RETRY, "RETRY"},
+ {RWNX_PUSH_IMMEDIATE, "IMMEDIATE"}),
+ __entry->sn, __print_amsdu(__entry->pkt_cnt))
+#endif /* CONFIG_RWNX_FULLMAC */
+);
+
+TRACE_EVENT(txq_queue_skb, TP_PROTO(struct sk_buff *skb, struct rwnx_txq *txq, bool retry),
+ TP_ARGS(skb, txq, retry),
+ TP_STRUCT__entry(__field(struct sk_buff *, skb) __field(u16, txq_idx)
+ __field(s8, credit) __field(u16, q_len)
+ __field(u16, q_len_retry) __field(bool, retry)),
+ TP_fast_assign(__entry->skb = skb; __entry->txq_idx = txq->idx;
+ __entry->credit = txq->credits;
+ __entry->q_len = skb_queue_len(&txq->sk_list);
+ __entry->q_len_retry = txq->nb_retry;
+ __entry->retry = retry;),
+ TP_printk("%s skb=%p retry=%d txq_credits=%d queue_len=%d (retry = %d)",
+ __print_txq(__entry->txq_idx), __entry->skb, __entry->retry,
+ __entry->credit, __entry->q_len, __entry->q_len_retry));
+
+#ifdef CONFIG_MAC80211_TXQ
+TRACE_EVENT(txq_wake, TP_PROTO(struct rwnx_txq *txq), TP_ARGS(txq),
+ TP_STRUCT__entry(__field(u16, txq_idx) __field(u16, q_len)),
+ TP_fast_assign(__entry->txq_idx = txq->idx;
+ __entry->q_len = txq->nb_ready_mac80211;),
+ TP_printk("%s mac80211_queue_len=%d", __print_txq(__entry->txq_idx),
+ __entry->q_len));
+
+TRACE_EVENT(txq_drop, TP_PROTO(struct rwnx_txq *txq, unsigned long nb_drop),
+ TP_ARGS(txq, nb_drop),
+ TP_STRUCT__entry(__field(u16, txq_idx) __field(u16, nb_drop)),
+ TP_fast_assign(__entry->txq_idx = txq->idx;
+ __entry->nb_drop = nb_drop;),
+ TP_printk("%s %u pkt have been dropped by codel in mac80211 txq",
+ __print_txq(__entry->txq_idx), __entry->nb_drop));
+
+#endif
+
+DECLARE_EVENT_CLASS(idx_template, TP_PROTO(u16 idx), TP_ARGS(idx),
+ TP_STRUCT__entry(__field(u16, idx)),
+ TP_fast_assign(__entry->idx = idx;),
+ TP_printk("idx=%d", __entry->idx));
+
+DEFINE_EVENT(idx_template, txq_vif_start, TP_PROTO(u16 idx), TP_ARGS(idx));
+
+DEFINE_EVENT(idx_template, txq_vif_stop, TP_PROTO(u16 idx), TP_ARGS(idx));
+
+TRACE_EVENT(process_hw_queue, TP_PROTO(struct rwnx_hwq *hwq), TP_ARGS(hwq),
+ TP_STRUCT__entry(__field(u16, hwq)
+ __array(u8, credits, CONFIG_USER_MAX)),
+ TP_fast_assign(__entry->hwq = hwq->id;),
+ TP_printk("hw_queue=%s hw_credits=%s", __print_hwq(__entry->hwq),
+ __print_hwq_cred(__entry->credits)));
+
+DECLARE_EVENT_CLASS(sta_idx_template, TP_PROTO(u16 idx), TP_ARGS(idx),
+ TP_STRUCT__entry(__field(u16, idx)),
+ TP_fast_assign(__entry->idx = idx;),
+ TP_printk("%s", __print_sta(__entry->idx)));
+
+DEFINE_EVENT(sta_idx_template, txq_sta_start, TP_PROTO(u16 idx), TP_ARGS(idx));
+
+DEFINE_EVENT(sta_idx_template, txq_sta_stop, TP_PROTO(u16 idx), TP_ARGS(idx));
+
+#ifdef CONFIG_RWNX_FULLMAC
+
+DEFINE_EVENT(sta_idx_template, ps_disable, TP_PROTO(u16 idx), TP_ARGS(idx));
+
+#endif /* CONFIG_RWNX_FULLMAC */
+
+TRACE_EVENT(skb_confirm,
+ #ifdef CONFIG_RWNX_FULLMAC
+ TP_PROTO(struct sk_buff *skb, struct rwnx_txq *txq,
+ struct rwnx_hwq *hwq, struct tx_cfm_tag *cfm),
+ #else
+ TP_PROTO(struct sk_buff *skb, struct rwnx_txq *txq,
+ struct rwnx_hwq *hwq, u8 cfm),
+ #endif
+ TP_ARGS(skb, txq, hwq, cfm),
+ TP_STRUCT__entry(__field(struct sk_buff *, skb) __field(u16, txq_idx)
+ __field(u8, hw_queue) __array(u8, hw_credit, CONFIG_USER_MAX)
+ __field(s8, sw_credit) __field(s8, sw_credit_up)
+#ifdef CONFIG_RWNX_FULLMAC
+ __field(u8, ampdu_size)
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+ __field(u16, amsdu)
+#endif /* CONFIG_RWNX_SPLIT_TX_BUF */
+ __field(u16, sn)
+#endif /* CONFIG_RWNX_FULLMAC */
+ ),
+ TP_fast_assign(__entry->skb = skb; __entry->txq_idx = txq->idx;
+ __entry->hw_queue = hwq->id;
+ __entry->sw_credit = txq->credits;
+#if defined CONFIG_RWNX_FULLMAC
+ __entry->sw_credit_up = cfm->credits;
+ __entry->ampdu_size = cfm->ampdu_size;
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+ __entry->amsdu = cfm->amsdu_size; __entry->sn = cfm->sn;
+#endif
+#else
+ __entry->sw_credit_up = cfm
+#endif /* CONFIG_RWNX_FULLMAC */
+ ),
+ TP_printk("%s skb=%p hw_queue=%s, hw_credits=%s, txq_credits=%d (+%d)"
+#ifdef CONFIG_RWNX_FULLMAC
+ " sn=%u ampdu=%d"
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+ " amsdu=%u"
+#endif
+#endif
+ ,
+ __print_txq(__entry->txq_idx), __entry->skb,
+ __print_hwq(__entry->hw_queue),
+ __print_hwq_cred(__entry->hw_credit), __entry->sw_credit,
+ __entry->sw_credit_up
+#ifdef CONFIG_RWNX_FULLMAC
+ ,
+ __entry->sn, __entry->ampdu_size
+#ifdef CONFIG_RWNX_SPLIT_TX_BUF
+ ,
+ __entry->amsdu
+#endif
+#endif
+ ));
+
+TRACE_EVENT(credit_update, TP_PROTO(struct rwnx_txq *txq, s8 cred_up),
+ TP_ARGS(txq, cred_up),
+ TP_STRUCT__entry(__field(struct sk_buff *, skb)
+ __field(u16, txq_idx) __field(s8, sw_credit)
+ __field(s8, sw_credit_up)),
+ TP_fast_assign(__entry->txq_idx = txq->idx;
+ __entry->sw_credit = txq->credits;
+ __entry->sw_credit_up = cred_up;),
+ TP_printk("%s txq_credits=%d (%+d)", __print_txq(__entry->txq_idx),
+ __entry->sw_credit, __entry->sw_credit_up))
+#ifdef CONFIG_RWNX_FULLMAC
+DECLARE_EVENT_CLASS(ps_template, TP_PROTO(struct rwnx_sta *sta), TP_ARGS(sta),
+ TP_STRUCT__entry(__field(u16, idx) __field(u16, ready_ps)
+ __field(u16, sp_ps) __field(u16, ready_uapsd)
+ __field(u16, sp_uapsd)),
+ TP_fast_assign(__entry->idx = sta->sta_idx;
+ __entry->ready_ps = sta->ps.pkt_ready[LEGACY_PS_ID];
+ __entry->sp_ps = sta->ps.sp_cnt[LEGACY_PS_ID];
+ __entry->ready_uapsd = sta->ps.pkt_ready[UAPSD_ID];
+ __entry->sp_uapsd = sta->ps.sp_cnt[UAPSD_ID];),
+ TP_printk("%s [PS] ready=%d sp=%d [UAPSD] ready=%d sp=%d",
+ __print_sta(__entry->idx), __entry->ready_ps, __entry->sp_ps,
+ __entry->ready_uapsd, __entry->sp_uapsd));
+
+DEFINE_EVENT(ps_template, ps_queue, TP_PROTO(struct rwnx_sta *sta), TP_ARGS(sta));
+
+DEFINE_EVENT(ps_template, ps_push, TP_PROTO(struct rwnx_sta *sta), TP_ARGS(sta));
+
+DEFINE_EVENT(ps_template, ps_enable, TP_PROTO(struct rwnx_sta *sta), TP_ARGS(sta));
+
+TRACE_EVENT(ps_traffic_update, TP_PROTO(u16 sta_idx, u8 traffic, bool uapsd),
+ TP_ARGS(sta_idx, traffic, uapsd),
+ TP_STRUCT__entry(__field(u16, sta_idx) __field(u8, traffic)
+ __field(bool, uapsd)),
+ TP_fast_assign(__entry->sta_idx = sta_idx;
+ __entry->traffic = traffic; __entry->uapsd = uapsd;),
+ TP_printk("%s %s%s traffic available ",
+ __print_sta(__entry->sta_idx),
+ __entry->traffic ? "" : "no more ",
+ __entry->uapsd ? "U-APSD" : "legacy PS"));
+
+TRACE_EVENT(ps_traffic_req, TP_PROTO(struct rwnx_sta *sta, u16 pkt_req, u8 ps_id),
+ TP_ARGS(sta, pkt_req, ps_id),
+ TP_STRUCT__entry(__field(u16, idx) __field(u16, pkt_req)
+ __field(u8, ps_id) __field(u16, ready)
+ __field(u16, sp)),
+ TP_fast_assign(__entry->idx = sta->sta_idx;
+ __entry->pkt_req = pkt_req; __entry->ps_id = ps_id;
+ __entry->ready = sta->ps.pkt_ready[ps_id];
+ __entry->sp = sta->ps.sp_cnt[ps_id];),
+ TP_printk("%s %s traffic request %d pkt (ready=%d, sp=%d)",
+ __print_sta(__entry->idx),
+ __entry->ps_id == UAPSD_ID ? "U-APSD" : "legacy PS",
+ __entry->pkt_req, __entry->ready, __entry->sp));
+
+#ifdef CONFIG_RWNX_AMSDUS_TX
+TRACE_EVENT(amsdu_subframe, TP_PROTO(struct rwnx_sw_txhdr *sw_txhdr),
+ TP_ARGS(sw_txhdr),
+ TP_STRUCT__entry(__field(struct sk_buff *, skb)
+ __field(u16, txq_idx) __field(u8, nb)
+ __field(u32, len)),
+ TP_fast_assign(__entry->skb = sw_txhdr->skb;
+ __entry->nb = sw_txhdr->amsdu.nb;
+ __entry->len = sw_txhdr->amsdu.len;
+ __entry->txq_idx = sw_txhdr->txq->idx;),
+ TP_printk("%s skb=%p %s nb_subframe=%d, len=%u",
+ __print_txq(__entry->txq_idx), __entry->skb,
+ (__entry->nb == 2) ? "Start new AMSDU" : "Add subframe",
+ __entry->nb, __entry->len));
+#endif
+
+#endif /* CONFIG_RWNX_FULLMAC */
+
+#ifdef CONFIG_RWNX_MUMIMO_TX
+TRACE_EVENT(mu_group_update, TP_PROTO(struct rwnx_mu_group *group),
+ TP_ARGS(group),
+ TP_STRUCT__entry(__field(u8, nb_user) __field(u8, group_id)
+ __array(u8, users, CONFIG_USER_MAX)),
+ TP_fast_assign(int i; __entry->nb_user = group->user_cnt;
+ for (i = 0; i < CONFIG_USER_MAX; i++) {
+ if (group->users[i])
+ __entry->users[i] = group->users[i]->sta_idx;
+ else
+ __entry->users[i] = 0xff;
+ }
+ __entry->group_id = group->group_id;),
+ TP_printk("Group-id = %d, Users = %s", __entry->group_id,
+ __print_mu_group(__entry->nb_user, __entry->users)));
+
+TRACE_EVENT(mu_group_delete, TP_PROTO(int group_id), TP_ARGS(group_id),
+ TP_STRUCT__entry(__field(u8, group_id)),
+ TP_fast_assign(__entry->group_id = group_id;),
+ TP_printk("Group-id = %d", __entry->group_id));
+
+TRACE_EVENT(mu_group_selection, TP_PROTO(struct rwnx_sta *sta, int group_id),
+ TP_ARGS(sta, group_id),
+ TP_STRUCT__entry(__field(u8, sta_idx) __field(u8, group_id)),
+ TP_fast_assign(__entry->sta_idx = sta->sta_idx;
+ __entry->group_id = group_id;),
+ TP_printk("[Sta %d] Group-id = %d", __entry->sta_idx,
+ __entry->group_id));
+
+TRACE_EVENT(txq_select_mu_group,
+ TP_PROTO(struct rwnx_txq *txq, int group_id, int pos),
+ TP_ARGS(txq, group_id, pos),
+ TP_STRUCT__entry(__field(u16, txq_idx) __field(u8, group_id)
+ __field(u8, pos)),
+ TP_fast_assign(__entry->txq_idx = txq->idx;
+ __entry->group_id = group_id; __entry->pos = pos;),
+ TP_printk("%s: group=%d pos=%d", __print_txq(__entry->txq_idx),
+ __entry->group_id, __entry->pos));
+
+#endif /* CONFIG_RWNX_MUMIMO_TX */
+
+/*****************************************************************************
+ * TRACE functions for MESH
+ ****************************************************************************/
+#ifdef CONFIG_RWNX_FULLMAC
+DECLARE_EVENT_CLASS(mesh_path_template, TP_PROTO(struct rwnx_mesh_path *mesh_path),
+ TP_ARGS(mesh_path),
+ TP_STRUCT__entry(__field(u8, idx) __field(u8, next_hop_sta)
+ __array(u8, tgt_mac, ETH_ALEN)),
+ TP_fast_assign(__entry->idx = mesh_path->path_idx;
+ memcpy(__entry->tgt_mac, &mesh_path->tgt_mac_addr, ETH_ALEN);
+ if (mesh_path->p_nhop_sta)
+ __entry->next_hop_sta = mesh_path->p_nhop_sta->sta_idx;
+ else
+ __entry->next_hop_sta = 0xff;),
+ TP_printk("Mpath(%d): target=%pM next_hop=STA-%d", __entry->idx,
+ __entry->tgt_mac, __entry->next_hop_sta));
+
+DEFINE_EVENT(mesh_path_template, mesh_create_path,
+ TP_PROTO(struct rwnx_mesh_path *mesh_path), TP_ARGS(mesh_path));
+
+DEFINE_EVENT(mesh_path_template, mesh_delete_path,
+ TP_PROTO(struct rwnx_mesh_path *mesh_path), TP_ARGS(mesh_path));
+
+DEFINE_EVENT(mesh_path_template, mesh_update_path,
+ TP_PROTO(struct rwnx_mesh_path *mesh_path), TP_ARGS(mesh_path));
+
+#endif /* CONFIG_RWNX_FULLMAC */
+
+/*****************************************************************************
+ * TRACE functions for RADAR
+ ****************************************************************************/
+#ifdef CONFIG_RWNX_RADAR
+TRACE_EVENT(radar_pulse, TP_PROTO(u8 chain, struct radar_pulse *pulse),
+ TP_ARGS(chain, pulse),
+ TP_STRUCT__entry(__field(u8, chain) __field(s16, freq)
+ __field(u16, pri) __field(u8, len)
+ __field(u8, fom)),
+ TP_fast_assign(__entry->freq = pulse->freq * 2;
+ __entry->len = pulse->len * 2;
+ __entry->fom = pulse->fom * 6;
+ __entry->pri = pulse->rep; __entry->chain = chain;),
+ TP_printk("%s: PRI=%.5d LEN=%.3d FOM=%.2d%% freq=%dMHz ",
+ __print_symbolic(__entry->chain, {RWNX_RADAR_RIU, "RIU"},
+ {RWNX_RADAR_FCU, "FCU"}),
+ __entry->pri, __entry->len, __entry->fom, __entry->freq));
+
+TRACE_EVENT(radar_detected, TP_PROTO(u8 chain, u8 region, s16 freq, u8 type, u16 pri),
+ TP_ARGS(chain, region, freq, type, pri),
+ TP_STRUCT__entry(__field(u8, chain) __field(u8, region) __field(s16, freq)
+ __field(u8, type) __field(u16, pri)),
+ TP_fast_assign(__entry->chain = chain; __entry->region = region;
+ __entry->freq = freq; __entry->type = type;
+ __entry->pri = pri;),
+ TP_printk("%s: region=%s type=%d freq=%dMHz (pri=%dus)",
+ __print_symbolic(__entry->chain, {RWNX_RADAR_RIU, "RIU"},
+ {RWNX_RADAR_FCU, "FCU"}),
+ __print_symbolic(__entry->region, {NL80211_DFS_UNSET, "UNSET"},
+ {NL80211_DFS_FCC, "FCC"},
+ {NL80211_DFS_ETSI, "ETSI"},
+ {NL80211_DFS_JP, "JP"}),
+ __entry->type, __entry->freq, __entry->pri));
+
+TRACE_EVENT(radar_set_region, TP_PROTO(u8 region), TP_ARGS(region),
+ TP_STRUCT__entry(__field(u8, region)),
+ TP_fast_assign(__entry->region = region;),
+ TP_printk("region=%s",
+ __print_symbolic(__entry->region,
+ {NL80211_DFS_UNSET, "UNSET"},
+ {NL80211_DFS_FCC, "FCC"},
+ {NL80211_DFS_ETSI, "ETSI"},
+ {NL80211_DFS_JP, "JP"})));
+
+TRACE_EVENT(radar_enable_detection, TP_PROTO(u8 region, u8 enable, u8 chain),
+ TP_ARGS(region, enable, chain),
+ TP_STRUCT__entry(__field(u8, region) __field(u8, chain)
+ __field(u8, enable)),
+ TP_fast_assign(__entry->chain = chain; __entry->enable = enable;
+ __entry->region = region;),
+ TP_printk("%s: %s radar detection %s",
+ __print_symbolic(__entry->chain, {RWNX_RADAR_RIU, "RIU"},
+ {RWNX_RADAR_FCU, "FCU"}),
+ __print_symbolic(__entry->enable,
+ {RWNX_RADAR_DETECT_DISABLE, "Disable"},
+ {RWNX_RADAR_DETECT_ENABLE,
+ "Enable (no report)"},
+ {RWNX_RADAR_DETECT_REPORT, "Enable"}),
+ __entry->enable == RWNX_RADAR_DETECT_DISABLE
+ ? "" : __print_symbolic(__entry->region,
+ {NL80211_DFS_UNSET, "UNSET"},
+ {NL80211_DFS_FCC, "FCC"},
+ {NL80211_DFS_ETSI, "ETSI"},
+ {NL80211_DFS_JP, "JP"})));
+#endif /* CONFIG_RWNX_RADAR */
+
+/*****************************************************************************
+ * TRACE functions for IPC message
+ ****************************************************************************/
+#include "rwnx_strs.h"
+
+DECLARE_EVENT_CLASS(ipc_msg_template, TP_PROTO(u16 id), TP_ARGS(id),
+ TP_STRUCT__entry(__field(u16, id)),
+ TP_fast_assign(__entry->id = id;),
+ TP_printk("%s (%d - %d)", RWNX_ID2STR(__entry->id),
+ MSG_T(__entry->id), MSG_I(__entry->id)));
+
+DEFINE_EVENT(ipc_msg_template, msg_send, TP_PROTO(u16 id), TP_ARGS(id));
+
+DEFINE_EVENT(ipc_msg_template, msg_recv, TP_PROTO(u16 id), TP_ARGS(id));
+
+#endif /* !defined(_RWNX_EVENTS_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH AIC_TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_FILE rwnx_events
+#include <trace/define_trace.h>
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_irqs.c b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_irqs.c
new file mode 100644
index 0000000000000..994b6f84cdaac
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_irqs.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief IRQ handler
+ *
+ ******************************************************************************
+ */
+#include <linux/interrupt.h>
+
+#include "rwnx_irqs.h"
+#include "ipc_host.h"
+#include "rwnx_defs.h"
+#include "rwnx_prof.h"
+
+/**
+ * rwnx_irq_hdlr - IRQ handler
+ * @irq: Interrupt number
+ * @dev_id: Driver private data registered for the interrupt
+ *
+ * Handler registered by the platform driver
+ *
+ * Return: %IRQ_HANDLED after scheduling the interrupt bottom half.
+ */
+irqreturn_t rwnx_irq_hdlr(int irq, void *dev_id)
+{
+ struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)dev_id;
+
+ disable_irq_nosync(irq);
+ tasklet_schedule(&rwnx_hw->task);
+ return IRQ_HANDLED;
+}
+
+/**
+ * rwnx_task - Bottom half for IRQ handler
+ * @data: Driver private data passed to the tasklet
+ *
+ * Read irq status and process accordingly
+ */
+void rwnx_task(unsigned long data)
+{
+ struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)data;
+
+ spin_lock_bh(&rwnx_hw->tx_lock);
+ rwnx_hwq_process_all(rwnx_hw);
+ spin_unlock_bh(&rwnx_hw->tx_lock);
+}
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_irqs.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_irqs.h
new file mode 100644
index 0000000000000..ff6c766c727c3
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_irqs.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _RWNX_IRQS_H_
+#define _RWNX_IRQS_H_
+
+#include <linux/interrupt.h>
+
+/* IRQ handler to be registered by platform driver */
+irqreturn_t rwnx_irq_hdlr(int irq, void *dev_id);
+
+void rwnx_task(unsigned long data);
+
+#endif /* _RWNX_IRQS_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_rx.c b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_rx.c
new file mode 100644
index 0000000000000..cc124c8a34e8b
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_rx.c
@@ -0,0 +1,1614 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief RX function definitions
+ *
+ ******************************************************************************
+ */
+
+#include "rwnx_defs.h"
+#include "rwnx_prof.h"
+#include "rwnx_tx.h"
+#include "rwnx_rx.h"
+#include <linux/rtnetlink.h>
+#include <linux/vmalloc.h>
+#ifdef CONFIG_RWNX_BFMER
+#include "rwnx_bfmer.h"
+#endif //(CONFIG_RWNX_BFMER)
+#ifdef CONFIG_RWNX_FULLMAC
+#include "rwnx_msg_tx.h"
+#include "rwnx_tdls.h"
+#endif /* CONFIG_RWNX_FULLMAC */
+#include "aicwf_txrxif.h"
+#include "aicwf_sdio.h"
+#include "rwnx_compat.h"
+#include "rwnx_events.h"
+#include "rwnx_msg_rx.h"
+#include "rwnx_mod_params.h"
+#include <linux/pm.h>
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+#include "aicwf_compat_8800d80.h"
+#endif
+
+void rwnx_cfg80211_unlink_bss(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif);
+
+static int rwnx_freq_to_idx(struct rwnx_hw *rwnx_hw, int freq)
+{
+ struct ieee80211_supported_band *sband = NULL;
+ int band, ch, idx = 0;
+
+ for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
+#ifdef CONFIG_RWNX_FULLMAC
+ sband = rwnx_hw->wiphy->bands[band];
+#endif /* CONFIG_RWNX_FULLMAC */
+ if (!sband)
+ continue;
+
+ for (ch = 0; ch < sband->n_channels; ch++, idx++) {
+ if (sband->channels[ch].center_freq == freq)
+ goto exit;
+ }
+ }
+
+ WARN_ON_ONCE(1);
+
+exit:
+ // Channel has been found, return the index
+ return idx;
+}
+
+/***************************************************************************
+ * Messages from MM task
+ **************************************************************************/
+static inline int rwnx_rx_chan_pre_switch_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct rwnx_vif *rwnx_vif;
+ int chan_idx = ((struct mm_channel_pre_switch_ind *)msg->param)->chan_index;
+
+ REG_SW_SET_PROFILING_CHAN(rwnx_hw, SW_PROF_CHAN_CTXT_PSWTCH_BIT);
+
+#ifdef CONFIG_RWNX_FULLMAC
+ list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
+ if (rwnx_vif->up && rwnx_vif->ch_index == chan_idx)
+ rwnx_txq_vif_stop(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
+ }
+#endif /* CONFIG_RWNX_FULLMAC */
+
+ REG_SW_CLEAR_PROFILING_CHAN(rwnx_hw, SW_PROF_CHAN_CTXT_PSWTCH_BIT);
+
+ return 0;
+}
+
+static inline int rwnx_rx_chan_switch_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct rwnx_vif *rwnx_vif;
+ int chan_idx = ((struct mm_channel_switch_ind *)msg->param)->chan_index;
+ bool roc = ((struct mm_channel_switch_ind *)msg->param)->roc;
+ bool roc_tdls = ((struct mm_channel_switch_ind *)msg->param)->roc_tdls;
+
+ REG_SW_SET_PROFILING_CHAN(rwnx_hw, SW_PROF_CHAN_CTXT_SWTCH_BIT);
+
+#ifdef CONFIG_RWNX_FULLMAC
+ if (roc_tdls) {
+ u8 vif_index = ((struct mm_channel_switch_ind *)msg->param)->vif_index;
+
+ list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
+ if (rwnx_vif->vif_index == vif_index) {
+ rwnx_vif->roc_tdls = true;
+ rwnx_txq_tdls_sta_start(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
+ }
+ }
+ } else if (!roc) {
+ list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
+ if (rwnx_vif->up && rwnx_vif->ch_index == chan_idx)
+ rwnx_txq_vif_start(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
+ }
+ } else {
+ /* Retrieve the allocated RoC element */
+ struct rwnx_roc_elem *roc_elem = rwnx_hw->roc_elem;
+ /* Get VIF on which RoC has been started */
+ // rwnx_vif = netdev_priv(roc_elem->wdev->netdev);
+
+ /* For debug purpose (use ftrace kernel option) */
+ // trace_switch_roc(rwnx_vif->vif_index);
+
+ if (roc_elem) {
+ /* If mgmt_roc is true, remain on channel has been started by
+ * ourself
+ */
+ if (!roc_elem->mgmt_roc) {
+ /* Inform the host that we have switch on the indicated
+ * off-channel
+ */
+ cfg80211_ready_on_channel(roc_elem->wdev,
+ roc_elem->cookie,
+ roc_elem->chan, roc_elem->duration,
+ GFP_ATOMIC);
+ }
+
+ /* Keep in mind that we have switched on the channel */
+ roc_elem->on_chan = true;
+ } else {
+ AICWFDBG(LOGDEBUG, "roc_elem == null\n");
+ }
+ // Enable traffic on OFF channel queue
+ rwnx_txq_offchan_start(rwnx_hw);
+ }
+
+ tasklet_schedule(&rwnx_hw->task);
+
+ rwnx_hw->cur_chanctx = chan_idx;
+ rwnx_radar_detection_enable_on_cur_channel(rwnx_hw);
+
+#endif /* CONFIG_RWNX_FULLMAC */
+
+ REG_SW_CLEAR_PROFILING_CHAN(rwnx_hw, SW_PROF_CHAN_CTXT_SWTCH_BIT);
+
+ return 0;
+}
+
+static inline int rwnx_rx_tdls_chan_switch_cfm(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ return 0;
+}
+
+static inline int rwnx_rx_tdls_chan_switch_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+#ifdef CONFIG_RWNX_FULLMAC
+ // Enable traffic on OFF channel queue
+ rwnx_txq_offchan_start(rwnx_hw);
+
+ return 0;
+#endif
+}
+
+static inline int rwnx_rx_tdls_chan_switch_base_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct rwnx_vif *rwnx_vif;
+ u8 vif_index = ((struct tdls_chan_switch_base_ind *)msg->param)->vif_index;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+#ifdef CONFIG_RWNX_FULLMAC
+ list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
+ if (rwnx_vif->vif_index == vif_index) {
+ rwnx_vif->roc_tdls = false;
+ rwnx_txq_tdls_sta_stop(rwnx_vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
+ }
+ }
+ return 0;
+#endif
+}
+
+static inline int rwnx_rx_tdls_peer_ps_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct rwnx_vif *rwnx_vif;
+ u8 vif_index = ((struct tdls_peer_ps_ind *)msg->param)->vif_index;
+ bool ps_on = ((struct tdls_peer_ps_ind *)msg->param)->ps_on;
+
+#ifdef CONFIG_RWNX_FULLMAC
+ list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
+ if (rwnx_vif->vif_index == vif_index) {
+ rwnx_vif->sta.tdls_sta->tdls.ps_on = ps_on;
+ // Update PS status for the TDLS station
+ rwnx_ps_bh_enable(rwnx_hw, rwnx_vif->sta.tdls_sta, ps_on);
+ }
+ }
+
+ return 0;
+#endif
+}
+
+static inline int rwnx_rx_remain_on_channel_exp_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+#ifdef CONFIG_RWNX_FULLMAC
+ /* Retrieve the allocated RoC element */
+ struct rwnx_roc_elem *roc_elem = rwnx_hw->roc_elem;
+ /* Get VIF on which RoC has been started */
+ struct rwnx_vif *rwnx_vif;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ if (!roc_elem)
+ return 0;
+
+ rwnx_vif = container_of(roc_elem->wdev, struct rwnx_vif, wdev);
+ /* For debug purpose (use ftrace kernel option) */
+#ifdef AIC8800_CREATE_TRACE_POINTS
+ trace_roc_exp(rwnx_vif->vif_index);
+#endif
+ /* If mgmt_roc is true, remain on channel has been started by ourself */
+ /* If RoC has been cancelled before we switched on channel, do not call
+ * cfg80211
+ */
+ if (!roc_elem->mgmt_roc && roc_elem->on_chan) {
+ /* Inform the host that off-channel period has expired */
+ cfg80211_remain_on_channel_expired(roc_elem->wdev,
+ roc_elem->cookie,
+ roc_elem->chan, GFP_ATOMIC);
+ }
+
+ /* De-init offchannel TX queue */
+ rwnx_txq_offchan_deinit(rwnx_vif);
+
+ /* Free the allocated RoC element */
+ kfree(roc_elem);
+ rwnx_hw->roc_elem = NULL;
+
+#endif /* CONFIG_RWNX_FULLMAC */
+ return 0;
+}
+
+static inline int rwnx_rx_p2p_vif_ps_change_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ int vif_idx = ((struct mm_p2p_vif_ps_change_ind *)msg->param)->vif_index;
+ int ps_state = ((struct mm_p2p_vif_ps_change_ind *)msg->param)->ps_state;
+ struct rwnx_vif *vif_entry;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+#ifdef CONFIG_RWNX_FULLMAC
+ vif_entry = rwnx_hw->vif_table[vif_idx];
+
+ if (vif_entry)
+ goto found_vif;
+#endif /* CONFIG_RWNX_FULLMAC */
+
+ goto exit;
+found_vif:
+
+#ifdef CONFIG_RWNX_FULLMAC
+ if (ps_state == MM_PS_MODE_OFF) {
+ // Start TX queues for provided VIF
+ rwnx_txq_vif_start(vif_entry, RWNX_TXQ_STOP_VIF_PS, rwnx_hw);
+ } else {
+ // Stop TX queues for provided VIF
+ rwnx_txq_vif_stop(vif_entry, RWNX_TXQ_STOP_VIF_PS, rwnx_hw);
+ }
+#endif /* CONFIG_RWNX_FULLMAC */
+
+exit:
+ return 0;
+}
+
+static inline int rwnx_rx_channel_survey_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mm_channel_survey_ind *ind =
+ (struct mm_channel_survey_ind *)msg->param;
+ // Get the channel index
+ int idx = rwnx_freq_to_idx(rwnx_hw, ind->freq);
+ // Get the survey
+ struct rwnx_survey_info *rwnx_survey;
+
+ if (idx > ARRAY_SIZE(rwnx_hw->survey))
+ return 0;
+
+ rwnx_survey = &rwnx_hw->survey[idx];
+
+ // Store the received parameters
+ rwnx_survey->chan_time_ms = ind->chan_time_ms;
+ rwnx_survey->chan_time_busy_ms = ind->chan_time_busy_ms;
+ rwnx_survey->noise_dbm = ind->noise_dbm;
+ rwnx_survey->filled = (SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY);
+
+ if (ind->noise_dbm != 0)
+ rwnx_survey->filled |= SURVEY_INFO_NOISE_DBM;
+
+ return 0;
+}
+
+static inline int rwnx_rx_p2p_noa_upd_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ return 0;
+}
+
+static inline int rwnx_rx_rssi_status_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mm_rssi_status_ind *ind = (struct mm_rssi_status_ind *)msg->param;
+ int vif_idx = ind->vif_index;
+ bool rssi_status = ind->rssi_status;
+
+ struct rwnx_vif *vif_entry;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+#ifdef CONFIG_RWNX_FULLMAC
+ vif_entry = rwnx_hw->vif_table[vif_idx];
+ if (vif_entry) {
+ cfg80211_cqm_rssi_notify(vif_entry->ndev,
+ rssi_status ? NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW
+ : NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+ ind->rssi, GFP_ATOMIC);
+ }
+#endif /* CONFIG_RWNX_FULLMAC */
+
+ return 0;
+}
+
+static inline int rwnx_rx_pktloss_notify_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+#ifdef CONFIG_RWNX_FULLMAC
+ struct mm_pktloss_ind *ind = (struct mm_pktloss_ind *)msg->param;
+ struct rwnx_vif *vif_entry;
+ int vif_idx = ind->vif_index;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ vif_entry = rwnx_hw->vif_table[vif_idx];
+ if (vif_entry) {
+ cfg80211_cqm_pktloss_notify(vif_entry->ndev,
+ (const u8 *)ind->mac_addr.array,
+ ind->num_packets, GFP_ATOMIC);
+ }
+#endif /* CONFIG_RWNX_FULLMAC */
+
+ return 0;
+}
+
+static inline int rwnx_apm_staloss_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mm_apm_staloss_ind *ind = (struct mm_apm_staloss_ind *)msg->param;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ memcpy(rwnx_hw->sta_mac_addr, ind->mac_addr, 6);
+ rwnx_hw->apm_vif_idx = ind->vif_idx;
+
+ queue_work(rwnx_hw->apm_staloss_wq, &rwnx_hw->apm_staloss_work);
+
+ return 0;
+}
+
+static struct sk_buff *arp_80211_to_8023(struct sk_buff *skb, u8 hdrlen)
+{
+ struct ethhdr *eth;
+ size_t payload_len;
+ struct sk_buff *new_skb = NULL;
+ char *llc;
+ u8 da[MAC_ADDR_LEN] = {0};
+ u8 sa[MAC_ADDR_LEN] = {0};
+
+ if (skb->len <= hdrlen) {
+ AICWFDBG(LOGERROR, "%s skb_len err1\n", __func__);
+ return NULL;
+ }
+
+ memcpy(da, &skb->data[4], 6);
+ memcpy(sa, &skb->data[16], 6);
+
+ skb_pull(skb, hdrlen);
+ llc = skb->data;
+ if (llc[0] == 0xAA && llc[1] == 0xAA && llc[2] == 0x03) {
+ if (skb->len < 8) {
+ AICWFDBG(LOGERROR, "%s skb_len err2\n", __func__);
+ return NULL;
+ }
+ skb_pull(skb, 8);
+ }
+ payload_len = skb->len;
+
+ new_skb = __dev_alloc_skb(ETH_HLEN + payload_len, GFP_ATOMIC);
+ if (!new_skb) {
+ AICWFDBG(LOGERROR, "%s skb alloc fail\n", __func__);
+ return NULL;
+ }
+
+ skb_reserve(new_skb, ETH_HLEN);
+ skb_put(new_skb, payload_len);
+ memcpy(new_skb->data, skb->data, payload_len);
+
+ eth = (struct ethhdr *)skb_push(new_skb, ETH_HLEN);
+
+ memcpy(eth->h_dest, da, ETH_ALEN);
+ memcpy(eth->h_source, sa, ETH_ALEN);
+
+ eth->h_proto = htons(ETH_P_ARP);
+
+ new_skb->protocol = eth->h_proto;
+ new_skb->dev = skb->dev;
+
+ return new_skb;
+}
+
+static inline int rwnx_arp_announcement_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct rwnx_vif *vif;
+ struct sk_buff *skb = NULL;
+ struct sk_buff *new_skb = NULL;
+ struct hw_rxhdr rxhdr;
+ int hdrlen = 24;
+ struct rxu_arp_announcement_ind *ind = (struct rxu_arp_announcement_ind *)msg->param;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ //AICWFDBG(LOGDEBUG, "vif: %d, length: %d, offset: %d\n",
+ // ind->vif_index, ind->length, ind->offset);
+
+ AICWFDBG(LOGDEBUG, "%s, vif: %d, length: %d, offset: %d\n",
+ __func__, ind->vif_index, ind->length, ind->offset);
+
+ vif = rwnx_hw->vif_table[ind->vif_index];
+ rxhdr.flags_is_amsdu = false;
+ rxhdr.flags_dst_idx = 0xff;
+
+ if (ind->payload[0] & 0x80)
+ hdrlen += 2;
+
+ switch ((ind->rx_status >> 2) & 0x7) {
+ case RWNX_RX_HD_DECR_CCMP128:
+ hdrlen += 8;
+ break;
+ case RWNX_RX_HD_DECR_TKIP:
+ hdrlen += 8;
+ break;
+ case RWNX_RX_HD_DECR_WEP:
+ hdrlen += 4;
+ break;
+ case RWNX_RX_HD_DECR_WAPI:
+ hdrlen += 18;
+ break;
+ default:
+ break;
+ }
+
+ skb = __dev_alloc_skb(ind->length, GFP_ATOMIC);
+ if (!skb) {
+ AICWFDBG(LOGERROR, "%s skb alloc fail\n", __func__);
+ return -1;
+ }
+ skb_put(skb, ind->length);
+ memcpy(skb->data, ind->payload, ind->length);
+ skb->dev = vif->ndev;
+
+ new_skb = arp_80211_to_8023(skb, hdrlen);
+ if (!new_skb) {
+ AICWFDBG(LOGERROR, "arp_80211_to_8023 fail\n");
+ dev_kfree_skb(skb);
+ return -1;
+ }
+ if (!rwnx_rx_data_skb(rwnx_hw, vif, new_skb, &rxhdr)) {
+ AICWFDBG(LOGERROR, "rwnx_rx_data_skb fail\n");
+ dev_kfree_skb(new_skb);
+ dev_kfree_skb(skb);
+ return -1;
+ }
+
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static inline int rwnx_rx_csa_counter_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mm_csa_counter_ind *ind = (struct mm_csa_counter_ind *)msg->param;
+ struct rwnx_vif *vif;
+ bool found = false;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ // Look for VIF entry
+ list_for_each_entry(vif, &rwnx_hw->vifs, list) {
+ if (vif->vif_index == ind->vif_index) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+#ifdef CONFIG_RWNX_FULLMAC
+ if (vif->ap.csa)
+ vif->ap.csa->count = ind->csa_count;
+ else
+ netdev_err(vif->ndev, "CSA counter update but no active CSA");
+
+#endif
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_RWNX_FULLMAC
+static inline int rwnx_rx_csa_finish_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mm_csa_finish_ind *ind = (struct mm_csa_finish_ind *)msg->param;
+ struct rwnx_vif *vif;
+ bool found = false;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ // Look for VIF entry
+ list_for_each_entry(vif, &rwnx_hw->vifs, list) {
+ if (vif->vif_index == ind->vif_index) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ if (RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_AP ||
+ RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_P2P_GO) {
+ if (vif->ap.csa) {
+ vif->ap.csa->status = ind->status;
+ vif->ap.csa->ch_idx = ind->chan_idx;
+ schedule_work(&vif->ap.csa->work);
+ } else {
+ netdev_err(vif->ndev,
+ "CSA finish indication but no active CSA");
+ }
+ } else {
+ if (ind->status == 0) {
+ rwnx_chanctx_unlink(vif);
+ rwnx_chanctx_link(vif, ind->chan_idx, NULL);
+ if (rwnx_hw->cur_chanctx == ind->chan_idx) {
+ rwnx_radar_detection_enable_on_cur_channel(rwnx_hw);
+ rwnx_txq_vif_start(vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
+ } else {
+ rwnx_txq_vif_stop(vif, RWNX_TXQ_STOP_CHAN, rwnx_hw);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static inline int rwnx_rx_csa_traffic_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mm_csa_traffic_ind *ind = (struct mm_csa_traffic_ind *)msg->param;
+ struct rwnx_vif *vif;
+ bool found = false;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ // Look for VIF entry
+ list_for_each_entry(vif, &rwnx_hw->vifs, list) {
+ if (vif->vif_index == ind->vif_index) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ if (ind->enable)
+ rwnx_txq_vif_start(vif, RWNX_TXQ_STOP_CSA, rwnx_hw);
+ else
+ rwnx_txq_vif_stop(vif, RWNX_TXQ_STOP_CSA, rwnx_hw);
+ }
+
+ return 0;
+}
+
+static inline int rwnx_rx_ps_change_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mm_ps_change_ind *ind = (struct mm_ps_change_ind *)msg->param;
+ struct rwnx_sta *sta = &rwnx_hw->sta_table[ind->sta_idx];
+
+ if (ind->sta_idx >= (NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX)) {
+ wiphy_err(rwnx_hw->wiphy, "Invalid sta index reported by fw %d\n",
+ ind->sta_idx);
+ return 1;
+ }
+
+ netdev_dbg(rwnx_hw->vif_table[sta->vif_idx]->ndev,
+ "Sta %d, change PS mode to %s", sta->sta_idx,
+ ind->ps_state ? "ON" : "OFF");
+
+ if (sta->valid) {
+ rwnx_ps_bh_enable(rwnx_hw, sta, ind->ps_state);
+ } else if (rwnx_hw->adding_sta) {
+ sta->ps.active = ind->ps_state ? true : false;
+ } else {
+ if (rwnx_hw->vif_table[sta->vif_idx] &&
+ rwnx_hw->vif_table[sta->vif_idx]->ndev)
+ netdev_err(rwnx_hw->vif_table[sta->vif_idx]->ndev,
+ "Ignore PS mode change on invalid sta\n");
+ }
+
+ return 0;
+}
+
+static inline int rwnx_rx_traffic_req_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mm_traffic_req_ind *ind = (struct mm_traffic_req_ind *)msg->param;
+ struct rwnx_sta *sta = &rwnx_hw->sta_table[ind->sta_idx];
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ netdev_dbg(rwnx_hw->vif_table[sta->vif_idx]->ndev,
+ "Sta %d, asked for %d pkt", sta->sta_idx, ind->pkt_cnt);
+
+ rwnx_ps_bh_traffic_req(rwnx_hw, sta, ind->pkt_cnt,
+ ind->uapsd ? UAPSD_ID : LEGACY_PS_ID);
+
+ return 0;
+}
+#endif /* CONFIG_RWNX_FULLMAC */
+
+/***************************************************************************
+ * Messages from SCANU task
+ **************************************************************************/
+#ifdef CONFIG_RWNX_FULLMAC
+
+static inline int rwnx_rx_scanu_start_cfm(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+#ifdef CONFIG_AIC8800_AUTO_CUSTREG
+ const struct ieee80211_regdomain *regdomain;
+#endif
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+#ifdef CONFIG_AIC8800_SCHED_SCAN
+ if (rwnx_hw->scan_request && !rwnx_hw->is_sched_scan)
+#endif // CONFIG_AIC8800_SCHED_SCAN
+ {
+ struct cfg80211_scan_info info = {
+ .aborted = false,
+ };
+
+ cfg80211_scan_done(rwnx_hw->scan_request, &info);
+ }
+
+#ifdef CONFIG_AIC8800_SCHED_SCAN
+ if (rwnx_hw->is_sched_scan) {
+ AICWFDBG(LOGINFO, "%s cfg80211_sched_scan_results \r\n", __func__);
+ cfg80211_sched_scan_results(rwnx_hw->scan_request->wiphy,
+ rwnx_hw->sched_scan_req->reqid);
+ kfree(rwnx_hw->scan_request);
+ rwnx_hw->is_sched_scan = false;
+ }
+#endif // CONFIG_AIC8800_SCHED_SCAN
+
+#ifdef CONFIG_AIC8800_AUTO_CUSTREG
+ if (rwnx_hw->ccode.auto_set && rwnx_hw->ccode.ccode_find) {
+#ifdef CONFIG_AIC8800_REGION_PW
+ schedule_work(&rwnx_hw->region_wk);
+#endif
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+ if (!work_pending(&rwnx_hw->pwlt_wk))
+ schedule_work(&rwnx_hw->pwlt_wk);
+#endif
+ regdomain = get_regdomain_from_rwnx_db(rwnx_hw->wiphy, rwnx_hw->country_abbr);
+ rwnx_regulatory_set_wiphy_regd(rwnx_hw->wiphy, regdomain);
+ rwnx_hw->ccode.ccode_cnt = 0;
+ rwnx_hw->ccode.ccode_find = false;
+ rwnx_hw->ccode.ccode_set = true;
+ }
+#endif
+
+ rwnx_hw->scan_request = NULL;
+ rwnx_hw->scanning = 0;
+ aicwf_sdio_scan_activity_put(rwnx_hw);
+
+ return 0;
+}
+
+#ifdef CONFIG_AIC8800_AUTO_CUSTREG
+static void parse_ssid_from_id(const u8 *ssid_id, char ssid_name[33], u8 *ssid_len)
+{
+ u8 len;
+
+ if (!ssid_id)
+ return;
+
+ len = *(ssid_id + 1);
+ if (len > 32)
+ len = 32;
+
+ strscpy(ssid_name, ssid_id + 2, len);
+ ssid_name[len] = '\0';
+ *ssid_len = len;
+
+ if (len > 0)
+ AICWFDBG(LOGDEBUG, "find_ccode ssid: %s\n", ssid_name);
+ else
+ AICWFDBG(LOGDEBUG, "find_ccode ssid is null\n");
+}
+
+static void rwnx_update_country(struct rwnx_hw *rwnx_hw,
+ const u8 *country_id,
+ const struct ieee80211_regdomain **regdomain)
+{
+ if (!country_id)
+ return;
+
+ if (memcmp(rwnx_hw->country_abbr, country_id + 2, 2) != 0) {
+ AICWFDBG(LOGINFO, "update ccode of the connected ap\n");
+
+ strscpy(rwnx_hw->country_abbr, country_id + 2, 2);
+
+ *regdomain = get_regdomain_from_rwnx_db(rwnx_hw->wiphy, rwnx_hw->country_abbr);
+
+#ifdef CONFIG_AIC8800_REGION_PW
+ schedule_work(&rwnx_hw->region_wk);
+#endif
+
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+ if (!work_pending(&rwnx_hw->pwlt_wk))
+ schedule_work(&rwnx_hw->pwlt_wk);
+#endif
+
+ rwnx_regulatory_set_wiphy_regd(rwnx_hw->wiphy, *regdomain);
+ }
+}
+#endif
+
+static inline int rwnx_rx_scanu_result_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct cfg80211_bss *bss = NULL;
+ struct ieee80211_channel *chan;
+ struct scanu_result_ind *ind = (struct scanu_result_ind *)msg->param;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)ind->payload;
+ u64 tsf;
+
+#ifdef CONFIG_AIC8800_AUTO_CUSTREG
+ const u8 *country_id;
+ const u8 *ssid_id;
+ char ssid_name[33];
+ u8 ssid_len;
+ const struct ieee80211_regdomain *regdomain;
+#endif
+
+
+ // RWNX_DBG(RWNX_FN_ENTRY_STR); //debug trace
+
+ chan = ieee80211_get_channel(rwnx_hw->wiphy, ind->center_freq);
+
+ if (chan) {
+ struct timespec64 ts;
+
+ ts = ktime_to_timespec64(ktime_get_boottime());
+ tsf = (u64)ts.tv_sec * 1000000 + div_u64(ts.tv_nsec, 1000);
+ mgmt->u.probe_resp.timestamp = cpu_to_le64(tsf);
+
+#ifdef CONFIG_AIC8800_AUTO_CUSTREG
+ if (rwnx_hw->ccode.auto_set && !rwnx_hw->ccode.ccode_set &&
+ rwnx_hw->ccode.ccode_cnt < MAX_SEARCH_CNT) {
+ country_id =
+ cfg80211_find_ie(WLAN_EID_COUNTRY, mgmt->u.beacon.variable,
+ ind->length - offsetof(struct ieee80211_mgmt,
+ u.beacon.variable));
+ if (country_id) {
+ if (ind->rssi > rwnx_hw->ccode.ccode_rssi) {
+ rwnx_hw->ccode.ccode_rssi = ind->rssi;
+ // AICWFDBG(LOGINFO, "find_ccode, bssid: %pM\n",
+ // mgmt->bssid); //debug trace
+ if (!rwnx_hw->ccode.ccode_find)
+ rwnx_hw->ccode.ccode_find = true;
+ strscpy(rwnx_hw->country_abbr, country_id + 2, 2);
+ ssid_id =
+ cfg80211_find_ie(WLAN_EID_SSID, mgmt->u.beacon.variable,
+ ind->length -
+ offsetof(struct ieee80211_mgmt,
+ u.beacon.variable));
+ parse_ssid_from_id(ssid_id, ssid_name, &ssid_len);
+ }
+ }
+ rwnx_hw->ccode.ccode_cnt += 1;
+ AICWFDBG(LOGDEBUG, "find cnt: %d\n",
+ rwnx_hw->ccode.ccode_cnt); // debug trace
+ } else if (rwnx_hw->ccode.auto_set && !rwnx_hw->ccode.ccode_find &&
+ !rwnx_hw->ccode.ccode_set &&
+ rwnx_hw->ccode.ccode_cnt >= MAX_SEARCH_CNT) {
+ AICWFDBG(LOGINFO, "find cnt over !!!\n");
+ strscpy(rwnx_hw->country_abbr, "XX", 2);
+ rwnx_hw->ccode.ccode_find = true;
+ }
+
+ if (rwnx_hw->ccode.auto_set &&
+ atomic_read(&rwnx_hw->ccode.link_scan) == 1) {
+ if (memcmp(&rwnx_hw->ccode.bssid, mgmt->bssid, ETH_ALEN) == 0) {
+ country_id =
+ cfg80211_find_ie(WLAN_EID_COUNTRY,
+ mgmt->u.probe_resp.variable,
+ ind->length - offsetof(struct ieee80211_mgmt,
+ u.probe_resp.variable));
+ rwnx_update_country(rwnx_hw, country_id, ®domain);
+ memset(&rwnx_hw->ccode.bssid, 0, sizeof(rwnx_hw->ccode.bssid));
+ }
+ atomic_set(&rwnx_hw->ccode.link_scan, 0);
+ rwnx_hw->ccode.ccode_cnt = 0;
+ }
+#endif
+ bss =
+ cfg80211_inform_bss_frame(rwnx_hw->wiphy, chan,
+ (struct ieee80211_mgmt *)ind->payload,
+ ind->length, ind->rssi * 100, GFP_ATOMIC);
+
+ }
+ if (bss)
+ cfg80211_put_bss(rwnx_hw->wiphy, bss);
+ return 0;
+}
+#endif /* CONFIG_RWNX_FULLMAC */
+
+/***************************************************************************
+ * Messages from ME task
+ **************************************************************************/
+#ifdef CONFIG_RWNX_FULLMAC
+static inline int rwnx_rx_me_tkip_mic_failure_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct me_tkip_mic_failure_ind *ind =
+ (struct me_tkip_mic_failure_ind *)msg->param;
+ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
+ struct net_device *dev = rwnx_vif->ndev;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ cfg80211_michael_mic_failure(dev, (u8 *)&ind->addr,
+ (ind->ga ? NL80211_KEYTYPE_GROUP : NL80211_KEYTYPE_PAIRWISE),
+ ind->keyid, (u8 *)&ind->tsc, GFP_ATOMIC);
+
+ return 0;
+}
+
+static inline int rwnx_rx_me_tx_credits_update_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct me_tx_credits_update_ind *ind =
+ (struct me_tx_credits_update_ind *)msg->param;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ rwnx_txq_credit_update(rwnx_hw, ind->sta_idx, ind->tid, ind->credits);
+
+ return 0;
+}
+#endif /* CONFIG_RWNX_FULLMAC */
+
+/***************************************************************************
+ * Messages from SM task
+ **************************************************************************/
+#ifdef CONFIG_RWNX_FULLMAC
+static inline int rwnx_rx_sm_connect_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct sm_connect_ind *ind = (struct sm_connect_ind *)msg->param;
+ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
+ struct net_device *dev = rwnx_vif->ndev;
+ const u8 *req_ie, *rsp_ie;
+ const u8 *extcap_ie;
+ const struct ieee_types_extcap *extcap;
+ struct ieee80211_channel *chan;
+ const u8 *ht_ie = NULL;
+ const u8 *vht_ie = NULL;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Retrieve IE addresses and lengths */
+ req_ie = (const u8 *)ind->assoc_ie_buf;
+ rsp_ie = req_ie + ind->assoc_req_ie_len;
+
+ // Fill-in the AP information
+ AICWFDBG(LOGINFO, "%s ind->status_code:%d \r\n", __func__,
+ ind->status_code);
+
+ if (ind->status_code == 0) {
+ struct rwnx_sta *sta = &rwnx_hw->sta_table[ind->ap_idx];
+ u8 txq_status;
+ struct cfg80211_chan_def chandef;
+
+ sta->valid = true;
+ sta->sta_idx = ind->ap_idx;
+ sta->ch_idx = ind->ch_idx;
+ sta->vif_idx = ind->vif_idx;
+ sta->vlan_idx = sta->vif_idx;
+ sta->qos = ind->qos;
+ sta->acm = ind->acm;
+ sta->ps.active = false;
+ sta->aid = ind->aid;
+ sta->band = ind->band; // ind->chan.band;
+ sta->width = ind->width; // ind->chan.type;
+ sta->center_freq = ind->center_freq; // ind->chan.prim20_freq;
+ sta->center_freq1 = ind->center_freq1; // ind->chan.center1_freq;
+ sta->center_freq2 = ind->center_freq2; // ind->chan.center2_freq;
+ rwnx_vif->sta.ap = sta;
+ // ind->chan.prim20_freq);
+ chan = ieee80211_get_channel(rwnx_hw->wiphy, ind->center_freq);
+ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+ if (!rwnx_hw->mod_params->ht_on)
+ chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
+ else
+ chandef.width = chnl2bw[ind->width]; //[ind->chan.type];
+ chandef.center_freq1 = ind->center_freq1; // ind->chan.center1_freq;
+ chandef.center_freq2 = ind->center_freq2; // ind->chan.center2_freq;
+ rwnx_chanctx_link(rwnx_vif, ind->ch_idx, &chandef);
+ memcpy(sta->mac_addr, ind->bssid.array, ETH_ALEN);
+ if (ind->ch_idx == rwnx_hw->cur_chanctx)
+ txq_status = 0;
+ else
+ txq_status = RWNX_TXQ_STOP_CHAN;
+ memcpy(sta->ac_param, ind->ac_param, sizeof(sta->ac_param));
+ rwnx_txq_sta_init(rwnx_hw, sta, txq_status);
+ rwnx_txq_tdls_vif_init(rwnx_vif);
+ rwnx_mu_group_sta_init(sta, NULL);
+ /* Look for TDLS Channel Switch Prohibited flag in the Extended
+ * Capability Information Element
+ */
+ extcap_ie = cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY, rsp_ie,
+ ind->assoc_rsp_ie_len);
+ if (extcap_ie && extcap_ie[1] >= 5) {
+ extcap = (void *)(extcap_ie);
+ rwnx_vif->tdls_chsw_prohibited =
+ extcap->ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED;
+ }
+
+ if (rwnx_vif->wep_enabled)
+ rwnx_vif->wep_auth_err = false;
+
+#ifdef CONFIG_RWNX_BFMER
+ /* If Beamformer feature is activated, check if features can be used
+ * with the new peer device
+ */
+ if (rwnx_hw->mod_params->bfmer) {
+ const u8 *vht_capa_ie;
+ const struct ieee80211_vht_cap *vht_cap;
+
+ do {
+ /* Look for VHT Capability Information Element */
+ vht_capa_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, rsp_ie,
+ ind->assoc_rsp_ie_len);
+
+ /* Stop here if peer device does not support VHT */
+ if (!vht_capa_ie)
+ break;
+
+ vht_cap = (const struct ieee80211_vht_cap *)(vht_capa_ie + 2);
+
+ /* Send MM_BFMER_ENABLE_REQ message if needed */
+ rwnx_send_bfmer_enable(rwnx_hw, sta, vht_cap);
+ } while (0);
+ }
+#endif //(CONFIG_RWNX_BFMER)
+
+ ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, rsp_ie,
+ ind->assoc_rsp_ie_len);
+ if (ht_ie)
+ rwnx_vif->sta.ap->ht = true;
+ vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, rsp_ie,
+ ind->assoc_rsp_ie_len);
+ if (vht_ie)
+ rwnx_vif->sta.ap->vht = true;
+
+#ifdef CONFIG_RWNX_MON_DATA
+ // If there are 1 sta and 1 monitor interface active at the same time
+ // then monitor interface channel context is always the same as the STA
+ // interface. This doesn't work with 2 STA interfaces but we don't want
+ // to support it.
+ if (rwnx_hw->monitor_vif != RWNX_INVALID_VIF) {
+ struct rwnx_vif *rwnx_mon_vif =
+ rwnx_hw->vif_table[rwnx_hw->monitor_vif];
+ rwnx_chanctx_unlink(rwnx_mon_vif);
+ rwnx_chanctx_link(rwnx_mon_vif, ind->ch_idx, NULL);
+ }
+#endif
+ // atomic_set(&rwnx_vif->drv_conn_state,
+ // (int)RWNX_DRV_STATUS_CONNECTED);
+ } else if (ind->status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
+ if (rwnx_vif->wep_enabled) {
+ rwnx_vif->wep_auth_err = true;
+ AICWFDBG(LOGINFO, "con ind wep_auth_err %d\n",
+ rwnx_vif->wep_auth_err);
+ }
+ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
+ } else {
+ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
+ }
+
+ AICWFDBG(LOGINFO,
+ "%s ind->roamed:%d ind->status_code:%d rwnx_vif->drv_conn_state:%d\r\n",
+ __func__, ind->roamed, ind->status_code,
+ (int)atomic_read(&rwnx_vif->drv_conn_state));
+
+ if (ind->status_code == 0 &&
+ (int)atomic_read(&rwnx_vif->drv_conn_state) == RWNX_DRV_STATUS_DISCONNECTING) {
+ AICWFDBG(LOGINFO, "%s the disconnection has been requested, return it\r\n",
+ __func__);
+ goto exit;
+ }
+
+ if (!ind->roamed) { // not roaming
+ cfg80211_connect_result(dev, (const u8 *)ind->bssid.array,
+ req_ie, ind->assoc_req_ie_len,
+ rsp_ie, ind->assoc_rsp_ie_len, ind->status_code,
+ GFP_ATOMIC);
+ if (ind->status_code == 0) {
+ rwnx_set_conn_state(&rwnx_vif->drv_conn_state,
+ (int)RWNX_DRV_STATUS_CONNECTED);
+ AICWFDBG(LOGINFO,
+ "%s cfg80211_connect_result pass, rwnx_vif->drv_conn_state:%d\r\n",
+ __func__, (int)atomic_read(&rwnx_vif->drv_conn_state));
+ rwnx_vif->sta.link_time = jiffies;
+ } else {
+ rwnx_set_conn_state(&rwnx_vif->drv_conn_state,
+ (int)RWNX_DRV_STATUS_DISCONNECTED);
+ rwnx_external_auth_disable(rwnx_vif);
+ }
+ } else { // roaming
+ if (ind->status_code != 0) {
+ AICWFDBG(LOGINFO, "%s roaming fail to notify disconnect \r\n",
+ __func__);
+ cfg80211_disconnected(dev, 0, NULL, 0, 1, GFP_ATOMIC);
+ rwnx_set_conn_state(&rwnx_vif->drv_conn_state,
+ (int)RWNX_DRV_STATUS_DISCONNECTED);
+ rwnx_external_auth_disable(rwnx_vif);
+ } else {
+ struct cfg80211_roam_info info;
+
+ memset(&info, 0, sizeof(info));
+ if (rwnx_vif->ch_index < NX_CHAN_CTXT_CNT)
+ info.links[0].channel =
+ rwnx_hw->chanctx_table[rwnx_vif->ch_index].chan_def.chan;
+ info.links[0].bssid = (const u8 *)ind->bssid.array;
+ info.req_ie = req_ie;
+ info.req_ie_len = ind->assoc_req_ie_len;
+ info.resp_ie = rsp_ie;
+ info.resp_ie_len = ind->assoc_rsp_ie_len;
+ cfg80211_roamed(dev, &info, GFP_ATOMIC);
+ rwnx_vif->sta.link_time = jiffies;
+
+ rwnx_set_conn_state(&rwnx_vif->drv_conn_state,
+ (int)RWNX_DRV_STATUS_CONNECTED);
+ rwnx_vif->sta.link_time = jiffies;
+ }
+ rwnx_vif->sta.is_roam = false;
+ }
+
+ if (ind->status_code == 0) {
+ netif_tx_start_all_queues(dev);
+ netif_carrier_on(dev);
+ }
+
+exit:
+ rwnx_vif->sta.is_roam = false;
+ return 0;
+}
+
+void rwnx_cfg80211_unlink_bss(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif)
+{
+ struct wiphy *wiphy = rwnx_hw->wiphy;
+ struct cfg80211_bss *bss = NULL;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ bss = cfg80211_get_bss(wiphy, NULL /*notify_channel */, rwnx_vif->sta.bssid,
+ rwnx_vif->sta.ssid, rwnx_vif->sta.ssid_len,
+ IEEE80211_BSS_TYPE_ESS,
+ IEEE80211_PRIVACY(true)); // temp set true
+ if (bss) {
+ cfg80211_unlink_bss(wiphy, bss);
+ AICWFDBG(LOGINFO, "%s(): cfg80211_unlink %s!!\n", __func__,
+ rwnx_vif->sta.ssid);
+ cfg80211_put_bss(wiphy, bss);
+ } else {
+ AICWFDBG(LOGINFO, "%s(): cfg80211_unlink error %s!!\n", __func__,
+ rwnx_vif->sta.ssid);
+ }
+}
+
+static inline int rwnx_rx_sm_disconnect_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct sm_disconnect_ind *ind = (struct sm_disconnect_ind *)msg->param;
+ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
+ struct net_device *dev;
+#ifdef AICWF_RX_REORDER
+ struct reord_ctrl_info *reord_info, *tmp;
+ u8 *macaddr;
+ struct aicwf_rx_priv *rx_priv;
+#endif
+
+ AICWFDBG(LOGINFO, "%s reason code:%d \r\n", __func__, ind->reason_code);
+
+ if (!rwnx_vif)
+ return 0;
+
+ if ((int)atomic_read(&rwnx_vif->drv_conn_state) ==
+ (int)RWNX_DRV_STATUS_DISCONNECTED) {
+ AICWFDBG(LOGINFO, "%s, is already disconnected, drop disconnect ind",
+ __func__);
+ return 0;
+ }
+
+ dev = rwnx_vif->ndev;
+
+ if (!rwnx_vif->sta.is_roam)
+ rwnx_cfg80211_unlink_bss(rwnx_hw, rwnx_vif);
+ else
+ AICWFDBG(LOGINFO, "%s roaming no rwnx_cfg80211_unlink_bss \r\n",
+ __func__);
+ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)
+ rwnx_hw->is_p2p_connected = 0;
+ /* if vif is not up, rwnx_close has already been called */
+ if (rwnx_vif->up) {
+ if (!ind->ft_over_ds && !ind->reassoc) {
+ cfg80211_disconnected(dev, ind->reason_code, NULL, 0,
+ (ind->reason_code < 1), GFP_ATOMIC);
+ }
+ netif_tx_stop_all_queues(dev);
+ netif_carrier_off(dev);
+ }
+
+#ifdef CONFIG_RWNX_BFMER
+ /* Disable Beamformer if supported */
+ rwnx_bfmer_report_del(rwnx_hw, rwnx_vif->sta.ap);
+#endif //(CONFIG_RWNX_BFMER)
+
+#ifdef AICWF_RX_REORDER
+#ifdef AICWF_SDIO_SUPPORT
+ rx_priv = rwnx_hw->sdiodev->rx_priv;
+#else
+ rx_priv = rwnx_hw->usbdev->rx_priv;
+#endif
+ if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION ||
+ rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
+ macaddr = (u8 *)rwnx_vif->ndev->dev_addr;
+ AICWFDBG(LOGDEBUG, "deinit:macaddr:%x,%x,%x,%x,%x,%x\r\n", macaddr[0], macaddr[1],
+ macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
+
+ // spin_lock_bh(&rx_priv->stas_reord_lock);
+ list_for_each_entry_safe(reord_info, tmp, &rx_priv->stas_reord_list,
+ list) {
+ macaddr = (u8 *)rwnx_vif->ndev->dev_addr;
+ AICWFDBG(LOGDEBUG, "reord_mac:%x,%x,%x,%x,%x,%x\r\n",
+ reord_info->mac_addr[0], reord_info->mac_addr[1],
+ reord_info->mac_addr[2], reord_info->mac_addr[3],
+ reord_info->mac_addr[4], reord_info->mac_addr[5]);
+ if (!memcmp(reord_info->mac_addr, macaddr, 6)) {
+ reord_deinit_sta(rx_priv, reord_info);
+ break;
+ }
+ }
+ // spin_unlock_bh(&rx_priv->stas_reord_lock);
+ } else if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP ||
+ rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
+ // WARN_ON_ONCE(); // should be not here: del_sta function
+ }
+#endif
+
+ rwnx_txq_sta_deinit(rwnx_hw, rwnx_vif->sta.ap);
+ rwnx_txq_tdls_vif_deinit(rwnx_vif);
+ rwnx_vif->sta.ap->valid = false;
+ rwnx_vif->sta.ap = NULL;
+ rwnx_external_auth_disable(rwnx_vif);
+ rwnx_chanctx_unlink(rwnx_vif);
+
+ // msleep(200);
+ if (!rwnx_vif->sta.is_roam)
+ rwnx_set_conn_state(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
+
+ return 0;
+}
+
+static inline int rwnx_rx_sm_external_auth_required_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct sm_external_auth_required_ind *ind =
+ (struct sm_external_auth_required_ind *)msg->param;
+ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
+ struct net_device *dev = rwnx_vif->ndev;
+ struct cfg80211_external_auth_params params;
+ int ret = 0;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int retry_counter = 10;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ params.action = NL80211_EXTERNAL_AUTH_START;
+ memcpy(params.bssid, ind->bssid.array, ETH_ALEN);
+ params.ssid.ssid_len = ind->ssid.length;
+ memcpy(params.ssid.ssid, ind->ssid.array,
+ min_t(size_t, ind->ssid.length, sizeof(params.ssid.ssid)));
+ params.key_mgmt_suite = ind->akm;
+
+ while (wdev->conn_owner_nlportid == 0) {
+ AICWFDBG(LOGINFO,
+ "%s WARNING conn_owner_nlportid = 0, msleep 100ms.\r\n",
+ __func__);
+ msleep(100);
+ retry_counter--;
+ if (retry_counter == 0)
+ break;
+ }
+ AICWFDBG(LOGINFO, "%s wdev->conn_owner_nlportid:%d \r\n", __func__,
+ (int)wdev->conn_owner_nlportid);
+ ret = cfg80211_external_auth_request(dev, ¶ms, GFP_ATOMIC);
+ if (ind->vif_idx > NX_VIRT_DEV_MAX || !rwnx_vif->up ||
+ RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_STATION ||
+ ret) {
+ wiphy_err(rwnx_hw->wiphy,
+ "Failed to start external auth on vif %d, rwnx_vif->up %d, iftype:%d, ret %d",
+ ind->vif_idx, rwnx_vif->up, RWNX_VIF_TYPE(rwnx_vif), ret);
+ rwnx_send_sm_external_auth_required_rsp(rwnx_hw, rwnx_vif,
+ WLAN_STATUS_UNSPECIFIED_FAILURE);
+ return 0;
+ }
+
+ rwnx_external_auth_enable(rwnx_vif);
+ return 0;
+}
+
+static inline int rwnx_rx_mesh_path_create_cfm(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mesh_path_create_cfm *cfm =
+ (struct mesh_path_create_cfm *)msg->param;
+ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[cfm->vif_idx];
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Check we well have a Mesh Point Interface */
+ if (rwnx_vif && RWNX_VIF_TYPE(rwnx_vif) == NL80211_IFTYPE_MESH_POINT)
+ rwnx_vif->ap.create_path = false;
+
+ return 0;
+}
+
+static inline int rwnx_rx_mesh_peer_update_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mesh_peer_update_ind *ind =
+ (struct mesh_peer_update_ind *)msg->param;
+ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
+ struct rwnx_sta *rwnx_sta = &rwnx_hw->sta_table[ind->sta_idx];
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ if (ind->vif_idx >= (NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX) ||
+ (rwnx_vif && RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT) ||
+ ind->sta_idx >= NX_REMOTE_STA_MAX)
+ return 1;
+
+ /* Check we well have a Mesh Point Interface */
+ if (!rwnx_vif->user_mpm) {
+ /* Check if peer link has been established or lost */
+ if (ind->estab) {
+ if (!rwnx_sta->valid) {
+ u8 txq_status;
+
+ rwnx_sta->valid = true;
+ rwnx_sta->sta_idx = ind->sta_idx;
+ rwnx_sta->ch_idx = rwnx_vif->ch_index;
+ rwnx_sta->vif_idx = ind->vif_idx;
+ rwnx_sta->vlan_idx = rwnx_sta->vif_idx;
+ rwnx_sta->ps.active = false;
+ rwnx_sta->qos = true;
+ rwnx_sta->aid = ind->sta_idx + 1;
+ // rwnx_sta->acm = ind->acm;
+ memcpy(rwnx_sta->mac_addr, ind->peer_addr.array, ETH_ALEN);
+
+ rwnx_chanctx_link(rwnx_vif, rwnx_sta->ch_idx, NULL);
+
+ /* Add the station in the list of VIF's stations */
+ INIT_LIST_HEAD(&rwnx_sta->list);
+ list_add_tail(&rwnx_sta->list, &rwnx_vif->ap.sta_list);
+
+ /* Initialize the TX queues */
+ if (rwnx_sta->ch_idx == rwnx_hw->cur_chanctx)
+ txq_status = 0;
+ else
+ txq_status = RWNX_TXQ_STOP_CHAN;
+
+ rwnx_txq_sta_init(rwnx_hw, rwnx_sta, txq_status);
+#ifdef CONFIG_RWNX_BFMER
+ // TODO: update indication to contains vht capabilities
+ if (rwnx_hw->mod_params->bfmer)
+ rwnx_send_bfmer_enable(rwnx_hw, rwnx_sta, NULL);
+
+ rwnx_mu_group_sta_init(rwnx_sta, NULL);
+#endif /* CONFIG_RWNX_BFMER */
+
+ } else {
+ WARN_ON(0);
+ }
+ } else {
+ if (rwnx_sta->valid) {
+ rwnx_sta->ps.active = false;
+ rwnx_sta->valid = false;
+
+ /* Remove the station from the list of VIF's station */
+ list_del_init(&rwnx_sta->list);
+
+ rwnx_txq_sta_deinit(rwnx_hw, rwnx_sta);
+ } else {
+ WARN_ON(0);
+ }
+ }
+ } else {
+ if (!ind->estab && rwnx_sta->valid) {
+ /* There is no way to inform upper layer for lost of peer, still
+ * clean everything in the driver
+ */
+ rwnx_sta->ps.active = false;
+ rwnx_sta->valid = false;
+
+ /* Remove the station from the list of VIF's station */
+ list_del_init(&rwnx_sta->list);
+
+ rwnx_txq_sta_deinit(rwnx_hw, rwnx_sta);
+ } else {
+ WARN_ON(0);
+ }
+ }
+
+ return 0;
+}
+
+static inline int rwnx_rx_mesh_path_update_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mesh_path_update_ind *ind =
+ (struct mesh_path_update_ind *)msg->param;
+ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
+ struct rwnx_mesh_path *mesh_path;
+ bool found = false;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ if (ind->vif_idx >= (NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX))
+ return 1;
+
+ if (!rwnx_vif || (RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT))
+ return 0;
+
+ /* Look for path with provided target address */
+ list_for_each_entry(mesh_path, &rwnx_vif->ap.mpath_list, list) {
+ if (mesh_path->path_idx == ind->path_idx) {
+ found = true;
+ break;
+ }
+ }
+
+ /* Check if element has been deleted */
+ if (ind->delete) {
+ if (found) {
+#ifdef AIC8800_CREATE_TRACE_POINTS
+ trace_mesh_delete_path(mesh_path);
+#endif
+ /* Remove element from list */
+ list_del_init(&mesh_path->list);
+ /* Free the element */
+ kfree(mesh_path);
+ }
+ } else {
+ if (found) {
+ // Update the Next Hop STA
+ mesh_path->p_nhop_sta = &rwnx_hw->sta_table[ind->nhop_sta_idx];
+#ifdef AIC8800_CREATE_TRACE_POINTS
+ trace_mesh_update_path(mesh_path);
+#endif
+ } else {
+ // Allocate a Mesh Path structure
+ mesh_path =
+ kmalloc_obj(struct rwnx_mesh_path, GFP_ATOMIC);
+
+ if (mesh_path) {
+ INIT_LIST_HEAD(&mesh_path->list);
+
+ mesh_path->path_idx = ind->path_idx;
+ mesh_path->p_nhop_sta = &rwnx_hw->sta_table[ind->nhop_sta_idx];
+ memcpy(&mesh_path->tgt_mac_addr, &ind->tgt_mac_addr,
+ MAC_ADDR_LEN);
+
+ // Insert the path in the list of path
+ list_add_tail(&mesh_path->list, &rwnx_vif->ap.mpath_list);
+#ifdef AIC8800_CREATE_TRACE_POINTS
+ trace_mesh_create_path(mesh_path);
+#endif
+ }
+ }
+ }
+
+ return 0;
+}
+
+static inline int rwnx_rx_mesh_proxy_update_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ struct mesh_proxy_update_ind *ind =
+ (struct mesh_proxy_update_ind *)msg->param;
+ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[ind->vif_idx];
+ struct rwnx_mesh_proxy *mesh_proxy;
+ bool found = false;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ if (ind->vif_idx >= (NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX))
+ return 1;
+
+ if (!rwnx_vif || RWNX_VIF_TYPE(rwnx_vif) != NL80211_IFTYPE_MESH_POINT)
+ return 0;
+
+ /* Look for path with provided external STA address */
+ list_for_each_entry(mesh_proxy, &rwnx_vif->ap.proxy_list, list) {
+ if (!memcmp(&ind->ext_sta_addr, &mesh_proxy->ext_sta_addr, ETH_ALEN)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (ind->delete && found) {
+ /* Delete mesh path */
+ list_del_init(&mesh_proxy->list);
+ kfree(mesh_proxy);
+ } else if (!ind->delete && !found) {
+ /* Allocate a Mesh Path structure */
+ mesh_proxy =
+ kmalloc_obj(*mesh_proxy, GFP_ATOMIC);
+
+ if (mesh_proxy) {
+ INIT_LIST_HEAD(&mesh_proxy->list);
+
+ memcpy(&mesh_proxy->ext_sta_addr, &ind->ext_sta_addr, MAC_ADDR_LEN);
+ mesh_proxy->local = ind->local;
+
+ if (!ind->local)
+ memcpy(&mesh_proxy->proxy_addr, &ind->proxy_mac_addr,
+ MAC_ADDR_LEN);
+
+ /* Insert the path in the list of path */
+ list_add_tail(&mesh_proxy->list, &rwnx_vif->ap.proxy_list);
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_RWNX_FULLMAC */
+
+/***************************************************************************
+ * Messages from DEBUG task
+ **************************************************************************/
+static inline int rwnx_rx_dbg_error_ind(struct rwnx_hw *rwnx_hw,
+ struct rwnx_cmd *cmd,
+ struct ipc_e2a_msg *msg)
+{
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ return 0;
+}
+
+#ifdef CONFIG_RWNX_FULLMAC
+
+static msg_cb_fct mm_hdlrs[MSG_I(MM_MAX)] = {
+ [MSG_I(MM_CHANNEL_SWITCH_IND)] = rwnx_rx_chan_switch_ind,
+ [MSG_I(MM_CHANNEL_PRE_SWITCH_IND)] = rwnx_rx_chan_pre_switch_ind,
+ [MSG_I(MM_REMAIN_ON_CHANNEL_EXP_IND)] = rwnx_rx_remain_on_channel_exp_ind,
+ [MSG_I(MM_PS_CHANGE_IND)] = rwnx_rx_ps_change_ind,
+ [MSG_I(MM_TRAFFIC_REQ_IND)] = rwnx_rx_traffic_req_ind,
+ [MSG_I(MM_P2P_VIF_PS_CHANGE_IND)] = rwnx_rx_p2p_vif_ps_change_ind,
+ [MSG_I(MM_CSA_COUNTER_IND)] = rwnx_rx_csa_counter_ind,
+ [MSG_I(MM_CSA_FINISH_IND)] = rwnx_rx_csa_finish_ind,
+ [MSG_I(MM_CSA_TRAFFIC_IND)] = rwnx_rx_csa_traffic_ind,
+ [MSG_I(MM_CHANNEL_SURVEY_IND)] = rwnx_rx_channel_survey_ind,
+ [MSG_I(MM_P2P_NOA_UPD_IND)] = rwnx_rx_p2p_noa_upd_ind,
+ [MSG_I(MM_RSSI_STATUS_IND)] = rwnx_rx_rssi_status_ind,
+ [MSG_I(MM_PKTLOSS_IND)] = rwnx_rx_pktloss_notify_ind,
+ [MSG_I(MM_APM_STALOSS_IND)] = rwnx_apm_staloss_ind,
+ [MSG_I(MM_ARP_ANNOUNCEMENT_IND)] = rwnx_arp_announcement_ind,
+};
+
+static msg_cb_fct scan_hdlrs[MSG_I(SCANU_MAX)] = {
+ [MSG_I(SCANU_START_CFM)] = rwnx_rx_scanu_start_cfm,
+ [MSG_I(SCANU_RESULT_IND)] = rwnx_rx_scanu_result_ind,
+};
+
+static msg_cb_fct me_hdlrs[MSG_I(ME_MAX)] = {
+ [MSG_I(ME_TKIP_MIC_FAILURE_IND)] = rwnx_rx_me_tkip_mic_failure_ind,
+ [MSG_I(ME_TX_CREDITS_UPDATE_IND)] = rwnx_rx_me_tx_credits_update_ind,
+};
+
+static msg_cb_fct sm_hdlrs[MSG_I(SM_MAX)] = {
+ [MSG_I(SM_CONNECT_IND)] = rwnx_rx_sm_connect_ind,
+ [MSG_I(SM_DISCONNECT_IND)] = rwnx_rx_sm_disconnect_ind,
+ [MSG_I(SM_EXTERNAL_AUTH_REQUIRED_IND)] =
+ rwnx_rx_sm_external_auth_required_ind,
+};
+
+static msg_cb_fct apm_hdlrs[MSG_I(APM_MAX)] = {};
+
+static msg_cb_fct mesh_hdlrs[MSG_I(MESH_MAX)] = {
+ [MSG_I(MESH_PATH_CREATE_CFM)] = rwnx_rx_mesh_path_create_cfm,
+ [MSG_I(MESH_PEER_UPDATE_IND)] = rwnx_rx_mesh_peer_update_ind,
+ [MSG_I(MESH_PATH_UPDATE_IND)] = rwnx_rx_mesh_path_update_ind,
+ [MSG_I(MESH_PROXY_UPDATE_IND)] = rwnx_rx_mesh_proxy_update_ind,
+};
+
+#endif /* CONFIG_RWNX_FULLMAC */
+
+static msg_cb_fct dbg_hdlrs[MSG_I(DBG_MAX)] = {
+ [MSG_I(DBG_ERROR_IND)] = rwnx_rx_dbg_error_ind,
+};
+
+static msg_cb_fct tdls_hdlrs[MSG_I(TDLS_MAX)] = {
+ [MSG_I(TDLS_CHAN_SWITCH_CFM)] = rwnx_rx_tdls_chan_switch_cfm,
+ [MSG_I(TDLS_CHAN_SWITCH_IND)] = rwnx_rx_tdls_chan_switch_ind,
+ [MSG_I(TDLS_CHAN_SWITCH_BASE_IND)] = rwnx_rx_tdls_chan_switch_base_ind,
+ [MSG_I(TDLS_PEER_PS_IND)] = rwnx_rx_tdls_peer_ps_ind,
+};
+
+static msg_cb_fct *msg_hdlrs[] = {
+ [TASK_MM] = mm_hdlrs, [TASK_DBG] = dbg_hdlrs,
+#ifdef CONFIG_RWNX_FULLMAC
+ [TASK_TDLS] = tdls_hdlrs, [TASK_SCANU] = scan_hdlrs,
+ [TASK_ME] = me_hdlrs, [TASK_SM] = sm_hdlrs,
+ [TASK_APM] = apm_hdlrs, [TASK_MESH] = mesh_hdlrs,
+#endif /* CONFIG_RWNX_FULLMAC */
+};
+
+/*
+ *
+ */
+void rwnx_rx_handle_msg(struct rwnx_hw *rwnx_hw, struct ipc_e2a_msg *msg)
+{
+ // AICWFDBG(LOGDEBUG, "%s msg->id:0x%x \r\n", __func__, msg->id);
+
+ rwnx_hw->cmd_mgr->msgind(rwnx_hw->cmd_mgr, msg,
+ msg_hdlrs[MSG_T(msg->id)][MSG_I(msg->id)]);
+}
+
+void rwnx_rx_handle_print(struct rwnx_hw *rwnx_hw, u8 *msg, u32 len)
+{
+ (void)len;
+
+ if (!rwnx_hw || !rwnx_hw->fwlog_en) {
+ pr_err("FWLOG-OVFL: %s", msg);
+ return;
+ }
+
+ AICWFDBG(LOGDEBUG, "FWLOG: %s", msg);
+}
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_rx.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_rx.h
new file mode 100644
index 0000000000000..211f2e616cbf4
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_rx.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _RWNX_MSG_RX_H_
+#define _RWNX_MSG_RX_H_
+
+void rwnx_rx_handle_msg(struct rwnx_hw *rwnx_hw, struct ipc_e2a_msg *msg);
+void rwnx_rx_handle_print(struct rwnx_hw *rwnx_hw, u8 *msg, u32 len);
+
+#endif /* _RWNX_MSG_RX_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_tx.c b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_tx.c
new file mode 100644
index 0000000000000..08dd58442b8a7
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_tx.c
@@ -0,0 +1,3619 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @brief TX function definitions
+ *
+ ******************************************************************************
+ */
+
+#include "rwnx_msg_tx.h"
+#include "reg_access.h"
+#include "rwnx_mod_params.h"
+#ifdef CONFIG_RWNX_BFMER
+#include "rwnx_bfmer.h"
+#endif //(CONFIG_RWNX_BFMER)
+#include "aicwf_txrxif.h"
+#include "rwnx_cmds.h"
+#include "rwnx_compat.h"
+#include "rwnx_main.h"
+#include "rwnx_strs.h"
+#include <linux/pm.h>
+#include "aicwf_sdio.h"
+#include "aicwf_chip_ops.h"
+
+static const struct mac_addr mac_addr_bcst = {{0xFFFF, 0xFFFF, 0xFFFF}};
+
+/* Default MAC Rx filters that can be changed by mac80211
+ * (via the configure_filter() callback)
+ */
+#define RWNX_MAC80211_CHANGEABLE \
+ (NXMAC_ACCEPT_BA_BIT | NXMAC_ACCEPT_BAR_BIT | \
+ NXMAC_ACCEPT_OTHER_DATA_FRAMES_BIT | NXMAC_ACCEPT_PROBE_REQ_BIT | \
+ NXMAC_ACCEPT_PS_POLL_BIT)
+
+/* Default MAC Rx filters that cannot be changed by mac80211 */
+#define RWNX_MAC80211_NOT_CHANGEABLE \
+ (NXMAC_ACCEPT_QO_S_NULL_BIT | NXMAC_ACCEPT_Q_DATA_BIT | \
+ NXMAC_ACCEPT_DATA_BIT | NXMAC_ACCEPT_OTHER_MGMT_FRAMES_BIT | \
+ NXMAC_ACCEPT_MY_UNICAST_BIT | NXMAC_ACCEPT_BROADCAST_BIT | \
+ NXMAC_ACCEPT_BEACON_BIT | NXMAC_ACCEPT_PROBE_RESP_BIT)
+
+/* Default MAC Rx filter */
+#define RWNX_DEFAULT_RX_FILTER \
+ (RWNX_MAC80211_CHANGEABLE | RWNX_MAC80211_NOT_CHANGEABLE)
+
+const int bw2chnl[] = {
+ [NL80211_CHAN_WIDTH_20_NOHT] = PHY_CHNL_BW_20,
+ [NL80211_CHAN_WIDTH_20] = PHY_CHNL_BW_20,
+ [NL80211_CHAN_WIDTH_40] = PHY_CHNL_BW_40,
+ [NL80211_CHAN_WIDTH_80] = PHY_CHNL_BW_80,
+ [NL80211_CHAN_WIDTH_160] = PHY_CHNL_BW_160,
+ [NL80211_CHAN_WIDTH_80P80] = PHY_CHNL_BW_80P80,
+};
+
+const int chnl2bw[] = {
+ [PHY_CHNL_BW_20] = NL80211_CHAN_WIDTH_20,
+ [PHY_CHNL_BW_40] = NL80211_CHAN_WIDTH_40,
+ [PHY_CHNL_BW_80] = NL80211_CHAN_WIDTH_80,
+ [PHY_CHNL_BW_160] = NL80211_CHAN_WIDTH_160,
+ [PHY_CHNL_BW_80P80] = NL80211_CHAN_WIDTH_80P80,
+};
+
+#define RWNX_CMD_ARRAY_SIZE 20
+#define RWNX_CMD_HIGH_WATER_SIZE (RWNX_CMD_ARRAY_SIZE / 2)
+
+static struct rwnx_cmd cmd_array[RWNX_CMD_ARRAY_SIZE];
+static spinlock_t cmd_array_lock;
+static int cmd_array_index;
+
+/*****************************************************************************/
+/*
+ * Parse the ampdu density to retrieve the value in usec, according to the
+ * values defined in ieee80211.h
+ */
+static inline u8 rwnx_ampdudensity2usec(u8 ampdudensity)
+{
+ switch (ampdudensity) {
+ case IEEE80211_HT_MPDU_DENSITY_NONE:
+ return 0;
+ /* 1 microsecond is our granularity */
+ case IEEE80211_HT_MPDU_DENSITY_0_25:
+ case IEEE80211_HT_MPDU_DENSITY_0_5:
+ case IEEE80211_HT_MPDU_DENSITY_1:
+ return 1;
+ case IEEE80211_HT_MPDU_DENSITY_2:
+ return 2;
+ case IEEE80211_HT_MPDU_DENSITY_4:
+ return 4;
+ case IEEE80211_HT_MPDU_DENSITY_8:
+ return 8;
+ case IEEE80211_HT_MPDU_DENSITY_16:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+static inline bool use_pairwise_key(struct cfg80211_crypto_settings *crypto)
+{
+ if (crypto->cipher_group == WLAN_CIPHER_SUITE_WEP40 ||
+ crypto->cipher_group == WLAN_CIPHER_SUITE_WEP104)
+ return false;
+
+ return true;
+}
+
+static inline bool is_non_blocking_msg(int id)
+{
+ return (id == MM_TIM_UPDATE_REQ || id == ME_RC_SET_RATE_REQ ||
+ id == MM_BFMER_ENABLE_REQ || id == ME_TRAFFIC_IND_REQ ||
+ id == TDLS_PEER_TRAFFIC_IND_REQ || id == MESH_PATH_CREATE_REQ ||
+ id == MESH_PROXY_ADD_REQ || id == SM_EXTERNAL_AUTH_REQUIRED_RSP);
+}
+
+static inline u8 get_chan_flags(uint32_t flags)
+{
+ u8 chan_flags = 0;
+#ifdef AIC8800_RADAR_OR_IR_DETECT
+
+ if (flags & IEEE80211_CHAN_NO_IR)
+ chan_flags |= CHAN_NO_IR;
+
+ if (flags & IEEE80211_CHAN_RADAR)
+ chan_flags |= CHAN_RADAR;
+#endif
+ return chan_flags;
+}
+
+static inline s8 chan_to_fw_pwr(int power)
+{
+ return power > 127 ? 127 : (s8)power;
+}
+
+static inline void limit_chan_bw(u8 *bw, u16 primary, u16 *center1)
+{
+ int oft, new_oft = 10;
+
+ if (*bw <= PHY_CHNL_BW_40)
+ return;
+
+ oft = *center1 - primary;
+ *bw = PHY_CHNL_BW_40;
+
+ if (oft < 0)
+ new_oft = new_oft * -1;
+ if (abs(oft) == 10 || abs(oft) == 50)
+ new_oft = new_oft * -1;
+
+ *center1 = primary + new_oft;
+}
+
+struct rwnx_cmd *rwnx_cmd_malloc(void)
+{
+ struct rwnx_cmd *cmd = NULL;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&cmd_array_lock, flags);
+
+ for (cmd_array_index = 0; cmd_array_index < RWNX_CMD_ARRAY_SIZE;
+ cmd_array_index++) {
+ if (cmd_array[cmd_array_index].used == 0) {
+ AICWFDBG(LOGTRACE, "%s get cmd_array[%d]:%p \r\n", __func__,
+ cmd_array_index, &cmd_array[cmd_array_index]);
+ cmd = &cmd_array[cmd_array_index];
+ cmd_array[cmd_array_index].used = 1;
+ break;
+ }
+ }
+
+ if (cmd_array_index >= RWNX_CMD_HIGH_WATER_SIZE) {
+ AICWFDBG(LOGERROR, "%s cmd(%d) was pending...\r\n", __func__,
+ cmd_array_index);
+ mdelay(100);
+ }
+
+ if (!cmd)
+ AICWFDBG(LOGERROR, "%s array is empty...\r\n", __func__);
+
+ spin_unlock_irqrestore(&cmd_array_lock, flags);
+
+ return cmd;
+}
+
+void rwnx_cmd_free(struct rwnx_cmd *cmd)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&cmd_array_lock, flags);
+ cmd->used = 0;
+ AICWFDBG(LOGTRACE, "%s cmd_array[%d]:%p \r\n", __func__, cmd->array_id,
+ cmd);
+ spin_unlock_irqrestore(&cmd_array_lock, flags);
+}
+
+int rwnx_init_cmd_array(void)
+{
+ AICWFDBG(LOGTRACE, "%s Enter \r\n", __func__);
+ spin_lock_init(&cmd_array_lock);
+
+ for (cmd_array_index = 0; cmd_array_index < RWNX_CMD_ARRAY_SIZE;
+ cmd_array_index++) {
+ AICWFDBG(LOGTRACE, "%s cmd_queue[%d]:%p \r\n", __func__,
+ cmd_array_index, &cmd_array[cmd_array_index]);
+ cmd_array[cmd_array_index].used = 0;
+ cmd_array[cmd_array_index].array_id = cmd_array_index;
+ }
+ AICWFDBG(LOGTRACE, "%s Exit \r\n", __func__);
+
+ return 0;
+}
+
+void rwnx_free_cmd_array(void)
+{
+ AICWFDBG(LOGTRACE, "%s Enter \r\n", __func__);
+
+ for (cmd_array_index = 0; cmd_array_index < RWNX_CMD_ARRAY_SIZE;
+ cmd_array_index++)
+ cmd_array[cmd_array_index].used = 0;
+
+ AICWFDBG(LOGTRACE, "%s Exit \r\n", __func__);
+}
+
+/*
+ ******************************************************************************
+ * @brief Allocate memory for a message
+ *
+ * This primitive allocates memory for a message that has to be sent. The memory
+ * is allocated dynamically on the heap and the length of the variable parameter
+ * structure has to be provided in order to allocate the correct size.
+ *
+ * Several additional parameters are provided which will be preset in the
+ *message and which may be used internally to choose the kind of memory to
+ *allocate.
+ *
+ * The memory allocated will be automatically freed by the kernel, after the
+ * pointer has been sent to ke_msg_send(). If the message is not sent, it must
+ * be freed explicitly with ke_msg_free().
+ *
+ * Allocation failure is considered critical and should not happen.
+ *
+ * @param[in] id Message identifier
+ * @param[in] dest_id Destination Task Identifier
+ * @param[in] src_id Source Task Identifier
+ * @param[in] param_len Size of the message parameters to be allocated
+ *
+ * @return Pointer to the parameter member of the ke_msg. If the parameter
+ * structure is empty, the pointer will point to the end of the message
+ * and should not be used (except to retrieve the message pointer or to
+ * send the message)
+ ******************************************************************************
+ */
+static inline void *rwnx_msg_zalloc(lmac_msg_id_t const id,
+ lmac_task_id_t const dest_id,
+ lmac_task_id_t const src_id,
+ uint16_t const param_len)
+{
+ struct lmac_msg *msg;
+ gfp_t flags;
+
+ // if (is_non_blocking_msg(id) && (in_softirq()||in_atomic()))
+ flags = GFP_ATOMIC;
+ // else
+ // flags = GFP_KERNEL;
+
+ // msg = (struct lmac_msg *)kzalloc(sizeof(struct lmac_msg) + param_len, flags);
+ msg = kzalloc(sizeof(*msg) + param_len, flags);
+ if (!msg) {
+ AICWFDBG(LOGERROR, "%s: msg allocation failed\n", __func__);
+ return NULL;
+ }
+ msg->id = id;
+ msg->dest_id = dest_id;
+ msg->src_id = src_id;
+ msg->param_len = param_len;
+ // AICWFDBG(LOGDEBUG, "rwnx_msg_zalloc size=%d id=%d\n",msg->param_len,msg->id);
+
+ return msg->param;
+}
+
+static void rwnx_msg_free(struct rwnx_hw *rwnx_hw, const void *msg_params)
+{
+ struct lmac_msg *msg = container_of((void *)msg_params, struct lmac_msg, param);
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+ /* Free the message */
+ kfree(msg);
+}
+
+// void rwnx_pm_relax(struct aic_sdio_dev *sdiodev);
+// void rwnx_pm_stay_awake(struct aic_sdio_dev *sdiodev);
+
+static int rwnx_send_msg(struct rwnx_hw *rwnx_hw, const void *msg_params,
+ int reqcfm, lmac_msg_id_t reqid, void *cfm)
+{
+ struct lmac_msg *msg;
+ struct rwnx_cmd *cmd;
+ bool nonblock;
+ int ret = 0;
+ u8 empty = 0;
+
+ // RWNX_DBG(RWNX_FN_ENTRY_STR);
+ AICWFDBG(LOGTRACE,
+ "%s (%d)%s reqcfm:%d in_hardirq:%d in_softirq:%d irqs_disabled:%d\r\n",
+ __func__, reqid, RWNX_ID2STR(reqid), reqcfm, (int)in_hardirq(),
+ (int)in_softirq(), (int)irqs_disabled());
+
+#ifdef AICWF_SDIO_SUPPORT
+ if (!aicwf_sdio_activity_get(rwnx_hw, rwnx_hw->ws_tx)) {
+ rwnx_msg_free(rwnx_hw, msg_params);
+ return -EBUSY;
+ }
+ if (rwnx_hw->sdiodev->bus_if->state == BUS_DOWN_ST) {
+ rwnx_msg_free(rwnx_hw, msg_params);
+ sdio_err("bus is down\n");
+ aicwf_sdio_activity_put(rwnx_hw, rwnx_hw->ws_tx);
+ return 0;
+ }
+#endif
+
+ msg = container_of((void *)msg_params, struct lmac_msg, param);
+
+ // nonblock = is_non_blocking_msg(msg->id);
+ nonblock = 0;
+ cmd = rwnx_cmd_malloc(); // kzalloc_obj(struct rwnx_cmd, nonblock ?
+ // GFP_ATOMIC : GFP_KERNEL);
+ cmd->result = -EINTR;
+ cmd->id = msg->id;
+ cmd->reqid = reqid;
+ cmd->a2e_msg = msg;
+ cmd->e2a_msg = cfm;
+ if (nonblock)
+ cmd->flags = RWNX_CMD_FLAG_NONBLOCK;
+ if (reqcfm)
+ cmd->flags |= RWNX_CMD_FLAG_REQ_CFM;
+
+ if (cfm) {
+ do {
+ if (rwnx_hw->cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED)
+ break;
+ spin_lock_bh(&rwnx_hw->cmd_mgr->lock);
+ empty = list_empty(&rwnx_hw->cmd_mgr->cmds);
+ spin_unlock_bh(&rwnx_hw->cmd_mgr->lock);
+ if (!empty) {
+ if (in_softirq()) {
+ AICWFDBG(LOGDEBUG,
+ "AICWF_LOG in_softirq:check cmdqueue empty\n");
+ mdelay(10);
+ } else {
+ AICWFDBG(LOGDEBUG, "AICWF_LOG check cmdqueue empty\n");
+ msleep(50);
+ }
+ }
+ } while (!empty); // wait for cmd queue empty
+ }
+
+ if (reqcfm) {
+ cmd->flags &= ~RWNX_CMD_FLAG_WAIT_ACK; // we don't need ack any more
+ ret = rwnx_hw->cmd_mgr->queue(rwnx_hw->cmd_mgr, cmd);
+ } else {
+#ifdef AICWF_SDIO_SUPPORT
+ aicwf_set_cmd_tx((void *)(rwnx_hw->sdiodev), cmd->a2e_msg,
+ sizeof(struct lmac_msg) + cmd->a2e_msg->param_len);
+#else
+ aicwf_set_cmd_tx((void *)(rwnx_hw->usbdev), cmd->a2e_msg,
+ sizeof(struct lmac_msg) + cmd->a2e_msg->param_len);
+#endif
+ }
+
+ if (!reqcfm || ret)
+ rwnx_cmd_free(cmd); // kfree(cmd);
+
+ aicwf_sdio_activity_put(rwnx_hw, rwnx_hw->ws_tx);
+ return 0;
+}
+
+static int rwnx_send_msg1(struct rwnx_hw *rwnx_hw, const void *msg_params,
+ int reqcfm, lmac_msg_id_t reqid, void *cfm,
+ bool defer)
+{
+ struct lmac_msg *msg;
+ struct rwnx_cmd *cmd;
+ bool nonblock;
+ int ret = 0;
+
+ // RWNX_DBG(RWNX_FN_ENTRY_STR);
+ AICWFDBG(LOGDEBUG,
+ "AICWF_LOG %s (%d)%s reqcfm:%d in_hardirq:%d in_softirq:%d irqs_disabled:%d\r\n",
+ __func__, reqid, RWNX_ID2STR(reqid), reqcfm, (int)in_hardirq(),
+ (int)in_softirq(), (int)irqs_disabled());
+
+ if (!aicwf_sdio_activity_get(rwnx_hw, rwnx_hw->ws_tx)) {
+ rwnx_msg_free(rwnx_hw, msg_params);
+ return -EBUSY;
+ }
+ msg = container_of((void *)msg_params, struct lmac_msg, param);
+
+ // nonblock = is_non_blocking_msg(msg->id);
+ nonblock = 0;
+ cmd = rwnx_cmd_malloc(); // kzalloc_obj(struct rwnx_cmd, nonblock ?
+ // GFP_ATOMIC : GFP_KERNEL);
+ cmd->result = -EINTR;
+ cmd->id = msg->id;
+ cmd->reqid = reqid;
+ cmd->a2e_msg = msg;
+ cmd->e2a_msg = cfm;
+ if (nonblock)
+ cmd->flags = RWNX_CMD_FLAG_NONBLOCK;
+ if (reqcfm)
+ cmd->flags |= RWNX_CMD_FLAG_REQ_CFM;
+
+ if (reqcfm) {
+ cmd->flags &= ~RWNX_CMD_FLAG_WAIT_ACK; // we don't need ack any more
+ if (!defer)
+ ret = rwnx_hw->cmd_mgr->queue(rwnx_hw->cmd_mgr, cmd);
+ else
+ ret = cmd_mgr_queue_force_defer(rwnx_hw->cmd_mgr, cmd);
+ }
+
+ if (!reqcfm || ret)
+ rwnx_cmd_free(cmd); // kfree(cmd);
+
+ if (!ret)
+ ret = cmd->result;
+
+ aicwf_sdio_activity_put(rwnx_hw, rwnx_hw->ws_tx);
+ // return ret;
+ return 0;
+}
+
+/******************************************************************************
+ * Control messages handling functions (FULLMAC)
+ *****************************************************************************/
+int rwnx_send_reset(struct rwnx_hw *rwnx_hw)
+{
+ void *void_param;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* RESET REQ has no parameter */
+ void_param = rwnx_msg_zalloc(MM_RESET_REQ, TASK_MM, DRV_TASK_ID, 0);
+ if (!void_param)
+ return -ENOMEM;
+
+ return rwnx_send_msg(rwnx_hw, void_param, 1, MM_RESET_CFM, NULL);
+}
+
+int rwnx_send_start(struct rwnx_hw *rwnx_hw)
+{
+ struct mm_start_req *start_req_param;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the START REQ message */
+ start_req_param = rwnx_msg_zalloc(MM_START_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_start_req));
+ if (!start_req_param)
+ return -ENOMEM;
+
+ /* Set parameters for the START message */
+ memcpy(&start_req_param->phy_cfg, &rwnx_hw->phy.cfg,
+ sizeof(rwnx_hw->phy.cfg));
+ start_req_param->uapsd_timeout = (u32)rwnx_hw->mod_params->uapsd_timeout;
+ start_req_param->lp_clk_accuracy = (u16)rwnx_hw->mod_params->lp_clk_ppm;
+
+ /* Send the START REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, start_req_param, 1, MM_START_CFM, NULL);
+}
+
+int rwnx_send_version_req(struct rwnx_hw *rwnx_hw, struct mm_version_cfm *cfm)
+{
+ void *void_param;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* VERSION REQ has no parameter */
+ void_param = rwnx_msg_zalloc(MM_VERSION_REQ, TASK_MM, DRV_TASK_ID, 0);
+ if (!void_param)
+ return -ENOMEM;
+
+ return rwnx_send_msg(rwnx_hw, void_param, 1, MM_VERSION_CFM, cfm);
+}
+
+int rwnx_send_add_if(struct rwnx_hw *rwnx_hw, const unsigned char *mac,
+ enum nl80211_iftype iftype, bool p2p,
+ struct mm_add_if_cfm *cfm)
+{
+ struct mm_add_if_req *add_if_req_param;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the ADD_IF_REQ message */
+ add_if_req_param = rwnx_msg_zalloc(MM_ADD_IF_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_add_if_req));
+ if (!add_if_req_param)
+ return -ENOMEM;
+
+ /* Set parameters for the ADD_IF_REQ message */
+ memcpy(&add_if_req_param->addr.array[0], mac, ETH_ALEN);
+ switch (iftype) {
+#if !IS_ENABLED(CONFIG_AIC8800_STA_ONLY)
+#ifdef CONFIG_RWNX_FULLMAC
+ // case NL80211_IFTYPE_P2P_DEVICE:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ add_if_req_param->p2p = true;
+ fallthrough;
+ // no break
+#endif /* CONFIG_RWNX_FULLMAC */
+#endif
+ case NL80211_IFTYPE_STATION:
+ add_if_req_param->type = MM_STA;
+ break;
+
+#if !IS_ENABLED(CONFIG_AIC8800_STA_ONLY)
+ case NL80211_IFTYPE_ADHOC:
+ add_if_req_param->type = MM_IBSS;
+ break;
+
+#ifdef CONFIG_RWNX_FULLMAC
+ case NL80211_IFTYPE_P2P_GO:
+ add_if_req_param->p2p = true;
+ fallthrough;
+ // no break
+#endif /* CONFIG_RWNX_FULLMAC */
+ case NL80211_IFTYPE_AP:
+ add_if_req_param->type = MM_AP;
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ add_if_req_param->type = MM_MESH_POINT;
+ break;
+ case NL80211_IFTYPE_AP_VLAN:
+ return -1;
+ case NL80211_IFTYPE_MONITOR:
+ add_if_req_param->type = MM_MONITOR;
+ break;
+#endif
+ default:
+ rwnx_msg_free(rwnx_hw, add_if_req_param);
+ return -EOPNOTSUPP;
+ }
+
+ /* Send the ADD_IF_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, add_if_req_param, 1, MM_ADD_IF_CFM, cfm);
+}
+
+int rwnx_send_remove_if(struct rwnx_hw *rwnx_hw, u8 vif_index, bool defer)
+{
+ struct mm_remove_if_req *remove_if_req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_REMOVE_IF_REQ message */
+ remove_if_req = rwnx_msg_zalloc(MM_REMOVE_IF_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_remove_if_req));
+ if (!remove_if_req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_REMOVE_IF_REQ message */
+ remove_if_req->inst_nbr = vif_index;
+
+ /* Send the MM_REMOVE_IF_REQ message to LMAC FW */
+ return rwnx_send_msg1(rwnx_hw, remove_if_req, 1, MM_REMOVE_IF_CFM, NULL,
+ defer);
+}
+
+int rwnx_send_set_channel(struct rwnx_hw *rwnx_hw, int phy_idx,
+ struct mm_set_channel_cfm *cfm)
+{
+ struct mm_set_channel_req *req;
+ enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;
+ u16 center_freq = 2412, center_freq1 = 2412, center_freq2 = 2412;
+ s8 tx_power = 0;
+ u8 flags = 0;
+ enum nl80211_band band = NL80211_BAND_2GHZ;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ if (phy_idx >= rwnx_hw->phy.cnt)
+ return -EOPNOTSUPP;
+
+ req = rwnx_msg_zalloc(MM_SET_CHANNEL_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_channel_req));
+ if (!req)
+ return -ENOMEM;
+
+ if (phy_idx == 0) {
+#ifdef CONFIG_RWNX_FULLMAC
+ /* On FULLMAC only setting channel of secondary chain */
+ wiphy_err(rwnx_hw->wiphy, "Trying to set channel of primary chain");
+ return 0;
+#endif /* CONFIG_RWNX_FULLMAC */
+ } else {
+ struct rwnx_sec_phy_chan *chan = &rwnx_hw->phy.sec_chan;
+
+ width = chnl2bw[chan->type];
+ band = chan->band;
+ center_freq = chan->prim20_freq;
+ center_freq1 = chan->center_freq1;
+ center_freq2 = chan->center_freq2;
+ flags = 0;
+ }
+
+ req->chan.band = band;
+ req->chan.type = bw2chnl[width];
+ req->chan.prim20_freq = center_freq;
+ req->chan.center1_freq = center_freq1;
+ req->chan.center2_freq = center_freq2;
+ req->chan.tx_power = tx_power;
+ req->chan.flags = flags;
+ req->index = phy_idx;
+
+ if (rwnx_hw->phy.limit_bw)
+ limit_chan_bw(&req->chan.type, req->chan.prim20_freq,
+ &req->chan.center1_freq);
+
+ RWNX_DBG("mac80211: freq=%d(c1:%d - c2:%d)/width=%d - band=%d\n"
+ " hw(%d): prim20=%d(c1:%d - c2:%d)/ type=%d - band=%d\n",
+ center_freq, center_freq1, center_freq2, width, band, phy_idx,
+ req->chan.prim20_freq, req->chan.center1_freq,
+ req->chan.center2_freq, req->chan.type, req->chan.band);
+
+ /* Send the MM_SET_CHANNEL_REQ REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MM_SET_CHANNEL_CFM, cfm);
+}
+
+int rwnx_send_key_add(struct rwnx_hw *rwnx_hw, u8 vif_idx, u8 sta_idx,
+ bool pairwise, u8 *key, u8 key_len, u8 key_idx,
+ u8 cipher_suite, struct mm_key_add_cfm *cfm)
+{
+ struct mm_key_add_req *key_add_req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_KEY_ADD_REQ message */
+ key_add_req = rwnx_msg_zalloc(MM_KEY_ADD_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_key_add_req));
+ if (!key_add_req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_KEY_ADD_REQ message */
+ if (sta_idx != 0xFF) {
+ /* Pairwise key */
+ key_add_req->sta_idx = sta_idx;
+ } else {
+ /* Default key */
+ key_add_req->sta_idx = sta_idx;
+ key_add_req->key_idx = (u8)key_idx; /* only useful for default keys */
+ }
+ key_add_req->pairwise = pairwise;
+ key_add_req->inst_nbr = vif_idx;
+ key_add_req->key.length = key_len;
+ memcpy(&key_add_req->key.array[0], key, key_len);
+
+ key_add_req->cipher_suite = cipher_suite;
+
+ RWNX_DBG("%s: sta_idx:%d key_idx:%d inst_nbr:%d cipher:%d key_len:%d\n",
+ __func__, key_add_req->sta_idx, key_add_req->key_idx,
+ key_add_req->inst_nbr, key_add_req->cipher_suite,
+ key_add_req->key.length);
+#if defined(CONFIG_RWNX_DBG) || defined(CONFIG_DYNAMIC_DEBUG)
+ print_hex_dump_bytes("key: ", DUMP_PREFIX_OFFSET, key_add_req->key.array,
+ key_add_req->key.length);
+#endif
+
+ /* Send the MM_KEY_ADD_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, key_add_req, 1, MM_KEY_ADD_CFM, cfm);
+}
+
+int rwnx_send_key_del(struct rwnx_hw *rwnx_hw, uint8_t hw_key_idx)
+{
+ struct mm_key_del_req *key_del_req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_KEY_DEL_REQ message */
+ key_del_req = rwnx_msg_zalloc(MM_KEY_DEL_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_key_del_req));
+ if (!key_del_req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_KEY_DEL_REQ message */
+ key_del_req->hw_key_idx = hw_key_idx;
+
+ /* Send the MM_KEY_DEL_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, key_del_req, 1, MM_KEY_DEL_CFM, NULL);
+}
+
+int rwnx_send_bcn(struct rwnx_hw *rwnx_hw, u8 *buf, u8 vif_idx, u16 bcn_len)
+{
+ struct apm_set_bcn_ie_req *bcn_ie_req;
+
+ bcn_ie_req = rwnx_msg_zalloc(APM_SET_BEACON_IE_REQ, TASK_APM, DRV_TASK_ID,
+ sizeof(struct apm_set_bcn_ie_req));
+ if (!bcn_ie_req)
+ return -ENOMEM;
+
+ bcn_ie_req->vif_idx = vif_idx;
+ bcn_ie_req->bcn_ie_len = bcn_len;
+ memcpy(bcn_ie_req->bcn_ie, (u8 *)buf, bcn_len);
+ kfree(buf);
+
+ return rwnx_send_msg(rwnx_hw, bcn_ie_req, 1, APM_SET_BEACON_IE_CFM, NULL);
+}
+
+int rwnx_send_bcn_change(struct rwnx_hw *rwnx_hw, u8 vif_idx, u32 bcn_addr,
+ u16 bcn_len, u16 tim_oft, u16 tim_len, u16 *csa_oft)
+{
+ struct mm_bcn_change_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_BCN_CHANGE_REQ message */
+ req = rwnx_msg_zalloc(MM_BCN_CHANGE_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_bcn_change_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_BCN_CHANGE_REQ message */
+ req->bcn_ptr = bcn_addr;
+ req->bcn_len = bcn_len;
+ req->tim_oft = tim_oft;
+ req->tim_len = tim_len;
+ req->inst_nbr = vif_idx;
+
+ if (csa_oft) {
+ int i;
+
+ for (i = 0; i < BCN_MAX_CSA_CPT; i++)
+ req->csa_oft[i] = csa_oft[i];
+ }
+
+ /* Send the MM_BCN_CHANGE_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MM_BCN_CHANGE_CFM, NULL);
+}
+
+int rwnx_send_roc(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ struct ieee80211_channel *chan, unsigned int duration,
+ struct mm_remain_on_channel_cfm *roc_cfm)
+{
+ struct mm_remain_on_channel_req *req;
+ struct cfg80211_chan_def chandef;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Create channel definition structure */
+ cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+
+ /* Build the MM_REMAIN_ON_CHANNEL_REQ message */
+ req = rwnx_msg_zalloc(MM_REMAIN_ON_CHANNEL_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_remain_on_channel_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_REMAIN_ON_CHANNEL_REQ message */
+ req->op_code = MM_ROC_OP_START;
+ req->vif_index = vif->vif_index;
+ req->duration_ms = duration;
+ req->band = chan->band;
+ req->type = bw2chnl[chandef.width];
+ req->prim20_freq = chan->center_freq;
+ req->center1_freq = chandef.center_freq1;
+ req->center2_freq = chandef.center_freq2;
+ req->tx_power = chan_to_fw_pwr(chan->max_power);
+
+ /* Send the MM_REMAIN_ON_CHANNEL_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MM_REMAIN_ON_CHANNEL_CFM, roc_cfm);
+}
+
+int rwnx_send_cancel_roc(struct rwnx_hw *rwnx_hw)
+{
+ struct mm_remain_on_channel_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_REMAIN_ON_CHANNEL_REQ message */
+ req = rwnx_msg_zalloc(MM_REMAIN_ON_CHANNEL_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_remain_on_channel_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_REMAIN_ON_CHANNEL_REQ message */
+ req->op_code = MM_ROC_OP_CANCEL;
+
+ /* Send the MM_REMAIN_ON_CHANNEL_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MM_REMAIN_ON_CHANNEL_CFM, NULL);
+}
+
+int rwnx_send_set_power(struct rwnx_hw *rwnx_hw, u8 vif_idx, s8 pwr,
+ struct mm_set_power_cfm *cfm)
+{
+ struct mm_set_power_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_POWER_REQ message */
+ req = rwnx_msg_zalloc(MM_SET_POWER_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_power_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_SET_POWER_REQ message */
+ req->inst_nbr = vif_idx;
+ req->power = pwr;
+
+ /* Send the MM_SET_POWER_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MM_SET_POWER_CFM, cfm);
+}
+
+int rwnx_send_set_edca(struct rwnx_hw *rwnx_hw, u8 hw_queue, u32 param,
+ bool uapsd, u8 inst_nbr)
+{
+ struct mm_set_edca_req *set_edca_req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_EDCA_REQ message */
+ set_edca_req = rwnx_msg_zalloc(MM_SET_EDCA_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_edca_req));
+ if (!set_edca_req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_SET_EDCA_REQ message */
+ set_edca_req->ac_param = param;
+ set_edca_req->uapsd = uapsd;
+ set_edca_req->hw_queue = hw_queue;
+ set_edca_req->inst_nbr = inst_nbr;
+
+ /* Send the MM_SET_EDCA_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, set_edca_req, 1, MM_SET_EDCA_CFM, NULL);
+}
+
+#ifdef AICWF_ARP_OFFLOAD
+int rwnx_send_arpoffload_en_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif, u32 ipaddr,
+ u8 enable)
+{
+ struct mm_set_arpoffload_en_req *arp_offload_req;
+ int error;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_P2P_NOA_REQ message */
+ arp_offload_req =
+ rwnx_msg_zalloc(MM_SET_ARPOFFLOAD_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_arpoffload_en_req));
+
+ if (!arp_offload_req)
+ return -ENOMEM;
+
+ /* Fill the message parameters */
+ arp_offload_req->enable = enable;
+ arp_offload_req->vif_idx = rwnx_vif->vif_index;
+ arp_offload_req->ipaddr = ipaddr;
+
+ /* Send the MM_ARPOFFLOAD_EN_REQ message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, arp_offload_req, 1, MM_SET_ARPOFFLOAD_CFM, NULL);
+
+ return error;
+}
+#endif
+
+int rwnx_send_disable_agg_req(struct rwnx_hw *rwnx_hw, u8 agg_disable,
+ u8 agg_disable_rx, u8 sta_idx)
+{
+ struct mm_set_agg_disable_req *req;
+ int error;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_AGG_DISABLE_REQ message */
+ req = rwnx_msg_zalloc(MM_SET_AGG_DISABLE_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_agg_disable_req));
+
+ if (!req)
+ return -ENOMEM;
+
+ req->disable = agg_disable;
+ req->staidx = sta_idx;
+ req->disable_rx = agg_disable_rx;
+
+ /* Send the MM_SET_AGG_DISABLE_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_AGG_DISABLE_CFM, NULL);
+
+ return error;
+};
+
+int rwnx_send_coex_req(struct rwnx_hw *rwnx_hw, u8 disable_coexnull,
+ u8 enable_nullcts)
+{
+ struct mm_set_coex_req *coex_req;
+ int error;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_COEX_REQ message */
+ coex_req = rwnx_msg_zalloc(MM_SET_COEX_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_coex_req));
+
+ if (!coex_req)
+ return -ENOMEM;
+
+ coex_req->bt_on = 1;
+ coex_req->disable_coexnull = disable_coexnull;
+ coex_req->enable_nullcts = enable_nullcts;
+ coex_req->enable_periodic_timer = 0;
+ coex_req->coex_timeslot_set = 0;
+
+ /* Send the MM_SET_COEX_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, coex_req, 1, MM_SET_COEX_CFM, NULL);
+
+ return error;
+};
+
+int rwnx_send_rf_config_req(struct rwnx_hw *rwnx_hw, u8 ofst, u8 sel,
+ u8 *tbl, u16 len)
+{
+ struct mm_set_rf_config_req *rf_config_req;
+ int error;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_RF_CONFIG_REQ message */
+ rf_config_req = rwnx_msg_zalloc(MM_SET_RF_CONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_rf_config_req));
+
+ if (!rf_config_req)
+ return -ENOMEM;
+
+ rf_config_req->table_sel = sel;
+ rf_config_req->table_ofst = ofst;
+ rf_config_req->table_num = 16;
+ rf_config_req->deft_page = 0;
+
+ memcpy(rf_config_req->data, tbl, len);
+
+ /* Send the MM_SET_RF_CONFIG_REQ message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, rf_config_req, 1, MM_SET_RF_CONFIG_CFM, NULL);
+
+ return error;
+}
+
+int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw,
+ struct mm_set_rf_calib_cfm *cfm)
+{
+ struct mm_set_rf_calib_req *rf_calib_req;
+ struct xtal_cap_conf xtal_cap = {
+ 0,
+ };
+ int error;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_P2P_NOA_REQ message */
+ rf_calib_req = rwnx_msg_zalloc(MM_SET_RF_CALIB_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_rf_calib_req));
+
+ if (!rf_calib_req)
+ return -ENOMEM;
+
+ aic_chip_set_rf_calib_cfg(rwnx_hw, rf_calib_req);
+
+ rf_calib_req->param_alpha = 0x0c34c008;
+ rf_calib_req->bt_calib_en = 0;
+ rf_calib_req->bt_calib_param = 0x264203;
+
+ get_userconfig_xtal_cap(&xtal_cap);
+
+ if (xtal_cap.enable) {
+ AICWFDBG(LOGDEBUG, "user xtal cap: %d, cap_fine: %d\n", xtal_cap.xtal_cap,
+ xtal_cap.xtal_cap_fine);
+ rf_calib_req->xtal_cap = xtal_cap.xtal_cap;
+ rf_calib_req->xtal_cap_fine = xtal_cap.xtal_cap_fine;
+ } else {
+ rf_calib_req->xtal_cap = 0;
+ rf_calib_req->xtal_cap_fine = 0;
+ }
+
+ /* Send the MM_SET_RF_CALIB_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, rf_calib_req, 1, MM_SET_RF_CALIB_CFM, cfm);
+
+ return error;
+};
+
+int rwnx_send_get_macaddr_req(struct rwnx_hw *rwnx_hw,
+ struct mm_get_mac_addr_cfm *cfm)
+{
+ struct mm_get_mac_addr_req *get_macaddr_req;
+ int error;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_GET_MAC_ADDR_REQ message */
+ get_macaddr_req = rwnx_msg_zalloc(MM_GET_MAC_ADDR_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_get_mac_addr_req));
+
+ if (!get_macaddr_req)
+ return -ENOMEM;
+
+ get_macaddr_req->get = 1;
+
+ /* Send the MM_GET_MAC_ADDR_REQ message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, get_macaddr_req, 1, MM_GET_MAC_ADDR_CFM, cfm);
+
+ return error;
+};
+
+int rwnx_send_get_sta_info_req(struct rwnx_hw *rwnx_hw, u8 sta_idx,
+ struct mm_get_sta_info_cfm *cfm)
+{
+ struct mm_get_sta_info_req *get_info_req;
+ int error;
+
+ /* Build the MM_GET_STA_INFO_REQ message */
+ get_info_req = rwnx_msg_zalloc(MM_GET_STA_INFO_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_get_sta_info_req));
+
+ if (!get_info_req)
+ return -ENOMEM;
+
+ get_info_req->sta_idx = sta_idx;
+
+ /* Send the MM_GET_STA_INFO_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, get_info_req, 1, MM_GET_STA_INFO_CFM, cfm);
+
+ return error;
+};
+
+int rwnx_send_set_stack_start_req(struct rwnx_hw *rwnx_hw, u8 on,
+ u8 efuse_valid, u8 set_vendor_info,
+ u8 fwtrace_redir_en,
+ struct mm_set_stack_start_cfm *cfm)
+{
+ struct mm_set_stack_start_req *req;
+ int error;
+
+ /* Build the MM_SET_STACK_START_REQ message */
+ req = rwnx_msg_zalloc(MM_SET_STACK_START_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_stack_start_req));
+
+ if (!req)
+ return -ENOMEM;
+
+ req->is_stack_start = on;
+ req->efuse_valid = efuse_valid;
+ req->set_vendor_info = set_vendor_info;
+ req->fwtrace_redir = fwtrace_redir_en;
+ /* Send the MM_SET_STACK_START_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_STACK_START_CFM, cfm);
+
+ return error;
+}
+
+int rwnx_send_get_temp_req(struct rwnx_hw *rwnx_hw,
+ struct mm_set_vendor_swconfig_cfm *cfm)
+{
+ struct mm_set_vendor_swconfig_req *req;
+ int ret;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the TEMP_COMP_GET_REQ message */
+ req = rwnx_msg_zalloc(MM_SET_VENDOR_SWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_vendor_swconfig_req));
+ if (!req) {
+ AICWFDBG(LOGINFO, "%s msg_alloc fail\n", __func__);
+ return -ENOMEM;
+ }
+ req->swconfig_id = TEMP_COMP_GET_REQ;
+
+ ret = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, cfm);
+ if (!ret) {
+ AICWFDBG(LOGDEBUG, "status=%d, temp=%d\n", cfm->temp_comp_get_cfm.status,
+ cfm->temp_comp_get_cfm.degree);
+ } else {
+ AICWFDBG(LOGINFO, "%s msg_fail\n", __func__);
+ return ret;
+ }
+#ifdef CONFIG_AIC8800_TEMP_CONTROL
+ // rwnx_hw->started_jiffies = jiffies;
+ rwnx_hw->temp = cfm->temp_comp_get_cfm.degree;
+#endif
+
+ return ret;
+}
+
+int rwnx_send_get_temp_hwconfig_req(struct rwnx_hw *rwnx_hw,
+ struct mm_set_vendor_hwconfig_cfm *cfm)
+{
+ struct mm_get_chip_temp_req *req;
+ int ret;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+ /* Build the TEMP_COMP_HWCONFIG_GET_REQ message */
+ req = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_get_chip_temp_req));
+ if (!req) {
+ AICWFDBG(LOGINFO, "%s msg_alloc fail\n", __func__);
+ return -ENOMEM;
+ }
+ req->hwconfig_id = CHIP_TEMP_GET_REQ;
+
+ ret = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_HWCONFIG_CFM, cfm);
+ if (!ret) {
+ AICWFDBG(LOGDEBUG, "get_chip_temp degree=%d\n",
+ cfm->chip_temp_cfm.degree);
+ } else {
+ AICWFDBG(LOGINFO, "%s msg_fail\n", __func__);
+ return ret;
+ }
+ return ret;
+}
+
+int rwnx_send_set_temp_comp_req(struct rwnx_hw *rwnx_hw,
+ struct mm_set_vendor_swconfig_cfm *cfm)
+{
+ struct mm_set_vendor_swconfig_req *req;
+ int ret;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+ /* Build the TEMP_COMP_SET_REQ message */
+ req = rwnx_msg_zalloc(MM_SET_VENDOR_SWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_vendor_swconfig_req));
+ if (!req) {
+ AICWFDBG(LOGERROR, "%s msg_alloc fail\n", __func__);
+ return -ENOMEM;
+ }
+ req->swconfig_id = TEMP_COMP_SET_REQ;
+ req->temp_comp_set_req.enable = 1;
+#ifdef CONFIG_AIC8800_TEMP_CONTROL
+ req->temp_comp_set_req.tmr_period_ms = TEMP_GET_INTERVAL;
+#else
+ req->temp_comp_set_req.tmr_period_ms = 15 * 1000;
+#endif
+
+ ret = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, cfm);
+ if (!ret) {
+ AICWFDBG(LOGINFO, "temp_comp status: %d\n", cfm->temp_comp_set_cfm.status);
+ } else {
+ AICWFDBG(LOGINFO, "%s msg_fail\n", __func__);
+ return ret;
+ }
+ return ret;
+}
+
+int rwnx_send_vendor_hwconfig_req(struct rwnx_hw *rwnx_hw, u32 hwconfig_id,
+ s32 *param, s32 *param_out)
+{
+ struct mm_set_acs_txop_req *req0;
+ struct mm_set_channel_access_req *req1;
+ struct mm_set_mac_timescale_req *req2;
+ struct mm_set_cca_threshold_req *req3;
+ struct mm_set_bwmode_req *req4;
+ struct mm_set_ap_ps_level_req *req5 = NULL;
+ struct mm_set_customized_freq_req *req6;
+
+ int error = 0;
+ int i;
+
+ switch (hwconfig_id) {
+ case ACS_TXOP_REQ:
+ /* Build the ACS_TXOP_REQ message */
+ req0 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_acs_txop_req));
+ if (!req0)
+ return -ENOMEM;
+ req0->hwconfig_id = hwconfig_id;
+ req0->txop_be = param[0];
+ req0->txop_bk = param[1];
+ req0->txop_vi = param[2];
+ req0->txop_vo = param[3];
+ AICWFDBG(LOGDEBUG, "set_acs_txop_req: be: %x,bk: %x,vi: %x,vo: %x\n", req0->txop_be,
+ req0->txop_bk, req0->txop_vi, req0->txop_vo);
+ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req0, 1, MM_SET_VENDOR_HWCONFIG_CFM, NULL);
+ break;
+
+ case CHANNEL_ACCESS_REQ:
+ /* Build the CHANNEL_ACCESS_REQ message */
+ req1 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_channel_access_req));
+ if (!req1)
+ return -ENOMEM;
+ req1->hwconfig_id = hwconfig_id;
+ req1->edca[0] = param[0];
+ req1->edca[1] = param[1];
+ req1->edca[2] = param[2];
+ req1->edca[3] = param[3];
+ req1->vif_idx = param[4];
+ req1->retry_cnt = param[5];
+ req1->rts_en = param[6];
+ req1->long_nav_en = param[7];
+ req1->cfe_en = param[8];
+ req1->rc_retry_cnt[0] = param[9];
+ req1->rc_retry_cnt[1] = param[10];
+ req1->rc_retry_cnt[2] = param[11];
+ req1->ccademod_th = param[12];
+ AICWFDBG(LOGDEBUG,
+ "set_channel_access_req:edca[]= %x %x %x %x\nvif_idx: %x, retry_cnt: %x, rts_en: %x, long_nav_en: %x, cfe_en: %x, rc_retry_cnt: %x:%x:%x, ccademod_th = %d\n",
+ req1->edca[0], req1->edca[1], req1->edca[2], req1->edca[3],
+ req1->vif_idx, req1->retry_cnt, req1->rts_en, req1->long_nav_en,
+ req1->cfe_en, req1->rc_retry_cnt[0], req1->rc_retry_cnt[1],
+ req1->rc_retry_cnt[2], req1->ccademod_th);
+ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req1, 1, MM_SET_VENDOR_HWCONFIG_CFM, NULL);
+ break;
+
+ case MAC_TIMESCALE_REQ:
+ /* Build the MAC_TIMESCALE_REQ message */
+ req2 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_mac_timescale_req));
+ if (!req2)
+ return -ENOMEM;
+ req2->hwconfig_id = hwconfig_id;
+ req2->sifs_a_time = param[0];
+ req2->sifs_b_time = param[1];
+ req2->slot_time = param[2];
+ req2->rx_startdelay_ofdm = param[3];
+ req2->rx_startdelay_long = param[4];
+ req2->rx_startdelay_short = param[5];
+ AICWFDBG(LOGDEBUG,
+ "set_mac_timescale_req:sifsA_time: %x, sifsB_time: %x, slot_time: %x, rx_startdelay ofdm:%x long %x short %x\n",
+ req2->sifs_a_time, req2->sifs_b_time, req2->slot_time,
+ req2->rx_startdelay_ofdm, req2->rx_startdelay_long,
+ req2->rx_startdelay_short);
+ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req2, 1, MM_SET_VENDOR_HWCONFIG_CFM, NULL);
+ break;
+
+ case CCA_THRESHOLD_REQ:
+ /* Build the CCA_THRESHOLD_REQ message */
+ req3 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_cca_threshold_req));
+ if (!req3)
+ return -ENOMEM;
+ req3->hwconfig_id = hwconfig_id;
+ req3->auto_cca_en = param[0];
+ req3->cca20p_rise_th = param[1];
+ req3->cca20s_rise_th = param[2];
+ req3->cca20p_fall_th = param[3];
+ req3->cca20s_fall_th = param[4];
+ AICWFDBG(LOGDEBUG,
+ "cca_threshold_req: auto_cca_en:%d\ncca20p_rise_th = %d\ncca20s_rise_th = %d\ncca20p_fall_th = %d\ncca20s_fall_th = %d\n",
+ req3->auto_cca_en, req3->cca20p_rise_th, req3->cca20s_rise_th,
+ req3->cca20p_fall_th, req3->cca20s_fall_th);
+ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req3, 1, MM_SET_VENDOR_HWCONFIG_CFM, NULL);
+ break;
+ case BWMODE_REQ:
+ /* Build the SET_BWMODE_REQ message */
+ req4 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_bwmode_req));
+ if (!req4)
+ return -ENOMEM;
+ req4->hwconfig_id = hwconfig_id;
+ req4->bwmode = param[0];
+ AICWFDBG(LOGDEBUG, "bwmode :%d\n", req4->bwmode);
+ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req4, 1, MM_SET_VENDOR_HWCONFIG_CFM, NULL);
+ break;
+ case CHIP_TEMP_GET_REQ:
+ aic_chip_get_temp(rwnx_hw, param_out);
+ break;
+ case AP_PS_LEVEL_SET_REQ:
+ /*
+ * AP_PS_CLK_1 = 1, // 3:7 -> active 3, doze 7
+ * AP_PS_CLK_2, // 5:5 -> active 5, doze 5
+ * AP_PS_CLK_3, // 7:3 -> active 7, doze 3
+ * AP_PS_CLK_4, // 8:2 -> active 8, doze 2
+ * AP_PS_CLK_5, // 9:1 -> active 9, doze 1
+ */
+ /* Build the MM_SET_VENDOR_HWCONFIG_REQ message */
+ req5 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_ap_ps_level_req));
+ if (!req5)
+ return -ENOMEM;
+ req5->hwconfig_id = hwconfig_id;
+ req5->ap_ps_level = param[0];
+
+ /* Send the MM_GET_MAC_ADDR_REQ message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req5, 1, MM_SET_VENDOR_HWCONFIG_CFM, NULL);
+ if (!error)
+ AICWFDBG(LOGDEBUG, "set ap_ps_level=%d\n", param[0]);
+ break;
+
+ case CUSTOMIZED_FREQ_REQ:
+ /* Build the CUSTOMIZED_FREQ_REQ message */
+ req6 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_customized_freq_req));
+ if (!req6)
+ return -ENOMEM;
+ req5->hwconfig_id = hwconfig_id;
+ for (i = 0; i < 4; i++) {
+ req6->raw_freq[i] = param[i];
+ req6->map_freq[i] = param[i + 4];
+ }
+ AICWFDBG(LOGDEBUG,
+ "customized_freq_req: raw_freq[ %d %d %d %d ], map_freq[ %d %d %d %d]\n",
+ param[0], param[1], param[2], param[3], param[4], param[5],
+ param[6], param[7]);
+ /* Send the MM_SET_VENDOR_HWCONFIG_CFM message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req5, 1, MM_SET_VENDOR_HWCONFIG_CFM, NULL);
+
+ break;
+ default:
+ return -ENOMEM;
+ }
+ return error;
+}
+
+int rwnx_send_vendor_swconfig_req(struct rwnx_hw *rwnx_hw, u32 swconfig_id,
+ s32 *param_in, s32 *param_out)
+{
+ struct mm_set_vendor_swconfig_req *req;
+ struct mm_set_vendor_swconfig_cfm cfm = {
+ 0,
+ };
+ int error;
+
+ req = rwnx_msg_zalloc(MM_SET_VENDOR_SWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_vendor_swconfig_req));
+ if (!req)
+ return -ENOMEM;
+ req->swconfig_id = swconfig_id;
+
+ switch (swconfig_id) {
+ case BCN_CFG_REQ:
+ /* Build the BCN_CFG_REQ message */
+ req->bcn_cfg_req.tim_bcmc_ignored_enable = (bool)param_in[0];
+ AICWFDBG(LOGDEBUG, "bcn_cfg_req: tim_bcmc_ignd=%d\n",
+ req->bcn_cfg_req.tim_bcmc_ignored_enable);
+ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, &cfm);
+ if (!error) {
+ param_out[0] = (s32)cfm.bcn_cfg_cfm.tim_bcmc_ignored_status;
+ AICWFDBG(LOGDEBUG, "status=%d\n", cfm.bcn_cfg_cfm.tim_bcmc_ignored_status);
+ }
+ break;
+
+ case TEMP_COMP_SET_REQ:
+ /* Build the TEMP_COMP_SET_REQ message */
+ req->temp_comp_set_req.enable = (u8)param_in[0];
+ req->temp_comp_set_req.tmr_period_ms = (u32)param_in[1];
+ AICWFDBG(LOGDEBUG, "temp_comp_set_req: en=%d, tmr=%x\n",
+ req->temp_comp_set_req.enable,
+ req->temp_comp_set_req.tmr_period_ms);
+ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, &cfm);
+ if (!error) {
+ param_out[0] = (s32)cfm.temp_comp_set_cfm.status;
+ AICWFDBG(LOGDEBUG, "status=%d\n", cfm.temp_comp_set_cfm.status);
+ }
+ break;
+
+ case TEMP_COMP_GET_REQ:
+ AICWFDBG(LOGDEBUG, "temp_comp_get_req\n");
+ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, &cfm);
+ if (!error) {
+ param_out[0] = (s32)cfm.temp_comp_get_cfm.status;
+ param_out[1] = (s32)cfm.temp_comp_get_cfm.degree;
+ AICWFDBG(LOGDEBUG, "status=%d, degree=%d\n", cfm.temp_comp_get_cfm.status,
+ cfm.temp_comp_get_cfm.degree);
+ }
+ break;
+
+ case EXT_FLAGS_SET_REQ:
+ /* Build the EXT_FLAGS_SET_REQ message */
+ req->ext_flags_set_req.user_flags = (u32)param_in[0];
+ AICWFDBG(LOGDEBUG, "ext_flags_set_req: flags=%x\n",
+ req->ext_flags_set_req.user_flags);
+ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, &cfm);
+ if (!error) {
+ param_out[0] = (u32)cfm.ext_flags_set_cfm.user_flags;
+ AICWFDBG(LOGDEBUG, "cfm flags=%x\n", cfm.ext_flags_set_cfm.user_flags);
+ }
+ break;
+
+ case EXT_FLAGS_GET_REQ:
+ /* Build the EXT_FLAGS_GET_REQ message */
+ AICWFDBG(LOGDEBUG, "ext_flags_get_req\n");
+ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, &cfm);
+ if (!error) {
+ param_out[0] = (u32)cfm.ext_flags_get_cfm.user_flags;
+ AICWFDBG(LOGDEBUG, "cfm flags=%x\n", cfm.ext_flags_get_cfm.user_flags);
+ }
+ break;
+
+ case EXT_FLAGS_MASK_SET_REQ:
+ /* Build the EXT_FLAGS_MASK_SET_REQ message */
+ req->ext_flags_mask_set_req.user_flags_mask = (u32)param_in[0];
+ req->ext_flags_mask_set_req.user_flags_val = (u32)param_in[1];
+ AICWFDBG(LOGDEBUG, "ext_flags_mask_set_req: flags mask=0x%x, val=0x%x\n",
+ req->ext_flags_mask_set_req.user_flags_mask,
+ req->ext_flags_mask_set_req.user_flags_val);
+ /* Send the MM_SET_VENDOR_SWCONFIG_REQ message to UMAC FW */
+ error =
+ rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, &cfm);
+ if (!error) {
+ param_out[0] = (u32)cfm.ext_flags_mask_set_cfm.user_flags;
+ AICWFDBG(LOGDEBUG, "cfm flags=%x\n", cfm.ext_flags_mask_set_cfm.user_flags);
+ }
+ break;
+
+ default:
+ error = -ENOMEM;
+ break;
+ }
+
+ return error;
+}
+
+int rwnx_send_mask_set_ext_flags_req(struct rwnx_hw *rwnx_hw,
+ u32 flags_mask, u32 flags_val,
+ struct mm_set_vendor_swconfig_cfm *cfm)
+{
+ struct mm_set_vendor_swconfig_req *req;
+ int ret;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+ /* Build the REQ message */
+ req = rwnx_msg_zalloc(MM_SET_VENDOR_SWCONFIG_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_vendor_swconfig_req));
+ if (!req) {
+ AICWFDBG(LOGERROR, "%s msg_alloc fail\n", __func__);
+ return -ENOMEM;
+ }
+ req->swconfig_id = EXT_FLAGS_MASK_SET_REQ;
+ req->ext_flags_mask_set_req.user_flags_mask = (u32)flags_mask;
+ req->ext_flags_mask_set_req.user_flags_val = (u32)flags_val;
+
+ ret = rwnx_send_msg(rwnx_hw, req, 1, MM_SET_VENDOR_SWCONFIG_CFM, cfm);
+ if (!ret) {
+ AICWFDBG(LOGINFO, "curr ext_flags=%x\n",
+ cfm->ext_flags_mask_set_cfm.user_flags);
+ } else {
+ AICWFDBG(LOGERROR, "%s send_msg_fail\n", __func__);
+ return ret;
+ }
+ return ret;
+}
+
+int rwnx_send_get_fw_version_req(struct rwnx_hw *rwnx_hw,
+ struct mm_get_fw_version_cfm *cfm)
+{
+ void *req;
+ int error;
+
+ /* Build the MM_GET_FW_VERSION_REQ message */
+ req = rwnx_msg_zalloc(MM_GET_FW_VERSION_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(u8));
+
+ if (!req)
+ return -ENOMEM;
+
+ /* Send the MM_GET_FW_VERSION_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, req, 1, MM_GET_FW_VERSION_CFM, cfm);
+
+ return error;
+}
+
+int rwnx_send_txpwr_lvl_req(struct rwnx_hw *rwnx_hw)
+{
+ struct mm_set_txpwr_lvl_req *txpwr_lvl_req;
+ struct txpwr_lvl_conf_v2 txpwr_lvl_v2_tmp;
+ struct txpwr_lvl_conf_v2 *txpwr_lvl_v2;
+ int error;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_TXPWR_LVL_REQ message */
+ txpwr_lvl_req =
+ rwnx_msg_zalloc(MM_SET_TXPWR_IDX_LVL_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_txpwr_lvl_req));
+
+ if (!txpwr_lvl_req)
+ return -ENOMEM;
+
+ txpwr_lvl_v2 = &txpwr_lvl_v2_tmp;
+
+ get_userconfig_txpwr_lvl_v2_in_fdrv(txpwr_lvl_v2);
+
+ if (txpwr_lvl_v2->enable == 0) {
+ rwnx_msg_free(rwnx_hw, txpwr_lvl_req);
+ return 0;
+ }
+
+ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_lvl_v2->enable);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_1m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[0]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_2m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[1]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[2]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[3]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_6m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[4]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_9m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[5]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[6]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[7]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[8]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[9]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[10]);
+ AICWFDBG(LOGINFO, "%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[11]);
+ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs0_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[0]);
+ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs1_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[1]);
+ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs2_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[2]);
+ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs3_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[3]);
+ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs4_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[4]);
+ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs5_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[5]);
+ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs6_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[6]);
+ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs7_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[7]);
+ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs8_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[8]);
+ AICWFDBG(LOGINFO, "%s:lvl_11n_11ac_mcs9_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[9]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs0_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[0]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs1_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[1]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs2_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[2]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs3_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[3]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs4_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[4]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs5_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[5]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs6_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[6]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs7_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[7]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs8_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[8]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs9_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[9]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs10_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[10]);
+ AICWFDBG(LOGINFO, "%s:lvl_11ax_mcs11_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[11]);
+
+ if (rwnx_hw->testmode == 0 && chip_sub_id == 0) {
+ txpwr_lvl_req->txpwr_lvl.enable = txpwr_lvl_v2->enable;
+ txpwr_lvl_req->txpwr_lvl.dsss =
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[3]; // 11M
+ txpwr_lvl_req->txpwr_lvl.ofdmlowrate_2g4 =
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[4]; // MCS4
+ txpwr_lvl_req->txpwr_lvl.ofdm64qam_2g4 =
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[7]; // MCS7
+ txpwr_lvl_req->txpwr_lvl.ofdm256qam_2g4 =
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[9]; // MCS9
+ txpwr_lvl_req->txpwr_lvl.ofdm1024qam_2g4 =
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[11]; // MCS11
+ txpwr_lvl_req->txpwr_lvl.ofdmlowrate_5g = 13; // unused
+ txpwr_lvl_req->txpwr_lvl.ofdm64qam_5g = 13; // unused
+ txpwr_lvl_req->txpwr_lvl.ofdm256qam_5g = 13; // unused
+ txpwr_lvl_req->txpwr_lvl.ofdm1024qam_5g = 13; // unused
+ } else {
+ txpwr_lvl_req->txpwr_lvl_v2 = *txpwr_lvl_v2;
+ }
+
+ /* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, txpwr_lvl_req, 1,
+ MM_SET_TXPWR_IDX_LVL_CFM, NULL);
+
+ return error;
+}
+
+int rwnx_send_txpwr_lvl_v3_req(struct rwnx_hw *rwnx_hw, int index_reg)
+{
+ struct mm_set_txpwr_lvl_req *txpwr_lvl_req;
+ struct txpwr_lvl_conf_v3 txpwr_lvl_v3_tmp;
+ struct txpwr_lvl_conf_v3 *txpwr_lvl_v3;
+ struct txpwr_loss_conf txpwr_loss_tmp;
+ struct txpwr_loss_conf *txpwr_loss;
+ int error;
+ int i;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_TXPWR_LVL_REQ message */
+ txpwr_lvl_req =
+ rwnx_msg_zalloc(MM_SET_TXPWR_IDX_LVL_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_txpwr_lvl_req));
+
+ if (!txpwr_lvl_req)
+ return -ENOMEM;
+
+ txpwr_lvl_v3 = &txpwr_lvl_v3_tmp;
+ txpwr_loss = &txpwr_loss_tmp;
+ txpwr_loss->loss_enable_2g4 = 0;
+ txpwr_loss->loss_enable_5g = 0;
+
+ //get_userconfig_txpwr_lvl_v3_in_fdrv(txpwr_lvl_v3);
+ get_userconfig_txpwr_lvl_group_in_fdrv(txpwr_lvl_v3, index_reg);
+ get_userconfig_txpwr_loss(txpwr_loss);
+
+ if (txpwr_loss->loss_enable_2g4 == 1) {
+ AICWFDBG(LOGINFO, "%s:loss_value_2g4: %d\r\n", __func__,
+ txpwr_loss->loss_value_2g4);
+
+ for (i = 0; i <= 11; i++)
+ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[i] -= txpwr_loss->loss_value_2g4;
+ for (i = 0; i <= 9; i++)
+ txpwr_lvl_v3->pwrlvl_11n_11ac_2g4[i] -= txpwr_loss->loss_value_2g4;
+ for (i = 0; i <= 11; i++)
+ txpwr_lvl_v3->pwrlvl_11ax_2g4[i] -= txpwr_loss->loss_value_2g4;
+ }
+
+ if (txpwr_loss->loss_enable_5g == 1) {
+ AICWFDBG(LOGINFO, "%s:loss_value_5g: %d\r\n", __func__,
+ txpwr_loss->loss_value_5g);
+
+ for (i = 0; i <= 11; i++)
+ txpwr_lvl_v3->pwrlvl_11a_5g[i] -= txpwr_loss->loss_value_5g;
+ for (i = 0; i <= 9; i++)
+ txpwr_lvl_v3->pwrlvl_11n_11ac_5g[i] -= txpwr_loss->loss_value_5g;
+ for (i = 0; i <= 11; i++)
+ txpwr_lvl_v3->pwrlvl_11ax_5g[i] -= txpwr_loss->loss_value_5g;
+ }
+
+ if (txpwr_lvl_v3->enable == 0) {
+ rwnx_msg_free(rwnx_hw, txpwr_lvl_req);
+ return 0;
+ }
+
+ AICWFDBG(LOGDEBUG, "%s: dump\n", __func__);
+ AICWFDBG(LOGDEBUG, "txpwr_lvl_v3->enable: %d\r\n", txpwr_lvl_v3->enable);
+ AICWFDBG(LOGDEBUG, "lvl_11b_11ag_1m_2g4:%d\r\n",
+ txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[0]);
+
+ txpwr_lvl_req->txpwr_lvl_v3 = *txpwr_lvl_v3;
+
+ /* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, txpwr_lvl_req, 1,
+ MM_SET_TXPWR_IDX_LVL_CFM, NULL);
+
+ return error;
+}
+
+int rwnx_send_txpwr_lvl_adj_req(struct rwnx_hw *rwnx_hw)
+{
+ struct mm_set_txpwr_lvl_adj_req *txpwr_lvl_adj_req;
+ struct txpwr_lvl_adj_conf txpwr_lvl_adj_tmp;
+ struct txpwr_lvl_adj_conf *txpwr_lvl_adj;
+ int error;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_TXPWR_LVL_REQ message */
+ txpwr_lvl_adj_req =
+ rwnx_msg_zalloc(MM_SET_TXPWR_LVL_ADJ_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_txpwr_lvl_adj_req));
+
+ if (!txpwr_lvl_adj_req)
+ return -ENOMEM;
+
+ txpwr_lvl_adj = &txpwr_lvl_adj_tmp;
+
+ get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj);
+
+ if (txpwr_lvl_adj->enable == 0) {
+ rwnx_msg_free(rwnx_hw, txpwr_lvl_adj_req);
+ return 0;
+ }
+
+ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_lvl_adj->enable);
+ AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_1_4:%d\r\n", __func__,
+ txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[0]);
+ AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_5_9:%d\r\n", __func__,
+ txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[1]);
+ AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_10_13:%d\r\n", __func__,
+ txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[2]);
+ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_42:%d\r\n", __func__,
+ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[0]);
+ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_58:%d\r\n", __func__,
+ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[1]);
+ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_106:%d\r\n", __func__,
+ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[2]);
+ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_122:%d\r\n", __func__,
+ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[3]);
+ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_138:%d\r\n", __func__,
+ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[4]);
+ AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_155:%d\r\n", __func__,
+ txpwr_lvl_adj->pwrlvl_adj_tbl_5g[5]);
+
+ txpwr_lvl_adj_req->txpwr_lvl_adj = *txpwr_lvl_adj;
+
+ /* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, txpwr_lvl_adj_req, 1,
+ MM_SET_TXPWR_LVL_ADJ_CFM, NULL);
+
+ return error;
+}
+
+int rwnx_send_txpwr_idx_req(struct rwnx_hw *rwnx_hw)
+{
+ struct mm_set_txpwr_idx_req *txpwr_idx_req;
+ struct txpwr_idx_conf *txpwr_idx;
+ int error;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_TXPWR_IDX_LVL_REQ message */
+ txpwr_idx_req =
+ rwnx_msg_zalloc(MM_SET_TXPWR_IDX_LVL_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_txpwr_idx_req));
+
+ if (!txpwr_idx_req)
+ return -ENOMEM;
+
+ txpwr_idx = &txpwr_idx_req->txpwr_idx;
+ txpwr_idx->enable = 1;
+ txpwr_idx->dsss = 9;
+ txpwr_idx->ofdmlowrate_2g4 = 8;
+ txpwr_idx->ofdm64qam_2g4 = 8;
+ txpwr_idx->ofdm256qam_2g4 = 8;
+ txpwr_idx->ofdm1024qam_2g4 = 8;
+ txpwr_idx->ofdmlowrate_5g = 11;
+ txpwr_idx->ofdm64qam_5g = 10;
+ txpwr_idx->ofdm256qam_5g = 9;
+ txpwr_idx->ofdm1024qam_5g = 9;
+
+ get_userconfig_txpwr_idx(txpwr_idx);
+
+ if (txpwr_idx->enable == 0) {
+ rwnx_msg_free(rwnx_hw, txpwr_idx_req);
+ return 0;
+ }
+ /* Send the MM_SET_TXPWR_IDX_LVL_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, txpwr_idx_req, 1,
+ MM_SET_TXPWR_IDX_LVL_CFM, NULL);
+
+ return error;
+};
+
+int rwnx_send_txpwr_ofst_req(struct rwnx_hw *rwnx_hw)
+{
+ struct mm_set_txpwr_ofst_req *txpwr_ofst_req;
+ struct txpwr_ofst_conf *txpwr_ofst;
+ int error;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_TXPWR_OFST_REQ message */
+ txpwr_ofst_req =
+ rwnx_msg_zalloc(MM_SET_TXPWR_OFST_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_txpwr_ofst_req));
+
+ if (!txpwr_ofst_req)
+ return -ENOMEM;
+
+ txpwr_ofst = &txpwr_ofst_req->txpwr_ofst;
+ txpwr_ofst->enable = 1;
+ txpwr_ofst->chan_1_4 = 0;
+ txpwr_ofst->chan_5_9 = 0;
+ txpwr_ofst->chan_10_13 = 0;
+ txpwr_ofst->chan_36_64 = 0;
+ txpwr_ofst->chan_100_120 = 0;
+ txpwr_ofst->chan_122_140 = 0;
+ txpwr_ofst->chan_142_165 = 0;
+
+ aic_chip_get_userconfig_txpwr_ofst(rwnx_hw, txpwr_ofst);
+
+ if (txpwr_ofst->enable == 0) {
+ rwnx_msg_free(rwnx_hw, txpwr_ofst_req);
+ return 0;
+ }
+ /* Send the MM_SET_TXPWR_OFST_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, txpwr_ofst_req, 1, MM_SET_TXPWR_OFST_CFM,
+ NULL);
+
+ return error;
+};
+
+int rwnx_send_txpwr_ofst2x_req(struct rwnx_hw *rwnx_hw)
+{
+ struct mm_set_txpwr_ofst_req *txpwr_ofst_req;
+ struct txpwr_ofst2x_conf *txpwr_ofst2x;
+ int error = 0;
+ int type, ch_grp;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_SET_TXPWR_OFST_REQ message */
+ txpwr_ofst_req =
+ rwnx_msg_zalloc(MM_SET_TXPWR_OFST_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_set_txpwr_ofst_req));
+
+ if (!txpwr_ofst_req)
+ return -ENOMEM;
+
+ txpwr_ofst2x = &txpwr_ofst_req->txpwr_ofst2x;
+ txpwr_ofst2x->enable = 0;
+ for (type = 0; type < 3; type++) {
+ for (ch_grp = 0; ch_grp < 6; ch_grp++) {
+ if (ch_grp < 3)
+ txpwr_ofst2x->pwrofst2x_tbl_2g4[type][ch_grp] = 0;
+ txpwr_ofst2x->pwrofst2x_tbl_5g[type][ch_grp] = 0;
+ }
+ }
+
+ aic_chip_get_userconfig_txpwr_ofst2x(rwnx_hw, txpwr_ofst2x);
+
+ if (txpwr_ofst2x->enable) {
+ AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_ofst2x->enable);
+ AICWFDBG(LOGDEBUG,
+ "pwrofst2x 2.4g: [0]:11b, [1]:ofdm_highrate, [2]:ofdm_lowrate\n chan=\t1-4\t5-9\t10-13");
+ for (type = 0; type < 3; type++) {
+ AICWFDBG(LOGDEBUG, "\n [%d] =", type);
+ for (ch_grp = 0; ch_grp < 3; ch_grp++) {
+ AICWFDBG(LOGDEBUG, "\t%d",
+ txpwr_ofst2x->pwrofst2x_tbl_2g4[type][ch_grp]);
+ }
+ }
+ AICWFDBG(LOGDEBUG,
+ "\npwrofst2x 5g: [0]:ofdm_lowrate, [1]:ofdm_highrate, [2]:ofdm_midrate\n chan=\t36-50\t51-64\t98-114\t115-130\t131-146\t147-166");
+ for (type = 0; type < 3; type++) {
+ AICWFDBG(LOGDEBUG, "\n [%d] =", type);
+ for (ch_grp = 0; ch_grp < 6; ch_grp++)
+ AICWFDBG(LOGDEBUG, "\t%d",
+ txpwr_ofst2x->pwrofst2x_tbl_5g[type][ch_grp]);
+ }
+ AICWFDBG(LOGDEBUG, "\n");
+
+ /* Send the MM_SET_TXPWR_OFST_REQ message to UMAC FW */
+ error = rwnx_send_msg(rwnx_hw, txpwr_ofst_req, 1, MM_SET_TXPWR_OFST_CFM,
+ NULL);
+ } else {
+ AICWFDBG(LOGDEBUG, "%s:Do not use txpwr_ofst2x\r\n", __func__);
+ rwnx_msg_free(rwnx_hw, txpwr_ofst_req);
+ }
+
+ return error;
+}
+
+/******************************************************************************
+ * Control messages handling functions (FULLMAC only)
+ *****************************************************************************/
+#ifdef CONFIG_RWNX_FULLMAC
+int rwnx_send_me_config_req(struct rwnx_hw *rwnx_hw)
+{
+ struct me_config_req *req;
+ struct wiphy *wiphy = rwnx_hw->wiphy;
+ struct ieee80211_supported_band *band_2ghz =
+ wiphy->bands[NL80211_BAND_2GHZ];
+ struct ieee80211_sta_ht_cap *ht_cap;
+ struct ieee80211_sta_vht_cap *vht_cap;
+ struct ieee80211_sta_he_cap const *he_cap = NULL;
+
+ u8 *ht_mcs;
+ int i;
+
+ if (rwnx_hw->chip_ops->use_80_bandwidth)
+ rwnx_hw->mod_params->use_80 = true;
+
+ if (rwnx_hw->band_5g_support) {
+ ht_cap = &wiphy->bands[NL80211_BAND_5GHZ]->ht_cap;
+ vht_cap = &wiphy->bands[NL80211_BAND_5GHZ]->vht_cap;
+ } else {
+ ht_cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap;
+ vht_cap = &wiphy->bands[NL80211_BAND_2GHZ]->vht_cap;
+ }
+
+ ht_mcs = (u8 *)&ht_cap->mcs;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the ME_CONFIG_REQ message */
+ req = rwnx_msg_zalloc(ME_CONFIG_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_config_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the ME_CONFIG_REQ message */
+ req->ht_supp = ht_cap->ht_supported;
+ req->vht_supp = vht_cap->vht_supported;
+ req->ht_cap.ht_capa_info =
+ cpu_to_le16(ht_cap->cap | IEEE80211_HT_CAP_LDPC_CODING);
+ req->ht_cap.a_mpdu_param =
+ ht_cap->ampdu_factor |
+ (ht_cap->ampdu_density << IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+ for (i = 0; i < sizeof(ht_cap->mcs); i++)
+ req->ht_cap.mcs_rate[i] = ht_mcs[i];
+ req->ht_cap.ht_extended_capa = 0;
+ req->ht_cap.tx_beamforming_capa = 0;
+ req->ht_cap.asel_capa = 0;
+
+ if (req->vht_supp) {
+ req->vht_cap.vht_capa_info = cpu_to_le32(vht_cap->cap);
+ req->vht_cap.rx_highest = vht_cap->vht_mcs.rx_highest;
+ req->vht_cap.rx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
+ req->vht_cap.tx_highest = vht_cap->vht_mcs.tx_highest;
+ req->vht_cap.tx_mcs_map = vht_cap->vht_mcs.tx_mcs_map;
+ }
+
+ he_cap = ieee80211_get_he_iftype_cap(band_2ghz, NL80211_IFTYPE_STATION);
+ if (he_cap) {
+ req->he_supp = he_cap->has_he;
+ for (i = 0; i < ARRAY_SIZE(he_cap->he_cap_elem.mac_cap_info); i++)
+ req->he_cap.mac_cap_info[i] = he_cap->he_cap_elem.mac_cap_info[i];
+
+ for (i = 0; i < ARRAY_SIZE(he_cap->he_cap_elem.phy_cap_info); i++)
+ req->he_cap.phy_cap_info[i] = he_cap->he_cap_elem.phy_cap_info[i];
+
+ req->he_cap.mcs_supp.rx_mcs_80 = he_cap->he_mcs_nss_supp.rx_mcs_80;
+ req->he_cap.mcs_supp.tx_mcs_80 = he_cap->he_mcs_nss_supp.tx_mcs_80;
+ req->he_cap.mcs_supp.rx_mcs_160 = he_cap->he_mcs_nss_supp.rx_mcs_160;
+ req->he_cap.mcs_supp.tx_mcs_160 = he_cap->he_mcs_nss_supp.tx_mcs_160;
+ req->he_cap.mcs_supp.rx_mcs_80p80 =
+ he_cap->he_mcs_nss_supp.rx_mcs_80p80;
+ req->he_cap.mcs_supp.tx_mcs_80p80 =
+ he_cap->he_mcs_nss_supp.tx_mcs_80p80;
+ for (i = 0; i < MAC_HE_PPE_THRES_MAX_LEN; i++)
+ req->he_cap.ppe_thres[i] = he_cap->ppe_thres[i];
+
+ req->he_ul_on = rwnx_hw->mod_params->he_ul_on;
+ }
+ req->ps_on = rwnx_hw->mod_params->ps_on;
+ req->dpsm = rwnx_hw->mod_params->dpsm;
+ req->tx_lft = rwnx_hw->mod_params->tx_lft;
+ req->ant_div_on = rwnx_hw->mod_params->ant_div;
+ if (rwnx_hw->mod_params->use_80)
+ req->phy_bw_max = PHY_CHNL_BW_80;
+ else if (rwnx_hw->mod_params->use_2040)
+ req->phy_bw_max = PHY_CHNL_BW_40;
+ else
+ req->phy_bw_max = PHY_CHNL_BW_20;
+
+ wiphy_info(wiphy, "AICWF HT supp %d, VHT supp %d, HE supp %d\n", req->ht_supp,
+ req->vht_supp, req->he_supp);
+ /* Send the ME_CONFIG_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, ME_CONFIG_CFM, NULL);
+}
+
+int rwnx_send_me_chan_config_req(struct rwnx_hw *rwnx_hw)
+{
+ struct me_chan_config_req *req;
+ struct wiphy *wiphy = rwnx_hw->wiphy;
+ int i;
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+ u8 enable = 0;
+ s8 max_pwr;
+ struct txpwr_loss_conf txpwr_loss_tmp;
+ struct txpwr_loss_conf *txpwr_loss;
+#endif
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the ME_CHAN_CONFIG_REQ message */
+ req = rwnx_msg_zalloc(ME_CHAN_CONFIG_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_chan_config_req));
+ if (!req)
+ return -ENOMEM;
+
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+ txpwr_loss = &txpwr_loss_tmp;
+ get_userconfig_txpwr_loss(txpwr_loss);
+
+ if (txpwr_loss->loss_enable_2g4 == 1)
+ AICWFDBG(LOGINFO, "%s:loss_value_2g4: %d\r\n", __func__,
+ txpwr_loss->loss_value_2g4);
+ if (txpwr_loss->loss_enable_5g == 1)
+ AICWFDBG(LOGINFO, "%s:loss_value_5g: %d\r\n", __func__,
+ txpwr_loss->loss_value_5g);
+#endif
+
+ req->chan2G4_cnt = 0;
+ if (wiphy->bands[NL80211_BAND_2GHZ]) {
+ struct ieee80211_supported_band *b = wiphy->bands[NL80211_BAND_2GHZ];
+
+ for (i = 0; i < b->n_channels; i++) {
+ req->chan2G4[req->chan2G4_cnt].flags = 0;
+
+ if (b->channels[i].flags & IEEE80211_CHAN_DISABLED)
+ req->chan2G4[req->chan2G4_cnt].flags |= CHAN_DISABLED;
+ req->chan2G4[req->chan2G4_cnt].flags |=
+ get_chan_flags(b->channels[i].flags);
+ req->chan2G4[req->chan2G4_cnt].band = NL80211_BAND_2GHZ;
+ req->chan2G4[req->chan2G4_cnt].freq = b->channels[i].center_freq;
+ req->chan2G4[req->chan2G4_cnt].tx_power =
+ chan_to_fw_pwr(b->channels[i].max_power);
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+ max_pwr = get_powerlimit_by_freq(PHY_BAND_2G4,
+ req->chan2G4[req->chan2G4_cnt].freq,
+ &enable);
+ if (txpwr_loss->loss_enable_2g4 == 1)
+ max_pwr -= txpwr_loss->loss_value_2g4;
+ if (enable) {
+ if (req->chan2G4[req->chan2G4_cnt].tx_power > max_pwr)
+ req->chan2G4[req->chan2G4_cnt].tx_power = max_pwr;
+ }
+#endif
+ req->chan2G4_cnt++;
+ if (req->chan2G4_cnt == MAC_DOMAINCHANNEL_24G_MAX)
+ break;
+ }
+ }
+
+ req->chan5G_cnt = 0;
+ if (wiphy->bands[NL80211_BAND_5GHZ]) {
+ struct ieee80211_supported_band *b = wiphy->bands[NL80211_BAND_5GHZ];
+
+ for (i = 0; i < b->n_channels; i++) {
+ req->chan5G[req->chan5G_cnt].flags = 0;
+ if (b->channels[i].flags & IEEE80211_CHAN_DISABLED)
+ req->chan5G[req->chan5G_cnt].flags |= CHAN_DISABLED;
+ req->chan5G[req->chan5G_cnt].flags |=
+ get_chan_flags(b->channels[i].flags);
+ req->chan5G[req->chan5G_cnt].band = NL80211_BAND_5GHZ;
+ req->chan5G[req->chan5G_cnt].freq = b->channels[i].center_freq;
+ req->chan5G[req->chan5G_cnt].tx_power =
+ chan_to_fw_pwr(b->channels[i].max_power);
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+ max_pwr = get_powerlimit_by_freq(PHY_BAND_5G,
+ req->chan5G[req->chan5G_cnt].freq,
+ &enable);
+ if (txpwr_loss->loss_enable_5g == 1)
+ max_pwr -= txpwr_loss->loss_value_5g;
+ if (enable) {
+ if (req->chan5G[req->chan5G_cnt].tx_power > max_pwr)
+ req->chan5G[req->chan5G_cnt].tx_power = max_pwr;
+ }
+#endif
+ req->chan5G_cnt++;
+ if (req->chan5G_cnt == MAC_DOMAINCHANNEL_5G_MAX)
+ break;
+ }
+ }
+
+ /* Send the ME_CHAN_CONFIG_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, ME_CHAN_CONFIG_CFM, NULL);
+}
+
+int rwnx_send_me_set_control_port_req(struct rwnx_hw *rwnx_hw, bool opened,
+ u8 sta_idx)
+{
+ struct me_set_control_port_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the ME_SET_CONTROL_PORT_REQ message */
+ req = rwnx_msg_zalloc(ME_SET_CONTROL_PORT_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_set_control_port_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the ME_SET_CONTROL_PORT_REQ message */
+ req->sta_idx = sta_idx;
+ req->control_port_open = opened;
+
+ /* Send the ME_SET_CONTROL_PORT_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, ME_SET_CONTROL_PORT_CFM, NULL);
+}
+
+int rwnx_send_me_sta_add(struct rwnx_hw *rwnx_hw,
+ struct station_parameters *params, const u8 *mac,
+ u8 inst_nbr, struct me_sta_add_cfm *cfm)
+{
+ struct me_sta_add_req *req;
+ struct link_station_parameters *link_sta_params = ¶ms->link_sta_params;
+ struct rwnx_vif *rwnx_vif = rwnx_hw->vif_table[inst_nbr];
+
+ u8 *ht_mcs = (u8 *)&link_sta_params->ht_capa->mcs;
+
+ int i;
+
+ /* Build the MM_STA_ADD_REQ message */
+ req = rwnx_msg_zalloc(ME_STA_ADD_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_sta_add_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_STA_ADD_REQ message */
+ memcpy(&req->mac_addr.array[0], mac, ETH_ALEN);
+
+ req->rate_set.length = link_sta_params->supported_rates_len;
+ for (i = 0; i < link_sta_params->supported_rates_len; i++)
+ req->rate_set.array[i] = link_sta_params->supported_rates[i];
+
+ req->flags = 0;
+ if (link_sta_params->ht_capa) {
+ const struct ieee80211_ht_cap *ht_capa = link_sta_params->ht_capa;
+
+ req->flags |= STA_HT_CAPA;
+ req->ht_cap.ht_capa_info = ht_capa->cap_info;
+ req->ht_cap.a_mpdu_param = ht_capa->ampdu_params_info;
+ for (i = 0; i < sizeof(ht_capa->mcs); i++)
+ req->ht_cap.mcs_rate[i] = ht_mcs[i];
+ req->ht_cap.ht_extended_capa = ht_capa->extended_ht_cap_info;
+ req->ht_cap.tx_beamforming_capa = ht_capa->tx_BF_cap_info;
+ req->ht_cap.asel_capa = ht_capa->antenna_selection_info;
+ }
+
+ if (link_sta_params->vht_capa) {
+ const struct ieee80211_vht_cap *vht_capa = link_sta_params->vht_capa;
+
+ req->flags |= STA_VHT_CAPA;
+ req->vht_cap.vht_capa_info = vht_capa->vht_cap_info;
+ req->vht_cap.rx_highest = vht_capa->supp_mcs.rx_highest;
+ req->vht_cap.rx_mcs_map = vht_capa->supp_mcs.rx_mcs_map;
+ req->vht_cap.tx_highest = vht_capa->supp_mcs.tx_highest;
+ req->vht_cap.tx_mcs_map = vht_capa->supp_mcs.tx_mcs_map;
+ }
+
+ if (link_sta_params->he_capa) {
+ const struct ieee80211_he_cap_elem *he_capa = link_sta_params->he_capa;
+ struct ieee80211_he_mcs_nss_supp *mcs_nss_supp =
+ (struct ieee80211_he_mcs_nss_supp *)(he_capa + 1);
+
+ req->flags |= STA_HE_CAPA;
+ for (i = 0; i < ARRAY_SIZE(he_capa->mac_cap_info); i++)
+ req->he_cap.mac_cap_info[i] = he_capa->mac_cap_info[i];
+ for (i = 0; i < ARRAY_SIZE(he_capa->phy_cap_info); i++)
+ req->he_cap.phy_cap_info[i] = he_capa->phy_cap_info[i];
+ req->he_cap.mcs_supp.rx_mcs_80 = mcs_nss_supp->rx_mcs_80;
+ req->he_cap.mcs_supp.tx_mcs_80 = mcs_nss_supp->tx_mcs_80;
+ req->he_cap.mcs_supp.rx_mcs_160 = mcs_nss_supp->rx_mcs_160;
+ req->he_cap.mcs_supp.tx_mcs_160 = mcs_nss_supp->tx_mcs_160;
+ req->he_cap.mcs_supp.rx_mcs_80p80 = mcs_nss_supp->rx_mcs_80p80;
+ req->he_cap.mcs_supp.tx_mcs_80p80 = mcs_nss_supp->tx_mcs_80p80;
+ }
+
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME))
+ req->flags |= STA_QOS_CAPA;
+
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_MFP))
+ req->flags |= STA_MFP_CAPA;
+
+ if (link_sta_params->opmode_notif_used) {
+ req->flags |= STA_OPMOD_NOTIF;
+ req->opmode = link_sta_params->opmode_notif_used;
+ }
+
+ req->aid = cpu_to_le16(params->aid);
+ req->uapsd_queues = params->uapsd_queues;
+ req->max_sp_len = params->max_sp * 2;
+ req->vif_idx = inst_nbr;
+
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
+ req->tdls_sta = true;
+ if ((params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) &&
+ !rwnx_vif->tdls_chsw_prohibited)
+ req->tdls_chsw_allowed = true;
+ if (rwnx_vif->tdls_status == TDLS_SETUP_RSP_TX)
+ req->tdls_sta_initiator = true;
+ }
+
+ /* Send the ME_STA_ADD_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, ME_STA_ADD_CFM, cfm);
+}
+
+int rwnx_send_me_sta_del(struct rwnx_hw *rwnx_hw, u8 sta_idx, bool tdls_sta)
+{
+ struct me_sta_del_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_STA_DEL_REQ message */
+ req = rwnx_msg_zalloc(ME_STA_DEL_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_sta_del_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_STA_DEL_REQ message */
+ req->sta_idx = sta_idx;
+ req->tdls_sta = tdls_sta;
+
+ /* Send the ME_STA_DEL_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, ME_STA_DEL_CFM, NULL);
+}
+
+int rwnx_send_me_traffic_ind(struct rwnx_hw *rwnx_hw, u8 sta_idx, bool uapsd,
+ u8 tx_status)
+{
+ struct me_traffic_ind_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the ME_UTRAFFIC_IND_REQ message */
+ req = rwnx_msg_zalloc(ME_TRAFFIC_IND_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_traffic_ind_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the ME_TRAFFIC_IND_REQ message */
+ req->sta_idx = sta_idx;
+ req->tx_avail = tx_status;
+ req->uapsd = uapsd;
+
+ /* Send the ME_TRAFFIC_IND_REQ to UMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, ME_TRAFFIC_IND_CFM, NULL);
+}
+
+int rwnx_send_me_rc_stats(struct rwnx_hw *rwnx_hw, u8 sta_idx,
+ struct me_rc_stats_cfm *cfm)
+{
+ struct me_rc_stats_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the ME_RC_STATS_REQ message */
+ req = rwnx_msg_zalloc(ME_RC_STATS_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_rc_stats_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the ME_RC_STATS_REQ message */
+ req->sta_idx = sta_idx;
+
+ /* Send the ME_RC_STATS_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, ME_RC_STATS_CFM, cfm);
+}
+
+int rwnx_send_me_rc_set_rate(struct rwnx_hw *rwnx_hw, u8 sta_idx, u16 rate_cfg)
+{
+ struct me_rc_set_rate_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the ME_RC_SET_RATE_REQ message */
+ req = rwnx_msg_zalloc(ME_RC_SET_RATE_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_rc_set_rate_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the ME_RC_SET_RATE_REQ message */
+ req->sta_idx = sta_idx;
+ req->fixed_rate_cfg = rate_cfg;
+
+ /* Send the ME_RC_SET_RATE_REQ message to FW */
+ return rwnx_send_msg(rwnx_hw, req, 0, 0, NULL);
+}
+
+int rwnx_send_me_set_ps_mode(struct rwnx_hw *rwnx_hw, u8 ps_mode)
+{
+ struct me_set_ps_mode_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the ME_SET_PS_MODE_REQ message */
+ req = rwnx_msg_zalloc(ME_SET_PS_MODE_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_set_ps_mode_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the ME_SET_PS_MODE_REQ message */
+ req->ps_state = ps_mode;
+
+ /* Send the ME_SET_PS_MODE_REQ message to FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, ME_SET_PS_MODE_CFM, NULL);
+}
+
+int rwnx_send_me_set_lp_level(struct rwnx_hw *rwnx_hw, u8 lp_level, u8 disable_filter)
+{
+ struct me_set_lp_level_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+ AICWFDBG(LOGDEBUG, "lp_lvl: %d %d\n", lp_level, disable_filter);
+ /* Build the ME_SET_LP_LEVEL_REQ message */
+ req = rwnx_msg_zalloc(ME_SET_LP_LEVEL_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_set_lp_level_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the ME_SET_LP_LEVEL_REQ message */
+ req->lp_level = lp_level;
+ req->disable_filter = disable_filter;
+
+ /* Send the ME_SET_LP_LEVEL_REQ message to FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, ME_SET_LP_LEVEL_CFM, NULL);
+}
+
+int rwnx_send_sm_connect_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
+ struct cfg80211_connect_params *sme,
+ struct sm_connect_cfm *cfm)
+{
+ struct sm_connect_req *req;
+ int i;
+ u32 flags = 0;
+ bool gval = false;
+ bool pval = false;
+
+ rwnx_vif->wep_enabled = false;
+ rwnx_vif->wep_auth_err = false;
+ rwnx_vif->last_auth_type = 0;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the SM_CONNECT_REQ message */
+ req = rwnx_msg_zalloc(SM_CONNECT_REQ, TASK_SM, DRV_TASK_ID,
+ sizeof(struct sm_connect_req));
+ if (!req)
+ return -ENOMEM;
+
+ if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40 ||
+ sme->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104)
+ gval = true;
+
+ if (sme->crypto.n_ciphers_pairwise &&
+ (sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP40 ||
+ sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP104))
+ pval = true;
+
+ /* Set parameters for the SM_CONNECT_REQ message */
+ if (sme->crypto.n_ciphers_pairwise &&
+ (sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP40 ||
+ sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_TKIP ||
+ sme->crypto.ciphers_pairwise[0] == WLAN_CIPHER_SUITE_WEP104))
+ flags |= DISABLE_HT;
+
+ if (sme->crypto.control_port)
+ flags |= CONTROL_PORT_HOST;
+
+ if (sme->crypto.control_port_no_encrypt)
+ flags |= CONTROL_PORT_NO_ENC;
+
+ if (use_pairwise_key(&sme->crypto))
+ flags |= WPA_WPA2_IN_USE;
+
+ if (sme->mfp == NL80211_MFP_REQUIRED)
+ flags |= MFP_IN_USE;
+
+ if (rwnx_vif->sta.ap)
+ flags |= REASSOCIATION;
+
+ req->ctrl_port_ethertype = sme->crypto.control_port_ethertype;
+
+ if (sme->bssid)
+ memcpy(&req->bssid, sme->bssid, ETH_ALEN);
+ else
+ req->bssid = mac_addr_bcst;
+#ifdef CONFIG_AIC8800_AUTO_CUSTREG
+ if (rwnx_hw->ccode.auto_set) {
+ memcpy(&rwnx_hw->ccode.bssid, &req->bssid, ETH_ALEN);
+ atomic_set(&rwnx_hw->ccode.link_scan, 1);
+ }
+#endif
+ req->vif_idx = rwnx_vif->vif_index;
+ if (sme->channel) {
+ req->chan.band = sme->channel->band;
+ req->chan.freq = sme->channel->center_freq;
+ req->chan.flags = get_chan_flags(sme->channel->flags);
+ } else {
+ req->chan.freq = (u16)-1;
+ }
+ for (i = 0; i < sme->ssid_len; i++)
+ req->ssid.array[i] = sme->ssid[i];
+ req->ssid.length = sme->ssid_len;
+ req->flags = flags;
+ if (WARN_ON(sme->ie_len > sizeof(req->ie_buf)))
+ goto invalid_param;
+ if (sme->ie_len)
+ memcpy(req->ie_buf, sme->ie, sme->ie_len);
+ req->ie_len = sme->ie_len;
+ req->listen_interval = rwnx_mod_params.listen_itv;
+ req->dont_wait_bcmc = !rwnx_mod_params.listen_bcmc;
+
+ /* Set auth_type */
+ if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC)
+ req->auth_type = WLAN_AUTH_OPEN;
+ else if (sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
+ req->auth_type = WLAN_AUTH_OPEN;
+ else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+ req->auth_type = WLAN_AUTH_SHARED_KEY;
+ else if (sme->auth_type == NL80211_AUTHTYPE_FT)
+ req->auth_type = WLAN_AUTH_FT;
+ else if (sme->auth_type == NL80211_AUTHTYPE_SAE)
+ req->auth_type = WLAN_AUTH_SAE;
+ else
+ goto invalid_param;
+
+ rwnx_vif->sta.auth_type = sme->auth_type;
+
+ /* Set UAPSD queues */
+ req->uapsd_queues = rwnx_mod_params.uapsd_queues;
+
+ rwnx_vif->wep_enabled = pval & gval;
+
+ if (rwnx_vif->wep_enabled)
+ rwnx_vif->last_auth_type = sme->auth_type;
+
+ rwnx_vif->sta.ssid_len = (int)sme->ssid_len;
+ memset(rwnx_vif->sta.ssid, 0, rwnx_vif->sta.ssid_len + 1);
+ memcpy(rwnx_vif->sta.ssid, sme->ssid, rwnx_vif->sta.ssid_len);
+ if (sme->bssid)
+ memcpy(rwnx_vif->sta.bssid, sme->bssid, ETH_ALEN);
+
+ AICWFDBG(LOGDEBUG,
+ "AICWF %s drv_vif_index:%d connect to %s(%d) channel:%d auth_type:%d\r\n",
+ __func__, rwnx_vif->drv_vif_index, rwnx_vif->sta.ssid,
+ rwnx_vif->sta.ssid_len, req->chan.freq, req->auth_type);
+
+ /* Send the SM_CONNECT_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, SM_CONNECT_CFM, cfm);
+
+invalid_param:
+ rwnx_msg_free(rwnx_hw, req);
+ return -EINVAL;
+}
+
+int rwnx_send_sm_disconnect_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif, u16 reason)
+{
+ struct sm_disconnect_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the SM_DISCONNECT_REQ message */
+ req = rwnx_msg_zalloc(SM_DISCONNECT_REQ, TASK_SM, DRV_TASK_ID,
+ sizeof(struct sm_disconnect_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the SM_DISCONNECT_REQ message */
+ req->reason_code = reason;
+ req->vif_idx = rwnx_vif->vif_index;
+
+ /* Send the SM_DISCONNECT_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, SM_DISCONNECT_CFM, NULL);
+}
+
+int rwnx_send_sm_external_auth_required_rsp(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif,
+ u16 status)
+{
+ struct sm_external_auth_required_rsp *rsp;
+
+ /* Build the SM_EXTERNAL_AUTH_CFM message */
+ rsp = rwnx_msg_zalloc(SM_EXTERNAL_AUTH_REQUIRED_RSP, TASK_SM, DRV_TASK_ID,
+ sizeof(struct sm_external_auth_required_rsp));
+ if (!rsp)
+ return -ENOMEM;
+
+ rsp->status = status;
+ rsp->vif_idx = rwnx_vif->vif_index;
+
+ /* send the SM_EXTERNAL_AUTH_REQUIRED_RSP message UMAC FW */
+ return rwnx_send_msg(rwnx_hw, rsp, 1, SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM,
+ NULL);
+}
+
+int rwnx_send_apm_start_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ struct cfg80211_ap_settings *settings,
+ struct apm_start_cfm *cfm,
+ struct rwnx_ipc_elem_var *elem)
+{
+ struct apm_start_req *req;
+ struct rwnx_bcn *bcn = &vif->ap.bcn;
+ u8 *buf;
+ u32 flags = 0;
+ const u8 *rate_ie;
+ u8 rate_len = 0;
+ int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+ const u8 *var_pos;
+ int len, i;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the APM_START_REQ message */
+ req = rwnx_msg_zalloc(APM_START_REQ, TASK_APM, DRV_TASK_ID,
+ sizeof(struct apm_start_req));
+ if (!req)
+ return -ENOMEM;
+
+ // Build the beacon
+ bcn->dtim = (u8)settings->dtim_period;
+ buf = rwnx_build_bcn(bcn, &settings->beacon);
+ if (!buf) {
+ rwnx_msg_free(rwnx_hw, req);
+ return -ENOMEM;
+ }
+
+ // Retrieve the basic rate set from the beacon buffer
+ len = bcn->len - var_offset;
+ var_pos = buf + var_offset;
+
+// Assume that rate higher that 54 Mbps are BSS membership
+
+ rate_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
+ if (rate_ie) {
+ const u8 *rates = rate_ie + 2;
+ u8 rate1 = 0;
+ bool is_basic1;
+
+ for (i = 0; i < rate_ie[1] && rate_len < MAC_RATESET_LEN; i++) {
+ rate1 = rates[i];
+ is_basic1 = ((rate1 & 0x80) && ((rate1 & ~0x80) <= (54 * 2)));
+ if (is_basic1)
+ req->basic_rates.array[rate_len++] = rate1;
+ }
+ }
+ rate_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, var_pos, len);
+ if (rate_ie) {
+ const u8 *rates = rate_ie + 2;
+ u8 rate2 = 0;
+ bool is_basic2;
+
+ for (i = 0; i < rate_ie[1] && rate_len < MAC_RATESET_LEN; i++) {
+ rate2 = rates[i];
+ is_basic2 = ((rate2 & 0x80) && ((rate2 & ~0x80) <= (54 * 2)));
+ if (is_basic2)
+ req->basic_rates.array[rate_len++] = rate2;
+ }
+ }
+ req->basic_rates.length = rate_len;
+
+ rwnx_send_bcn(rwnx_hw, buf, vif->vif_index, bcn->len);
+
+ /* Set parameters for the APM_START_REQ message */
+ req->vif_idx = vif->vif_index;
+ req->bcn_addr = elem->dma_addr;
+ req->bcn_len = bcn->len;
+ req->tim_oft = bcn->head_len;
+ req->tim_len = bcn->tim_len;
+ req->chan.band = settings->chandef.chan->band;
+ req->chan.freq = settings->chandef.chan->center_freq;
+ req->chan.flags = 0;
+ req->chan.tx_power = chan_to_fw_pwr(settings->chandef.chan->max_power);
+ req->center_freq1 = settings->chandef.center_freq1;
+ req->center_freq2 = settings->chandef.center_freq2;
+ req->ch_width = bw2chnl[settings->chandef.width];
+ req->bcn_int = settings->beacon_interval;
+
+ if (settings->crypto.control_port)
+ flags |= CONTROL_PORT_HOST;
+
+ if (settings->crypto.control_port_no_encrypt)
+ flags |= CONTROL_PORT_NO_ENC;
+
+ if (use_pairwise_key(&settings->crypto))
+ flags |= WPA_WPA2_IN_USE;
+
+ if (settings->crypto.control_port_ethertype)
+ req->ctrl_port_ethertype = settings->crypto.control_port_ethertype;
+ else
+ req->ctrl_port_ethertype = cpu_to_be16(ETH_P_PAE);
+ req->flags = flags;
+
+ /* Send the APM_START_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, APM_START_CFM, cfm);
+}
+
+int rwnx_send_apm_stop_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif)
+{
+ struct apm_stop_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the APM_STOP_REQ message */
+ req = rwnx_msg_zalloc(APM_STOP_REQ, TASK_APM, DRV_TASK_ID,
+ sizeof(struct apm_stop_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the APM_STOP_REQ message */
+ req->vif_idx = vif->vif_index;
+
+ /* Send the APM_STOP_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, APM_STOP_CFM, NULL);
+}
+
+#define P2P_WILDCARD_SSID "DIRECT-"
+#define P2P_WILDCARD_SSID_LEN (sizeof(P2P_WILDCARD_SSID) - 1)
+
+#ifdef CONFIG_AIC8800_SET_VENDOR_EXTENSION_IE
+u8 vendor_extension_data[256];
+u8 vendor_extension_len;
+
+static void rwnx_insert_vendor_extension_data(struct scanu_vendor_ie_req *ie_req)
+{
+ u8 temp_ie[256];
+ u8 vendor_extension_subelement[3] = {0x00, 0x37, 0x2A};
+ u8 vendor_extension_id[2] = {0x10, 0x49};
+ int index = 0;
+ int vendor_extension_subelement_len = 0;
+
+ memset(temp_ie, 0, 256);
+
+ // find vendor_extension_subelement
+ for (index = 0; index < ie_req->add_ie_len; index++) {
+ if (ie_req->ie[index] == vendor_extension_id[0]) {
+ index++;
+ if (index == ie_req->add_ie_len)
+ return;
+
+ if (ie_req->ie[index] == vendor_extension_id[1] &&
+ ie_req->ie[index + 3] == vendor_extension_subelement[0] &&
+ ie_req->ie[index + 4] == vendor_extension_subelement[1] &&
+ ie_req->ie[index + 5] == vendor_extension_subelement[2]) {
+ index = index + 2;
+ vendor_extension_subelement_len = ie_req->ie[index];
+ AICWFDBG(LOGDEBUG,
+ "AICWF %s find vendor_extension_subelement,index:%d len:%d\r\n",
+ __func__, index, ie_req->ie[index]);
+ break;
+ }
+ }
+ }
+ index = index + vendor_extension_subelement_len;
+
+ // insert vendor extension
+ memcpy(&temp_ie[0], ie_req->ie, index + 1);
+ memcpy(&temp_ie[index + 1], vendor_extension_data,
+ vendor_extension_len /*sizeof(vendor_extension_data) */);
+ memcpy(&temp_ie[index + 1 +
+ vendor_extension_len /*sizeof(vendor_extension_data) */],
+ &ie_req->ie[index + 1], ie_req->add_ie_len - index);
+
+ memcpy(ie_req->ie, temp_ie,
+ ie_req->add_ie_len +
+ vendor_extension_len /*sizeof(vendor_extension_data) */);
+ ie_req->add_ie_len =
+ ie_req->add_ie_len +
+ vendor_extension_len /*sizeof(vendor_extension_data) */;
+ ie_req->ie[1] =
+ ie_req->ie[1] + vendor_extension_len /*sizeof(vendor_extension_data) */;
+
+ // rwnx_data_dump((char*)__func__, (void*)ie_req->ie,
+ // ie_req->add_ie_len);
+}
+#endif // CONFIG_AIC8800_SET_VENDOR_EXTENSION_IE
+
+int rwnx_send_scanu_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
+ struct cfg80211_scan_request *param)
+{
+ struct scanu_start_req *req = NULL;
+ struct scanu_vendor_ie_req *ie_req = NULL;
+ struct mm_add_if_cfm add_if_cfm;
+ int i;
+ u8 chan_flags = 0;
+ int err;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the SCANU_START_REQ message */
+ req = rwnx_msg_zalloc(SCANU_START_REQ, TASK_SCANU, DRV_TASK_ID,
+ sizeof(struct scanu_start_req));
+ if (!req)
+ return -ENOMEM;
+
+ rwnx_hw->scanning = 1;
+ /* Set parameters */
+ req->vif_idx = rwnx_vif->vif_index;
+ req->chan_cnt = (u8)min_t(int, SCAN_CHANNEL_MAX, param->n_channels);
+
+#ifdef CONFIG_AIC8800_AUTO_CUSTREG
+ if (rwnx_hw->ccode.ccode_set || rwnx_hw->ccode.ccode_cnt >= MAX_SEARCH_CNT)
+ req->ssid_cnt = (u8)min_t(int, SCAN_SSID_MAX, param->n_ssids);
+ else
+ req->ssid_cnt = (u8)min_t(int, 0, param->n_ssids);
+#else
+ req->ssid_cnt = (u8)min_t(int, SCAN_SSID_MAX, param->n_ssids);
+#endif
+
+ req->bssid = mac_addr_bcst;
+ req->no_cck = param->no_cck;
+ if (param->duration_mandatory)
+ // req->duration = ieee80211_tu_to_usec(param->duration);
+ req->duration = 0;
+
+#ifdef AIC8800_RADAR_OR_IR_DETECT
+ if (req->ssid_cnt == 0)
+ chan_flags |= CHAN_NO_IR;
+#endif
+ for (i = 0; i < req->ssid_cnt; i++) {
+ int j;
+
+ for (j = 0; j < param->ssids[i].ssid_len; j++)
+ req->ssid[i].array[j] = param->ssids[i].ssid[j];
+ req->ssid[i].length = param->ssids[i].ssid_len;
+
+ if (!memcmp(P2P_WILDCARD_SSID, param->ssids[i].ssid,
+ P2P_WILDCARD_SSID_LEN)) {
+ AICWFDBG(LOGINFO, "p2p scanu:%d,%d,%d\n", rwnx_vif->vif_index,
+ rwnx_vif->is_p2p_vif, rwnx_hw->is_p2p_alive);
+#ifdef CONFIG_AIC8800_USE_P2P0
+ if (rwnx_vif->is_p2p_vif && !rwnx_hw->is_p2p_alive) {
+#else
+ if (rwnx_vif == rwnx_hw->p2p_dev_vif && !rwnx_vif->up) {
+#endif
+ err = rwnx_send_add_if(rwnx_hw, rwnx_vif->wdev.address,
+ RWNX_VIF_TYPE(rwnx_vif), false,
+ &add_if_cfm);
+ if (err)
+ goto error;
+
+ if (add_if_cfm.status != 0)
+ return -EIO;
+
+ /* Save the index retrieved from LMAC */
+ spin_lock_bh(&rwnx_hw->cb_lock);
+ rwnx_vif->vif_index = add_if_cfm.inst_nbr;
+ rwnx_vif->up = true;
+ rwnx_hw->vif_started++;
+ rwnx_hw->vif_table[add_if_cfm.inst_nbr] = rwnx_vif;
+ spin_unlock_bh(&rwnx_hw->cb_lock);
+ }
+ rwnx_hw->is_p2p_alive = 1;
+#ifndef CONFIG_AIC8800_USE_P2P0
+ mod_timer(&rwnx_hw->p2p_alive_timer,
+ jiffies + msecs_to_jiffies(1000));
+ atomic_set(&rwnx_hw->p2p_alive_timer_count, 0);
+#endif
+ AICWFDBG(LOGINFO, "p2p scan start\n");
+ }
+ }
+
+ if (param->ie) {
+ ie_req = rwnx_msg_zalloc(SCANU_VENDOR_IE_REQ, TASK_SCANU, DRV_TASK_ID,
+ sizeof(struct scanu_vendor_ie_req));
+ if (!ie_req)
+ return -ENOMEM;
+
+ ie_req->add_ie_len = param->ie_len;
+ ie_req->vif_idx = rwnx_vif->vif_index;
+ memcpy(ie_req->ie, param->ie, param->ie_len);
+#ifdef CONFIG_AIC8800_SET_VENDOR_EXTENSION_IE
+ rwnx_insert_vendor_extension_data(ie_req);
+#endif // CONFIG_AIC8800_SET_VENDOR_EXTENSION_IE
+ req->add_ie_len = 0;
+ req->add_ies = 0;
+
+ err = rwnx_send_msg(rwnx_hw, ie_req, 1, SCANU_VENDOR_IE_CFM, NULL);
+ if (err)
+ goto error;
+ } else {
+ req->add_ie_len = 0;
+ req->add_ies = 0;
+ }
+
+ for (i = 0; i < req->chan_cnt; i++) {
+ struct ieee80211_channel *chan = param->channels[i];
+
+ AICWFDBG(LOGDEBUG, "scan channel:%d(%d) \r\n",
+ ieee80211_frequency_to_channel(chan->center_freq),
+ chan->center_freq);
+ req->chan[i].band = chan->band;
+ req->chan[i].freq = chan->center_freq;
+ req->chan[i].flags = chan_flags | get_chan_flags(chan->flags);
+ req->chan[i].tx_power = chan_to_fw_pwr(chan->max_reg_power);
+ }
+
+ /* Send the SCANU_START_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, SCANU_START_CFM_ADDTIONAL, NULL);
+error:
+ if (req)
+ rwnx_msg_free(rwnx_hw, req);
+ if (ie_req)
+ rwnx_msg_free(rwnx_hw, ie_req);
+ return -ENOMEM;
+}
+
+int rwnx_send_scanu_cancel_req(struct rwnx_hw *rwnx_hw,
+ struct scan_cancel_cfm *cfm)
+{
+ struct scan_cancel_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the SCAN_CANCEL_REQ message */
+ req = rwnx_msg_zalloc(SCANU_CANCEL_REQ, TASK_SCANU, DRV_TASK_ID,
+ sizeof(struct scan_cancel_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Send the SCAN_CANCEL_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, SCANU_CANCEL_CFM, cfm);
+}
+
+int rwnx_send_apm_start_cac_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ struct cfg80211_chan_def *chandef,
+ struct apm_start_cac_cfm *cfm)
+{
+ struct apm_start_cac_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the APM_START_CAC_REQ message */
+ req = rwnx_msg_zalloc(APM_START_CAC_REQ, TASK_APM, DRV_TASK_ID,
+ sizeof(struct apm_start_cac_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the APM_START_CAC_REQ message */
+ req->vif_idx = vif->vif_index;
+ req->chan.band = chandef->chan->band;
+ req->chan.freq = chandef->chan->center_freq;
+ req->chan.flags = 0;
+ req->center_freq1 = chandef->center_freq1;
+ req->center_freq2 = chandef->center_freq2;
+ req->ch_width = bw2chnl[chandef->width];
+
+ /* Send the APM_START_CAC_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, APM_START_CAC_CFM, cfm);
+}
+
+int rwnx_send_apm_stop_cac_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif)
+{
+ struct apm_stop_cac_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the APM_STOP_CAC_REQ message */
+ req = rwnx_msg_zalloc(APM_STOP_CAC_REQ, TASK_APM, DRV_TASK_ID,
+ sizeof(struct apm_stop_cac_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the APM_STOP_CAC_REQ message */
+ req->vif_idx = vif->vif_index;
+
+ /* Send the APM_STOP_CAC_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, APM_STOP_CAC_CFM, NULL);
+}
+
+int rwnx_send_mesh_start_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ const struct mesh_config *conf,
+ const struct mesh_setup *setup,
+ struct mesh_start_cfm *cfm)
+{
+ // Message to send
+ struct mesh_start_req *req;
+ // Supported basic rates
+ struct ieee80211_supported_band *band_2ghz =
+ rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
+ /* Counter */
+ int i;
+ /* Return status */
+ int status;
+ /* DMA Address to be unmapped after confirmation reception */
+ u32 dma_addr = 0;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MESH_START_REQ message */
+ req = rwnx_msg_zalloc(MESH_START_REQ, TASK_MESH, DRV_TASK_ID,
+ sizeof(struct mesh_start_req));
+ if (!req)
+ return -ENOMEM;
+
+ req->vif_index = vif->vif_index;
+ req->bcn_int = setup->beacon_interval;
+ req->dtim_period = setup->dtim_period;
+ req->mesh_id_len = setup->mesh_id_len;
+
+ for (i = 0; i < setup->mesh_id_len; i++)
+ req->mesh_id[i] = *(setup->mesh_id + i);
+
+ req->user_mpm = setup->user_mpm;
+ req->is_auth = setup->is_authenticated;
+ req->auth_id = setup->auth_id;
+ req->ie_len = setup->ie_len;
+
+ if (setup->ie_len) {
+ /*
+ * Need to provide a Virtual Address to the MAC so that it can
+ * download the additional information elements.
+ */
+ req->ie_addr = dma_map_single(rwnx_hw->dev, (void *)setup->ie,
+ setup->ie_len, DMA_FROM_DEVICE);
+
+ /* Check DMA mapping result */
+ if (dma_mapping_error(rwnx_hw->dev, req->ie_addr)) {
+ AICWFDBG(LOGDEBUG, KERN_CRIT
+ "AICWF %s - DMA Mapping error on additional IEs\n",
+ __func__);
+
+ /* Consider there is no Additional IEs */
+ req->ie_len = 0;
+ } else {
+ /* Store DMA Address so that we can unmap the memory section
+ * once MESH_START_CFM is received
+ */
+ dma_addr = req->ie_addr;
+ }
+ }
+
+ /* Provide rate information */
+ req->basic_rates.length = 0;
+ for (i = 0; i < band_2ghz->n_bitrates; i++) {
+ u16 rate = band_2ghz->bitrates[i].bitrate;
+
+ /* Read value is in units of 100 Kbps, provided value is in units
+ * of 1Mbps, and multiplied by 2 so that 5.5 becomes 11
+ */
+ rate = (rate << 1) / 10;
+
+ if (setup->basic_rates & CO_BIT(i))
+ rate |= 0x80;
+
+ req->basic_rates.array[i] = (u8)rate;
+ req->basic_rates.length++;
+ }
+
+ /* Provide channel information */
+ req->chan.band = setup->chandef.chan->band;
+ req->chan.freq = setup->chandef.chan->center_freq;
+ req->chan.flags = 0;
+ req->chan.tx_power = chan_to_fw_pwr(setup->chandef.chan->max_power);
+ req->center_freq1 = setup->chandef.center_freq1;
+ req->center_freq2 = setup->chandef.center_freq2;
+ req->ch_width = bw2chnl[setup->chandef.width];
+
+ /* Send the MESH_START_REQ message to UMAC FW */
+ status = rwnx_send_msg(rwnx_hw, req, 1, MESH_START_CFM, cfm);
+
+ /* Unmap DMA area */
+ if (setup->ie_len)
+ dma_unmap_single(rwnx_hw->dev, dma_addr, setup->ie_len, DMA_TO_DEVICE);
+
+ /* Return the status */
+ return status;
+}
+
+int rwnx_send_mesh_stop_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ struct mesh_stop_cfm *cfm)
+{
+ // Message to send
+ struct mesh_stop_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MESH_STOP_REQ message */
+ req = rwnx_msg_zalloc(MESH_STOP_REQ, TASK_MESH, DRV_TASK_ID,
+ sizeof(struct mesh_stop_req));
+ if (!req)
+ return -ENOMEM;
+
+ req->vif_idx = vif->vif_index;
+
+ /* Send the MESH_STOP_REQ message to UMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MESH_STOP_CFM, cfm);
+}
+
+int rwnx_send_mesh_update_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ u32 mask, const struct mesh_config *p_mconf,
+ struct mesh_update_cfm *cfm)
+{
+ // Message to send
+ struct mesh_update_req *req;
+ // Keep only bit for fields which can be updated
+ u32 supp_mask = (mask << 1) & (CO_BIT(NL80211_MESHCONF_GATE_ANNOUNCEMENTS) |
+ CO_BIT(NL80211_MESHCONF_HWMP_ROOTMODE) |
+ CO_BIT(NL80211_MESHCONF_FORWARDING) |
+ CO_BIT(NL80211_MESHCONF_POWER_MODE));
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ if (!supp_mask)
+ return -ENOENT;
+
+ /* Build the MESH_UPDATE_REQ message */
+ req = rwnx_msg_zalloc(MESH_UPDATE_REQ, TASK_MESH, DRV_TASK_ID,
+ sizeof(struct mesh_update_req));
+
+ if (!req)
+ return -ENOMEM;
+
+ req->vif_idx = vif->vif_index;
+
+ if (supp_mask & CO_BIT(NL80211_MESHCONF_GATE_ANNOUNCEMENTS)) {
+ req->flags |= CO_BIT(MESH_UPDATE_FLAGS_GATE_MODE_BIT);
+ req->gate_announ = p_mconf->dot11MeshGateAnnouncementProtocol;
+ }
+
+ if (supp_mask & CO_BIT(NL80211_MESHCONF_HWMP_ROOTMODE)) {
+ req->flags |= CO_BIT(MESH_UPDATE_FLAGS_ROOT_MODE_BIT);
+ req->root_mode = p_mconf->dot11MeshHWMPRootMode;
+ }
+
+ if (supp_mask & CO_BIT(NL80211_MESHCONF_FORWARDING)) {
+ req->flags |= CO_BIT(MESH_UPDATE_FLAGS_MESH_FWD_BIT);
+ req->mesh_forward = p_mconf->dot11MeshForwarding;
+ }
+
+ if (supp_mask & CO_BIT(NL80211_MESHCONF_POWER_MODE)) {
+ req->flags |= CO_BIT(MESH_UPDATE_FLAGS_LOCAL_PSM_BIT);
+ req->local_ps_mode = p_mconf->power_mode;
+ }
+
+ /* Send the MESH_UPDATE_REQ message to UMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MESH_UPDATE_CFM, cfm);
+}
+
+int rwnx_send_mesh_peer_info_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ u8 sta_idx, struct mesh_peer_info_cfm *cfm)
+{
+ // Message to send
+ struct mesh_peer_info_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MESH_PEER_INFO_REQ message */
+ req = rwnx_msg_zalloc(MESH_PEER_INFO_REQ, TASK_MESH, DRV_TASK_ID,
+ sizeof(struct mesh_peer_info_req));
+ if (!req)
+ return -ENOMEM;
+
+ req->sta_idx = sta_idx;
+
+ /* Send the MESH_PEER_INFO_REQ message to UMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MESH_PEER_INFO_CFM, cfm);
+}
+
+void rwnx_send_mesh_peer_update_ntf(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *vif, u8 sta_idx,
+ u8 mlink_state)
+{
+ // Message to send
+ struct mesh_peer_update_ntf *ntf;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MESH_PEER_UPDATE_NTF message */
+ ntf = rwnx_msg_zalloc(MESH_PEER_UPDATE_NTF, TASK_MESH, DRV_TASK_ID,
+ sizeof(struct mesh_peer_update_ntf));
+
+ if (ntf) {
+ ntf->vif_idx = vif->vif_index;
+ ntf->sta_idx = sta_idx;
+ ntf->state = mlink_state;
+
+ /* Send the MESH_PEER_INFO_REQ message to UMAC FW */
+ rwnx_send_msg(rwnx_hw, ntf, 0, 0, NULL);
+ }
+}
+
+void rwnx_send_mesh_path_create_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *vif, u8 *tgt_addr)
+{
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Check if we are already waiting for a confirmation */
+ if (!vif->ap.create_path) {
+ // Message to send
+ struct mesh_path_create_req *req;
+
+ /* Build the MESH_PATH_CREATE_REQ message */
+ req = rwnx_msg_zalloc(MESH_PATH_CREATE_REQ, TASK_MESH, DRV_TASK_ID,
+ sizeof(struct mesh_path_create_req));
+
+ if (req) {
+ req->vif_idx = vif->vif_index;
+ memcpy(&req->tgt_mac_addr, tgt_addr, ETH_ALEN);
+
+ vif->ap.create_path = true;
+
+ /* Send the MESH_PATH_CREATE_REQ message to UMAC FW */
+ rwnx_send_msg(rwnx_hw, req, 0, 0, NULL);
+ }
+ }
+}
+
+int rwnx_send_mesh_path_update_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *vif, const u8 *tgt_addr,
+ const u8 *p_nhop_addr,
+ struct mesh_path_update_cfm *cfm)
+{
+ // Message to send
+ struct mesh_path_update_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MESH_PATH_UPDATE_REQ message */
+ req = rwnx_msg_zalloc(MESH_PATH_UPDATE_REQ, TASK_MESH, DRV_TASK_ID,
+ sizeof(struct mesh_path_update_req));
+ if (!req)
+ return -ENOMEM;
+
+ req->delete = (!p_nhop_addr);
+ req->vif_idx = vif->vif_index;
+ memcpy(&req->tgt_mac_addr, tgt_addr, ETH_ALEN);
+
+ if (p_nhop_addr)
+ memcpy(&req->nhop_mac_addr, p_nhop_addr, ETH_ALEN);
+
+ /* Send the MESH_PATH_UPDATE_REQ message to UMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MESH_PATH_UPDATE_CFM, cfm);
+}
+
+void rwnx_send_mesh_proxy_add_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ u8 *ext_addr)
+{
+ // Message to send
+ struct mesh_proxy_add_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MESH_PROXY_ADD_REQ message */
+ req = rwnx_msg_zalloc(MESH_PROXY_ADD_REQ, TASK_MESH, DRV_TASK_ID,
+ sizeof(struct mesh_proxy_add_req));
+
+ if (req) {
+ req->vif_idx = vif->vif_index;
+ memcpy(&req->ext_sta_addr, ext_addr, ETH_ALEN);
+
+ /* Send the MESH_PROXY_ADD_REQ message to UMAC FW */
+ rwnx_send_msg(rwnx_hw, req, 0, 0, NULL);
+ }
+}
+
+int rwnx_send_tdls_peer_traffic_ind_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif)
+{
+ struct tdls_peer_traffic_ind_req *tdls_peer_traffic_ind_req;
+
+ if (!rwnx_vif->sta.tdls_sta)
+ return -ENOLINK;
+
+ /* Build the TDLS_PEER_TRAFFIC_IND_REQ message */
+ tdls_peer_traffic_ind_req =
+ rwnx_msg_zalloc(TDLS_PEER_TRAFFIC_IND_REQ, TASK_TDLS, DRV_TASK_ID,
+ sizeof(struct tdls_peer_traffic_ind_req));
+
+ if (!tdls_peer_traffic_ind_req)
+ return -ENOMEM;
+
+ /* Set parameters for the TDLS_PEER_TRAFFIC_IND_REQ message */
+ tdls_peer_traffic_ind_req->vif_index = rwnx_vif->vif_index;
+ tdls_peer_traffic_ind_req->sta_idx = rwnx_vif->sta.tdls_sta->sta_idx;
+ memcpy(&tdls_peer_traffic_ind_req->peer_mac_addr.array[0],
+ rwnx_vif->sta.tdls_sta->mac_addr, ETH_ALEN);
+ tdls_peer_traffic_ind_req->dialog_token = 0; // check dialog token value
+ tdls_peer_traffic_ind_req->last_tid = rwnx_vif->sta.tdls_sta->tdls.last_tid;
+ tdls_peer_traffic_ind_req->last_sn = rwnx_vif->sta.tdls_sta->tdls.last_sn;
+
+ /* Send the TDLS_PEER_TRAFFIC_IND_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, tdls_peer_traffic_ind_req, 0, 0, NULL);
+}
+
+int rwnx_send_config_monitor_req(struct rwnx_hw *rwnx_hw,
+ struct cfg80211_chan_def *chandef,
+ struct me_config_monitor_cfm *cfm)
+{
+ struct me_config_monitor_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the ME_CONFIG_MONITOR_REQ message */
+ req = rwnx_msg_zalloc(ME_CONFIG_MONITOR_REQ, TASK_ME, DRV_TASK_ID,
+ sizeof(struct me_config_monitor_req));
+ if (!req)
+ return -ENOMEM;
+
+ if (chandef) {
+ req->chan_set = true;
+
+ req->chan.band = chandef->chan->band;
+ req->chan.type = bw2chnl[chandef->width];
+ req->chan.prim20_freq = chandef->chan->center_freq;
+ req->chan.center1_freq = chandef->center_freq1;
+ req->chan.center2_freq = chandef->center_freq2;
+ req->chan.tx_power = chan_to_fw_pwr(chandef->chan->max_power);
+
+ if (rwnx_hw->phy.limit_bw)
+ limit_chan_bw(&req->chan.type, req->chan.prim20_freq,
+ &req->chan.center1_freq);
+ } else {
+ req->chan_set = false;
+ }
+
+ req->uf = rwnx_hw->mod_params->uf;
+ req->auto_reply = rwnx_hw->mod_params->auto_reply;
+
+ /* Send the ME_CONFIG_MONITOR_REQ message to FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, ME_CONFIG_MONITOR_CFM, cfm);
+}
+#endif /* CONFIG_RWNX_FULLMAC */
+
+int rwnx_send_tdls_chan_switch_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif,
+ struct rwnx_sta *rwnx_sta,
+ bool sta_initiator, u8 oper_class,
+ struct cfg80211_chan_def *chandef,
+ struct tdls_chan_switch_cfm *cfm)
+{
+ struct tdls_chan_switch_req *tdls_chan_switch_req;
+
+ /* Build the TDLS_CHAN_SWITCH_REQ message */
+ tdls_chan_switch_req =
+ rwnx_msg_zalloc(TDLS_CHAN_SWITCH_REQ, TASK_TDLS, DRV_TASK_ID,
+ sizeof(struct tdls_chan_switch_req));
+
+ if (!tdls_chan_switch_req)
+ return -ENOMEM;
+
+ /* Set parameters for the TDLS_CHAN_SWITCH_REQ message */
+ tdls_chan_switch_req->vif_index = rwnx_vif->vif_index;
+ tdls_chan_switch_req->sta_idx = rwnx_sta->sta_idx;
+ memcpy(&tdls_chan_switch_req->peer_mac_addr.array[0],
+ rwnx_sta_addr(rwnx_sta), ETH_ALEN);
+ tdls_chan_switch_req->initiator = sta_initiator;
+ tdls_chan_switch_req->band = chandef->chan->band;
+ tdls_chan_switch_req->type = bw2chnl[chandef->width];
+ tdls_chan_switch_req->prim20_freq = chandef->chan->center_freq;
+ tdls_chan_switch_req->center1_freq = chandef->center_freq1;
+ tdls_chan_switch_req->center2_freq = chandef->center_freq2;
+ tdls_chan_switch_req->tx_power = chan_to_fw_pwr(chandef->chan->max_power);
+ tdls_chan_switch_req->op_class = oper_class;
+
+ /* Send the TDLS_CHAN_SWITCH_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, tdls_chan_switch_req, 1, TDLS_CHAN_SWITCH_CFM,
+ cfm);
+}
+
+int rwnx_send_tdls_cancel_chan_switch_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif,
+ struct rwnx_sta *rwnx_sta,
+ struct tdls_cancel_chan_switch_cfm *cfm)
+{
+ struct tdls_cancel_chan_switch_req *tdls_cancel_chan_switch_req;
+
+ /* Build the TDLS_CHAN_SWITCH_REQ message */
+ tdls_cancel_chan_switch_req =
+ rwnx_msg_zalloc(TDLS_CANCEL_CHAN_SWITCH_REQ, TASK_TDLS, DRV_TASK_ID,
+ sizeof(struct tdls_cancel_chan_switch_req));
+ if (!tdls_cancel_chan_switch_req)
+ return -ENOMEM;
+
+ /* Set parameters for the TDLS_CHAN_SWITCH_REQ message */
+ tdls_cancel_chan_switch_req->vif_index = rwnx_vif->vif_index;
+ tdls_cancel_chan_switch_req->sta_idx = rwnx_sta->sta_idx;
+ memcpy(&tdls_cancel_chan_switch_req->peer_mac_addr.array[0],
+ rwnx_sta_addr(rwnx_sta), ETH_ALEN);
+
+ /* Send the TDLS_CHAN_SWITCH_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, tdls_cancel_chan_switch_req, 1,
+ TDLS_CANCEL_CHAN_SWITCH_CFM, cfm);
+}
+
+#ifdef CONFIG_RWNX_BFMER
+#ifdef CONFIG_RWNX_FULLMAC
+void rwnx_send_bfmer_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta,
+ const struct ieee80211_vht_cap *vht_cap)
+#endif /* CONFIG_RWNX_FULLMAC */
+{
+ struct mm_bfmer_enable_req *bfmer_en_req;
+#ifdef CONFIG_RWNX_FULLMAC
+ u32 vht_capability;
+ u8 rx_nss = 0;
+#endif /* CONFIG_RWNX_FULLMAC */
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+#ifdef CONFIG_RWNX_FULLMAC
+ if (!vht_cap) {
+#endif /* CONFIG_RWNX_FULLMAC */
+ goto end;
+ }
+
+#ifdef CONFIG_RWNX_FULLMAC
+ vht_capability = le32_to_cpu(vht_cap->vht_cap_info);
+#endif /* CONFIG_RWNX_FULLMAC */
+
+ if (!(vht_capability & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+ goto end;
+
+#ifdef CONFIG_RWNX_FULLMAC
+ rx_nss = rwnx_bfmer_get_rx_nss(vht_cap);
+#endif /* CONFIG_RWNX_FULLMAC */
+
+ /* Allocate a structure that will contain the beamforming report */
+ if (rwnx_bfmer_report_add(rwnx_hw, rwnx_sta,
+ RWNX_BFMER_REPORT_SPACE_SIZE))
+ goto end;
+
+ /* Build the MM_BFMER_ENABLE_REQ message */
+ bfmer_en_req = rwnx_msg_zalloc(MM_BFMER_ENABLE_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_bfmer_enable_req));
+
+ /* Check message allocation */
+ if (!bfmer_en_req) {
+ /* Free memory allocated for the report */
+ rwnx_bfmer_report_del(rwnx_hw, rwnx_sta);
+ /* Do not use beamforming */
+ goto end;
+ }
+
+ /* Provide DMA address to the MAC */
+ bfmer_en_req->host_bfr_addr = rwnx_sta->bfm_report->dma_addr;
+ bfmer_en_req->host_bfr_size = RWNX_BFMER_REPORT_SPACE_SIZE;
+ bfmer_en_req->sta_idx = rwnx_sta->sta_idx;
+#ifdef CONFIG_RWNX_FULLMAC
+ bfmer_en_req->aid = rwnx_sta->aid;
+ bfmer_en_req->rx_nss = rx_nss;
+#endif /* CONFIG_RWNX_FULLMAC */
+
+ if (vht_capability & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)
+ bfmer_en_req->vht_mu_bfmee = true;
+ else
+ bfmer_en_req->vht_mu_bfmee = false;
+
+ /* Send the MM_BFMER_EN_REQ message to LMAC FW */
+ rwnx_send_msg(rwnx_hw, bfmer_en_req, 0, 0, NULL);
+
+end:
+ return;
+}
+
+#ifdef CONFIG_RWNX_MUMIMO_TX
+int rwnx_send_mu_group_update_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_sta *rwnx_sta)
+{
+ struct mm_mu_group_update_req *req;
+ int group_id, i = 0;
+ u64 map;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_MU_GROUP_UPDATE_REQ message */
+ req =
+ rwnx_msg_zalloc(MM_MU_GROUP_UPDATE_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_mu_group_update_req) +
+ rwnx_sta->group_info.cnt * sizeof(req->groups[0]));
+
+ /* Check message allocation */
+ if (!req)
+ return -ENOMEM;
+
+ map = rwnx_sta->group_info.map & RWNX_MU_GROUP_MASK;
+ for (group_id = (fls64(map) - 1); group_id > 0;
+ map &= ~(u64)BIT_ULL(group_id), group_id = (fls64(map) - 1)) {
+ int user_pos = rwnx_mu_group_sta_get_pos(rwnx_hw, rwnx_sta, group_id);
+
+ if (WARN(i >= rwnx_sta->group_info.cnt,
+ "STA%d: Too much group (%d)\n", rwnx_sta->sta_idx, i + 1))
+ break;
+
+ req->groups[i].group_id = group_id;
+ req->groups[i].user_pos = user_pos;
+
+ i++;
+ }
+
+ req->group_cnt = rwnx_sta->group_info.cnt;
+ req->sta_idx = rwnx_sta->sta_idx;
+
+ /* Send the MM_MU_GROUP_UPDATE_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MM_MU_GROUP_UPDATE_CFM, NULL);
+}
+#endif /* CONFIG_RWNX_MUMIMO_TX */
+#endif /* CONFIG_RWNX_BFMER */
+
+/**********************************************************************
+ * Debug Messages
+ *********************************************************************/
+int rwnx_send_dbg_trigger_req(struct rwnx_hw *rwnx_hw, char *msg)
+{
+ struct mm_dbg_trigger_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_DBG_TRIGGER_REQ message */
+ req = rwnx_msg_zalloc(MM_DBG_TRIGGER_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_dbg_trigger_req));
+ if (!req)
+ return -ENOMEM;
+
+ /* Set parameters for the MM_DBG_TRIGGER_REQ message */
+ strscpy(req->error, msg, sizeof(req->error));
+
+ /* Send the MM_DBG_TRIGGER_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 0, -1, NULL);
+}
+
+int rwnx_send_dbg_mem_read_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
+ struct dbg_mem_read_cfm *cfm)
+{
+ struct dbg_mem_read_req *mem_read_req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the DBG_MEM_READ_REQ message */
+ mem_read_req = rwnx_msg_zalloc(DBG_MEM_READ_REQ, TASK_DBG, DRV_TASK_ID,
+ sizeof(struct dbg_mem_read_req));
+ if (!mem_read_req)
+ return -ENOMEM;
+
+ /* Set parameters for the DBG_MEM_READ_REQ message */
+ mem_read_req->memaddr = mem_addr;
+
+ /* Send the DBG_MEM_READ_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, mem_read_req, 1, DBG_MEM_READ_CFM, cfm);
+}
+
+int rwnx_send_dbg_mem_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
+ u32 mem_data)
+{
+ struct dbg_mem_write_req *mem_write_req;
+
+ // RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the DBG_MEM_WRITE_REQ message */
+ mem_write_req = rwnx_msg_zalloc(DBG_MEM_WRITE_REQ, TASK_DBG, DRV_TASK_ID,
+ sizeof(struct dbg_mem_write_req));
+ if (!mem_write_req)
+ return -ENOMEM;
+
+ /* Set parameters for the DBG_MEM_WRITE_REQ message */
+ mem_write_req->memaddr = mem_addr;
+ mem_write_req->memdata = mem_data;
+
+ /* Send the DBG_MEM_WRITE_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, mem_write_req, 1, DBG_MEM_WRITE_CFM, NULL);
+}
+
+int rwnx_send_dbg_mem_mask_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
+ u32 mem_mask, u32 mem_data)
+{
+ struct dbg_mem_mask_write_req *mem_mask_write_req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the DBG_MEM_MASK_WRITE_REQ message */
+ mem_mask_write_req =
+ rwnx_msg_zalloc(DBG_MEM_MASK_WRITE_REQ, TASK_DBG, DRV_TASK_ID,
+ sizeof(struct dbg_mem_mask_write_req));
+ if (!mem_mask_write_req)
+ return -ENOMEM;
+
+ /* Set parameters for the DBG_MEM_MASK_WRITE_REQ message */
+ mem_mask_write_req->memaddr = mem_addr;
+ mem_mask_write_req->memmask = mem_mask;
+ mem_mask_write_req->memdata = mem_data;
+
+ /* Send the DBG_MEM_MASK_WRITE_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, mem_mask_write_req, 1, DBG_MEM_MASK_WRITE_CFM,
+ NULL);
+}
+
+int rwnx_send_rftest_req(struct rwnx_hw *rwnx_hw, u32 cmd, u32 argc,
+ u8 *argv, struct dbg_rftest_cmd_cfm *cfm)
+{
+ struct dbg_rftest_cmd_req *mem_rftest_cmd_req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the DBG_RFTEST_CMD_REQ message */
+ mem_rftest_cmd_req =
+ rwnx_msg_zalloc(DBG_RFTEST_CMD_REQ, TASK_DBG, DRV_TASK_ID,
+ sizeof(struct dbg_rftest_cmd_req));
+ if (!mem_rftest_cmd_req)
+ return -ENOMEM;
+
+ if (argc > 10)
+ return -ENOMEM;
+
+ /* Set parameters for the DBG_MEM_MASK_WRITE_REQ message */
+ mem_rftest_cmd_req->cmd = cmd;
+ mem_rftest_cmd_req->argc = argc;
+ if (argc != 0)
+ memcpy(mem_rftest_cmd_req->argv, argv, argc);
+
+ /* Send the DBG_RFTEST_CMD_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, mem_rftest_cmd_req, 1, DBG_RFTEST_CMD_CFM,
+ cfm);
+}
+
+int rwnx_send_dbg_set_mod_filter_req(struct rwnx_hw *rwnx_hw, u32 filter)
+{
+ struct dbg_set_mod_filter_req *set_mod_filter_req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the DBG_SET_MOD_FILTER_REQ message */
+ set_mod_filter_req =
+ rwnx_msg_zalloc(DBG_SET_MOD_FILTER_REQ, TASK_DBG, DRV_TASK_ID,
+ sizeof(struct dbg_set_mod_filter_req));
+ if (!set_mod_filter_req)
+ return -ENOMEM;
+
+ /* Set parameters for the DBG_SET_MOD_FILTER_REQ message */
+ set_mod_filter_req->mod_filter = filter;
+
+ /* Send the DBG_SET_MOD_FILTER_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, set_mod_filter_req, 1, DBG_SET_MOD_FILTER_CFM,
+ NULL);
+}
+
+int rwnx_send_dbg_set_sev_filter_req(struct rwnx_hw *rwnx_hw, u32 filter)
+{
+ struct dbg_set_sev_filter_req *set_sev_filter_req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the DBG_SET_SEV_FILTER_REQ message */
+ set_sev_filter_req =
+ rwnx_msg_zalloc(DBG_SET_SEV_FILTER_REQ, TASK_DBG, DRV_TASK_ID,
+ sizeof(struct dbg_set_sev_filter_req));
+ if (!set_sev_filter_req)
+ return -ENOMEM;
+
+ /* Set parameters for the DBG_SET_SEV_FILTER_REQ message */
+ set_sev_filter_req->sev_filter = filter;
+
+ /* Send the DBG_SET_SEV_FILTER_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, set_sev_filter_req, 1, DBG_SET_SEV_FILTER_CFM,
+ NULL);
+}
+
+int rwnx_send_dbg_get_sys_stat_req(struct rwnx_hw *rwnx_hw,
+ struct dbg_get_sys_stat_cfm *cfm)
+{
+ void *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Allocate the message */
+ req = rwnx_msg_zalloc(DBG_GET_SYS_STAT_REQ, TASK_DBG, DRV_TASK_ID, 0);
+ if (!req)
+ return -ENOMEM;
+
+ /* Send the DBG_MEM_READ_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, DBG_GET_SYS_STAT_CFM, cfm);
+}
+
+int rwnx_send_dbg_mem_block_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
+ u32 mem_size, u32 *mem_data)
+{
+ struct dbg_mem_block_write_req *mem_blk_write_req;
+
+ // RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the DBG_MEM_BLOCK_WRITE_REQ message */
+ mem_blk_write_req =
+ rwnx_msg_zalloc(DBG_MEM_BLOCK_WRITE_REQ, TASK_DBG, DRV_TASK_ID,
+ sizeof(struct dbg_mem_block_write_req));
+ if (!mem_blk_write_req)
+ return -ENOMEM;
+
+ /* Set parameters for the DBG_MEM_BLOCK_WRITE_REQ message */
+ mem_blk_write_req->memaddr = mem_addr;
+ mem_blk_write_req->memsize = mem_size;
+ memcpy(mem_blk_write_req->memdata, mem_data, mem_size);
+
+ /* Send the DBG_MEM_BLOCK_WRITE_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, mem_blk_write_req, 1, DBG_MEM_BLOCK_WRITE_CFM,
+ NULL);
+}
+
+int rwnx_send_dbg_start_app_req(struct rwnx_hw *rwnx_hw, u32 boot_addr,
+ u32 boot_type)
+{
+ struct dbg_start_app_req *start_app_req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the DBG_START_APP_REQ message */
+ start_app_req = rwnx_msg_zalloc(DBG_START_APP_REQ, TASK_DBG, DRV_TASK_ID,
+ sizeof(struct dbg_start_app_req));
+ if (!start_app_req)
+ return -ENOMEM;
+
+ /* Set parameters for the DBG_START_APP_REQ message */
+ start_app_req->bootaddr = boot_addr;
+ start_app_req->boottype = boot_type;
+
+ /* Send the DBG_START_APP_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, start_app_req, 1, DBG_START_APP_CFM, NULL);
+}
+
+int rwnx_send_cfg_rssi_req(struct rwnx_hw *rwnx_hw, u8 vif_index,
+ int rssi_thold, u32 rssi_hyst)
+{
+ struct mm_cfg_rssi_req *req;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ /* Build the MM_CFG_RSSI_REQ message */
+ req = rwnx_msg_zalloc(MM_CFG_RSSI_REQ, TASK_MM, DRV_TASK_ID,
+ sizeof(struct mm_cfg_rssi_req));
+ if (!req)
+ return -ENOMEM;
+
+ if (!rwnx_hw->vif_table[vif_index])
+ return 0;
+
+ /* Set parameters for the MM_CFG_RSSI_REQ message */
+ req->vif_index = vif_index;
+ req->rssi_thold = (s8)rssi_thold;
+ req->rssi_hyst = (u8)rssi_hyst;
+
+ /* Send the MM_CFG_RSSI_REQ message to LMAC FW */
+ return rwnx_send_msg(rwnx_hw, req, 1, MM_CFG_RSSI_CFM, NULL);
+}
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_tx.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_tx.h
new file mode 100644
index 0000000000000..1e01ef8f7976c
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_msg_tx.h
@@ -0,0 +1,266 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _RWNX_MSG_TX_H_
+#define _RWNX_MSG_TX_H_
+
+#include "lmac_types.h"
+#include "rwnx_defs.h"
+
+int rwnx_send_reset(struct rwnx_hw *rwnx_hw);
+
+int rwnx_send_start(struct rwnx_hw *rwnx_hw);
+
+int rwnx_send_version_req(struct rwnx_hw *rwnx_hw, struct mm_version_cfm *cfm);
+
+int rwnx_send_add_if(struct rwnx_hw *rwnx_hw, const unsigned char *mac,
+ enum nl80211_iftype iftype, bool p2p,
+ struct mm_add_if_cfm *cfm);
+
+int rwnx_send_remove_if(struct rwnx_hw *rwnx_hw, u8 vif_index, bool defer);
+
+int rwnx_send_set_channel(struct rwnx_hw *rwnx_hw, int phy_idx,
+ struct mm_set_channel_cfm *cfm);
+
+int rwnx_send_key_add(struct rwnx_hw *rwnx_hw, u8 vif_idx, u8 sta_idx,
+ bool pairwise, u8 *key, u8 key_len, u8 key_idx,
+ u8 cipher_suite, struct mm_key_add_cfm *cfm);
+
+int rwnx_send_key_del(struct rwnx_hw *rwnx_hw, uint8_t hw_key_idx);
+
+int rwnx_send_bcn(struct rwnx_hw *rwnx_hw, u8 *buf, u8 vif_idx, u16 bcn_len);
+
+int rwnx_send_bcn_change(struct rwnx_hw *rwnx_hw, u8 vif_idx, u32 bcn_addr,
+ u16 bcn_len, u16 tim_oft, u16 tim_len, u16 *csa_oft);
+
+int rwnx_send_tim_update(struct rwnx_hw *rwnx_hw, u8 vif_idx, u16 aid,
+ u8 tx_status);
+
+int rwnx_send_roc(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ struct ieee80211_channel *chan, unsigned int duration,
+ struct mm_remain_on_channel_cfm *roc_cfm);
+
+int rwnx_send_cancel_roc(struct rwnx_hw *rwnx_hw);
+
+int rwnx_send_set_power(struct rwnx_hw *rwnx_hw, u8 vif_idx, s8 pwr,
+ struct mm_set_power_cfm *cfm);
+
+int rwnx_send_set_edca(struct rwnx_hw *rwnx_hw, u8 hw_queue, u32 param,
+ bool uapsd, u8 inst_nbr);
+
+int rwnx_send_tdls_chan_switch_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif,
+ struct rwnx_sta *rwnx_sta,
+ bool sta_initiator, u8 oper_class,
+ struct cfg80211_chan_def *chandef,
+ struct tdls_chan_switch_cfm *cfm);
+
+int rwnx_send_tdls_cancel_chan_switch_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
+ struct rwnx_sta *rwnx_sta,
+ struct tdls_cancel_chan_switch_cfm *cfm);
+
+#ifdef AICWF_ARP_OFFLOAD
+int rwnx_send_arpoffload_en_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif, u32 ipaddr,
+ u8 enable);
+#endif
+int rwnx_send_rf_config_req(struct rwnx_hw *rwnx_hw, u8 ofst, u8 sel, u8 *tbl, u16 len);
+
+int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw,
+ struct mm_set_rf_calib_cfm *cfm);
+
+int rwnx_send_get_macaddr_req(struct rwnx_hw *rwnx_hw,
+ struct mm_get_mac_addr_cfm *cfm);
+
+#ifdef CONFIG_RWNX_FULLMAC
+int rwnx_send_me_config_req(struct rwnx_hw *rwnx_hw);
+
+int rwnx_send_me_chan_config_req(struct rwnx_hw *rwnx_hw);
+
+int rwnx_send_me_set_control_port_req(struct rwnx_hw *rwnx_hw, bool opened,
+ u8 sta_idx);
+
+int rwnx_send_me_sta_add(struct rwnx_hw *rwnx_hw,
+ struct station_parameters *params, const u8 *mac,
+ u8 inst_nbr, struct me_sta_add_cfm *cfm);
+
+int rwnx_send_me_sta_del(struct rwnx_hw *rwnx_hw, u8 sta_idx, bool tdls_sta);
+
+int rwnx_send_me_traffic_ind(struct rwnx_hw *rwnx_hw, u8 sta_idx, bool uapsd,
+ u8 tx_status);
+
+int rwnx_send_me_rc_stats(struct rwnx_hw *rwnx_hw, u8 sta_idx,
+ struct me_rc_stats_cfm *cfm);
+
+int rwnx_send_me_rc_set_rate(struct rwnx_hw *rwnx_hw, u8 sta_idx, u16 rate_idx);
+
+int rwnx_send_me_set_ps_mode(struct rwnx_hw *rwnx_hw, u8 ps_mode);
+
+int rwnx_send_me_set_lp_level(struct rwnx_hw *rwnx_hw, u8 lp_level, u8 disable_filter);
+
+int rwnx_send_sm_connect_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
+ struct cfg80211_connect_params *sme, struct sm_connect_cfm *cfm);
+
+int rwnx_send_sm_disconnect_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif, u16 reason);
+
+int rwnx_send_sm_external_auth_required_rsp(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif, u16 status);
+
+int rwnx_send_apm_start_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ struct cfg80211_ap_settings *settings, struct apm_start_cfm *cfm,
+ struct rwnx_ipc_elem_var *elem);
+
+int rwnx_send_apm_stop_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif);
+
+int rwnx_send_scanu_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
+ struct cfg80211_scan_request *param);
+
+int rwnx_send_scanu_cancel_req(struct rwnx_hw *rwnx_hw,
+ struct scan_cancel_cfm *cfm);
+
+int rwnx_send_apm_start_cac_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ struct cfg80211_chan_def *chandef,
+ struct apm_start_cac_cfm *cfm);
+
+int rwnx_send_apm_stop_cac_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif);
+
+int rwnx_send_tdls_peer_traffic_ind_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *rwnx_vif);
+
+int rwnx_send_config_monitor_req(struct rwnx_hw *rwnx_hw,
+ struct cfg80211_chan_def *chandef,
+ struct me_config_monitor_cfm *cfm);
+
+int rwnx_send_mesh_start_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ const struct mesh_config *conf, const struct mesh_setup *setup,
+ struct mesh_start_cfm *cfm);
+
+int rwnx_send_mesh_stop_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ struct mesh_stop_cfm *cfm);
+
+int rwnx_send_mesh_update_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ u32 mask, const struct mesh_config *p_mconf,
+ struct mesh_update_cfm *cfm);
+
+int rwnx_send_mesh_peer_info_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ u8 sta_idx, struct mesh_peer_info_cfm *cfm);
+
+void rwnx_send_mesh_peer_update_ntf(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *vif, u8 sta_idx,
+ u8 mlink_state);
+
+void rwnx_send_mesh_path_create_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *vif, u8 *tgt_addr);
+
+int rwnx_send_mesh_path_update_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_vif *vif, const u8 *tgt_addr,
+ const u8 *p_nhop_addr,
+ struct mesh_path_update_cfm *cfm);
+
+void rwnx_send_mesh_proxy_add_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
+ u8 *ext_addr);
+
+#endif /* CONFIG_RWNX_FULLMAC */
+
+#ifdef CONFIG_RWNX_BFMER
+#ifdef CONFIG_RWNX_FULLMAC
+void rwnx_send_bfmer_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta,
+ const struct ieee80211_vht_cap *vht_cap);
+
+#endif /* CONFIG_RWNX_FULLMAC */
+#ifdef CONFIG_RWNX_MUMIMO_TX
+int rwnx_send_mu_group_update_req(struct rwnx_hw *rwnx_hw,
+ struct rwnx_sta *rwnx_sta);
+#endif /* CONFIG_RWNX_MUMIMO_TX */
+#endif /* CONFIG_RWNX_BFMER */
+
+/* Debug messages */
+int rwnx_send_dbg_trigger_req(struct rwnx_hw *rwnx_hw, char *msg);
+
+int rwnx_send_dbg_mem_read_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
+ struct dbg_mem_read_cfm *cfm);
+
+int rwnx_send_dbg_mem_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
+ u32 mem_data);
+
+int rwnx_send_dbg_mem_mask_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
+ u32 mem_mask, u32 mem_data);
+
+int rwnx_send_dbg_set_mod_filter_req(struct rwnx_hw *rwnx_hw, u32 filter);
+
+int rwnx_send_rftest_req(struct rwnx_hw *rwnx_hw, u32 cmd, u32 argc,
+ u8 *argv, struct dbg_rftest_cmd_cfm *cfm);
+
+int rwnx_send_dbg_set_sev_filter_req(struct rwnx_hw *rwnx_hw, u32 filter);
+
+int rwnx_send_dbg_get_sys_stat_req(struct rwnx_hw *rwnx_hw,
+ struct dbg_get_sys_stat_cfm *cfm);
+
+int rwnx_send_dbg_mem_block_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
+ u32 mem_size, u32 *mem_data);
+
+int rwnx_send_dbg_start_app_req(struct rwnx_hw *rwnx_hw, u32 boot_addr,
+ u32 boot_type);
+
+int rwnx_send_cfg_rssi_req(struct rwnx_hw *rwnx_hw, u8 vif_index,
+ int rssi_thold, u32 rssi_hyst);
+
+int rwnx_send_disable_agg_req(struct rwnx_hw *rwnx_hw, u8 agg_disable,
+ u8 agg_disable_rx, u8 sta_idx);
+
+int rwnx_send_coex_req(struct rwnx_hw *rwnx_hw, u8 disable_coexnull,
+ u8 enable_nullcts);
+
+int rwnx_send_get_sta_info_req(struct rwnx_hw *rwnx_hw, u8 sta_idx,
+ struct mm_get_sta_info_cfm *cfm);
+
+int rwnx_send_set_stack_start_req(struct rwnx_hw *rwnx_hw, u8 on,
+ u8 efuse_valid, u8 set_vendor_info,
+ u8 fwtrace_redir_en,
+ struct mm_set_stack_start_cfm *cfm);
+
+int rwnx_send_get_temp_req(struct rwnx_hw *rwnx_hw,
+ struct mm_set_vendor_swconfig_cfm *cfm);
+
+int rwnx_send_get_temp_hwconfig_req(struct rwnx_hw *rwnx_hw,
+ struct mm_set_vendor_hwconfig_cfm *cfm);
+
+int rwnx_send_set_temp_comp_req(struct rwnx_hw *rwnx_hw,
+ struct mm_set_vendor_swconfig_cfm *cfm);
+
+int rwnx_send_txop_req(struct rwnx_hw *rwnx_hw, uint16_t *txop,
+ u8 long_nav_en, u8 cfe_en);
+
+int rwnx_send_vendor_hwconfig_req(struct rwnx_hw *rwnx_hw, u32 hwconfig_id,
+ s32 *param, s32 *param_out);
+
+int rwnx_send_vendor_swconfig_req(struct rwnx_hw *rwnx_hw, u32 swconfig_id,
+ s32 *param_in, s32 *param_out);
+
+int rwnx_send_mask_set_ext_flags_req(struct rwnx_hw *rwnx_hw,
+ u32 flags_mask, u32 flags_val,
+ struct mm_set_vendor_swconfig_cfm *cfm);
+
+int rwnx_send_get_fw_version_req(struct rwnx_hw *rwnx_hw,
+ struct mm_get_fw_version_cfm *cfm);
+
+int rwnx_send_txpwr_idx_req(struct rwnx_hw *rwnx_hw);
+
+int rwnx_send_txpwr_ofst_req(struct rwnx_hw *rwnx_hw);
+
+int rwnx_send_txpwr_ofst2x_req(struct rwnx_hw *rwnx_hw);
+
+int rwnx_send_txpwr_lvl_req(struct rwnx_hw *rwnx_hw);
+
+int rwnx_send_txpwr_lvl_v3_req(struct rwnx_hw *rwnx_hw, int index_reg);
+
+int rwnx_send_txpwr_lvl_adj_req(struct rwnx_hw *rwnx_hw);
+
+struct rwnx_cmd *rwnx_cmd_malloc(void);
+
+void rwnx_cmd_free(struct rwnx_cmd *cmd);
+
+int rwnx_init_cmd_array(void);
+
+void rwnx_free_cmd_array(void);
+
+#endif /* _RWNX_MSG_TX_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_platform.c b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_platform.c
new file mode 100644
index 0000000000000..a4d96a6a082f5
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_platform.c
@@ -0,0 +1,2868 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @file rwnx_platform.c
+ *
+ * @brief Platform profile
+ *
+ ******************************************************************************
+ */
+
+#include <linux/delay.h>
+#include <crypto/md5.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sprintf.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+#include "hal_desc.h"
+#include "reg_access.h"
+#include "rwnx_main.h"
+#include "rwnx_platform.h"
+#include "ipc_host.h"
+#include "rwnx_msg_tx.h"
+
+#ifdef AICWF_SDIO_SUPPORT
+#include "aicwf_sdio.h"
+#endif
+
+#include "aicwf_compat_8800d80.h"
+#include "aicwf_compat_8800dc.h"
+#include "aicwf_chip_ops.h"
+
+// Parser state
+#define INIT 0
+#define CMD 1
+#define PRINT 2
+#define GET_VALUE 3
+
+struct reg_table {
+ char ccode[3];
+ enum regions_code region;
+};
+
+/* If the region conflicts with the kernel, the actual authentication standard prevails */
+static struct reg_table reg_tables[] = {
+ {.ccode = "CN", .region = REGIONS_SRRC},
+ {.ccode = "US", .region = REGIONS_FCC},
+ {.ccode = "DE", .region = REGIONS_ETSI},
+ {.ccode = "00", .region = REGIONS_DEFAULT},
+ {.ccode = "WW", .region = REGIONS_DEFAULT},
+ {.ccode = "XX", .region = REGIONS_DEFAULT},
+ {.ccode = "JP", .region = REGIONS_JP},
+ {.ccode = "AD", .region = REGIONS_ETSI},
+ {.ccode = "AE", .region = REGIONS_ETSI},
+ {.ccode = "AF", .region = REGIONS_ETSI},
+ {.ccode = "AI", .region = REGIONS_ETSI},
+ {.ccode = "AL", .region = REGIONS_ETSI},
+ {.ccode = "AM", .region = REGIONS_ETSI},
+ {.ccode = "AN", .region = REGIONS_ETSI},
+ {.ccode = "AR", .region = REGIONS_FCC},
+ {.ccode = "AS", .region = REGIONS_FCC},
+ {.ccode = "AT", .region = REGIONS_ETSI},
+ {.ccode = "AU", .region = REGIONS_ETSI},
+ {.ccode = "AW", .region = REGIONS_ETSI},
+ {.ccode = "AZ", .region = REGIONS_ETSI},
+ {.ccode = "BA", .region = REGIONS_ETSI},
+ {.ccode = "BB", .region = REGIONS_FCC},
+ {.ccode = "BD", .region = REGIONS_ETSI},
+ {.ccode = "BE", .region = REGIONS_ETSI},
+ {.ccode = "BF", .region = REGIONS_FCC},
+ {.ccode = "BG", .region = REGIONS_ETSI},
+ {.ccode = "BH", .region = REGIONS_ETSI},
+ {.ccode = "BL", .region = REGIONS_ETSI},
+ {.ccode = "BM", .region = REGIONS_FCC},
+ {.ccode = "BN", .region = REGIONS_JP},
+ {.ccode = "BO", .region = REGIONS_JP},
+ {.ccode = "BR", .region = REGIONS_FCC},
+ {.ccode = "BS", .region = REGIONS_FCC},
+ {.ccode = "BT", .region = REGIONS_ETSI},
+ {.ccode = "BW", .region = REGIONS_ETSI},
+ {.ccode = "BY", .region = REGIONS_ETSI},
+ {.ccode = "BZ", .region = REGIONS_JP},
+ {.ccode = "CA", .region = REGIONS_FCC},
+ {.ccode = "CF", .region = REGIONS_FCC},
+ {.ccode = "CH", .region = REGIONS_ETSI},
+ {.ccode = "CI", .region = REGIONS_FCC},
+ {.ccode = "CL", .region = REGIONS_ETSI},
+ {.ccode = "CO", .region = REGIONS_FCC},
+ {.ccode = "CR", .region = REGIONS_FCC},
+ {.ccode = "CU", .region = REGIONS_FCC},
+ {.ccode = "CX", .region = REGIONS_FCC},
+ {.ccode = "CY", .region = REGIONS_ETSI},
+ {.ccode = "CZ", .region = REGIONS_ETSI},
+ {.ccode = "DK", .region = REGIONS_ETSI},
+ {.ccode = "DM", .region = REGIONS_FCC},
+ {.ccode = "DO", .region = REGIONS_FCC},
+ {.ccode = "DZ", .region = REGIONS_ETSI},
+ {.ccode = "EC", .region = REGIONS_FCC},
+ {.ccode = "EE", .region = REGIONS_ETSI},
+ {.ccode = "EG", .region = REGIONS_ETSI},
+ {.ccode = "ES", .region = REGIONS_ETSI},
+ {.ccode = "ET", .region = REGIONS_ETSI},
+ {.ccode = "FI", .region = REGIONS_ETSI},
+ {.ccode = "FK", .region = REGIONS_ETSI},
+ {.ccode = "FM", .region = REGIONS_FCC},
+ {.ccode = "FO", .region = REGIONS_ETSI},
+ {.ccode = "FR", .region = REGIONS_ETSI},
+ {.ccode = "GB", .region = REGIONS_ETSI},
+ {.ccode = "GD", .region = REGIONS_FCC},
+ {.ccode = "GE", .region = REGIONS_ETSI},
+ {.ccode = "GF", .region = REGIONS_ETSI},
+ {.ccode = "GH", .region = REGIONS_ETSI},
+ {.ccode = "GI", .region = REGIONS_ETSI},
+ {.ccode = "GL", .region = REGIONS_ETSI},
+ {.ccode = "GP", .region = REGIONS_ETSI},
+ {.ccode = "GR", .region = REGIONS_ETSI},
+ {.ccode = "GT", .region = REGIONS_FCC},
+ {.ccode = "GU", .region = REGIONS_FCC},
+ {.ccode = "GY", .region = REGIONS_DEFAULT},
+ {.ccode = "HK", .region = REGIONS_ETSI},
+ {.ccode = "HN", .region = REGIONS_FCC},
+ {.ccode = "HR", .region = REGIONS_ETSI},
+ {.ccode = "HT", .region = REGIONS_FCC},
+ {.ccode = "HU", .region = REGIONS_ETSI},
+ {.ccode = "ID", .region = REGIONS_ETSI},
+ {.ccode = "IE", .region = REGIONS_ETSI},
+ {.ccode = "IL", .region = REGIONS_ETSI},
+ {.ccode = "IN", .region = REGIONS_ETSI},
+ {.ccode = "IQ", .region = REGIONS_ETSI},
+ {.ccode = "IR", .region = REGIONS_JP},
+ {.ccode = "IS", .region = REGIONS_ETSI},
+ {.ccode = "IT", .region = REGIONS_ETSI},
+ {.ccode = "JM", .region = REGIONS_FCC},
+ {.ccode = "JO", .region = REGIONS_ETSI},
+ {.ccode = "KE", .region = REGIONS_ETSI},
+ {.ccode = "KG", .region = REGIONS_ETSI},
+ {.ccode = "KH", .region = REGIONS_ETSI},
+ {.ccode = "KN", .region = REGIONS_ETSI},
+ {.ccode = "KP", .region = REGIONS_JP},
+ {.ccode = "KR", .region = REGIONS_ETSI},
+ {.ccode = "KW", .region = REGIONS_ETSI},
+ {.ccode = "KY", .region = REGIONS_FCC},
+ {.ccode = "KZ", .region = REGIONS_ETSI},
+ {.ccode = "LB", .region = REGIONS_ETSI},
+ {.ccode = "LC", .region = REGIONS_ETSI},
+ {.ccode = "LI", .region = REGIONS_ETSI},
+ {.ccode = "LK", .region = REGIONS_FCC},
+ {.ccode = "LS", .region = REGIONS_ETSI},
+ {.ccode = "LT", .region = REGIONS_ETSI},
+ {.ccode = "LU", .region = REGIONS_ETSI},
+ {.ccode = "LV", .region = REGIONS_ETSI},
+ {.ccode = "LY", .region = REGIONS_ETSI},
+ {.ccode = "MA", .region = REGIONS_ETSI},
+ {.ccode = "MC", .region = REGIONS_ETSI},
+ {.ccode = "MD", .region = REGIONS_ETSI},
+ {.ccode = "ME", .region = REGIONS_ETSI},
+ {.ccode = "MF", .region = REGIONS_ETSI},
+ {.ccode = "MH", .region = REGIONS_FCC},
+ {.ccode = "MK", .region = REGIONS_ETSI},
+ {.ccode = "MN", .region = REGIONS_ETSI},
+ {.ccode = "MO", .region = REGIONS_ETSI},
+ {.ccode = "MP", .region = REGIONS_FCC},
+ {.ccode = "MQ", .region = REGIONS_ETSI},
+ {.ccode = "MR", .region = REGIONS_ETSI},
+ {.ccode = "MT", .region = REGIONS_ETSI},
+ {.ccode = "MU", .region = REGIONS_FCC},
+ {.ccode = "MV", .region = REGIONS_ETSI},
+ {.ccode = "MW", .region = REGIONS_ETSI},
+ {.ccode = "MX", .region = REGIONS_FCC},
+ {.ccode = "MY", .region = REGIONS_ETSI},
+ {.ccode = "NA", .region = REGIONS_ETSI},
+ {.ccode = "NG", .region = REGIONS_ETSI},
+ {.ccode = "NI", .region = REGIONS_FCC},
+ {.ccode = "NL", .region = REGIONS_ETSI},
+ {.ccode = "NO", .region = REGIONS_ETSI},
+ {.ccode = "NP", .region = REGIONS_JP},
+ {.ccode = "NZ", .region = REGIONS_ETSI},
+ {.ccode = "OM", .region = REGIONS_ETSI},
+ {.ccode = "PA", .region = REGIONS_FCC},
+ {.ccode = "PE", .region = REGIONS_ETSI},
+ {.ccode = "PF", .region = REGIONS_ETSI},
+ {.ccode = "PG", .region = REGIONS_FCC},
+ {.ccode = "PH", .region = REGIONS_ETSI},
+ {.ccode = "PK", .region = REGIONS_ETSI},
+ {.ccode = "PL", .region = REGIONS_ETSI},
+ {.ccode = "PM", .region = REGIONS_ETSI},
+ {.ccode = "PR", .region = REGIONS_FCC},
+ {.ccode = "PT", .region = REGIONS_ETSI},
+ {.ccode = "PW", .region = REGIONS_FCC},
+ {.ccode = "PY", .region = REGIONS_FCC},
+ {.ccode = "QA", .region = REGIONS_ETSI},
+ {.ccode = "RE", .region = REGIONS_ETSI},
+ {.ccode = "RO", .region = REGIONS_ETSI},
+ {.ccode = "RS", .region = REGIONS_ETSI},
+ {.ccode = "RU", .region = REGIONS_ETSI},
+ {.ccode = "RW", .region = REGIONS_FCC},
+ {.ccode = "SA", .region = REGIONS_ETSI},
+ {.ccode = "SE", .region = REGIONS_ETSI},
+ {.ccode = "SG", .region = REGIONS_ETSI},
+ {.ccode = "SI", .region = REGIONS_ETSI},
+ {.ccode = "SK", .region = REGIONS_ETSI},
+ {.ccode = "SM", .region = REGIONS_ETSI},
+ {.ccode = "SN", .region = REGIONS_FCC},
+ {.ccode = "SR", .region = REGIONS_ETSI},
+ {.ccode = "SV", .region = REGIONS_FCC},
+ {.ccode = "SY", .region = REGIONS_DEFAULT},
+ {.ccode = "TC", .region = REGIONS_FCC},
+ {.ccode = "TD", .region = REGIONS_ETSI},
+ {.ccode = "TG", .region = REGIONS_ETSI},
+ {.ccode = "TH", .region = REGIONS_ETSI},
+ {.ccode = "TJ", .region = REGIONS_ETSI},
+ {.ccode = "TM", .region = REGIONS_ETSI},
+ {.ccode = "TN", .region = REGIONS_ETSI},
+ {.ccode = "TR", .region = REGIONS_ETSI},
+ {.ccode = "TT", .region = REGIONS_FCC},
+ {.ccode = "TW", .region = REGIONS_FCC},
+ {.ccode = "TZ", .region = REGIONS_DEFAULT},
+ {.ccode = "UA", .region = REGIONS_ETSI},
+ {.ccode = "UG", .region = REGIONS_FCC},
+ {.ccode = "UY", .region = REGIONS_ETSI},
+ {.ccode = "UZ", .region = REGIONS_ETSI},
+ {.ccode = "VC", .region = REGIONS_ETSI},
+ {.ccode = "VE", .region = REGIONS_FCC},
+ {.ccode = "VI", .region = REGIONS_FCC},
+ {.ccode = "VN", .region = REGIONS_JP},
+ {.ccode = "VU", .region = REGIONS_FCC},
+ {.ccode = "WF", .region = REGIONS_ETSI},
+ {.ccode = "WS", .region = REGIONS_ETSI},
+ {.ccode = "YE", .region = REGIONS_DEFAULT},
+ {.ccode = "YT", .region = REGIONS_ETSI},
+ {.ccode = "ZA", .region = REGIONS_ETSI},
+ {.ccode = "ZM", .region = REGIONS_ETSI},
+ {.ccode = "ZW", .region = REGIONS_ETSI},
+ {.ccode = "XK", .region = REGIONS_ETSI},
+};
+
+struct rwnx_plat *g_rwnx_plat;
+
+struct userconfig_info_t {
+ struct txpwr_lvl_conf txpwr_lvl;
+ struct txpwr_lvl_conf_v2 txpwr_lvl_v2;
+ struct txpwr_lvl_conf_v3 txpwr_lvl_v3;
+ struct txpwr_lvl_conf_v3 txpwr_lvl_v3_gp[REGION_NUM_MAX];
+ struct txpwr_lvl_adj_conf txpwr_lvl_adj;
+ struct txpwr_loss_conf txpwr_loss;
+ struct txpwr_ofst_conf txpwr_ofst;
+ struct txpwr_ofst2x_conf txpwr_ofst2x;
+ struct xtal_cap_conf xtal_cap;
+};
+
+static struct userconfig_info_t userconfig_info = {
+ .txpwr_lvl = { .enable = 1,
+ .dsss = 9,
+ .ofdmlowrate_2g4 = 8,
+ .ofdm64qam_2g4 = 8,
+ .ofdm256qam_2g4 = 8,
+ .ofdm1024qam_2g4 = 8,
+ .ofdmlowrate_5g = 11,
+ .ofdm64qam_5g = 10,
+ .ofdm256qam_5g = 9,
+ .ofdm1024qam_5g = 9},
+ .txpwr_lvl_v2 = { .enable = 1,
+ .pwrlvl_11b_11ag_2g4 =
+ // 1M, 2M, 5M5, 11M, 6M, 9M, 12M, 18M, 24M, 36M,
+ // 48M, 54M
+ {20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_2g4 =
+ // MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9
+ {20, 20, 20, 20, 18, 18, 16, 16, 16, 16},
+ .pwrlvl_11ax_2g4 =
+ // MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9,
+ // MCS10,MCS11
+ {20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15},
+ },
+ .txpwr_lvl_v3 = { .enable = 1,
+ .pwrlvl_11b_11ag_2g4 =
+ // 1M, 2M, 5M5, 11M, 6M, 9M, 12M, 18M, 24M, 36M,
+ // 48M, 54M
+ {20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_2g4 =
+ // MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9
+ {20, 20, 20, 20, 18, 18, 16, 16, 16, 16},
+ .pwrlvl_11ax_2g4 =
+ // MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9,
+ // MCS10,MCS11
+ {20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15},
+ .pwrlvl_11a_5g =
+ // NA, NA, NA, NA, 6M, 9M, 12M, 18M, 24M, 36M,
+ // 48M, 54M
+ {0x80, 0x80, 0x80, 0x80, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_5g =
+ // MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9
+ {20, 20, 20, 20, 18, 18, 16, 16, 16, 15},
+ .pwrlvl_11ax_5g =
+ // MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9,
+ // MCS10,MCS11
+ {20, 20, 20, 20, 18, 18, 16, 16, 16, 15, 14, 14},
+ },
+ .txpwr_lvl_v3_gp[0] = { .enable = 1,
+ .pwrlvl_11b_11ag_2g4 =
+ // 1M, 2M, 5M5, 11M, 6M, 9M, 12M, 18M, 24M, 36M,
+ // 48M, 54M
+ {20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_2g4 =
+ // MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9
+ {20, 20, 20, 20, 18, 18, 16, 16, 16, 16},
+ .pwrlvl_11ax_2g4 =
+ // MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9,
+ // MCS10,MCS11
+ {20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15},
+ .pwrlvl_11a_5g =
+ // NA, NA, NA, NA, 6M, 9M, 12M, 18M, 24M, 36M,
+ // 48M, 54M
+ {0x80, 0x80, 0x80, 0x80, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_5g =
+ // MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9
+ {20, 20, 20, 20, 18, 18, 16, 16, 16, 15},
+ .pwrlvl_11ax_5g =
+ // MCS0, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9,
+ // MCS10,MCS11
+ {20, 20, 20, 20, 18, 18, 16, 16, 16, 15, 14, 14},
+ },
+ .txpwr_lvl_v3_gp[1] = { .enable = 1,
+ .pwrlvl_11b_11ag_2g4 = {20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_2g4 = {20, 20, 20, 20, 18, 18, 16, 16, 16, 16},
+ .pwrlvl_11ax_2g4 = {20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15},
+ .pwrlvl_11a_5g = {0x80, 0x80, 0x80, 0x80, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_5g = {20, 20, 20, 20, 18, 18, 16, 16, 16, 15},
+ .pwrlvl_11ax_5g = {20, 20, 20, 20, 18, 18, 16, 16, 16, 15, 14, 14},
+ },
+ .txpwr_lvl_v3_gp[2] = { .enable = 1,
+ .pwrlvl_11b_11ag_2g4 = {20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_2g4 = {20, 20, 20, 20, 18, 18, 16, 16, 16, 16},
+ .pwrlvl_11ax_2g4 = {20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15},
+ .pwrlvl_11a_5g = {0x80, 0x80, 0x80, 0x80, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_5g = {20, 20, 20, 20, 18, 18, 16, 16, 16, 15},
+ .pwrlvl_11ax_5g = {20, 20, 20, 20, 18, 18, 16, 16, 16, 15, 14, 14},
+ },
+ .txpwr_lvl_v3_gp[3] = { .enable = 1,
+ .pwrlvl_11b_11ag_2g4 = {20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_2g4 = {20, 20, 20, 20, 18, 18, 16, 16, 16, 16},
+ .pwrlvl_11ax_2g4 = {20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15},
+ .pwrlvl_11a_5g = {0x80, 0x80, 0x80, 0x80, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_5g = {20, 20, 20, 20, 18, 18, 16, 16, 16, 15},
+ .pwrlvl_11ax_5g = {20, 20, 20, 20, 18, 18, 16, 16, 16, 15, 14, 14},
+ },
+ .txpwr_lvl_v3_gp[4] = { .enable = 1,
+ .pwrlvl_11b_11ag_2g4 = {20, 20, 20, 20, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_2g4 = {20, 20, 20, 20, 18, 18, 16, 16, 16, 16},
+ .pwrlvl_11ax_2g4 = {20, 20, 20, 20, 18, 18, 16, 16, 16, 16, 15, 15},
+ .pwrlvl_11a_5g = {0x80, 0x80, 0x80, 0x80, 20, 20, 20, 20, 18, 18, 16, 16},
+ .pwrlvl_11n_11ac_5g = {20, 20, 20, 20, 18, 18, 16, 16, 16, 15},
+ .pwrlvl_11ax_5g = {20, 20, 20, 20, 18, 18, 16, 16, 16, 15, 14, 14},
+ },
+ .txpwr_loss = { .loss_enable_2g4 = 1,
+ .loss_value_2g4 = 0,
+ .loss_enable_5g = 1,
+ .loss_value_5g = 0,
+ },
+ .txpwr_ofst = { .enable = 1,
+ .chan_1_4 = 0,
+ .chan_5_9 = 0,
+ .chan_10_13 = 0,
+ .chan_36_64 = 0,
+ .chan_100_120 = 0,
+ .chan_122_140 = 0,
+ .chan_142_165 = 0,
+ },
+ .txpwr_ofst2x = { .enable = 0,
+ .pwrofst2x_tbl_2g4 = {
+ // ch1-4, ch5-9, ch10-13
+ {0, 0, 0}, // 11b
+ {0, 0, 0}, // ofdm_highrate
+ {0, 0, 0}, // ofdm_lowrate
+ },
+ .pwrofst2x_tbl_5g = {
+ // ch42, ch58, ch106,ch122,ch138,ch155
+ {0, 0, 0, 0, 0, 0}, // ofdm_lowrate
+ {0, 0, 0, 0, 0, 0}, // ofdm_highrate
+ {0, 0, 0, 0, 0, 0}, // ofdm_midrate
+ },
+ },
+ .xtal_cap = { .enable = 0,
+ .xtal_cap = 24,
+ .xtal_cap_fine = 31,
+ },
+};
+
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+#define POWER_LIMIT_INVALID_VAL POWER_LEVEL_INVALID_VAL
+
+#define POWER_LIMIT_CC_MATCHED_BIT (0x1U << 0)
+
+struct txpwr_lmt_info_t {
+ u8 ch_cnt_2g4;
+ u8 ch_cnt_5g;
+ u8 ch_num_2g4[MAC_DOMAINCHANNEL_24G_MAX];
+ u8 ch_num_5g[MAC_DOMAINCHANNEL_5G_MAX];
+ s8 max_pwr_2g4[MAC_DOMAINCHANNEL_24G_MAX];
+ s8 max_pwr_5g[MAC_DOMAINCHANNEL_5G_MAX];
+};
+
+struct powerlimit_info_t {
+ u32 flags;
+ struct txpwr_lmt_info_t txpwr_lmt;
+};
+
+static struct powerlimit_info_t powerlimit_info = {
+ 0,
+};
+#endif
+
+int aicwf_request_firmware(const struct firmware **fw, const char *name,
+ struct device *dev)
+{
+ char *fw_name;
+ int ret;
+
+ if (!name || !name[0])
+ return -EINVAL;
+
+ fw_name = kasprintf(GFP_KERNEL, AIC8800_FW_DIR "%s", name);
+ if (!fw_name)
+ return -ENOMEM;
+
+ ret = request_firmware(fw, fw_name, dev);
+ kfree(fw_name);
+
+ return ret;
+}
+
+#define MD5PINRT \
+ "file " \
+ "md5:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\r\n"
+
+static int rwnx_load_firmware(u32 **fw_buf, const char *name,
+ struct device *device)
+{
+ const struct firmware *fw = NULL;
+ u32 *dst = NULL;
+ void *buffer = NULL;
+ u8 digest[MD5_DIGEST_SIZE];
+ int size = 0;
+ int ret = 0;
+
+ AICWFDBG(LOGINFO, "AICWF %s: request firmware = %s\n", __func__, name);
+
+ ret = aicwf_request_firmware(&fw, name, device);
+
+ if (ret < 0) {
+ AICWFDBG(LOGDEBUG, "AICWF Load %s fail\n", name);
+ return ret;
+ }
+
+ size = fw->size;
+ dst = (u32 *)fw->data;
+
+ if (size <= 0) {
+ AICWFDBG(LOGDEBUG, "AICWF wrong size of firmware file\n");
+ release_firmware(fw);
+ return -1;
+ }
+
+ buffer = vmalloc(size);
+ if (!buffer) {
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+ memset(buffer, 0, size);
+ memcpy(buffer, dst, size);
+
+ *fw_buf = buffer;
+
+ md5(buffer, size, digest);
+ AICWFDBG(LOGDEBUG, "AICWF " MD5PINRT, digest[0], digest[1], digest[2], digest[3],
+ digest[4], digest[5], digest[6], digest[7], digest[8], digest[9],
+ digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]);
+
+ release_firmware(fw);
+
+ return size;
+}
+
+/* buffer is allocated by kzalloc */
+int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw, u32 **buffer,
+ const char *filename)
+{
+ int size;
+
+ AICWFDBG(LOGDEBUG, "### Load file %s\n", filename);
+
+ size = rwnx_load_firmware(buffer, filename, rwnx_hw->dev);
+
+ return size;
+}
+
+static void rwnx_restore_firmware(u32 **fw_buf)
+{
+ vfree(*fw_buf);
+ *fw_buf = NULL;
+}
+
+void rwnx_release_firmware_common(u32 **buffer)
+{
+ rwnx_restore_firmware(buffer);
+}
+
+/**
+ * rwnx_plat_bin_fw_upload_2 - Load the requested binary FW into embedded
+ * side.
+ *
+ * @rwnx_hw: Main driver data
+ * @fw_addr: Address where the fw must be loaded
+ * @filename: Name of the fw.
+ *
+ * Load a fw, stored as a binary file, into the specified address
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+int rwnx_plat_bin_fw_upload_2(struct rwnx_hw *rwnx_hw, u32 fw_addr,
+ char *filename)
+{
+ int err = 0;
+ unsigned int i = 0, size;
+ // u32 *src;
+ u32 *dst = NULL;
+
+ /* Copy the file on the Embedded side */
+ AICWFDBG(LOGINFO, "### Upload %s firmware, @ = %x\n", filename, fw_addr);
+
+ size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
+ if (!dst) {
+ AICWFDBG(LOGERROR, "No such file or directory\n");
+ return -1;
+ }
+ if (size <= 0) {
+ AICWFDBG(LOGERROR, "wrong size of firmware file\n");
+ dst = NULL;
+ err = -1;
+ }
+
+ AICWFDBG(LOGINFO, "size=%d, dst[0]=%x\n", size, dst[0]);
+ if (size > 512) {
+ for (; i < (size - 512); i += 512) {
+ // AICWFDBG(LOGDEBUG, "AICWF wr blk 0: %p -> %x\r\n",
+ // dst + i / 4, fw_addr + i);
+ err = rwnx_send_dbg_mem_block_write_req(rwnx_hw, fw_addr + i, 512,
+ dst + i / 4);
+ if (err) {
+ AICWFDBG(LOGERROR, "bin upload fail: %x, err:%d\r\n",
+ fw_addr + i, err);
+ break;
+ }
+ }
+ }
+ if (!err && i < size) {
+ // AICWFDBG(LOGDEBUG, "AICWF wr blk 1: %p -> %x\r\n", dst + i / 4, fw_addr + i);
+ err = rwnx_send_dbg_mem_block_write_req(rwnx_hw, fw_addr + i, size - i,
+ dst + i / 4);
+ if (err) {
+ AICWFDBG(LOGERROR, "bin upload fail: %x, err:%d\r\n", fw_addr + i,
+ err);
+ }
+ }
+
+ if (dst)
+ rwnx_release_firmware_common(&dst);
+
+ return err;
+}
+
+struct nvram_info_t {
+ struct txpwr_idx_conf txpwr_idx;
+ struct txpwr_ofst_conf txpwr_ofst;
+ struct xtal_cap_conf xtal_cap;
+};
+
+static struct nvram_info_t nvram_info = {
+ .txpwr_idx = {.enable = 1,
+ .dsss = 9,
+ .ofdmlowrate_2g4 = 8,
+ .ofdm64qam_2g4 = 8,
+ .ofdm256qam_2g4 = 8,
+ .ofdm1024qam_2g4 = 8,
+ .ofdmlowrate_5g = 11,
+ .ofdm64qam_5g = 10,
+ .ofdm256qam_5g = 9,
+ .ofdm1024qam_5g = 9},
+ .txpwr_ofst = { .enable = 1,
+ .chan_1_4 = 0,
+ .chan_5_9 = 0,
+ .chan_10_13 = 0,
+ .chan_36_64 = 0,
+ .chan_100_120 = 0,
+ .chan_122_140 = 0,
+ .chan_142_165 = 0,
+ },
+ .xtal_cap = { .enable = 0,
+ .xtal_cap = 24,
+ .xtal_cap_fine = 31,
+ },
+};
+
+void get_userconfig_txpwr_ofst_in_fdrv(struct txpwr_ofst_conf *txpwr_ofst)
+{
+ txpwr_ofst->enable = userconfig_info.txpwr_ofst.enable;
+ txpwr_ofst->chan_1_4 = userconfig_info.txpwr_ofst.chan_1_4;
+ txpwr_ofst->chan_5_9 = userconfig_info.txpwr_ofst.chan_5_9;
+ txpwr_ofst->chan_10_13 = userconfig_info.txpwr_ofst.chan_10_13;
+ txpwr_ofst->chan_36_64 = userconfig_info.txpwr_ofst.chan_36_64;
+ txpwr_ofst->chan_100_120 = userconfig_info.txpwr_ofst.chan_100_120;
+ txpwr_ofst->chan_122_140 = userconfig_info.txpwr_ofst.chan_122_140;
+ txpwr_ofst->chan_142_165 = userconfig_info.txpwr_ofst.chan_142_165;
+
+ AICWFDBG(LOGINFO, "%s:enable :%d\r\n", __func__, txpwr_ofst->enable);
+ AICWFDBG(LOGINFO, "%s:chan_1_4 :%d\r\n", __func__, txpwr_ofst->chan_1_4);
+ AICWFDBG(LOGINFO, "%s:chan_5_9 :%d\r\n", __func__, txpwr_ofst->chan_5_9);
+ AICWFDBG(LOGINFO, "%s:chan_10_13 :%d\r\n", __func__,
+ txpwr_ofst->chan_10_13);
+ AICWFDBG(LOGINFO, "%s:chan_36_64 :%d\r\n", __func__,
+ txpwr_ofst->chan_36_64);
+ AICWFDBG(LOGINFO, "%s:chan_100_120:%d\r\n", __func__,
+ txpwr_ofst->chan_100_120);
+ AICWFDBG(LOGINFO, "%s:chan_122_140:%d\r\n", __func__,
+ txpwr_ofst->chan_122_140);
+ AICWFDBG(LOGINFO, "%s:chan_142_165:%d\r\n", __func__,
+ txpwr_ofst->chan_142_165);
+}
+
+void get_userconfig_txpwr_ofst2x_in_fdrv(struct txpwr_ofst2x_conf *txpwr_ofst2x)
+{
+ int type, ch_grp;
+ *txpwr_ofst2x = userconfig_info.txpwr_ofst2x;
+ AICWFDBG(LOGINFO, "%s:enable :%d\r\n", __func__, txpwr_ofst2x->enable);
+ AICWFDBG(LOGDEBUG,
+ "pwrofst2x 2.4g: [0]:11b, [1]:ofdm_highrate, [2]:ofdm_lowrate\n chan=\t1-4\t5-9\t10-13");
+
+ for (type = 0; type < 3; type++) {
+ AICWFDBG(LOGDEBUG, "\n [%d] =", type);
+ for (ch_grp = 0; ch_grp < 3; ch_grp++) {
+ AICWFDBG(LOGDEBUG, "\t%d",
+ txpwr_ofst2x->pwrofst2x_tbl_2g4[type][ch_grp]);
+ }
+ }
+ AICWFDBG(LOGDEBUG,
+ "\npwrofst2x 5g: [0]:ofdm_lowrate, [1]:ofdm_highrate, [2]:ofdm_midrate\n chan=\t36-50\t51-64\t98-114\t115-130\t131-146\t147-166");
+ for (type = 0; type < 3; type++) {
+ AICWFDBG(LOGDEBUG, "\n [%d] =", type);
+ for (ch_grp = 0; ch_grp < 6; ch_grp++) {
+ AICWFDBG(LOGDEBUG, "\t%d",
+ txpwr_ofst2x->pwrofst2x_tbl_5g[type][ch_grp]);
+ }
+ }
+ AICWFDBG(LOGDEBUG, "\n");
+}
+
+void get_userconfig_txpwr_idx(struct txpwr_idx_conf *txpwr_idx)
+{
+ memcpy(txpwr_idx, &nvram_info.txpwr_idx, sizeof(struct txpwr_idx_conf));
+}
+
+void get_userconfig_txpwr_ofst(struct txpwr_ofst_conf *txpwr_ofst)
+{
+ memcpy(txpwr_ofst, &nvram_info.txpwr_ofst, sizeof(struct txpwr_ofst_conf));
+}
+
+void get_userconfig_xtal_cap(struct xtal_cap_conf *xtal_cap)
+{
+ if (nvram_info.xtal_cap.enable)
+ *xtal_cap = nvram_info.xtal_cap;
+
+ if (userconfig_info.xtal_cap.enable)
+ *xtal_cap = userconfig_info.xtal_cap;
+
+ AICWFDBG(LOGINFO, "%s:enable :%d\r\n", __func__, xtal_cap->enable);
+ AICWFDBG(LOGINFO, "%s:xtal_cap :%d\r\n", __func__, xtal_cap->xtal_cap);
+ AICWFDBG(LOGINFO, "%s:xtal_cap_fine:%d\r\n", __func__,
+ xtal_cap->xtal_cap_fine);
+}
+
+s8 get_txpwr_max(s8 power)
+{
+ int i = 0;
+
+ for (i = 0; i <= 11; i++) {
+ if (power < userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[i])
+ power = userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[i];
+ }
+ for (i = 0; i <= 9; i++) {
+ if (power < userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[i])
+ power = userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[i];
+ }
+ for (i = 0; i <= 11; i++) {
+ if (power < userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[i])
+ power = userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[i];
+ }
+ for (i = 4; i <= 11; i++) {
+ if (power < userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[i])
+ power = userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[i];
+ }
+ for (i = 0; i <= 9; i++) {
+ if (power < userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[i])
+ power = userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[i];
+ }
+ for (i = 0; i <= 11; i++) {
+ if (power < userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[i])
+ power = userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[i];
+ }
+
+ if (userconfig_info.txpwr_loss.loss_enable_2g4 == 1 ||
+ userconfig_info.txpwr_loss.loss_enable_5g == 1) {
+ if (userconfig_info.txpwr_loss.loss_value_2g4 <
+ userconfig_info.txpwr_loss.loss_value_5g)
+ power += userconfig_info.txpwr_loss.loss_value_5g;
+ else
+ power += userconfig_info.txpwr_loss.loss_value_2g4;
+ }
+
+ AICWFDBG(LOGDEBUG, "AICWF %s:txpwr_max:%d \r\n", __func__, power);
+ return power;
+}
+
+void set_txpwr_loss_ofst(s8 value)
+{
+ int i = 0;
+
+ for (i = 0; i <= 11; i++)
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[i] += value;
+
+ for (i = 0; i <= 9; i++)
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[i] += value;
+
+ for (i = 0; i <= 11; i++)
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[i] += value;
+
+ for (i = 4; i <= 11; i++)
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[i] += value;
+
+ for (i = 0; i <= 9; i++)
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[i] += value;
+
+ for (i = 0; i <= 11; i++)
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[i] += value;
+
+ AICWFDBG(LOGDEBUG, "AICWF %s:value:%d\r\n", __func__, value);
+}
+
+#define MATCH_NODE(type, node, cfg_key) {cfg_key, offsetof(type, node)}
+
+struct parse_match_t {
+ char keyname[64];
+ int offset;
+};
+
+static const char * const parse_key_prefix[] = {
+ [0x01] = "module0_",
+ [0x21] = "module1_",
+};
+
+static const struct parse_match_t parse_match_tab[] = {
+ MATCH_NODE(struct nvram_info_t, txpwr_idx.enable, "enable"),
+ MATCH_NODE(struct nvram_info_t, txpwr_idx.dsss, "dsss"),
+ MATCH_NODE(struct nvram_info_t, txpwr_idx.ofdmlowrate_2g4, "ofdmlowrate_2g4"),
+ MATCH_NODE(struct nvram_info_t, txpwr_idx.ofdm64qam_2g4, "ofdm64qam_2g4"),
+ MATCH_NODE(struct nvram_info_t, txpwr_idx.ofdm256qam_2g4, "ofdm256qam_2g4"),
+ MATCH_NODE(struct nvram_info_t, txpwr_idx.ofdm1024qam_2g4, "ofdm1024qam_2g4"),
+ MATCH_NODE(struct nvram_info_t, txpwr_idx.ofdmlowrate_5g, "ofdmlowrate_5g"),
+ MATCH_NODE(struct nvram_info_t, txpwr_idx.ofdm64qam_5g, "ofdm64qam_5g"),
+ MATCH_NODE(struct nvram_info_t, txpwr_idx.ofdm256qam_5g, "ofdm256qam_5g"),
+ MATCH_NODE(struct nvram_info_t, txpwr_idx.ofdm1024qam_5g, "ofdm1024qam_5g"),
+
+ MATCH_NODE(struct nvram_info_t, txpwr_ofst.enable, "ofst_enable"),
+ MATCH_NODE(struct nvram_info_t, txpwr_ofst.chan_1_4, "ofst_chan_1_4"),
+ MATCH_NODE(struct nvram_info_t, txpwr_ofst.chan_5_9, "ofst_chan_5_9"),
+ MATCH_NODE(struct nvram_info_t, txpwr_ofst.chan_10_13, "ofst_chan_10_13"),
+ MATCH_NODE(struct nvram_info_t, txpwr_ofst.chan_36_64, "ofst_chan_36_64"),
+ MATCH_NODE(struct nvram_info_t, txpwr_ofst.chan_100_120, "ofst_chan_100_120"),
+ MATCH_NODE(struct nvram_info_t, txpwr_ofst.chan_122_140, "ofst_chan_122_140"),
+ MATCH_NODE(struct nvram_info_t, txpwr_ofst.chan_142_165, "ofst_chan_142_165"),
+
+ MATCH_NODE(struct nvram_info_t, xtal_cap.enable, "xtal_enable"),
+ MATCH_NODE(struct nvram_info_t, xtal_cap.xtal_cap, "xtal_cap"),
+ MATCH_NODE(struct nvram_info_t, xtal_cap.xtal_cap_fine, "xtal_cap_fine"),
+};
+
+static int parse_key_val(const char *str, const char *key, char *val)
+{
+ const char *p = NULL;
+ const char *dst = NULL;
+ int keysize = 0;
+ int bufsize = 0;
+
+ if (!str || !key || !val)
+ return -1;
+
+ keysize = strlen(key);
+ bufsize = strlen(str);
+ if (bufsize <= keysize)
+ return -1;
+
+ p = str;
+ while (*p != 0 && *p == ' ')
+ p++;
+
+ if (*p == '#')
+ return -1;
+
+ if (str + bufsize - p <= keysize)
+ return -1;
+
+ if (strncmp(p, key, keysize) != 0)
+ return -1;
+
+ p += keysize;
+
+ while (*p != 0 && *p == ' ')
+ p++;
+
+ if (*p != '=')
+ return -1;
+
+ p++;
+ while (*p != 0 && *p == ' ')
+ p++;
+
+ if (*p == '"')
+ p++;
+
+ dst = p;
+ while (*p != 0)
+ p++;
+
+ p--;
+ while (*p == ' ')
+ p--;
+
+ if (*p == '"')
+ p--;
+
+ while (*p == '\r' || *p == '\n')
+ p--;
+
+ p++;
+ strscpy(val, dst, p - dst);
+ val[p - dst] = 0;
+ return 0;
+}
+
+int rwnx_atoi(char *value)
+{
+ int len = 0;
+ int i = 0;
+ int result = 0;
+ int flag = 1;
+
+ if (value[0] == '-') {
+ flag = -1;
+ value++;
+ }
+ len = strlen(value);
+
+ for (i = 0; i < len; i++) {
+ result = result * 10;
+ if (value[i] >= 48 && value[i] <= 57) {
+ result += value[i] - 48;
+ } else {
+ result = 0;
+ break;
+ }
+ }
+
+ return result * flag;
+}
+
+static int rwnx_parse_mul_value(char *line, char *val[])
+{
+ int nargs = 0;
+
+ while (nargs < 10) {
+ while ((*line == ' ') || (*line == '\t'))
+ ++line;
+
+ if (*line == '\0') { /* end of line, no more args */
+ //AICWFDBG(LOGDEBUG, "%s p1,%d\n", __func__, nargs);
+ return nargs;
+ }
+
+ val[nargs++] = line; /* begin of argument string */
+
+ /* find end of string */
+ while (*line && (*line != ' ') && (*line != '\t'))
+ ++line;
+
+ if (*line == '\0') { /* end of line, no more args */
+ //AICWFDBG(LOGDEBUG, "%s p2,%d\n", __func__, nargs);
+ return nargs;
+ }
+
+ *line++ = '\0'; /* terminate current arg */
+ }
+
+ AICWFDBG(LOGDEBUG, "nargs: %d\n", nargs);
+ //AICWFDBG(LOGDEBUG, "%s exit,%d\n", __func__, nargs);
+ return nargs;
+}
+
+int get_ccode_region(char *ccode)
+{
+ int i, cnt;
+
+ AICWFDBG(LOGDEBUG, "%s ccode:%s\r\n", __func__, ccode);
+ cnt = ARRAY_SIZE(reg_tables);
+
+ for (i = 0; i < cnt; i++) {
+ if (reg_tables[i].ccode[0] == ccode[0] &&
+ reg_tables[i].ccode[1] == ccode[1]) {
+ AICWFDBG(LOGDEBUG, "region: %d\r\n", reg_tables[i].region);
+ return reg_tables[i].region;
+ }
+ }
+ AICWFDBG(LOGDEBUG, "use default region\r\n");
+ return REGIONS_DEFAULT;
+}
+
+void rwnx_plat_nvram_set_value(char *command, char *value)
+{
+ // TODO send command
+ AICWFDBG(LOGDEBUG, "%s:command=%s value=%s\n", __func__, command, value);
+ if (!strcmp(command, "enable")) {
+ userconfig_info.txpwr_lvl.enable = rwnx_atoi(value);
+ userconfig_info.txpwr_lvl_v2.enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "dsss")) {
+ userconfig_info.txpwr_lvl.dsss = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdmlowrate_2g4")) {
+ userconfig_info.txpwr_lvl.ofdmlowrate_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm64qam_2g4")) {
+ userconfig_info.txpwr_lvl.ofdm64qam_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm256qam_2g4")) {
+ userconfig_info.txpwr_lvl.ofdm256qam_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm1024qam_2g4")) {
+ userconfig_info.txpwr_lvl.ofdm1024qam_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdmlowrate_5g")) {
+ userconfig_info.txpwr_lvl.ofdmlowrate_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm64qam_5g")) {
+ userconfig_info.txpwr_lvl.ofdm64qam_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm256qam_5g")) {
+ userconfig_info.txpwr_lvl.ofdm256qam_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm1024qam_5g")) {
+ userconfig_info.txpwr_lvl.ofdm1024qam_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_1m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_2m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_5m5_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_11m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_6m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_9m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_12m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[6] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_18m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[7] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_24m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[8] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_36m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[9] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_48m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[10] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_54m_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[11] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs0_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs1_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs2_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs3_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs4_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs5_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs6_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[6] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs7_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[7] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs8_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[8] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs9_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[9] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs0_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs1_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs2_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs3_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs4_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs5_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs6_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[6] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs7_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[7] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs8_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[8] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs9_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[9] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs10_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[10] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs11_2g4")) {
+ userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[11] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_enable")) {
+ userconfig_info.txpwr_ofst.enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_1_4")) {
+ userconfig_info.txpwr_ofst.chan_1_4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_5_9")) {
+ userconfig_info.txpwr_ofst.chan_5_9 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_10_13")) {
+ userconfig_info.txpwr_ofst.chan_10_13 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_36_64")) {
+ userconfig_info.txpwr_ofst.chan_36_64 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_100_120")) {
+ userconfig_info.txpwr_ofst.chan_100_120 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_122_140")) {
+ userconfig_info.txpwr_ofst.chan_122_140 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_142_165")) {
+ userconfig_info.txpwr_ofst.chan_142_165 = rwnx_atoi(value);
+ } else if (!strcmp(command, "xtal_enable")) {
+ userconfig_info.xtal_cap.enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "xtal_cap")) {
+ userconfig_info.xtal_cap.xtal_cap = rwnx_atoi(value);
+ } else if (!strcmp(command, "xtal_cap_fine")) {
+ userconfig_info.xtal_cap.xtal_cap_fine = rwnx_atoi(value);
+ } else {
+ AICWFDBG(LOGERROR, "invalid cmd: %s\n", command);
+ }
+}
+
+void rwnx_plat_nvram_set_value_group(char *command, char *value)
+{
+ char *mul_val[10];
+ int i;
+
+ // TODO send command
+ AICWFDBG(LOGDEBUG, "%s:command=%s value=%s\n", __func__, command, value);
+ if (!strcmp(command, "enable")) {
+ userconfig_info.txpwr_lvl.enable = rwnx_atoi(value);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "dsss")) {
+ userconfig_info.txpwr_lvl.dsss = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdmlowrate_2g4")) {
+ userconfig_info.txpwr_lvl.ofdmlowrate_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm64qam_2g4")) {
+ userconfig_info.txpwr_lvl.ofdm64qam_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm256qam_2g4")) {
+ userconfig_info.txpwr_lvl.ofdm256qam_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm1024qam_2g4")) {
+ userconfig_info.txpwr_lvl.ofdm1024qam_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdmlowrate_5g")) {
+ userconfig_info.txpwr_lvl.ofdmlowrate_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm64qam_5g")) {
+ userconfig_info.txpwr_lvl.ofdm64qam_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm256qam_5g")) {
+ userconfig_info.txpwr_lvl.ofdm256qam_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm1024qam_5g")) {
+ userconfig_info.txpwr_lvl.ofdm1024qam_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_1m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[0] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_2m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[1] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_5m5_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[2] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_11m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[3] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_6m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[4] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_9m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[5] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_12m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[6] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_18m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[7] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_24m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[8] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_36m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[9] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_48m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[10] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11b_11ag_54m_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11b_11ag_2g4[11] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs0_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_2g4[0] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs1_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_2g4[1] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs2_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_2g4[2] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs3_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_2g4[3] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs4_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_2g4[4] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs5_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_2g4[5] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs6_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_2g4[6] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs7_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_2g4[7] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs8_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_2g4[8] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs9_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_2g4[9] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs0_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[0] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs1_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[1] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs2_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[2] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs3_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[3] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs4_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[4] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs5_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[5] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs6_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[6] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs7_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[7] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs8_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[8] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs9_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[9] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs10_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[10] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs11_2g4")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_2g4[11] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_1m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[0] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_2m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[1] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_5m5_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[2] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_11m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[3] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_6m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[4] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_9m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[5] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_12m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[6] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_18m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[7] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_24m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[8] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_36m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[9] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_48m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[10] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11a_54m_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11a_5g[11] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs0_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_5g[0] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs1_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_5g[1] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs2_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_5g[2] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs3_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_5g[3] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs4_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_5g[4] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs5_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_5g[5] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs6_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_5g[6] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs7_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_5g[7] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs8_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_5g[8] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs9_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11n_11ac_5g[9] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs0_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[0] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs1_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[1] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs2_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[2] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs3_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[3] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs4_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[4] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs5_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[5] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs6_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[6] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs7_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[7] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs8_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[8] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs9_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[9] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs10_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[10] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_11ax_mcs11_5g")) {
+ rwnx_parse_mul_value(value, mul_val);
+ for (i = 0; i < REGION_NUM_MAX; i++)
+ userconfig_info.txpwr_lvl_v3_gp[i].pwrlvl_11ax_5g[11] =
+ rwnx_atoi(mul_val[i]);
+ } else if (!strcmp(command, "lvl_adj_enable")) {
+ userconfig_info.txpwr_lvl_adj.enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_2g4_chan_1_4")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_2g4_chan_5_9")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_2g4_chan_10_13")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_42")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_58")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_106")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_122")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_138")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_155")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "loss_enable_2g4")) {
+ userconfig_info.txpwr_loss.loss_enable_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "loss_value_2g4")) {
+ userconfig_info.txpwr_loss.loss_value_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "loss_enable_5g")) {
+ userconfig_info.txpwr_loss.loss_enable_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "loss_value_5g")) {
+ userconfig_info.txpwr_loss.loss_value_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_enable")) {
+ userconfig_info.txpwr_ofst.enable = rwnx_atoi(value);
+ userconfig_info.txpwr_ofst2x.enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_1_4")) {
+ userconfig_info.txpwr_ofst.chan_1_4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_5_9")) {
+ userconfig_info.txpwr_ofst.chan_5_9 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_10_13")) {
+ userconfig_info.txpwr_ofst.chan_10_13 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_36_64")) {
+ userconfig_info.txpwr_ofst.chan_36_64 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_100_120")) {
+ userconfig_info.txpwr_ofst.chan_100_120 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_122_140")) {
+ userconfig_info.txpwr_ofst.chan_122_140 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_142_165")) {
+ userconfig_info.txpwr_ofst.chan_142_165 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_11b_chan_1_4")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_11b_chan_5_9")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_11b_chan_10_13")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_1_4")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_5_9")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_10_13")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_1_4")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_5_9")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_10_13")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_42")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_58")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_106")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_122")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_138")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_155")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_42")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_58")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_106")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_122")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_138")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_155")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_42")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_58")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_106")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_122")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_138")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_155")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "xtal_enable")) {
+ userconfig_info.xtal_cap.enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "xtal_cap")) {
+ userconfig_info.xtal_cap.xtal_cap = rwnx_atoi(value);
+ } else if (!strcmp(command, "xtal_cap_fine")) {
+ userconfig_info.xtal_cap.xtal_cap_fine = rwnx_atoi(value);
+ } else {
+ AICWFDBG(LOGERROR, "invalid cmd: %s\n", command);
+ }
+}
+
+void rwnx_plat_nvram_set_value_v3(char *command, char *value)
+{
+ // TODO send command
+ AICWFDBG(LOGDEBUG, "%s:command=%s value=%s\n", __func__, command, value);
+ //AICWFDBG(LOGDEBUG, "AICWF command=%s value=%s\n", command, value);
+ if (!strcmp(command, "enable")) {
+ userconfig_info.txpwr_lvl.enable = rwnx_atoi(value);
+ userconfig_info.txpwr_lvl_v3.enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "dsss")) {
+ userconfig_info.txpwr_lvl.dsss = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdmlowrate_2g4")) {
+ userconfig_info.txpwr_lvl.ofdmlowrate_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm64qam_2g4")) {
+ userconfig_info.txpwr_lvl.ofdm64qam_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm256qam_2g4")) {
+ userconfig_info.txpwr_lvl.ofdm256qam_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm1024qam_2g4")) {
+ userconfig_info.txpwr_lvl.ofdm1024qam_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdmlowrate_5g")) {
+ userconfig_info.txpwr_lvl.ofdmlowrate_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm64qam_5g")) {
+ userconfig_info.txpwr_lvl.ofdm64qam_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm256qam_5g")) {
+ userconfig_info.txpwr_lvl.ofdm256qam_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofdm1024qam_5g")) {
+ userconfig_info.txpwr_lvl.ofdm1024qam_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_1m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_2m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_5m5_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_11m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_6m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_9m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_12m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[6] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_18m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[7] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_24m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[8] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_36m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[9] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_48m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[10] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11b_11ag_54m_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[11] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs0_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs1_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs2_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs3_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs4_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs5_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs6_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[6] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs7_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[7] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs8_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[8] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs9_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[9] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs0_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs1_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs2_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs3_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs4_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs5_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs6_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[6] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs7_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[7] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs8_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[8] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs9_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[9] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs10_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[10] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs11_2g4")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[11] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_1m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_2m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_5m5_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_11m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_6m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_9m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_12m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[6] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_18m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[7] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_24m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[8] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_36m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[9] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_48m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[10] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11a_54m_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[11] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs0_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs1_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs2_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs3_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs4_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs5_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs6_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[6] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs7_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[7] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs8_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[8] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11n_11ac_mcs9_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[9] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs0_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs1_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs2_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs3_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs4_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs5_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs6_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[6] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs7_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[7] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs8_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[8] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs9_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[9] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs10_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[10] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_11ax_mcs11_5g")) {
+ userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[11] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_enable")) {
+ userconfig_info.txpwr_lvl_adj.enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_2g4_chan_1_4")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_2g4_chan_5_9")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_2g4_chan_10_13")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_2g4[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_42")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_58")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_106")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_122")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_138")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "lvl_adj_5g_chan_155")) {
+ userconfig_info.txpwr_lvl_adj.pwrlvl_adj_tbl_5g[5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "loss_enable_2g4")) {
+ userconfig_info.txpwr_loss.loss_enable_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "loss_value_2g4")) {
+ userconfig_info.txpwr_loss.loss_value_2g4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "loss_enable_5g")) {
+ userconfig_info.txpwr_loss.loss_enable_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "loss_value_5g")) {
+ userconfig_info.txpwr_loss.loss_value_5g = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_enable")) {
+ userconfig_info.txpwr_ofst.enable = rwnx_atoi(value);
+ userconfig_info.txpwr_ofst2x.enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_1_4")) {
+ userconfig_info.txpwr_ofst.chan_1_4 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_5_9")) {
+ userconfig_info.txpwr_ofst.chan_5_9 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_10_13")) {
+ userconfig_info.txpwr_ofst.chan_10_13 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_36_64")) {
+ userconfig_info.txpwr_ofst.chan_36_64 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_100_120")) {
+ userconfig_info.txpwr_ofst.chan_100_120 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_122_140")) {
+ userconfig_info.txpwr_ofst.chan_122_140 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_chan_142_165")) {
+ userconfig_info.txpwr_ofst.chan_142_165 = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_11b_chan_1_4")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_11b_chan_5_9")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_11b_chan_10_13")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[0][2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_1_4")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_5_9")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_highrate_chan_10_13")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[1][2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_1_4")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_5_9")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_2g4_ofdm_lowrate_chan_10_13")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_2g4[2][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_42")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_58")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_106")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_122")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_138")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_lowrate_chan_155")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[0][5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_42")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_58")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_106")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_122")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_138")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_highrate_chan_155")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[1][5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_42")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][0] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_58")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][1] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_106")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][2] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_122")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][3] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_138")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][4] = rwnx_atoi(value);
+ } else if (!strcmp(command, "ofst_5g_ofdm_midrate_chan_155")) {
+ userconfig_info.txpwr_ofst2x.pwrofst2x_tbl_5g[2][5] = rwnx_atoi(value);
+ } else if (!strcmp(command, "xtal_enable")) {
+ userconfig_info.xtal_cap.enable = rwnx_atoi(value);
+ } else if (!strcmp(command, "xtal_cap")) {
+ userconfig_info.xtal_cap.xtal_cap = rwnx_atoi(value);
+ } else if (!strcmp(command, "xtal_cap_fine")) {
+ userconfig_info.xtal_cap.xtal_cap_fine = rwnx_atoi(value);
+ } else {
+ AICWFDBG(LOGERROR, "invalid cmd: %s\n", command);
+ }
+}
+
+void rwnx_plat_userconfig_parsing2(char *buffer, int size)
+{
+ int i = 0;
+ int parse_state = 0;
+ char command[30];
+ char value[100];
+ int char_counter = 0;
+
+ memset(command, 0, 30);
+ memset(value, 0, 100);
+
+ for (i = 0; i < size; i++) {
+ // Send command or print nvram log when char is \r or \n
+ if (buffer[i] == 0x0a || buffer[i] == 0x0d) {
+ if (command[0] != 0 && value[0] != 0) {
+ if (parse_state == PRINT)
+ AICWFDBG(LOGINFO, "%s:%s\r\n", __func__, value);
+ else if (parse_state == GET_VALUE)
+ rwnx_plat_nvram_set_value(command, value);
+ }
+ // Reset command value and char_counter
+ memset(command, 0, 30);
+ memset(value, 0, 100);
+ char_counter = 0;
+ parse_state = INIT;
+ continue;
+ }
+
+ // Switch parser state
+ if (parse_state == INIT) {
+ if (buffer[i] == '#') {
+ parse_state = PRINT;
+ continue;
+ } else if (buffer[i] == 0x0a || buffer[i] == 0x0d) {
+ parse_state = INIT;
+ continue;
+ } else {
+ parse_state = CMD;
+ }
+ }
+
+ // Fill data to command and value
+ if (parse_state == PRINT) {
+ command[0] = 0x01;
+ value[char_counter] = buffer[i];
+ char_counter++;
+ } else if (parse_state == CMD) {
+ if (command[0] != 0 && buffer[i] == '=') {
+ parse_state = GET_VALUE;
+ char_counter = 0;
+ continue;
+ }
+ command[char_counter] = buffer[i];
+ char_counter++;
+ } else if (parse_state == GET_VALUE) {
+ value[char_counter] = buffer[i];
+ char_counter++;
+ }
+ }
+}
+
+void rwnx_plat_userconfig_parsing3(char *buffer, int size)
+{
+ int i = 0;
+ int parse_state = 0;
+ char command[64];
+ char value[100];
+ int char_counter = 0;
+ u8 area_pw = 0;
+
+ memset(command, 0, 64);
+ memset(value, 0, 100);
+
+ for (i = 0; i < size; i++) {
+ // Send command or print nvram log when char is \r or \n
+ if (buffer[i] == 0x0a || buffer[i] == 0x0d) {
+ if (command[0] != 0 && value[0] != 0) {
+ if (parse_state == PRINT) {
+ if (area_pw == 0 &&
+ strnstr(value, "SRRC", strlen(value))) {
+ area_pw = 1;
+ AICWFDBG(LOGINFO,
+ "use diff_area_power userconfig\n");
+ }
+ AICWFDBG(LOGINFO, "%s:%s\r\n", __func__, value);
+ } else if (parse_state == GET_VALUE) {
+ if (area_pw)
+ rwnx_plat_nvram_set_value_group(command, value);
+ else
+ rwnx_plat_nvram_set_value_v3(command, value);
+ }
+ }
+ // Reset command value and char_counter
+ memset(command, 0, 64);
+ memset(value, 0, 100);
+ char_counter = 0;
+ parse_state = INIT;
+ continue;
+ }
+
+ // Switch parser state
+ if (parse_state == INIT) {
+ if (buffer[i] == '#') {
+ parse_state = PRINT;
+ continue;
+ } else if (buffer[i] == 0x0a || buffer[i] == 0x0d) {
+ parse_state = INIT;
+ continue;
+ } else {
+ parse_state = CMD;
+ }
+ }
+
+ // Fill data to command and value
+ if (parse_state == PRINT) {
+ command[0] = 0x01;
+ value[char_counter] = buffer[i];
+ char_counter++;
+ } else if (parse_state == CMD) {
+ if (command[0] != 0 && buffer[i] == '=') {
+ parse_state = GET_VALUE;
+ char_counter = 0;
+ continue;
+ }
+ command[char_counter] = buffer[i];
+ char_counter++;
+ } else if (parse_state == GET_VALUE) {
+ if (buffer[i] != 0x2D &&
+ (buffer[i] < 0x30 || buffer[i] > 0x39) &&
+ buffer[i] != 0x20)
+ continue;
+ value[char_counter] = buffer[i];
+ char_counter++;
+ }
+ }
+}
+
+void rwnx_plat_userconfig_parsing(struct rwnx_hw *rwnx_hw, char *buffer,
+ int size)
+{
+ char conf[100], keyname[64];
+ char *line;
+ char *data;
+ int i = 0, len = 0;
+ long val;
+
+ if (size <= 0) {
+ pr_err("Config buffer size %d error\n", size);
+ return;
+ }
+
+ AICWFDBG(LOGDEBUG, "AICWF %s rwnx_hw->vendor_info:0x%02X \r\n", __func__,
+ rwnx_hw->vendor_info);
+ if (rwnx_hw->vendor_info == 0x00 ||
+ rwnx_hw->vendor_info > (ARRAY_SIZE(parse_key_prefix) - 1)) {
+ AICWFDBG(LOGDEBUG, "AICWF Unsuppor vendor info config\n");
+ AICWFDBG(LOGDEBUG, "AICWF Using module0 config\n");
+ rwnx_hw->vendor_info = 0x01;
+ // return;
+ }
+
+ data = vmalloc(size + 1);
+ if (!data) {
+ AICWFDBG(LOGERROR, "%s vmalloc fail\n", __func__);
+ return;
+ }
+
+ memcpy(data, buffer, size);
+ buffer = data;
+
+ while (1) {
+ line = buffer;
+ if (*line == 0)
+ break;
+
+ while (*buffer != '\r' && *buffer != '\n' &&
+ *buffer != 0 && len++ < size)
+ buffer++;
+
+ while ((*buffer == '\r' || *buffer == '\n') && len++ < size)
+ *buffer++ = 0;
+
+ if (len >= size)
+ *buffer = 0;
+
+ // store value to data struct
+ for (i = 0; i < ARRAY_SIZE(parse_match_tab); i++) {
+ scnprintf(keyname, sizeof(keyname), "%s%s",
+ parse_key_prefix[rwnx_hw->vendor_info],
+ parse_match_tab[i].keyname);
+ if (parse_key_val(line, keyname, conf) == 0) {
+ if (kstrtol(conf, 0, &val)) {
+ pr_warn("Invalid value for %s\n", keyname);
+ continue;
+ }
+ *(unsigned long *)((unsigned long)&nvram_info +
+ parse_match_tab[i].offset) = val;
+ AICWFDBG(LOGDEBUG, "AICWF %s, %s = %ld\n", __func__,
+ parse_match_tab[i].keyname, val);
+ break;
+ }
+ }
+ }
+ vfree(data);
+}
+
+int rwnx_plat_userconfig_upload(struct rwnx_hw *rwnx_hw,
+ const char *filename)
+{
+ int size;
+ u32 *dst = NULL;
+
+ AICWFDBG(LOGDEBUG, "AICWF userconfig file path:%s \r\n", filename);
+
+ /* load aic firmware */
+ size = rwnx_load_firmware(&dst, filename, rwnx_hw->dev);
+ if (size <= 0) {
+ AICWFDBG(LOGDEBUG, "AICWF wrong size of firmware file\n");
+ vfree(dst);
+ dst = NULL;
+ return 0;
+ }
+
+ /* Copy the file on the Embedded side */
+ AICWFDBG(LOGDEBUG, "AICWF ### Upload %s userconfig, size=%d\n", filename, size);
+
+ rwnx_plat_userconfig_parsing(rwnx_hw, (char *)dst, size);
+
+ if (dst) {
+ vfree(dst);
+ dst = NULL;
+ }
+
+ AICWFDBG(LOGDEBUG, "AICWF userconfig download complete\n\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+static inline char *get_line_from_buffer(char **buffer)
+{
+ return strsep(buffer, "\n");
+}
+
+int is_all_space_or_tab(u8 *data, u8 size)
+{
+ u8 cnt = 0;
+ u8 num_of_space_and_tab = 0;
+
+ while (size > cnt) {
+ if (data[cnt] == ' ' || data[cnt] == '\t' || data[cnt] == '\0')
+ ++num_of_space_and_tab;
+ ++cnt;
+ }
+ return size == num_of_space_and_tab;
+}
+
+int is_comment_string(char *sz_str)
+{
+ if (*sz_str == '#' && *(sz_str + 1) == ' ')
+ return 1;
+ else
+ return 0;
+}
+
+int is_enable_limit(char *szs_str)
+{
+ int i = 0, value = 0;
+ char en[15];
+
+ if (*szs_str == '#' && *(szs_str + 1) == '*') {
+ i = 2;
+ while (szs_str[i] != '=' && (i < 15)) {
+ en[i - 2] = szs_str[i];
+ i++;
+ }
+ en[i - 2] = '\0';
+ i += 1;
+ if (strncmp(en, "enable", 6) == 0) {
+ value = rwnx_atoi(szs_str + i);
+ if (value == 1)
+ return 1;
+ else
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int parse_qualified_string(char *in, u32 *start, char *out, char left_qualifier,
+ char right_qualifier)
+{
+ u32 i = 0, j = 0;
+ char c = in[(*start)++];
+
+ if (c != left_qualifier)
+ return 0;
+ i = (*start);
+ c = in[(*start)++];
+ while (c != right_qualifier && c != '\0')
+ c = in[(*start)++];
+ if (c == '\0')
+ return 0;
+ j = (*start) - 2;
+ strscpy((char *)out, (const char *)(in + i), j - i + 1);
+ return 1;
+}
+
+int get_u1_byte_integer_from_string_in_decimal(char *str, u8 *p_int)
+{
+ u16 i = 0;
+ *p_int = 0;
+ while (str[i] != '\0') {
+ if (str[i] >= '0' && str[i] <= '9') {
+ *p_int *= 10;
+ *p_int += (str[i] - '0');
+ } else {
+ return 0;
+ }
+ ++i;
+ }
+ return 1;
+}
+
+int get_s1_byte_integer_from_string_in_decimal(char *str, s8 *val)
+{
+ u8 negative = 0;
+ u16 i = 0;
+ *val = 0;
+ while (str[i] != '\0') {
+ if (i == 0 && (str[i] == '+' || str[i] == '-')) {
+ if (str[i] == '-')
+ negative = 1;
+ } else if (str[i] >= '0' && str[i] <= '9') {
+ *val *= 10;
+ *val += (str[i] - '0');
+ } else {
+ return 0;
+ }
+ ++i;
+ }
+ if (negative)
+ *val = -*val;
+ return 1;
+}
+
+static void update_power_limit(u8 band_cc, const char *channel, u8 channel_num,
+ const char *power_limit, u8 power_limit_val,
+ struct powerlimit_info_t *powerlimit_info)
+{
+ if (band_cc == PHY_BAND_2G4) {
+ u8 cur_idx = powerlimit_info->txpwr_lmt.ch_cnt_2g4;
+
+ if (cur_idx == 0)
+ AICWFDBG(LOGDEBUG, "[%d]: ch=%s, pwr=%s\n", cur_idx, channel, power_limit);
+ if (cur_idx < MAC_DOMAINCHANNEL_24G_MAX) {
+ powerlimit_info->txpwr_lmt.ch_num_2g4[cur_idx] = channel_num;
+ powerlimit_info->txpwr_lmt.max_pwr_2g4[cur_idx] = power_limit_val;
+ powerlimit_info->txpwr_lmt.ch_cnt_2g4++;
+ } else {
+ AICWFDBG(LOGERROR, "band %d chan_cnt reached %d\n",
+ band_cc, MAC_DOMAINCHANNEL_24G_MAX);
+ AICWFDBG(LOGERROR, "channel=%s(%d) powerLimit=%s(%d)\n",
+ channel, channel_num, power_limit, power_limit_val);
+ }
+ } else if (band_cc == PHY_BAND_5G) {
+ u8 cur_idx = powerlimit_info->txpwr_lmt.ch_cnt_5g;
+
+ if (cur_idx == 0)
+ AICWFDBG(LOGDEBUG, "[%d]: ch=%s, pwr=%s\n", cur_idx, channel, power_limit);
+ if (cur_idx < MAC_DOMAINCHANNEL_5G_MAX) {
+ powerlimit_info->txpwr_lmt.ch_num_5g[cur_idx] = channel_num;
+ powerlimit_info->txpwr_lmt.max_pwr_5g[cur_idx] = power_limit_val;
+ powerlimit_info->txpwr_lmt.ch_cnt_5g++;
+ } else {
+ AICWFDBG(LOGERROR, "band %d chan_cnt reached %d\n",
+ band_cc, MAC_DOMAINCHANNEL_5G_MAX);
+ AICWFDBG(LOGERROR, "channel=%s(%d) powerLimit=%s(%d)\n",
+ channel, channel_num, power_limit, power_limit_val);
+ }
+ }
+}
+
+void rwnx_plat_powerlimit_parsing(char *buffer, int size, char *cc)
+{
+#define LD_STAGE_EXC_MAPPING 0
+#define LD_STAGE_TAB_DEFINE 1
+#define LD_STAGE_TAB_START 2
+#define LD_STAGE_COLUMN_DEFINE 3
+#define LD_STAGE_CH_ROW 4
+
+ u8 loading_stage = LD_STAGE_EXC_MAPPING;
+ u32 i = 0, for_cnt = 0;
+ u32 i_cc;
+ char *sz_line, *ptmp;
+ char band[10], col_num_buf[10];
+ u8 col_num = 0, col_num_cc = 255, band_cc = 0;
+ bool sp_cc = false;
+ // clear powerlimit info at first
+ memset((void *)&powerlimit_info, 0, sizeof(struct powerlimit_info_t));
+ ptmp = buffer;
+ for (sz_line = get_line_from_buffer(&ptmp); sz_line;
+ sz_line = get_line_from_buffer(&ptmp)) {
+ if (is_all_space_or_tab(sz_line, sizeof(*sz_line)))
+ continue;
+
+ if (is_enable_limit(sz_line) == 0)
+ return;
+
+ if (is_comment_string(sz_line))
+ continue;
+
+ if (loading_stage == LD_STAGE_EXC_MAPPING) {
+ if (sz_line[0] == '#' || sz_line[1] == '#')
+ loading_stage = LD_STAGE_TAB_DEFINE;
+ else
+ continue;
+ }
+
+ if (loading_stage == LD_STAGE_TAB_DEFINE) {
+ /* read "## 2.4G" */
+ if (sz_line[0] != '#' || sz_line[1] != '#')
+ continue;
+
+ /* skip the space */
+ i = 2;
+ while (sz_line[i] == ' ' || sz_line[i] == '\t')
+ ++i;
+
+ sz_line[--i] =
+ ' '; /* return the space in front of the regulation info */
+
+ /* Parse the label of the table */
+ memset((void *)band, 0, 10);
+ if (!parse_qualified_string(sz_line, &i, band, ' ', ',')) {
+ AICWFDBG(LOGERROR, "Fail to parse band!\n");
+ goto exit;
+ }
+ if (strncmp(band, "2.4G", 4) == 0)
+ band_cc = PHY_BAND_2G4;
+ else if (strncmp(band, "5G", 2) == 0)
+ band_cc = PHY_BAND_5G;
+
+ memset((void *)col_num_buf, 0, 10);
+ if (!parse_qualified_string(sz_line, &i, col_num_buf, '#', '#')) {
+ AICWFDBG(LOGERROR, "Fail to parse column number!\n");
+ goto exit;
+ }
+ if (!get_u1_byte_integer_from_string_in_decimal(col_num_buf, &col_num)) {
+ AICWFDBG(LOGERROR,
+ "Column number \"%s\" is not unsigned decimal\n",
+ col_num_buf);
+ goto exit;
+ }
+ if (col_num == 0) {
+ AICWFDBG(LOGERROR, "Column number is 0\n");
+ goto exit;
+ }
+
+ AICWFDBG(LOGDEBUG, "band=%s(%d)\n", band, band_cc);
+ loading_stage = LD_STAGE_TAB_START;
+ } else if (loading_stage == LD_STAGE_TAB_START) {
+ /* read "## START" */
+ if (sz_line[0] != '#' || sz_line[1] != '#')
+ continue;
+
+ /* skip the space */
+ i = 2;
+ while (sz_line[i] == ' ' || sz_line[i] == '\t')
+ ++i;
+
+ if (strncmp((u8 *)(sz_line + i), "START", 5)) {
+ AICWFDBG(LOGERROR, "Missing \"## START\" label\n");
+ goto exit;
+ }
+
+ loading_stage = LD_STAGE_COLUMN_DEFINE;
+ } else if (loading_stage == LD_STAGE_COLUMN_DEFINE) {
+ /* read "## CN US" */
+ if (sz_line[0] != '#' || sz_line[1] != '#')
+ continue;
+
+ /* skip the space */
+ i = 2;
+ while (sz_line[i] == ' ' || sz_line[i] == '\t')
+ ++i;
+
+ for (for_cnt = 0; for_cnt < col_num; for_cnt++) {
+ /* skip the space */
+ while (sz_line[i] == ' ' || sz_line[i] == '\t')
+ i++;
+ i_cc = i;
+
+ while (sz_line[i] != ' ' && sz_line[i] != '\t' &&
+ sz_line[i] != '\0')
+ i++;
+
+ if ((i - i_cc) != 2) {
+ AICWFDBG(LOGERROR, "CC len err\n");
+ goto exit;
+ } else if ((sz_line[i_cc] == cc[0]) &&
+ (sz_line[i_cc + 1] == cc[1])) {
+ AICWFDBG(LOGDEBUG, "CC matched: %s, col=%d\n", cc, for_cnt);
+ col_num_cc = for_cnt;
+ powerlimit_info.flags |= POWER_LIMIT_CC_MATCHED_BIT;
+ sp_cc = true;
+ break;
+ }
+ }
+ if (!sp_cc) {
+ col_num_cc = col_num - 1;
+ AICWFDBG(LOGDEBUG, "use 00: %s, col_num_cc=%d\n", cc, col_num_cc);
+ powerlimit_info.flags |= POWER_LIMIT_CC_MATCHED_BIT;
+ }
+
+ loading_stage = LD_STAGE_CH_ROW;
+ } else if (loading_stage == LD_STAGE_CH_ROW) {
+ char channel[10] = {0}, power_limit[10] = {0};
+ u8 channel_num, power_limit_val, cnt = 0;
+
+ /* the table ends */
+ if (sz_line[0] == '#' && sz_line[1] == '#') {
+ i = 2;
+ while (sz_line[i] == ' ' || sz_line[i] == '\t')
+ ++i;
+
+ if (strncmp((u8 *)(sz_line + i), "END", 3) == 0) {
+ loading_stage = LD_STAGE_TAB_DEFINE;
+ col_num = 0;
+ continue;
+ } else {
+ AICWFDBG(LOGERROR, "Missing \"## END\" label\n");
+ goto exit;
+ }
+ }
+
+ if ((sz_line[0] != 'c' && sz_line[0] != 'C') ||
+ (sz_line[1] != 'h' && sz_line[1] != 'H')) {
+ AICWFDBG(LOGERROR, "Wrong channel prefix: '%c','%c'(%d,%d)\n",
+ sz_line[0], sz_line[1], sz_line[0], sz_line[1]);
+ continue;
+ }
+ i = 2; /* move to the location behind 'h' */
+
+ /* load the channel number */
+ cnt = 0;
+ while (sz_line[i] >= '0' && sz_line[i] <= '9') {
+ channel[cnt] = sz_line[i];
+ ++cnt;
+ ++i;
+ }
+
+ for (for_cnt = 0; for_cnt < col_num; ++for_cnt) {
+ /* skip the space between channel number and the power limit
+ * value
+ */
+ while (sz_line[i] == ' ' || sz_line[i] == '\t')
+ ++i;
+
+ /* load the power limit value */
+ memset((void *)power_limit, 0, 10);
+
+ if (sz_line[i] == 'N' && sz_line[i + 1] == 'A') {
+ /*
+ * means channel not available
+ */
+ sprintf(power_limit, "%d", POWER_LIMIT_INVALID_VAL);
+ i += 2;
+ } else if ((sz_line[i] >= '0' && sz_line[i] <= '9') ||
+ sz_line[i] == '+' || sz_line[i] == '-') {
+ /* case of dBm value */
+ cnt = 0;
+ while ((sz_line[i] >= '0' && sz_line[i] <= '9') ||
+ sz_line[i] == '+' || sz_line[i] == '-') {
+ power_limit[cnt] = sz_line[i];
+ ++cnt;
+ ++i;
+ }
+ } else {
+ AICWFDBG
+ (LOGERROR, "Wrong limit expression \"%c%c\"(%d, %d)\n",
+ sz_line[i], sz_line[i + 1], sz_line[i], sz_line[i + 1]);
+ goto exit;
+ }
+
+ if (for_cnt == col_num_cc) {
+ /* store the power limit value */
+ if (get_u1_byte_integer_from_string_in_decimal
+ ((char *)channel, &channel_num) == 0 ||
+ get_s1_byte_integer_from_string_in_decimal
+ ((char *)power_limit, &power_limit_val) == 0) {
+ AICWFDBG(LOGERROR,
+ "Illegal index of power limit table [ch %s][val %s]\n",
+ channel, power_limit);
+ goto exit;
+ }
+
+ update_power_limit(band_cc, channel, channel_num,
+ power_limit, power_limit_val,
+ &powerlimit_info);
+ break;
+ }
+ }
+ }
+ }
+exit:
+ return;
+}
+
+/// 5G lower bound freq
+#define PHY_FREQ_5G 5000
+
+u16 phy_channel_to_freq(u8 band, int channel)
+{
+ if (band == PHY_BAND_2G4 && channel >= 1 && channel <= 14) {
+ if (channel == 14)
+ return 2484;
+ else
+ return 2407 + channel * 5;
+ } else if (band == PHY_BAND_5G && channel >= 1 && channel <= 165) {
+ return PHY_FREQ_5G + channel * 5;
+ }
+ return 0;
+}
+
+s8 get_powerlimit_by_freq(u8 band, u16 freq, u8 *enable)
+{
+ s8 ret = POWER_LIMIT_INVALID_VAL;
+ u8 idx;
+
+ if ((powerlimit_info.flags & POWER_LIMIT_CC_MATCHED_BIT) == 0) {
+ *enable = 0;
+ } else if (powerlimit_info.flags & POWER_LIMIT_CC_MATCHED_BIT) {
+ *enable = 1;
+
+ if (band == PHY_BAND_2G4) {
+ u8 idx_cnt = powerlimit_info.txpwr_lmt.ch_cnt_2g4;
+
+ for (idx = 0; idx < idx_cnt; idx++) {
+ int ch_num = powerlimit_info.txpwr_lmt.ch_num_2g4[idx];
+ u16 freq_tmp = phy_channel_to_freq(PHY_BAND_2G4, ch_num);
+
+ if (freq == freq_tmp) {
+ ret = powerlimit_info.txpwr_lmt.max_pwr_2g4[idx];
+ // AICWFDBG(LOGINFO, "[%d]: ch=%d(freq=%d), pwr=%d\n", idx,
+ // ch_num, freq, ret);
+ break;
+ }
+ }
+ if (idx == idx_cnt) {
+ AICWFDBG(LOGERROR,
+ "powerlimit search failed: band=%d freq=%d\n", band,
+ freq);
+ }
+ } else if (band == PHY_BAND_5G) {
+ u8 idx_cnt = powerlimit_info.txpwr_lmt.ch_cnt_5g;
+
+ for (idx = 0; idx < idx_cnt; idx++) {
+ int ch_num = powerlimit_info.txpwr_lmt.ch_num_5g[idx];
+ u16 freq_tmp = phy_channel_to_freq(PHY_BAND_5G, ch_num);
+
+ if (freq == freq_tmp) {
+ ret = powerlimit_info.txpwr_lmt.max_pwr_5g[idx];
+ // AICWFDBG(LOGINFO, "[%d]: ch=%d(freq=%d), pwr=%d\n", idx,
+ // ch_num, freq, ret);
+ break;
+ }
+ }
+ if (idx == idx_cnt) {
+ AICWFDBG(LOGERROR,
+ "powerlimit search failed: band=%d freq=%d\n", band,
+ freq);
+ }
+ }
+ }
+ return ret;
+}
+
+s8 get_powerlimit_by_chnum(u8 chnum, u8 *enable)
+{
+ s8 ret = POWER_LIMIT_INVALID_VAL;
+ u8 idx;
+
+ if ((powerlimit_info.flags & POWER_LIMIT_CC_MATCHED_BIT) == 0) {
+ *enable = 0;
+ } else if (powerlimit_info.flags & POWER_LIMIT_CC_MATCHED_BIT) {
+ *enable = 1;
+
+ if (chnum <= 14) {
+ u8 idx_cnt = powerlimit_info.txpwr_lmt.ch_cnt_2g4;
+
+ for (idx = 0; idx < idx_cnt; idx++) {
+ u8 ch_num = powerlimit_info.txpwr_lmt.ch_num_2g4[idx];
+
+ if (chnum == ch_num) {
+ ret = powerlimit_info.txpwr_lmt.max_pwr_2g4[idx];
+ // AICWFDBG(LOGINFO, "[%d]: ch=%d, pwr=%d\n", idx, ch_num,
+ // ret);
+ break;
+ }
+ }
+ if (idx == idx_cnt) {
+ AICWFDBG(LOGERROR, "powerlimit search failed: chnum=%d\n",
+ chnum);
+ }
+ } else if (chnum <= 165) {
+ u8 idx_cnt = powerlimit_info.txpwr_lmt.ch_cnt_5g;
+
+ for (idx = 0; idx < idx_cnt; idx++) {
+ int ch_num = powerlimit_info.txpwr_lmt.ch_num_5g[idx];
+
+ if (chnum == ch_num) {
+ ret = powerlimit_info.txpwr_lmt.max_pwr_5g[idx];
+ // AICWFDBG(LOGINFO, "[%d]: ch=%d, pwr=%d\n", idx, ch_num,
+ // ret);
+ break;
+ }
+ }
+ if (idx == idx_cnt) {
+ AICWFDBG(LOGERROR, "powerlimit search failed: chnum=%d\n",
+ chnum);
+ }
+ }
+ }
+ return ret;
+}
+#endif
+
+/**
+ * rwnx_platform_reset - Reset the platform
+ *
+ * @rwnx_plat: platform data
+ *
+ * Return: 0 on success, or %-EIO if the platform did not reset.
+ */
+static int rwnx_platform_reset(struct rwnx_plat *rwnx_plat)
+{
+ u32 regval;
+
+#if defined(AICWF_SDIO_SUPPORT)
+ return 0;
+#endif
+
+ /*
+ * the doc states that SOFT implies FPGA_B_RESET
+ * adding FPGA_B_RESET is clearer
+ */
+ RWNX_REG_WRITE(SOFT_RESET | FPGA_B_RESET, rwnx_plat, RWNX_ADDR_SYSTEM,
+ SYSCTRL_MISC_CNTL_ADDR);
+ msleep(100);
+
+ regval = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, SYSCTRL_MISC_CNTL_ADDR);
+
+ if (regval & SOFT_RESET) {
+ dev_err(rwnx_platform_get_dev(rwnx_plat), "reset: failed\n");
+ return -EIO;
+ }
+
+ RWNX_REG_WRITE(regval & ~FPGA_B_RESET, rwnx_plat, RWNX_ADDR_SYSTEM,
+ SYSCTRL_MISC_CNTL_ADDR);
+ msleep(100);
+ return 0;
+}
+
+/*
+ * rwmx_platform_save_config() - Save hardware config before reload
+ *
+ * @rwnx_plat: Pointer to platform data
+ *
+ * Return configuration registers values.
+ */
+static void *rwnx_term_save_config(struct rwnx_plat *rwnx_plat)
+{
+ const u32 *reg_list;
+ u32 *reg_value, *res;
+ int i, size = 0;
+
+ if (rwnx_plat->get_config_reg)
+ size = rwnx_plat->get_config_reg(rwnx_plat, ®_list);
+
+ if (size <= 0)
+ return NULL;
+
+ // res = kmalloc(sizeof(u32) * size, GFP_KERNEL);
+ res = kmalloc_array(size, sizeof(u32), GFP_KERNEL);
+ if (!res)
+ return NULL;
+
+ reg_value = res;
+ for (i = 0; i < size; i++)
+ *reg_value++ = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, *reg_list++);
+
+ return res;
+}
+
+void get_userconfig_txpwr_lvl_in_fdrv(struct txpwr_lvl_conf *txpwr_lvl)
+{
+ txpwr_lvl->enable = userconfig_info.txpwr_lvl.enable;
+ txpwr_lvl->dsss = userconfig_info.txpwr_lvl.dsss;
+ txpwr_lvl->ofdmlowrate_2g4 = userconfig_info.txpwr_lvl.ofdmlowrate_2g4;
+ txpwr_lvl->ofdm64qam_2g4 = userconfig_info.txpwr_lvl.ofdm64qam_2g4;
+ txpwr_lvl->ofdm256qam_2g4 = userconfig_info.txpwr_lvl.ofdm256qam_2g4;
+ txpwr_lvl->ofdm1024qam_2g4 = userconfig_info.txpwr_lvl.ofdm1024qam_2g4;
+ txpwr_lvl->ofdmlowrate_5g = userconfig_info.txpwr_lvl.ofdmlowrate_5g;
+ txpwr_lvl->ofdm64qam_5g = userconfig_info.txpwr_lvl.ofdm64qam_5g;
+ txpwr_lvl->ofdm256qam_5g = userconfig_info.txpwr_lvl.ofdm256qam_5g;
+ txpwr_lvl->ofdm1024qam_5g = userconfig_info.txpwr_lvl.ofdm1024qam_5g;
+
+ AICWFDBG(LOGDEBUG, "%s:enable:%d\r\n", __func__, txpwr_lvl->enable);
+ AICWFDBG(LOGDEBUG, "%s:dsss:%d\r\n", __func__, txpwr_lvl->dsss);
+ AICWFDBG(LOGDEBUG, "%s:ofdmlowrate_2g4:%d\r\n", __func__,
+ txpwr_lvl->ofdmlowrate_2g4);
+ AICWFDBG(LOGDEBUG, "%s:ofdm64qam_2g4:%d\r\n", __func__,
+ txpwr_lvl->ofdm64qam_2g4);
+ AICWFDBG(LOGDEBUG, "%s:ofdm256qam_2g4:%d\r\n", __func__,
+ txpwr_lvl->ofdm256qam_2g4);
+ AICWFDBG(LOGDEBUG, "%s:ofdm1024qam_2g4:%d\r\n", __func__,
+ txpwr_lvl->ofdm1024qam_2g4);
+ AICWFDBG(LOGDEBUG, "%s:ofdmlowrate_5g:%d\r\n", __func__,
+ txpwr_lvl->ofdmlowrate_5g);
+ AICWFDBG(LOGDEBUG, "%s:ofdm64qam_5g:%d\r\n", __func__,
+ txpwr_lvl->ofdm64qam_5g);
+ AICWFDBG(LOGDEBUG, "%s:ofdm256qam_5g:%d\r\n", __func__,
+ txpwr_lvl->ofdm256qam_5g);
+ AICWFDBG(LOGDEBUG, "%s:ofdm1024qam_5g:%d\r\n", __func__,
+ txpwr_lvl->ofdm1024qam_5g);
+}
+
+void get_userconfig_txpwr_lvl_v2_in_fdrv(struct txpwr_lvl_conf_v2 *txpwr_lvl_v2)
+{
+ *txpwr_lvl_v2 = userconfig_info.txpwr_lvl_v2;
+
+ AICWFDBG(LOGDEBUG, "%s:enable:%d\r\n", __func__, txpwr_lvl_v2->enable);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_1m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[0]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_2m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[1]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_5m5_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[2]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_11m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[3]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_6m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[4]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_9m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[5]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_12m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[6]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_18m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[7]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_24m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[8]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_36m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[9]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_48m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[10]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11b_11ag_54m_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[11]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11n_11ac_mcs0_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[0]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11n_11ac_mcs1_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[1]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11n_11ac_mcs2_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[2]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11n_11ac_mcs3_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[3]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11n_11ac_mcs4_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[4]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11n_11ac_mcs5_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[5]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11n_11ac_mcs6_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[6]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11n_11ac_mcs7_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[7]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11n_11ac_mcs8_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[8]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11n_11ac_mcs9_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11n_11ac_2g4[9]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs0_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[0]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs1_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[1]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs2_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[2]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs3_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[3]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs4_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[4]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs5_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[5]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs6_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[6]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs7_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[7]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs8_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[8]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs9_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[9]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs10_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[10]);
+ AICWFDBG(LOGDEBUG, "%s:lvl_11ax_mcs11_2g4:%d\r\n", __func__,
+ txpwr_lvl_v2->pwrlvl_11ax_2g4[11]);
+}
+
+void get_userconfig_txpwr_lvl_group_in_fdrv(struct txpwr_lvl_conf_v3 *txpwr_lvl_v3, int index_reg)
+{
+ *txpwr_lvl_v3 = userconfig_info.txpwr_lvl_v3_gp[index_reg];
+
+ AICWFDBG(LOGDEBUG, "%s:enable:%d\r\n", __func__, txpwr_lvl_v3->enable);
+ AICWFDBG(LOGDEBUG, "lvl_11b_11ag_1m_2g4:%d\r\n", txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[0]);
+}
+
+void get_userconfig_txpwr_lvl_v3_in_fdrv(struct txpwr_lvl_conf_v3 *txpwr_lvl_v3)
+{
+ *txpwr_lvl_v3 = userconfig_info.txpwr_lvl_v3;
+
+ AICWFDBG(LOGDEBUG, "%s:enable:%d\r\n", __func__, txpwr_lvl_v3->enable);
+ AICWFDBG(LOGDEBUG, "lvl_11b_11ag_1m_2g4:%d\r\n", txpwr_lvl_v3->pwrlvl_11b_11ag_2g4[0]);
+}
+
+void get_userconfig_txpwr_lvl_adj_in_fdrv(struct txpwr_lvl_adj_conf *txpwr_lvl_adj)
+{
+ *txpwr_lvl_adj = userconfig_info.txpwr_lvl_adj;
+
+ AICWFDBG(LOGDEBUG, "%s:enable:%d\r\n", __func__, txpwr_lvl_adj->enable);
+ AICWFDBG(LOGDEBUG, "lvl_adj_2g4_chan_1_4:%d\r\n", txpwr_lvl_adj->pwrlvl_adj_tbl_2g4[0]);
+}
+
+/*
+ * rwnx_plat_userconfig_load ---Load aic_userconfig.txt
+ *@filename name of config
+ */
+static int rwnx_plat_userconfig_load(struct rwnx_hw *rwnx_hw)
+{
+ aic_chip_userconfig_load(rwnx_hw);
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+ aic_chip_powerlimit_load(rwnx_hw);
+#endif
+ return 0;
+}
+
+void get_userconfig_txpwr_loss(struct txpwr_loss_conf *txpwr_loss)
+{
+ txpwr_loss->loss_enable_2g4 = userconfig_info.txpwr_loss.loss_enable_2g4;
+ txpwr_loss->loss_value_2g4 = userconfig_info.txpwr_loss.loss_value_2g4;
+ txpwr_loss->loss_enable_5g = userconfig_info.txpwr_loss.loss_enable_5g;
+ txpwr_loss->loss_value_5g = userconfig_info.txpwr_loss.loss_value_5g;
+
+ AICWFDBG(LOGDEBUG,
+ "%s:loss_enable_2g4: %d, val_2g4: %d, loss_enable_5g: %d, val_5g: %d\r\n",
+ __func__,
+ txpwr_loss->loss_enable_2g4, txpwr_loss->loss_value_2g4,
+ txpwr_loss->loss_enable_5g, txpwr_loss->loss_value_5g);
+}
+
+/**
+ * rwnx_platform_on - Start the platform
+ *
+ * @rwnx_hw: Main driver data
+ * @config: Config to restore (NULL if nothing to restore)
+ *
+ * It starts the platform :
+ * - load fw and ucodes
+ * - initialize IPC
+ * - boot the fw
+ * - enable link communication/IRQ
+ *
+ * Called by 802.11 part
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+int rwnx_platform_on(struct rwnx_hw *rwnx_hw, void *config)
+{
+ int ret;
+ struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
+ (void)ret;
+
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ if (rwnx_plat->enabled)
+ return 0;
+
+ rwnx_plat_userconfig_load(rwnx_hw);
+ // rwnx_plat->enabled = true;
+ return 0;
+}
+
+/**
+ * rwnx_platform_off() - Stop the platform
+ *
+ * @rwnx_hw: Main driver data
+ * @config: Updated with pointer to config, to be able to restore it with
+ * rwnx_platform_on(). It's up to the caller to free the config. Set to NULL
+ * if configuration is not needed.
+ *
+ * Called by 802.11 part
+ */
+void rwnx_platform_off(struct rwnx_hw *rwnx_hw, void **config)
+{
+#if defined(AICWF_SDIO_SUPPORT)
+ tasklet_kill(&rwnx_hw->task);
+ rwnx_hw->plat->enabled = false;
+ return;
+#endif
+
+ if (!rwnx_hw->plat->enabled) {
+ if (config)
+ *config = NULL;
+ return;
+ }
+
+ if (config)
+ *config = rwnx_term_save_config(rwnx_hw->plat);
+
+ rwnx_hw->plat->disable(rwnx_hw);
+
+ tasklet_kill(&rwnx_hw->task);
+ rwnx_platform_reset(rwnx_hw->plat);
+
+ rwnx_hw->plat->enabled = false;
+}
+
+/**
+ * rwnx_platform_init() - Initialize the platform
+ *
+ * @rwnx_plat: platform data (already updated by platform driver)
+ * @platform_data: Pointer to store the main driver data pointer (aka rwnx_hw)
+ * That will be set as driver data for the platform driver
+ * Return: 0 on success, < 0 otherwise
+ *
+ * Called by the platform driver after it has been probed
+ */
+int rwnx_platform_init(struct rwnx_plat *rwnx_plat, void **platform_data)
+{
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ rwnx_plat->enabled = false;
+ g_rwnx_plat = rwnx_plat;
+
+ return rwnx_cfg80211_init(rwnx_plat, platform_data);
+}
+
+/**
+ * rwnx_platform_deinit() - Deinitialize the platform
+ *
+ * @rwnx_hw: main driver data
+ *
+ * Called by the platform driver after it is removed
+ */
+void rwnx_platform_deinit(struct rwnx_hw *rwnx_hw)
+{
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+
+ rwnx_cfg80211_deinit(rwnx_hw);
+}
+
+struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat)
+{
+#ifdef AICWF_SDIO_SUPPORT
+ return rwnx_plat->sdiodev->dev;
+#endif
+}
+
+MODULE_FIRMWARE(AIC8800_FW_DIR RWNX_AGC_FW_NAME);
+MODULE_FIRMWARE(AIC8800_FW_DIR RWNX_FCU_FW_NAME);
+MODULE_FIRMWARE(AIC8800_FW_DIR RWNX_LDPC_RAM_NAME);
+
+MODULE_FIRMWARE(AIC8800_FW_DIR RWNX_MAC_FW_NAME);
+MODULE_FIRMWARE(AIC8800_FW_DIR RWNX_MAC_FW_NAME2);
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_platform.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_platform.h
new file mode 100644
index 0000000000000..efcff3b08b2a3
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_platform.h
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _RWNX_PLATFORM_H_
+#define _RWNX_PLATFORM_H_
+
+#include "lmac_msg.h"
+#include <linux/pci.h>
+
+#define AIC8800_FW_DIR "aic8800/"
+
+#define RWNX_CONFIG_FW_NAME "rwnx_settings.ini"
+#define RWNX_PHY_CONFIG_TRD_NAME "rwnx_trident.ini"
+#define RWNX_PHY_CONFIG_KARST_NAME "rwnx_karst.ini"
+#define RWNX_AGC_FW_NAME "agcram.bin"
+#define RWNX_LDPC_RAM_NAME "ldpcram.bin"
+
+#define RWNX_MAC_FW_BASE_NAME "fmacfw"
+
+#define RWNX_MAC_FW_NAME RWNX_MAC_FW_BASE_NAME ".ihex"
+#define RWNX_MAC_FW_NAME2 RWNX_MAC_FW_BASE_NAME ".bin"
+
+#define RWNX_FCU_FW_NAME "fcuram.bin"
+#if (defined(CONFIG_DPD) && !defined(CONFIG_FORCE_DPD_CALIB))
+#define FW_DPDRESULT_NAME_8800DC "aic_dpdresult_lite_8800dc.bin"
+#endif
+
+#define POWER_LEVEL_INVALID_VAL (127)
+
+/*
+ * Type of memory to access (cf rwnx_plat.get_address)
+ *
+ * @RWNX_ADDR_CPU To access memory of the embedded CPU
+ * @RWNX_ADDR_SYSTEM To access memory/registers of one subsystem of the
+ * embedded system
+ *
+ */
+enum rwnx_platform_addr {
+ RWNX_ADDR_CPU,
+ RWNX_ADDR_SYSTEM,
+ RWNX_ADDR_MAX,
+};
+
+enum regions_code {
+ REGIONS_SRRC,
+ REGIONS_FCC,
+ REGIONS_ETSI,
+ REGIONS_JP,
+ REGIONS_DEFAULT,
+};
+
+struct rwnx_hw;
+struct device;
+struct firmware;
+
+int aicwf_request_firmware(const struct firmware **fw, const char *name,
+ struct device *dev);
+
+/**
+ * struct rwnx_plat - Operations and state for an RWNX platform
+ *
+ * @pci_dev: pointer to pci dev
+ * @sdiodev: SDIO device data
+ * @enabled: Set if embedded platform has been enabled (i.e. fw loaded and
+ * ipc started)
+ * @enable: Configure communication with the fw (i.e. configure the transfers
+ * enable and register interrupt)
+ * @disable: Stop communication with the fw
+ * @deinit: Free all resources allocated for the embedded platform
+ * @get_address: Return the virtual address to access the requested address on
+ * the platform.
+ * @ack_irq: Acknowledge the irq at link level.
+ * @get_config_reg: Return the list (size + pointer) of registers to restore in
+ * order to reload the platform while keeping the current configuration.
+ *
+ * @priv: Private data for the link driver
+ */
+struct rwnx_plat {
+ struct pci_dev *pci_dev;
+
+#ifdef AICWF_SDIO_SUPPORT
+ struct aic_sdio_dev *sdiodev;
+#endif
+
+ bool enabled;
+
+ int (*enable)(struct rwnx_hw *rwnx_hw);
+ int (*disable)(struct rwnx_hw *rwnx_hw);
+ void (*deinit)(struct rwnx_plat *rwnx_plat);
+ u8 __iomem *(*get_address)(struct rwnx_plat *rwnx_plat, int addr_name,
+ unsigned int offset);
+ void (*ack_irq)(struct rwnx_plat *rwnx_plat);
+ int (*get_config_reg)(struct rwnx_plat *rwnx_plat, const u32 **list);
+
+ u8 priv[0] __aligned(sizeof(void *));
+};
+
+static inline void __iomem *RWNX_ADDR(void *plat, int base, int offset)
+{
+ struct rwnx_plat *p = (struct rwnx_plat *)plat;
+
+ return p->get_address(p, base, offset);
+}
+
+static inline u32 RWNX_REG_READ(void *plat, int base, int offset)
+{
+ struct rwnx_plat *p = (struct rwnx_plat *)plat;
+
+ return readl(p->get_address(p, base, offset));
+}
+
+static inline void RWNX_REG_WRITE(u32 val, void *plat, int base, int offset)
+{
+ struct rwnx_plat *p = (struct rwnx_plat *)plat;
+
+ writel(val, p->get_address(p, base, offset));
+}
+
+extern struct rwnx_plat *g_rwnx_plat;
+
+int rwnx_platform_init(struct rwnx_plat *rwnx_plat, void **platform_data);
+void rwnx_platform_deinit(struct rwnx_hw *rwnx_hw);
+
+int rwnx_platform_on(struct rwnx_hw *rwnx_hw, void *config);
+void rwnx_platform_off(struct rwnx_hw *rwnx_hw, void **config);
+
+int rwnx_platform_register_drv(void);
+void rwnx_platform_unregister_drv(void);
+
+void get_userconfig_txpwr_idx(struct txpwr_idx_conf *txpwr_idx);
+void get_userconfig_txpwr_ofst(struct txpwr_ofst_conf *txpwr_ofst);
+void get_userconfig_xtal_cap(struct xtal_cap_conf *xtal_cap);
+s8 get_txpwr_max(s8 power);
+void set_txpwr_loss_ofst(s8 value);
+
+int get_ccode_region(char *ccode);
+
+void rwnx_release_firmware_common(u32 **buffer);
+
+int rwnx_plat_userconfig_upload(struct rwnx_hw *rwnx_hw,
+ const char *filename);
+void rwnx_plat_userconfig_parsing(struct rwnx_hw *rwnx_hw, char *buffer, int size);
+void rwnx_plat_userconfig_parsing2(char *buffer, int size);
+void rwnx_plat_userconfig_parsing3(char *buffer, int size);
+
+void get_userconfig_txpwr_lvl_in_fdrv(struct txpwr_lvl_conf *txpwr_lvl);
+void get_userconfig_txpwr_lvl_v2_in_fdrv(struct txpwr_lvl_conf_v2 *txpwr_lvl_v2);
+void get_userconfig_txpwr_lvl_group_in_fdrv(struct txpwr_lvl_conf_v3 *txpwr_lvl_v3, int index_reg);
+void get_userconfig_txpwr_lvl_v3_in_fdrv(struct txpwr_lvl_conf_v3 *txpwr_lvl_v3);
+void get_userconfig_txpwr_lvl_adj_in_fdrv(struct txpwr_lvl_adj_conf *txpwr_lvl_adj);
+
+void get_userconfig_txpwr_ofst_in_fdrv(struct txpwr_ofst_conf *txpwr_ofst);
+void get_userconfig_txpwr_ofst2x_in_fdrv(struct txpwr_ofst2x_conf *txpwr_ofst2x);
+void get_userconfig_txpwr_loss(struct txpwr_loss_conf *txpwr_loss);
+#ifdef CONFIG_AIC8800_POWER_LIMIT
+int is_all_space_or_tab(u8 *data, u8 size);
+int is_comment_string(char *sz_str);
+int is_enable_limit(char *sz_str);
+int parse_qualified_string(char *in, u32 *start, char *out, char left_qualifier,
+ char right_qualifier);
+int get_u1_byte_integer_from_string_in_decimal(char *str, u8 *p_int);
+int get_s1_byte_integer_from_string_in_decimal(char *str, s8 *val);
+void rwnx_plat_powerlimit_parsing(char *buffer, int size, char *cc);
+s8 get_powerlimit_by_freq(u8 band, u16 freq, u8 *enable);
+s8 get_powerlimit_by_chnum(u8 chnum, u8 *enable);
+u16 phy_channel_to_freq(u8 band, int channel);
+#endif
+
+struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat);
+
+int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw, u32 **buffer,
+ const char *filename);
+int rwnx_plat_bin_fw_upload_2(struct rwnx_hw *rwnx_hw, u32 fw_addr,
+ char *filename);
+int rwnx_atoi(char *value);
+void rwnx_plat_nvram_set_value(char *command, char *value);
+void rwnx_plat_nvram_set_value_group(char *command, char *value);
+void rwnx_plat_nvram_set_value_v3(char *command, char *value);
+
+static inline unsigned int rwnx_platform_get_irq(struct rwnx_plat *rwnx_plat)
+{
+ return rwnx_plat->pci_dev->irq;
+}
+
+#endif /* _RWNX_PLATFORM_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_prof.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_prof.h
new file mode 100644
index 0000000000000..093e243f3c94f
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_prof.h
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _RWNX_PROF_H_
+#define _RWNX_PROF_H_
+
+#include "reg_access.h"
+#include "rwnx_platform.h"
+#include "rwnx_radar.h"
+
+static inline void rwnx_prof_set(struct rwnx_hw *rwnx_hw, int val)
+{
+ struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
+
+ RWNX_REG_WRITE(val, rwnx_plat, RWNX_ADDR_SYSTEM,
+ NXMAC_SW_SET_PROFILING_ADDR);
+}
+
+static inline void rwnx_prof_clear(struct rwnx_hw *rwnx_hw, int val)
+{
+ struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
+
+ RWNX_REG_WRITE(val, rwnx_plat, RWNX_ADDR_SYSTEM,
+ NXMAC_SW_CLEAR_PROFILING_ADDR);
+}
+
+enum {
+ SW_PROF_HOSTBUF_IDX = 12,
+ /****** IPC IRQs related signals ******/
+ /* E2A direction */
+ SW_PROF_IRQ_E2A_RXDESC =
+ 16, // to make sure we let 16 bits available for LMAC FW
+ SW_PROF_IRQ_E2A_TXCFM,
+ SW_PROF_IRQ_E2A_DBG,
+ SW_PROF_IRQ_E2A_MSG,
+ SW_PROF_IPC_MSGPUSH,
+ SW_PROF_MSGALLOC,
+ SW_PROF_MSGIND,
+ SW_PROF_DBGIND,
+
+ /* A2E direction */
+ SW_PROF_IRQ_A2E_TXCFM_BACK,
+
+ /****** Driver functions related signals ******/
+ SW_PROF_WAIT_QUEUE_STOP,
+ SW_PROF_WAIT_QUEUE_WAKEUP,
+ SW_PROF_RWNXDATAIND,
+ SW_PROF_RWNX_IPC_IRQ_HDLR,
+ SW_PROF_RWNX_IPC_THR_IRQ_HDLR,
+ SW_PROF_IEEE80211RX,
+ SW_PROF_RWNX_PATTERN,
+ SW_PROF_MAX
+};
+
+// [LT]For debug purpose only
+#if (0)
+#define SW_PROF_CHAN_CTXT_CFM_HDL_BIT (21)
+#define SW_PROF_CHAN_CTXT_CFM_BIT (22)
+#define SW_PROF_CHAN_CTXT_CFM_SWDONE_BIT (23)
+#define SW_PROF_CHAN_CTXT_PUSH_BIT (24)
+#define SW_PROF_CHAN_CTXT_QUEUE_BIT (25)
+#define SW_PROF_CHAN_CTXT_TX_BIT (26)
+#define SW_PROF_CHAN_CTXT_TX_PAUSE_BIT (27)
+#define SW_PROF_CHAN_CTXT_PSWTCH_BIT (28)
+#define SW_PROF_CHAN_CTXT_SWTCH_BIT (29)
+
+#else
+#define SW_PROF_CHAN_CTXT_CFM_HDL_BIT (0)
+#define SW_PROF_CHAN_CTXT_CFM_BIT (0)
+#define SW_PROF_CHAN_CTXT_CFM_SWDONE_BIT (0)
+#define SW_PROF_CHAN_CTXT_PUSH_BIT (0)
+#define SW_PROF_CHAN_CTXT_QUEUE_BIT (0)
+#define SW_PROF_CHAN_CTXT_TX_BIT (0)
+#define SW_PROF_CHAN_CTXT_TX_PAUSE_BIT (0)
+#define SW_PROF_CHAN_CTXT_PSWTCH_BIT (0)
+#define SW_PROF_CHAN_CTXT_SWTCH_BIT (0)
+#endif
+
+static inline void REG_SW_SET_PROFILING_CHAN(void *env, int bit)
+{
+#if (0)
+ rwnx_prof_clear((struct rwnx_hw *)env, BIT(bit));
+#else
+
+#endif
+}
+
+static inline void REG_SW_CLEAR_PROFILING_CHAN(void *env, int bit)
+{
+#if (0)
+ rwnx_prof_clear((struct rwnx_hw *)env, BIT(bit));
+#else
+
+#endif
+}
+
+#ifdef CONFIG_RWNX_SW_PROFILING
+/* Macros for SW PRofiling registers access */
+static inline void REG_SW_SET_PROFILING(void *env, int bit)
+{
+ rwnx_prof_set((struct rwnx_hw *)env, BIT(bit));
+}
+
+static inline void REG_SW_SET_HOSTBUF_IDX_PROFILING(void *env, int val)
+{
+ rwnx_prof_set((struct rwnx_hw *)env, (val) << (SW_PROF_HOSTBUF_IDX));
+}
+
+static inline void REG_SW_CLEAR_PROFILING(void *env, int bit)
+{
+ rwnx_prof_clear((struct rwnx_hw *)env, BIT(bit));
+}
+
+static inline void REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(void *env)
+{
+ rwnx_prof_clear((struct rwnx_hw *)env, 0x0F << (SW_PROF_HOSTBUF_IDX));
+}
+
+#else
+static inline void REG_SW_SET_PROFILING(void *env, int value)
+{
+ (void)env;
+ (void)value;
+}
+
+static inline void REG_SW_CLEAR_PROFILING(void *env, int value)
+{
+ (void)env;
+ (void)value;
+}
+
+static inline void REG_SW_SET_HOSTBUF_IDX_PROFILING(void *env, int val)
+{
+ (void)env;
+ (void)val;
+}
+
+static inline void REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(void *env)
+{
+ (void)env;
+}
+#endif
+
+#endif /* _RWNX_PROF_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_strs.c b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_strs.c
new file mode 100644
index 0000000000000..50e81d81abf1e
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_strs.c
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ ****************************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @file rwnx_strs.c
+ *
+ * @brief Miscellaneous debug strings
+ *
+ ****************************************************************************************
+ */
+
+#include "lmac_msg.h"
+#include "rwnx_strs.h"
+static const char *const rwnx_mmid2str[MSG_I(MM_MAX)] = {
+ [MSG_I(MM_RESET_REQ)] = "MM_RESET_REQ",
+ [MSG_I(MM_RESET_CFM)] = "MM_RESET_CFM",
+ [MSG_I(MM_START_REQ)] = "MM_START_REQ",
+ [MSG_I(MM_START_CFM)] = "MM_START_CFM",
+ [MSG_I(MM_VERSION_REQ)] = "MM_VERSION_REQ",
+ [MSG_I(MM_VERSION_CFM)] = "MM_VERSION_CFM",
+ [MSG_I(MM_ADD_IF_REQ)] = "MM_ADD_IF_REQ",
+ [MSG_I(MM_ADD_IF_CFM)] = "MM_ADD_IF_CFM",
+ [MSG_I(MM_REMOVE_IF_REQ)] = "MM_REMOVE_IF_REQ",
+ [MSG_I(MM_REMOVE_IF_CFM)] = "MM_REMOVE_IF_CFM",
+ [MSG_I(MM_STA_ADD_REQ)] = "MM_STA_ADD_REQ",
+ [MSG_I(MM_STA_ADD_CFM)] = "MM_STA_ADD_CFM",
+ [MSG_I(MM_STA_DEL_REQ)] = "MM_STA_DEL_REQ",
+ [MSG_I(MM_STA_DEL_CFM)] = "MM_STA_DEL_CFM",
+ [MSG_I(MM_SET_FILTER_REQ)] = "MM_SET_FILTER_REQ",
+ [MSG_I(MM_SET_FILTER_CFM)] = "MM_SET_FILTER_CFM",
+ [MSG_I(MM_SET_CHANNEL_REQ)] = "MM_SET_CHANNEL_REQ",
+ [MSG_I(MM_SET_CHANNEL_CFM)] = "MM_SET_CHANNEL_CFM",
+ [MSG_I(MM_SET_DTIM_REQ)] = "MM_SET_DTIM_REQ",
+ [MSG_I(MM_SET_DTIM_CFM)] = "MM_SET_DTIM_CFM",
+ [MSG_I(MM_SET_BEACON_INT_REQ)] = "MM_SET_BEACON_INT_REQ",
+ [MSG_I(MM_SET_BEACON_INT_CFM)] = "MM_SET_BEACON_INT_CFM",
+ [MSG_I(MM_SET_BASIC_RATES_REQ)] = "MM_SET_BASIC_RATES_REQ",
+ [MSG_I(MM_SET_BASIC_RATES_CFM)] = "MM_SET_BASIC_RATES_CFM",
+ [MSG_I(MM_SET_BSSID_REQ)] = "MM_SET_BSSID_REQ",
+ [MSG_I(MM_SET_BSSID_CFM)] = "MM_SET_BSSID_CFM",
+ [MSG_I(MM_SET_EDCA_REQ)] = "MM_SET_EDCA_REQ",
+ [MSG_I(MM_SET_EDCA_CFM)] = "MM_SET_EDCA_CFM",
+ [MSG_I(MM_SET_MODE_REQ)] = "MM_SET_MODE_REQ",
+ [MSG_I(MM_SET_MODE_CFM)] = "MM_SET_MODE_CFM",
+ [MSG_I(MM_SET_VIF_STATE_REQ)] = "MM_SET_VIF_STATE_REQ",
+ [MSG_I(MM_SET_VIF_STATE_CFM)] = "MM_SET_VIF_STATE_CFM",
+ [MSG_I(MM_SET_SLOTTIME_REQ)] = "MM_SET_SLOTTIME_REQ",
+ [MSG_I(MM_SET_SLOTTIME_CFM)] = "MM_SET_SLOTTIME_CFM",
+ [MSG_I(MM_SET_IDLE_REQ)] = "MM_SET_IDLE_REQ",
+ [MSG_I(MM_SET_IDLE_CFM)] = "MM_SET_IDLE_CFM",
+ [MSG_I(MM_KEY_ADD_REQ)] = "MM_KEY_ADD_REQ",
+ [MSG_I(MM_KEY_ADD_CFM)] = "MM_KEY_ADD_CFM",
+ [MSG_I(MM_KEY_DEL_REQ)] = "MM_KEY_DEL_REQ",
+ [MSG_I(MM_KEY_DEL_CFM)] = "MM_KEY_DEL_CFM",
+ [MSG_I(MM_BA_ADD_REQ)] = "MM_BA_ADD_REQ",
+ [MSG_I(MM_BA_ADD_CFM)] = "MM_BA_ADD_CFM",
+ [MSG_I(MM_BA_DEL_REQ)] = "MM_BA_DEL_REQ",
+ [MSG_I(MM_BA_DEL_CFM)] = "MM_BA_DEL_CFM",
+ [MSG_I(MM_PRIMARY_TBTT_IND)] = "MM_PRIMARY_TBTT_IND",
+ [MSG_I(MM_SECONDARY_TBTT_IND)] = "MM_SECONDARY_TBTT_IND",
+ [MSG_I(MM_SET_POWER_REQ)] = "MM_SET_POWER_REQ",
+ [MSG_I(MM_SET_POWER_CFM)] = "MM_SET_POWER_CFM",
+ [MSG_I(MM_DBG_TRIGGER_REQ)] = "MM_DBG_TRIGGER_REQ",
+ [MSG_I(MM_SET_PS_MODE_REQ)] = "MM_SET_PS_MODE_REQ",
+ [MSG_I(MM_SET_PS_MODE_CFM)] = "MM_SET_PS_MODE_CFM",
+ [MSG_I(MM_CHAN_CTXT_ADD_REQ)] = "MM_CHAN_CTXT_ADD_REQ",
+ [MSG_I(MM_CHAN_CTXT_ADD_CFM)] = "MM_CHAN_CTXT_ADD_CFM",
+ [MSG_I(MM_CHAN_CTXT_DEL_REQ)] = "MM_CHAN_CTXT_DEL_REQ",
+ [MSG_I(MM_CHAN_CTXT_DEL_CFM)] = "MM_CHAN_CTXT_DEL_CFM",
+ [MSG_I(MM_CHAN_CTXT_LINK_REQ)] = "MM_CHAN_CTXT_LINK_REQ",
+ [MSG_I(MM_CHAN_CTXT_LINK_CFM)] = "MM_CHAN_CTXT_LINK_CFM",
+ [MSG_I(MM_CHAN_CTXT_UNLINK_REQ)] = "MM_CHAN_CTXT_UNLINK_REQ",
+ [MSG_I(MM_CHAN_CTXT_UNLINK_CFM)] = "MM_CHAN_CTXT_UNLINK_CFM",
+ [MSG_I(MM_CHAN_CTXT_UPDATE_REQ)] = "MM_CHAN_CTXT_UPDATE_REQ",
+ [MSG_I(MM_CHAN_CTXT_UPDATE_CFM)] = "MM_CHAN_CTXT_UPDATE_CFM",
+ [MSG_I(MM_CHAN_CTXT_SCHED_REQ)] = "MM_CHAN_CTXT_SCHED_REQ",
+ [MSG_I(MM_CHAN_CTXT_SCHED_CFM)] = "MM_CHAN_CTXT_SCHED_CFM",
+ [MSG_I(MM_BCN_CHANGE_REQ)] = "MM_BCN_CHANGE_REQ",
+ [MSG_I(MM_BCN_CHANGE_CFM)] = "MM_BCN_CHANGE_CFM",
+ [MSG_I(MM_TIM_UPDATE_REQ)] = "MM_TIM_UPDATE_REQ",
+ [MSG_I(MM_TIM_UPDATE_CFM)] = "MM_TIM_UPDATE_CFM",
+ [MSG_I(MM_CONNECTION_LOSS_IND)] = "MM_CONNECTION_LOSS_IND",
+ [MSG_I(MM_CHANNEL_SWITCH_IND)] = "MM_CHANNEL_SWITCH_IND",
+ [MSG_I(MM_CHANNEL_PRE_SWITCH_IND)] = "MM_CHANNEL_PRE_SWITCH_IND",
+ [MSG_I(MM_REMAIN_ON_CHANNEL_REQ)] = "MM_REMAIN_ON_CHANNEL_REQ",
+ [MSG_I(MM_REMAIN_ON_CHANNEL_CFM)] = "MM_REMAIN_ON_CHANNEL_CFM",
+ [MSG_I(MM_REMAIN_ON_CHANNEL_EXP_IND)] = "MM_REMAIN_ON_CHANNEL_EXP_IND",
+ [MSG_I(MM_PS_CHANGE_IND)] = "MM_PS_CHANGE_IND",
+ [MSG_I(MM_TRAFFIC_REQ_IND)] = "MM_TRAFFIC_REQ_IND",
+ [MSG_I(MM_SET_PS_OPTIONS_REQ)] = "MM_SET_PS_OPTIONS_REQ",
+ [MSG_I(MM_SET_PS_OPTIONS_CFM)] = "MM_SET_PS_OPTIONS_CFM",
+ [MSG_I(MM_P2P_VIF_PS_CHANGE_IND)] = "MM_P2P_VIF_PS_CHANGE_IND",
+ [MSG_I(MM_CSA_COUNTER_IND)] = "MM_CSA_COUNTER_IND",
+ [MSG_I(MM_CHANNEL_SURVEY_IND)] = "MM_CHANNEL_SURVEY_IND",
+ [MSG_I(MM_SET_P2P_NOA_REQ)] = "MM_SET_P2P_NOA_REQ",
+ [MSG_I(MM_SET_P2P_OPPPS_REQ)] = "MM_SET_P2P_OPPPS_REQ",
+ [MSG_I(MM_SET_P2P_NOA_CFM)] = "MM_SET_P2P_NOA_CFM",
+ [MSG_I(MM_SET_P2P_OPPPS_CFM)] = "MM_SET_P2P_OPPPS_CFM",
+ [MSG_I(MM_CFG_RSSI_REQ)] = "MM_CFG_RSSI_REQ",
+ [MSG_I(MM_RSSI_STATUS_IND)] = "MM_RSSI_STATUS_IND",
+ [MSG_I(MM_CSA_FINISH_IND)] = "MM_CSA_FINISH_IND",
+ [MSG_I(MM_CSA_TRAFFIC_IND)] = "MM_CSA_TRAFFIC_IND",
+ [MSG_I(MM_MU_GROUP_UPDATE_REQ)] = "MM_MU_GROUP_UPDATE_REQ",
+ [MSG_I(MM_MU_GROUP_UPDATE_CFM)] = "MM_MU_GROUP_UPDATE_CFM",
+
+ [MSG_I(MM_SET_ARPOFFLOAD_REQ)] = "MM_SET_ARPOFFLOAD_REQ",
+ [MSG_I(MM_SET_ARPOFFLOAD_CFM)] = "MM_SET_ARPOFFLOAD_CFM",
+ [MSG_I(MM_SET_AGG_DISABLE_REQ)] = "MM_SET_AGG_DISABLE_REQ",
+ [MSG_I(MM_SET_AGG_DISABLE_CFM)] = "MM_SET_AGG_DISABLE_CFM",
+ [MSG_I(MM_SET_COEX_REQ)] = "MM_SET_COEX_REQ",
+ [MSG_I(MM_SET_COEX_CFM)] = "MM_SET_COEX_CFM",
+ [MSG_I(MM_SET_RF_CONFIG_REQ)] = "MM_SET_RF_CONFIG_REQ",
+ [MSG_I(MM_SET_RF_CONFIG_CFM)] = "MM_SET_RF_CONFIG_CFM",
+ [MSG_I(MM_SET_RF_CALIB_REQ)] = "MM_SET_RF_CALIB_REQ",
+ [MSG_I(MM_SET_RF_CALIB_CFM)] = "MM_SET_RF_CALIB_CFM",
+
+ [MSG_I(MM_GET_MAC_ADDR_REQ)] = "MM_GET_MAC_ADDR_REQ",
+ [MSG_I(MM_GET_MAC_ADDR_CFM)] = "MM_GET_MAC_ADDR_CFM",
+ [MSG_I(MM_GET_STA_INFO_REQ)] = "MM_GET_STA_INFO_REQ",
+ [MSG_I(MM_GET_STA_INFO_CFM)] = "MM_GET_STA_INFO_CFM",
+ [MSG_I(MM_SET_TXPWR_IDX_LVL_REQ)] = "MM_SET_TXPWR_IDX_LVL_REQ",
+ [MSG_I(MM_SET_TXPWR_IDX_LVL_CFM)] = "MM_SET_TXPWR_IDX_LVL_CFM",
+ [MSG_I(MM_SET_TXPWR_OFST_REQ)] = "MM_SET_TXPWR_OFST_REQ",
+ [MSG_I(MM_SET_TXPWR_OFST_CFM)] = "MM_SET_TXPWR_OFST_CFM",
+ [MSG_I(MM_SET_STACK_START_REQ)] = "MM_SET_STACK_START_REQ",
+ [MSG_I(MM_SET_STACK_START_CFM)] = "MM_SET_STACK_START_CFM",
+ [MSG_I(MM_APM_STALOSS_IND)] = "MM_APM_STALOSS_IND",
+ [MSG_I(MM_SET_VENDOR_HWCONFIG_REQ)] = "MM_SET_VENDOR_HWCONFIG_REQ",
+ [MSG_I(MM_SET_VENDOR_HWCONFIG_CFM)] = "MM_SET_VENDOR_HWCONFIG_CFM",
+ [MSG_I(MM_GET_FW_VERSION_REQ)] = "MM_GET_FW_VERSION_REQ",
+ [MSG_I(MM_GET_FW_VERSION_CFM)] = "MM_GET_FW_VERSION_CFM",
+ [MSG_I(MM_SET_RESUME_RESTORE_REQ)] = "MM_SET_RESUME_RESTORE_REQ",
+ [MSG_I(MM_SET_RESUME_RESTORE_CFM)] = "MM_SET_RESUME_RESTORE_CFM",
+ [MSG_I(MM_GET_WIFI_DISABLE_REQ)] = "MM_GET_WIFI_DISABLE_REQ",
+ [MSG_I(MM_GET_WIFI_DISABLE_CFM)] = "MM_GET_WIFI_DISABLE_CFM",
+ [MSG_I(MM_CFG_RSSI_CFM)] = "MM_CFG_RSSI_CFM",
+ [MSG_I(MM_SET_VENDOR_SWCONFIG_REQ)] = "MM_SET_VENDOR_SWCONFIG_REQ",
+ [MSG_I(MM_SET_VENDOR_SWCONFIG_CFM)] = "MM_SET_VENDOR_SWCONFIG_CFM",
+};
+
+static const char *const rwnx_dbgid2str[MSG_I(DBG_MAX)] = {
+ [MSG_I(DBG_MEM_READ_REQ)] = "DBG_MEM_READ_REQ",
+ [MSG_I(DBG_MEM_READ_CFM)] = "DBG_MEM_READ_CFM",
+ [MSG_I(DBG_MEM_WRITE_REQ)] = "DBG_MEM_WRITE_REQ",
+ [MSG_I(DBG_MEM_WRITE_CFM)] = "DBG_MEM_WRITE_CFM",
+ [MSG_I(DBG_SET_MOD_FILTER_REQ)] = "DBG_SET_MOD_FILTER_REQ",
+ [MSG_I(DBG_SET_MOD_FILTER_CFM)] = "DBG_SET_MOD_FILTER_CFM",
+ [MSG_I(DBG_SET_SEV_FILTER_REQ)] = "DBG_SET_SEV_FILTER_REQ",
+ [MSG_I(DBG_SET_SEV_FILTER_CFM)] = "DBG_SET_SEV_FILTER_CFM",
+ [MSG_I(DBG_ERROR_IND)] = "DBG_ERROR_IND",
+ [MSG_I(DBG_GET_SYS_STAT_REQ)] = "DBG_GET_SYS_STAT_REQ",
+ [MSG_I(DBG_GET_SYS_STAT_CFM)] = "DBG_GET_SYS_STAT_CFM",
+};
+
+static const char *const rwnx_scanid2str[MSG_I(SCAN_MAX)] = {
+ [MSG_I(SCAN_START_REQ)] = "SCAN_START_REQ",
+ [MSG_I(SCAN_START_CFM)] = "SCAN_START_CFM",
+ [MSG_I(SCAN_DONE_IND)] = "SCAN_DONE_IND",
+};
+
+static const char *const rwnx_tdlsid2str[MSG_I(TDLS_MAX)] = {
+ [MSG_I(TDLS_CHAN_SWITCH_CFM)] = "TDLS_CHAN_SWITCH_CFM",
+ [MSG_I(TDLS_CHAN_SWITCH_REQ)] = "TDLS_CHAN_SWITCH_REQ",
+ [MSG_I(TDLS_CHAN_SWITCH_IND)] = "TDLS_CHAN_SWITCH_IND",
+ [MSG_I(TDLS_CHAN_SWITCH_BASE_IND)] = "TDLS_CHAN_SWITCH_BASE_IND",
+ [MSG_I(TDLS_CANCEL_CHAN_SWITCH_REQ)] = "TDLS_CANCEL_CHAN_SWITCH_REQ",
+ [MSG_I(TDLS_CANCEL_CHAN_SWITCH_CFM)] = "TDLS_CANCEL_CHAN_SWITCH_CFM",
+ [MSG_I(TDLS_PEER_PS_IND)] = "TDLS_PEER_PS_IND",
+ [MSG_I(TDLS_PEER_TRAFFIC_IND_REQ)] = "TDLS_PEER_TRAFFIC_IND_REQ",
+ [MSG_I(TDLS_PEER_TRAFFIC_IND_CFM)] = "TDLS_PEER_TRAFFIC_IND_CFM",
+};
+
+#ifdef CONFIG_RWNX_FULLMAC
+
+static const char *const rwnx_scanuid2str[MSG_I(SCANU_MAX)] = {
+ [MSG_I(SCANU_START_REQ)] = "SCANU_START_REQ",
+ [MSG_I(SCANU_START_CFM)] = "SCANU_START_CFM",
+ [MSG_I(SCANU_JOIN_REQ)] = "SCANU_JOIN_REQ",
+ [MSG_I(SCANU_JOIN_CFM)] = "SCANU_JOIN_CFM",
+ [MSG_I(SCANU_RESULT_IND)] = "SCANU_RESULT_IND",
+ [MSG_I(SCANU_FAST_REQ)] = "SCANU_FAST_REQ",
+ [MSG_I(SCANU_FAST_CFM)] = "SCANU_FAST_CFM",
+ [MSG_I(SCANU_VENDOR_IE_REQ)] = "SCANU_VENDOR_IE_REQ",
+ [MSG_I(SCANU_VENDOR_IE_CFM)] = "SCANU_VENDOR_IE_CFM",
+ [MSG_I(SCANU_START_CFM_ADDTIONAL)] = "SCANU_START_CFM_ADDTIONAL",
+ [MSG_I(SCANU_CANCEL_REQ)] = "SCANU_CANCEL_REQ",
+ [MSG_I(SCANU_CANCEL_CFM)] = "SCANU_CANCEL_CFM",
+};
+
+static const char *const rwnx_meid2str[MSG_I(ME_MAX)] = {
+ [MSG_I(ME_CONFIG_REQ)] = "ME_CONFIG_REQ",
+ [MSG_I(ME_CONFIG_CFM)] = "ME_CONFIG_CFM",
+ [MSG_I(ME_CHAN_CONFIG_REQ)] = "ME_CHAN_CONFIG_REQ",
+ [MSG_I(ME_CHAN_CONFIG_CFM)] = "ME_CHAN_CONFIG_CFM",
+ [MSG_I(ME_SET_CONTROL_PORT_REQ)] = "ME_SET_CONTROL_PORT_REQ",
+ [MSG_I(ME_SET_CONTROL_PORT_CFM)] = "ME_SET_CONTROL_PORT_CFM",
+ [MSG_I(ME_TKIP_MIC_FAILURE_IND)] = "ME_TKIP_MIC_FAILURE_IND",
+ [MSG_I(ME_STA_ADD_REQ)] = "ME_STA_ADD_REQ",
+ [MSG_I(ME_STA_ADD_CFM)] = "ME_STA_ADD_CFM",
+ [MSG_I(ME_STA_DEL_REQ)] = "ME_STA_DEL_REQ",
+ [MSG_I(ME_STA_DEL_CFM)] = "ME_STA_DEL_CFM",
+ [MSG_I(ME_TX_CREDITS_UPDATE_IND)] = "ME_TX_CREDITS_UPDATE_IND",
+ [MSG_I(ME_RC_STATS_REQ)] = "ME_RC_STATS_REQ",
+ [MSG_I(ME_RC_STATS_CFM)] = "ME_RC_STATS_CFM",
+ [MSG_I(ME_RC_SET_RATE_REQ)] = "ME_RC_SET_RATE_REQ",
+ [MSG_I(ME_TRAFFIC_IND_REQ)] = "ME_TRAFFIC_IND_REQ",
+ [MSG_I(ME_TRAFFIC_IND_CFM)] = "ME_TRAFFIC_IND_CFM",
+ [MSG_I(ME_SET_PS_MODE_REQ)] = "ME_SET_PS_MODE_REQ",
+ [MSG_I(ME_SET_PS_MODE_CFM)] = "ME_SET_PS_MODE_CFM",
+ [MSG_I(ME_SET_LP_LEVEL_REQ)] = "ME_SET_LP_LEVEL_REQ",
+ [MSG_I(ME_SET_LP_LEVEL_CFM)] = "ME_SET_LP_LEVEL_CFM",
+};
+
+static const char *const rwnx_smid2str[MSG_I(SM_MAX)] = {
+ [MSG_I(SM_CONNECT_REQ)] = "SM_CONNECT_REQ",
+ [MSG_I(SM_CONNECT_CFM)] = "SM_CONNECT_CFM",
+ [MSG_I(SM_CONNECT_IND)] = "SM_CONNECT_IND",
+ [MSG_I(SM_DISCONNECT_REQ)] = "SM_DISCONNECT_REQ",
+ [MSG_I(SM_DISCONNECT_CFM)] = "SM_DISCONNECT_CFM",
+ [MSG_I(SM_DISCONNECT_IND)] = "SM_DISCONNECT_IND",
+ [MSG_I(SM_EXTERNAL_AUTH_REQUIRED_IND)] = "SM_EXTERNAL_AUTH_REQUIRED_IND",
+ [MSG_I(SM_EXTERNAL_AUTH_REQUIRED_RSP)] = "SM_EXTERNAL_AUTH_REQUIRED_RSP",
+ [MSG_I(SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM)] =
+ "SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM",
+};
+
+static const char *const rwnx_apmid2str[MSG_I(APM_MAX)] = {
+ [MSG_I(APM_START_REQ)] = "APM_START_REQ",
+ [MSG_I(APM_START_CFM)] = "APM_START_CFM",
+ [MSG_I(APM_STOP_REQ)] = "APM_STOP_REQ",
+ [MSG_I(APM_STOP_CFM)] = "APM_STOP_CFM",
+ [MSG_I(APM_START_CAC_REQ)] = "APM_START_CAC_REQ",
+ [MSG_I(APM_START_CAC_CFM)] = "APM_START_CAC_CFM",
+ [MSG_I(APM_STOP_CAC_REQ)] = "APM_STOP_CAC_REQ",
+ [MSG_I(APM_STOP_CAC_CFM)] = "APM_STOP_CAC_CFM",
+ [MSG_I(APM_SET_BEACON_IE_REQ)] = "APM_SET_BEACON_IE_REQ",
+ [MSG_I(APM_SET_BEACON_IE_CFM)] = "APM_SET_BEACON_IE_CFM",
+};
+
+static const char *const rwnx_meshid2str[MSG_I(MESH_MAX)] = {
+ [MSG_I(MESH_START_REQ)] = "MESH_START_REQ",
+ [MSG_I(MESH_START_CFM)] = "MESH_START_CFM",
+ [MSG_I(MESH_STOP_REQ)] = "MESH_STOP_REQ",
+ [MSG_I(MESH_STOP_CFM)] = "MESH_STOP_CFM",
+ [MSG_I(MESH_UPDATE_REQ)] = "MESH_UPDATE_REQ",
+ [MSG_I(MESH_UPDATE_CFM)] = "MESH_UPDATE_CFM",
+ [MSG_I(MESH_PATH_CREATE_REQ)] = "MESH_PATH_CREATE_REQ",
+ [MSG_I(MESH_PATH_CREATE_CFM)] = "MESH_PATH_CREATE_CFM",
+ [MSG_I(MESH_PATH_UPDATE_REQ)] = "MESH_PATH_UPDATE_REQ",
+ [MSG_I(MESH_PATH_UPDATE_CFM)] = "MESH_PATH_UPDATE_CFM",
+ [MSG_I(MESH_PROXY_ADD_REQ)] = "MESH_PROXY_ADD_REQ",
+ [MSG_I(MESH_PEER_UPDATE_IND)] = "MESH_PEER_UPDATE_IND",
+ [MSG_I(MESH_PATH_UPDATE_IND)] = "MESH_PATH_UPDATE_IND",
+ [MSG_I(MESH_PROXY_UPDATE_IND)] = "MESH_PROXY_UPDATE_IND",
+};
+
+#endif /* CONFIG_RWNX_FULLMAC */
+
+const char *const *rwnx_id2str[TASK_LAST_EMB + 1] = {
+ [TASK_MM] = rwnx_mmid2str, [TASK_DBG] = rwnx_dbgid2str,
+ [TASK_SCAN] = rwnx_scanid2str, [TASK_TDLS] = rwnx_tdlsid2str,
+#ifdef CONFIG_RWNX_FULLMAC
+ [TASK_SCANU] = rwnx_scanuid2str, [TASK_ME] = rwnx_meid2str,
+ [TASK_SM] = rwnx_smid2str, [TASK_APM] = rwnx_apmid2str,
+ [TASK_MESH] = rwnx_meshid2str,
+#endif
+};
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_strs.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_strs.h
new file mode 100644
index 0000000000000..1b4df40f2a912
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_strs.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ****************************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @file rwnx_strs.h
+ *
+ * @brief Miscellaneous debug strings
+ *
+ ****************************************************************************************
+ */
+
+#ifndef _RWNX_STRS_H_
+#define _RWNX_STRS_H_
+
+#include "lmac_msg.h"
+
+#define RWNX_ID2STR(tag) \
+ ({ \
+ const typeof(tag) __tag = (tag); \
+ ((MSG_T(__tag) < ARRAY_SIZE(rwnx_id2str)) && \
+ (rwnx_id2str[MSG_T(__tag)]) && \
+ ((rwnx_id2str[MSG_T(__tag)])[MSG_I(__tag)])) \
+ ? (rwnx_id2str[MSG_T(__tag)])[MSG_I(__tag)] \
+ : "unknown"; \
+ })
+
+extern const char *const *rwnx_id2str[TASK_LAST_EMB + 1];
+
+#endif /* _RWNX_STRS_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_utils.c b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_utils.c
new file mode 100644
index 0000000000000..73e8ab7c8af5c
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_utils.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ ****************************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @file rwnx_utils.c
+ *
+ * @brief IPC utility function declarations
+ *
+ ****************************************************************************************
+ */
+
+#include "rwnx_utils.h"
+#include "ipc_host.h"
+#include "rwnx_defs.h"
+#include "rwnx_msg_rx.h"
+#include "rwnx_prof.h"
+#include "rwnx_rx.h"
+#include "rwnx_tx.h"
+
+int rwnx_init_aic(struct rwnx_hw *rwnx_hw)
+{
+ RWNX_DBG(RWNX_FN_ENTRY_STR);
+#ifdef AICWF_SDIO_SUPPORT
+ aicwf_sdio_host_init(&rwnx_hw->sdio_env, NULL, NULL, rwnx_hw);
+#else
+ aicwf_usb_host_init(&rwnx_hw->usb_env, NULL, NULL, rwnx_hw);
+#endif
+ rwnx_cmd_mgr_init(rwnx_hw->cmd_mgr);
+
+ rwnx_hw->testmode = get_testmode();
+
+ return 0;
+}
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_utils.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_utils.h
new file mode 100644
index 0000000000000..aecd627ff9867
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_utils.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ****************************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @file rwnx_utils.c
+ *
+ * @brief IPC utility function declarations
+ *
+ ****************************************************************************************
+ */
+
+#ifndef _RWNX_IPC_UTILS_H_
+#define _RWNX_IPC_UTILS_H_
+
+#include "aicwf_debug.h"
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/skbuff.h>
+#include "lmac_msg.h"
+#include "rwnx_compat.h"
+
+enum rwnx_dev_flag {
+ RWNX_DEV_RESTARTING,
+ RWNX_DEV_STACK_RESTARTING,
+ RWNX_DEV_STARTED,
+};
+
+struct rwnx_hw;
+struct rwnx_sta;
+
+/**
+ * struct rwnx_ipc_elem - Generic IPC buffer of fixed size
+ *
+ * @addr: Host address of the buffer.
+ * @dma_addr: DMA address of the buffer.
+ */
+struct rwnx_ipc_elem {
+ void *addr;
+ dma_addr_t dma_addr;
+};
+
+/**
+ * struct rwnx_ipc_elem_pool - Generic pool of IPC buffers of fixed size
+ *
+ * @nb: Number of buffers currenlty allocated in the pool
+ * @buf: Array of buffers (size of array is @nb)
+ * @pool: DMA pool in which buffers have been allocated
+ */
+struct rwnx_ipc_elem_pool {
+ int nb;
+ struct rwnx_ipc_elem *buf;
+ struct dma_pool *pool;
+};
+
+/**
+ * struct rwnx_ipc_elem_var - Generic IPC buffer of variable size
+ *
+ * @addr: Host address of the buffer.
+ * @dma_addr: DMA address of the buffer.
+ * @size: Size, in bytes, of the buffer
+ */
+struct rwnx_ipc_elem_var {
+ void *addr;
+ dma_addr_t dma_addr;
+ size_t size;
+};
+
+/**
+ * struct rwnx_ipc_dbgdump_elem - IPC buffer for debug dump
+ *
+ * @mutex: Mutex to protect access to debug dump
+ * @buf: IPC buffer
+ */
+struct rwnx_ipc_dbgdump_elem {
+ struct mutex mutex; //Mutex to protect access to debug dump
+ struct rwnx_ipc_elem_var buf;
+};
+
+/*
+ * Maximum Length of Radiotap header vendor specific data(in bytes)
+ */
+#define RADIOTAP_HDR_VEND_MAX_LEN 16
+
+/*
+ * Maximum Radiotap Header Length without vendor specific data (in bytes)
+ */
+#define RADIOTAP_HDR_MAX_LEN 80
+
+/*
+ * Unsupported HT Frame data length (in bytes)
+ */
+#define UNSUP_RX_VEC_DATA_LEN 2
+
+/**
+ * struct rwnx_ipc_skb_elem - IPC buffer for SKB element
+ *
+ * @skb: Pointer to the skb buffer allocated
+ * @dma_addr: DMA address of the data buffer fo skb
+ *
+ */
+struct rwnx_ipc_skb_elem {
+ struct sk_buff *skb;
+ dma_addr_t dma_addr;
+};
+
+#ifdef CONFIG_RWNX_FULLMAC
+
+/* Maximum number of rx buffer the fw may use at the same time */
+#define RWNX_RXBUFF_MAX (64 * NX_REMOTE_STA_MAX)
+
+/**
+ * struct rwnx_ipc_rxbuf_elems - IPC buffers for RX
+ *
+ * @skb: Array of buffer push to FW.
+ * @idx: Index of the last pushed skb.(Use to find the next free entry quicker)
+ *
+ * Note: contrary to softmac version, dma_addr are stored inside skb->cb.
+ */
+struct rwnx_ipc_rxbuf_elems {
+ struct sk_buff *skb[RWNX_RXBUFF_MAX];
+ int idx;
+};
+
+#endif /* CONFIG_RWNX_FULLMAC */
+int rwnx_init_aic(struct rwnx_hw *rwnx_hw);
+
+int get_testmode(void);
+
+#endif /* _RWNX_IPC_UTILS_H_ */
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_v7.c b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_v7.c
new file mode 100644
index 0000000000000..4138c7f7d07e4
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_v7.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ ****************************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @file rwnx_v7.h
+ *
+ ****************************************************************************************
+ */
+
+#include "rwnx_v7.h"
+#include "hal_desc.h"
+#include "reg_access.h"
+#include "rwnx_defs.h"
+#include "rwnx_irqs.h"
+
+struct rwnx_v7 {
+ u8 __iomem *pci_bar0_vaddr;
+ u8 __iomem *pci_bar1_vaddr;
+};
+
+static int rwnx_v7_platform_enable(struct rwnx_hw *rwnx_hw)
+{
+ int ret;
+
+ /* sched_setscheduler on ONESHOT threaded irq handler for BCNs ? */
+ ret = request_irq(rwnx_hw->plat->pci_dev->irq, rwnx_irq_hdlr, 0, "rwnx",
+ rwnx_hw);
+ return ret;
+}
+
+static int rwnx_v7_platform_disable(struct rwnx_hw *rwnx_hw)
+{
+ free_irq(rwnx_hw->plat->pci_dev->irq, rwnx_hw);
+ return 0;
+}
+
+static void rwnx_v7_platform_deinit(struct rwnx_plat *rwnx_plat)
+{
+#ifdef CONFIG_PCI
+ struct rwnx_v7 *rwnx_v7 = (struct rwnx_v7 *)rwnx_plat->priv;
+
+ pci_disable_device(rwnx_plat->pci_dev);
+ iounmap(rwnx_v7->pci_bar0_vaddr);
+ iounmap(rwnx_v7->pci_bar1_vaddr);
+ pci_release_regions(rwnx_plat->pci_dev);
+ pci_clear_master(rwnx_plat->pci_dev);
+ pci_disable_msi(rwnx_plat->pci_dev);
+#endif
+ kfree(rwnx_plat);
+}
+
+static u8 __iomem *rwnx_v7_get_address(struct rwnx_plat *rwnx_plat,
+ int addr_name, unsigned int offset)
+{
+ struct rwnx_v7 *rwnx_v7 = (struct rwnx_v7 *)rwnx_plat->priv;
+
+ if (WARN(addr_name >= RWNX_ADDR_MAX, "Invalid address %d", addr_name))
+ return NULL;
+
+ if (addr_name == RWNX_ADDR_CPU)
+ return rwnx_v7->pci_bar0_vaddr + offset;
+ else
+ return rwnx_v7->pci_bar1_vaddr + offset;
+}
+
+static void rwnx_v7_ack_irq(struct rwnx_plat *rwnx_plat)
+{
+}
+
+static const u32 rwnx_v7_config_reg[] = {
+ NXMAC_DEBUG_PORT_SEL_ADDR, SYSCTRL_DIAG_CONF_ADDR,
+ SYSCTRL_PHYDIAG_CONF_ADDR, SYSCTRL_RIUDIAG_CONF_ADDR,
+ RF_V7_DIAGPORT_CONF1_ADDR,
+};
+
+static const u32 rwnx_v7_he_config_reg[] = {
+ SYSCTRL_DIAG_CONF0,
+ SYSCTRL_DIAG_CONF1,
+ SYSCTRL_DIAG_CONF2,
+ SYSCTRL_DIAG_CONF3,
+};
+
+static int rwnx_v7_get_config_reg(struct rwnx_plat *rwnx_plat, const u32 **list)
+{
+ u32 fpga_sign;
+
+ if (!list)
+ return 0;
+
+ fpga_sign =
+ RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, SYSCTRL_SIGNATURE_ADDR);
+ if (__FPGA_TYPE(fpga_sign) == 0xc0ca) {
+ *list = rwnx_v7_he_config_reg;
+ return ARRAY_SIZE(rwnx_v7_he_config_reg);
+ }
+ *list = rwnx_v7_config_reg;
+ return ARRAY_SIZE(rwnx_v7_config_reg);
+}
+
+/**
+ * rwnx_v7_platform_init - Initialize the DINI platform
+ * @pci_dev: PCI device
+ * @rwnx_plat: Location in which to return the allocated platform data
+ *
+ * Allocate and initialize a rwnx_plat structure for the dini platform.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+int rwnx_v7_platform_init(struct pci_dev *pci_dev, struct rwnx_plat **rwnx_plat)
+{
+ struct rwnx_v7 *rwnx_v7;
+ u16 pci_cmd;
+ int ret = 0;
+
+ *rwnx_plat =
+ kzalloc(sizeof(struct rwnx_plat) + sizeof(struct rwnx_v7), GFP_KERNEL);
+ if (!*rwnx_plat)
+ return -ENOMEM;
+
+ rwnx_v7 = (struct rwnx_v7 *)(*rwnx_plat)->priv;
+
+ /* Hotplug fixups */
+ pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd);
+ pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+ pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd);
+
+ ret = pci_enable_device(pci_dev);
+ if (ret) {
+ dev_err(&pci_dev->dev, "pci_enable_device failed\n");
+ goto out_enable;
+ }
+
+ pci_set_master(pci_dev);
+
+#ifdef CONFIG_PCI
+ if (pci_enable_msi(pci_dev)) {
+ dev_err(&pci_dev->dev, "pci_enable_msi failed\n");
+ goto out_msi;
+ }
+#endif
+
+ rwnx_v7->pci_bar0_vaddr = pci_ioremap_bar(pci_dev, 0);
+ if (!rwnx_v7->pci_bar0_vaddr) {
+ dev_err(&pci_dev->dev, "pci_ioremap_bar(%d) failed\n", 0);
+ ret = -ENOMEM;
+ goto out_bar0;
+ }
+ rwnx_v7->pci_bar1_vaddr = pci_ioremap_bar(pci_dev, 1);
+ if (!rwnx_v7->pci_bar1_vaddr) {
+ dev_err(&pci_dev->dev, "pci_ioremap_bar(%d) failed\n", 1);
+ ret = -ENOMEM;
+ goto out_bar1;
+ }
+
+ (*rwnx_plat)->enable = rwnx_v7_platform_enable;
+ (*rwnx_plat)->disable = rwnx_v7_platform_disable;
+ (*rwnx_plat)->deinit = rwnx_v7_platform_deinit;
+ (*rwnx_plat)->get_address = rwnx_v7_get_address;
+ (*rwnx_plat)->ack_irq = rwnx_v7_ack_irq;
+ (*rwnx_plat)->get_config_reg = rwnx_v7_get_config_reg;
+
+ return 0;
+
+out_bar1:
+ iounmap(rwnx_v7->pci_bar0_vaddr);
+out_bar0:
+#ifdef CONFIG_PCI
+ pci_disable_msi(pci_dev);
+out_msi:
+#endif
+ pci_release_regions(pci_dev);
+#ifdef CONFIG_PCI
+ pci_clear_master(pci_dev);
+#endif
+ pci_disable_device(pci_dev);
+out_enable:
+ kfree(*rwnx_plat);
+ return ret;
+}
diff --git a/drivers/net/wireless/aic/aic8800_fdrv/rwnx_v7.h b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_v7.h
new file mode 100644
index 0000000000000..709553f96c2a1
--- /dev/null
+++ b/drivers/net/wireless/aic/aic8800_fdrv/rwnx_v7.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ ****************************************************************************************
+ *
+ * Copyright (C) 2020 AIC semiconductor.
+ *
+ * @file rwnx_v7.h
+ *
+ ****************************************************************************************
+ */
+
+#ifndef _RWNX_V7_H_
+#define _RWNX_V7_H_
+
+#include "rwnx_platform.h"
+#include <linux/pci.h>
+
+int rwnx_v7_platform_init(struct pci_dev *pci_dev,
+ struct rwnx_plat **rwnx_plat);
+
+#endif /* _RWNX_V7_H_ */
--
2.34.1
next prev parent reply other threads:[~2026-08-29 8:22 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-23 2:13 [RFC PATCH wireless-next v2 0/4] wifi: aic: add AIC8800 SDIO FullMAC driver Yanli Yang
2026-07-23 2:13 ` [RFC PATCH wireless-next v2 1/4] wifi: aic: add SDIO BSP and build configuration Yanli Yang
2026-07-23 2:13 ` [RFC PATCH wireless-next v2 2/4] wifi: aic: add FullMAC firmware and platform interface Yanli Yang
2026-07-23 2:13 ` [RFC PATCH wireless-next v2 3/4] wifi: aic: add FullMAC WLAN driver Yanli Yang
2026-07-23 2:13 ` [RFC PATCH wireless-next v2 4/4] wifi: aic: integrate AIC8800 driver Yanli Yang
2026-07-23 8:42 ` [RFC PATCH wireless-next v2 0/4] wifi: aic: add AIC8800 SDIO FullMAC driver Johannes Berg
2026-07-23 8:48 ` Johannes Berg
2026-08-28 12:11 ` [RFC PATCH wireless-next v3 0/4] wifi: aic: add AIC8800D80 " Yanli Yang
2026-08-28 12:11 ` [RFC PATCH wireless-next v3 1/4] wifi: aic: add SDIO BSP and build configuration Yanli Yang
2026-08-29 8:18 ` Krzysztof Kozlowski
2026-08-28 12:11 ` [RFC PATCH wireless-next v3 2/4] wifi: aic: add FullMAC firmware and platform interface Yanli Yang
2026-08-28 12:11 ` [RFC PATCH wireless-next v3 3/4] wifi: aic: add FullMAC WLAN driver Yanli Yang
2026-08-29 8:21 ` Krzysztof Kozlowski
2026-08-28 12:11 ` [RFC PATCH wireless-next v3 4/4] wifi: aic: integrate AIC8800 driver Yanli Yang
2026-08-29 8:21 ` [RFC PATCH wireless-next v4 0/4] wifi: aic: add AIC8800D80 SDIO FullMAC driver Yanli Yang
2026-08-29 8:21 ` [RFC PATCH wireless-next v4 1/4] wifi: aic: add SDIO BSP and build configuration Yanli Yang
2026-08-29 8:21 ` Yanli Yang [this message]
2026-08-29 8:21 ` [RFC PATCH wireless-next v4 3/4] wifi: aic: add FullMAC WLAN driver Yanli Yang
2026-08-29 8:21 ` [RFC PATCH wireless-next v4 4/4] wifi: aic: integrate AIC8800 driver Yanli Yang
2026-08-31 7:16 ` [RFC PATCH wireless-next v4 0/4] wifi: aic: add AIC8800D80 SDIO FullMAC driver Christian Hewitt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9d002f2a238c38ef40a3434ae47b4d91fa191840.1787991457.git.yanli.yang@bedmex.com \
--to=yanli.yang@bedmex.com \
--cc=chunqiuliu@aicsemi.com \
--cc=dijiaxu@aicsemi.com \
--cc=johannes@sipsolutions.net \
--cc=liheng.wei@bedmex.com \
--cc=linux-wireless@vger.kernel.org \
--cc=zhirunliu@aicsemi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox