Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/wireless/realtek/rtw89/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 353 kB image not shown  

Quelle  coex.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2019-2020  Realtek Corporation
 */


#include "chan.h"
#include "coex.h"
#include "debug.h"
#include "fw.h"
#include "mac.h"
#include "phy.h"
#include "ps.h"
#include "reg.h"

#define RTW89_COEX_VERSION 0x09000013
#define FCXDEF_STEP 50 /* MUST <= FCXMAX_STEP and match with wl fw*/
#define BTC_E2G_LIMIT_DEF 80

enum btc_fbtc_tdma_template {
 CXTD_OFF = 0x0,
 CXTD_OFF_B2,
 CXTD_OFF_EXT,
 CXTD_FIX,
 CXTD_PFIX,
 CXTD_AUTO,
 CXTD_PAUTO,
 CXTD_AUTO2,
 CXTD_PAUTO2,
 CXTD_MAX,
};

enum btc_fbtc_tdma_type {
 CXTDMA_OFF = 0x0,
 CXTDMA_FIX = 0x1,
 CXTDMA_AUTO = 0x2,
 CXTDMA_AUTO2 = 0x3,
 CXTDMA_MAX
};

enum btc_fbtc_tdma_rx_flow_ctrl {
 CXFLC_OFF = 0x0,
 CXFLC_NULLP = 0x1,
 CXFLC_QOSNULL = 0x2,
 CXFLC_CTS = 0x3,
 CXFLC_MAX
};

enum btc_fbtc_tdma_wlan_tx_pause {
 CXTPS_OFF = 0x0,  /* no wl tx pause*/
 CXTPS_ON = 0x1,
 CXTPS_MAX
};

enum btc_mlme_state {
 MLME_NO_LINK,
 MLME_LINKING,
 MLME_LINKED,
};

struct btc_fbtc_1slot {
 u8 fver;
 u8 sid; /* slot id */
 struct rtw89_btc_fbtc_slot slot;
} __packed;

static const struct rtw89_btc_fbtc_tdma t_def[] = {
 [CXTD_OFF] = { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
 [CXTD_OFF_B2] = { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 1, 0, 0},
 [CXTD_OFF_EXT] = { CXTDMA_OFF,    CXFLC_OFF, CXTPS_OFF, 0, 0, 2, 0, 0},
 [CXTD_FIX] = { CXTDMA_FIX,    CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
 [CXTD_PFIX] = { CXTDMA_FIX,  CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0},
 [CXTD_AUTO] = { CXTDMA_AUTO,   CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
 [CXTD_PAUTO] = { CXTDMA_AUTO, CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0},
 [CXTD_AUTO2] = {CXTDMA_AUTO2,   CXFLC_OFF, CXTPS_OFF, 0, 0, 0, 0, 0},
 [CXTD_PAUTO2] = {CXTDMA_AUTO2, CXFLC_NULLP,  CXTPS_ON, 0, 5, 0, 0, 0}
};

#define __DEF_FBTC_SLOT(__dur, __cxtbl, __cxtype) \
 { .dur = cpu_to_le16(__dur), .cxtbl = cpu_to_le32(__cxtbl), \
   .cxtype = cpu_to_le16(__cxtype),}

static const struct rtw89_btc_fbtc_slot s_def[] = {
 [CXST_OFF] = __DEF_FBTC_SLOT(100, 0x55555555, SLOT_MIX),
 [CXST_B2W] = __DEF_FBTC_SLOT(5,   0xea5a5a5a, SLOT_ISO),
 [CXST_W1] = __DEF_FBTC_SLOT(70,  0xea5a5a5a, SLOT_ISO),
 [CXST_W2] = __DEF_FBTC_SLOT(15,  0xea5a5a5a, SLOT_ISO),
 [CXST_W2B] = __DEF_FBTC_SLOT(15,  0xea5a5a5a, SLOT_ISO),
 [CXST_B1] = __DEF_FBTC_SLOT(250, 0xe5555555, SLOT_MIX),
 [CXST_B2] = __DEF_FBTC_SLOT(7,   0xea5a5a5a, SLOT_MIX),
 [CXST_B3] = __DEF_FBTC_SLOT(5,   0xe5555555, SLOT_MIX),
 [CXST_B4] = __DEF_FBTC_SLOT(50,  0xe5555555, SLOT_MIX),
 [CXST_LK] = __DEF_FBTC_SLOT(20,  0xea5a5a5a, SLOT_ISO),
 [CXST_BLK] = __DEF_FBTC_SLOT(500, 0x55555555, SLOT_MIX),
 [CXST_E2G] = __DEF_FBTC_SLOT(5,   0xea5a5a5a, SLOT_MIX),
 [CXST_E5G] = __DEF_FBTC_SLOT(5,   0xffffffff, SLOT_ISO),
 [CXST_EBT] = __DEF_FBTC_SLOT(5,   0xe5555555, SLOT_MIX),
 [CXST_ENULL] = __DEF_FBTC_SLOT(5,   0x55555555, SLOT_MIX),
 [CXST_WLK] = __DEF_FBTC_SLOT(250, 0xea5a5a5a, SLOT_MIX),
 [CXST_W1FDD] = __DEF_FBTC_SLOT(50,  0xffffffff, SLOT_ISO),
 [CXST_B1FDD] = __DEF_FBTC_SLOT(50,  0xffffdfff, SLOT_ISO),
};

static const u32 cxtbl[] = {
 0xffffffff, /* 0 */
 0xaaaaaaaa, /* 1 */
 0xe5555555, /* 2 */
 0xee555555, /* 3 */
 0xd5555555, /* 4 */
 0x5a5a5a5a, /* 5 */
 0xfa5a5a5a, /* 6 */
 0xda5a5a5a, /* 7 */
 0xea5a5a5a, /* 8 */
 0x6a5a5aaa, /* 9 */
 0x6a5a6a5a, /* 10 */
 0x6a5a6aaa, /* 11 */
 0x6afa5afa, /* 12 */
 0xaaaa5aaa, /* 13 */
 0xaaffffaa, /* 14 */
 0xaa5555aa, /* 15 */
 0xfafafafa, /* 16 */
 0xffffddff, /* 17 */
 0xdaffdaff, /* 18 */
 0xfafadafa, /* 19 */
 0xea6a6a6a, /* 20 */
 0xea55556a, /* 21 */
 0xaafafafa, /* 22 */
 0xfafaaafa, /* 23 */
 0xfafffaff, /* 24 */
 0xea6a5a5a, /* 25 */
 0xfaff5aff, /* 26 */
 0xffffdfff, /* 27 */
 0xe6555555, /* 28 */
};

static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
 /* firmware version must be in decreasing order for each chip */
 {RTL8852BT, RTW89_FW_VER_CODE(0, 29, 122, 0),
  .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  .fwlrole = 7,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
  .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800,
  .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
 },
 {RTL8852BT, RTW89_FW_VER_CODE(0, 29, 90, 0),
  .fcxbtcrpt = 7, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  .fwlrole = 7,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
  .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800,
  .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
 },
 {RTL8922A, RTW89_FW_VER_CODE(0, 35, 71, 0),
  .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  .fwlrole = 8,   .frptmap = 4,    .fcxctrl = 7,  .fcxinit = 7,
  .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_type = 2, .info_buf = 1800,
  .max_role_num = 6, .fcxosi = 1,  .fcxmlo = 1,   .bt_desired = 9,
 },
 {RTL8922A, RTW89_FW_VER_CODE(0, 35, 63, 0),
  .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  .fwlrole = 8,   .frptmap = 4,    .fcxctrl = 7,  .fcxinit = 7,
  .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_type = 2, .info_buf = 1800,
  .max_role_num = 6, .fcxosi = 1,  .fcxmlo = 1,   .bt_desired = 9,
 },
 {RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0),
  .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  .fwlrole = 8,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
  .fwevntrptl = 1, .fwc2hfunc = 1, .drvinfo_type = 1, .info_buf = 1800,
  .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },
 {RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0),
  .fcxbtcrpt = 105, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 5,
  .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 2,  .fcxgpiodbg = 1,
  .fcxbtver = 1,  .fcxbtscan = 2,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  .fwlrole = 2,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
  .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800,
  .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },
 {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0),
  .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
  .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  .fwlrole = 1,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
  .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
  .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },
 {RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0),
  .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
  .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  .fwlrole = 1,   .frptmap = 2,    .fcxctrl = 1,  .fcxinit = 0,
  .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
  .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },
 {RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0),
  .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
  .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
  .fwlrole = 1,   .frptmap = 2,    .fcxctrl = 1,  .fcxinit = 0,
  .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
  .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },
 {RTL8852B, RTW89_FW_VER_CODE(0, 29, 122, 0),
  .fcxbtcrpt = 8, .fcxtdma = 7,    .fcxslots = 7, .fcxcysta = 7,
  .fcxstep = 7,   .fcxnullsta = 7, .fcxmreg = 7,  .fcxgpiodbg = 7,
  .fcxbtver = 7,  .fcxbtscan = 7,  .fcxbtafh = 7, .fcxbtdevinfo = 7,
  .fwlrole = 7,   .frptmap = 3,    .fcxctrl = 7,  .fcxinit = 7,
  .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800,
  .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 8,
 },
 {RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0),
  .fcxbtcrpt = 105, .fcxtdma = 3,  .fcxslots = 1, .fcxcysta = 5,
  .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 2,  .fcxgpiodbg = 1,
  .fcxbtver = 1,  .fcxbtscan = 2,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  .fwlrole = 2,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
  .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800,
  .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },
 {RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0),
  .fcxbtcrpt = 5, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 4,
  .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  .fwlrole = 1,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
  .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800,
  .max_role_num = 6, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },
 {RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0),
  .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
  .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
  .fwlrole = 1,   .frptmap = 1,    .fcxctrl = 1,  .fcxinit = 0,
  .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280,
  .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },
 {RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0),
  .fcxbtcrpt = 4, .fcxtdma = 3,    .fcxslots = 1, .fcxcysta = 3,
  .fcxstep = 3,   .fcxnullsta = 2, .fcxmreg = 1,  .fcxgpiodbg = 1,
  .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 2, .fcxbtdevinfo = 1,
  .fwlrole = 1,   .frptmap = 3,    .fcxctrl = 1,  .fcxinit = 0,
  .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1280,
  .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },
 {RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0),
  .fcxbtcrpt = 1, .fcxtdma = 1,    .fcxslots = 1, .fcxcysta = 2,
  .fcxstep = 2,   .fcxnullsta = 1, .fcxmreg = 1,  .fcxgpiodbg = 1,
  .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
  .fwlrole = 0,   .frptmap = 0,    .fcxctrl = 0,  .fcxinit = 0,
  .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1024,
  .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },

 /* keep it to be the last as default entry */
 {0, RTW89_FW_VER_CODE(0, 0, 0, 0),
  .fcxbtcrpt = 1, .fcxtdma = 1,    .fcxslots = 1, .fcxcysta = 2,
  .fcxstep = 2,   .fcxnullsta = 1, .fcxmreg = 1,  .fcxgpiodbg = 1,
  .fcxbtver = 1,  .fcxbtscan = 1,  .fcxbtafh = 1, .fcxbtdevinfo = 1,
  .fwlrole = 0,   .frptmap = 0,    .fcxctrl = 0,  .fcxinit = 0,
  .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1024,
  .max_role_num = 5, .fcxosi = 0,  .fcxmlo = 0,   .bt_desired = 7,
 },
};

