Path: blob/master/drivers/net/wireless/realtek/rtw88/coex.c
25924 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/* Copyright(c) 2018-2019 Realtek Corporation2*/34#include "main.h"5#include "coex.h"6#include "fw.h"7#include "ps.h"8#include "debug.h"9#include "reg.h"10#include "phy.h"1112static u8 rtw_coex_next_rssi_state(struct rtw_dev *rtwdev, u8 pre_state,13u8 rssi, u8 rssi_thresh)14{15const struct rtw_chip_info *chip = rtwdev->chip;16u8 tol = chip->rssi_tolerance;17u8 next_state;1819if (pre_state == COEX_RSSI_STATE_LOW ||20pre_state == COEX_RSSI_STATE_STAY_LOW) {21if (rssi >= (rssi_thresh + tol))22next_state = COEX_RSSI_STATE_HIGH;23else24next_state = COEX_RSSI_STATE_STAY_LOW;25} else {26if (rssi < rssi_thresh)27next_state = COEX_RSSI_STATE_LOW;28else29next_state = COEX_RSSI_STATE_STAY_HIGH;30}3132return next_state;33}3435static void rtw_coex_limited_tx(struct rtw_dev *rtwdev,36bool tx_limit_en, bool ampdu_limit_en)37{38const struct rtw_chip_info *chip = rtwdev->chip;39struct rtw_coex *coex = &rtwdev->coex;40struct rtw_coex_stat *coex_stat = &coex->stat;41u8 num_of_active_port = 1;4243if (!chip->scbd_support)44return;4546/* force max tx retry limit = 8 */47if (coex_stat->wl_tx_limit_en == tx_limit_en &&48coex_stat->wl_ampdu_limit_en == ampdu_limit_en)49return;5051if (!coex_stat->wl_tx_limit_en) {52coex_stat->darfrc = rtw_read32(rtwdev, REG_DARFRC);53coex_stat->darfrch = rtw_read32(rtwdev, REG_DARFRCH);54coex_stat->retry_limit = rtw_read16(rtwdev, REG_RETRY_LIMIT);55}5657if (!coex_stat->wl_ampdu_limit_en)58coex_stat->ampdu_max_time =59rtw_read8(rtwdev, REG_AMPDU_MAX_TIME_V1);6061coex_stat->wl_tx_limit_en = tx_limit_en;62coex_stat->wl_ampdu_limit_en = ampdu_limit_en;6364if (tx_limit_en) {65/* set BT polluted packet on for tx rate adaptive,66* not including tx retry broken by PTA67*/68rtw_write8_set(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE);6970/* set queue life time to avoid can't reach tx retry limit71* if tx is always broken by GNT_BT72*/73if (num_of_active_port <= 1)74rtw_write8_set(rtwdev, REG_LIFETIME_EN, 0xf);75rtw_write16(rtwdev, REG_RETRY_LIMIT, 0x0808);7677/* auto rate fallback step within 8 retries */78rtw_write32(rtwdev, REG_DARFRC, 0x1000000);79rtw_write32(rtwdev, REG_DARFRCH, 0x4030201);80} else {81rtw_write8_clr(rtwdev, REG_TX_HANG_CTRL, BIT_EN_GNT_BT_AWAKE);82rtw_write8_clr(rtwdev, REG_LIFETIME_EN, 0xf);8384rtw_write16(rtwdev, REG_RETRY_LIMIT, coex_stat->retry_limit);85rtw_write32(rtwdev, REG_DARFRC, coex_stat->darfrc);86rtw_write32(rtwdev, REG_DARFRCH, coex_stat->darfrch);87}8889if (ampdu_limit_en)90rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1, 0x20);91else92rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1,93coex_stat->ampdu_max_time);94}9596static void rtw_coex_limited_wl(struct rtw_dev *rtwdev)97{98struct rtw_coex *coex = &rtwdev->coex;99struct rtw_coex_dm *coex_dm = &coex->dm;100bool tx_limit = false;101bool tx_agg_ctrl = false;102103if (!coex->under_5g && coex_dm->bt_status != COEX_BTSTATUS_NCON_IDLE) {104tx_limit = true;105tx_agg_ctrl = true;106}107108rtw_coex_limited_tx(rtwdev, tx_limit, tx_agg_ctrl);109}110111static bool rtw_coex_freerun_check(struct rtw_dev *rtwdev)112{113struct rtw_coex *coex = &rtwdev->coex;114struct rtw_coex_dm *coex_dm = &coex->dm;115struct rtw_coex_stat *coex_stat = &coex->stat;116struct rtw_efuse *efuse = &rtwdev->efuse;117u8 bt_rssi;118u8 ant_distance = 10;119120if (coex_stat->bt_disabled)121return false;122123if (efuse->share_ant || ant_distance <= 5 || !coex_stat->wl_gl_busy)124return false;125126if (ant_distance >= 40 || coex_stat->bt_hid_pair_num >= 2)127return true;128129/* ant_distance = 5 ~ 40 */130if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]) &&131COEX_RSSI_HIGH(coex_dm->bt_rssi_state[0]))132return true;133134if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)135bt_rssi = coex_dm->bt_rssi_state[0];136else137bt_rssi = coex_dm->bt_rssi_state[1];138139if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&140COEX_RSSI_HIGH(bt_rssi) &&141coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] <= 5)142return true;143144return false;145}146147static void rtw_coex_wl_slot_extend(struct rtw_dev *rtwdev, bool enable)148{149struct rtw_coex *coex = &rtwdev->coex;150struct rtw_coex_stat *coex_stat = &coex->stat;151u8 para[6] = {0};152153para[0] = COEX_H2C69_WL_LEAKAP;154para[1] = PARA1_H2C69_DIS_5MS;155156if (enable)157para[1] = PARA1_H2C69_EN_5MS;158else159coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;160161coex_stat->wl_slot_extend = enable;162rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]);163}164165static void rtw_coex_wl_ccklock_action(struct rtw_dev *rtwdev)166{167struct rtw_coex *coex = &rtwdev->coex;168struct rtw_coex_stat *coex_stat = &coex->stat;169170if (coex->manual_control || coex->stop_dm)171return;172173174if (coex_stat->tdma_timer_base == 3 && coex_stat->wl_slot_extend) {175rtw_dbg(rtwdev, RTW_DBG_COEX,176"[BTCoex], set h2c 0x69 opcode 12 to turn off 5ms WL slot extend!!\n");177rtw_coex_wl_slot_extend(rtwdev, false);178return;179}180181if (coex_stat->wl_slot_extend && coex_stat->wl_force_lps_ctrl &&182!coex_stat->wl_cck_lock_ever) {183if (coex_stat->wl_fw_dbg_info[7] <= 5)184coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND]++;185else186coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] = 0;187188rtw_dbg(rtwdev, RTW_DBG_COEX,189"[BTCoex], 5ms WL slot extend cnt = %d!!\n",190coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND]);191192if (coex_stat->cnt_wl[COEX_CNT_WL_5MS_NOEXTEND] == 7) {193rtw_dbg(rtwdev, RTW_DBG_COEX,194"[BTCoex], set h2c 0x69 opcode 12 to turn off 5ms WL slot extend!!\n");195rtw_coex_wl_slot_extend(rtwdev, false);196}197} else if (!coex_stat->wl_slot_extend && coex_stat->wl_cck_lock) {198rtw_dbg(rtwdev, RTW_DBG_COEX,199"[BTCoex], set h2c 0x69 opcode 12 to turn on 5ms WL slot extend!!\n");200201rtw_coex_wl_slot_extend(rtwdev, true);202}203}204205static void rtw_coex_wl_ccklock_detect(struct rtw_dev *rtwdev)206{207struct rtw_coex *coex = &rtwdev->coex;208struct rtw_coex_stat *coex_stat = &coex->stat;209struct rtw_coex_dm *coex_dm = &coex->dm;210211bool is_cck_lock_rate = false;212213if (coex_stat->wl_coex_mode != COEX_WLINK_2G1PORT &&214coex_stat->wl_coex_mode != COEX_WLINK_2GFREE)215return;216217if (coex_dm->bt_status == COEX_BTSTATUS_INQ_PAGE ||218coex_stat->bt_setup_link) {219coex_stat->wl_cck_lock = false;220coex_stat->wl_cck_lock_pre = false;221return;222}223224if (coex_stat->wl_rx_rate <= COEX_CCK_2 ||225coex_stat->wl_rts_rx_rate <= COEX_CCK_2)226is_cck_lock_rate = true;227228if (coex_stat->wl_connected && coex_stat->wl_gl_busy &&229COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&230(coex_dm->bt_status == COEX_BTSTATUS_ACL_BUSY ||231coex_dm->bt_status == COEX_BTSTATUS_ACL_SCO_BUSY ||232coex_dm->bt_status == COEX_BTSTATUS_SCO_BUSY)) {233if (is_cck_lock_rate) {234coex_stat->wl_cck_lock = true;235236rtw_dbg(rtwdev, RTW_DBG_COEX,237"[BTCoex], cck locking...\n");238239} else {240coex_stat->wl_cck_lock = false;241242rtw_dbg(rtwdev, RTW_DBG_COEX,243"[BTCoex], cck unlock...\n");244}245} else {246coex_stat->wl_cck_lock = false;247}248249/* CCK lock identification */250if (coex_stat->wl_cck_lock && !coex_stat->wl_cck_lock_pre)251ieee80211_queue_delayed_work(rtwdev->hw, &coex->wl_ccklock_work,2523 * HZ);253254coex_stat->wl_cck_lock_pre = coex_stat->wl_cck_lock;255}256257static void rtw_coex_wl_noisy_detect(struct rtw_dev *rtwdev)258{259struct rtw_coex *coex = &rtwdev->coex;260struct rtw_coex_stat *coex_stat = &coex->stat;261struct rtw_dm_info *dm_info = &rtwdev->dm_info;262u32 cnt_cck;263bool wl_cck_lock = false;264265/* wifi noisy environment identification */266cnt_cck = dm_info->cck_ok_cnt + dm_info->cck_err_cnt;267268if (!coex_stat->wl_gl_busy && !wl_cck_lock) {269if (cnt_cck > 250) {270if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] < 5)271coex_stat->cnt_wl[COEX_CNT_WL_NOISY2]++;272273if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5) {274coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0;275coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0;276}277} else if (cnt_cck < 100) {278if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] < 5)279coex_stat->cnt_wl[COEX_CNT_WL_NOISY0]++;280281if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] == 5) {282coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] = 0;283coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0;284}285} else {286if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] < 5)287coex_stat->cnt_wl[COEX_CNT_WL_NOISY1]++;288289if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5) {290coex_stat->cnt_wl[COEX_CNT_WL_NOISY0] = 0;291coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] = 0;292}293}294295if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY2] == 5)296coex_stat->wl_noisy_level = 2;297else if (coex_stat->cnt_wl[COEX_CNT_WL_NOISY1] == 5)298coex_stat->wl_noisy_level = 1;299else300coex_stat->wl_noisy_level = 0;301302rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], wl_noisy_level = %d\n",303coex_stat->wl_noisy_level);304}305}306307static void rtw_coex_tdma_timer_base(struct rtw_dev *rtwdev, u8 type)308{309struct rtw_coex *coex = &rtwdev->coex;310struct rtw_coex_stat *coex_stat = &coex->stat;311u8 para[6] = {};312u8 times;313u16 tbtt_interval = coex_stat->wl_beacon_interval;314315if (coex_stat->tdma_timer_base == type)316return;317318coex_stat->tdma_timer_base = type;319320para[0] = COEX_H2C69_TDMA_SLOT;321322rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], tbtt_interval = %d\n",323tbtt_interval);324325if (type == TDMA_TIMER_TYPE_4SLOT && tbtt_interval < 120) {326para[1] = PARA1_H2C69_TDMA_4SLOT; /* 4-slot */327} else if (tbtt_interval < 80 && tbtt_interval > 0) {328times = 100 / tbtt_interval;329if (100 % tbtt_interval != 0)330times++;331332para[1] = FIELD_PREP(PARA1_H2C69_TBTT_TIMES, times);333} else if (tbtt_interval >= 180) {334times = tbtt_interval / 100;335if (tbtt_interval % 100 <= 80)336times--;337338para[1] = FIELD_PREP(PARA1_H2C69_TBTT_TIMES, times) |339FIELD_PREP(PARA1_H2C69_TBTT_DIV100, 1);340} else {341para[1] = PARA1_H2C69_TDMA_2SLOT;342}343344rtw_fw_bt_wifi_control(rtwdev, para[0], ¶[1]);345346rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): h2c_0x69 = 0x%x\n",347__func__, para[1]);348349/* no 5ms_wl_slot_extend for 4-slot mode */350if (coex_stat->tdma_timer_base == 3)351rtw_coex_wl_ccklock_action(rtwdev);352}353354static void rtw_coex_set_wl_pri_mask(struct rtw_dev *rtwdev, u8 bitmap,355u8 data)356{357u32 addr;358359addr = REG_BT_COEX_TABLE_H + (bitmap / 8);360bitmap = bitmap % 8;361362rtw_write8_mask(rtwdev, addr, BIT(bitmap), data);363}364365void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set)366{367const struct rtw_chip_info *chip = rtwdev->chip;368struct rtw_coex *coex = &rtwdev->coex;369struct rtw_coex_stat *coex_stat = &coex->stat;370u16 val = 0x2;371372if (!chip->scbd_support)373return;374375val |= coex_stat->score_board;376377/* for 8822b, scbd[10] is CQDDR on378* for 8822c, scbd[10] is no fix 2M379*/380if (!chip->new_scbd10_def && (bitpos & COEX_SCBD_FIX2M)) {381if (set)382val &= ~COEX_SCBD_FIX2M;383else384val |= COEX_SCBD_FIX2M;385} else {386if (set)387val |= bitpos;388else389val &= ~bitpos;390}391392if (val != coex_stat->score_board) {393coex_stat->score_board = val;394val |= BIT_BT_INT_EN;395rtw_write16(rtwdev, REG_WIFI_BT_INFO, val);396}397}398EXPORT_SYMBOL(rtw_coex_write_scbd);399400static u16 rtw_coex_read_scbd(struct rtw_dev *rtwdev)401{402const struct rtw_chip_info *chip = rtwdev->chip;403404if (!chip->scbd_support)405return 0;406407return (rtw_read16(rtwdev, REG_WIFI_BT_INFO)) & ~(BIT_BT_INT_EN);408}409410static void rtw_coex_check_rfk(struct rtw_dev *rtwdev)411{412const struct rtw_chip_info *chip = rtwdev->chip;413struct rtw_coex *coex = &rtwdev->coex;414struct rtw_coex_stat *coex_stat = &coex->stat;415struct rtw_coex_rfe *coex_rfe = &coex->rfe;416u8 cnt = 0;417u32 wait_cnt;418bool btk, wlk;419420if (coex_rfe->wlg_at_btg && chip->scbd_support &&421coex_stat->bt_iqk_state != 0xff) {422rtw_dbg(rtwdev, RTW_DBG_COEX,423"[BTCoex], (Before Ant Setup) Delay by IQK\n");424425wait_cnt = COEX_RFK_TIMEOUT / COEX_MIN_DELAY;426do {427/* BT RFK */428btk = !!(rtw_coex_read_scbd(rtwdev) & COEX_SCBD_BT_RFK);429430/* WL RFK */431wlk = !!(rtw_read8(rtwdev, REG_ARFR4) & BIT_WL_RFK);432433if (!btk && !wlk)434break;435436rtw_dbg(rtwdev, RTW_DBG_COEX,437"[BTCoex], (Before Ant Setup) wlk = %d, btk = %d\n",438wlk, btk);439440mdelay(COEX_MIN_DELAY);441} while (++cnt < wait_cnt);442443if (cnt >= wait_cnt)444coex_stat->bt_iqk_state = 0xff;445}446}447448void rtw_coex_query_bt_info(struct rtw_dev *rtwdev)449{450struct rtw_coex *coex = &rtwdev->coex;451struct rtw_coex_stat *coex_stat = &coex->stat;452453if (coex_stat->bt_disabled)454return;455456rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);457458rtw_fw_query_bt_info(rtwdev);459}460461static void rtw_coex_gnt_workaround(struct rtw_dev *rtwdev, bool force, u8 mode)462{463rtw_coex_set_gnt_fix(rtwdev);464}465466static void rtw_coex_monitor_bt_ctr(struct rtw_dev *rtwdev)467{468struct rtw_coex *coex = &rtwdev->coex;469struct rtw_coex_stat *coex_stat = &coex->stat;470u32 tmp;471472tmp = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS);473coex_stat->hi_pri_tx = FIELD_GET(MASKLWORD, tmp);474coex_stat->hi_pri_rx = FIELD_GET(MASKHWORD, tmp);475476tmp = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS_1);477coex_stat->lo_pri_tx = FIELD_GET(MASKLWORD, tmp);478coex_stat->lo_pri_rx = FIELD_GET(MASKHWORD, tmp);479480rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL,481BIT_R_GRANTALL_WLMASK | BIT_STATIS_BT_EN);482483rtw_dbg(rtwdev, RTW_DBG_COEX,484"[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n",485coex_stat->hi_pri_rx, coex_stat->hi_pri_tx,486coex_stat->lo_pri_rx, coex_stat->lo_pri_tx);487}488489static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev)490{491const struct rtw_chip_info *chip = rtwdev->chip;492struct rtw_coex *coex = &rtwdev->coex;493struct rtw_coex_stat *coex_stat = &coex->stat;494struct rtw_coex_dm *coex_dm = &coex->dm;495bool bt_disabled = false;496bool bt_active = true;497u16 score_board;498499if (chip->scbd_support) {500score_board = rtw_coex_read_scbd(rtwdev);501bt_disabled = !(score_board & COEX_SCBD_ONOFF);502} else {503if (coex_stat->hi_pri_tx == 0 && coex_stat->hi_pri_rx == 0 &&504coex_stat->lo_pri_tx == 0 && coex_stat->lo_pri_rx == 0)505bt_active = false;506507if (coex_stat->hi_pri_tx == 0xffff && coex_stat->hi_pri_rx == 0xffff &&508coex_stat->lo_pri_tx == 0xffff && coex_stat->lo_pri_rx == 0xffff)509bt_active = false;510511if (bt_active) {512coex_stat->bt_disable_cnt = 0;513bt_disabled = false;514} else {515coex_stat->bt_disable_cnt++;516if (coex_stat->bt_disable_cnt >= 10)517bt_disabled = true;518}519}520521if (coex_stat->bt_disabled != bt_disabled) {522rtw_dbg(rtwdev, RTW_DBG_COEX,523"[BTCoex], BT state changed (%d) -> (%d)\n",524coex_stat->bt_disabled, bt_disabled);525526coex_stat->bt_disabled = bt_disabled;527coex_stat->bt_ble_scan_type = 0;528coex_dm->cur_bt_lna_lvl = 0;529530if (!coex_stat->bt_disabled) {531coex_stat->bt_reenable = true;532ieee80211_queue_delayed_work(rtwdev->hw,533&coex->bt_reenable_work,53415 * HZ);535} else {536coex_stat->bt_mailbox_reply = false;537coex_stat->bt_reenable = false;538}539}540}541542static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason)543{544const struct rtw_chip_info *chip = rtwdev->chip;545struct rtw_coex *coex = &rtwdev->coex;546struct rtw_coex_stat *coex_stat = &coex->stat;547struct rtw_coex_dm *coex_dm = &coex->dm;548struct rtw_traffic_stats *stats = &rtwdev->stats;549bool is_5G = false;550bool wl_busy = false;551bool scan = false, link = false;552int i;553u8 rssi_state;554u8 rssi_step;555u8 rssi;556557scan = test_bit(RTW_FLAG_SCANNING, rtwdev->flags);558coex_stat->wl_connected = !!rtwdev->sta_cnt;559560wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);561if (wl_busy != coex_stat->wl_gl_busy) {562if (wl_busy)563coex_stat->wl_gl_busy = true;564else565ieee80211_queue_delayed_work(rtwdev->hw,566&coex->wl_remain_work,56712 * HZ);568}569570if (stats->tx_throughput > stats->rx_throughput)571coex_stat->wl_tput_dir = COEX_WL_TPUT_TX;572else573coex_stat->wl_tput_dir = COEX_WL_TPUT_RX;574575if (scan || link || reason == COEX_RSN_2GCONSTART ||576reason == COEX_RSN_2GSCANSTART || reason == COEX_RSN_2GSWITCHBAND)577coex_stat->wl_linkscan_proc = true;578else579coex_stat->wl_linkscan_proc = false;580581rtw_coex_wl_noisy_detect(rtwdev);582583for (i = 0; i < 4; i++) {584rssi_state = coex_dm->wl_rssi_state[i];585rssi_step = chip->wl_rssi_step[i];586rssi = rtwdev->dm_info.min_rssi;587rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state,588rssi, rssi_step);589coex_dm->wl_rssi_state[i] = rssi_state;590}591592if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 ||593coex_stat->wl_hi_pri_task2 || coex_stat->wl_gl_busy)594rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, true);595else596rtw_coex_write_scbd(rtwdev, COEX_SCBD_SCAN, false);597598switch (reason) {599case COEX_RSN_5GSCANSTART:600case COEX_RSN_5GSWITCHBAND:601case COEX_RSN_5GCONSTART:602603is_5G = true;604break;605case COEX_RSN_2GSCANSTART:606case COEX_RSN_2GSWITCHBAND:607case COEX_RSN_2GCONSTART:608609is_5G = false;610break;611default:612if (rtwdev->hal.current_band_type == RTW_BAND_5G)613is_5G = true;614else615is_5G = false;616break;617}618619coex->under_5g = is_5G;620}621622static inline u8 *get_payload_from_coex_resp(struct sk_buff *resp)623{624struct rtw_c2h_cmd *c2h;625u32 pkt_offset;626627pkt_offset = *((u32 *)resp->cb);628c2h = (struct rtw_c2h_cmd *)(resp->data + pkt_offset);629630return c2h->payload;631}632633void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb)634{635struct rtw_coex *coex = &rtwdev->coex;636u8 *payload = get_payload_from_coex_resp(skb);637638if (payload[0] != COEX_RESP_ACK_BY_WL_FW) {639dev_kfree_skb_any(skb);640return;641}642643skb_queue_tail(&coex->queue, skb);644wake_up(&coex->wait);645}646647static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev,648struct rtw_coex_info_req *req)649{650struct rtw_coex *coex = &rtwdev->coex;651struct sk_buff *skb_resp = NULL;652653lockdep_assert_held(&rtwdev->mutex);654655rtw_fw_query_bt_mp_info(rtwdev, req);656657if (!wait_event_timeout(coex->wait, !skb_queue_empty(&coex->queue),658COEX_REQUEST_TIMEOUT)) {659rtw_err(rtwdev, "coex request time out\n");660goto out;661}662663skb_resp = skb_dequeue(&coex->queue);664if (!skb_resp) {665rtw_err(rtwdev, "failed to get coex info response\n");666goto out;667}668669out:670return skb_resp;671}672673static bool rtw_coex_get_bt_scan_type(struct rtw_dev *rtwdev, u8 *scan_type)674{675struct rtw_coex_info_req req = {0};676struct sk_buff *skb;677u8 *payload;678679req.op_code = BT_MP_INFO_OP_SCAN_TYPE;680skb = rtw_coex_info_request(rtwdev, &req);681if (!skb)682return false;683684payload = get_payload_from_coex_resp(skb);685*scan_type = GET_COEX_RESP_BT_SCAN_TYPE(payload);686dev_kfree_skb_any(skb);687return true;688}689690static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev,691u8 lna_constrain_level)692{693struct rtw_coex_info_req req = {0};694struct sk_buff *skb;695696req.op_code = BT_MP_INFO_OP_LNA_CONSTRAINT;697req.para1 = lna_constrain_level;698skb = rtw_coex_info_request(rtwdev, &req);699if (!skb)700return false;701702dev_kfree_skb_any(skb);703return true;704}705706#define case_BTSTATUS(src) \707case COEX_BTSTATUS_##src: return #src708709static const char *rtw_coex_get_bt_status_string(u8 bt_status)710{711switch (bt_status) {712case_BTSTATUS(NCON_IDLE);713case_BTSTATUS(CON_IDLE);714case_BTSTATUS(INQ_PAGE);715case_BTSTATUS(ACL_BUSY);716case_BTSTATUS(SCO_BUSY);717case_BTSTATUS(ACL_SCO_BUSY);718default:719return "Unknown";720}721}722723static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)724{725const struct rtw_chip_info *chip = rtwdev->chip;726struct rtw_coex *coex = &rtwdev->coex;727struct rtw_coex_stat *coex_stat = &coex->stat;728struct rtw_coex_dm *coex_dm = &coex->dm;729u8 i;730u8 rssi_state;731u8 rssi_step;732u8 rssi;733734/* update wl/bt rssi by btinfo */735for (i = 0; i < COEX_RSSI_STEP; i++) {736rssi_state = coex_dm->bt_rssi_state[i];737rssi_step = chip->bt_rssi_step[i];738rssi = coex_stat->bt_rssi;739rssi_state = rtw_coex_next_rssi_state(rtwdev, rssi_state, rssi,740rssi_step);741coex_dm->bt_rssi_state[i] = rssi_state;742}743744if (coex_stat->bt_ble_scan_en &&745coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE] % 3 == 0) {746u8 scan_type;747748if (rtw_coex_get_bt_scan_type(rtwdev, &scan_type)) {749coex_stat->bt_ble_scan_type = scan_type;750if ((coex_stat->bt_ble_scan_type & 0x1) == 0x1)751coex_stat->bt_init_scan = true;752else753coex_stat->bt_init_scan = false;754}755}756757coex_stat->bt_profile_num = 0;758759/* set link exist status */760if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) {761coex_stat->bt_link_exist = false;762coex_stat->bt_pan_exist = false;763coex_stat->bt_a2dp_exist = false;764coex_stat->bt_hid_exist = false;765coex_stat->bt_hfp_exist = false;766} else {767/* connection exists */768coex_stat->bt_link_exist = true;769if (coex_stat->bt_info_lb2 & COEX_INFO_FTP) {770coex_stat->bt_pan_exist = true;771coex_stat->bt_profile_num++;772} else {773coex_stat->bt_pan_exist = false;774}775776if (coex_stat->bt_info_lb2 & COEX_INFO_A2DP) {777coex_stat->bt_a2dp_exist = true;778coex_stat->bt_profile_num++;779} else {780coex_stat->bt_a2dp_exist = false;781}782783if (coex_stat->bt_info_lb2 & COEX_INFO_HID) {784coex_stat->bt_hid_exist = true;785coex_stat->bt_profile_num++;786} else {787coex_stat->bt_hid_exist = false;788}789790if (coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) {791coex_stat->bt_hfp_exist = true;792coex_stat->bt_profile_num++;793} else {794coex_stat->bt_hfp_exist = false;795}796}797798if (coex_stat->bt_info_lb2 & COEX_INFO_INQ_PAGE) {799coex_dm->bt_status = COEX_BTSTATUS_INQ_PAGE;800} else if (!(coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION)) {801coex_dm->bt_status = COEX_BTSTATUS_NCON_IDLE;802coex_stat->bt_multi_link_remain = false;803} else if (coex_stat->bt_info_lb2 == COEX_INFO_CONNECTION) {804coex_dm->bt_status = COEX_BTSTATUS_CON_IDLE;805} else if ((coex_stat->bt_info_lb2 & COEX_INFO_SCO_ESCO) ||806(coex_stat->bt_info_lb2 & COEX_INFO_SCO_BUSY)) {807if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY)808coex_dm->bt_status = COEX_BTSTATUS_ACL_SCO_BUSY;809else810coex_dm->bt_status = COEX_BTSTATUS_SCO_BUSY;811} else if (coex_stat->bt_info_lb2 & COEX_INFO_ACL_BUSY) {812coex_dm->bt_status = COEX_BTSTATUS_ACL_BUSY;813} else {814coex_dm->bt_status = COEX_BTSTATUS_MAX;815}816817coex_stat->cnt_bt[COEX_CNT_BT_INFOUPDATE]++;818819rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(), %s!!!\n", __func__,820rtw_coex_get_bt_status_string(coex_dm->bt_status));821}822823static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)824{825const struct rtw_chip_info *chip = rtwdev->chip;826struct rtw_efuse *efuse = &rtwdev->efuse;827struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm;828struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;829u8 link = 0;830u8 center_chan = 0;831u8 bw;832int i;833834bw = rtwdev->hal.current_band_width;835836if (type != COEX_MEDIA_DISCONNECT)837center_chan = rtwdev->hal.current_channel;838839if (center_chan == 0 ||840(efuse->share_ant && center_chan <= 14 &&841coex_stat->wl_coex_mode != COEX_WLINK_2GFREE)) {842link = 0;843center_chan = 0;844bw = 0;845} else if (center_chan <= 14) {846link = 0x1;847848if (bw == RTW_CHANNEL_WIDTH_40)849bw = chip->bt_afh_span_bw40;850else851bw = chip->bt_afh_span_bw20;852} else if (chip->afh_5g_num > 1) {853for (i = 0; i < chip->afh_5g_num; i++) {854if (center_chan == chip->afh_5g[i].wl_5g_ch) {855link = 0x3;856center_chan = chip->afh_5g[i].bt_skip_ch;857bw = chip->afh_5g[i].bt_skip_span;858break;859}860}861}862863coex_dm->wl_ch_info[0] = link;864coex_dm->wl_ch_info[1] = center_chan;865coex_dm->wl_ch_info[2] = bw;866867rtw_fw_wl_ch_info(rtwdev, link, center_chan, bw);868rtw_dbg(rtwdev, RTW_DBG_COEX,869"[BTCoex], %s: para[0:2] = 0x%x 0x%x 0x%x\n", __func__, link,870center_chan, bw);871}872873static void rtw_coex_set_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl)874{875struct rtw_coex *coex = &rtwdev->coex;876struct rtw_coex_dm *coex_dm = &coex->dm;877878if (bt_pwr_dec_lvl == coex_dm->cur_bt_pwr_lvl)879return;880881coex_dm->cur_bt_pwr_lvl = bt_pwr_dec_lvl;882883rtw_fw_force_bt_tx_power(rtwdev, bt_pwr_dec_lvl);884}885886static void rtw_coex_set_bt_rx_gain(struct rtw_dev *rtwdev, u8 bt_lna_lvl)887{888struct rtw_coex *coex = &rtwdev->coex;889struct rtw_coex_dm *coex_dm = &coex->dm;890891if (bt_lna_lvl == coex_dm->cur_bt_lna_lvl)892return;893894coex_dm->cur_bt_lna_lvl = bt_lna_lvl;895896/* notify BT rx gain table changed */897if (bt_lna_lvl < 7) {898rtw_coex_set_lna_constrain_level(rtwdev, bt_lna_lvl);899rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, true);900} else {901rtw_coex_write_scbd(rtwdev, COEX_SCBD_RXGAIN, false);902}903rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): bt_rx_LNA_level = %d\n",904__func__, bt_lna_lvl);905}906907static void rtw_coex_set_rf_para(struct rtw_dev *rtwdev,908struct coex_rf_para para)909{910struct rtw_coex *coex = &rtwdev->coex;911struct rtw_coex_stat *coex_stat = &coex->stat;912u8 offset = 0;913914if (coex->freerun && coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] <= 5)915offset = 3;916917rtw_coex_set_wl_tx_power(rtwdev, para.wl_pwr_dec_lvl);918rtw_coex_set_bt_tx_power(rtwdev, para.bt_pwr_dec_lvl + offset);919rtw_coex_set_wl_rx_gain(rtwdev, para.wl_low_gain_en);920rtw_coex_set_bt_rx_gain(rtwdev, para.bt_lna_lvl);921}922923u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr)924{925u32 val;926927if (!ltecoex_read_reg(rtwdev, addr, &val)) {928rtw_err(rtwdev, "failed to read indirect register\n");929return 0;930}931932return val;933}934EXPORT_SYMBOL(rtw_coex_read_indirect_reg);935936void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr,937u32 mask, u32 val)938{939u32 shift = __ffs(mask);940u32 tmp;941942tmp = rtw_coex_read_indirect_reg(rtwdev, addr);943tmp = (tmp & (~mask)) | ((val << shift) & mask);944945if (!ltecoex_reg_write(rtwdev, addr, tmp))946rtw_err(rtwdev, "failed to write indirect register\n");947}948EXPORT_SYMBOL(rtw_coex_write_indirect_reg);949950static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control)951{952const struct rtw_chip_info *chip = rtwdev->chip;953const struct rtw_hw_reg *btg_reg = chip->btg_reg;954955if (wifi_control) {956rtw_write8_set(rtwdev, REG_SYS_SDIO_CTRL + 3,957BIT_LTE_MUX_CTRL_PATH >> 24);958if (btg_reg)959rtw_write8_set(rtwdev, btg_reg->addr, btg_reg->mask);960} else {961rtw_write8_clr(rtwdev, REG_SYS_SDIO_CTRL + 3,962BIT_LTE_MUX_CTRL_PATH >> 24);963if (btg_reg)964rtw_write8_clr(rtwdev, btg_reg->addr, btg_reg->mask);965}966}967968static void rtw_coex_set_gnt_bt(struct rtw_dev *rtwdev, u8 state)969{970if (!rtwdev->chip->ltecoex_addr)971return;972973rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0xc000, state);974rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0c00, state);975}976977static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state)978{979if (!rtwdev->chip->ltecoex_addr)980return;981982rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x3000, state);983rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0300, state);984}985986static void rtw_coex_mimo_ps(struct rtw_dev *rtwdev, bool force, bool state)987{988struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;989990if (!force && state == coex_stat->wl_mimo_ps)991return;992993coex_stat->wl_mimo_ps = state;994995rtw_set_txrx_1ss(rtwdev, state);996997rtw_coex_update_wl_ch_info(rtwdev, (u8)coex_stat->wl_connected);998999rtw_dbg(rtwdev, RTW_DBG_COEX,1000"[BTCoex], %s(): state = %d\n", __func__, state);1001}10021003static void rtw_btc_wltoggle_table_a(struct rtw_dev *rtwdev, bool force,1004u8 table_case)1005{1006const struct rtw_chip_info *chip = rtwdev->chip;1007struct rtw_efuse *efuse = &rtwdev->efuse;1008u8 h2c_para[6] = {0};1009u32 table_wl = 0x5a5a5a5a;10101011h2c_para[0] = COEX_H2C69_TOGGLE_TABLE_A;1012/* no definition */1013h2c_para[1] = 0x1;10141015if (efuse->share_ant) {1016if (table_case < chip->table_sant_num)1017table_wl = chip->table_sant[table_case].wl;1018} else {1019if (table_case < chip->table_nsant_num)1020table_wl = chip->table_nsant[table_case].wl;1021}10221023/* tell WL FW WL slot toggle table-A*/1024h2c_para[2] = (u8)u32_get_bits(table_wl, GENMASK(7, 0));1025h2c_para[3] = (u8)u32_get_bits(table_wl, GENMASK(15, 8));1026h2c_para[4] = (u8)u32_get_bits(table_wl, GENMASK(23, 16));1027h2c_para[5] = (u8)u32_get_bits(table_wl, GENMASK(31, 24));10281029rtw_fw_bt_wifi_control(rtwdev, h2c_para[0], &h2c_para[1]);10301031rtw_dbg(rtwdev, RTW_DBG_COEX,1032"[BTCoex], %s(): H2C = [%02x %02x %02x %02x %02x %02x]\n",1033__func__, h2c_para[0], h2c_para[1], h2c_para[2],1034h2c_para[3], h2c_para[4], h2c_para[5]);1035}10361037#define COEX_WL_SLOT_TOGLLE 0x5a5a5aaa1038static void rtw_btc_wltoggle_table_b(struct rtw_dev *rtwdev, bool force,1039u8 interval, u32 table)1040{1041struct rtw_coex *coex = &rtwdev->coex;1042struct rtw_coex_stat *coex_stat = &coex->stat;1043u8 cur_h2c_para[6] = {0};1044u8 i;10451046cur_h2c_para[0] = COEX_H2C69_TOGGLE_TABLE_B;1047cur_h2c_para[1] = interval;1048cur_h2c_para[2] = (u8)u32_get_bits(table, GENMASK(7, 0));1049cur_h2c_para[3] = (u8)u32_get_bits(table, GENMASK(15, 8));1050cur_h2c_para[4] = (u8)u32_get_bits(table, GENMASK(23, 16));1051cur_h2c_para[5] = (u8)u32_get_bits(table, GENMASK(31, 24));10521053coex_stat->wl_toggle_interval = interval;10541055for (i = 0; i <= 5; i++)1056coex_stat->wl_toggle_para[i] = cur_h2c_para[i];10571058rtw_fw_bt_wifi_control(rtwdev, cur_h2c_para[0], &cur_h2c_para[1]);10591060rtw_dbg(rtwdev, RTW_DBG_COEX,1061"[BTCoex], %s(): H2C = [%02x %02x %02x %02x %02x %02x]\n",1062__func__, cur_h2c_para[0], cur_h2c_para[1], cur_h2c_para[2],1063cur_h2c_para[3], cur_h2c_para[4], cur_h2c_para[5]);1064}10651066static void rtw_coex_set_table(struct rtw_dev *rtwdev, bool force, u32 table0,1067u32 table1)1068{1069#define DEF_BRK_TABLE_VAL 0xf0ffffff1070struct rtw_coex *coex = &rtwdev->coex;1071struct rtw_coex_dm *coex_dm = &coex->dm;10721073/* If last tdma is wl slot toggle, force write table*/1074if (!force && coex_dm->reason != COEX_RSN_LPS) {1075if (table0 == rtw_read32(rtwdev, REG_BT_COEX_TABLE0) &&1076table1 == rtw_read32(rtwdev, REG_BT_COEX_TABLE1))1077return;1078}1079rtw_write32(rtwdev, REG_BT_COEX_TABLE0, table0);1080rtw_write32(rtwdev, REG_BT_COEX_TABLE1, table1);1081rtw_write32(rtwdev, REG_BT_COEX_BRK_TABLE, DEF_BRK_TABLE_VAL);10821083rtw_dbg(rtwdev, RTW_DBG_COEX,1084"[BTCoex], %s(): 0x6c0 = %x, 0x6c4 = %x\n", __func__, table0,1085table1);1086}10871088static void rtw_coex_table(struct rtw_dev *rtwdev, bool force, u8 type)1089{1090const struct rtw_chip_info *chip = rtwdev->chip;1091struct rtw_coex *coex = &rtwdev->coex;1092struct rtw_coex_dm *coex_dm = &coex->dm;1093struct rtw_efuse *efuse = &rtwdev->efuse;1094struct rtw_coex_stat *coex_stat = &coex->stat;10951096coex_dm->cur_table = type;10971098rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], Coex_Table - %d\n", type);10991100if (efuse->share_ant) {1101if (type < chip->table_sant_num)1102rtw_coex_set_table(rtwdev, force,1103chip->table_sant[type].bt,1104chip->table_sant[type].wl);1105} else {1106type = type - 100;1107if (type < chip->table_nsant_num)1108rtw_coex_set_table(rtwdev, force,1109chip->table_nsant[type].bt,1110chip->table_nsant[type].wl);1111}1112if (coex_stat->wl_slot_toggle_change)1113rtw_btc_wltoggle_table_a(rtwdev, true, type);1114}11151116static void rtw_coex_ignore_wlan_act(struct rtw_dev *rtwdev, bool enable)1117{1118struct rtw_coex *coex = &rtwdev->coex;11191120if (coex->manual_control || coex->stop_dm)1121return;11221123rtw_fw_bt_ignore_wlan_action(rtwdev, enable);1124}11251126static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type,1127u8 lps_val, u8 rpwm_val)1128{1129struct rtw_coex *coex = &rtwdev->coex;1130struct rtw_coex_stat *coex_stat = &coex->stat;1131u8 lps_mode = 0x0;11321133lps_mode = rtwdev->lps_conf.mode;11341135switch (ps_type) {1136case COEX_PS_WIFI_NATIVE:1137/* recover to original 32k low power setting */1138coex_stat->wl_force_lps_ctrl = false;1139rtw_dbg(rtwdev, RTW_DBG_COEX,1140"[BTCoex], %s(): COEX_PS_WIFI_NATIVE\n", __func__);1141rtw_leave_lps(rtwdev);1142break;1143case COEX_PS_LPS_OFF:1144coex_stat->wl_force_lps_ctrl = true;1145if (lps_mode)1146rtw_fw_coex_tdma_type(rtwdev, 0, 0, 0, 0, 0);11471148rtw_leave_lps(rtwdev);1149rtw_dbg(rtwdev, RTW_DBG_COEX,1150"[BTCoex], %s(): COEX_PS_LPS_OFF\n", __func__);1151break;1152default:1153break;1154}1155}11561157static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,1158u8 byte3, u8 byte4, u8 byte5)1159{1160const struct rtw_chip_info *chip = rtwdev->chip;1161struct rtw_coex *coex = &rtwdev->coex;1162struct rtw_coex_dm *coex_dm = &coex->dm;1163struct rtw_coex_stat *coex_stat = &coex->stat;1164u8 ps_type = COEX_PS_WIFI_NATIVE;1165bool ap_enable = false;11661167if (ap_enable && (byte1 & BIT(4) && !(byte1 & BIT(5)))) {1168rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): AP mode\n",1169__func__);11701171byte1 &= ~BIT(4);1172byte1 |= BIT(5);11731174byte5 |= BIT(5);1175byte5 &= ~BIT(6);11761177ps_type = COEX_PS_WIFI_NATIVE;1178rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);1179} else if ((byte1 & BIT(4) && !(byte1 & BIT(5))) ||1180coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {1181rtw_dbg(rtwdev, RTW_DBG_COEX,1182"[BTCoex], %s(): Force LPS (byte1 = 0x%x)\n", __func__,1183byte1);11841185if (chip->pstdma_type == COEX_PSTDMA_FORCE_LPSOFF)1186ps_type = COEX_PS_LPS_OFF;1187else1188ps_type = COEX_PS_LPS_ON;1189rtw_coex_power_save_state(rtwdev, ps_type, 0x50, 0x4);1190} else {1191rtw_dbg(rtwdev, RTW_DBG_COEX,1192"[BTCoex], %s(): native power save (byte1 = 0x%x)\n",1193__func__, byte1);11941195ps_type = COEX_PS_WIFI_NATIVE;1196rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);1197}11981199coex_dm->ps_tdma_para[0] = byte1;1200coex_dm->ps_tdma_para[1] = byte2;1201coex_dm->ps_tdma_para[2] = byte3;1202coex_dm->ps_tdma_para[3] = byte4;1203coex_dm->ps_tdma_para[4] = byte5;12041205rtw_fw_coex_tdma_type(rtwdev, byte1, byte2, byte3, byte4, byte5);12061207if (byte1 & BIT(2)) {1208coex_stat->wl_slot_toggle = true;1209coex_stat->wl_slot_toggle_change = false;1210} else {1211coex_stat->wl_slot_toggle_change = coex_stat->wl_slot_toggle;1212coex_stat->wl_slot_toggle = false;1213}1214}12151216static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase)1217{1218const struct rtw_chip_info *chip = rtwdev->chip;1219struct rtw_coex *coex = &rtwdev->coex;1220struct rtw_coex_dm *coex_dm = &coex->dm;1221struct rtw_coex_stat *coex_stat = &coex->stat;1222struct rtw_efuse *efuse = &rtwdev->efuse;1223u8 n, type;1224bool turn_on;1225bool wl_busy = false;12261227if (tcase & TDMA_4SLOT) /* 4-slot (50ms) mode */1228rtw_coex_tdma_timer_base(rtwdev, TDMA_TIMER_TYPE_4SLOT);1229else1230rtw_coex_tdma_timer_base(rtwdev, TDMA_TIMER_TYPE_2SLOT);12311232type = (u8)(tcase & 0xff);12331234turn_on = (type == 0 || type == 100) ? false : true;12351236if (!force && turn_on == coex_dm->cur_ps_tdma_on &&1237type == coex_dm->cur_ps_tdma) {1238rtw_dbg(rtwdev, RTW_DBG_COEX,1239"[BTCoex], Skip TDMA because no change TDMA(%s, %d)\n",1240(coex_dm->cur_ps_tdma_on ? "on" : "off"),1241coex_dm->cur_ps_tdma);12421243return;1244}1245wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);12461247if ((coex_stat->bt_a2dp_exist &&1248(coex_stat->bt_inq_remain || coex_stat->bt_multi_link)) ||1249!wl_busy)1250rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, false);1251else1252rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, true);12531254/* update pre state */1255coex_dm->cur_ps_tdma_on = turn_on;1256coex_dm->cur_ps_tdma = type;12571258if (efuse->share_ant) {1259if (type < chip->tdma_sant_num)1260rtw_coex_set_tdma(rtwdev,1261chip->tdma_sant[type].para[0],1262chip->tdma_sant[type].para[1],1263chip->tdma_sant[type].para[2],1264chip->tdma_sant[type].para[3],1265chip->tdma_sant[type].para[4]);1266} else {1267n = type - 100;1268if (n < chip->tdma_nsant_num)1269rtw_coex_set_tdma(rtwdev,1270chip->tdma_nsant[n].para[0],1271chip->tdma_nsant[n].para[1],1272chip->tdma_nsant[n].para[2],1273chip->tdma_nsant[n].para[3],1274chip->tdma_nsant[n].para[4]);1275}127612771278rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], coex tdma type(%s, %d)\n",1279turn_on ? "on" : "off", type);1280}12811282static void rtw_coex_set_ant_path(struct rtw_dev *rtwdev, bool force, u8 phase)1283{1284struct rtw_coex *coex = &rtwdev->coex;1285struct rtw_coex_stat *coex_stat = &coex->stat;1286struct rtw_coex_rfe *coex_rfe = &coex->rfe;1287struct rtw_coex_dm *coex_dm = &coex->dm;1288u8 ctrl_type = COEX_SWITCH_CTRL_MAX;1289u8 pos_type = COEX_SWITCH_TO_MAX;12901291if (!force && coex_dm->cur_ant_pos_type == phase)1292return;12931294coex_dm->cur_ant_pos_type = phase;12951296/* avoid switch coex_ctrl_owner during BT IQK */1297rtw_coex_check_rfk(rtwdev);12981299rtw_dbg(rtwdev, RTW_DBG_COEX,1300"[BTCoex], coex_stat->bt_disabled = 0x%x\n",1301coex_stat->bt_disabled);13021303switch (phase) {1304case COEX_SET_ANT_POWERON:1305rtw_dbg(rtwdev, RTW_DBG_COEX,1306"[BTCoex], %s() - PHASE_COEX_POWERON\n", __func__);1307/* set path control owner to BT at power-on */1308if (coex_stat->bt_disabled)1309rtw_coex_coex_ctrl_owner(rtwdev, true);1310else1311rtw_coex_coex_ctrl_owner(rtwdev, false);13121313ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;1314pos_type = COEX_SWITCH_TO_BT;1315break;1316case COEX_SET_ANT_INIT:1317rtw_dbg(rtwdev, RTW_DBG_COEX,1318"[BTCoex], %s() - PHASE_COEX_INIT\n", __func__);1319if (coex_stat->bt_disabled) {1320/* set GNT_BT to SW low */1321rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW);13221323/* set GNT_WL to SW high */1324rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);1325} else {1326/* set GNT_BT to SW high */1327rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_HIGH);13281329/* set GNT_WL to SW low */1330rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_LOW);1331}13321333/* set path control owner to wl at initial step */1334rtw_coex_coex_ctrl_owner(rtwdev, true);13351336ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;1337pos_type = COEX_SWITCH_TO_BT;1338break;1339case COEX_SET_ANT_WONLY:1340rtw_dbg(rtwdev, RTW_DBG_COEX,1341"[BTCoex], %s() - PHASE_WLANONLY_INIT\n", __func__);1342/* set GNT_BT to SW Low */1343rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_SW_LOW);13441345/* set GNT_WL to SW high */1346rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);13471348/* set path control owner to wl at initial step */1349rtw_coex_coex_ctrl_owner(rtwdev, true);13501351ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;1352pos_type = COEX_SWITCH_TO_WLG;1353break;1354case COEX_SET_ANT_WOFF:1355rtw_dbg(rtwdev, RTW_DBG_COEX,1356"[BTCoex], %s() - PHASE_WLAN_OFF\n", __func__);1357/* set path control owner to BT */1358rtw_coex_coex_ctrl_owner(rtwdev, false);13591360ctrl_type = COEX_SWITCH_CTRL_BY_BT;1361pos_type = COEX_SWITCH_TO_NOCARE;1362break;1363case COEX_SET_ANT_2G:1364rtw_dbg(rtwdev, RTW_DBG_COEX,1365"[BTCoex], %s() - PHASE_2G_RUNTIME\n", __func__);1366/* set GNT_BT to PTA */1367rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);13681369/* set GNT_WL to PTA */1370rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA);13711372/* set path control owner to wl at runtime step */1373rtw_coex_coex_ctrl_owner(rtwdev, true);13741375ctrl_type = COEX_SWITCH_CTRL_BY_PTA;1376pos_type = COEX_SWITCH_TO_NOCARE;1377break;1378case COEX_SET_ANT_5G:1379rtw_dbg(rtwdev, RTW_DBG_COEX,1380"[BTCoex], %s() - PHASE_5G_RUNTIME\n", __func__);13811382/* set GNT_BT to HW PTA */1383rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);13841385/* set GNT_WL to SW high */1386rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);13871388/* set path control owner to wl at runtime step */1389rtw_coex_coex_ctrl_owner(rtwdev, true);13901391ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;1392pos_type = COEX_SWITCH_TO_WLA;1393break;1394case COEX_SET_ANT_2G_FREERUN:1395rtw_dbg(rtwdev, RTW_DBG_COEX,1396"[BTCoex], %s() - PHASE_2G_FREERUN\n", __func__);13971398/* set GNT_BT to HW PTA */1399rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);14001401/* Set GNT_WL to SW high */1402rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_SW_HIGH);14031404/* set path control owner to wl at runtime step */1405rtw_coex_coex_ctrl_owner(rtwdev, true);14061407ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;1408pos_type = COEX_SWITCH_TO_WLG_BT;1409break;1410case COEX_SET_ANT_2G_WLBT:1411rtw_dbg(rtwdev, RTW_DBG_COEX,1412"[BTCoex], %s() - PHASE_2G_WLBT\n", __func__);1413/* set GNT_BT to HW PTA */1414rtw_coex_set_gnt_bt(rtwdev, COEX_GNT_SET_HW_PTA);14151416/* Set GNT_WL to HW PTA */1417rtw_coex_set_gnt_wl(rtwdev, COEX_GNT_SET_HW_PTA);14181419/* set path control owner to wl at runtime step */1420rtw_coex_coex_ctrl_owner(rtwdev, true);14211422ctrl_type = COEX_SWITCH_CTRL_BY_BBSW;1423pos_type = COEX_SWITCH_TO_WLG_BT;1424break;1425default:1426WARN(1, "unknown phase when setting antenna path\n");1427return;1428}14291430if (ctrl_type < COEX_SWITCH_CTRL_MAX && pos_type < COEX_SWITCH_TO_MAX &&1431coex_rfe->ant_switch_exist)1432rtw_coex_set_ant_switch(rtwdev, ctrl_type, pos_type);1433}14341435#define case_ALGO(src) \1436case COEX_ALGO_##src: return #src14371438static const char *rtw_coex_get_algo_string(u8 algo)1439{1440switch (algo) {1441case_ALGO(NOPROFILE);1442case_ALGO(HFP);1443case_ALGO(HID);1444case_ALGO(A2DP);1445case_ALGO(PAN);1446case_ALGO(A2DP_HID);1447case_ALGO(A2DP_PAN);1448case_ALGO(PAN_HID);1449case_ALGO(A2DP_PAN_HID);1450default:1451return "Unknown";1452}1453}14541455#define case_BT_PROFILE(src) \1456case BPM_##src: return #src14571458static const char *rtw_coex_get_bt_profile_string(u8 bt_profile)1459{1460switch (bt_profile) {1461case_BT_PROFILE(NOPROFILE);1462case_BT_PROFILE(HFP);1463case_BT_PROFILE(HID);1464case_BT_PROFILE(A2DP);1465case_BT_PROFILE(PAN);1466case_BT_PROFILE(HID_HFP);1467case_BT_PROFILE(A2DP_HFP);1468case_BT_PROFILE(A2DP_HID);1469case_BT_PROFILE(A2DP_HID_HFP);1470case_BT_PROFILE(PAN_HFP);1471case_BT_PROFILE(PAN_HID);1472case_BT_PROFILE(PAN_HID_HFP);1473case_BT_PROFILE(PAN_A2DP);1474case_BT_PROFILE(PAN_A2DP_HFP);1475case_BT_PROFILE(PAN_A2DP_HID);1476case_BT_PROFILE(PAN_A2DP_HID_HFP);1477default:1478return "Unknown";1479}1480}14811482static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev)1483{1484struct rtw_coex *coex = &rtwdev->coex;1485struct rtw_coex_stat *coex_stat = &coex->stat;1486u8 algorithm = COEX_ALGO_NOPROFILE;1487u8 profile_map = 0;14881489if (coex_stat->bt_hfp_exist)1490profile_map |= BPM_HFP;1491if (coex_stat->bt_hid_exist)1492profile_map |= BPM_HID;1493if (coex_stat->bt_a2dp_exist)1494profile_map |= BPM_A2DP;1495if (coex_stat->bt_pan_exist)1496profile_map |= BPM_PAN;14971498switch (profile_map) {1499case BPM_HFP:1500algorithm = COEX_ALGO_HFP;1501break;1502case BPM_HID:1503case BPM_HFP | BPM_HID:1504algorithm = COEX_ALGO_HID;1505break;1506case BPM_HFP | BPM_A2DP:1507case BPM_HID | BPM_A2DP:1508case BPM_HFP | BPM_HID | BPM_A2DP:1509algorithm = COEX_ALGO_A2DP_HID;1510break;1511case BPM_HFP | BPM_PAN:1512case BPM_HID | BPM_PAN:1513case BPM_HFP | BPM_HID | BPM_PAN:1514algorithm = COEX_ALGO_PAN_HID;1515break;1516case BPM_HFP | BPM_A2DP | BPM_PAN:1517case BPM_HID | BPM_A2DP | BPM_PAN:1518case BPM_HFP | BPM_HID | BPM_A2DP | BPM_PAN:1519algorithm = COEX_ALGO_A2DP_PAN_HID;1520break;1521case BPM_PAN:1522algorithm = COEX_ALGO_PAN;1523break;1524case BPM_A2DP | BPM_PAN:1525algorithm = COEX_ALGO_A2DP_PAN;1526break;1527case BPM_A2DP:1528if (coex_stat->bt_multi_link) {1529if (coex_stat->bt_hid_pair_num > 0)1530algorithm = COEX_ALGO_A2DP_HID;1531else1532algorithm = COEX_ALGO_A2DP_PAN;1533} else {1534algorithm = COEX_ALGO_A2DP;1535}1536break;1537default:1538algorithm = COEX_ALGO_NOPROFILE;1539break;1540}15411542rtw_dbg(rtwdev, RTW_DBG_COEX,1543"[BTCoex], BT Profile = %s => Algorithm = %s\n",1544rtw_coex_get_bt_profile_string(profile_map),1545rtw_coex_get_algo_string(algorithm));1546return algorithm;1547}15481549static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev)1550{1551const struct rtw_chip_info *chip = rtwdev->chip;1552struct rtw_efuse *efuse = &rtwdev->efuse;1553u8 table_case, tdma_case;15541555rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);1556rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);15571558if (efuse->share_ant) {1559/* Shared-Ant */1560table_case = 2;1561tdma_case = 0;1562} else {1563/* Non-Shared-Ant */1564table_case = 100;1565tdma_case = 100;1566}15671568rtw_coex_table(rtwdev, false, table_case);1569rtw_coex_tdma(rtwdev, false, tdma_case);1570}15711572static void rtw_coex_action_freerun(struct rtw_dev *rtwdev)1573{1574const struct rtw_chip_info *chip = rtwdev->chip;1575struct rtw_coex *coex = &rtwdev->coex;1576struct rtw_coex_stat *coex_stat = &coex->stat;1577struct rtw_coex_dm *coex_dm = &coex->dm;1578struct rtw_efuse *efuse = &rtwdev->efuse;1579u8 level = 0;1580bool bt_afh_loss = true;15811582rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);15831584if (efuse->share_ant)1585return;15861587coex->freerun = true;15881589if (bt_afh_loss)1590rtw_coex_update_wl_ch_info(rtwdev, COEX_MEDIA_CONNECT);15911592rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN);15931594rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);15951596if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[0]))1597level = 2;1598else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))1599level = 3;1600else if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[2]))1601level = 4;1602else1603level = 5;16041605if (level > chip->wl_rf_para_num - 1)1606level = chip->wl_rf_para_num - 1;16071608if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)1609rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[level]);1610else1611rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[level]);16121613rtw_coex_table(rtwdev, false, 100);1614rtw_coex_tdma(rtwdev, false, 100);1615}16161617static void rtw_coex_action_rf4ce(struct rtw_dev *rtwdev)1618{1619const struct rtw_chip_info *chip = rtwdev->chip;1620struct rtw_efuse *efuse = &rtwdev->efuse;1621u8 table_case, tdma_case;16221623rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);16241625rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);1626rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);16271628if (efuse->share_ant) {1629/* Shared-Ant */1630table_case = 9;1631tdma_case = 16;1632} else {1633/* Non-Shared-Ant */1634table_case = 100;1635tdma_case = 100;1636}16371638rtw_coex_table(rtwdev, false, table_case);1639rtw_coex_tdma(rtwdev, false, tdma_case);1640}16411642static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev)1643{1644const struct rtw_chip_info *chip = rtwdev->chip;1645struct rtw_efuse *efuse = &rtwdev->efuse;1646u8 table_case, tdma_case;16471648rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);16491650rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);1651rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);16521653if (efuse->share_ant) {1654/* Shared-Ant */1655table_case = 2;1656tdma_case = 0;1657} else {1658/* Non-Shared-Ant */1659table_case = 100;1660tdma_case = 100;1661}16621663rtw_coex_table(rtwdev, false, table_case);1664rtw_coex_tdma(rtwdev, false, tdma_case);1665}16661667static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev)1668{1669const struct rtw_chip_info *chip = rtwdev->chip;1670struct rtw_coex *coex = &rtwdev->coex;1671struct rtw_coex_stat *coex_stat = &coex->stat;1672struct rtw_efuse *efuse = &rtwdev->efuse;1673u8 table_case, tdma_case;1674u32 slot_type = 0;16751676rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);16771678rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);1679rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);16801681if (efuse->share_ant) { /* Shared-Ant */1682if (coex_stat->wl_gl_busy) {1683table_case = 26;1684if (coex_stat->bt_hid_exist &&1685coex_stat->bt_profile_num == 1) {1686slot_type = TDMA_4SLOT;1687tdma_case = 20;1688} else {1689tdma_case = 20;1690}1691} else {1692table_case = 1;1693tdma_case = 0;1694}1695} else { /* Non-Shared-Ant */1696if (coex_stat->wl_gl_busy)1697table_case = 115;1698else1699table_case = 100;1700tdma_case = 100;1701}17021703rtw_coex_table(rtwdev, false, table_case);1704rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);1705}17061707static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)1708{1709const struct rtw_chip_info *chip = rtwdev->chip;1710struct rtw_coex *coex = &rtwdev->coex;1711struct rtw_coex_stat *coex_stat = &coex->stat;1712struct rtw_coex_dm *coex_dm = &coex->dm;1713struct rtw_efuse *efuse = &rtwdev->efuse;1714struct rtw_coex_rfe *coex_rfe = &coex->rfe;1715u8 table_case = 0xff, tdma_case = 0xff;17161717rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);1718rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);17191720if (coex_rfe->ant_switch_with_bt &&1721coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {1722if (efuse->share_ant &&1723COEX_RSSI_HIGH(coex_dm->wl_rssi_state[3]) &&1724coex_stat->wl_gl_busy) {1725table_case = 0;1726tdma_case = 0;1727} else if (!efuse->share_ant) {1728table_case = 100;1729tdma_case = 100;1730}1731}17321733if (table_case != 0xff && tdma_case != 0xff) {1734rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G_FREERUN);1735goto exit;1736}17371738rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);17391740if (efuse->share_ant) {1741/* Shared-Ant */1742if (!coex_stat->wl_gl_busy) {1743table_case = 10;1744tdma_case = 3;1745} else if (coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {1746table_case = 11;17471748if (coex_stat->lo_pri_rx + coex_stat->lo_pri_tx > 250)1749tdma_case = 17;1750else1751tdma_case = 7;1752} else {1753table_case = 12;1754tdma_case = 7;1755}1756} else {1757/* Non-Shared-Ant */1758if (!coex_stat->wl_gl_busy) {1759table_case = 112;1760tdma_case = 104;1761} else if ((coex_stat->bt_ble_scan_type & 0x2) &&1762coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE) {1763table_case = 114;1764tdma_case = 103;1765} else {1766table_case = 112;1767tdma_case = 103;1768}1769}17701771exit:1772rtw_coex_table(rtwdev, false, table_case);1773rtw_coex_tdma(rtwdev, false, tdma_case);1774}17751776static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)1777{1778const struct rtw_chip_info *chip = rtwdev->chip;1779struct rtw_coex *coex = &rtwdev->coex;1780struct rtw_coex_stat *coex_stat = &coex->stat;1781struct rtw_efuse *efuse = &rtwdev->efuse;1782bool wl_hi_pri = false;1783u8 table_case, tdma_case;1784u32 slot_type = 0;17851786rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);1787rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);1788rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);17891790if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 ||1791coex_stat->wl_hi_pri_task2)1792wl_hi_pri = true;17931794if (efuse->share_ant) {1795/* Shared-Ant */1796if (wl_hi_pri) {1797rtw_dbg(rtwdev, RTW_DBG_COEX,1798"[BTCoex], bt inq/page + wifi hi-pri task\n");1799table_case = 15;18001801if (coex_stat->bt_profile_num > 0)1802tdma_case = 10;1803else if (coex_stat->wl_hi_pri_task1)1804tdma_case = 6;1805else if (!coex_stat->bt_page)1806tdma_case = 8;1807else1808tdma_case = 9;1809} else if (coex_stat->wl_gl_busy) {1810rtw_dbg(rtwdev, RTW_DBG_COEX,1811"[BTCoex], bt inq/page + wifi busy\n");1812if (coex_stat->bt_profile_num == 0) {1813table_case = 12;1814tdma_case = 18;1815} else if (coex_stat->bt_profile_num == 1 &&1816!coex_stat->bt_a2dp_exist) {1817slot_type = TDMA_4SLOT;1818table_case = 12;1819tdma_case = 20;1820} else {1821slot_type = TDMA_4SLOT;1822table_case = 12;1823tdma_case = 26;1824}1825} else if (coex_stat->wl_connected) {1826rtw_dbg(rtwdev, RTW_DBG_COEX,1827"[BTCoex], bt inq/page + wifi connected\n");1828table_case = 9;1829tdma_case = 27;1830} else {1831rtw_dbg(rtwdev, RTW_DBG_COEX,1832"[BTCoex], bt inq/page + wifi not-connected\n");1833table_case = 1;1834tdma_case = 0;1835}1836} else {1837/* Non_Shared-Ant */1838if (wl_hi_pri) {1839rtw_dbg(rtwdev, RTW_DBG_COEX,1840"[BTCoex], bt inq/page + wifi hi-pri task\n");1841table_case = 114;18421843if (coex_stat->bt_profile_num > 0)1844tdma_case = 110;1845else if (coex_stat->wl_hi_pri_task1)1846tdma_case = 106;1847else if (!coex_stat->bt_page)1848tdma_case = 108;1849else1850tdma_case = 109;1851} else if (coex_stat->wl_gl_busy) {1852rtw_dbg(rtwdev, RTW_DBG_COEX,1853"[BTCoex], bt inq/page + wifi busy\n");1854table_case = 114;1855tdma_case = 121;1856} else if (coex_stat->wl_connected) {1857rtw_dbg(rtwdev, RTW_DBG_COEX,1858"[BTCoex], bt inq/page + wifi connected\n");1859table_case = 101;1860tdma_case = 100;1861} else {1862rtw_dbg(rtwdev, RTW_DBG_COEX,1863"[BTCoex], bt inq/page + wifi not-connected\n");1864table_case = 101;1865tdma_case = 100;1866}1867}18681869rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], wifi hi(%d), bt page(%d)\n",1870wl_hi_pri, coex_stat->bt_page);18711872rtw_coex_table(rtwdev, false, table_case);1873rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);1874}18751876static void rtw_coex_action_bt_game_hid(struct rtw_dev *rtwdev)1877{1878const struct rtw_chip_info *chip = rtwdev->chip;1879struct rtw_coex *coex = &rtwdev->coex;1880struct rtw_coex_stat *coex_stat = &coex->stat;1881struct rtw_efuse *efuse = &rtwdev->efuse;1882struct rtw_coex_dm *coex_dm = &coex->dm;1883u8 table_case, tdma_case;18841885rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);1886rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);18871888if (efuse->share_ant) {1889coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;1890if (coex_stat->bt_whck_test)1891table_case = 2;1892else if (coex_stat->wl_linkscan_proc || coex_stat->bt_hid_exist)1893table_case = 33;1894else if (coex_stat->bt_setup_link || coex_stat->bt_inq_page)1895table_case = 0;1896else if (coex_stat->bt_a2dp_exist)1897table_case = 34;1898else1899table_case = 33;19001901tdma_case = 0;1902} else {1903if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))1904tdma_case = 112;1905else1906tdma_case = 113;19071908table_case = 121;1909}19101911if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {1912if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)1913rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[6]);1914else1915rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[5]);1916} else {1917rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);1918}19191920rtw_coex_table(rtwdev, false, table_case);1921rtw_coex_tdma(rtwdev, false, tdma_case);1922}19231924static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev)1925{1926const struct rtw_chip_info *chip = rtwdev->chip;1927struct rtw_coex *coex = &rtwdev->coex;1928struct rtw_coex_stat *coex_stat = &coex->stat;1929struct rtw_efuse *efuse = &rtwdev->efuse;1930u8 table_case, tdma_case;19311932rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);1933rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);1934rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);19351936if (efuse->share_ant) {1937/* Shared-Ant */1938table_case = 10;1939tdma_case = 5;1940} else {1941/* Non-Shared-Ant */1942if (coex_stat->bt_multi_link) {1943table_case = 112;1944tdma_case = 117;1945} else {1946table_case = 105;1947tdma_case = 100;1948}1949}19501951rtw_coex_table(rtwdev, false, table_case);1952rtw_coex_tdma(rtwdev, false, tdma_case);1953}19541955static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev)1956{1957const struct rtw_chip_info *chip = rtwdev->chip;1958struct rtw_coex *coex = &rtwdev->coex;1959struct rtw_coex_stat *coex_stat = &coex->stat;1960struct rtw_efuse *efuse = &rtwdev->efuse;1961u8 table_case, tdma_case;1962u32 slot_type = 0;1963bool bt_multi_link_remain = false, is_toggle_table = false;19641965rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);1966rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);1967rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);19681969if (efuse->share_ant) {1970/* Shared-Ant */1971if (coex_stat->bt_ble_exist) {1972/* RCU */1973if (coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] > 5) {1974table_case = 26;1975tdma_case = 2;1976} else {1977table_case = 27;1978tdma_case = 9;1979}1980} else {1981/* Legacy HID */1982if (coex_stat->bt_profile_num == 1 &&1983(coex_stat->bt_multi_link ||1984(coex_stat->lo_pri_rx +1985coex_stat->lo_pri_tx > 360) ||1986coex_stat->bt_slave ||1987bt_multi_link_remain)) {1988slot_type = TDMA_4SLOT;1989table_case = 12;1990tdma_case = 20;1991} else if (coex_stat->bt_a2dp_active) {1992table_case = 9;1993tdma_case = 18;1994} else if (coex_stat->bt_418_hid_exist &&1995coex_stat->wl_gl_busy) {1996is_toggle_table = true;1997slot_type = TDMA_4SLOT;1998table_case = 9;1999tdma_case = 24;2000} else if (coex_stat->bt_ble_hid_exist &&2001coex_stat->wl_gl_busy) {2002table_case = 32;2003tdma_case = 9;2004} else {2005table_case = 9;2006tdma_case = 9;2007}2008}2009} else {2010/* Non-Shared-Ant */2011if (coex_stat->bt_ble_exist) {2012/* BLE */2013if (coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] > 5) {2014table_case = 121;2015tdma_case = 102;2016} else {2017table_case = 122;2018tdma_case = 109;2019}2020} else if (coex_stat->bt_a2dp_active) {2021table_case = 113;2022tdma_case = 118;2023} else {2024table_case = 113;2025tdma_case = 104;2026}2027}20282029rtw_coex_table(rtwdev, false, table_case);2030if (is_toggle_table) {2031rtw_btc_wltoggle_table_a(rtwdev, true, table_case);2032rtw_btc_wltoggle_table_b(rtwdev, false, 1, COEX_WL_SLOT_TOGLLE);2033}20342035rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);2036}20372038static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev)2039{2040const struct rtw_chip_info *chip = rtwdev->chip;2041struct rtw_coex *coex = &rtwdev->coex;2042struct rtw_coex_stat *coex_stat = &coex->stat;2043struct rtw_coex_dm *coex_dm = &coex->dm;2044struct rtw_efuse *efuse = &rtwdev->efuse;2045u8 table_case, tdma_case;2046u32 slot_type = 0;20472048rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);20492050rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);2051rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);20522053slot_type = TDMA_4SLOT;20542055if (efuse->share_ant) {2056/* Shared-Ant */2057if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0)2058table_case = 12;2059else2060table_case = 9;20612062if (coex_stat->wl_connecting || !coex_stat->wl_gl_busy)2063tdma_case = 14;2064else2065tdma_case = 13;2066} else {2067/* Non-Shared-Ant */2068table_case = 112;20692070if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))2071tdma_case = 112;2072else2073tdma_case = 113;2074}20752076rtw_coex_table(rtwdev, false, table_case);2077rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);2078}20792080static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev)2081{2082const struct rtw_chip_info *chip = rtwdev->chip;2083struct rtw_coex *coex = &rtwdev->coex;2084struct rtw_coex_stat *coex_stat = &coex->stat;2085struct rtw_efuse *efuse = &rtwdev->efuse;2086u8 table_case, tdma_case;2087bool ap_enable = false;20882089rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);20902091rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);2092rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);20932094if (efuse->share_ant) { /* Shared-Ant */2095if (ap_enable) {2096table_case = 2;2097tdma_case = 0;2098} else if (coex_stat->wl_gl_busy) {2099table_case = 28;2100tdma_case = 20;2101} else {2102table_case = 28;2103tdma_case = 26;2104}2105} else { /* Non-Shared-Ant */2106if (ap_enable) {2107table_case = 100;2108tdma_case = 100;2109} else {2110table_case = 119;2111tdma_case = 120;2112}2113}21142115rtw_coex_table(rtwdev, false, table_case);2116rtw_coex_tdma(rtwdev, false, tdma_case);2117}21182119static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev)2120{2121const struct rtw_chip_info *chip = rtwdev->chip;2122struct rtw_coex *coex = &rtwdev->coex;2123struct rtw_coex_stat *coex_stat = &coex->stat;2124struct rtw_efuse *efuse = &rtwdev->efuse;2125u8 table_case, tdma_case;21262127rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);2128rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);2129rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);21302131if (efuse->share_ant) {2132/* Shared-Ant */2133if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0)2134table_case = 14;2135else2136table_case = 10;21372138if (coex_stat->wl_gl_busy)2139tdma_case = 17;2140else2141tdma_case = 20;2142} else {2143/* Non-Shared-Ant */2144table_case = 112;21452146if (coex_stat->wl_gl_busy)2147tdma_case = 117;2148else2149tdma_case = 119;2150}21512152rtw_coex_table(rtwdev, false, table_case);2153rtw_coex_tdma(rtwdev, false, tdma_case);2154}21552156static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev)2157{2158const struct rtw_chip_info *chip = rtwdev->chip;2159struct rtw_coex *coex = &rtwdev->coex;2160struct rtw_coex_stat *coex_stat = &coex->stat;2161struct rtw_coex_dm *coex_dm = &coex->dm;2162struct rtw_efuse *efuse = &rtwdev->efuse;2163u8 table_case, tdma_case, interval = 0;2164u32 slot_type = 0;2165bool is_toggle_table = false;21662167slot_type = TDMA_4SLOT;21682169rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);2170rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);2171rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);21722173if (efuse->share_ant) {2174/* Shared-Ant */2175if (coex_stat->bt_ble_exist) {2176table_case = 26; /* for RCU */2177} else if (coex_stat->bt_418_hid_exist) {2178table_case = 9;2179interval = 1;2180} else {2181table_case = 9;2182}21832184if (coex_stat->wl_connecting || !coex_stat->wl_gl_busy) {2185tdma_case = 14;2186} else if (coex_stat->bt_418_hid_exist) {2187is_toggle_table = true;2188tdma_case = 23;2189} else {2190tdma_case = 13;2191}2192} else {2193/* Non-Shared-Ant */2194if (coex_stat->bt_ble_exist)2195table_case = 121;2196else2197table_case = 113;21982199if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))2200tdma_case = 112;2201else2202tdma_case = 113;2203}22042205rtw_coex_table(rtwdev, false, table_case);2206if (is_toggle_table) {2207rtw_btc_wltoggle_table_a(rtwdev, true, table_case);2208rtw_btc_wltoggle_table_b(rtwdev, false, interval, COEX_WL_SLOT_TOGLLE);2209}2210rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);2211}22122213static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev)2214{2215const struct rtw_chip_info *chip = rtwdev->chip;2216struct rtw_coex *coex = &rtwdev->coex;2217struct rtw_coex_stat *coex_stat = &coex->stat;2218struct rtw_efuse *efuse = &rtwdev->efuse;2219u8 table_case, tdma_case;22202221rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);22222223rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);2224rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);2225if (efuse->share_ant) {2226/* Shared-Ant */2227if (coex_stat->wl_gl_busy &&2228coex_stat->wl_noisy_level == 0)2229table_case = 14;2230else2231table_case = 10;22322233if (coex_stat->wl_gl_busy)2234tdma_case = 15;2235else2236tdma_case = 20;2237} else {2238/* Non-Shared-Ant */2239table_case = 112;22402241if (coex_stat->wl_gl_busy)2242tdma_case = 115;2243else2244tdma_case = 120;2245}22462247rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);2248rtw_coex_table(rtwdev, false, table_case);2249rtw_coex_tdma(rtwdev, false, tdma_case);2250}22512252static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev)2253{2254const struct rtw_chip_info *chip = rtwdev->chip;2255struct rtw_coex *coex = &rtwdev->coex;2256struct rtw_coex_stat *coex_stat = &coex->stat;2257struct rtw_efuse *efuse = &rtwdev->efuse;2258u8 table_case, tdma_case;22592260rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);22612262rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);2263rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);22642265if (efuse->share_ant) {2266/* Shared-Ant */2267table_case = 9;22682269if (coex_stat->wl_gl_busy)2270tdma_case = 18;2271else2272tdma_case = 19;2273} else {2274/* Non-Shared-Ant */2275table_case = 113;22762277if (coex_stat->wl_gl_busy)2278tdma_case = 117;2279else2280tdma_case = 119;2281}22822283rtw_coex_table(rtwdev, false, table_case);2284rtw_coex_tdma(rtwdev, false, tdma_case);2285}22862287static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev)2288{2289const struct rtw_chip_info *chip = rtwdev->chip;2290struct rtw_coex *coex = &rtwdev->coex;2291struct rtw_coex_stat *coex_stat = &coex->stat;2292struct rtw_efuse *efuse = &rtwdev->efuse;2293u8 table_case, tdma_case;22942295rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);2296rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);2297rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);22982299if (efuse->share_ant) {2300/* Shared-Ant */2301table_case = 10;23022303if (coex_stat->wl_gl_busy)2304tdma_case = 15;2305else2306tdma_case = 20;2307} else {2308/* Non-Shared-Ant */2309table_case = 113;23102311if (coex_stat->wl_gl_busy)2312tdma_case = 115;2313else2314tdma_case = 120;2315}23162317rtw_coex_table(rtwdev, false, table_case);2318rtw_coex_tdma(rtwdev, false, tdma_case);2319}23202321static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)2322{2323const struct rtw_chip_info *chip = rtwdev->chip;2324struct rtw_coex *coex = &rtwdev->coex;2325struct rtw_efuse *efuse = &rtwdev->efuse;2326struct rtw_coex_stat *coex_stat = &coex->stat;2327u8 table_case, tdma_case;23282329rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);23302331rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);2332rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);23332334rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);23352336if (coex_stat->bt_game_hid_exist && coex_stat->wl_linkscan_proc)2337coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;23382339if (efuse->share_ant) {2340/* Shared-Ant */2341table_case = 0;2342tdma_case = 0;2343} else {2344/* Non-Shared-Ant */2345table_case = 100;2346tdma_case = 100;2347}23482349rtw_coex_table(rtwdev, false, table_case);2350rtw_coex_tdma(rtwdev, false, tdma_case);2351}23522353static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev)2354{2355const struct rtw_chip_info *chip = rtwdev->chip;2356struct rtw_efuse *efuse = &rtwdev->efuse;2357u8 table_case, tdma_case;23582359rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);2360rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);2361rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);23622363if (efuse->share_ant) {2364/* Shared-Ant */2365table_case = 2;2366tdma_case = 0;2367} else {2368/* Non-Shared-Ant */2369table_case = 100;2370tdma_case = 100;2371}23722373rtw_coex_table(rtwdev, false, table_case);2374rtw_coex_tdma(rtwdev, false, tdma_case);2375}23762377static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)2378{2379const struct rtw_chip_info *chip = rtwdev->chip;2380struct rtw_coex *coex = &rtwdev->coex;2381struct rtw_efuse *efuse = &rtwdev->efuse;2382struct rtw_coex_stat *coex_stat = &coex->stat;2383u8 table_case, tdma_case;23842385if (coex->under_5g)2386return;23872388rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);23892390rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);23912392if (efuse->share_ant) {2393/* Shared-Ant */2394table_case = 28;2395tdma_case = 0;2396} else {2397/* Non-Shared-Ant */2398table_case = 100;2399tdma_case = 100;2400}24012402if (coex_stat->bt_game_hid_exist) {2403coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;2404if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)2405rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[6]);2406else2407rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[5]);2408} else {2409rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);2410}24112412rtw_coex_table(rtwdev, false, table_case);2413rtw_coex_tdma(rtwdev, false, tdma_case);2414}24152416static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev)2417{2418const struct rtw_chip_info *chip = rtwdev->chip;2419struct rtw_coex *coex = &rtwdev->coex;2420struct rtw_coex_stat *coex_stat = &coex->stat;2421struct rtw_efuse *efuse = &rtwdev->efuse;2422u8 table_case, tdma_case;2423u32 slot_type = 0;24242425rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);2426rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);2427rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);24282429if (efuse->share_ant) { /* Shared-Ant */2430if (coex_stat->bt_a2dp_exist) {2431slot_type = TDMA_4SLOT;2432tdma_case = 11;2433if (coex_stat->wl_gl_busy)2434table_case = 26;2435else2436table_case = 9;2437} else {2438table_case = 9;2439tdma_case = 7;2440}2441} else { /* Non-Shared-Ant */2442if (coex_stat->bt_a2dp_exist) {2443slot_type = TDMA_4SLOT;2444table_case = 112;2445tdma_case = 111;2446} else {2447table_case = 112;2448tdma_case = 107;2449}2450}24512452rtw_coex_table(rtwdev, false, table_case);2453rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);2454}24552456static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev)2457{2458const struct rtw_chip_info *chip = rtwdev->chip;2459struct rtw_efuse *efuse = &rtwdev->efuse;2460u8 table_case, tdma_case;24612462rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);2463rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);2464rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);24652466if (efuse->share_ant) {2467/* Shared-Ant */2468table_case = 1;2469tdma_case = 0;2470} else {2471/* Non-Shared-Ant */2472table_case = 100;2473tdma_case = 100;2474}24752476rtw_coex_table(rtwdev, false, table_case);2477rtw_coex_tdma(rtwdev, false, tdma_case);2478}24792480static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev)2481{2482struct rtw_coex *coex = &rtwdev->coex;2483struct rtw_coex_stat *coex_stat = &coex->stat;2484u8 algorithm;24852486rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);24872488algorithm = rtw_coex_algorithm(rtwdev);24892490switch (algorithm) {2491case COEX_ALGO_HFP:2492rtw_coex_action_bt_hfp(rtwdev);2493break;2494case COEX_ALGO_HID:2495if (rtw_coex_freerun_check(rtwdev))2496rtw_coex_action_freerun(rtwdev);2497else2498rtw_coex_action_bt_hid(rtwdev);2499break;2500case COEX_ALGO_A2DP:2501if (rtw_coex_freerun_check(rtwdev))2502rtw_coex_action_freerun(rtwdev);2503else if (coex_stat->bt_a2dp_sink)2504rtw_coex_action_bt_a2dpsink(rtwdev);2505else2506rtw_coex_action_bt_a2dp(rtwdev);2507break;2508case COEX_ALGO_PAN:2509rtw_coex_action_bt_pan(rtwdev);2510break;2511case COEX_ALGO_A2DP_HID:2512if (rtw_coex_freerun_check(rtwdev))2513rtw_coex_action_freerun(rtwdev);2514else2515rtw_coex_action_bt_a2dp_hid(rtwdev);2516break;2517case COEX_ALGO_A2DP_PAN:2518rtw_coex_action_bt_a2dp_pan(rtwdev);2519break;2520case COEX_ALGO_PAN_HID:2521rtw_coex_action_bt_pan_hid(rtwdev);2522break;2523case COEX_ALGO_A2DP_PAN_HID:2524rtw_coex_action_bt_a2dp_pan_hid(rtwdev);2525break;2526default:2527case COEX_ALGO_NOPROFILE:2528rtw_coex_action_bt_idle(rtwdev);2529break;2530}2531}25322533static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)2534{2535const struct rtw_chip_info *chip = rtwdev->chip;2536struct rtw_coex *coex = &rtwdev->coex;2537struct rtw_coex_dm *coex_dm = &coex->dm;2538struct rtw_coex_stat *coex_stat = &coex->stat;2539bool rf4ce_en = false;25402541lockdep_assert_held(&rtwdev->mutex);25422543if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags))2544return;25452546coex_dm->reason = reason;25472548rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): reason = %d\n", __func__,2549reason);25502551/* update wifi_link_info_ext variable */2552rtw_coex_update_wl_link_info(rtwdev, reason);25532554rtw_coex_monitor_bt_enable(rtwdev);25552556if (coex->manual_control) {2557rtw_dbg(rtwdev, RTW_DBG_COEX,2558"[BTCoex], return for Manual CTRL!!\n");2559return;2560}25612562if (coex->stop_dm) {2563rtw_dbg(rtwdev, RTW_DBG_COEX,2564"[BTCoex], return for Stop Coex DM!!\n");2565return;2566}25672568if (coex_stat->wl_under_ips) {2569rtw_dbg(rtwdev, RTW_DBG_COEX,2570"[BTCoex], return for wifi is under IPS!!\n");2571return;2572}25732574if (coex->freeze && coex_dm->reason == COEX_RSN_BTINFO &&2575!coex_stat->bt_setup_link) {2576rtw_dbg(rtwdev, RTW_DBG_COEX,2577"[BTCoex], return for coex_freeze!!\n");2578return;2579}25802581coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN]++;2582coex->freerun = false;25832584/* Pure-5G Coex Process */2585if (coex->under_5g) {2586coex_stat->wl_coex_mode = COEX_WLINK_5G;2587rtw_coex_action_wl_under5g(rtwdev);2588goto exit;2589}25902591rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], WiFi is single-port 2G!!\n");2592coex_stat->wl_coex_mode = COEX_WLINK_2G1PORT;25932594if (coex_stat->bt_disabled) {2595if (coex_stat->wl_connected && rf4ce_en)2596rtw_coex_action_rf4ce(rtwdev);2597else if (!coex_stat->wl_connected)2598rtw_coex_action_wl_not_connected(rtwdev);2599else2600rtw_coex_action_wl_only(rtwdev);2601goto exit;2602}26032604if (coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl) {2605rtw_coex_action_wl_native_lps(rtwdev);2606goto exit;2607}26082609if (coex_stat->bt_game_hid_exist && coex_stat->wl_connected) {2610rtw_coex_action_bt_game_hid(rtwdev);2611goto exit;2612}26132614if (coex_stat->bt_whck_test) {2615rtw_coex_action_bt_whql_test(rtwdev);2616goto exit;2617}26182619if (coex_stat->bt_setup_link) {2620rtw_coex_action_bt_relink(rtwdev);2621goto exit;2622}26232624if (coex_stat->bt_inq_page) {2625rtw_coex_action_bt_inquiry(rtwdev);2626goto exit;2627}26282629if ((coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE ||2630coex_dm->bt_status == COEX_BTSTATUS_CON_IDLE) &&2631coex_stat->wl_connected) {2632rtw_coex_action_bt_idle(rtwdev);2633goto exit;2634}26352636if (coex_stat->wl_linkscan_proc && !coex->freerun) {2637rtw_coex_action_wl_linkscan(rtwdev);2638goto exit;2639}26402641if (coex_stat->wl_connected) {2642rtw_coex_action_wl_connected(rtwdev);2643goto exit;2644} else {2645rtw_coex_action_wl_not_connected(rtwdev);2646goto exit;2647}26482649exit:26502651if (chip->wl_mimo_ps_support) {2652if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {2653if (coex_dm->reason == COEX_RSN_2GMEDIA)2654rtw_coex_mimo_ps(rtwdev, true, true);2655else2656rtw_coex_mimo_ps(rtwdev, false, true);2657} else {2658rtw_coex_mimo_ps(rtwdev, false, false);2659}2660}26612662rtw_coex_gnt_workaround(rtwdev, false, coex_stat->wl_coex_mode);2663rtw_coex_limited_wl(rtwdev);2664}26652666static void rtw_coex_init_coex_var(struct rtw_dev *rtwdev)2667{2668struct rtw_coex *coex = &rtwdev->coex;2669struct rtw_coex_stat *coex_stat = &coex->stat;2670struct rtw_coex_dm *coex_dm = &coex->dm;2671u8 i;26722673memset(coex_dm, 0, sizeof(*coex_dm));2674memset(coex_stat, 0, sizeof(*coex_stat));26752676for (i = 0; i < COEX_CNT_WL_MAX; i++)2677coex_stat->cnt_wl[i] = 0;26782679for (i = 0; i < COEX_CNT_BT_MAX; i++)2680coex_stat->cnt_bt[i] = 0;26812682for (i = 0; i < ARRAY_SIZE(coex_dm->bt_rssi_state); i++)2683coex_dm->bt_rssi_state[i] = COEX_RSSI_STATE_LOW;26842685for (i = 0; i < ARRAY_SIZE(coex_dm->wl_rssi_state); i++)2686coex_dm->wl_rssi_state[i] = COEX_RSSI_STATE_LOW;26872688coex_stat->wl_coex_mode = COEX_WLINK_MAX;2689coex_stat->wl_rx_rate = DESC_RATE5_5M;2690coex_stat->wl_rts_rx_rate = DESC_RATE5_5M;2691}26922693static void __rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)2694{2695struct rtw_coex *coex = &rtwdev->coex;2696struct rtw_coex_stat *coex_stat = &coex->stat;26972698rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);26992700rtw_coex_init_coex_var(rtwdev);27012702coex_stat->kt_ver = u8_get_bits(rtw_read8(rtwdev, 0xf1), GENMASK(7, 4));27032704rtw_coex_monitor_bt_enable(rtwdev);2705rtw_coex_wl_slot_extend(rtwdev, coex_stat->wl_slot_extend);27062707rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION);27082709rtw_coex_set_rfe_type(rtwdev);2710rtw_coex_set_init(rtwdev);27112712/* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */2713rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_RSP, 1);27142715/* set Tx beacon = Hi-Pri */2716rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_BEACON, 1);27172718/* set Tx beacon queue = Hi-Pri */2719rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_TX_BEACONQ, 1);27202721/* antenna config */2722if (coex->wl_rf_off) {2723rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF);2724rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false);2725coex->stop_dm = true;27262727rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): RF Off\n",2728__func__);2729} else if (wifi_only) {2730rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WONLY);2731rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF,2732true);2733coex->stop_dm = true;2734} else {2735rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_INIT);2736rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF,2737true);2738coex->stop_dm = false;2739coex->freeze = true;2740}27412742/* PTA parameter */2743rtw_coex_table(rtwdev, true, 1);2744rtw_coex_tdma(rtwdev, true, 0);2745rtw_coex_query_bt_info(rtwdev);2746}27472748void rtw_coex_power_on_setting(struct rtw_dev *rtwdev)2749{2750struct rtw_coex *coex = &rtwdev->coex;2751u8 table_case = 1;27522753rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);27542755coex->stop_dm = true;2756coex->wl_rf_off = false;27572758/* enable BB, we can write 0x948 */2759rtw_write8_set(rtwdev, REG_SYS_FUNC_EN,2760BIT_FEN_BB_GLB_RST | BIT_FEN_BB_RSTB);27612762rtw_coex_monitor_bt_enable(rtwdev);2763rtw_coex_set_rfe_type(rtwdev);27642765/* set antenna path to BT */2766rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_POWERON);27672768rtw_coex_table(rtwdev, true, table_case);2769/* red x issue */2770rtw_write8(rtwdev, 0xff1a, 0x0);2771rtw_coex_set_gnt_debug(rtwdev);2772}2773EXPORT_SYMBOL(rtw_coex_power_on_setting);27742775void rtw_coex_power_off_setting(struct rtw_dev *rtwdev)2776{2777rtw_write16(rtwdev, REG_WIFI_BT_INFO, BIT_BT_INT_EN);2778}2779EXPORT_SYMBOL(rtw_coex_power_off_setting);27802781void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only)2782{2783__rtw_coex_init_hw_config(rtwdev, wifi_only);2784}2785EXPORT_SYMBOL(rtw_coex_init_hw_config);27862787void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type)2788{2789struct rtw_coex *coex = &rtwdev->coex;2790struct rtw_coex_stat *coex_stat = &coex->stat;27912792if (coex->manual_control || coex->stop_dm)2793return;27942795if (type == COEX_IPS_ENTER) {2796rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], IPS ENTER notify\n");27972798coex_stat->wl_under_ips = true;27992800/* for lps off */2801rtw_coex_write_scbd(rtwdev, COEX_SCBD_ALL, false);28022803rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_WOFF);2804rtw_coex_action_coex_all_off(rtwdev);2805} else if (type == COEX_IPS_LEAVE) {2806rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], IPS LEAVE notify\n");28072808rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);2809/* run init hw config (exclude wifi only) */2810__rtw_coex_init_hw_config(rtwdev, false);28112812coex_stat->wl_under_ips = false;2813}2814}28152816void rtw_coex_lps_notify(struct rtw_dev *rtwdev, u8 type)2817{2818struct rtw_coex *coex = &rtwdev->coex;2819struct rtw_coex_stat *coex_stat = &coex->stat;28202821if (coex->manual_control || coex->stop_dm)2822return;28232824if (type == COEX_LPS_ENABLE) {2825rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], LPS ENABLE notify\n");28262827coex_stat->wl_under_lps = true;28282829if (coex_stat->wl_force_lps_ctrl) {2830/* for ps-tdma */2831rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);2832} else {2833/* for native ps */2834rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, false);2835rtw_coex_write_scbd(rtwdev, COEX_SCBD_WLBUSY, false);28362837rtw_coex_run_coex(rtwdev, COEX_RSN_LPS);2838}2839} else if (type == COEX_LPS_DISABLE) {2840rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], LPS DISABLE notify\n");28412842coex_stat->wl_under_lps = false;28432844/* for lps off */2845rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);28462847if (!coex_stat->wl_force_lps_ctrl)2848rtw_coex_query_bt_info(rtwdev);28492850rtw_coex_run_coex(rtwdev, COEX_RSN_LPS);2851}2852}28532854void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type)2855{2856struct rtw_coex *coex = &rtwdev->coex;2857struct rtw_coex_stat *coex_stat = &coex->stat;28582859if (coex->manual_control || coex->stop_dm)2860return;28612862coex->freeze = false;2863rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);28642865if (type == COEX_SCAN_START_5G) {2866rtw_dbg(rtwdev, RTW_DBG_COEX,2867"[BTCoex], SCAN START notify (5G)\n");28682869rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);2870rtw_coex_run_coex(rtwdev, COEX_RSN_5GSCANSTART);2871} else if ((type == COEX_SCAN_START_2G) || (type == COEX_SCAN_START)) {2872rtw_dbg(rtwdev, RTW_DBG_COEX,2873"[BTCoex], SCAN START notify (2G)\n");28742875coex_stat->wl_hi_pri_task2 = true;28762877/* Force antenna setup for no scan result issue */2878rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);2879rtw_coex_run_coex(rtwdev, COEX_RSN_2GSCANSTART);2880} else {2881coex_stat->cnt_wl[COEX_CNT_WL_SCANAP] = 30; /* To do */28822883rtw_dbg(rtwdev, RTW_DBG_COEX,2884"[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n",2885coex_stat->cnt_wl[COEX_CNT_WL_SCANAP]);28862887coex_stat->wl_hi_pri_task2 = false;2888rtw_coex_run_coex(rtwdev, COEX_RSN_SCANFINISH);2889}2890}28912892void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type)2893{2894struct rtw_coex *coex = &rtwdev->coex;28952896if (coex->manual_control || coex->stop_dm)2897return;28982899if (type == COEX_SWITCH_TO_5G) {2900rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): TO_5G\n",2901__func__);2902} else if (type == COEX_SWITCH_TO_24G_NOFORSCAN) {2903rtw_dbg(rtwdev, RTW_DBG_COEX,2904"[BTCoex], %s(): TO_24G_NOFORSCAN\n", __func__);2905} else {2906rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): TO_2G\n",2907__func__);2908}29092910if (type == COEX_SWITCH_TO_5G)2911rtw_coex_run_coex(rtwdev, COEX_RSN_5GSWITCHBAND);2912else if (type == COEX_SWITCH_TO_24G_NOFORSCAN)2913rtw_coex_run_coex(rtwdev, COEX_RSN_2GSWITCHBAND);2914else2915rtw_coex_scan_notify(rtwdev, COEX_SCAN_START_2G);2916}29172918void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type)2919{2920struct rtw_coex *coex = &rtwdev->coex;2921struct rtw_coex_stat *coex_stat = &coex->stat;29222923if (coex->manual_control || coex->stop_dm)2924return;29252926rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE | COEX_SCBD_ONOFF, true);29272928if (type == COEX_ASSOCIATE_5G_START) {2929rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 5G start\n",2930__func__);29312932rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);2933rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONSTART);2934} else if (type == COEX_ASSOCIATE_5G_FINISH) {2935rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 5G finish\n",2936__func__);29372938rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);2939rtw_coex_run_coex(rtwdev, COEX_RSN_5GCONFINISH);2940} else if (type == COEX_ASSOCIATE_START) {2941coex_stat->wl_hi_pri_task1 = true;2942coex_stat->wl_connecting = true;2943coex_stat->cnt_wl[COEX_CNT_WL_CONNPKT] = 2;2944coex_stat->wl_connecting = true;2945ieee80211_queue_delayed_work(rtwdev->hw,2946&coex->wl_connecting_work, 2 * HZ);29472948rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 2G start\n",2949__func__);2950/* Force antenna setup for no scan result issue */2951rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);29522953rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONSTART);29542955/* To keep TDMA case during connect process,2956* to avoid changed by Btinfo and runcoexmechanism2957*/2958coex->freeze = true;2959ieee80211_queue_delayed_work(rtwdev->hw, &coex->defreeze_work,29605 * HZ);2961} else {2962coex_stat->wl_hi_pri_task1 = false;2963coex->freeze = false;2964coex_stat->wl_connecting = false;29652966rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 2G finish\n",2967__func__);2968rtw_coex_run_coex(rtwdev, COEX_RSN_2GCONFINISH);2969}2970}29712972void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type)2973{2974struct rtw_coex *coex = &rtwdev->coex;2975struct rtw_coex_stat *coex_stat = &coex->stat;29762977if (coex->manual_control || coex->stop_dm)2978return;29792980if (type == COEX_MEDIA_CONNECT_5G) {2981rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 5G\n", __func__);29822983rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);29842985rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_5G);2986rtw_coex_run_coex(rtwdev, COEX_RSN_5GMEDIA);2987} else if (type == COEX_MEDIA_CONNECT) {2988rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): 2G\n", __func__);29892990coex_stat->wl_connecting = false;29912992rtw_coex_write_scbd(rtwdev, COEX_SCBD_ACTIVE, true);29932994/* Force antenna setup for no scan result issue */2995rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G);29962997/* Set CCK Rx high Pri */2998rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 1);2999rtw_coex_run_coex(rtwdev, COEX_RSN_2GMEDIA);3000} else {3001rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s(): disconnect!!\n",3002__func__);3003rtw_coex_set_wl_pri_mask(rtwdev, COEX_WLPRI_RX_CCK, 0);3004rtw_coex_run_coex(rtwdev, COEX_RSN_MEDIADISCON);3005}30063007rtw_coex_update_wl_ch_info(rtwdev, type);3008}30093010void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)3011{3012const struct rtw_chip_info *chip = rtwdev->chip;3013struct rtw_coex *coex = &rtwdev->coex;3014struct rtw_coex_stat *coex_stat = &coex->stat;3015struct rtw_coex_dm *coex_dm = &coex->dm;3016u32 bt_relink_time;3017u8 i, rsp_source = 0, type;3018bool inq_page = false;30193020rsp_source = buf[0] & 0xf;3021if (rsp_source >= COEX_BTINFO_SRC_MAX)3022return;3023coex_stat->cnt_bt_info_c2h[rsp_source]++;30243025if (rsp_source == COEX_BTINFO_SRC_BT_IQK) {3026coex_stat->bt_iqk_state = buf[1];3027if (coex_stat->bt_iqk_state == 0)3028coex_stat->cnt_bt[COEX_CNT_BT_IQK]++;3029else if (coex_stat->bt_iqk_state == 2)3030coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]++;30313032rtw_dbg(rtwdev, RTW_DBG_COEX,3033"[BTCoex], BT IQK by bt_info, data0 = 0x%02x\n",3034buf[1]);30353036return;3037}30383039if (rsp_source == COEX_BTINFO_SRC_BT_SCBD) {3040rtw_dbg(rtwdev, RTW_DBG_COEX,3041"[BTCoex], BT Scoreboard change notify by WL FW c2h, 0xaa = 0x%02x, 0xab = 0x%02x\n",3042buf[1], buf[2]);30433044rtw_coex_monitor_bt_enable(rtwdev);3045if (coex_stat->bt_disabled != coex_stat->bt_disabled_pre) {3046coex_stat->bt_disabled_pre = coex_stat->bt_disabled;3047rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);3048}3049return;3050}30513052if (rsp_source == COEX_BTINFO_SRC_H2C60) {3053rtw_dbg(rtwdev, RTW_DBG_COEX,3054"[BTCoex], H2C 0x60 content replied by WL FW: H2C_0x60 = [%02x %02x %02x %02x %02x]\n",3055buf[1], buf[2], buf[3], buf[4], buf[5]);30563057for (i = 1; i <= COEX_WL_TDMA_PARA_LENGTH; i++)3058coex_dm->fw_tdma_para[i - 1] = buf[i];3059return;3060}30613062if (rsp_source == COEX_BTINFO_SRC_WL_FW) {3063rtw_dbg(rtwdev, RTW_DBG_COEX,3064"[BTCoex], bt_info reply by WL FW\n");30653066rtw_coex_update_bt_link_info(rtwdev);3067return;3068}30693070if (rsp_source == COEX_BTINFO_SRC_BT_RSP ||3071rsp_source == COEX_BTINFO_SRC_BT_ACT) {3072if (coex_stat->bt_disabled) {3073coex_stat->bt_disabled = false;3074coex_stat->bt_reenable = true;3075ieee80211_queue_delayed_work(rtwdev->hw,3076&coex->bt_reenable_work,307715 * HZ);3078rtw_dbg(rtwdev, RTW_DBG_COEX,3079"[BTCoex], BT enable detected by bt_info\n");3080}3081}30823083if (length != COEX_BTINFO_LENGTH) {3084rtw_dbg(rtwdev, RTW_DBG_COEX,3085"[BTCoex], Bt_info length = %d invalid!!\n", length);30863087return;3088}30893090rtw_dbg(rtwdev, RTW_DBG_COEX,3091"[BTCoex], Bt_info[%d], len=%d, data=[%02x %02x %02x %02x %02x %02x]\n",3092buf[0], length, buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);30933094for (i = 0; i < COEX_BTINFO_LENGTH; i++)3095coex_stat->bt_info_c2h[rsp_source][i] = buf[i];30963097/* get the same info from bt, skip it */3098if (coex_stat->bt_info_c2h[rsp_source][1] == coex_stat->bt_info_lb2 &&3099coex_stat->bt_info_c2h[rsp_source][2] == coex_stat->bt_info_lb3 &&3100coex_stat->bt_info_c2h[rsp_source][3] == coex_stat->bt_info_hb0 &&3101coex_stat->bt_info_c2h[rsp_source][4] == coex_stat->bt_info_hb1 &&3102coex_stat->bt_info_c2h[rsp_source][5] == coex_stat->bt_info_hb2 &&3103coex_stat->bt_info_c2h[rsp_source][6] == coex_stat->bt_info_hb3) {3104rtw_dbg(rtwdev, RTW_DBG_COEX,3105"[BTCoex], Return because Btinfo duplicate!!\n");3106return;3107}31083109coex_stat->bt_info_lb2 = coex_stat->bt_info_c2h[rsp_source][1];3110coex_stat->bt_info_lb3 = coex_stat->bt_info_c2h[rsp_source][2];3111coex_stat->bt_info_hb0 = coex_stat->bt_info_c2h[rsp_source][3];3112coex_stat->bt_info_hb1 = coex_stat->bt_info_c2h[rsp_source][4];3113coex_stat->bt_info_hb2 = coex_stat->bt_info_c2h[rsp_source][5];3114coex_stat->bt_info_hb3 = coex_stat->bt_info_c2h[rsp_source][6];31153116/* 0xff means BT is under WHCK test */3117coex_stat->bt_whck_test = (coex_stat->bt_info_lb2 == 0xff);31183119inq_page = ((coex_stat->bt_info_lb2 & BIT(2)) == BIT(2));31203121if (inq_page != coex_stat->bt_inq_page) {3122cancel_delayed_work_sync(&coex->bt_remain_work);3123coex_stat->bt_inq_page = inq_page;31243125if (inq_page)3126coex_stat->bt_inq_remain = true;3127else3128ieee80211_queue_delayed_work(rtwdev->hw,3129&coex->bt_remain_work,31304 * HZ);3131}3132coex_stat->bt_acl_busy = ((coex_stat->bt_info_lb2 & BIT(3)) == BIT(3));3133if (chip->ble_hid_profile_support) {3134if (coex_stat->bt_info_lb2 & BIT(5)) {3135if (coex_stat->bt_info_hb1 & BIT(0)) {3136/*BLE HID*/3137coex_stat->bt_ble_hid_exist = true;3138} else {3139coex_stat->bt_ble_hid_exist = false;3140}3141coex_stat->bt_ble_exist = false;3142} else if (coex_stat->bt_info_hb1 & BIT(0)) {3143/*RCU*/3144coex_stat->bt_ble_hid_exist = false;3145coex_stat->bt_ble_exist = true;3146} else {3147coex_stat->bt_ble_hid_exist = false;3148coex_stat->bt_ble_exist = false;3149}3150} else {3151if (coex_stat->bt_info_hb1 & BIT(0)) {3152if (coex_stat->bt_hid_slot == 1 &&3153coex_stat->hi_pri_rx + 100 < coex_stat->hi_pri_tx &&3154coex_stat->hi_pri_rx < 100) {3155coex_stat->bt_ble_hid_exist = true;3156coex_stat->bt_ble_exist = false;3157} else {3158coex_stat->bt_ble_hid_exist = false;3159coex_stat->bt_ble_exist = true;3160}3161} else {3162coex_stat->bt_ble_hid_exist = false;3163coex_stat->bt_ble_exist = false;3164}3165}31663167coex_stat->cnt_bt[COEX_CNT_BT_RETRY] = coex_stat->bt_info_lb3 & 0xf;3168if (coex_stat->cnt_bt[COEX_CNT_BT_RETRY] >= 1)3169coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]++;31703171coex_stat->bt_fix_2M = ((coex_stat->bt_info_lb3 & BIT(4)) == BIT(4));3172coex_stat->bt_inq = ((coex_stat->bt_info_lb3 & BIT(5)) == BIT(5));3173if (coex_stat->bt_inq)3174coex_stat->cnt_bt[COEX_CNT_BT_INQ]++;31753176coex_stat->bt_page = ((coex_stat->bt_info_lb3 & BIT(7)) == BIT(7));3177if (coex_stat->bt_page)3178coex_stat->cnt_bt[COEX_CNT_BT_PAGE]++;31793180/* unit: % (value-100 to translate to unit: dBm in coex info) */3181if (chip->bt_rssi_type == COEX_BTRSSI_RATIO) {3182coex_stat->bt_rssi = coex_stat->bt_info_hb0 * 2 + 10;3183} else {3184if (coex_stat->bt_info_hb0 <= 127)3185coex_stat->bt_rssi = 100;3186else if (256 - coex_stat->bt_info_hb0 <= 100)3187coex_stat->bt_rssi = 100 - (256 - coex_stat->bt_info_hb0);3188else3189coex_stat->bt_rssi = 0;3190}31913192if (coex_stat->bt_info_hb1 & BIT(1))3193coex_stat->cnt_bt[COEX_CNT_BT_REINIT]++;31943195if (coex_stat->bt_info_hb1 & BIT(2)) {3196coex_stat->cnt_bt[COEX_CNT_BT_SETUPLINK]++;3197coex_stat->bt_setup_link = true;3198if (coex_stat->bt_reenable)3199bt_relink_time = 6 * HZ;3200else3201bt_relink_time = 1 * HZ;32023203ieee80211_queue_delayed_work(rtwdev->hw,3204&coex->bt_relink_work,3205bt_relink_time);32063207rtw_dbg(rtwdev, RTW_DBG_COEX,3208"[BTCoex], Re-Link start in BT info!!\n");3209}32103211if (coex_stat->bt_info_hb1 & BIT(3))3212coex_stat->cnt_bt[COEX_CNT_BT_IGNWLANACT]++;32133214coex_stat->bt_ble_voice = ((coex_stat->bt_info_hb1 & BIT(4)) == BIT(4));3215coex_stat->bt_ble_scan_en = ((coex_stat->bt_info_hb1 & BIT(5)) == BIT(5));3216if (coex_stat->bt_info_hb1 & BIT(6))3217coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH]++;32183219coex_stat->bt_multi_link = ((coex_stat->bt_info_hb1 & BIT(7)) == BIT(7));3220/* for multi_link = 0 but bt pkt remain exist */3221/* Use PS-TDMA to protect WL RX */3222if (!coex_stat->bt_multi_link && coex_stat->bt_multi_link_pre) {3223coex_stat->bt_multi_link_remain = true;3224ieee80211_queue_delayed_work(rtwdev->hw,3225&coex->bt_multi_link_remain_work,32263 * HZ);3227}3228coex_stat->bt_multi_link_pre = coex_stat->bt_multi_link;32293230/* resend wifi info to bt, it is reset and lost the info */3231if (coex_stat->bt_info_hb1 & BIT(1)) {3232rtw_dbg(rtwdev, RTW_DBG_COEX,3233"[BTCoex], BT Re-init, send wifi BW & Chnl to BT!!\n");32343235if (coex_stat->wl_connected)3236type = COEX_MEDIA_CONNECT;3237else3238type = COEX_MEDIA_DISCONNECT;3239rtw_coex_update_wl_ch_info(rtwdev, type);3240}32413242/* if ignore_wlan_act && not set_up_link */3243if ((coex_stat->bt_info_hb1 & BIT(3)) &&3244(!(coex_stat->bt_info_hb1 & BIT(2)))) {3245rtw_dbg(rtwdev, RTW_DBG_COEX,3246"[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n");3247rtw_coex_ignore_wlan_act(rtwdev, false);3248}32493250coex_stat->bt_opp_exist = ((coex_stat->bt_info_hb2 & BIT(0)) == BIT(0));3251if (coex_stat->bt_info_hb2 & BIT(1))3252coex_stat->cnt_bt[COEX_CNT_BT_AFHUPDATE]++;32533254coex_stat->bt_a2dp_active = (coex_stat->bt_info_hb2 & BIT(2)) == BIT(2);3255coex_stat->bt_slave = ((coex_stat->bt_info_hb2 & BIT(3)) == BIT(3));3256coex_stat->bt_hid_slot = (coex_stat->bt_info_hb2 & 0x30) >> 4;3257coex_stat->bt_hid_pair_num = (coex_stat->bt_info_hb2 & 0xc0) >> 6;3258if (coex_stat->bt_hid_pair_num > 0 && coex_stat->bt_hid_slot >= 2)3259coex_stat->bt_418_hid_exist = true;3260else if (coex_stat->bt_hid_pair_num == 0 || coex_stat->bt_hid_slot == 1)3261coex_stat->bt_418_hid_exist = false;32623263if ((coex_stat->bt_info_lb2 & 0x49) == 0x49)3264coex_stat->bt_a2dp_bitpool = (coex_stat->bt_info_hb3 & 0x7f);3265else3266coex_stat->bt_a2dp_bitpool = 0;32673268coex_stat->bt_a2dp_sink = ((coex_stat->bt_info_hb3 & BIT(7)) == BIT(7));32693270rtw_coex_update_bt_link_info(rtwdev);3271rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);3272}32733274#define COEX_BT_HIDINFO_MTK 0x463275static const u8 coex_bt_hidinfo_ps[] = {0x57, 0x69, 0x72};3276static const u8 coex_bt_hidinfo_xb[] = {0x58, 0x62, 0x6f};32773278void rtw_coex_bt_hid_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)3279{3280const struct rtw_chip_info *chip = rtwdev->chip;3281struct rtw_coex *coex = &rtwdev->coex;3282struct rtw_coex_stat *coex_stat = &coex->stat;3283struct rtw_coex_hid *hidinfo;3284struct rtw_coex_hid_info_a *hida;3285struct rtw_coex_hid_handle_list *hl, *bhl;3286u8 sub_id = buf[2], gamehid_cnt = 0, handle, i;3287bool cur_game_hid_exist, complete;32883289if (!chip->wl_mimo_ps_support &&3290(sub_id == COEX_BT_HIDINFO_LIST || sub_id == COEX_BT_HIDINFO_A))3291return;32923293rtw_dbg(rtwdev, RTW_DBG_COEX,3294"[BTCoex], HID info notify, sub_id = 0x%x\n", sub_id);32953296switch (sub_id) {3297case COEX_BT_HIDINFO_LIST:3298hl = &coex_stat->hid_handle_list;3299bhl = (struct rtw_coex_hid_handle_list *)buf;3300if (!memcmp(hl, bhl, sizeof(*hl)))3301return;3302coex_stat->hid_handle_list = *bhl;3303memset(&coex_stat->hid_info, 0, sizeof(coex_stat->hid_info));3304for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {3305hidinfo = &coex_stat->hid_info[i];3306if (hl->handle[i] != COEX_BT_HIDINFO_NOTCON &&3307hl->handle[i] != 0)3308hidinfo->hid_handle = hl->handle[i];3309}3310break;3311case COEX_BT_HIDINFO_A:3312hida = (struct rtw_coex_hid_info_a *)buf;3313handle = hida->handle;3314for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {3315hidinfo = &coex_stat->hid_info[i];3316if (hidinfo->hid_handle == handle) {3317hidinfo->hid_vendor = hida->vendor;3318memcpy(hidinfo->hid_name, hida->name,3319sizeof(hidinfo->hid_name));3320hidinfo->hid_info_completed = true;3321break;3322}3323}3324break;3325}3326for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {3327hidinfo = &coex_stat->hid_info[i];3328complete = hidinfo->hid_info_completed;3329handle = hidinfo->hid_handle;3330if (!complete || handle == COEX_BT_HIDINFO_NOTCON ||3331handle == 0 || handle >= COEX_BT_BLE_HANDLE_THRS) {3332hidinfo->is_game_hid = false;3333continue;3334}33353336if (hidinfo->hid_vendor == COEX_BT_HIDINFO_MTK) {3337if ((memcmp(hidinfo->hid_name,3338coex_bt_hidinfo_ps,3339COEX_BT_HIDINFO_NAME)) == 0)3340hidinfo->is_game_hid = true;3341else if ((memcmp(hidinfo->hid_name,3342coex_bt_hidinfo_xb,3343COEX_BT_HIDINFO_NAME)) == 0)3344hidinfo->is_game_hid = true;3345else3346hidinfo->is_game_hid = false;3347} else {3348hidinfo->is_game_hid = false;3349}3350if (hidinfo->is_game_hid)3351gamehid_cnt++;3352}33533354if (gamehid_cnt > 0)3355cur_game_hid_exist = true;3356else3357cur_game_hid_exist = false;33583359if (cur_game_hid_exist != coex_stat->bt_game_hid_exist) {3360coex_stat->bt_game_hid_exist = cur_game_hid_exist;3361rtw_dbg(rtwdev, RTW_DBG_COEX,3362"[BTCoex], HID info changed!bt_game_hid_exist = %d!\n",3363coex_stat->bt_game_hid_exist);3364rtw_coex_run_coex(rtwdev, COEX_RSN_BTSTATUS);3365}3366}33673368void rtw_coex_query_bt_hid_list(struct rtw_dev *rtwdev)3369{3370const struct rtw_chip_info *chip = rtwdev->chip;3371struct rtw_coex *coex = &rtwdev->coex;3372struct rtw_coex_stat *coex_stat = &coex->stat;3373struct rtw_coex_hid *hidinfo;3374u8 i, handle;3375bool complete;33763377if (!chip->wl_mimo_ps_support || coex_stat->wl_under_ips ||3378(coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl))3379return;33803381if (!coex_stat->bt_hid_exist &&3382!((coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION) &&3383(coex_stat->hi_pri_tx + coex_stat->hi_pri_rx >3384COEX_BT_GAMEHID_CNT)))3385return;33863387rtw_fw_coex_query_hid_info(rtwdev, COEX_BT_HIDINFO_LIST, 0);33883389for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {3390hidinfo = &coex_stat->hid_info[i];3391complete = hidinfo->hid_info_completed;3392handle = hidinfo->hid_handle;3393if (handle == 0 || handle == COEX_BT_HIDINFO_NOTCON ||3394handle >= COEX_BT_BLE_HANDLE_THRS || complete)3395continue;33963397rtw_fw_coex_query_hid_info(rtwdev,3398COEX_BT_HIDINFO_A,3399handle);3400}3401}34023403void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)3404{3405struct rtw_coex *coex = &rtwdev->coex;3406struct rtw_coex_stat *coex_stat = &coex->stat;3407u8 val;3408int i;34093410rtw_dbg(rtwdev, RTW_DBG_COEX,3411"[BTCoex], WiFi Fw Dbg info = %8ph (len = %d)\n",3412buf, length);3413if (WARN(length < 8, "invalid wl info c2h length\n"))3414return;34153416if (buf[0] != 0x08)3417return;34183419for (i = 1; i < 8; i++) {3420val = coex_stat->wl_fw_dbg_info_pre[i];3421if (buf[i] >= val)3422coex_stat->wl_fw_dbg_info[i] = buf[i] - val;3423else3424coex_stat->wl_fw_dbg_info[i] = 255 - val + buf[i];34253426coex_stat->wl_fw_dbg_info_pre[i] = buf[i];3427}34283429coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]++;3430rtw_coex_wl_ccklock_action(rtwdev);3431rtw_coex_wl_ccklock_detect(rtwdev);3432}34333434void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type)3435{3436rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);3437}34383439void rtw_coex_wl_status_check(struct rtw_dev *rtwdev)3440{3441struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;34423443if ((coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl) ||3444coex_stat->wl_under_ips)3445return;34463447rtw_coex_monitor_bt_ctr(rtwdev);3448}34493450void rtw_coex_bt_relink_work(struct work_struct *work)3451{3452struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,3453coex.bt_relink_work.work);3454struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;34553456mutex_lock(&rtwdev->mutex);3457coex_stat->bt_setup_link = false;3458rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);3459mutex_unlock(&rtwdev->mutex);3460}34613462void rtw_coex_bt_reenable_work(struct work_struct *work)3463{3464struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,3465coex.bt_reenable_work.work);3466struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;34673468mutex_lock(&rtwdev->mutex);3469coex_stat->bt_reenable = false;3470mutex_unlock(&rtwdev->mutex);3471}34723473void rtw_coex_defreeze_work(struct work_struct *work)3474{3475struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,3476coex.defreeze_work.work);3477struct rtw_coex *coex = &rtwdev->coex;3478struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;34793480mutex_lock(&rtwdev->mutex);3481coex->freeze = false;3482coex_stat->wl_hi_pri_task1 = false;3483rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);3484mutex_unlock(&rtwdev->mutex);3485}34863487void rtw_coex_wl_remain_work(struct work_struct *work)3488{3489struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,3490coex.wl_remain_work.work);3491struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;34923493mutex_lock(&rtwdev->mutex);3494coex_stat->wl_gl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags);3495rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);3496mutex_unlock(&rtwdev->mutex);3497}34983499void rtw_coex_bt_remain_work(struct work_struct *work)3500{3501struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,3502coex.bt_remain_work.work);3503struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;35043505mutex_lock(&rtwdev->mutex);3506coex_stat->bt_inq_remain = coex_stat->bt_inq_page;3507rtw_coex_run_coex(rtwdev, COEX_RSN_BTSTATUS);3508mutex_unlock(&rtwdev->mutex);3509}35103511void rtw_coex_wl_connecting_work(struct work_struct *work)3512{3513struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,3514coex.wl_connecting_work.work);3515struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;35163517mutex_lock(&rtwdev->mutex);3518coex_stat->wl_connecting = false;3519rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], WL connecting stop!!\n");3520rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);3521mutex_unlock(&rtwdev->mutex);3522}35233524void rtw_coex_bt_multi_link_remain_work(struct work_struct *work)3525{3526struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,3527coex.bt_multi_link_remain_work.work);3528struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;35293530mutex_lock(&rtwdev->mutex);3531coex_stat->bt_multi_link_remain = false;3532mutex_unlock(&rtwdev->mutex);3533}35343535void rtw_coex_wl_ccklock_work(struct work_struct *work)3536{3537struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,3538coex.wl_ccklock_work.work);3539struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;35403541mutex_lock(&rtwdev->mutex);3542coex_stat->wl_cck_lock = false;3543mutex_unlock(&rtwdev->mutex);3544}35453546#ifdef CONFIG_RTW88_DEBUGFS3547#define INFO_SIZE 8035483549#define case_BTINFO(src) \3550case COEX_BTINFO_SRC_##src: return #src35513552static const char *rtw_coex_get_bt_info_src_string(u8 bt_info_src)3553{3554switch (bt_info_src) {3555case_BTINFO(WL_FW);3556case_BTINFO(BT_RSP);3557case_BTINFO(BT_ACT);3558default:3559return "Unknown";3560}3561}35623563#define case_RSN(src) \3564case COEX_RSN_##src: return #src35653566static const char *rtw_coex_get_reason_string(u8 reason)3567{3568switch (reason) {3569case_RSN(2GSCANSTART);3570case_RSN(5GSCANSTART);3571case_RSN(SCANFINISH);3572case_RSN(2GSWITCHBAND);3573case_RSN(5GSWITCHBAND);3574case_RSN(2GCONSTART);3575case_RSN(5GCONSTART);3576case_RSN(2GCONFINISH);3577case_RSN(5GCONFINISH);3578case_RSN(2GMEDIA);3579case_RSN(5GMEDIA);3580case_RSN(MEDIADISCON);3581case_RSN(BTINFO);3582case_RSN(LPS);3583case_RSN(WLSTATUS);3584default:3585return "Unknown";3586}3587}35883589static u8 rtw_coex_get_table_index(struct rtw_dev *rtwdev, u32 wl_reg_6c0,3590u32 wl_reg_6c4)3591{3592const struct rtw_chip_info *chip = rtwdev->chip;3593struct rtw_efuse *efuse = &rtwdev->efuse;3594u8 ans = 0xFF;3595u8 n, i;3596u32 load_bt_val;3597u32 load_wl_val;3598bool share_ant = efuse->share_ant;35993600if (share_ant)3601n = chip->table_sant_num;3602else3603n = chip->table_nsant_num;36043605for (i = 0; i < n; i++) {3606if (share_ant) {3607load_bt_val = chip->table_sant[i].bt;3608load_wl_val = chip->table_sant[i].wl;3609} else {3610load_bt_val = chip->table_nsant[i].bt;3611load_wl_val = chip->table_nsant[i].wl;3612}36133614if (wl_reg_6c0 == load_bt_val &&3615wl_reg_6c4 == load_wl_val) {3616ans = i;3617if (!share_ant)3618ans += 100;3619break;3620}3621}36223623return ans;3624}36253626static u8 rtw_coex_get_tdma_index(struct rtw_dev *rtwdev, u8 *tdma_para)3627{3628const struct rtw_chip_info *chip = rtwdev->chip;3629struct rtw_efuse *efuse = &rtwdev->efuse;3630u8 ans = 0xFF;3631u8 n, i, j;3632u8 load_cur_tab_val;3633bool valid = false;3634bool share_ant = efuse->share_ant;36353636if (share_ant)3637n = chip->tdma_sant_num;3638else3639n = chip->tdma_nsant_num;36403641for (i = 0; i < n; i++) {3642valid = false;3643for (j = 0; j < 5; j++) {3644if (share_ant)3645load_cur_tab_val = chip->tdma_sant[i].para[j];3646else3647load_cur_tab_val = chip->tdma_nsant[i].para[j];36483649if (*(tdma_para + j) != load_cur_tab_val)3650break;36513652if (j == 4)3653valid = true;3654}3655if (valid) {3656ans = i;3657break;3658}3659}36603661return ans;3662}36633664static int rtw_coex_addr_info(struct rtw_dev *rtwdev,3665const struct rtw_reg_domain *reg,3666char addr_info[], int n)3667{3668const char *rf_prefix = "";3669const char *sep = n == 0 ? "" : "/ ";3670int ffs, fls;3671int max_fls;36723673if (INFO_SIZE - n <= 0)3674return 0;36753676switch (reg->domain) {3677case RTW_REG_DOMAIN_MAC32:3678max_fls = 31;3679break;3680case RTW_REG_DOMAIN_MAC16:3681max_fls = 15;3682break;3683case RTW_REG_DOMAIN_MAC8:3684max_fls = 7;3685break;3686case RTW_REG_DOMAIN_RF_A:3687case RTW_REG_DOMAIN_RF_B:3688rf_prefix = "RF_";3689max_fls = 19;3690break;3691default:3692return 0;3693}36943695ffs = __ffs(reg->mask);3696fls = __fls(reg->mask);36973698if (ffs == 0 && fls == max_fls)3699return scnprintf(addr_info + n, INFO_SIZE - n, "%s%s%x",3700sep, rf_prefix, reg->addr);3701else if (ffs == fls)3702return scnprintf(addr_info + n, INFO_SIZE - n, "%s%s%x[%d]",3703sep, rf_prefix, reg->addr, ffs);3704else3705return scnprintf(addr_info + n, INFO_SIZE - n, "%s%s%x[%d:%d]",3706sep, rf_prefix, reg->addr, fls, ffs);3707}37083709static int rtw_coex_val_info(struct rtw_dev *rtwdev,3710const struct rtw_reg_domain *reg,3711char val_info[], int n)3712{3713const char *sep = n == 0 ? "" : "/ ";3714u8 rf_path;37153716if (INFO_SIZE - n <= 0)3717return 0;37183719switch (reg->domain) {3720case RTW_REG_DOMAIN_MAC32:3721return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,3722rtw_read32_mask(rtwdev, reg->addr, reg->mask));3723case RTW_REG_DOMAIN_MAC16:3724return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,3725rtw_read16_mask(rtwdev, reg->addr, reg->mask));3726case RTW_REG_DOMAIN_MAC8:3727return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,3728rtw_read8_mask(rtwdev, reg->addr, reg->mask));3729case RTW_REG_DOMAIN_RF_A:3730rf_path = RF_PATH_A;3731break;3732case RTW_REG_DOMAIN_RF_B:3733rf_path = RF_PATH_B;3734break;3735default:3736return 0;3737}37383739/* only RF go through here */3740return scnprintf(val_info + n, INFO_SIZE - n, "%s0x%x", sep,3741rtw_read_rf(rtwdev, rf_path, reg->addr, reg->mask));3742}37433744static void rtw_coex_set_coexinfo_hw(struct rtw_dev *rtwdev, struct seq_file *m)3745{3746const struct rtw_chip_info *chip = rtwdev->chip;3747const struct rtw_reg_domain *reg;3748char addr_info[INFO_SIZE];3749int n_addr = 0;3750char val_info[INFO_SIZE];3751int n_val = 0;3752int i;37533754for (i = 0; i < chip->coex_info_hw_regs_num; i++) {3755reg = &chip->coex_info_hw_regs[i];37563757n_addr += rtw_coex_addr_info(rtwdev, reg, addr_info, n_addr);3758n_val += rtw_coex_val_info(rtwdev, reg, val_info, n_val);37593760if (reg->domain == RTW_REG_DOMAIN_NL) {3761seq_printf(m, "%-40s = %s\n", addr_info, val_info);3762n_addr = 0;3763n_val = 0;3764}3765}37663767if (n_addr != 0 && n_val != 0)3768seq_printf(m, "%-40s = %s\n", addr_info, val_info);3769}37703771static bool rtw_coex_get_bt_reg(struct rtw_dev *rtwdev,3772u8 type, u16 addr, u16 *val)3773{3774struct rtw_coex_info_req req = {0};3775struct sk_buff *skb;3776__le16 le_addr;3777u8 *payload;37783779le_addr = cpu_to_le16(addr);3780req.op_code = BT_MP_INFO_OP_READ_REG;3781req.para1 = type;3782req.para2 = le16_get_bits(le_addr, GENMASK(7, 0));3783req.para3 = le16_get_bits(le_addr, GENMASK(15, 8));3784skb = rtw_coex_info_request(rtwdev, &req);3785if (!skb) {3786*val = 0xeaea;3787return false;3788}37893790payload = get_payload_from_coex_resp(skb);3791*val = GET_COEX_RESP_BT_REG_VAL(payload);3792dev_kfree_skb_any(skb);37933794return true;3795}37963797static bool rtw_coex_get_bt_patch_version(struct rtw_dev *rtwdev,3798u32 *patch_version)3799{3800struct rtw_coex_info_req req = {0};3801struct sk_buff *skb;3802u8 *payload;38033804req.op_code = BT_MP_INFO_OP_PATCH_VER;3805skb = rtw_coex_info_request(rtwdev, &req);3806if (!skb)3807return false;38083809payload = get_payload_from_coex_resp(skb);3810*patch_version = GET_COEX_RESP_BT_PATCH_VER(payload);3811dev_kfree_skb_any(skb);38123813return true;3814}38153816static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev,3817u32 *supported_version)3818{3819struct rtw_coex_info_req req = {0};3820struct sk_buff *skb;3821u8 *payload;38223823req.op_code = BT_MP_INFO_OP_SUPP_VER;3824skb = rtw_coex_info_request(rtwdev, &req);3825if (!skb)3826return false;38273828payload = get_payload_from_coex_resp(skb);3829*supported_version = GET_COEX_RESP_BT_SUPP_VER(payload);3830dev_kfree_skb_any(skb);38313832return true;3833}38343835static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev,3836u32 *supported_feature)3837{3838struct rtw_coex_info_req req = {0};3839struct sk_buff *skb;3840u8 *payload;38413842req.op_code = BT_MP_INFO_OP_SUPP_FEAT;3843skb = rtw_coex_info_request(rtwdev, &req);3844if (!skb)3845return false;38463847payload = get_payload_from_coex_resp(skb);3848*supported_feature = GET_COEX_RESP_BT_SUPP_FEAT(payload);3849dev_kfree_skb_any(skb);38503851return true;3852}38533854struct rtw_coex_sta_stat_iter_data {3855struct rtw_vif *rtwvif;3856struct seq_file *file;3857};38583859static void rtw_coex_sta_stat_iter(void *data, struct ieee80211_sta *sta)3860{3861struct rtw_coex_sta_stat_iter_data *sta_iter_data = data;3862struct rtw_vif *rtwvif = sta_iter_data->rtwvif;3863struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;3864struct seq_file *m = sta_iter_data->file;3865struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);3866u8 rssi;38673868if (si->vif != vif)3869return;38703871rssi = ewma_rssi_read(&si->avg_rssi);3872seq_printf(m, "\tPeer %3d\n", si->mac_id);3873seq_printf(m, "\t\t%-24s = %d\n", "RSSI", rssi);3874seq_printf(m, "\t\t%-24s = %d\n", "BW mode", si->bw_mode);3875}38763877struct rtw_coex_vif_stat_iter_data {3878struct rtw_dev *rtwdev;3879struct seq_file *file;3880};38813882static void rtw_coex_vif_stat_iter(void *data, u8 *mac,3883struct ieee80211_vif *vif)3884{3885struct rtw_coex_vif_stat_iter_data *vif_iter_data = data;3886struct rtw_coex_sta_stat_iter_data sta_iter_data;3887struct rtw_dev *rtwdev = vif_iter_data->rtwdev;3888struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;3889struct seq_file *m = vif_iter_data->file;3890struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;38913892seq_printf(m, "Iface on Port (%d)\n", rtwvif->port);3893seq_printf(m, "\t%-32s = %d\n",3894"Beacon interval", bss_conf->beacon_int);3895seq_printf(m, "\t%-32s = %d\n",3896"Network Type", rtwvif->net_type);38973898sta_iter_data.rtwvif = rtwvif;3899sta_iter_data.file = m;3900rtw_iterate_stas_atomic(rtwdev, rtw_coex_sta_stat_iter,3901&sta_iter_data);3902}39033904#define case_WLINK(src) \3905case COEX_WLINK_##src: return #src39063907static const char *rtw_coex_get_wl_coex_mode(u8 coex_wl_link_mode)3908{3909switch (coex_wl_link_mode) {3910case_WLINK(2G1PORT);3911case_WLINK(5G);3912case_WLINK(2GFREE);3913default:3914return "Unknown";3915}3916}39173918void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)3919{3920const struct rtw_chip_info *chip = rtwdev->chip;3921struct rtw_dm_info *dm_info = &rtwdev->dm_info;3922struct rtw_coex *coex = &rtwdev->coex;3923struct rtw_coex_stat *coex_stat = &coex->stat;3924struct rtw_coex_dm *coex_dm = &coex->dm;3925struct rtw_hal *hal = &rtwdev->hal;3926struct rtw_efuse *efuse = &rtwdev->efuse;3927struct rtw_fw_state *fw = &rtwdev->fw;3928struct rtw_coex_vif_stat_iter_data vif_iter_data;3929u8 reason = coex_dm->reason;3930u8 sys_lte;3931u16 score_board_WB, score_board_BW;3932u32 wl_reg_6c0, wl_reg_6c4, wl_reg_6c8, wl_reg_778, wl_reg_6cc;3933u32 lte_coex = 0, bt_coex = 0;3934int i;39353936score_board_BW = rtw_coex_read_scbd(rtwdev);3937score_board_WB = coex_stat->score_board;3938wl_reg_6c0 = rtw_read32(rtwdev, REG_BT_COEX_TABLE0);3939wl_reg_6c4 = rtw_read32(rtwdev, REG_BT_COEX_TABLE1);3940wl_reg_6c8 = rtw_read32(rtwdev, REG_BT_COEX_BRK_TABLE);3941wl_reg_6cc = rtw_read32(rtwdev, REG_BT_COEX_TABLE_H);3942wl_reg_778 = rtw_read8(rtwdev, REG_BT_STAT_CTRL);39433944sys_lte = rtw_read8(rtwdev, 0x73);3945if (rtwdev->chip->ltecoex_addr) {3946lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38);3947bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54);3948}39493950if (!coex_stat->wl_under_ips &&3951(!coex_stat->wl_under_lps || coex_stat->wl_force_lps_ctrl) &&3952!coex_stat->bt_disabled && !coex_stat->bt_mailbox_reply) {3953rtw_coex_get_bt_supported_version(rtwdev,3954&coex_stat->bt_supported_version);3955rtw_coex_get_bt_patch_version(rtwdev, &coex_stat->patch_ver);3956rtw_coex_get_bt_supported_feature(rtwdev,3957&coex_stat->bt_supported_feature);3958rtw_coex_get_bt_reg(rtwdev, 3, 0xae, &coex_stat->bt_reg_vendor_ae);3959rtw_coex_get_bt_reg(rtwdev, 3, 0xac, &coex_stat->bt_reg_vendor_ac);39603961if (coex_stat->patch_ver != 0)3962coex_stat->bt_mailbox_reply = true;3963}39643965rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);3966seq_printf(m, "**********************************************\n");3967seq_printf(m, "\t\tBT Coexist info %x\n", chip->id);3968seq_printf(m, "**********************************************\n");39693970if (coex->manual_control) {3971seq_puts(m, "============[Under Manual Control]============\n");3972seq_puts(m, "==========================================\n");39733974} else if (coex->stop_dm) {3975seq_puts(m, "============[Coex is STOPPED]============\n");3976seq_puts(m, "==========================================\n");39773978} else if (coex->freeze) {3979seq_puts(m, "============[coex_freeze]============\n");3980seq_puts(m, "==========================================\n");3981}39823983seq_printf(m, "%-40s = %s/ %d\n",3984"Mech/ RFE",3985efuse->share_ant ? "Shared" : "Non-Shared",3986efuse->rfe_option);3987seq_printf(m, "%-40s = %08x/ 0x%02x/ 0x%08x %s\n",3988"Coex Ver/ BT Dez/ BT Rpt",3989chip->coex_para_ver, chip->bt_desired_ver,3990coex_stat->bt_supported_version,3991coex_stat->bt_disabled ? "(BT disabled)" :3992coex_stat->bt_supported_version >= chip->bt_desired_ver ?3993"(Match)" : "(Mismatch)");3994seq_printf(m, "%-40s = %s/ %u/ %d\n",3995"Role/ RoleSwCnt/ IgnWL/ Feature",3996coex_stat->bt_slave ? "Slave" : "Master",3997coex_stat->cnt_bt[COEX_CNT_BT_ROLESWITCH],3998coex_dm->ignore_wl_act);3999seq_printf(m, "%-40s = %u.%u/ 0x%x/ 0x%x/ %c\n",4000"WL FW/ BT FW/ BT FW Desired/ KT",4001fw->version, fw->sub_version,4002coex_stat->patch_ver,4003chip->wl_fw_desired_ver, coex_stat->kt_ver + 65);4004seq_printf(m, "%-40s = %u/ %u/ %u/ ch-(%u)\n",4005"AFH Map",4006coex_dm->wl_ch_info[0], coex_dm->wl_ch_info[1],4007coex_dm->wl_ch_info[2], hal->current_channel);40084009rtw_debugfs_get_simple_phy_info(m);4010seq_printf(m, "**********************************************\n");4011seq_printf(m, "\t\tBT Status\n");4012seq_printf(m, "**********************************************\n");4013seq_printf(m, "%-40s = %s/ %ddBm/ %u/ %u\n",4014"BT status/ rssi/ retry/ pop",4015coex_dm->bt_status == COEX_BTSTATUS_NCON_IDLE ? "non-conn" :4016coex_dm->bt_status == COEX_BTSTATUS_CON_IDLE ? "conn-idle" : "busy",4017coex_stat->bt_rssi - 100,4018coex_stat->cnt_bt[COEX_CNT_BT_RETRY],4019coex_stat->cnt_bt[COEX_CNT_BT_POPEVENT]);4020seq_printf(m, "%-40s = %s%s%s%s%s (multi-link %d)\n",4021"Profiles",4022coex_stat->bt_a2dp_exist ? (coex_stat->bt_a2dp_sink ?4023"A2DP sink," : "A2DP,") : "",4024coex_stat->bt_hfp_exist ? "HFP," : "",4025coex_stat->bt_hid_exist ?4026(coex_stat->bt_ble_exist ? "HID(RCU)," :4027coex_stat->bt_hid_slot >= 2 ? "HID(4/18)" :4028coex_stat->bt_ble_hid_exist ? "HID(BLE)" :4029"HID(2/18),") : "",4030coex_stat->bt_pan_exist ? coex_stat->bt_opp_exist ?4031"OPP," : "PAN," : "",4032coex_stat->bt_ble_voice ? "Voice," : "",4033coex_stat->bt_multi_link);4034seq_printf(m, "%-40s = %u/ %u/ %u/ 0x%08x\n",4035"Reinit/ Relink/ IgnWl/ Feature",4036coex_stat->cnt_bt[COEX_CNT_BT_REINIT],4037coex_stat->cnt_bt[COEX_CNT_BT_SETUPLINK],4038coex_stat->cnt_bt[COEX_CNT_BT_IGNWLANACT],4039coex_stat->bt_supported_feature);4040seq_printf(m, "%-40s = %u/ %u/ %u/ %u\n",4041"Page/ Inq/ iqk/ iqk fail",4042coex_stat->cnt_bt[COEX_CNT_BT_PAGE],4043coex_stat->cnt_bt[COEX_CNT_BT_INQ],4044coex_stat->cnt_bt[COEX_CNT_BT_IQK],4045coex_stat->cnt_bt[COEX_CNT_BT_IQKFAIL]);4046seq_printf(m, "%-40s = 0x%04x/ 0x%04x/ 0x%04x/ 0x%04x\n",4047"0xae/ 0xac/ score board (W->B)/ (B->W)",4048coex_stat->bt_reg_vendor_ae,4049coex_stat->bt_reg_vendor_ac,4050score_board_WB, score_board_BW);4051seq_printf(m, "%-40s = %u/%u, %u/%u\n",4052"Hi-Pri TX/RX, Lo-Pri TX/RX",4053coex_stat->hi_pri_tx, coex_stat->hi_pri_rx,4054coex_stat->lo_pri_tx, coex_stat->lo_pri_rx);4055for (i = 0; i < COEX_BTINFO_SRC_BT_IQK; i++)4056seq_printf(m, "%-40s = %7ph\n",4057rtw_coex_get_bt_info_src_string(i),4058coex_stat->bt_info_c2h[i]);40594060seq_printf(m, "**********************************************\n");4061seq_printf(m, "\t\tWiFi Status\n");4062seq_printf(m, "**********************************************\n");4063seq_printf(m, "%-40s = %d\n",4064"Scanning", test_bit(RTW_FLAG_SCANNING, rtwdev->flags));4065seq_printf(m, "%-40s = %u/ TX %d Mbps/ RX %d Mbps\n",4066"G_busy/ TX/ RX",4067coex_stat->wl_gl_busy,4068rtwdev->stats.tx_throughput, rtwdev->stats.rx_throughput);4069seq_printf(m, "%-40s = %u/ %u/ %u\n",4070"IPS/ Low Power/ PS mode",4071!test_bit(RTW_FLAG_POWERON, rtwdev->flags),4072test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags),4073rtwdev->lps_conf.mode);40744075vif_iter_data.rtwdev = rtwdev;4076vif_iter_data.file = m;4077rtw_iterate_vifs_atomic(rtwdev, rtw_coex_vif_stat_iter, &vif_iter_data);40784079if (coex->manual_control) {4080seq_printf(m, "**********************************************\n");4081seq_printf(m, "\t\tMechanism (Under Manual)\n");4082seq_printf(m, "**********************************************\n");4083seq_printf(m, "%-40s = %5ph (%d)\n",4084"TDMA Now",4085coex_dm->fw_tdma_para,4086rtw_coex_get_tdma_index(rtwdev,4087&coex_dm->fw_tdma_para[0]));4088} else {4089seq_printf(m, "**********************************************\n");4090seq_printf(m, "\t\tMechanism\n");4091seq_printf(m, "**********************************************\n");4092seq_printf(m, "%-40s = %5ph (case-%d)\n",4093"TDMA",4094coex_dm->ps_tdma_para, coex_dm->cur_ps_tdma);4095}4096seq_printf(m, "%-40s = %s/ %s/ %d\n",4097"Coex Mode/Free Run/Timer base",4098rtw_coex_get_wl_coex_mode(coex_stat->wl_coex_mode),4099coex->freerun ? "Yes" : "No",4100coex_stat->tdma_timer_base);4101seq_printf(m, "%-40s = %d(%d)/ 0x%08x/ 0x%08x/ 0x%08x\n",4102"Table/ 0x6c0/ 0x6c4/ 0x6c8",4103coex_dm->cur_table,4104rtw_coex_get_table_index(rtwdev, wl_reg_6c0, wl_reg_6c4),4105wl_reg_6c0, wl_reg_6c4, wl_reg_6c8);4106seq_printf(m, "%-40s = 0x%08x/ 0x%08x/ %d/ reason (%s)\n",4107"0x778/ 0x6cc/ Run Count/ Reason",4108wl_reg_778, wl_reg_6cc,4109coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN],4110rtw_coex_get_reason_string(reason));4111seq_printf(m, "%-40s = %3ph\n",4112"AFH Map to BT",4113coex_dm->wl_ch_info);4114seq_printf(m, "%-40s = %s/ %d\n",4115"AntDiv/ BtCtrlLPS/ g_busy",4116coex_stat->wl_force_lps_ctrl ? "On" : "Off",4117coex_stat->wl_gl_busy);4118seq_printf(m, "%-40s = %u/ %u/ %u/ %u/ %u\n",4119"Null All/ Retry/ Ack/ BT Empty/ BT Late",4120coex_stat->wl_fw_dbg_info[1], coex_stat->wl_fw_dbg_info[2],4121coex_stat->wl_fw_dbg_info[3], coex_stat->wl_fw_dbg_info[4],4122coex_stat->wl_fw_dbg_info[5]);4123seq_printf(m, "%-40s = %u/ %u/ %s/ %u\n",4124"Cnt TDMA Toggle/ Lk 5ms/ Lk 5ms on/ FW",4125coex_stat->wl_fw_dbg_info[6],4126coex_stat->wl_fw_dbg_info[7],4127coex_stat->wl_slot_extend ? "Yes" : "No",4128coex_stat->cnt_wl[COEX_CNT_WL_FW_NOTIFY]);4129seq_printf(m, "%-40s = %d/ %d/ %s/ %d\n",4130"WL_TxPw/ BT_TxPw/ WL_Rx/ BT_LNA_Lvl",4131coex_dm->cur_wl_pwr_lvl,4132coex_dm->cur_bt_pwr_lvl,4133coex_dm->cur_wl_rx_low_gain_en ? "On" : "Off",4134coex_dm->cur_bt_lna_lvl);41354136seq_printf(m, "**********************************************\n");4137seq_printf(m, "\t\tHW setting\n");4138seq_printf(m, "**********************************************\n");4139seq_printf(m, "%-40s = %s/ %s\n",4140"LTE Coex/ Path Owner",4141lte_coex & BIT(7) ? "ON" : "OFF",4142sys_lte & BIT(2) ? "WL" : "BT");4143seq_printf(m, "%-40s = RF:%s_BB:%s/ RF:%s_BB:%s/ %s\n",4144"GNT_WL_CTRL/ GNT_BT_CTRL/ Dbg",4145lte_coex & BIT(12) ? "SW" : "HW",4146lte_coex & BIT(8) ? "SW" : "HW",4147lte_coex & BIT(14) ? "SW" : "HW",4148lte_coex & BIT(10) ? "SW" : "HW",4149sys_lte & BIT(3) ? "On" : "Off");4150seq_printf(m, "%-40s = %lu/ %lu\n",4151"GNT_WL/ GNT_BT",4152(bt_coex & BIT(2)) >> 2, (bt_coex & BIT(3)) >> 3);4153seq_printf(m, "%-40s = %u/ %u/ %u/ %u\n",4154"CRC OK CCK/ OFDM/ HT/ VHT",4155dm_info->cck_ok_cnt, dm_info->ofdm_ok_cnt,4156dm_info->ht_ok_cnt, dm_info->vht_ok_cnt);4157seq_printf(m, "%-40s = %u/ %u/ %u/ %u\n",4158"CRC ERR CCK/ OFDM/ HT/ VHT",4159dm_info->cck_err_cnt, dm_info->ofdm_err_cnt,4160dm_info->ht_err_cnt, dm_info->vht_err_cnt);4161seq_printf(m, "%-40s = %s/ %s/ %s/ %u\n",4162"HiPr/ Locking/ Locked/ Noisy",4163coex_stat->wl_hi_pri_task1 ? "Y" : "N",4164coex_stat->wl_cck_lock ? "Y" : "N",4165coex_stat->wl_cck_lock_ever ? "Y" : "N",4166coex_stat->wl_noisy_level);41674168rtw_coex_set_coexinfo_hw(rtwdev, m);4169seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n",4170"EVM A/ EVM B/ SNR A/ SNR B",4171-dm_info->rx_evm_dbm[RF_PATH_A],4172-dm_info->rx_evm_dbm[RF_PATH_B],4173-dm_info->rx_snr[RF_PATH_A],4174-dm_info->rx_snr[RF_PATH_B]);4175seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n",4176"CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA",4177dm_info->cck_cca_cnt, dm_info->cck_fa_cnt,4178dm_info->ofdm_cca_cnt, dm_info->ofdm_fa_cnt);4179seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n", "CRC OK CCK/11g/11n/11ac",4180dm_info->cck_ok_cnt, dm_info->ofdm_ok_cnt,4181dm_info->ht_ok_cnt, dm_info->vht_ok_cnt);4182seq_printf(m, "%-40s = %d/ %d/ %d/ %d\n", "CRC Err CCK/11g/11n/11ac",4183dm_info->cck_err_cnt, dm_info->ofdm_err_cnt,4184dm_info->ht_err_cnt, dm_info->vht_err_cnt);41854186}4187#endif /* CONFIG_RTW88_DEBUGFS */418841894190