#define RTW89_DEFAULT_BTC_VER_IDX (ARRAY_SIZE(rtw89_btc_ver_defs) - 1)

static const union rtw89_btc_wl_state_map btc_scanning_map = {
 .map = {
  .scan = 1,
  .connecting = 1,
  .roaming = 1,
  .dbccing = 1,
  ._4way = 1,
 },
};

static u32 chip_id_to_bt_rom_code_id(u32 id)
{
 switch (id) {
 case RTL8852A:
 case RTL8852B:
 case RTL8852C:
 case RTL8852BT:
  return 0x8852;
 case RTL8851B:
  return 0x8851;
 case RTL8922A:
  return 0x8922;
 default:
  return 0;
 }
}

#define CASE_BTC_MLME_STATE(e) case MLME_##e: return #e

static const char *id_to_mlme_state(u32 id)
{
 switch (id) {
 CASE_BTC_MLME_STATE(NO_LINK);
 CASE_BTC_MLME_STATE(LINKING);
 CASE_BTC_MLME_STATE(LINKED);
 default:
  return "unknown";
 }
}

static char *chip_id_str(u32 id)
{
 switch (id) {
 case RTL8852A:
  return "RTL8852A";
 case RTL8852B:
  return "RTL8852B";
 case RTL8852C:
  return "RTL8852C";
 case RTL8852BT:
  return "RTL8852BT";
 case RTL8851B:
  return "RTL8851B";
 case RTL8922A:
  return "RTL8922A";
 default:
  return "UNKNOWN";
 }
}

struct rtw89_btc_btf_tlv {
 u8 type;
 u8 len;
 u8 val[];
} __packed;

struct rtw89_btc_btf_tlv_v7 {
 u8 type;
 u8 ver;
 u8 len;
 u8 val[];
} __packed;

enum btc_btf_set_report_en {
 RPT_EN_TDMA,
 RPT_EN_CYCLE,
 RPT_EN_MREG,
 RPT_EN_BT_VER_INFO,
 RPT_EN_BT_SCAN_INFO,
 RPT_EN_BT_DEVICE_INFO,
 RPT_EN_BT_AFH_MAP,
 RPT_EN_BT_AFH_MAP_LE,
 RPT_EN_BT_TX_PWR_LVL,
 RPT_EN_FW_STEP_INFO,
 RPT_EN_TEST,
 RPT_EN_WL_ALL,
 RPT_EN_BT_ALL,
 RPT_EN_ALL,
 RPT_EN_MONITER,
};

struct rtw89_btc_btf_set_report_v1 {
 u8 fver;
 __le32 enable;
 __le32 para;
} __packed;

struct rtw89_btc_btf_set_report_v8 {
 u8 type;
 u8 fver;
 u8 len;
 __le32 map;
} __packed;

union rtw89_fbtc_rtp_ctrl {
 struct rtw89_btc_btf_set_report_v1 v1;
 struct rtw89_btc_btf_set_report_v8 v8;
};

#define BTF_SET_SLOT_TABLE_VER 1
struct rtw89_btc_btf_set_slot_table {
 u8 fver;
 u8 tbl_num;
 struct rtw89_btc_fbtc_slot tbls[] __counted_by(tbl_num);
} __packed;

struct rtw89_btc_btf_set_slot_table_v7 {
 u8 type;
 u8 ver;
 u8 len;
 struct rtw89_btc_fbtc_slot_v7 v7[CXST_MAX];
} __packed;

struct rtw89_btc_btf_set_mon_reg_v1 {
 u8 fver;
 u8 reg_num;
 struct rtw89_btc_fbtc_mreg regs[] __counted_by(reg_num);
} __packed;

struct rtw89_btc_btf_set_mon_reg_v7 {
 u8 type;
 u8 fver;
 u8 len;
 struct rtw89_btc_fbtc_mreg regs[] __counted_by(len);
} __packed;

union rtw89_fbtc_set_mon_reg {
 struct rtw89_btc_btf_set_mon_reg_v1 v1;
 struct rtw89_btc_btf_set_mon_reg_v7 v7;
} __packed;

struct _wl_rinfo_now {
 u8 link_mode;
 u32 dbcc_2g_phy: 2;
};

enum btc_btf_set_cx_policy {
 CXPOLICY_TDMA = 0x0,
 CXPOLICY_SLOT = 0x1,
 CXPOLICY_TYPE = 0x2,
 CXPOLICY_MAX,
};

enum btc_b2w_scoreboard {
 BTC_BSCB_ACT = BIT(0),
 BTC_BSCB_ON = BIT(1),
 BTC_BSCB_WHQL = BIT(2),
 BTC_BSCB_BT_S1 = BIT(3),
 BTC_BSCB_A2DP_ACT = BIT(4),
 BTC_BSCB_RFK_RUN = BIT(5),
 BTC_BSCB_RFK_REQ = BIT(6),
 BTC_BSCB_LPS = BIT(7),
 BTC_BSCB_BT_LNAB0 = BIT(8),
 BTC_BSCB_BT_LNAB1 = BIT(10),
 BTC_BSCB_WLRFK = BIT(11),
 BTC_BSCB_BT_HILNA = BIT(13),
 BTC_BSCB_BT_CONNECT = BIT(16),
 BTC_BSCB_PATCH_CODE = BIT(30),
 BTC_BSCB_ALL = GENMASK(30, 0),
};

enum btc_phymap {
 BTC_PHY_0 = BIT(0),
 BTC_PHY_1 = BIT(1),
 BTC_PHY_ALL = BIT(0) | BIT(1),
};

enum btc_cx_state_map {
 BTC_WIDLE = 0,
 BTC_WBUSY_BNOSCAN,
 BTC_WBUSY_BSCAN,
 BTC_WSCAN_BNOSCAN,
 BTC_WSCAN_BSCAN,
 BTC_WLINKING
};

enum btc_ant_phase {
 BTC_ANT_WPOWERON = 0,
 BTC_ANT_WINIT,
 BTC_ANT_WONLY,
 BTC_ANT_WOFF,
 BTC_ANT_W2G,
 BTC_ANT_W5G,
 BTC_ANT_W25G,
 BTC_ANT_FREERUN,
 BTC_ANT_WRFK,
 BTC_ANT_WRFK2,
 BTC_ANT_BRFK,
 BTC_ANT_MAX
};

enum btc_plt {
 BTC_PLT_NONE = 0,
 BTC_PLT_LTE_RX = BIT(0),
 BTC_PLT_GNT_BT_TX = BIT(1),
 BTC_PLT_GNT_BT_RX = BIT(2),
 BTC_PLT_GNT_WL = BIT(3),
 BTC_PLT_BT = BIT(1) | BIT(2),
 BTC_PLT_ALL = 0xf
};

enum btc_cx_poicy_main_type {
 BTC_CXP_OFF = 0,
 BTC_CXP_OFFB,
 BTC_CXP_OFFE,
 BTC_CXP_FIX,
 BTC_CXP_PFIX,
 BTC_CXP_AUTO,
 BTC_CXP_PAUTO,
 BTC_CXP_AUTO2,
 BTC_CXP_PAUTO2,
 BTC_CXP_MANUAL,
 BTC_CXP_USERDEF0,
 BTC_CXP_MAIN_MAX
};

enum btc_cx_poicy_type {
 /* TDMA off + pri: BT > WL */
 BTC_CXP_OFF_BT = (BTC_CXP_OFF << 8) | 0,

 /* TDMA off + pri: WL > BT */
 BTC_CXP_OFF_WL = (BTC_CXP_OFF << 8) | 1,

 /* TDMA off + pri: BT = WL */
 BTC_CXP_OFF_EQ0 = (BTC_CXP_OFF << 8) | 2,

 /* TDMA off + pri: BT = WL > BT_Lo */
 BTC_CXP_OFF_EQ1 = (BTC_CXP_OFF << 8) | 3,

 /* TDMA off + pri: WL = BT, BT_Rx > WL_Lo_Tx */
 BTC_CXP_OFF_EQ2 = (BTC_CXP_OFF << 8) | 4,

 /* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
 BTC_CXP_OFF_EQ3 = (BTC_CXP_OFF << 8) | 5,

 /* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
 BTC_CXP_OFF_EQ4 = (BTC_CXP_OFF << 8) | 6,

 /* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
 BTC_CXP_OFF_EQ5 = (BTC_CXP_OFF << 8) | 7,

 /* TDMA off + pri: BT_Hi > WL > BT_Lo */
 BTC_CXP_OFF_BWB0 = (BTC_CXP_OFF << 8) | 8,

 /* TDMA off + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo */
 BTC_CXP_OFF_BWB1 = (BTC_CXP_OFF << 8) | 9,

 /* TDMA off + pri: WL_Hi-Tx > BT, BT_Hi > other-WL > BT_Lo */
 BTC_CXP_OFF_BWB2 = (BTC_CXP_OFF << 8) | 10,

 /* TDMA off + pri: WL_Hi-Tx = BT */
 BTC_CXP_OFF_BWB3 = (BTC_CXP_OFF << 8) | 11,

 /* TDMA off + pri: WL > BT, Block-BT*/
 BTC_CXP_OFF_WL2 = (BTC_CXP_OFF << 8) | 12,

 /* TDMA off+Bcn-Protect + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo*/
 BTC_CXP_OFFB_BWB0 = (BTC_CXP_OFFB << 8) | 0,

 /* TDMA off + Ext-Ctrl + pri: default */
 BTC_CXP_OFFE_DEF = (BTC_CXP_OFFE << 8) | 0,

 /* TDMA off + Ext-Ctrl + pri: E2G-slot block all BT */
 BTC_CXP_OFFE_DEF2 = (BTC_CXP_OFFE << 8) | 1,

 /* TDMA off + Ext-Ctrl + pri: default */
 BTC_CXP_OFFE_2GBWISOB = (BTC_CXP_OFFE << 8) | 2,

 /* TDMA off + Ext-Ctrl + pri: E2G-slot block all BT */
 BTC_CXP_OFFE_2GISOB = (BTC_CXP_OFFE << 8) | 3,

 /* TDMA off + Ext-Ctrl + pri: E2G-slot WL > BT */
 BTC_CXP_OFFE_2GBWMIXB = (BTC_CXP_OFFE << 8) | 4,

 /* TDMA off + Ext-Ctrl + pri: E2G/EBT-slot WL > BT */
 BTC_CXP_OFFE_WL = (BTC_CXP_OFFE << 8) | 5,

 /* TDMA off + Ext-Ctrl + pri: default */
 BTC_CXP_OFFE_2GBWMIXB2 = (BTC_CXP_OFFE << 8) | 6,

 /* TDMA Fix slot-0: W1:B1 = 30:30 */
 BTC_CXP_FIX_TD3030 = (BTC_CXP_FIX << 8) | 0,

 /* TDMA Fix slot-1: W1:B1 = 50:50 */
 BTC_CXP_FIX_TD5050 = (BTC_CXP_FIX << 8) | 1,

 /* TDMA Fix slot-2: W1:B1 = 20:30 */
 BTC_CXP_FIX_TD2030 = (BTC_CXP_FIX << 8) | 2,

 /* TDMA Fix slot-3: W1:B1 = 40:10 */
 BTC_CXP_FIX_TD4010 = (BTC_CXP_FIX << 8) | 3,

 /* TDMA Fix slot-4: W1:B1 = 70:10 */
 BTC_CXP_FIX_TD7010 = (BTC_CXP_FIX << 8) | 4,

 /* TDMA Fix slot-5: W1:B1 = 20:60 */
 BTC_CXP_FIX_TD2060 = (BTC_CXP_FIX << 8) | 5,

 /* TDMA Fix slot-6: W1:B1 = 30:60 */
 BTC_CXP_FIX_TD3060 = (BTC_CXP_FIX << 8) | 6,

 /* TDMA Fix slot-7: W1:B1 = 20:80 */
 BTC_CXP_FIX_TD2080 = (BTC_CXP_FIX << 8) | 7,

 /* TDMA Fix slot-8: W1:B1 = user-define */
 BTC_CXP_FIX_TDW1B1 = (BTC_CXP_FIX << 8) | 8,

 /* TDMA Fix slot-9: W1:B1 = 40:10 */
 BTC_CXP_FIX_TD4010ISO = (BTC_CXP_FIX << 8) | 9,

 /* TDMA Fix slot-10: W1:B1 = 40:10 */
 BTC_CXP_FIX_TD4010ISO_DL = (BTC_CXP_FIX << 8) | 10,

 /* TDMA Fix slot-11: W1:B1 = 40:10 */
 BTC_CXP_FIX_TD4010ISO_UL = (BTC_CXP_FIX << 8) | 11,

 /* PS-TDMA Fix slot-0: W1:B1 = 30:30 */
 BTC_CXP_PFIX_TD3030 = (BTC_CXP_PFIX << 8) | 0,

 /* PS-TDMA Fix slot-1: W1:B1 = 50:50 */
 BTC_CXP_PFIX_TD5050 = (BTC_CXP_PFIX << 8) | 1,

 /* PS-TDMA Fix slot-2: W1:B1 = 20:30 */
 BTC_CXP_PFIX_TD2030 = (BTC_CXP_PFIX << 8) | 2,

 /* PS-TDMA Fix slot-3: W1:B1 = 20:60 */
 BTC_CXP_PFIX_TD2060 = (BTC_CXP_PFIX << 8) | 3,

 /* PS-TDMA Fix slot-4: W1:B1 = 30:70 */
 BTC_CXP_PFIX_TD3070 = (BTC_CXP_PFIX << 8) | 4,

 /* PS-TDMA Fix slot-5: W1:B1 = 20:80 */
 BTC_CXP_PFIX_TD2080 = (BTC_CXP_PFIX << 8) | 5,

 /* PS-TDMA Fix slot-6: W1:B1 = user-define */
 BTC_CXP_PFIX_TDW1B1 = (BTC_CXP_PFIX << 8) | 6,

 /* TDMA Auto slot-0: W1:B1 = 50:200 */
 BTC_CXP_AUTO_TD50B1 = (BTC_CXP_AUTO << 8) | 0,

 /* TDMA Auto slot-1: W1:B1 = 60:200 */
 BTC_CXP_AUTO_TD60B1 = (BTC_CXP_AUTO << 8) | 1,

 /* TDMA Auto slot-2: W1:B1 = 20:200 */
 BTC_CXP_AUTO_TD20B1 = (BTC_CXP_AUTO << 8) | 2,

 /* TDMA Auto slot-3: W1:B1 = user-define */
 BTC_CXP_AUTO_TDW1B1 = (BTC_CXP_AUTO << 8) | 3,

 /* PS-TDMA Auto slot-0: W1:B1 = 50:200 */
 BTC_CXP_PAUTO_TD50B1 = (BTC_CXP_PAUTO << 8) | 0,

 /* PS-TDMA Auto slot-1: W1:B1 = 60:200 */
 BTC_CXP_PAUTO_TD60B1 = (BTC_CXP_PAUTO << 8) | 1,

 /* PS-TDMA Auto slot-2: W1:B1 = 20:200 */
 BTC_CXP_PAUTO_TD20B1 = (BTC_CXP_PAUTO << 8) | 2,

 /* PS-TDMA Auto slot-3: W1:B1 = user-define */
 BTC_CXP_PAUTO_TDW1B1 = (BTC_CXP_PAUTO << 8) | 3,

 /* TDMA Auto slot2-0: W1:B4 = 30:50 */
 BTC_CXP_AUTO2_TD3050 = (BTC_CXP_AUTO2 << 8) | 0,

 /* TDMA Auto slot2-1: W1:B4 = 30:70 */
 BTC_CXP_AUTO2_TD3070 = (BTC_CXP_AUTO2 << 8) | 1,

 /* TDMA Auto slot2-2: W1:B4 = 50:50 */
 BTC_CXP_AUTO2_TD5050 = (BTC_CXP_AUTO2 << 8) | 2,

 /* TDMA Auto slot2-3: W1:B4 = 60:60 */
 BTC_CXP_AUTO2_TD6060 = (BTC_CXP_AUTO2 << 8) | 3,

 /* TDMA Auto slot2-4: W1:B4 = 20:80 */
 BTC_CXP_AUTO2_TD2080 = (BTC_CXP_AUTO2 << 8) | 4,

 /* TDMA Auto slot2-5: W1:B4 = user-define */
 BTC_CXP_AUTO2_TDW1B4 = (BTC_CXP_AUTO2 << 8) | 5,

 /* PS-TDMA Auto slot2-0: W1:B4 = 30:50 */
 BTC_CXP_PAUTO2_TD3050 = (BTC_CXP_PAUTO2 << 8) | 0,

 /* PS-TDMA Auto slot2-1: W1:B4 = 30:70 */
 BTC_CXP_PAUTO2_TD3070 = (BTC_CXP_PAUTO2 << 8) | 1,

 /* PS-TDMA Auto slot2-2: W1:B4 = 50:50 */
 BTC_CXP_PAUTO2_TD5050 = (BTC_CXP_PAUTO2 << 8) | 2,

 /* PS-TDMA Auto slot2-3: W1:B4 = 60:60 */
 BTC_CXP_PAUTO2_TD6060 = (BTC_CXP_PAUTO2 << 8) | 3,

 /* PS-TDMA Auto slot2-4: W1:B4 = 20:80 */
 BTC_CXP_PAUTO2_TD2080 = (BTC_CXP_PAUTO2 << 8) | 4,

 /* PS-TDMA Auto slot2-5: W1:B4 = user-define */
 BTC_CXP_PAUTO2_TDW1B4 = (BTC_CXP_PAUTO2 << 8) | 5,

 BTC_CXP_MAX = 0xffff
};

enum btc_wl_rfk_result {
 BTC_WRFK_REJECT = 0,
 BTC_WRFK_ALLOW = 1,
};

enum btc_coex_info_map_en {
 BTC_COEX_INFO_CX = BIT(0),
 BTC_COEX_INFO_WL = BIT(1),
 BTC_COEX_INFO_BT = BIT(2),
 BTC_COEX_INFO_DM = BIT(3),
 BTC_COEX_INFO_MREG = BIT(4),
 BTC_COEX_INFO_SUMMARY = BIT(5),
 BTC_COEX_INFO_ALL = GENMASK(7, 0),
};

#define BTC_CXP_MASK GENMASK(15, 8)

enum btc_w2b_scoreboard {
 BTC_WSCB_ACTIVE = BIT(0),
 BTC_WSCB_ON = BIT(1),
 BTC_WSCB_SCAN = BIT(2),
 BTC_WSCB_UNDERTEST = BIT(3),
 BTC_WSCB_RXGAIN = BIT(4),
 BTC_WSCB_WLBUSY = BIT(7),
 BTC_WSCB_EXTFEM = BIT(8),
 BTC_WSCB_TDMA = BIT(9),
 BTC_WSCB_FIX2M = BIT(10),
 BTC_WSCB_WLRFK = BIT(11),
 BTC_WSCB_RXSCAN_PRI = BIT(12),
 BTC_WSCB_BT_HILNA = BIT(13),
 BTC_WSCB_BTLOG = BIT(14),
 BTC_WSCB_ALL = GENMASK(23, 0),
};

enum btc_wl_link_mode {
 BTC_WLINK_NOLINK = 0x0,
 BTC_WLINK_2G_STA,
 BTC_WLINK_2G_AP,
 BTC_WLINK_2G_GO,
 BTC_WLINK_2G_GC,
 BTC_WLINK_2G_SCC,
 BTC_WLINK_2G_MCC,
 BTC_WLINK_25G_MCC,
 BTC_WLINK_25G_DBCC,
 BTC_WLINK_5G,
 BTC_WLINK_2G_NAN,
 BTC_WLINK_OTHER,
 BTC_WLINK_MAX
};

#define CASE_BTC_WL_LINK_MODE(e) case BTC_WLINK_## e: return #e

static const char *id_to_linkmode(u8 id)
{
 switch (id) {
 CASE_BTC_WL_LINK_MODE(NOLINK);
 CASE_BTC_WL_LINK_MODE(2G_STA);
 CASE_BTC_WL_LINK_MODE(2G_AP);
 CASE_BTC_WL_LINK_MODE(2G_GO);
 CASE_BTC_WL_LINK_MODE(2G_GC);
 CASE_BTC_WL_LINK_MODE(2G_SCC);
 CASE_BTC_WL_LINK_MODE(2G_MCC);
 CASE_BTC_WL_LINK_MODE(25G_MCC);
 CASE_BTC_WL_LINK_MODE(25G_DBCC);
 CASE_BTC_WL_LINK_MODE(5G);
 CASE_BTC_WL_LINK_MODE(OTHER);
 default:
  return "unknown";
 }
}

enum btc_wl_mrole_type {
 BTC_WLMROLE_NONE = 0x0,
 BTC_WLMROLE_STA_GC,
 BTC_WLMROLE_STA_GC_NOA,
 BTC_WLMROLE_STA_GO,
 BTC_WLMROLE_STA_GO_NOA,
 BTC_WLMROLE_STA_STA,
 BTC_WLMROLE_MAX
};

enum btc_bt_hid_type {
 BTC_HID_218 = BIT(0),
 BTC_HID_418 = BIT(1),
 BTC_HID_BLE = BIT(2),
 BTC_HID_RCU = BIT(3),
 BTC_HID_RCU_VOICE = BIT(4),
 BTC_HID_OTHER_LEGACY = BIT(5)
};

enum btc_reset_module {
 BTC_RESET_CX = BIT(0),
 BTC_RESET_DM = BIT(1),
 BTC_RESET_CTRL = BIT(2),
 BTC_RESET_CXDM = BIT(0) | BIT(1),
 BTC_RESET_BTINFO = BIT(3),
 BTC_RESET_MDINFO = BIT(4),
 BTC_RESET_ALL =  GENMASK(7, 0),
};

enum btc_gnt_state {
 BTC_GNT_HW = 0,
 BTC_GNT_SW_LO,
 BTC_GNT_SW_HI,
 BTC_GNT_MAX
};

enum btc_ctr_path {
 BTC_CTRL_BY_BT = 0,
 BTC_CTRL_BY_WL
};

enum btc_wlact_state {
 BTC_WLACT_HW = 0,
 BTC_WLACT_SW_LO,
 BTC_WLACT_SW_HI,
 BTC_WLACT_MAX,
};

enum btc_wl_max_tx_time {
 BTC_MAX_TX_TIME_L1 = 500,
 BTC_MAX_TX_TIME_L2 = 1000,
 BTC_MAX_TX_TIME_L3 = 2000,
 BTC_MAX_TX_TIME_DEF = 5280
};

enum btc_wl_max_tx_retry {
 BTC_MAX_TX_RETRY_L1 = 7,
 BTC_MAX_TX_RETRY_L2 = 15,
 BTC_MAX_TX_RETRY_DEF = 31,
};

enum btc_reason_and_action {
 BTC_RSN_NONE,
 BTC_RSN_NTFY_INIT,
 BTC_RSN_NTFY_SWBAND,
 BTC_RSN_NTFY_WL_STA,
 BTC_RSN_NTFY_RADIO_STATE,
 BTC_RSN_UPDATE_BT_SCBD,
 BTC_RSN_NTFY_WL_RFK,
 BTC_RSN_UPDATE_BT_INFO,
 BTC_RSN_NTFY_SCAN_START,
 BTC_RSN_NTFY_SCAN_FINISH,
 BTC_RSN_NTFY_SPECIFIC_PACKET,
 BTC_RSN_NTFY_POWEROFF,
 BTC_RSN_NTFY_ROLE_INFO,
 BTC_RSN_CMD_SET_COEX,
 BTC_RSN_ACT1_WORK,
 BTC_RSN_BT_DEVINFO_WORK,
 BTC_RSN_RFK_CHK_WORK,
 BTC_RSN_NUM,
 BTC_ACT_NONE = 100,
 BTC_ACT_WL_ONLY,
 BTC_ACT_WL_5G,
 BTC_ACT_WL_OTHER,
 BTC_ACT_WL_IDLE,
 BTC_ACT_WL_NC,
 BTC_ACT_WL_RFK,
 BTC_ACT_WL_INIT,
 BTC_ACT_WL_OFF,
 BTC_ACT_FREERUN,
 BTC_ACT_BT_WHQL,
 BTC_ACT_BT_RFK,
 BTC_ACT_BT_OFF,
 BTC_ACT_BT_IDLE,
 BTC_ACT_BT_HFP,
 BTC_ACT_BT_HID,
 BTC_ACT_BT_A2DP,
 BTC_ACT_BT_A2DPSINK,
 BTC_ACT_BT_PAN,
 BTC_ACT_BT_A2DP_HID,
 BTC_ACT_BT_A2DP_PAN,
 BTC_ACT_BT_PAN_HID,
 BTC_ACT_BT_A2DP_PAN_HID,
 BTC_ACT_WL_25G_MCC,
 BTC_ACT_WL_2G_MCC,
 BTC_ACT_WL_2G_SCC,
 BTC_ACT_WL_2G_AP,
 BTC_ACT_WL_2G_GO,
 BTC_ACT_WL_2G_GC,
 BTC_ACT_WL_2G_NAN,
 BTC_ACT_LAST,
 BTC_ACT_NUM = BTC_ACT_LAST - BTC_ACT_NONE,
 BTC_ACT_EXT_BIT = BIT(14),
 BTC_POLICY_EXT_BIT = BIT(15),
};

#define BTC_FREERUN_ANTISO_MIN 30
#define BTC_TDMA_BTHID_MAX 2
#define BTC_BLINK_NOCONNECT 0
#define BTC_B1_MAX 250 /* unit ms */

static void _run_coex(struct rtw89_dev *rtwdev,
        enum btc_reason_and_action reason);
static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state);
static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update);

static int _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func,
   void *param, u16 len)
{
 struct rtw89_btc *btc = &rtwdev->btc;
 struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
 struct rtw89_btc_cx *cx = &btc->cx;
 struct rtw89_btc_wl_info *wl = &cx->wl;
 struct rtw89_btc_dm *dm = &btc->dm;
 int ret;

 if (len > BTC_H2C_MAXLEN || len == 0) {
  btc->fwinfo.cnt_h2c_fail++;
  dm->error.map.h2c_buffer_over = true;
  return -EINVAL;
 } else if (!wl->status.map.init_ok) {
  rtw89_debug(rtwdev, RTW89_DBG_BTC,
       "[BTC], %s(): return by btc not init!!\n", __func__);
  pfwinfo->cnt_h2c_fail++;
  return -EINVAL;
 } else if ((wl->status.map.rf_off_pre == BTC_LPS_RF_OFF &&
      wl->status.map.rf_off == BTC_LPS_RF_OFF) ||
     (wl->status.map.lps_pre == BTC_LPS_RF_OFF &&
      wl->status.map.lps == BTC_LPS_RF_OFF)) {
  rtw89_debug(rtwdev, RTW89_DBG_BTC,
       "[BTC], %s(): return by wl off!!\n", __func__);
  pfwinfo->cnt_h2c_fail++;
  return -EINVAL;
 }

 ret = rtw89_fw_h2c_raw_with_hdr(rtwdev, h2c_class, h2c_func, param, len,
     falsetrue);
 if (ret)
  pfwinfo->cnt_h2c_fail++;
 else
  pfwinfo->cnt_h2c++;

 return ret;
}

#define BTC_BT_DEF_BR_TX_PWR 4
#define BTC_BT_DEF_LE_TX_PWR 4

static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
{
 struct rtw89_btc *btc = &rtwdev->btc;
 const struct rtw89_btc_ver *ver = btc->ver;
 struct rtw89_btc_cx *cx = &btc->cx;
 struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
 struct rtw89_btc_wl_link_info *wl_linfo;
 u8 i;

 rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);

 if (type & BTC_RESET_CX)
  memset(cx, 0, sizeof(*cx));

 if (type & BTC_RESET_BTINFO) /* only for BT enable */
  memset(bt, 0, sizeof(*bt));

 if (type & BTC_RESET_CTRL) {
  memset(&btc->ctrl, 0, sizeof(btc->ctrl));
  btc->manual_ctrl = false;
  if (ver->fcxctrl != 7)
   btc->ctrl.ctrl.trace_step = FCXDEF_STEP;
 }

 /* Init Coex variables that are not zero */
 if (type & BTC_RESET_DM) {
  memset(&btc->dm, 0, sizeof(btc->dm));
  memset(bt_linfo->rssi_state, 0, sizeof(bt_linfo->rssi_state));
  for (i = 0; i < RTW89_PORT_NUM; i++) {
   if (btc->ver->fwlrole == 8)
    wl_linfo = &wl->rlink_info[i][0];
   else
    wl_linfo = &wl->link_info[i];
   memset(wl_linfo->rssi_state, 0, sizeof(wl_linfo->rssi_state));
  }

  /* set the slot_now table to original */
  btc->dm.tdma_now = t_def[CXTD_OFF];
  btc->dm.tdma = t_def[CXTD_OFF];
  if (ver->fcxslots >= 7) {
   for (i = 0; i < ARRAY_SIZE(s_def); i++) {
    btc->dm.slot.v7[i].dur = s_def[i].dur;
    btc->dm.slot.v7[i].cxtype = s_def[i].cxtype;
    btc->dm.slot.v7[i].cxtbl = s_def[i].cxtbl;
   }
   memcpy(&btc->dm.slot_now.v7, &btc->dm.slot.v7,
          sizeof(btc->dm.slot_now.v7));
  } else {
   memcpy(&btc->dm.slot_now.v1, s_def,
          sizeof(btc->dm.slot_now.v1));
   memcpy(&btc->dm.slot.v1, s_def,
          sizeof(btc->dm.slot.v1));
  }

  btc->policy_len = 0;
  btc->bt_req_len = 0;

  btc->dm.coex_info_map = BTC_COEX_INFO_ALL;
  btc->dm.wl_tx_limit.tx_time = BTC_MAX_TX_TIME_DEF;
  btc->dm.wl_tx_limit.tx_retry = BTC_MAX_TX_RETRY_DEF;
  btc->dm.wl_pre_agc_rb = BTC_PREAGC_NOTFOUND;
  btc->dm.wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_NOTFOUND;
 }

 if (type & BTC_RESET_MDINFO)
  memset(&btc->mdinfo, 0, sizeof(btc->mdinfo));

 bt->link_info.bt_txpwr_desc.br_dbm = BTC_BT_DEF_BR_TX_PWR;
 bt->link_info.bt_txpwr_desc.le_dbm = BTC_BT_DEF_LE_TX_PWR;
}

static u8 _search_reg_index(struct rtw89_dev *rtwdev, u8 mreg_num, u16 reg_type, u32 target)
{
 const struct rtw89_chip_info *chip = rtwdev->chip;
 u8 i;

 for (i = 0; i < mreg_num; i++)
  if (le16_to_cpu(chip->mon_reg[i].type) == reg_type &&
      le32_to_cpu(chip->mon_reg[i].offset) == target) {
   return i;
 }
 return BTC_REG_NOTFOUND;
}

static void _get_reg_status(struct rtw89_dev *rtwdev, u8 type, u8 *val)
{
 struct rtw89_btc *btc = &rtwdev->btc;
 const struct rtw89_btc_ver *ver = btc->ver;
 union rtw89_btc_module_info *md = &btc->mdinfo;
 union rtw89_btc_fbtc_mreg_val *pmreg;
 u32 pre_agc_addr = R_BTC_BB_PRE_AGC_S1;
 u32 reg_val;
 u8 idx, switch_type;

 if (ver->fcxinit == 7)
  switch_type = md->md_v7.switch_type;
 else
  switch_type = md->md.switch_type;

 if (btc->btg_pos == RF_PATH_A)
  pre_agc_addr = R_BTC_BB_PRE_AGC_S0;

 switch (type) {
 case BTC_CSTATUS_TXDIV_POS:
  if (switch_type == BTC_SWITCH_INTERNAL)
   *val = BTC_ANT_DIV_MAIN;
  break;
 case BTC_CSTATUS_RXDIV_POS:
  if (switch_type == BTC_SWITCH_INTERNAL)
   *val = BTC_ANT_DIV_MAIN;
  break;
 case BTC_CSTATUS_BB_GNT_MUX:
  reg_val = rtw89_phy_read32(rtwdev, R_BTC_BB_BTG_RX);
  *val = !(reg_val & B_BTC_BB_GNT_MUX);
  break;
 case BTC_CSTATUS_BB_GNT_MUX_MON:
  if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid)
   return;

  pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo;
  if (ver->fcxmreg == 1) {
   idx = _search_reg_index(rtwdev, pmreg->v1.reg_num,
      REG_BB, R_BTC_BB_BTG_RX);
   if (idx == BTC_REG_NOTFOUND) {
    *val = BTC_BTGCTRL_BB_GNT_NOTFOUND;
   } else {
    reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]);
    *val = !(reg_val & B_BTC_BB_GNT_MUX);
   }
  } else if (ver->fcxmreg == 2) {
   idx = _search_reg_index(rtwdev, pmreg->v2.reg_num,
      REG_BB, R_BTC_BB_BTG_RX);
   if (idx == BTC_REG_NOTFOUND) {
    *val = BTC_BTGCTRL_BB_GNT_NOTFOUND;
   } else {
    reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]);
    *val = !(reg_val & B_BTC_BB_GNT_MUX);
   }
  }
  break;
 case BTC_CSTATUS_BB_PRE_AGC:
  reg_val = rtw89_phy_read32(rtwdev, pre_agc_addr);
  reg_val &= B_BTC_BB_PRE_AGC_MASK;
  *val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
  break;
 case BTC_CSTATUS_BB_PRE_AGC_MON:
  if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid)
   return;

  pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo;
  if (ver->fcxmreg == 1) {
   idx = _search_reg_index(rtwdev, pmreg->v1.reg_num,
      REG_BB, pre_agc_addr);
   if (idx == BTC_REG_NOTFOUND) {
    *val = BTC_PREAGC_NOTFOUND;
   } else {
    reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]) &
       B_BTC_BB_PRE_AGC_MASK;
    *val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
   }
  } else if (ver->fcxmreg == 2) {
   idx = _search_reg_index(rtwdev, pmreg->v2.reg_num,
      REG_BB, pre_agc_addr);
   if (idx == BTC_REG_NOTFOUND) {
    *val = BTC_PREAGC_NOTFOUND;
   } else {
    reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]) &
       B_BTC_BB_PRE_AGC_MASK;
    *val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
   }
  }
  break;
 default:
  break;
 }
}

#define BTC_RPT_HDR_SIZE 3
#define BTC_CHK_WLSLOT_DRIFT_MAX 15
#define BTC_CHK_BTSLOT_DRIFT_MAX 15
#define BTC_CHK_HANG_MAX 3

static void _chk_btc_err(struct rtw89_dev *rtwdev, u8 type, u32 cnt)
{
 struct rtw89_btc *btc = &rtwdev->btc;
 struct rtw89_btc_cx *cx = &btc->cx;
 struct rtw89_btc_bt_info *bt = &cx->bt;
 struct rtw89_btc_wl_info *wl = &cx->wl;
 struct rtw89_btc_dm *dm = &btc->dm;

 rtw89_debug(rtwdev, RTW89_DBG_BTC,
      "[BTC], %s(): type:%d cnt:%d\n",
      __func__, type, cnt);

 switch (type) {
 case BTC_DCNT_WL_FW_VER_MATCH:
  if ((wl->ver_info.fw_coex & 0xffff0000) !=
       rtwdev->chip->wlcx_desired) {
   wl->fw_ver_mismatch = true;
   dm->error.map.wl_ver_mismatch = true;
  } else {
   wl->fw_ver_mismatch = false;
   dm->error.map.wl_ver_mismatch = false;
  }
  break;
 case BTC_DCNT_RPT_HANG:
  if (dm->cnt_dm[BTC_DCNT_RPT] == cnt && btc->fwinfo.rpt_en_map)
   dm->cnt_dm[BTC_DCNT_RPT_HANG]++;
  else
   dm->cnt_dm[BTC_DCNT_RPT_HANG] = 0;

  if (dm->cnt_dm[BTC_DCNT_RPT_HANG] >= BTC_CHK_HANG_MAX)
   dm->error.map.wl_fw_hang = true;
  else
   dm->error.map.wl_fw_hang = false;

  dm->cnt_dm[BTC_DCNT_RPT] = cnt;
  break;
 case BTC_DCNT_CYCLE_HANG:
  if (dm->cnt_dm[BTC_DCNT_CYCLE] == cnt &&
      (dm->tdma_now.type != CXTDMA_OFF ||
       dm->tdma_now.ext_ctrl == CXECTL_EXT))
   dm->cnt_dm[BTC_DCNT_CYCLE_HANG]++;
  else
   dm->cnt_dm[BTC_DCNT_CYCLE_HANG] = 0;

  if (dm->cnt_dm[BTC_DCNT_CYCLE_HANG] >= BTC_CHK_HANG_MAX)
   dm->error.map.cycle_hang = true;
  else
   dm->error.map.cycle_hang = false;

  dm->cnt_dm[BTC_DCNT_CYCLE] = cnt;
  break;
 case BTC_DCNT_W1_HANG:
  if (dm->cnt_dm[BTC_DCNT_W1] == cnt &&
      dm->tdma_now.type != CXTDMA_OFF)
   dm->cnt_dm[BTC_DCNT_W1_HANG]++;
  else
   dm->cnt_dm[BTC_DCNT_W1_HANG] = 0;

  if (dm->cnt_dm[BTC_DCNT_W1_HANG] >= BTC_CHK_HANG_MAX)
   dm->error.map.w1_hang = true;
  else
   dm->error.map.w1_hang = false;

  dm->cnt_dm[BTC_DCNT_W1] = cnt;
  break;
 case BTC_DCNT_B1_HANG:
  if (dm->cnt_dm[BTC_DCNT_B1] == cnt &&
      dm->tdma_now.type != CXTDMA_OFF)
   dm->cnt_dm[BTC_DCNT_B1_HANG]++;
  else
   dm->cnt_dm[BTC_DCNT_B1_HANG] = 0;

  if (dm->cnt_dm[BTC_DCNT_B1_HANG] >= BTC_CHK_HANG_MAX)
   dm->error.map.b1_hang = true;
  else
   dm->error.map.b1_hang = false;

  dm->cnt_dm[BTC_DCNT_B1] = cnt;
  break;
 case BTC_DCNT_E2G_HANG:
  if (dm->cnt_dm[BTC_DCNT_E2G] == cnt &&
      dm->tdma_now.ext_ctrl == CXECTL_EXT)
   dm->cnt_dm[BTC_DCNT_E2G_HANG]++;
  else
   dm->cnt_dm[BTC_DCNT_E2G_HANG] = 0;

  if (dm->cnt_dm[BTC_DCNT_E2G_HANG] >= BTC_CHK_HANG_MAX)
   dm->error.map.wl_e2g_hang = true;
  else
   dm->error.map.wl_e2g_hang = false;

  dm->cnt_dm[BTC_DCNT_E2G] = cnt;
  break;
 case BTC_DCNT_TDMA_NONSYNC:
  if (cnt != 0) /* if tdma not sync between drv/fw  */
   dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC]++;
  else
   dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] = 0;

  if (dm->cnt_dm[BTC_DCNT_TDMA_NONSYNC] >= BTC_CHK_HANG_MAX)
   dm->error.map.tdma_no_sync = true;
  else
   dm->error.map.tdma_no_sync = false;
  break;
 case BTC_DCNT_SLOT_NONSYNC:
  if (cnt != 0) /* if slot not sync between drv/fw  */
   dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC]++;
  else
   dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] = 0;

  if (dm->cnt_dm[BTC_DCNT_SLOT_NONSYNC] >= BTC_CHK_HANG_MAX)
   dm->error.map.slot_no_sync = true;
  else
   dm->error.map.slot_no_sync = false;
  break;
 case BTC_DCNT_BTTX_HANG:
  cnt = cx->cnt_bt[BTC_BCNT_LOPRI_TX];

  if (cnt == 0 && bt->link_info.slave_role)
   dm->cnt_dm[BTC_DCNT_BTTX_HANG]++;
  else
   dm->cnt_dm[BTC_DCNT_BTTX_HANG] = 0;

  if (dm->cnt_dm[BTC_DCNT_BTTX_HANG] >= BTC_CHK_HANG_MAX)
   dm->error.map.bt_tx_hang = true;
  else
   dm->error.map.bt_tx_hang = false;
  break;
 case BTC_DCNT_BTCNT_HANG:
  cnt = cx->cnt_bt[BTC_BCNT_HIPRI_RX] +
        cx->cnt_bt[BTC_BCNT_HIPRI_TX] +
        cx->cnt_bt[BTC_BCNT_LOPRI_RX] +
        cx->cnt_bt[BTC_BCNT_LOPRI_TX];

  if (cnt == 0)
   dm->cnt_dm[BTC_DCNT_BTCNT_HANG]++;
  else
   dm->cnt_dm[BTC_DCNT_BTCNT_HANG] = 0;

  if ((dm->cnt_dm[BTC_DCNT_BTCNT_HANG] >= BTC_CHK_HANG_MAX &&
       bt->enable.now) || (!dm->cnt_dm[BTC_DCNT_BTCNT_HANG] &&
       !bt->enable.now))
   _update_bt_scbd(rtwdev, false);
  break;
 case BTC_DCNT_WL_SLOT_DRIFT:
  if (cnt >= BTC_CHK_WLSLOT_DRIFT_MAX)
   dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT]++;
  else
   dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] = 0;

  if (dm->cnt_dm[BTC_DCNT_WL_SLOT_DRIFT] >= BTC_CHK_HANG_MAX)
   dm->error.map.wl_slot_drift = true;
  else
   dm->error.map.wl_slot_drift = false;
  break;
 case BTC_DCNT_BT_SLOT_DRIFT:
  if (cnt >= BTC_CHK_BTSLOT_DRIFT_MAX)
   dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT]++;
  else
   dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT] = 0;

  if (dm->cnt_dm[BTC_DCNT_BT_SLOT_DRIFT] >= BTC_CHK_HANG_MAX)
   dm->error.map.bt_slot_drift = true;
  else
   dm->error.map.bt_slot_drift = false;

  break;
 }
}

static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
{
 struct rtw89_btc *btc = &rtwdev->btc;
 const struct rtw89_btc_ver *ver = btc->ver;
 struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
 struct rtw89_btc_bt_a2dp_desc *a2dp = &bt_linfo->a2dp_desc;
 union  rtw89_btc_fbtc_btver *pver = &btc->fwinfo.rpt_fbtc_btver.finfo;
 struct rtw89_btc_fbtc_btafh_v2 *pafh_v2 = NULL;
 struct rtw89_btc_fbtc_btafh_v7 *pafh_v7 = NULL;
 struct rtw89_btc_fbtc_btdevinfo *pdev = NULL;
 struct rtw89_btc_fbtc_btafh *pafh_v1 = NULL;
 struct rtw89_btc_fbtc_btscan_v1 *pscan_v1;
 struct rtw89_btc_fbtc_btscan_v2 *pscan_v2;
 struct rtw89_btc_fbtc_btscan_v7 *pscan_v7;
 bool scan_update = true;
 int i;

 rtw89_debug(rtwdev, RTW89_DBG_BTC,
      "[BTC], %s(): rpt_type:%d\n",
      __func__, rpt_type);

 switch (rpt_type) {
 case BTC_RPT_TYPE_BT_VER:
  if (ver->fcxbtver == 7) {
   pver->v7 = *(struct rtw89_btc_fbtc_btver_v7 *)pfinfo;
   bt->ver_info.fw = le32_to_cpu(pver->v7.fw_ver);
   bt->ver_info.fw_coex = le32_get_bits(pver->v7.coex_ver,
            GENMASK(7, 0));
   bt->feature = le32_to_cpu(pver->v7.feature);
  } else {
   pver->v1 = *(struct rtw89_btc_fbtc_btver_v1 *)pfinfo;
   bt->ver_info.fw = le32_to_cpu(pver->v1.fw_ver);
   bt->ver_info.fw_coex = le32_get_bits(pver->v1.coex_ver,
            GENMASK(7, 0));
   bt->feature = le32_to_cpu(pver->v1.feature);
  }
  break;
 case BTC_RPT_TYPE_BT_SCAN:
  if (ver->fcxbtscan == 1) {
   pscan_v1 = (struct rtw89_btc_fbtc_btscan_v1 *)pfinfo;
   for (i = 0; i < BTC_SCAN_MAX1; i++) {
    bt->scan_info_v1[i] = pscan_v1->scan[i];
    if (bt->scan_info_v1[i].win == 0 &&
        bt->scan_info_v1[i].intvl == 0)
     scan_update = false;
   }
  } else if (ver->fcxbtscan == 2) {
   pscan_v2 = (struct rtw89_btc_fbtc_btscan_v2 *)pfinfo;
   for (i = 0; i < CXSCAN_MAX; i++) {
    bt->scan_info_v2[i] = pscan_v2->para[i];
    if ((pscan_v2->type & BIT(i)) &&
        pscan_v2->para[i].win == 0 &&
        pscan_v2->para[i].intvl == 0)
     scan_update = false;
   }
  } else if (ver->fcxbtscan == 7) {
   pscan_v7 = (struct rtw89_btc_fbtc_btscan_v7 *)pfinfo;
   for (i = 0; i < CXSCAN_MAX; i++) {
    bt->scan_info_v2[i] = pscan_v7->para[i];
    if ((pscan_v7->type & BIT(i)) &&
        pscan_v7->para[i].win == 0 &&
        pscan_v7->para[i].intvl == 0)
     scan_update = false;
   }
  }
  if (scan_update)
   bt->scan_info_update = 1;
  break;
 case BTC_RPT_TYPE_BT_AFH:
  if (ver->fcxbtafh == 2) {
   pafh_v2 = (struct rtw89_btc_fbtc_btafh_v2 *)pfinfo;
   if (pafh_v2->map_type & RPT_BT_AFH_SEQ_LEGACY) {
    memcpy(&bt_linfo->afh_map[0], pafh_v2->afh_l, 4);
    memcpy(&bt_linfo->afh_map[4], pafh_v2->afh_m, 4);
    memcpy(&bt_linfo->afh_map[8], pafh_v2->afh_h, 2);
   }
   if (pafh_v2->map_type & RPT_BT_AFH_SEQ_LE) {
    memcpy(&bt_linfo->afh_map_le[0], pafh_v2->afh_le_a, 4);
    memcpy(&bt_linfo->afh_map_le[4], pafh_v2->afh_le_b, 1);
   }
  } else if (ver->fcxbtafh == 7) {
   pafh_v7 = (struct rtw89_btc_fbtc_btafh_v7 *)pfinfo;
   if (pafh_v7->map_type & RPT_BT_AFH_SEQ_LEGACY) {
    memcpy(&bt_linfo->afh_map[0], pafh_v7->afh_l, 4);
    memcpy(&bt_linfo->afh_map[4], pafh_v7->afh_m, 4);
    memcpy(&bt_linfo->afh_map[8], pafh_v7->afh_h, 2);
   }
   if (pafh_v7->map_type & RPT_BT_AFH_SEQ_LE) {
    memcpy(&bt_linfo->afh_map_le[0], pafh_v7->afh_le_a, 4);
    memcpy(&bt_linfo->afh_map_le[4], pafh_v7->afh_le_b, 1);
   }
  } else if (ver->fcxbtafh == 1) {
   pafh_v1 = (struct rtw89_btc_fbtc_btafh *)pfinfo;
   memcpy(&bt_linfo->afh_map[0], pafh_v1->afh_l, 4);
   memcpy(&bt_linfo->afh_map[4], pafh_v1->afh_m, 4);
   memcpy(&bt_linfo->afh_map[8], pafh_v1->afh_h, 2);
  }
  break;
 case BTC_RPT_TYPE_BT_DEVICE:
  pdev = (struct rtw89_btc_fbtc_btdevinfo *)pfinfo;
  a2dp->device_name = le32_to_cpu(pdev->dev_name);
  a2dp->vendor_id = le16_to_cpu(pdev->vendor_id);
  a2dp->flush_time = le32_to_cpu(pdev->flush_time);
  break;
 default:
  break;
 }
}

static void rtw89_btc_fw_rpt_evnt_ver(struct rtw89_dev *rtwdev, u8 *index)
{
 struct rtw89_btc *btc = &rtwdev->btc;
 const struct rtw89_btc_ver *ver = btc->ver;

 if (ver->fwevntrptl == 1)
  return;

 if (*index <= __BTC_RPT_TYPE_V0_SAME)
  return;
 else if (*index <= __BTC_RPT_TYPE_V0_MAX)
  (*index)++;
 else
  *index = BTC_RPT_TYPE_MAX;
}

#define BTC_LEAK_AP_TH 10
#define BTC_CYSTA_CHK_PERIOD 100

struct rtw89_btc_prpt {
 u8 type;
 __le16 len;
 u8 content[];
} __packed;

static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
      struct rtw89_btc_btf_fwinfo *pfwinfo,
      u8 *prptbuf, u32 index)
{
 struct rtw89_btc *btc = &rtwdev->btc;
 struct rtw89_btc_ver *fwsubver = &btc->fwinfo.fw_subver;
 const struct rtw89_btc_ver *ver = btc->ver;
 struct rtw89_btc_dm *dm = &btc->dm;
 struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
 struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 struct rtw89_btc_bt_info *bt = &btc->cx.bt;
 union rtw89_btc_fbtc_rpt_ctrl_ver_info *prpt = NULL;
 union rtw89_btc_fbtc_cysta_info *pcysta = NULL;
 struct rtw89_btc_prpt *btc_prpt = NULL;
 void *rpt_content = NULL, *pfinfo = NULL;
 u8 rpt_type = 0;
 u16 wl_slot_set = 0, wl_slot_real = 0, val16;
 u32 trace_step = 0, rpt_len = 0, diff_t = 0;
 u32 cnt_leak_slot, bt_slot_real, bt_slot_set, cnt_rx_imr;
 u8 i, val = 0, val1, val2;

 rtw89_debug(rtwdev, RTW89_DBG_BTC,
      "[BTC], %s(): index:%d\n",
      __func__, index);

 if (!prptbuf) {
  pfwinfo->err[BTFRE_INVALID_INPUT]++;
  return 0;
 }

 btc_prpt = (struct rtw89_btc_prpt *)&prptbuf[index];
 rpt_type = btc_prpt->type;
 rpt_len = le16_to_cpu(btc_prpt->len);
 rpt_content = btc_prpt->content;

 rtw89_debug(rtwdev, RTW89_DBG_BTC,
      "[BTC], %s(): rpt_type:%d\n",
      __func__, rpt_type);

 rtw89_btc_fw_rpt_evnt_ver(rtwdev, &rpt_type);

 switch (rpt_type) {
 case BTC_RPT_TYPE_CTRL:
  pcinfo = &pfwinfo->rpt_ctrl.cinfo;
  prpt = &pfwinfo->rpt_ctrl.finfo;
  if (ver->fcxbtcrpt == 1) {
   pfinfo = &pfwinfo->rpt_ctrl.finfo.v1;
   pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v1);
   fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v1.fver;
  } else if (ver->fcxbtcrpt == 4) {
   pfinfo = &pfwinfo->rpt_ctrl.finfo.v4;
   pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v4);
   fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v4.fver;
  } else if (ver->fcxbtcrpt == 5) {
   pfinfo = &pfwinfo->rpt_ctrl.finfo.v5;
   pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v5);
   fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v5.fver;
  } else if (ver->fcxbtcrpt == 105) {
   pfinfo = &pfwinfo->rpt_ctrl.finfo.v105;
   pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v105);
   fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v105.fver;
   pcinfo->req_fver = 5;
   break;
  } else if (ver->fcxbtcrpt == 8) {
   pfinfo = &pfwinfo->rpt_ctrl.finfo.v8;
   pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v8);
   fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v8.fver;
  } else if (ver->fcxbtcrpt == 7) {
   pfinfo = &pfwinfo->rpt_ctrl.finfo.v7;
   pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v7);
   fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v7.fver;
  } else {
   goto err;
  }
  pcinfo->req_fver = ver->fcxbtcrpt;
  break;
 case BTC_RPT_TYPE_TDMA:
  pcinfo = &pfwinfo->rpt_fbtc_tdma.cinfo;
  if (ver->fcxtdma == 1) {
   pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v1;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v1);
   fwsubver->fcxtdma = 0;
  } else if (ver->fcxtdma == 3 || ver->fcxtdma == 7) {
   pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v3;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v3);
   fwsubver->fcxtdma = pfwinfo->rpt_fbtc_tdma.finfo.v3.fver;
  } else {
   goto err;
  }
  pcinfo->req_fver = ver->fcxtdma;
  break;
 case BTC_RPT_TYPE_SLOT:
  pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo;
  if (ver->fcxslots == 1) {
   pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v1;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v1);
   fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v1.fver;
  } else if (ver->fcxslots == 7) {
   pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v7;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v7);
   fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v7.fver;
  } else {
   goto err;
  }
  pcinfo->req_fver = ver->fcxslots;
  break;
 case BTC_RPT_TYPE_CYSTA:
  pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
  pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
  if (ver->fcxcysta == 2) {
   pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v2;
   pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v2);
   fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v2.fver;
  } else if (ver->fcxcysta == 3) {
   pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v3;
   pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v3);
   fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v3.fver;
  } else if (ver->fcxcysta == 4) {
   pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v4;
   pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v4);
   fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v4.fver;
  } else if (ver->fcxcysta == 5) {
   pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v5;
   pcysta->v5 = pfwinfo->rpt_fbtc_cysta.finfo.v5;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v5);
   fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v5.fver;
  } else if (ver->fcxcysta == 7) {
   pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v7;
   pcysta->v7 = pfwinfo->rpt_fbtc_cysta.finfo.v7;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v7);
   fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v7.fver;
  } else {
   goto err;
  }
  pcinfo->req_fver = ver->fcxcysta;
  break;
 case BTC_RPT_TYPE_STEP:
  pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
  if (ver->fcxctrl != 7)
   trace_step = btc->ctrl.ctrl.trace_step;

  if (ver->fcxstep == 2) {
   pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v2;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v2.step[0]) *
       trace_step +
       offsetof(struct rtw89_btc_fbtc_steps_v2, step);
   fwsubver->fcxstep = pfwinfo->rpt_fbtc_step.finfo.v2.fver;
  } else if (ver->fcxstep == 3) {
   pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v3;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v3.step[0]) *
       trace_step +
       offsetof(struct rtw89_btc_fbtc_steps_v3, step);
   fwsubver->fcxstep = pfwinfo->rpt_fbtc_step.finfo.v3.fver;
  } else {
   goto err;
  }
  pcinfo->req_fver = ver->fcxstep;
  break;
 case BTC_RPT_TYPE_NULLSTA:
  pcinfo = &pfwinfo->rpt_fbtc_nullsta.cinfo;
  if (ver->fcxnullsta == 1) {
   pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v1;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v1);
   fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v1.fver;
  } else if (ver->fcxnullsta == 2) {
   pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v2;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v2);
   fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v2.fver;
  } else if (ver->fcxnullsta == 7) {
   pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v7;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v7);
   fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v7.fver;
  } else {
   goto err;
  }
  pcinfo->req_fver = ver->fcxnullsta;
  break;
 case BTC_RPT_TYPE_MREG:
  pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
  if (ver->fcxmreg == 1) {
   pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v1;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v1);
   fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v1.fver;
  } else if (ver->fcxmreg == 2) {
   pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v2;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v2);
   fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v2.fver;
  } else if (ver->fcxmreg == 7) {
   pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v7;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v7);
   fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v7.fver;
  } else {
   goto err;
  }
  pcinfo->req_fver = ver->fcxmreg;
  break;
 case BTC_RPT_TYPE_GPIO_DBG:
  pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
  if (ver->fcxgpiodbg == 7) {
   pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7);
   fwsubver->fcxgpiodbg = pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7.fver;
  } else {
   pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1);
   fwsubver->fcxgpiodbg = pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1.fver;
  }
  pcinfo->req_fver = ver->fcxgpiodbg;
  break;
 case BTC_RPT_TYPE_BT_VER:
  pcinfo = &pfwinfo->rpt_fbtc_btver.cinfo;
  if (ver->fcxbtver == 1) {
   pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v1;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v1);
   fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v1.fver;
  } else if (ver->fcxbtver == 7) {
   pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v7;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v7);
   fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v7.fver;
  }
  pcinfo->req_fver = ver->fcxbtver;
  break;
 case BTC_RPT_TYPE_BT_SCAN:
  pcinfo = &pfwinfo->rpt_fbtc_btscan.cinfo;
  if (ver->fcxbtscan == 1) {
   pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v1;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v1);
   fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v1.fver;
  } else if (ver->fcxbtscan == 2) {
   pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v2;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v2);
   fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v2.fver;
  } else if (ver->fcxbtscan == 7) {
   pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v7;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v7);
   fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v7.fver;
  } else {
   goto err;
  }
  pcinfo->req_fver = ver->fcxbtscan;
  break;
 case BTC_RPT_TYPE_BT_AFH:
  pcinfo = &pfwinfo->rpt_fbtc_btafh.cinfo;
  if (ver->fcxbtafh == 1) {
   pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v1;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v1);
   fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v1.fver;
  } else if (ver->fcxbtafh == 2) {
   pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v2;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v2);
   fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v2.fver;
  } else if (ver->fcxbtafh == 7) {
   pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v7;
   pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v7);
   fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v7.fver;
  } else {
   goto err;
  }
  pcinfo->req_fver = ver->fcxbtafh;
  break;
 case BTC_RPT_TYPE_BT_DEVICE:
  pcinfo = &pfwinfo->rpt_fbtc_btdev.cinfo;
  pfinfo = &pfwinfo->rpt_fbtc_btdev.finfo;
  pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btdev.finfo);
  fwsubver->fcxbtdevinfo = pfwinfo->rpt_fbtc_btdev.finfo.fver;
  pcinfo->req_fver = ver->fcxbtdevinfo;
  break;
 default:
  pfwinfo->err[BTFRE_UNDEF_TYPE]++;
  return 0;
 }

 pcinfo->rx_len = rpt_len;
 pcinfo->rx_cnt++;

 if (rpt_len != pcinfo->req_len) {
  if (rpt_type < BTC_RPT_TYPE_MAX)
   pfwinfo->len_mismch |= (0x1 << rpt_type);
  else
   pfwinfo->len_mismch |= BIT(31);
  rtw89_debug(rtwdev, RTW89_DBG_BTC,
       "[BTC], %s(): %d rpt_len:%d!=req_len:%d\n",
       __func__, rpt_type, rpt_len, pcinfo->req_len);

  pcinfo->valid = 0;
  return 0;
 } else if (!pfinfo || !rpt_content || !pcinfo->req_len) {
  pfwinfo->err[BTFRE_EXCEPTION]++;
  pcinfo->valid = 0;
  return 0;
 }

 memcpy(pfinfo, rpt_content, pcinfo->req_len);
 pcinfo->valid = 1;

 switch (rpt_type) {
 case BTC_RPT_TYPE_CTRL:
  if (ver->fcxbtcrpt == 1) {
   prpt->v1 = pfwinfo->rpt_ctrl.finfo.v1;
   btc->fwinfo.rpt_en_map = prpt->v1.rpt_enable;
   wl->ver_info.fw_coex = prpt->v1.wl_fw_coex_ver;
   wl->ver_info.fw = prpt->v1.wl_fw_ver;
   dm->wl_fw_cx_offload = !!prpt->v1.wl_fw_cx_offload;

   _chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
         pfwinfo->event[BTF_EVNT_RPT]);

   /* To avoid I/O if WL LPS or power-off */
   if (wl->status.map.lps != BTC_LPS_RF_OFF &&
       !wl->status.map.rf_off) {
    rtwdev->chip->ops->btc_update_bt_cnt(rtwdev);
    _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);

    btc->cx.cnt_bt[BTC_BCNT_POLUT] =
     rtw89_mac_get_plt_cnt(rtwdev,
             RTW89_MAC_0);
   }
  } else if (ver->fcxbtcrpt == 4) {
   prpt->v4 = pfwinfo->rpt_ctrl.finfo.v4;
   btc->fwinfo.rpt_en_map = le32_to_cpu(prpt->v4.rpt_info.en);
   wl->ver_info.fw_coex = le32_to_cpu(prpt->v4.wl_fw_info.cx_ver);
   wl->ver_info.fw = le32_to_cpu(prpt->v4.wl_fw_info.fw_ver);
   dm->wl_fw_cx_offload = !!le32_to_cpu(prpt->v4.wl_fw_info.cx_offload);

   for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
    memcpy(&dm->gnt.band[i], &prpt->v4.gnt_val[i],
           sizeof(dm->gnt.band[i]));

   btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
    le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_TX]);
   btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
    le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_HI_RX]);
   btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
    le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_TX]);
   btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
    le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_LO_RX]);
   btc->cx.cnt_bt[BTC_BCNT_POLUT] =
    le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_POLLUTED]);

   _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
   _chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
         pfwinfo->event[BTF_EVNT_RPT]);

   if (le32_to_cpu(prpt->v4.bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0)
    bt->rfk_info.map.timeout = 1;
   else
    bt->rfk_info.map.timeout = 0;

   dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
  } else if (ver->fcxbtcrpt == 5) {
   prpt->v5 = pfwinfo->rpt_ctrl.finfo.v5;
   pfwinfo->rpt_en_map = le32_to_cpu(prpt->v5.rpt_info.en);
   wl->ver_info.fw_coex = le32_to_cpu(prpt->v5.rpt_info.cx_ver);
   wl->ver_info.fw = le32_to_cpu(prpt->v5.rpt_info.fw_ver);
   dm->wl_fw_cx_offload = 0;

   for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
    memcpy(&dm->gnt.band[i], &prpt->v5.gnt_val[i][0],
           sizeof(dm->gnt.band[i]));

   btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
    le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_TX]);
   btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
    le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_HI_RX]);
   btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
    le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_TX]);
   btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
    le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_LO_RX]);
   btc->cx.cnt_bt[BTC_BCNT_POLUT] =
    le16_to_cpu(prpt->v5.bt_cnt[BTC_BCNT_POLLUTED]);

   _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
   _chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
         pfwinfo->event[BTF_EVNT_RPT]);

   dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
  } else if (ver->fcxbtcrpt == 105) {
   prpt->v105 = pfwinfo->rpt_ctrl.finfo.v105;
   pfwinfo->rpt_en_map = le32_to_cpu(prpt->v105.rpt_info.en);
   wl->ver_info.fw_coex = le32_to_cpu(prpt->v105.rpt_info.cx_ver);
   wl->ver_info.fw = le32_to_cpu(prpt->v105.rpt_info.fw_ver);
   dm->wl_fw_cx_offload = 0;

   for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
    memcpy(&dm->gnt.band[i], &prpt->v105.gnt_val[i][0],
           sizeof(dm->gnt.band[i]));

   btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
    le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_HI_TX_V105]);
   btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
    le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_HI_RX_V105]);
   btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
    le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_LO_TX_V105]);
   btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
    le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_LO_RX_V105]);
   btc->cx.cnt_bt[BTC_BCNT_POLUT] =
    le16_to_cpu(prpt->v105.bt_cnt[BTC_BCNT_POLLUTED_V105]);

   _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
   _chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
         pfwinfo->event[BTF_EVNT_RPT]);

   dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
  } else if (ver->fcxbtcrpt == 7) {
   prpt->v7 = pfwinfo->rpt_ctrl.finfo.v7;
   pfwinfo->rpt_en_map = le32_to_cpu(prpt->v7.rpt_info.en);
   wl->ver_info.fw_coex = le32_to_cpu(prpt->v7.rpt_info.cx_ver);
   wl->ver_info.fw = le32_to_cpu(prpt->v7.rpt_info.fw_ver);

   for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
    memcpy(&dm->gnt.band[i], &prpt->v7.gnt_val[i][0],
           sizeof(dm->gnt.band[i]));

   btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
    le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_HI_TX_V105]);
   btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
    le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_HI_RX_V105]);
   btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
    le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_LO_TX_V105]);
   btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
    le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_LO_RX_V105]);

   val1 = le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_POLLUTED_V105]);
   if (val1 > btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW])
    val1 -= btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW]; /* diff */

   btc->cx.cnt_bt[BTC_BCNT_POLUT_DIFF] = val1;
   btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW] =
    le16_to_cpu(prpt->v7.bt_cnt[BTC_BCNT_POLLUTED_V105]);

   val1 = pfwinfo->event[BTF_EVNT_RPT];
   _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
   _chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG, val1);
   _chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
   _chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
  } else if (ver->fcxbtcrpt == 8) {
   prpt->v8 = pfwinfo->rpt_ctrl.finfo.v8;
   pfwinfo->rpt_en_map = le32_to_cpu(prpt->v8.rpt_info.en);
   wl->ver_info.fw_coex = le32_to_cpu(prpt->v8.rpt_info.cx_ver);
   wl->ver_info.fw = le32_to_cpu(prpt->v8.rpt_info.fw_ver);

   for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
    memcpy(&dm->gnt.band[i], &prpt->v8.gnt_val[i][0],
           sizeof(dm->gnt.band[i]));

   btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
    le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_HI_TX_V105]);
   btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
    le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_HI_RX_V105]);
   btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
    le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_LO_TX_V105]);
   btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
    le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_LO_RX_V105]);

   val1 = le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_POLLUTED_V105]);
   if (val1 > btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW])
    val1 -= btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW]; /* diff */

   btc->cx.cnt_bt[BTC_BCNT_POLUT_DIFF] = val1;
   btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW] =
    le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_POLLUTED_V105]);

   val1 = pfwinfo->event[BTF_EVNT_RPT];
   if (((prpt->v8.rpt_len_max_h << 8) +
         prpt->v8.rpt_len_max_l) != ver->info_buf)
    dm->error.map.h2c_c2h_buffer_mismatch = true;
   else
    dm->error.map.h2c_c2h_buffer_mismatch = false;

   _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
   _chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG, val1);
   _chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
   _chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
  } else {
   goto err;
  }
  break;
 case BTC_RPT_TYPE_TDMA:
  rtw89_debug(rtwdev, RTW89_DBG_BTC,
       "[BTC], %s(): check %d %zu\n", __func__,
       BTC_DCNT_TDMA_NONSYNC,
       sizeof(dm->tdma_now));
  if (ver->fcxtdma == 1)
   _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC,
         memcmp(&dm->tdma_now,
         &pfwinfo->rpt_fbtc_tdma.finfo.v1,
         sizeof(dm->tdma_now)));
  else if (ver->fcxtdma == 3 || ver->fcxtdma == 7)
   _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC,
         memcmp(&dm->tdma_now,
         &pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma,
         sizeof(dm->tdma_now)));
  else
   goto err;
  break;
 case BTC_RPT_TYPE_SLOT:
  if (ver->fcxslots == 7) {
   rtw89_debug(rtwdev, RTW89_DBG_BTC,
        "[BTC], %s(): check %d %zu\n",
        __func__, BTC_DCNT_SLOT_NONSYNC,
        sizeof(dm->slot_now.v7));
   _chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
         memcmp(dm->slot_now.v7,
         pfwinfo->rpt_fbtc_slots.finfo.v7.slot,
         sizeof(dm->slot_now.v7)));
  } else if (ver->fcxslots == 1) {
   rtw89_debug(rtwdev, RTW89_DBG_BTC,
        "[BTC], %s(): check %d %zu\n",
        __func__, BTC_DCNT_SLOT_NONSYNC,
        sizeof(dm->slot_now.v1));
   _chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
         memcmp(dm->slot_now.v1,
         pfwinfo->rpt_fbtc_slots.finfo.v1.slot,
         sizeof(dm->slot_now.v1)));
  }
  break;
 case BTC_RPT_TYPE_CYSTA:
  if (ver->fcxcysta == 2) {
   if (le16_to_cpu(pcysta->v2.cycles) < BTC_CYSTA_CHK_PERIOD)
    break;
   /* Check Leak-AP */
   if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) != 0 &&
       le32_to_cpu(pcysta->v2.leakrx_cnt) != 0 && dm->tdma_now.rxflctrl) {
    if (le32_to_cpu(pcysta->v2.slot_cnt[CXST_LK]) <
        BTC_LEAK_AP_TH * le32_to_cpu(pcysta->v2.leakrx_cnt))
     dm->leak_ap = 1;
   }

   /* Check diff time between WL slot and W1/E2G slot */
   if (dm->tdma_now.type == CXTDMA_OFF &&
       dm->tdma_now.ext_ctrl == CXECTL_EXT) {
    if (ver->fcxslots == 1)
     wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_E2G].dur);
    else if (ver->fcxslots == 7)
     wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_E2G].dur);
   } else {
    if (ver->fcxslots == 1)
     wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
    else if (ver->fcxslots == 7)
     wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
   }

   if (le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) > wl_slot_set) {
    diff_t = le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) - wl_slot_set;
    _chk_btc_err(rtwdev,
          BTC_DCNT_WL_SLOT_DRIFT, diff_t);
   }

   _chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
         le32_to_cpu(pcysta->v2.slot_cnt[CXST_W1]));
   _chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
         le32_to_cpu(pcysta->v2.slot_cnt[CXST_B1]));
   _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
         le16_to_cpu(pcysta->v2.cycles));
  } else if (ver->fcxcysta == 3) {
   if (le16_to_cpu(pcysta->v3.cycles) < BTC_CYSTA_CHK_PERIOD)
    break;

   cnt_leak_slot = le32_to_cpu(pcysta->v3.slot_cnt[CXST_LK]);
   cnt_rx_imr = le32_to_cpu(pcysta->v3.leak_slot.cnt_rximr);

   /* Check Leak-AP */
   if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
       dm->tdma_now.rxflctrl) {
    if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
     dm->leak_ap = 1;
   }

   /* Check diff time between real WL slot and W1 slot */
   if (dm->tdma_now.type == CXTDMA_OFF) {
    if (ver->fcxslots == 1)
     wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
    else if (ver->fcxslots == 7)
     wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
    wl_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_WL]);
    if (wl_slot_real > wl_slot_set) {
     diff_t = wl_slot_real - wl_slot_set;
     _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
    }
   }

   /* Check diff time between real BT slot and EBT/E5G slot */
   if (dm->tdma_now.type == CXTDMA_OFF &&
       dm->tdma_now.ext_ctrl == CXECTL_EXT &&
       btc->bt_req_len != 0) {
    bt_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_BT]);
    if (btc->bt_req_len > bt_slot_real) {
     diff_t = btc->bt_req_len - bt_slot_real;
     _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
    }
   }

   _chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
         le32_to_cpu(pcysta->v3.slot_cnt[CXST_W1]));
   _chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
         le32_to_cpu(pcysta->v3.slot_cnt[CXST_B1]));
   _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
         le16_to_cpu(pcysta->v3.cycles));
  } else if (ver->fcxcysta == 4) {
   if (le16_to_cpu(pcysta->v4.cycles) < BTC_CYSTA_CHK_PERIOD)
    break;

   cnt_leak_slot = le16_to_cpu(pcysta->v4.slot_cnt[CXST_LK]);
   cnt_rx_imr = le32_to_cpu(pcysta->v4.leak_slot.cnt_rximr);

   /* Check Leak-AP */
   if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
       dm->tdma_now.rxflctrl) {
    if (cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
     dm->leak_ap = 1;
   }

   /* Check diff time between real WL slot and W1 slot */
   if (dm->tdma_now.type == CXTDMA_OFF) {
    if (ver->fcxslots == 1)
     wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
    else if (ver->fcxslots == 7)
     wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
    wl_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_WL]);
    if (wl_slot_real > wl_slot_set) {
     diff_t = wl_slot_real - wl_slot_set;
     _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, diff_t);
    }
   }

   /* Check diff time between real BT slot and EBT/E5G slot */
   if (dm->tdma_now.type == CXTDMA_OFF &&
       dm->tdma_now.ext_ctrl == CXECTL_EXT &&
       btc->bt_req_len != 0) {
    bt_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_BT]);

    if (btc->bt_req_len > bt_slot_real) {
     diff_t = btc->bt_req_len - bt_slot_real;
     _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, diff_t);
    }
   }

   _chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
         le16_to_cpu(pcysta->v4.slot_cnt[CXST_W1]));
   _chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
         le16_to_cpu(pcysta->v4.slot_cnt[CXST_B1]));
   _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
         le16_to_cpu(pcysta->v4.cycles));
  } else if (ver->fcxcysta == 5) {
   if (dm->fddt_train == BTC_FDDT_ENABLE)
    break;
   cnt_leak_slot = le16_to_cpu(pcysta->v5.slot_cnt[CXST_LK]);
   cnt_rx_imr = le32_to_cpu(pcysta->v5.leak_slot.cnt_rximr);

   /* Check Leak-AP */
   if (cnt_leak_slot != 0 && cnt_rx_imr != 0 &&
       dm->tdma_now.rxflctrl) {
    if (le16_to_cpu(pcysta->v5.cycles) >= BTC_CYSTA_CHK_PERIOD &&
        cnt_leak_slot < BTC_LEAK_AP_TH * cnt_rx_imr)
     dm->leak_ap = 1;
   }

   /* Check diff time between real WL slot and W1 slot */
   if (dm->tdma_now.type == CXTDMA_OFF) {
    if (ver->fcxslots == 1)
     wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
    else if (ver->fcxslots == 7)
     wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
    wl_slot_real = le16_to_cpu(pcysta->v5.cycle_time.tavg[CXT_WL]);

    if (wl_slot_real > wl_slot_set)
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=92 G=94

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.