From ac7ec508487340b9ad8a3c807c2ff520ec4dab5b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 3 Jul 2021 04:47:09 -0500 Subject: [PATCH] rtw89: Update driver to v5 This version is the latest released by Realtek and has a number of improvements over v4. I now have the chip and have run extensive tests on this version. For me, it has been stable and will handle up to 600 Mbps using a 5G connection to a Wifi 6 AP with a theoretical maximum throughput of 750 Mbps. Signed-off-by: Larry Finger --- Makefile | 4 +- README.md | 12 +- cam.c | 38 ++- cam.h | 5 +- coex.c | 551 ++++++++++++++++++++++++++++---------------- core.c | 284 ++++++++++++++++++----- core.h | 137 +++++++++-- debug.c | 57 ++++- dkms.conf | 12 + fw.c | 311 +++++++++++++++++++++++-- fw.h | 230 ++++++++++++++++++- mac.c | 609 +++++++++++++++++++++++++++++++++++++++++-------- mac.h | 55 ++++- mac80211.c | 151 ++++++++++-- pci.c | 244 ++++++++++++++------ pci.h | 48 +++- phy.c | 546 ++++++++++++++++++++++++++++++-------------- phy.h | 20 +- ps.c | 37 +-- ps.h | 2 +- reg.h | 123 ++++++++-- regd.c | 2 + regd.h | 71 ++++++ rtw8852a.c | 66 ++++-- rtw8852a_rfk.c | 8 +- sar.c | 192 ++++++++++++++++ sar.h | 29 +++ ser.c | 66 +++++- ser.h | 1 + txrx.h | 4 + util.c | 37 +++ util.h | 31 +++ 32 files changed, 3244 insertions(+), 739 deletions(-) create mode 100644 dkms.conf create mode 100644 regd.h create mode 100644 sar.c create mode 100644 sar.h create mode 100644 util.c create mode 100644 util.h diff --git a/Makefile b/Makefile index 80bc1f6e..22ccda89 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,9 @@ rtw89core-y += core.o \ regd.o \ coex.o \ ps.o \ - ser.o + sar.o \ + ser.o \ + util.o obj-m += rtw89pci.o rtw89pci-y := pci.o diff --git a/README.md b/README.md index 340ed929..eb76618b 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ -rtw89 +rtw89 v5 =========== ### A repo for the newest Realtek rtlwifi codes. +This branch has v5 of the code, which is latest from Realtek. + This code will build on any kernel 5.7 and newer as long as the distro has not modified any of the kernel APIs. IF YOU RUN UBUNTU, YOU CAN BE ASSURED THAT THE APIs HAVE CHANGED. NO, I WILL NOT MODIFY THE SOURCE FOR YOU. YOU ARE ON YOUR OWN!!!!! I am working on fixing builds on older kernels. -This repository includes drivers for the following cards: +This repository includes drivers for the following card: Realtek 8852AE @@ -25,12 +27,12 @@ You can install them with the following command, on **Ubuntu**: sudo apt-get update sudo apt-get install make gcc linux-headers-$(uname -r) build-essential git ``` -If any of the packets above are not found check if your distro installs them like that. +If any of the packages above are not found check if your distro installs them like that. ##### Installation For all distros: ```bash -git clone https://github.com/lwfinger/rtw89.git +git clone https://github.com/lwfinger/rtw89.git -b v5 cd rtw89 make sudo make install @@ -53,6 +55,8 @@ options <>= The available options for rtw89pci are disable_clkreq, disable_aspm, and disable_aspm The available options for rtw89core are debug_mask, and disable_ps_mode +Normally, none of these will be needed. + *********************************************************************************************** When your kernel changes, then you need to do the following: diff --git a/cam.c b/cam.c index 204cde71..fac5b6e9 100644 --- a/cam.c +++ b/cam.c @@ -330,10 +330,6 @@ int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev, case WLAN_CIPHER_SUITE_WEP104: hw_key_type = RTW89_SEC_KEY_TYPE_WEP104; break; - case WLAN_CIPHER_SUITE_TKIP: - hw_key_type = RTW89_SEC_KEY_TYPE_TKIP; - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - break; case WLAN_CIPHER_SUITE_CCMP: hw_key_type = RTW89_SEC_KEY_TYPE_CCMP128; key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; @@ -352,6 +348,7 @@ int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev, key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; ext_key = true; break; + case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_AES_CMAC: case WLAN_CIPHER_SUITE_BIP_CMAC_256: case WLAN_CIPHER_SUITE_BIP_GMAC_128: @@ -378,7 +375,8 @@ int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev, int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) + struct ieee80211_key_conf *key, + bool inform_fw) { struct rtw89_cam_info *cam_info = &rtwdev->cam_info; struct rtw89_vif *rtwvif; @@ -386,7 +384,7 @@ int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev, struct rtw89_sec_cam_entry *sec_cam; u8 key_idx = key->hw_key_idx; u8 sec_cam_idx; - int ret; + int ret = 0; if (!vif) { rtw89_err(rtwdev, "No iface for deleting sec cam\n"); @@ -400,9 +398,11 @@ int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev, /* detach sec cam from addr cam */ clear_bit(key_idx, addr_cam->sec_cam_map); addr_cam->sec_entries[key_idx] = NULL; - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif); - if (ret) - rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret); + if (inform_fw) { + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif); + if (ret) + rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret); + } /* clear valid bit in addr cam will disable sec cam, * so we don't need to send H2C command again @@ -417,6 +417,19 @@ int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev, return ret; } +static void rtw89_cam_reset_key_iter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *data) +{ + struct rtw89_dev *rtwdev = (struct rtw89_dev *)data; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + + rtw89_cam_sec_key_del(rtwdev, vif, sta, key, false); + rtw89_cam_deinit(rtwdev, rtwvif); +} + void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { struct rtw89_cam_info *cam_info = &rtwdev->cam_info; @@ -429,6 +442,13 @@ void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) clear_bit(bssid_cam->bssid_cam_idx, cam_info->bssid_cam_map); } +void rtw89_cam_reset_keys(struct rtw89_dev *rtwdev) +{ + rcu_read_lock(); + ieee80211_iter_keys_rcu(rtwdev->hw, NULL, rtw89_cam_reset_key_iter, rtwdev); + rcu_read_unlock(); +} + static int rtw89_cam_get_avail_addr_cam(struct rtw89_dev *rtwdev, u8 *addr_cam_idx) { diff --git a/cam.h b/cam.h index d6b20db5..90a20a53 100644 --- a/cam.h +++ b/cam.h @@ -157,8 +157,9 @@ int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev, int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); + struct ieee80211_key_conf *key, + bool inform_fw); void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); - +void rtw89_cam_reset_keys(struct rtw89_dev *rtwdev); #endif diff --git a/coex.c b/coex.c index b1f8b734..868aa9d6 100644 --- a/coex.c +++ b/coex.c @@ -71,28 +71,32 @@ static const struct rtw89_btc_fbtc_tdma t_def[] = { [CXTD_PAUTO2] = {CXTDMA_AUTO2, CXFLC_NULLP, CXTPS_ON, 0, 5, 0, 0, 0} }; +#define __DEF_FBTC_SLOT(__dur, __cxtbl, __cxtype) \ + { .dur = cpu_to_le16(__dur), .cxtbl = cpu_to_le32(__cxtbl), \ + .cxtype = cpu_to_le16(__cxtype),} + static const struct rtw89_btc_fbtc_slot s_def[] = { - [CXST_OFF] = {100, 0x55555555, SLOT_MIX}, - [CXST_B2W] = { 5, 0x5a5a5a5a, SLOT_ISO}, - [CXST_W1] = { 70, 0x5a5a5a5a, SLOT_ISO}, - [CXST_W2] = { 70, 0x5a5a5aaa, SLOT_ISO}, - [CXST_W2B] = { 15, 0x5a5a5a5a, SLOT_ISO}, - [CXST_B1] = {100, 0x55555555, SLOT_MIX}, - [CXST_B2] = { 7, 0x6a5a5a5a, SLOT_MIX}, - [CXST_B3] = { 5, 0x55555555, SLOT_MIX}, - [CXST_B4] = { 50, 0x55555555, SLOT_MIX}, - [CXST_LK] = { 20, 0x5a5a5a5a, SLOT_ISO}, - [CXST_BLK] = {250, 0x55555555, SLOT_MIX}, - [CXST_E2G] = { 20, 0x6a5a5a5a, SLOT_MIX}, - [CXST_E5G] = { 20, 0xffffffff, SLOT_MIX}, - [CXST_EBT] = { 20, 0x55555555, SLOT_MIX}, - [CXST_ENULL] = { 7, 0xaaaaaaaa, SLOT_ISO}, - [CXST_WLK] = {250, 0x6a5a6a5a, SLOT_MIX}, - [CXST_W1FDD] = { 35, 0xfafafafa, SLOT_ISO}, - [CXST_B1FDD] = {100, 0xffffffff, SLOT_MIX} + [CXST_OFF] = __DEF_FBTC_SLOT(100, 0x55555555, SLOT_MIX), + [CXST_B2W] = __DEF_FBTC_SLOT(5, 0x5a5a5a5a, SLOT_ISO), + [CXST_W1] = __DEF_FBTC_SLOT(70, 0x5a5a5a5a, SLOT_ISO), + [CXST_W2] = __DEF_FBTC_SLOT(70, 0x5a5a5aaa, SLOT_ISO), + [CXST_W2B] = __DEF_FBTC_SLOT(15, 0x5a5a5a5a, SLOT_ISO), + [CXST_B1] = __DEF_FBTC_SLOT(100, 0x55555555, SLOT_MIX), + [CXST_B2] = __DEF_FBTC_SLOT(7, 0x6a5a5a5a, SLOT_MIX), + [CXST_B3] = __DEF_FBTC_SLOT(5, 0x55555555, SLOT_MIX), + [CXST_B4] = __DEF_FBTC_SLOT(50, 0x55555555, SLOT_MIX), + [CXST_LK] = __DEF_FBTC_SLOT(20, 0x5a5a5a5a, SLOT_ISO), + [CXST_BLK] = __DEF_FBTC_SLOT(250, 0x55555555, SLOT_MIX), + [CXST_E2G] = __DEF_FBTC_SLOT(20, 0x6a5a5a5a, SLOT_MIX), + [CXST_E5G] = __DEF_FBTC_SLOT(20, 0xffffffff, SLOT_MIX), + [CXST_EBT] = __DEF_FBTC_SLOT(20, 0x55555555, SLOT_MIX), + [CXST_ENULL] = __DEF_FBTC_SLOT(7, 0xaaaaaaaa, SLOT_ISO), + [CXST_WLK] = __DEF_FBTC_SLOT(250, 0x6a5a6a5a, SLOT_MIX), + [CXST_W1FDD] = __DEF_FBTC_SLOT(35, 0xfafafafa, SLOT_ISO), + [CXST_B1FDD] = __DEF_FBTC_SLOT(100, 0xffffffff, SLOT_MIX), }; -const u32 cxtbl[] = { +static const u32 cxtbl[] = { 0xffffffff, /* 0 */ 0xaaaaaaaa, /* 1 */ 0x55555555, /* 2 */ @@ -121,34 +125,6 @@ struct rtw89_btc_btf_tlv { u8 val[1]; } __packed; -enum btc_bt_h2c_class { - BTFC_SET = 0x10, - BTFC_GET = 0x11, - BTFC_FW_EVENT = 0x12, -}; - -enum btc_btf_set { - SET_REPORT_EN = 0x0, - SET_SLOT_TABLE, - SET_MREG_TABLE, - SET_CX_POLICY, - SET_GPIO_DBG, - SET_DRV_INFO, - SET_DRV_EVENT, - SET_BT_WREG_ADDR, - SET_BT_WREG_VAL, - SET_BT_RREG_ADDR, - SET_BT_WL_CH_INFO, - SET_BT_INFO_REPORT, - SET_BT_IGNORE_WLAN_ACT, - SET_BT_TX_PWR, - SET_BT_LNA_CONSTRAIN, - SET_BT_GOLDEN_RX_RANGE, - SET_BT_PSD_REPORT, - SET_H2C_TEST, - SET_MAX1, -}; - enum btc_btf_set_report_en { RPT_EN_TDMA = BIT(0), RPT_EN_CYCLE = BIT(1), @@ -190,18 +166,6 @@ enum btc_btf_set_cx_policy { CXPOLICY_MAX, }; -enum btc_cxdrvinfo { - CXDRVINFO_INIT = 0, - CXDRVINFO_ROLE, - CXDRVINFO_DBCC, - CXDRVINFO_SMAP, - CXDRVINFO_RFK, - CXDRVINFO_RUN, - CXDRVINFO_CTRL, - CXDRVINFO_SCAN, - CXDRVINFO_MAX, -}; - enum btc_b2w_scoreboard { BTC_BSCB_ACT = BIT(0), BTC_BSCB_ON = BIT(1), @@ -525,7 +489,8 @@ enum btc_reason_and_action { BTC_RSN_NTFY_ROLE_INFO, BTC_RSN_CMD_SET_COEX, BTC_RSN_NUM, - BTC_ACT_WL_ONLY = 100, + BTC_ACT_NONE = 100, + BTC_ACT_WL_ONLY, BTC_ACT_WL_5G, BTC_ACT_WL_OTHER, BTC_ACT_WL_IDLE, @@ -554,7 +519,10 @@ enum btc_reason_and_action { BTC_ACT_WL_2G_GO, BTC_ACT_WL_2G_GC, BTC_ACT_WL_2G_NAN, - BTC_ACT_NUM, + BTC_ACT_LAST, + BTC_ACT_NUM = BTC_ACT_LAST - BTC_ACT_NONE, + BTC_ACT_EXT_BIT = BIT(14), + BTC_POLICY_EXT_BIT = BIT(15), }; #define BTC_FREERUN_ANTISO_MIN 30 @@ -770,9 +738,9 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo) switch (rpt_type) { case BTC_RPT_TYPE_BT_VER: - bt->ver_info.fw = pver->fw_ver; - bt->ver_info.fw_coex = FIELD_GET(GENMASK(7, 0), pver->coex_ver); - bt->feature = pver->feature; + bt->ver_info.fw = le32_to_cpu(pver->fw_ver); + bt->ver_info.fw_coex = le32_get_bits(pver->coex_ver, GENMASK(7, 0)); + bt->feature = le32_to_cpu(pver->feature); break; case BTC_RPT_TYPE_BT_SCAN: memcpy(bt->scan_info, pscan->scan, BTC_SCAN_MAX1); @@ -783,15 +751,89 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo) memcpy(&bt_linfo->afh_map[8], pafh->afh_h, 2); break; case BTC_RPT_TYPE_BT_DEVICE: - a2dp->device_name = pdev->dev_name; - a2dp->vendor_id = pdev->vendor_id; - a2dp->flush_time = pdev->flush_time; + a2dp->device_name = le32_to_cpu(pdev->dev_name); + a2dp->vendor_id = le16_to_cpu(pdev->vendor_id); + a2dp->flush_time = le32_to_cpu(pdev->flush_time); break; default: break; } } +struct rtw89_btc_fbtc_cysta_cpu { + u8 fver; + u8 rsvd; + u16 cycles; + u16 cycles_a2dp[CXT_FLCTRL_MAX]; + u16 a2dpept; + u16 a2dpeptto; + u16 tavg_cycle[CXT_MAX]; + u16 tmax_cycle[CXT_MAX]; + u16 tmaxdiff_cycle[CXT_MAX]; + u16 tavg_a2dp[CXT_FLCTRL_MAX]; + u16 tmax_a2dp[CXT_FLCTRL_MAX]; + u16 tavg_a2dpept; + u16 tmax_a2dpept; + u16 tavg_lk; + u16 tmax_lk; + u32 slot_cnt[CXST_MAX]; + u32 bcn_cnt[CXBCN_MAX]; + u32 leakrx_cnt; + u32 collision_cnt; + u32 skip_cnt; + u32 exception; + u32 except_cnt; +#if (FCXCYSTA_VER > 1) + u16 tslot_cycle[BTC_CYCLE_SLOT_MAX]; +#endif +}; + +static void rtw89_btc_fbtc_cysta_to_cpu(const struct rtw89_btc_fbtc_cysta *src, + struct rtw89_btc_fbtc_cysta_cpu *dst) +{ + static_assert(sizeof(*src) == sizeof(*dst)); + +#define __CPY_U8(_x) ({dst->_x = src->_x; }) +#define __CPY_LE16(_x) ({dst->_x = le16_to_cpu(src->_x); }) +#define __CPY_LE16S(_x) ({int _i; for (_i = 0; _i < ARRAY_SIZE(dst->_x); _i++) \ + dst->_x[_i] = le16_to_cpu(src->_x[_i]); }) +#define __CPY_LE32(_x) ({dst->_x = le32_to_cpu(src->_x); }) +#define __CPY_LE32S(_x) ({int _i; for (_i = 0; _i < ARRAY_SIZE(dst->_x); _i++) \ + dst->_x[_i] = le32_to_cpu(src->_x[_i]); }) + + __CPY_U8(fver); + __CPY_U8(rsvd); + __CPY_LE16(cycles); + __CPY_LE16S(cycles_a2dp); + __CPY_LE16(a2dpept); + __CPY_LE16(a2dpeptto); + __CPY_LE16S(tavg_cycle); + __CPY_LE16S(tmax_cycle); + __CPY_LE16S(tmaxdiff_cycle); + __CPY_LE16S(tavg_a2dp); + __CPY_LE16S(tmax_a2dp); + __CPY_LE16(tavg_a2dpept); + __CPY_LE16(tmax_a2dpept); + __CPY_LE16(tavg_lk); + __CPY_LE16(tmax_lk); + __CPY_LE32S(slot_cnt); + __CPY_LE32S(bcn_cnt); + __CPY_LE32(leakrx_cnt); + __CPY_LE32(collision_cnt); + __CPY_LE32(skip_cnt); + __CPY_LE32(exception); + __CPY_LE32(except_cnt); +#if (FCXCYSTA_VER > 1) + __CPY_LE16S(tslot_cycle); +#endif + +#undef __CPY_U8 +#undef __CPY_LE16 +#undef __CPY_LE16S +#undef __CPY_LE32 +#undef __CPY_LE32S +} + #define BTC_LEAK_AP_TH 10 #define BTC_CYSTA_CHK_PERIOD 100 @@ -810,11 +852,14 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_fbtc_rpt_ctrl *prpt = NULL; - struct rtw89_btc_fbtc_cysta *pcysta = NULL; + struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL; + struct rtw89_btc_fbtc_cysta_cpu pcysta[1]; struct rtw89_btc_prpt *btc_prpt = NULL; + struct rtw89_btc_fbtc_slot *rtp_slot = NULL; u8 rpt_type = 0, *rpt_content = NULL, *pfinfo = NULL; u16 wl_slot_set = 0; u32 trace_step = btc->ctrl.trace_step, rpt_len = 0, diff_t; + u8 i; rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s index:%d\n", @@ -862,7 +907,8 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, case BTC_RPT_TYPE_CYSTA: pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo; pfinfo = (u8 *)(&pfwinfo->rpt_fbtc_cysta.finfo); - pcysta = &pfwinfo->rpt_fbtc_cysta.finfo; + pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo; + rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta); pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo); pcinfo->req_fver = FCXCYSTA_VER; pcinfo->rx_len = rpt_len; @@ -963,6 +1009,29 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, "[BTC], %s check %d %ld\n", __func__, BTC_DCNT_TDMA_NONSYNC, sizeof(dm->tdma_now)); + if (memcmp(&dm->tdma_now, &pfwinfo->rpt_fbtc_tdma.finfo, + sizeof(dm->tdma_now)) != 0) { + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s %d tdma_now %x %x %x %x %x %x %x %x\n", + __func__, BTC_DCNT_TDMA_NONSYNC, + dm->tdma_now.type, dm->tdma_now.rxflctrl, + dm->tdma_now.txpause, dm->tdma_now.wtgle_n, + dm->tdma_now.leak_n, dm->tdma_now.ext_ctrl, + dm->tdma_now.rsvd0, dm->tdma_now.rsvd1); + + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s %d rpt_fbtc_tdma %x %x %x %x %x %x %x %x\n", + __func__, BTC_DCNT_TDMA_NONSYNC, + pfwinfo->rpt_fbtc_tdma.finfo.type, + pfwinfo->rpt_fbtc_tdma.finfo.rxflctrl, + pfwinfo->rpt_fbtc_tdma.finfo.txpause, + pfwinfo->rpt_fbtc_tdma.finfo.wtgle_n, + pfwinfo->rpt_fbtc_tdma.finfo.leak_n, + pfwinfo->rpt_fbtc_tdma.finfo.ext_ctrl, + pfwinfo->rpt_fbtc_tdma.finfo.rsvd0, + pfwinfo->rpt_fbtc_tdma.finfo.rsvd1); + } + _chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC, memcmp(&dm->tdma_now, &pfwinfo->rpt_fbtc_tdma.finfo, @@ -973,12 +1042,37 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s check %d %ld\n", __func__, BTC_DCNT_SLOT_NONSYNC, - CXST_MAX * sizeof(*dm->slot_now)); - + sizeof(dm->slot_now)); + + if (memcmp(dm->slot_now, pfwinfo->rpt_fbtc_slots.finfo.slot, + sizeof(dm->slot_now)) != 0) { + for (i = 0; i < CXST_MAX; i++) { + rtp_slot = + &pfwinfo->rpt_fbtc_slots.finfo.slot[i]; + if (memcmp(&dm->slot_now[i], rtp_slot, + sizeof(dm->slot_now[i])) != 0) { + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s %d slot_now[%d] dur=0x%04x tbl=%08x type=0x%04x\n", + __func__, + BTC_DCNT_SLOT_NONSYNC, i, + dm->slot_now[i].dur, + dm->slot_now[i].cxtbl, + dm->slot_now[i].cxtype); + + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s %d rpt_fbtc_slots[%d] dur=0x%04x tbl=%08x type=0x%04x\n", + __func__, + BTC_DCNT_SLOT_NONSYNC, i, + rtp_slot->dur, + rtp_slot->cxtbl, + rtp_slot->cxtype); + } + } + } _chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC, memcmp(dm->slot_now, pfwinfo->rpt_fbtc_slots.finfo.slot, - CXST_MAX * sizeof(*dm->slot_now))); + sizeof(dm->slot_now))); } if (rpt_type == BTC_RPT_TYPE_CYSTA && @@ -994,9 +1088,9 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, /* Check diff time between WL slot and W1/E2G slot */ if (dm->tdma_now.type == CXTDMA_OFF && dm->tdma_now.ext_ctrl == CXECTL_EXT) - wl_slot_set = dm->slot_now[CXST_E2G].dur; + wl_slot_set = le16_to_cpu(dm->slot_now[CXST_E2G].dur); else - wl_slot_set = dm->slot_now[CXST_W1].dur; + wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur); if (pcysta->tavg_cycle[CXT_WL] > wl_slot_set) { diff_t = pcysta->tavg_cycle[CXT_WL] - wl_slot_set; @@ -1218,25 +1312,14 @@ static void _update_dm_step(struct rtw89_dev *rtwdev, struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; - if (dm->dm_step.pos_new >= RTW89_BTC_DM_MAXSTEP || - dm->dm_step.pos_old >= RTW89_BTC_DM_MAXSTEP) - return; - /* use ring-structure to store dm step */ - if (dm->dm_step.step_cnt < RTW89_BTC_DM_MAXSTEP) { - dm->dm_step.step_cnt++; - dm->dm_step.pos_new = dm->dm_step.step_cnt - 1; - dm->dm_step.pos_old = 0; - } else { - dm->dm_step.pos_new = dm->dm_step.pos_old; + dm->dm_step.step[dm->dm_step.step_pos] = reason_or_action; + dm->dm_step.step_pos++; - if (dm->dm_step.pos_old == RTW89_BTC_DM_MAXSTEP - 1) - dm->dm_step.pos_old = 0; - else - dm->dm_step.pos_old++; + if (dm->dm_step.step_pos >= ARRAY_SIZE(dm->dm_step.step)) { + dm->dm_step.step_pos = 0; + dm->dm_step.step_ov = true; } - - dm->dm_step.step[dm->dm_step.pos_new] = reason_or_action; } static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type, @@ -1247,8 +1330,8 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type, dm->run_action = action; - _update_dm_step(rtwdev, action); - _update_dm_step(rtwdev, policy_type); + _update_dm_step(rtwdev, action | BTC_ACT_EXT_BIT); + _update_dm_step(rtwdev, policy_type | BTC_POLICY_EXT_BIT); btc->policy_len = 0; btc->policy_type = policy_type; @@ -1287,63 +1370,22 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type, static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type) { - struct rtw89_btc *btc = &rtwdev->btc; - struct rtw89_btc_wl_info *wl = &btc->cx.wl; - struct rtw89_btc_dm *dm = &btc->dm; - u8 buf[256] = {0}; - u16 sz = 0, n = 0; - - rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC] %s = %d\n", - __func__, type); - - if (type >= CXDRVINFO_MAX) - return; - switch (type) { case CXDRVINFO_INIT: - n = sizeof(dm->init_info); - sz = n + 2; - if (sz > sizeof(buf)) - return; - buf[0] = CXDRVINFO_INIT; - buf[1] = n; - memcpy((void *)&buf[2], &dm->init_info, n); + rtw89_fw_h2c_cxdrv_init(rtwdev); break; case CXDRVINFO_ROLE: - n = sizeof(wl->role_info); - sz = n + 2; - if (sz > sizeof(buf)) - return; - buf[0] = CXDRVINFO_ROLE; - buf[1] = n; - memcpy((void *)&buf[2], &wl->role_info, n); + rtw89_fw_h2c_cxdrv_role(rtwdev); break; case CXDRVINFO_CTRL: - n = sizeof(btc->ctrl); - sz = n + 2; - if (sz > sizeof(buf)) - return; - buf[0] = CXDRVINFO_CTRL; - buf[1] = n; - memcpy((void *)&buf[2], &btc->ctrl, n); + rtw89_fw_h2c_cxdrv_ctrl(rtwdev); break; case CXDRVINFO_RFK: - n = sizeof(wl->rfk_info); - sz = n + 2; - if (sz > sizeof(buf)) - return; - buf[0] = CXDRVINFO_RFK; - buf[1] = n; - memcpy((void *)&buf[2], &wl->rfk_info, n); + rtw89_fw_h2c_cxdrv_rfk(rtwdev); break; default: - return; + break; } - - rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC] H2C fun = %d, sz = %d\n", - SET_DRV_INFO, sz); - - _send_fw_cmd(rtwdev, BTFC_SET, SET_DRV_INFO, buf, sz); } static @@ -1606,7 +1648,7 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) wl_rinfo->link_mode == BTC_WLINK_2G_SCC) { en = true; /* get p2p channel */ - for (i = 0; i <= RTW89_MAX_HW_PORT_NUM; i++) { + for (i = 0; i < RTW89_MAX_HW_PORT_NUM; i++) { if (wl_rinfo->active_role[i].role == RTW89_WIFI_ROLE_P2P_GO || wl_rinfo->active_role[i].role == @@ -1619,7 +1661,7 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) } else { en = true; /* get 2g channel */ - for (i = 0; i <= RTW89_MAX_HW_PORT_NUM; i++) { + for (i = 0; i < RTW89_MAX_HW_PORT_NUM; i++) { if (wl_rinfo->active_role[i].connected && wl_rinfo->active_role[i].band == RTW89_BAND_2G) { ch = wl_rinfo->active_role[i].ch; @@ -1745,14 +1787,14 @@ static bool _check_freerun(struct rtw89_dev *rtwdev) do { \ typeof(sid) _sid = (sid); \ typeof(btc) _btc = (btc); \ - _btc->dm.slot[_sid].dur = dura;\ - _btc->dm.slot[_sid].cxtbl = tbl; \ - _btc->dm.slot[_sid].cxtype = type; \ + _btc->dm.slot[_sid].dur = cpu_to_le16(dura);\ + _btc->dm.slot[_sid].cxtbl = cpu_to_le32(tbl); \ + _btc->dm.slot[_sid].cxtype = cpu_to_le16(type); \ } while (0) -#define _slot_set_dur(btc, sid, dura) (btc)->dm.slot[sid].dur = dura -#define _slot_set_tbl(btc, sid, tbl) (btc)->dm.slot[sid].cxtbl = tbl -#define _slot_set_type(btc, sid, type) (btc)->dm.slot[sid].cxtype = type +#define _slot_set_dur(btc, sid, dura) (btc)->dm.slot[sid].dur = cpu_to_le16(dura) +#define _slot_set_tbl(btc, sid, tbl) (btc)->dm.slot[sid].cxtbl = cpu_to_le32(tbl) +#define _slot_set_type(btc, sid, type) (btc)->dm.slot[sid].cxtype = cpu_to_le16(type) struct btc_btinfo_lb2 { u8 connect: 1; @@ -3618,7 +3660,7 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode) _reset_btc_var(rtwdev, BTC_RESET_ALL); btc->dm.run_reason = BTC_RSN_NONE; - btc->dm.run_action = BTC_RSN_NONE; + btc->dm.run_action = BTC_ACT_NONE; btc->ctrl.igno_bt = true; rtw89_debug(rtwdev, RTW89_DBG_BTC, @@ -3792,6 +3834,7 @@ void rtw89_btc_ntfy_eapol_packet_work(struct work_struct *work) btc.eapol_notify_work); mutex_lock(&rtwdev->mutex); + rtw89_leave_ps_mode(rtwdev); rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_EAPOL); mutex_unlock(&rtwdev->mutex); } @@ -3802,6 +3845,7 @@ void rtw89_btc_ntfy_arp_packet_work(struct work_struct *work) btc.arp_notify_work); mutex_lock(&rtwdev->mutex); + rtw89_leave_ps_mode(rtwdev); rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_ARP); mutex_unlock(&rtwdev->mutex); } @@ -3812,6 +3856,7 @@ void rtw89_btc_ntfy_dhcp_packet_work(struct work_struct *work) btc.dhcp_notify_work); mutex_lock(&rtwdev->mutex); + rtw89_leave_ps_mode(rtwdev); rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_DHCP); mutex_unlock(&rtwdev->mutex); } @@ -4014,19 +4059,17 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC] wifi_role=%d\n", rtwvif->wifi_role); - if (rtwvif) { - r.role = rtwvif->wifi_role; - r.phy = rtwvif->phy_idx; - r.pid = rtwvif->port; - r.active = true; - r.connected = MLME_LINKED; - r.bcn_period = vif->bss_conf.beacon_int; - r.dtim_period = vif->bss_conf.dtim_period; - r.band = hal->current_band_type; - r.ch = hal->current_channel; - r.bw = hal->current_band_width; - memcpy(r.mac_addr, rtwvif->mac_addr, sizeof(r.mac_addr)); - } + r.role = rtwvif->wifi_role; + r.phy = rtwvif->phy_idx; + r.pid = rtwvif->port; + r.active = true; + r.connected = MLME_LINKED; + r.bcn_period = vif->bss_conf.beacon_int; + r.dtim_period = vif->bss_conf.dtim_period; + r.band = hal->current_band_type; + r.ch = hal->current_channel; + r.bw = hal->current_band_width; + ether_addr_copy(r.mac_addr, rtwvif->mac_addr); if (rtwsta && vif->type == NL80211_IFTYPE_STATION) r.mac_id = rtwsta->mac_id; @@ -4335,6 +4378,7 @@ void rtw89_btc_ntfy_wl_sta_work(struct work_struct *work) btc.wl_sta_notify_work); mutex_lock(&rtwdev->mutex); + rtw89_leave_ps_mode(rtwdev); _ntfy_wl_sta(rtwdev); mutex_unlock(&rtwdev->mutex); } @@ -4365,19 +4409,21 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, case BTF_EVNT_RPT: case BTF_EVNT_BUF_OVERFLOW: pfwinfo->event[func]++; + /* Don't need rtw89_leave_ps_mode() */ btc_fw_event(rtwdev, func, buf, len); break; case BTF_EVNT_BT_INFO: rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], handle C2H BT INFO with data %8ph\n", buf); btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE]++; - + rtw89_leave_ps_mode(rtwdev); _update_bt_info(rtwdev, buf, len); break; case BTF_EVNT_BT_SCBD: rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], handle C2H BT SCBD with data %8ph\n", buf); btc->cx.cnt_bt[BTC_BCNT_SCBDUPDATE]++; + rtw89_leave_ps_mode(rtwdev); _update_bt_scbd(rtwdev, false); break; case BTF_EVNT_BT_PSD: @@ -4459,7 +4505,7 @@ static void _show_cx_info(struct rtw89_dev *rtwdev, struct seq_file *m) id_branch = FIELD_GET(GENMASK(7, 0), wl->ver_info.fw); seq_printf(m, " %-15s : WL_FW:%d.%d.%d.%d, BT_FW:0x%x(%s)\n", "[sub_module]", - ver_main, ver_sub, ver_hotfix, ver_hotfix, + ver_main, ver_sub, ver_hotfix, id_branch, bt->ver_info.fw, bt->run_patch_code ? "patch" : "ROM"); seq_printf(m, " %-15s : cv:%x, rfe_type:0x%x, ant_iso:%d, ant_pg:%d, %s", @@ -4723,8 +4769,115 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m) cx->cnt_bt[BTC_BCNT_LOPRI_TX], polt_cnt); } +#define CASE_BTC_RSN_STR(e) case BTC_RSN_ ## e: return #e +#define CASE_BTC_ACT_STR(e) case BTC_ACT_ ## e | BTC_ACT_EXT_BIT: return #e +#define CASE_BTC_POLICY_STR(e) \ + case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e + +static const char *steps_to_str(u16 step) +{ + switch (step) { + CASE_BTC_RSN_STR(NONE); + CASE_BTC_RSN_STR(NTFY_INIT); + CASE_BTC_RSN_STR(NTFY_SWBAND); + CASE_BTC_RSN_STR(NTFY_WL_STA); + CASE_BTC_RSN_STR(NTFY_RADIO_STATE); + CASE_BTC_RSN_STR(UPDATE_BT_SCBD); + CASE_BTC_RSN_STR(NTFY_WL_RFK); + CASE_BTC_RSN_STR(UPDATE_BT_INFO); + CASE_BTC_RSN_STR(NTFY_SCAN_START); + CASE_BTC_RSN_STR(NTFY_SCAN_FINISH); + CASE_BTC_RSN_STR(NTFY_SPECIFIC_PACKET); + CASE_BTC_RSN_STR(NTFY_POWEROFF); + CASE_BTC_RSN_STR(NTFY_ROLE_INFO); + CASE_BTC_RSN_STR(CMD_SET_COEX); + + CASE_BTC_ACT_STR(NONE); + CASE_BTC_ACT_STR(WL_ONLY); + CASE_BTC_ACT_STR(WL_5G); + CASE_BTC_ACT_STR(WL_OTHER); + CASE_BTC_ACT_STR(WL_IDLE); + CASE_BTC_ACT_STR(WL_NC); + CASE_BTC_ACT_STR(WL_RFK); + CASE_BTC_ACT_STR(WL_INIT); + CASE_BTC_ACT_STR(WL_OFF); + CASE_BTC_ACT_STR(FREERUN); + CASE_BTC_ACT_STR(BT_WHQL); + CASE_BTC_ACT_STR(BT_RFK); + CASE_BTC_ACT_STR(BT_OFF); + CASE_BTC_ACT_STR(BT_IDLE); + CASE_BTC_ACT_STR(BT_HFP); + CASE_BTC_ACT_STR(BT_HID); + CASE_BTC_ACT_STR(BT_A2DP); + CASE_BTC_ACT_STR(BT_A2DPSINK); + CASE_BTC_ACT_STR(BT_PAN); + CASE_BTC_ACT_STR(BT_A2DP_HID); + CASE_BTC_ACT_STR(BT_A2DP_PAN); + CASE_BTC_ACT_STR(BT_PAN_HID); + CASE_BTC_ACT_STR(BT_A2DP_PAN_HID); + CASE_BTC_ACT_STR(WL_25G_MCC); + CASE_BTC_ACT_STR(WL_2G_MCC); + CASE_BTC_ACT_STR(WL_2G_SCC); + CASE_BTC_ACT_STR(WL_2G_AP); + CASE_BTC_ACT_STR(WL_2G_GO); + CASE_BTC_ACT_STR(WL_2G_GC); + CASE_BTC_ACT_STR(WL_2G_NAN); + + CASE_BTC_POLICY_STR(OFF_BT); + CASE_BTC_POLICY_STR(OFF_WL); + CASE_BTC_POLICY_STR(OFF_EQ0); + CASE_BTC_POLICY_STR(OFF_EQ1); + CASE_BTC_POLICY_STR(OFF_EQ2); + CASE_BTC_POLICY_STR(OFF_EQ3); + CASE_BTC_POLICY_STR(OFF_BWB0); + CASE_BTC_POLICY_STR(OFF_BWB1); + CASE_BTC_POLICY_STR(OFFB_BWB0); + CASE_BTC_POLICY_STR(OFFE_DEF); + CASE_BTC_POLICY_STR(OFFE_DEF2); + CASE_BTC_POLICY_STR(FIX_TD3030); + CASE_BTC_POLICY_STR(FIX_TD5050); + CASE_BTC_POLICY_STR(FIX_TD2030); + CASE_BTC_POLICY_STR(FIX_TD4010); + CASE_BTC_POLICY_STR(FIX_TD7010); + CASE_BTC_POLICY_STR(FIX_TD2060); + CASE_BTC_POLICY_STR(FIX_TD3060); + CASE_BTC_POLICY_STR(FIX_TD2080); + CASE_BTC_POLICY_STR(FIX_TDW1B1); + CASE_BTC_POLICY_STR(FIX_TD4020); + CASE_BTC_POLICY_STR(PFIX_TD3030); + CASE_BTC_POLICY_STR(PFIX_TD5050); + CASE_BTC_POLICY_STR(PFIX_TD2030); + CASE_BTC_POLICY_STR(PFIX_TD2060); + CASE_BTC_POLICY_STR(PFIX_TD3070); + CASE_BTC_POLICY_STR(PFIX_TD2080); + CASE_BTC_POLICY_STR(PFIX_TDW1B1); + CASE_BTC_POLICY_STR(AUTO_TD50200); + CASE_BTC_POLICY_STR(AUTO_TD60200); + CASE_BTC_POLICY_STR(AUTO_TD20200); + CASE_BTC_POLICY_STR(AUTO_TDW1B1); + CASE_BTC_POLICY_STR(PAUTO_TD50200); + CASE_BTC_POLICY_STR(PAUTO_TD60200); + CASE_BTC_POLICY_STR(PAUTO_TD20200); + CASE_BTC_POLICY_STR(PAUTO_TDW1B1); + CASE_BTC_POLICY_STR(AUTO2_TD3050); + CASE_BTC_POLICY_STR(AUTO2_TD3070); + CASE_BTC_POLICY_STR(AUTO2_TD5050); + CASE_BTC_POLICY_STR(AUTO2_TD6060); + CASE_BTC_POLICY_STR(AUTO2_TD2080); + CASE_BTC_POLICY_STR(AUTO2_TDW1B4); + CASE_BTC_POLICY_STR(PAUTO2_TD3050); + CASE_BTC_POLICY_STR(PAUTO2_TD3070); + CASE_BTC_POLICY_STR(PAUTO2_TD5050); + CASE_BTC_POLICY_STR(PAUTO2_TD6060); + CASE_BTC_POLICY_STR(PAUTO2_TD2080); + CASE_BTC_POLICY_STR(PAUTO2_TDW1B4); + default: + return "unknown step"; + } +} + static -void seq_print_segment(struct seq_file *m, const char *prefix, u8 *data, +void seq_print_segment(struct seq_file *m, const char *prefix, u16 *data, u8 len, u8 seg_len, u8 start_idx, u8 ring_len) { u8 i; @@ -4734,7 +4887,15 @@ void seq_print_segment(struct seq_file *m, const char *prefix, u8 *data, if ((i % seg_len) == 0) seq_printf(m, " %-15s : ", prefix); cur_index = (start_idx + i) % ring_len; - seq_printf(m, "-> %03d", *(data + cur_index)); + if (i % 3 == 0) + seq_printf(m, "-> %-20s", + steps_to_str(*(data + cur_index))); + else if (i % 3 == 1) + seq_printf(m, "-> %-15s", + steps_to_str(*(data + cur_index))); + else + seq_printf(m, "-> %-13s", + steps_to_str(*(data + cur_index))); if (i == (len - 1) || (i % seg_len) == (seg_len - 1)) seq_puts(m, "\n"); } @@ -4744,16 +4905,14 @@ static void _show_dm_step(struct rtw89_dev *rtwdev, struct seq_file *m) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; - u8 n_old = dm->dm_step.pos_old, n_new = dm->dm_step.pos_new; + u8 start_idx; u8 len; - if (n_new >= n_old) - len = n_new - n_old + 1; - else - len = RTW89_BTC_DM_MAXSTEP + n_new - n_old + 1; + len = dm->dm_step.step_ov ? RTW89_BTC_DM_MAXSTEP : dm->dm_step.step_pos; + start_idx = dm->dm_step.step_ov ? dm->dm_step.step_pos : 0; - seq_print_segment(m, "[dm_steps]", dm->dm_step.step, len, 6, n_old, - RTW89_BTC_DM_MAXSTEP); + seq_print_segment(m, "[dm_steps]", dm->dm_step.step, len, 6, start_idx, + ARRAY_SIZE(dm->dm_step.step)); } static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m) @@ -4771,10 +4930,11 @@ static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m) (btc->ctrl.manual ? "(Manual)" : "(Auto)")); seq_printf(m, - " %-15s : type:%s, reason:%d(), action:%d(), ant_path:%ld, run_cnt:%d\n", + " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%ld, run_cnt:%d\n", "[status]", module->ant.type == BTC_ANT_SHARED ? "shared" : "dedicated", - dm->run_reason, dm->run_action, + steps_to_str(dm->run_reason), + steps_to_str(dm->run_action | BTC_ACT_EXT_BIT), FIELD_GET(GENMASK(7, 0), dm->set_ant_path), dm->cnt_dm[BTC_DCNT_RUN]); @@ -4952,7 +5112,8 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; - struct rtw89_btc_fbtc_cysta *pcysta = NULL; + struct rtw89_btc_fbtc_cysta *pcysta_le32 = NULL; + struct rtw89_btc_fbtc_cysta_cpu pcysta[1]; union rtw89_btc_fbtc_rxflct r; u8 i, cnt = 0, slot_pair; u16 cycle, c_begin, c_end, store_index; @@ -4961,7 +5122,8 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) if (!pcinfo->valid) return; - pcysta = &pfwinfo->rpt_fbtc_cysta.finfo; + pcysta_le32 = &pfwinfo->rpt_fbtc_cysta.finfo; + rtw89_btc_fbtc_cysta_to_cpu(pcysta_le32, pcysta); seq_printf(m, " %-15s : cycle:%d, bcn[all:%d/all_ok:%d/bt:%d/bt_ok:%d]", "[cycle_cnt]", pcysta->cycles, pcysta->bcn_cnt[CXBCN_ALL], @@ -5039,7 +5201,7 @@ static void _show_fbtc_cysta(struct rtw89_dev *rtwdev, struct seq_file *m) "->b%02d->w%02d", pcysta->tslot_cycle[store_index], pcysta->tslot_cycle[store_index + 1]); - if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0) + if (cnt % (BTC_CYCLE_SLOT_MAX / 4) == 0 || cnt == c_end) seq_puts(m, "\n"); } @@ -5098,14 +5260,16 @@ static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m) seq_printf(m, ", null-%d", i); else seq_printf(m, "null-%d", i); - seq_printf(m, "[ok:%d/", ns->result[i][1]); - seq_printf(m, "fail:%d/", ns->result[i][0]); - seq_printf(m, "on_time:%d/", ns->result[i][2]); - seq_printf(m, "retry:%d/", ns->result[i][3]); + seq_printf(m, "[ok:%d/", le32_to_cpu(ns->result[i][1])); + seq_printf(m, "fail:%d/", le32_to_cpu(ns->result[i][0])); + seq_printf(m, "on_time:%d/", le32_to_cpu(ns->result[i][2])); + seq_printf(m, "retry:%d/", le32_to_cpu(ns->result[i][3])); seq_printf(m, "avg_t:%d.%03d/", - ns->avg_t[i] / 1000, ns->avg_t[i] % 1000); + le32_to_cpu(ns->avg_t[i]) / 1000, + le32_to_cpu(ns->avg_t[i]) % 1000); seq_printf(m, "max_t:%d.%03d]", - ns->max_t[i] / 1000, ns->max_t[i] % 1000); + le32_to_cpu(ns->max_t[i]) / 1000, + le32_to_cpu(ns->max_t[i]) % 1000); } seq_puts(m, "\n"); } @@ -5119,12 +5283,15 @@ static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) u8 type, val, cnt = 0, state = 0; bool outloop = false; u16 i, diff_t, n_start = 0, n_stop = 0; + u16 pos_old, pos_new; pcinfo = &pfwinfo->rpt_fbtc_step.cinfo; if (!pcinfo->valid) return; pstep = &pfwinfo->rpt_fbtc_step.finfo; + pos_old = le16_to_cpu(pstep->pos_old); + pos_new = le16_to_cpu(pstep->pos_new); if (pcinfo->req_fver != pstep->fver) return; @@ -5133,9 +5300,9 @@ static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) do { switch (state) { case 0: - n_start = pstep->pos_old; - if (pstep->pos_new >= pstep->pos_old) - n_stop = pstep->pos_new; + n_start = pos_old; + if (pos_new >= pos_old) + n_stop = pos_new; else n_stop = btc->ctrl.trace_step - 1; @@ -5145,7 +5312,7 @@ static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) for (i = n_start; i <= n_stop; i++) { type = pstep->step[i].type; val = pstep->step[i].val; - diff_t = pstep->step[i].difft; + diff_t = le16_to_cpu(pstep->step[i].difft); if (type == CXSTEP_NONE || type >= CXSTEP_MAX) continue; @@ -5164,9 +5331,9 @@ static void _show_fbtc_step(struct rtw89_dev *rtwdev, struct seq_file *m) state = 2; break; case 2: - if (pstep->pos_new < pstep->pos_old && n_start != 0) { + if (pos_new < pos_old && n_start != 0) { n_start = 0; - n_stop = pstep->pos_new; + n_stop = pos_new; state = 1; } else { outloop = true; @@ -5272,9 +5439,9 @@ static void _show_mreg(struct rtw89_dev *rtwdev, struct seq_file *m) __func__, pmreg->reg_num); for (i = 0; i < pmreg->reg_num; i++) { - type = (u8)chip->mon_reg[i].type; - offset = chip->mon_reg[i].offset; - val = pmreg->mreg_val[i]; + type = (u8)le16_to_cpu(chip->mon_reg[i].type); + offset = le32_to_cpu(chip->mon_reg[i].offset); + val = le32_to_cpu(pmreg->mreg_val[i]); if (cnt % 6 == 0) seq_printf(m, " %-15s : %d_0x%04x=0x%08x", @@ -5432,8 +5599,6 @@ void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m) seq_puts(m, "=========================================\n"); - seq_puts(m, "If no arguments, use seq_puts\n"); - seq_printf(m, "\n\r %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)", "[bt_info]", bt->raw_info[2], bt->raw_info[3], diff --git a/core.c b/core.c index 9295305f..dfb331d7 100644 --- a/core.c +++ b/core.c @@ -10,9 +10,10 @@ #include "phy.h" #include "ps.h" #include "reg.h" +#include "sar.h" #include "ser.h" #include "txrx.h" -#include +#include "util.h" static bool rtw89_disable_ps_mode; module_param_named(disable_ps_mode, rtw89_disable_ps_mode, bool, 0644); @@ -407,6 +408,84 @@ rtw89_core_tx_update_h2c_info(struct rtw89_dev *rtwdev, desc_info->ch_dma = RTW89_DMA_H2C; } +static bool +__rtw89_core_tx_check_he_qos_htc(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req, + enum btc_pkt_type pkt_type) +{ + struct ieee80211_sta *sta = tx_req->sta; + struct sk_buff *skb = tx_req->skb; + struct ieee80211_hdr *hdr = (void *)skb->data; + __le16 fc = hdr->frame_control; + + /* AP IOT issue with EAPoL, ARP and DHCP */ + if (pkt_type < PACKET_MAX) + return false; + + if (!sta || !sta->he_cap.has_he) + return false; + + if (!ieee80211_is_data_qos(fc)) + return false; + + if (skb_headroom(skb) < IEEE80211_HT_CTL_LEN) + return false; + + return true; +} + +static void +__rtw89_core_tx_adjust_he_qos_htc(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req) +{ + struct sk_buff *skb = tx_req->skb; + struct ieee80211_hdr *hdr = (void *)skb->data; + __le16 fc = hdr->frame_control; + void *data; + __le32 *htc; + u8 *qc; + int hdr_len; + + hdr_len = ieee80211_has_a4(fc) ? 32 : 26; + data = skb_push(skb, IEEE80211_HT_CTL_LEN); + memmove(data, data + IEEE80211_HT_CTL_LEN, hdr_len); + + hdr = data; + htc = data + hdr_len; + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_ORDER); + memset(htc, 0, sizeof(*htc)); + *htc = le32_encode_bits(RTW89_HTC_VARIANT_HE, RTW89_HTC_MASK_VARIANT) | + le32_encode_bits(RTW89_HTC_VARIANT_HE_CID_CAS, RTW89_HTC_MASK_CTL_ID); + + qc = data + hdr_len - IEEE80211_QOS_CTL_LEN; + qc[0] |= IEEE80211_QOS_CTL_EOSP; +} + +static void +rtw89_core_tx_update_he_qos_htc(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req, + enum btc_pkt_type pkt_type) +{ + struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; + struct ieee80211_vif *vif = tx_req->vif; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + + if (!__rtw89_core_tx_check_he_qos_htc(rtwdev, tx_req, pkt_type)) + goto desc_bk; + + __rtw89_core_tx_adjust_he_qos_htc(rtwdev, tx_req); + + desc_info->pkt_size += IEEE80211_HT_CTL_LEN; + desc_info->a_ctrl_bsr = true; + +desc_bk: + if (!rtwvif || rtwvif->last_a_ctrl == desc_info->a_ctrl_bsr) + return; + + rtwvif->last_a_ctrl = desc_info->a_ctrl_bsr; + desc_info->bk = true; +} + static void rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) @@ -473,6 +552,7 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, struct sk_buff *skb = tx_req->skb; struct ieee80211_hdr *hdr = (void *)skb->data; enum rtw89_core_tx_type tx_type; + enum btc_pkt_type pkt_type; bool is_bmc; u16 seq; @@ -495,7 +575,8 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, break; case RTW89_CORE_TX_TYPE_DATA: rtw89_core_tx_update_data_info(rtwdev, tx_req); - rtw89_core_tx_btc_spec_pkt_notify(rtwdev, tx_req); + pkt_type = rtw89_core_tx_btc_spec_pkt_notify(rtwdev, tx_req); + rtw89_core_tx_update_he_qos_htc(rtwdev, tx_req, pkt_type); break; case RTW89_CORE_TX_TYPE_FWCMD: rtw89_core_tx_update_h2c_info(rtwdev, tx_req); @@ -580,6 +661,7 @@ void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev, RTW89_SET_TXWD_BODY_QSEL(txdesc, desc_info->qsel); RTW89_SET_TXWD_BODY_TXPKT_SIZE(txdesc, desc_info->pkt_size); RTW89_SET_TXWD_BODY_AGG_EN(txdesc, desc_info->agg_en); + RTW89_SET_TXWD_BODY_BK(txdesc, desc_info->bk); if (!desc_info->en_wd_info) return; @@ -594,6 +676,7 @@ void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev, RTW89_SET_TXWD_INFO_SEC_CAM_IDX(txdesc, desc_info->sec_cam_idx); RTW89_SET_TXWD_INFO_RTS_EN(txdesc, 1); RTW89_SET_TXWD_INFO_HW_RTS_EN(txdesc, 1); + RTW89_SET_TXWD_INFO_A_CTRL_BSR(txdesc, desc_info->a_ctrl_bsr); } EXPORT_SYMBOL(rtw89_core_fill_txdesc); @@ -751,6 +834,26 @@ static void rtw89_core_rx_process_phy_sts(struct rtw89_dev *rtwdev, phy_ppdu->valid = true; } +static u8 rtw89_rxdesc_to_nl_he_gi(struct rtw89_dev *rtwdev, + const struct rtw89_rx_desc_info *desc_info, + bool rx_status) +{ + switch (desc_info->gi_ltf) { + case RTW89_GILTF_SGI_4XHE08: + case RTW89_GILTF_2XHE08: + case RTW89_GILTF_1XHE08: + return NL80211_RATE_INFO_HE_GI_0_8; + case RTW89_GILTF_2XHE16: + case RTW89_GILTF_1XHE16: + return NL80211_RATE_INFO_HE_GI_1_6; + case RTW89_GILTF_LGI_4XHE32: + return NL80211_RATE_INFO_HE_GI_3_2; + default: + rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info->gi_ltf); + return rx_status ? NL80211_RATE_INFO_HE_GI_3_2 : U8_MAX; + } +} + static bool rtw89_core_rx_ppdu_match(struct rtw89_dev *rtwdev, struct rtw89_rx_desc_info *desc_info, struct ieee80211_rx_status *status) @@ -784,22 +887,7 @@ static bool rtw89_core_rx_ppdu_match(struct rtw89_dev *rtwdev, else bw = RATE_INFO_BW_20; - switch (desc_info->gi_ltf) { - case RTW89_GILTF_SGI_4XHE08: - case RTW89_GILTF_2XHE08: - case RTW89_GILTF_1XHE08: - gi_ltf = NL80211_RATE_INFO_HE_GI_0_8; - break; - case RTW89_GILTF_2XHE16: - case RTW89_GILTF_1XHE16: - gi_ltf = NL80211_RATE_INFO_HE_GI_1_6; - break; - case RTW89_GILTF_LGI_4XHE32: - gi_ltf = NL80211_RATE_INFO_HE_GI_3_2; - break; - default: - gi_ltf = U8_MAX; - } + gi_ltf = rtw89_rxdesc_to_nl_he_gi(rtwdev, desc_info, false); ret = rtwdev->ppdu_sts.curr_rx_ppdu_cnt[band] == desc_info->ppdu_cnt && status->rate_idx == rate_idx && status->he_gi == gi_ltf && @@ -857,7 +945,7 @@ static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev, iter_data.desc_info = desc_info; iter_data.skb = skb; iter_data.bssid = get_hdr_bssid((struct ieee80211_hdr *)skb->data); - rtw89_iterate_vifs_atomic(rtwdev, rtw89_vif_rx_stats_iter, &iter_data); + rtw89_iterate_vifs_bh(rtwdev, rtw89_vif_rx_stats_iter, &iter_data); } static void rtw89_core_rx_pending_skb(struct rtw89_dev *rtwdev, @@ -1067,27 +1155,12 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev, rx_status->encoding = RX_ENC_HE; rx_status->rate_idx = GET_DATA_RATE_VHT_HE_IDX(data_rate); rx_status->nss = GET_DATA_RATE_NSS(data_rate) + 1; - - switch (desc_info->gi_ltf) { - case RTW89_GILTF_SGI_4XHE08: - case RTW89_GILTF_2XHE08: - case RTW89_GILTF_1XHE08: - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8; - break; - case RTW89_GILTF_2XHE16: - case RTW89_GILTF_1XHE16: - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_1_6; - break; - case RTW89_GILTF_LGI_4XHE32: - rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2; - break; - default: - break; - } } else { rtw89_warn(rtwdev, "invalid RX rate mode %d\n", data_rate_mode); } + /* he_gi is used to match ppdu, so we always fill it. */ + rx_status->he_gi = rtw89_rxdesc_to_nl_he_gi(rtwdev, desc_info, true); rx_status->flag |= RX_FLAG_MACTIME_START; rx_status->mactime = desc_info->free_run_cnt; @@ -1148,7 +1221,7 @@ void rtw89_core_rx(struct rtw89_dev *rtwdev, } rx_status = IEEE80211_SKB_RXCB(skb); - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + memset(rx_status, 0, sizeof(*rx_status)); rtw89_core_update_rx_status(rtwdev, desc_info, rx_status); if (desc_info->long_rxdesc && BIT(desc_info->frame_type) & PPDU_FILTER_BITMAP) { @@ -1206,22 +1279,29 @@ static void rtw89_core_ba_work(struct work_struct *work) list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->ba_list, list) { struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq); struct ieee80211_sta *sta = txq->sta; + struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; u8 tid = txq->tid; if (!sta) { rtw89_warn(rtwdev, "cannot start BA without sta\n"); - list_del_init(&rtwtxq->list); - continue; + goto skip_ba_work; + } + + if (rtwsta->disassoc) { + rtw89_debug(rtwdev, RTW89_DBG_TXRX, + "cannot start BA with disassoc sta\n"); + goto skip_ba_work; } ret = ieee80211_start_tx_ba_session(sta, tid, 0); if (ret) { - rtw89_info(rtwdev, - "failed to setup BA session for %pM:%2d: %d\n", - sta->addr, tid, ret); + rtw89_debug(rtwdev, RTW89_DBG_TXRX, + "failed to setup BA session for %pM:%2d: %d\n", + sta->addr, tid, ret); if (ret == -EINVAL) set_bit(RTW89_TXQ_F_BLOCK_BA, &rtwtxq->flags); } +skip_ba_work: list_del_init(&rtwtxq->list); } spin_unlock_bh(&rtwdev->ba_lock); @@ -1248,6 +1328,8 @@ static void rtw89_core_txq_check_agg(struct rtw89_dev *rtwdev, { struct ieee80211_hw *hw = rtwdev->hw; struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq); + struct ieee80211_sta *sta = txq->sta; + struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; if (unlikely(skb_get_queue_mapping(skb) == IEEE80211_AC_VO)) return; @@ -1255,7 +1337,7 @@ static void rtw89_core_txq_check_agg(struct rtw89_dev *rtwdev, if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) return; - if (unlikely(!txq->sta)) + if (unlikely(!sta)) return; if (unlikely(test_bit(RTW89_TXQ_F_BLOCK_BA, &rtwtxq->flags))) @@ -1267,7 +1349,7 @@ static void rtw89_core_txq_check_agg(struct rtw89_dev *rtwdev, } spin_lock_bh(&rtwdev->ba_lock); - if (list_empty(&rtwtxq->list)) { + if (!rtwsta->disassoc && list_empty(&rtwtxq->list)) { list_add_tail(&rtwtxq->list, &rtwdev->ba_list); ieee80211_queue_work(hw, &rtwdev->ba_work); } @@ -1312,7 +1394,40 @@ static u32 rtw89_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, u8 tid) return rtw89_hci_check_and_reclaim_tx_resource(rtwdev, ch_dma); } -static void rtw89_core_txq_schedule(struct rtw89_dev *rtwdev, u8 ac) +static bool rtw89_core_txq_agg_wait(struct rtw89_dev *rtwdev, + struct ieee80211_txq *txq, + unsigned long *frame_cnt, + bool *sched_txq, bool *reinvoke) +{ + struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv; + struct ieee80211_sta *sta = txq->sta; + struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + + if (!sta || rtwsta->max_agg_wait <= 0) + return false; + + if (rtwdev->stats.tx_tfc_lv <= RTW89_TFC_MID) + return false; + + if (*frame_cnt > 1) { + *frame_cnt -= 1; + *sched_txq = true; + *reinvoke = true; + rtwtxq->wait_cnt = 1; + return false; + } + + if (*frame_cnt == 1 && rtwtxq->wait_cnt < rtwsta->max_agg_wait) { + *reinvoke = true; + rtwtxq->wait_cnt++; + return true; + } + + rtwtxq->wait_cnt = 0; + return false; +} + +static void rtw89_core_txq_schedule(struct rtw89_dev *rtwdev, u8 ac, bool *reinvoke) { struct ieee80211_hw *hw = rtwdev->hw; struct ieee80211_txq *txq; @@ -1320,16 +1435,22 @@ static void rtw89_core_txq_schedule(struct rtw89_dev *rtwdev, u8 ac) unsigned long frame_cnt; unsigned long byte_cnt; u32 tx_resource; + bool sched_txq; ieee80211_txq_schedule_start(hw, ac); while ((txq = ieee80211_next_txq(hw, ac))) { rtwtxq = (struct rtw89_txq *)txq->drv_priv; tx_resource = rtw89_check_and_reclaim_tx_resource(rtwdev, txq->tid); + sched_txq = false; ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt); + if (rtw89_core_txq_agg_wait(rtwdev, txq, &frame_cnt, &sched_txq, reinvoke)) { + ieee80211_return_txq(hw, txq, true); + continue; + } frame_cnt = min_t(unsigned long, frame_cnt, tx_resource); rtw89_core_txq_push(rtwdev, rtwtxq, frame_cnt, byte_cnt); - ieee80211_return_txq(hw, txq, false); + ieee80211_return_txq(hw, txq, sched_txq); if (frame_cnt != 0) rtw89_core_tx_kick_off(rtwdev, rtw89_core_get_qsel(rtwdev, txq->tid)); } @@ -1339,10 +1460,24 @@ static void rtw89_core_txq_schedule(struct rtw89_dev *rtwdev, u8 ac) static void rtw89_core_txq_work(struct work_struct *w) { struct rtw89_dev *rtwdev = container_of(w, struct rtw89_dev, txq_work); + bool reinvoke = false; u8 ac; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - rtw89_core_txq_schedule(rtwdev, ac); + rtw89_core_txq_schedule(rtwdev, ac, &reinvoke); + + if (reinvoke) { + /* reinvoke to process the last frame */ + mod_delayed_work(rtwdev->txq_wq, &rtwdev->txq_reinvoke_work, 1); + } +} + +static void rtw89_core_txq_reinvoke_work(struct work_struct *w) +{ + struct rtw89_dev *rtwdev = container_of(w, struct rtw89_dev, + txq_reinvoke_work.work); + + queue_work(rtwdev->txq_wq, &rtwdev->txq_work); } static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev, @@ -1365,10 +1500,11 @@ static void rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev, enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv; enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv; - ewma_tp_add(&stats->tx_ewma_tp, - (u32)(stats->tx_unicast >> RTW89_TP_SHIFT)); - ewma_tp_add(&stats->rx_ewma_tp, - (u32)(stats->rx_unicast >> RTW89_TP_SHIFT)); + stats->tx_throughput_raw = (u32)(stats->tx_unicast >> RTW89_TP_SHIFT); + stats->rx_throughput_raw = (u32)(stats->rx_unicast >> RTW89_TP_SHIFT); + + ewma_tp_add(&stats->tx_ewma_tp, stats->tx_throughput_raw); + ewma_tp_add(&stats->rx_ewma_tp, stats->rx_throughput_raw); stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp); stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp); @@ -1376,6 +1512,8 @@ static void rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev, stats->tx_cnt); stats->rx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->rx_throughput, stats->rx_cnt); + stats->tx_avg_len = (u32)(stats->tx_cnt ? stats->tx_unicast / stats->tx_cnt : 0); + stats->rx_avg_len = (u32)(stats->rx_cnt ? stats->rx_unicast / stats->rx_cnt : 0); stats->tx_unicast = 0; stats->rx_unicast = 0; @@ -1399,7 +1537,7 @@ static void rtw89_traffic_stats_track(struct rtw89_dev *rtwdev) { rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats); - rtw89_iterate_vifs_atomic(rtwdev, rtw89_vif_traffic_stats_iter, rtwdev); + rtw89_iterate_vifs(rtwdev, rtw89_vif_traffic_stats_iter, rtwdev, false); } static void rtw89_vif_enter_lps_iter(void *data, u8 *mac, @@ -1418,7 +1556,7 @@ static void rtw89_vif_enter_lps_iter(void *data, u8 *mac, static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev) { - rtw89_iterate_vifs_atomic(rtwdev, rtw89_vif_enter_lps_iter, rtwdev); + rtw89_iterate_vifs(rtwdev, rtw89_vif_enter_lps_iter, rtwdev, false); } void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev, @@ -1445,7 +1583,7 @@ static void rtw89_track_work(struct work_struct *work) ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); - rtw89_leave_lps(rtwdev); + rtw89_leave_lps(rtwdev, false); rtw89_traffic_stats_track(rtwdev); rtw89_mac_bf_monitor_track(rtwdev); @@ -1456,7 +1594,7 @@ static void rtw89_track_work(struct work_struct *work) rtw89_phy_ra_update(rtwdev); rtw89_phy_cfo_track(rtwdev); - if (rtwdev->lps_enabled && !rtwdev->btc.lps) + if (rtwdev->lps_enabled && !rtwdev->btc.lps && !rtwdev->scanning) rtw89_enter_lps_track(rtwdev); out: @@ -1495,6 +1633,11 @@ void rtw89_core_release_bit_map(unsigned long *addr, u8 bit) clear_bit(bit, addr); } +void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits) +{ + bitmap_zero(addr, nbits); +} + #define RTW89_TYPE_MAPPING(_type) \ case NL80211_IFTYPE_ ## _type: \ rtwvif->wifi_role = RTW89_WIFI_ROLE_ ## _type; \ @@ -1575,7 +1718,10 @@ int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { + struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + rtwdev->total_sta_assoc--; + rtwsta->disassoc = true; return 0; } @@ -1745,10 +1891,14 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, enum nl80211_band band, struct ieee80211_supported_band *sband) { + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_hal *hal = &rtwdev->hal; struct ieee80211_sband_iftype_data *iftype_data; + bool no_ng16 = (chip->chip_id == RTL8852A && hal->cv == CHIP_CBV) || + (chip->chip_id == RTL8852B && hal->cv == CHIP_CAV); u16 mcs_map = 0; int i; - int nss = rtwdev->chip->rx_nss; + int nss = chip->rx_nss; int idx = 0; iftype_data = kcalloc(RTW89_SBAND_IFTYPES_NR, sizeof(*iftype_data), GFP_KERNEL); @@ -1813,9 +1963,14 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | IEEE80211_HE_PHY_CAP2_DOPPLER_TX; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,13,0) + phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA; +#else phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM; +#endif if (i == NL80211_IFTYPE_STATION) phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM | IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2; @@ -1827,7 +1982,8 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, #endif phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; - phy_cap_info[5] = IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | + phy_cap_info[5] = no_ng16 ? 0 : + IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | @@ -1961,6 +2117,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) set_bit(RTW89_FLAG_RUNNING, rtwdev->flags); rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); + rtw89_fw_h2c_fw_log(rtwdev, rtwdev->fw.fw_log_enable); return 0; } @@ -1984,8 +2141,10 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev) cancel_work_sync(&btc->arp_notify_work); cancel_work_sync(&btc->dhcp_notify_work); cancel_work_sync(&btc->wl_sta_notify_work); + cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work); cancel_delayed_work_sync(&rtwdev->track_work); cancel_delayed_work_sync(&rtwdev->coex_act1_work); + cancel_delayed_work_sync(&rtwdev->cfo_track_work); mutex_lock(&rtwdev->mutex); @@ -2006,8 +2165,10 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_LIST_HEAD(&rtwdev->ba_list); INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work); INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work); + INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work); INIT_DELAYED_WORK(&rtwdev->track_work, rtw89_track_work); INIT_DELAYED_WORK(&rtwdev->coex_act1_work, rtw89_coex_act1_work); + INIT_DELAYED_WORK(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work); rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); spin_lock_init(&rtwdev->ba_lock); mutex_init(&rtwdev->mutex); @@ -2020,6 +2181,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) rtw89_traffic_stats_init(rtwdev, &rtwdev->stats); rtwdev->ps_mode = rtw89_update_ps_mode(rtwdev); + rtwdev->hal.rx_fltr = DEFAULT_AX_RX_FLTR; INIT_WORK(&btc->eapol_notify_work, rtw89_btc_ntfy_eapol_packet_work); INIT_WORK(&btc->arp_notify_work, rtw89_btc_ntfy_arp_packet_work); @@ -2126,6 +2288,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) struct ieee80211_hw *hw = rtwdev->hw; struct rtw89_efuse *efuse = &rtwdev->efuse; int ret; + int tx_headroom = IEEE80211_HT_CTL_LEN; hw->vif_data_size = sizeof(struct rtw89_vif); hw->sta_data_size = sizeof(struct rtw89_sta); @@ -2133,6 +2296,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) SET_IEEE80211_PERM_ADDR(hw, efuse->addr); + hw->extra_tx_headroom = tx_headroom; hw->queues = IEEE80211_NUM_ACS; hw->max_rx_aggregation_subframes = RTW89_MAX_RX_AGG_NUM; hw->max_tx_aggregation_subframes = RTW89_MAX_TX_AGG_NUM; @@ -2150,6 +2314,8 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + hw->wiphy->available_antennas_tx = BIT(rtwdev->chip->rf_path_num) - 1; + hw->wiphy->available_antennas_rx = BIT(rtwdev->chip->rf_path_num) - 1; hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; @@ -2162,7 +2328,9 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) } hw->wiphy->reg_notifier = rtw89_regd_notifier; - +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) + hw->wiphy->sar_capa = &rtw89_sar_capa; +#endif ret = ieee80211_register_hw(hw); if (ret) { rtw89_err(rtwdev, "failed to register hw\n"); diff --git a/core.h b/core.h index 3e30f643..a8656336 100644 --- a/core.h +++ b/core.h @@ -30,18 +30,26 @@ extern const struct rtw89_chip_info rtw8852a_chip_info; #define INV_RF_DATA 0xffffffff #define RTW89_TRACK_WORK_PERIOD round_jiffies_relative(HZ * 2) -#define CFO_TRACK_MAX_USER 128 +#define CFO_TRACK_MAX_USER 64 #define MAX_RSSI 110 #define RSSI_FACTOR 1 #define RTW89_RSSI_RAW_TO_DBM(rssi) ((s8)((rssi) >> RSSI_FACTOR) - MAX_RSSI) #define RTW89_MAX_HW_PORT_NUM 5 +#define RTW89_HTC_MASK_VARIANT GENMASK(1, 0) +#define RTW89_HTC_VARIANT_HE 3 +#define RTW89_HTC_MASK_CTL_ID GENMASK(5, 2) +#define RTW89_HTC_VARIANT_HE_CID_CAS 6 +#define RTW89_HTC_MASK_CTL_INFO GENMASK(31, 6) + enum rtw89_subband { RTW89_CH_2G = 0, RTW89_CH_5G_BAND_1 = 1, /* RTW89_CH_5G_BAND_2 = 2, unused */ RTW89_CH_5G_BAND_3 = 3, RTW89_CH_5G_BAND_4 = 4, + + RTW89_SUBBAND_NR, }; enum rtw89_hci_type { @@ -656,6 +664,7 @@ struct rtw89_tx_desc_info { bool dis_data_fb; bool tid_indicate; bool agg_en; + bool bk; u8 ampdu_density; u8 ampdu_num; bool sec_en; @@ -664,6 +673,7 @@ struct rtw89_tx_desc_info { u16 data_rate; bool fw_dl; u16 seq; + bool a_ctrl_bsr; }; struct rtw89_core_tx_request { @@ -678,6 +688,7 @@ struct rtw89_core_tx_request { struct rtw89_txq { struct list_head list; unsigned long flags; + int wait_cnt; }; struct rtw89_mac_ax_gnt { @@ -834,6 +845,8 @@ struct rtw89_traffic_stats { /* units in bytes */ u64 tx_unicast; u64 rx_unicast; + u32 tx_avg_len; + u32 rx_avg_len; /* count for packets */ u64 tx_cnt; @@ -842,10 +855,13 @@ struct rtw89_traffic_stats { /* units in Mbps */ u32 tx_throughput; u32 rx_throughput; + u32 tx_throughput_raw; + u32 rx_throughput_raw; enum rtw89_tfc_lv tx_tfc_lv; enum rtw89_tfc_lv rx_tfc_lv; struct ewma_tp tx_ewma_tp; struct ewma_tp rx_ewma_tp; + u16 tx_rate; u16 rx_rate; }; @@ -986,8 +1002,8 @@ struct rtw89_btc_wl_active_role { u16 tx_lvl; u16 rx_lvl; - u32 tx_rate; - u32 rx_rate; + u16 tx_rate; + u16 rx_rate; }; struct rtw89_btc_wl_role_info_bpos { @@ -1030,7 +1046,7 @@ struct rtw89_btc_wl_afh_info { u8 ch; u8 bw; u8 rsvd; -}; +} __packed; struct rtw89_btc_wl_rfk_info { u32 state: 2; @@ -1146,13 +1162,12 @@ struct rtw89_btc_module { }; #define RTW89_BTC_DM_MAXSTEP 30 +#define RTW89_BTC_DM_CNT_MAX (RTW89_BTC_DM_MAXSTEP * 8) struct rtw89_btc_dm_step { - u8 step[RTW89_BTC_DM_MAXSTEP]; - u8 pos_new; /* the latest step in which array index */ - u8 pos_old; /* the oldest step in which array index */ - u8 step_cnt; /* the total step cnt */ - u8 rsvd; + u16 step[RTW89_BTC_DM_MAXSTEP]; + u8 step_pos; + bool step_ov; }; struct rtw89_btc_init_info { @@ -1359,6 +1374,10 @@ struct rtw89_btc_fbtc_mreg_val { __le32 mreg_val[CXMREG_MAX]; } __packed; +#define RTW89_DEF_FBTC_MREG(__type, __bytes, __offset) \ + { .type = cpu_to_le16(__type), .bytes = cpu_to_le16(__bytes), \ + .offset = cpu_to_le32(__offset), } + struct rtw89_btc_fbtc_mreg { __le16 type; __le16 bytes; @@ -1797,15 +1816,20 @@ DECLARE_EWMA(rssi, 10, 16); struct rtw89_sta { u8 mac_id; + bool disassoc; struct rtw89_vif *rtwvif; struct rtw89_ra_info ra; struct rtw89_ra_report ra_report; + int max_agg_wait; u8 prev_rssi; struct ewma_rssi avg_rssi; struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS]; struct ieee80211_rx_status rx_status; u16 rx_hw_rate; + bool use_cfg_mask; + struct cfg80211_bitrate_mask mask; + bool cctl_tx_time; u32 ampdu_max_time:4; bool cctl_tx_retry_limit; @@ -1866,6 +1890,7 @@ struct rtw89_efuse { }; struct rtw89_vif { + struct list_head list; u8 mac_id; u8 port; u8 mac_addr[ETH_ALEN]; @@ -1886,6 +1911,7 @@ struct rtw89_vif { bool wowlan_uc; bool wowlan_magic; bool is_hesta; + bool last_a_ctrl; union { struct { struct ieee80211_sta *ap; @@ -1900,6 +1926,11 @@ struct rtw89_vif { struct rtw89_traffic_stats stats; }; +enum rtw89_lv1_rcvy_step { + RTW89_LV1_RCVY_STEP_1, + RTW89_LV1_RCVY_STEP_2, +}; + struct rtw89_hci_ops { int (*tx_write)(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req); void (*tx_kick_off)(struct rtw89_dev *rtwdev, u8 txch); @@ -1921,7 +1952,8 @@ struct rtw89_hci_ops { int (*deinit)(struct rtw89_dev *rtwdev); u32 (*check_and_reclaim_tx_resource)(struct rtw89_dev *rtwdev, u8 txch); - int (*mac_lv1_rcvy)(struct rtw89_dev *rtwdev, u8 step); + int (*mac_lv1_rcvy)(struct rtw89_dev *rtwdev, enum rtw89_lv1_rcvy_step step); + void (*dump_err_status)(struct rtw89_dev *rtwdev); int (*napi_poll)(struct napi_struct *napi, int budget); }; @@ -1961,6 +1993,8 @@ struct rtw89_chip_ops { struct rtw89_rx_phy_ppdu *phy_ppdu, struct ieee80211_rx_status *status); void (*bb_ctrl_btc_preagc)(struct rtw89_dev *rtwdev, bool bt_en); + void (*set_txpwr_ul_tb_offset)(struct rtw89_dev *rtwdev, + s16 pw_ofst, enum rtw89_mac_idx mac_idx); void (*btc_set_rfe)(struct rtw89_dev *rtwdev); void (*btc_init_cfg)(struct rtw89_dev *rtwdev); @@ -2257,6 +2291,7 @@ struct rtw89_fw_info { u8 rec_seq; struct rtw89_fw_suit normal; struct rtw89_fw_suit wowlan; + bool fw_log_enable; }; struct rtw89_cam_info { @@ -2265,6 +2300,30 @@ struct rtw89_cam_info { DECLARE_BITMAP(sec_cam_map, RTW89_MAX_SEC_CAM_NUM); }; +enum rtw89_sar_sources { + RTW89_SAR_SOURCE_NONE, + RTW89_SAR_SOURCE_COMMON, + + RTW89_SAR_SOURCE_NR, +}; + +struct rtw89_sar_cfg_common { + bool set[RTW89_SUBBAND_NR]; + s32 cfg[RTW89_SUBBAND_NR]; +}; + +struct rtw89_sar_info { + /* used to decide how to acces SAR cfg union */ + enum rtw89_sar_sources src; + + /* reserved for different knids of SAR cfg struct. + * supposed that a single cfg struct cannot handle various SAR sources. + */ + union { + struct rtw89_sar_cfg_common cfg_common; + }; +}; + struct rtw89_hal { u32 rx_fltr; u8 cv; @@ -2278,6 +2337,8 @@ struct rtw89_hal { */ u8 cch_by_bw[RTW89_MAX_CHANNEL_WIDTH + 1]; u32 sw_amsdu_max_size; + u32 antenna_tx; + u32 antenna_rx; }; #define RTW89_MAX_MAC_ID_NUM 128 @@ -2440,18 +2501,41 @@ struct rtw89_dig_info { bool is_linked_pre; }; +enum rtw89_multi_cfo_mode { + RTW89_PKT_BASED_AVG_MODE = 0, + RTW89_ENTRY_BASED_AVG_MODE = 1, + RTW89_TP_BASED_AVG_MODE = 2, +}; + +enum rtw89_phy_cfo_status { + RTW89_PHY_DCFO_STATE_NORMAL = 0, + RTW89_PHY_DCFO_STATE_ENHANCE = 1, + RTW89_PHY_DCFO_STATE_MAX +}; + struct rtw89_cfo_tracking_info { + u16 cfo_timer_ms; + bool cfo_trig_by_timer_en; + enum rtw89_phy_cfo_status phy_cfo_status; + u8 phy_cfo_trk_cnt; bool is_adjust; + enum rtw89_multi_cfo_mode rtw89_multi_cfo_mode; bool apply_compensation; u8 crystal_cap; u8 crystal_cap_default; u8 def_x_cap; + s8 x_cap_ofst; + u32 sta_cfo_tolerance; s32 cfo_tail[CFO_TRACK_MAX_USER]; u16 cfo_cnt[CFO_TRACK_MAX_USER]; s32 cfo_avg_pre; + s32 cfo_avg[CFO_TRACK_MAX_USER]; + s32 pre_cfo_avg[CFO_TRACK_MAX_USER]; u32 packet_count; u32 packet_count_pre; s32 residual_cfo_acc; + u8 phy_cfotrk_state; + u8 phy_cfotrk_cnt; }; /* 2GL, 2GH, 5GL1, 5GH1, 5GM1, 5GM2, 5GH1, 5GH2 */ @@ -2678,6 +2762,7 @@ struct rtw89_dev { struct mutex rf_mutex; struct workqueue_struct *txq_wq; struct work_struct txq_work; + struct delayed_work txq_reinvoke_work; /* used to protect ba_list */ spinlock_t ba_lock; /* txqs to setup ba session */ @@ -2713,15 +2798,16 @@ struct rtw89_dev { struct rtw89_phy_ch_info ch_info; struct delayed_work track_work; struct delayed_work coex_act1_work; + struct delayed_work cfo_track_work; struct rtw89_ppdu_sts_info ppdu_sts; u8 total_sta_assoc; bool scanning; const struct rtw89_regulatory *regd; + struct rtw89_sar_info sar; struct rtw89_btc btc; enum rtw89_ps_mode ps_mode; - struct rtw89_lps_parm lps_parm; bool lps_enabled; /* napi structure */ @@ -2963,13 +3049,9 @@ static inline void rtw89_write_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, u32 addr, u32 mask, u32 data) { - if (in_atomic()) { - rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data); - } else { - mutex_lock(&rtwdev->rf_mutex); - rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data); - mutex_unlock(&rtwdev->rf_mutex); - } + mutex_lock(&rtwdev->rf_mutex); + rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data); + mutex_unlock(&rtwdev->rf_mutex); } static inline struct ieee80211_txq *rtw89_txq_to_txq(struct rtw89_txq *rtwtxq) @@ -3134,6 +3216,20 @@ static inline void rtw89_chip_bb_ctrl_btc_preagc(struct rtw89_dev *rtwdev, chip->ops->bb_ctrl_btc_preagc(rtwdev, bt_en); } +static inline +void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif) +{ + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (!vif->bss_conf.he_support || !vif->bss_conf.assoc) + return; + + if (chip->ops->set_txpwr_ul_tb_offset) + chip->ops->set_txpwr_ul_tb_offset(rtwdev, 0, rtwvif->mac_idx); +} + static inline void rtw89_load_txpwr_table(struct rtw89_dev *rtwdev, const struct rtw89_txpwr_table *tbl) { @@ -3165,10 +3261,6 @@ static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr) return hdr->addr3; } -#define rtw89_iterate_vifs_atomic(rtwdev, iterator, data) \ - ieee80211_iterate_active_interfaces_atomic((rtwdev)->hw, \ - IEEE80211_IFACE_ITER_NORMAL, iterator, data) - static inline bool rtw89_sta_has_beamformer_cap(struct ieee80211_sta *sta) { if ((sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || @@ -3230,6 +3322,7 @@ void rtw89_core_unregister(struct rtw89_dev *rtwdev); void rtw89_set_channel(struct rtw89_dev *rtwdev); u8 rtw89_core_acquire_bit_map(unsigned long *addr, unsigned long size); void rtw89_core_release_bit_map(unsigned long *addr, u8 bit); +void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits); void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc); int rtw89_chip_info_setup(struct rtw89_dev *rtwdev); u16 rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate); diff --git a/debug.c b/debug.c index b0cd5401..5db3f9e8 100644 --- a/debug.c +++ b/debug.c @@ -6,7 +6,9 @@ #include "debug.h" #include "fw.h" #include "mac.h" +#include "ps.h" #include "reg.h" +#include "sar.h" #ifdef CONFIG_RTW89_DEBUGMSG unsigned int rtw89_debug_mask; @@ -553,10 +555,16 @@ static int rtw89_debug_priv_txpwr_table_get(struct seq_file *m, void *v) int ret = 0; mutex_lock(&rtwdev->mutex); + rtw89_leave_ps_mode(rtwdev); seq_puts(m, "[Regulatory] "); __print_regd(m, rtwdev); + seq_puts(m, "[SAR]\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) + rtw89_print_sar(m, rtwdev); +#endif + seq_puts(m, "\n[TX power byrate]\n"); ret = __print_txpwr_map(m, rtwdev, &__txpwr_map_byr); if (ret) @@ -751,8 +759,7 @@ static void rtw89_debug_dump_mac_mem(struct seq_file *m, dump_len = min_t(u32, remain, MAC_MEM_DUMP_PAGE_SIZE); rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, base_addr); for (i = R_AX_INDIR_ACCESS_ENTRY + residue; - i < R_AX_INDIR_ACCESS_ENTRY + dump_len; - i += 4) { + i < R_AX_INDIR_ACCESS_ENTRY + dump_len;) { seq_printf(m, "%08xh:", i); for (j = 0; j < 4 && i < R_AX_INDIR_ACCESS_ENTRY + dump_len; @@ -773,10 +780,13 @@ rtw89_debug_priv_mac_mem_dump_get(struct seq_file *m, void *v) struct rtw89_debugfs_priv *debugfs_priv = m->private; struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; + mutex_lock(&rtwdev->mutex); + rtw89_leave_ps_mode(rtwdev); rtw89_debug_dump_mac_mem(m, rtwdev, debugfs_priv->mac_mem.sel, debugfs_priv->mac_mem.start, debugfs_priv->mac_mem.len); + mutex_unlock(&rtwdev->mutex); return 0; } @@ -2127,12 +2137,32 @@ static ssize_t rtw89_debug_priv_btc_manual_set(struct file *filp, struct rtw89_debugfs_priv *debugfs_priv = filp->private_data; struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; struct rtw89_btc *btc = &rtwdev->btc; - int btc_manual; + bool btc_manual; + + if (kstrtobool_from_user(user_buf, count, &btc_manual)) + goto out; + + btc->ctrl.manual = btc_manual; +out: + return count; +} + +static ssize_t rtw89_debug_fw_log_btc_manual_set(struct file *filp, + const char __user *user_buf, + size_t count, loff_t *loff) +{ + struct rtw89_debugfs_priv *debugfs_priv = filp->private_data; + struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; + struct rtw89_fw_info *fw_info = &rtwdev->fw; + bool fw_log_manual; - if (kstrtoint_from_user(user_buf, count, 10, &btc_manual) != 0) + if (kstrtobool_from_user(user_buf, count, &fw_log_manual)) goto out; - btc->ctrl.manual = !!btc_manual; + mutex_lock(&rtwdev->mutex); + fw_info->fw_log_enable = fw_log_manual; + rtw89_fw_h2c_fw_log(rtwdev, fw_log_manual); + mutex_unlock(&rtwdev->mutex); out: return count; } @@ -2164,7 +2194,9 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) he_gi_str[rate->he_gi] : "N/A"); else seq_printf(m, "Legacy %d", rate->legacy); - seq_printf(m, "\t(hw_rate=0x%x)\n", rtwsta->ra_report.hw_rate); + seq_printf(m, "\t(hw_rate=0x%x)", rtwsta->ra_report.hw_rate); + seq_printf(m, "\t==> agg_wait=%d (%d)\n", rtwsta->max_agg_wait, + sta->max_rc_amsdu_len); seq_printf(m, "RX rate [%d]: ", rtwsta->mac_id); @@ -2229,10 +2261,12 @@ static int rtw89_debug_priv_phy_info_get(struct seq_file *m, void *v) const struct rtw89_rx_rate_cnt_info *info; int i; - seq_printf(m, "TP TX: %u Mbps (lv: %d), RX: %u Mbps (lv: %d)\n", - stats->tx_throughput, stats->tx_tfc_lv, - stats->rx_throughput, stats->rx_tfc_lv); + seq_printf(m, "TP TX: %u [%u] Mbps (lv: %d), RX: %u [%u] Mbps (lv: %d)\n", + stats->tx_throughput, stats->tx_throughput_raw, stats->tx_tfc_lv, + stats->rx_throughput, stats->rx_throughput_raw, stats->rx_tfc_lv); seq_printf(m, "Beacon: %u\n", pkt_stat->beacon_nr); + seq_printf(m, "Avg packet length: TX=%u, RX=%u\n", stats->tx_avg_len, + stats->rx_avg_len); seq_puts(m, "RX count:\n"); for (i = 0; i < ARRAY_SIZE(rtw89_rx_rate_cnt_infos); i++) { @@ -2301,6 +2335,10 @@ static struct rtw89_debugfs_priv rtw89_debug_priv_btc_manual = { .cb_write = rtw89_debug_priv_btc_manual_set, }; +static struct rtw89_debugfs_priv rtw89_debug_priv_fw_log_manual = { + .cb_write = rtw89_debug_fw_log_btc_manual_set, +}; + static struct rtw89_debugfs_priv rtw89_debug_priv_phy_info = { .cb_read = rtw89_debug_priv_phy_info_get, }; @@ -2340,6 +2378,7 @@ void rtw89_debugfs_init(struct rtw89_dev *rtwdev) rtw89_debugfs_add_w(send_h2c); rtw89_debugfs_add_r(btc_info); rtw89_debugfs_add_w(btc_manual); + rtw89_debugfs_add_w(fw_log_manual); rtw89_debugfs_add_r(phy_info); } #endif diff --git a/dkms.conf b/dkms.conf new file mode 100644 index 00000000..d69191f5 --- /dev/null +++ b/dkms.conf @@ -0,0 +1,12 @@ +PACKAGE_NAME="rtw89" +PACKAGE_VERSION=1 +MAKE="make -C $kernel_source_dir M=$dkms_tree/$PACKAGE_NAME/build" +CLEAN="make -C $kernel_source_dir clean" +BUILT_MODULE_NAME[0]="rtw89pci" +BUILT_MODULE_NAME[1]="rtw89core" +DEST_MODULE_LOCATION[0]="/updates" +DEST_MODULE_LOCATION[1]="/updates" +BUILT_MODULE_LOCATION="rtw89" +REMAKE_INITRD=no +AUTOINSTALL=yes + diff --git a/fw.c b/fw.c index 5c9f7f54..7be5ce2c 100644 --- a/fw.c +++ b/fw.c @@ -371,10 +371,27 @@ static int rtw89_fw_download_main(struct rtw89_dev *rtwdev, const u8 *fw, return 0; } +static void rtw89_fw_prog_cnt_dump(struct rtw89_dev *rtwdev) +{ + u32 val32; + u16 index; + + rtw89_write32(rtwdev, R_AX_DBG_CTRL, + FIELD_PREP(B_AX_DBG_SEL0, FW_PROG_CNTR_DBG_SEL) | + FIELD_PREP(B_AX_DBG_SEL1, FW_PROG_CNTR_DBG_SEL)); + rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, B_AX_SEL_0XC0, MAC_DBG_SEL); + + for (index = 0; index < 15; index++) { + val32 = rtw89_read32(rtwdev, R_AX_DBG_PORT_SEL); + rtw89_err(rtwdev, "[ERR]fw PC = 0x%x\n", val32); + fsleep(10); + } +} + static void rtw89_fw_dl_fail_dump(struct rtw89_dev *rtwdev) { u32 val32; - u16 val16, index; + u16 val16; val32 = rtw89_read32(rtwdev, R_AX_WCPU_FW_CTRL); rtw89_err(rtwdev, "[ERR]fwdl 0x1E0 = 0x%x\n", val32); @@ -382,14 +399,7 @@ static void rtw89_fw_dl_fail_dump(struct rtw89_dev *rtwdev) val16 = rtw89_read16(rtwdev, R_AX_BOOT_DBG + 2); rtw89_err(rtwdev, "[ERR]fwdl 0x83F2 = 0x%x\n", val16); - rtw89_write32(rtwdev, R_AX_DBG_CTRL, 0xf200f2); - rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, B_AX_SEL_0XC0, 1); - - for (index = 0; index < 15; index++) { - val32 = rtw89_read32(rtwdev, R_AX_DBG_PORT_SEL); - rtw89_err(rtwdev, "[ERR]fw PC = 0x%x\n", val32); - udelay(10); - } + rtw89_fw_prog_cnt_dump(rtwdev); } int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type) @@ -576,6 +586,43 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, bool valid, u8 macid, return -EBUSY; } +#define H2C_LOG_CFG_LEN 12 +int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable) +{ + struct sk_buff *skb; + u32 comp = enable ? BIT(RTW89_FW_LOG_COMP_INIT) | BIT(RTW89_FW_LOG_COMP_TASK) | + BIT(RTW89_FW_LOG_COMP_PS) | BIT(RTW89_FW_LOG_COMP_ERROR) : 0; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LOG_CFG_LEN); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for fw log cfg\n"); + return -ENOMEM; + } + + skb_put(skb, H2C_LOG_CFG_LEN); + SET_LOG_CFG_LEVEL(skb->data, RTW89_FW_LOG_LEVEL_SER); + SET_LOG_CFG_PATH(skb->data, BIT(RTW89_FW_LOG_LEVEL_C2H)); + SET_LOG_CFG_COMP(skb->data, comp); + SET_LOG_CFG_COMP_EXT(skb->data, 0); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_FW_INFO, + H2C_FUNC_LOG_CFG, 0, 0, + H2C_LOG_CFG_LEN); + + if (rtw89_h2c_tx(rtwdev, skb, false)) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return -EBUSY; +} + #define H2C_GENERAL_PKT_LEN 6 #define H2C_GENERAL_PKT_ID_UND 0xff int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, u8 macid) @@ -614,10 +661,10 @@ int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, u8 macid) } #define H2C_LPS_PARM_LEN 8 -int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, u8 macid) +int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, + struct rtw89_lps_parm *lps_param) { struct sk_buff *skb; - struct rtw89_lps_parm *lps_param = &rtwdev->lps_parm; skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LPS_PARM_LEN); if (!skb) { @@ -658,7 +705,10 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, u8 macid) #define H2C_CMC_TBL_LEN 68 int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, u8 macid) { + struct rtw89_hal *hal = &rtwdev->hal; struct sk_buff *skb; + u8 ntx_path = hal->antenna_tx ? hal->antenna_tx : RF_B; + u8 map_b = hal->antenna_tx == RF_AB ? 1 : 0; skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_CMC_TBL_LEN); if (!skb) { @@ -669,10 +719,9 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, u8 macid) SET_CTRL_INFO_MACID(skb->data, macid); SET_CTRL_INFO_OPERATION(skb->data, 1); SET_CMC_TBL_TXPWR_MODE(skb->data, 0); - SET_CMC_TBL_NTX_PATH_EN(skb->data, 2); + SET_CMC_TBL_NTX_PATH_EN(skb->data, ntx_path); SET_CMC_TBL_PATH_MAP_A(skb->data, 0); - SET_CMC_TBL_PATH_MAP_B(skb->data, 0); - /* RTW_WKARD_DEF_CMACTBL_CFG */ + SET_CMC_TBL_PATH_MAP_B(skb->data, map_b); SET_CMC_TBL_PATH_MAP_C(skb->data, 0); SET_CMC_TBL_PATH_MAP_D(skb->data, 0); SET_CMC_TBL_ANTSEL_A(skb->data, 0); @@ -786,6 +835,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, SET_CMC_TBL_NOMINAL_PKT_PADDING(skb->data, pads[RTW89_CHANNEL_WIDTH_20]); SET_CMC_TBL_NOMINAL_PKT_PADDING40(skb->data, pads[RTW89_CHANNEL_WIDTH_40]); SET_CMC_TBL_NOMINAL_PKT_PADDING80(skb->data, pads[RTW89_CHANNEL_WIDTH_80]); + SET_CMC_TBL_BSR_QUEUE_SIZE_FORMAT(skb->data, sta->he_cap.has_he); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, @@ -1085,6 +1135,221 @@ int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi return -EBUSY; } +#define H2C_LEN_CXDRVHDR 2 +#define H2C_LEN_CXDRVINFO_INIT (12 + H2C_LEN_CXDRVHDR) +int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_init_info *init_info = &dm->init_info; + struct rtw89_btc_module *module = &init_info->module; + struct rtw89_btc_ant_info *ant = &module->ant; + struct sk_buff *skb; + u8 *cmd; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_CXDRVINFO_INIT); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_init\n"); + return -ENOMEM; + } + skb_put(skb, H2C_LEN_CXDRVINFO_INIT); + cmd = skb->data; + + RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_INIT); + RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_INIT - H2C_LEN_CXDRVHDR); + + RTW89_SET_FWCMD_CXINIT_ANT_TYPE(cmd, ant->type); + RTW89_SET_FWCMD_CXINIT_ANT_NUM(cmd, ant->num); + RTW89_SET_FWCMD_CXINIT_ANT_ISO(cmd, ant->isolation); + RTW89_SET_FWCMD_CXINIT_ANT_POS(cmd, ant->single_pos); + RTW89_SET_FWCMD_CXINIT_ANT_DIVERSITY(cmd, ant->diversity); + + RTW89_SET_FWCMD_CXINIT_MOD_RFE(cmd, module->rfe_type); + RTW89_SET_FWCMD_CXINIT_MOD_CV(cmd, module->cv); + RTW89_SET_FWCMD_CXINIT_MOD_BT_SOLO(cmd, module->bt_solo); + RTW89_SET_FWCMD_CXINIT_MOD_BT_POS(cmd, module->bt_pos); + RTW89_SET_FWCMD_CXINIT_MOD_SW_TYPE(cmd, module->switch_type); + + RTW89_SET_FWCMD_CXINIT_WL_GCH(cmd, init_info->wl_guard_ch); + RTW89_SET_FWCMD_CXINIT_WL_ONLY(cmd, init_info->wl_only); + RTW89_SET_FWCMD_CXINIT_WL_INITOK(cmd, init_info->wl_init_ok); + RTW89_SET_FWCMD_CXINIT_DBCC_EN(cmd, init_info->dbcc_en); + RTW89_SET_FWCMD_CXINIT_CX_OTHER(cmd, init_info->cx_other); + RTW89_SET_FWCMD_CXINIT_BT_ONLY(cmd, init_info->bt_only); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, BTFC_SET, + SET_DRV_INFO, 0, 0, + H2C_LEN_CXDRVINFO_INIT); + + if (rtw89_h2c_tx(rtwdev, skb, false)) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return -EBUSY; +} + +#define H2C_LEN_CXDRVINFO_ROLE (4 + 12 * RTW89_MAX_HW_PORT_NUM + H2C_LEN_CXDRVHDR) +int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_wl_info *wl = &btc->cx.wl; + struct rtw89_btc_wl_role_info *role_info = &wl->role_info; + struct rtw89_btc_wl_role_info_bpos *bpos = &role_info->role_map.role; + struct rtw89_btc_wl_active_role *active = role_info->active_role; + struct sk_buff *skb; + u8 *cmd; + int i; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_CXDRVINFO_ROLE); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_role\n"); + return -ENOMEM; + } + skb_put(skb, H2C_LEN_CXDRVINFO_ROLE); + cmd = skb->data; + + RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE); + RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_ROLE - H2C_LEN_CXDRVHDR); + + RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt); + RTW89_SET_FWCMD_CXROLE_LINK_MODE(cmd, role_info->link_mode); + + RTW89_SET_FWCMD_CXROLE_ROLE_NONE(cmd, bpos->none); + RTW89_SET_FWCMD_CXROLE_ROLE_STA(cmd, bpos->station); + RTW89_SET_FWCMD_CXROLE_ROLE_AP(cmd, bpos->ap); + RTW89_SET_FWCMD_CXROLE_ROLE_VAP(cmd, bpos->vap); + RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC(cmd, bpos->adhoc); + RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC_MASTER(cmd, bpos->adhoc_master); + RTW89_SET_FWCMD_CXROLE_ROLE_MESH(cmd, bpos->mesh); + RTW89_SET_FWCMD_CXROLE_ROLE_MONITOR(cmd, bpos->moniter); + RTW89_SET_FWCMD_CXROLE_ROLE_P2P_DEV(cmd, bpos->p2p_device); + RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GC(cmd, bpos->p2p_gc); + RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GO(cmd, bpos->p2p_go); + RTW89_SET_FWCMD_CXROLE_ROLE_NAN(cmd, bpos->nan); + + for (i = 0; i < RTW89_MAX_HW_PORT_NUM; i++, active++) { + RTW89_SET_FWCMD_CXROLE_ACT_CONNECTED(cmd, active->connected, i); + RTW89_SET_FWCMD_CXROLE_ACT_PID(cmd, active->pid, i); + RTW89_SET_FWCMD_CXROLE_ACT_PHY(cmd, active->phy, i); + RTW89_SET_FWCMD_CXROLE_ACT_NOA(cmd, active->noa, i); + RTW89_SET_FWCMD_CXROLE_ACT_BAND(cmd, active->band, i); + RTW89_SET_FWCMD_CXROLE_ACT_CLIENT_PS(cmd, active->client_ps, i); + RTW89_SET_FWCMD_CXROLE_ACT_BW(cmd, active->bw, i); + RTW89_SET_FWCMD_CXROLE_ACT_ROLE(cmd, active->role, i); + RTW89_SET_FWCMD_CXROLE_ACT_CH(cmd, active->ch, i); + RTW89_SET_FWCMD_CXROLE_ACT_TX_LVL(cmd, active->tx_lvl, i); + RTW89_SET_FWCMD_CXROLE_ACT_RX_LVL(cmd, active->rx_lvl, i); + RTW89_SET_FWCMD_CXROLE_ACT_TX_RATE(cmd, active->tx_rate, i); + RTW89_SET_FWCMD_CXROLE_ACT_RX_RATE(cmd, active->rx_rate, i); + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, BTFC_SET, + SET_DRV_INFO, 0, 0, + H2C_LEN_CXDRVINFO_ROLE); + + if (rtw89_h2c_tx(rtwdev, skb, false)) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return -EBUSY; +} + +#define H2C_LEN_CXDRVINFO_CTRL (4 + H2C_LEN_CXDRVHDR) +int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_ctrl *ctrl = &btc->ctrl; + struct sk_buff *skb; + u8 *cmd; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_CXDRVINFO_CTRL); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n"); + return -ENOMEM; + } + skb_put(skb, H2C_LEN_CXDRVINFO_CTRL); + cmd = skb->data; + + RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_CTRL); + RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_CTRL - H2C_LEN_CXDRVHDR); + + RTW89_SET_FWCMD_CXCTRL_MANUAL(cmd, ctrl->manual); + RTW89_SET_FWCMD_CXCTRL_IGNORE_BT(cmd, ctrl->igno_bt); + RTW89_SET_FWCMD_CXCTRL_ALWAYS_FREERUN(cmd, ctrl->always_freerun); + RTW89_SET_FWCMD_CXCTRL_TRACE_STEP(cmd, ctrl->trace_step); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, BTFC_SET, + SET_DRV_INFO, 0, 0, + H2C_LEN_CXDRVINFO_CTRL); + + if (rtw89_h2c_tx(rtwdev, skb, false)) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return -EBUSY; +} + +#define H2C_LEN_CXDRVINFO_RFK (4 + H2C_LEN_CXDRVHDR) +int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_wl_info *wl = &btc->cx.wl; + struct rtw89_btc_wl_rfk_info *rfk_info = &wl->rfk_info; + struct sk_buff *skb; + u8 *cmd; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(H2C_LEN_CXDRVINFO_RFK); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n"); + return -ENOMEM; + } + skb_put(skb, H2C_LEN_CXDRVINFO_RFK); + cmd = skb->data; + + RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_RFK); + RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_RFK - H2C_LEN_CXDRVHDR); + + RTW89_SET_FWCMD_CXRFK_STATE(cmd, rfk_info->state); + RTW89_SET_FWCMD_CXRFK_PATH_MAP(cmd, rfk_info->path_map); + RTW89_SET_FWCMD_CXRFK_PHY_MAP(cmd, rfk_info->phy_map); + RTW89_SET_FWCMD_CXRFK_BAND(cmd, rfk_info->band); + RTW89_SET_FWCMD_CXRFK_TYPE(cmd, rfk_info->type); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, BTFC_SET, + SET_DRV_INFO, 0, 0, + H2C_LEN_CXDRVINFO_RFK); + + if (rtw89_h2c_tx(rtwdev, skb, false)) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return -EBUSY; +} + int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rf_reg_info *info, u16 len, u8 page) @@ -1314,3 +1579,21 @@ int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev, return 0; } +void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev) +{ + if (!test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) { + rtw89_err(rtwdev, "[ERR]pwr is off\n"); + return; + } + + rtw89_info(rtwdev, "FW status = 0x%x\n", rtw89_read32(rtwdev, R_AX_UDM0)); + rtw89_info(rtwdev, "FW BADADDR = 0x%x\n", rtw89_read32(rtwdev, R_AX_UDM1)); + rtw89_info(rtwdev, "FW EPC/RA = 0x%x\n", rtw89_read32(rtwdev, R_AX_UDM2)); + rtw89_info(rtwdev, "FW MISC = 0x%x\n", rtw89_read32(rtwdev, R_AX_UDM3)); + rtw89_info(rtwdev, "R_AX_HALT_C2H = 0x%x\n", + rtw89_read32(rtwdev, R_AX_HALT_C2H)); + rtw89_info(rtwdev, "R_AX_SER_DBG_INFO = 0x%x\n", + rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); + + rtw89_fw_prog_cnt_dump(rtwdev); +} diff --git a/fw.h b/fw.h index 5609446b..9f7c452d 100644 --- a/fw.h +++ b/fw.h @@ -69,6 +69,44 @@ enum rtw89_fw_c2h_category { RTW89_C2H_CAT_OUTSRC, }; +enum rtw89_fw_log_level { + RTW89_FW_LOG_LEVEL_OFF, + RTW89_FW_LOG_LEVEL_CRT, + RTW89_FW_LOG_LEVEL_SER, + RTW89_FW_LOG_LEVEL_WARN, + RTW89_FW_LOG_LEVEL_LOUD, + RTW89_FW_LOG_LEVEL_TR, +}; + +enum rtw89_fw_log_path { + RTW89_FW_LOG_LEVEL_UART, + RTW89_FW_LOG_LEVEL_C2H, + RTW89_FW_LOG_LEVEL_SNI, +}; + +enum rtw89_fw_log_comp { + RTW89_FW_LOG_COMP_VER, + RTW89_FW_LOG_COMP_INIT, + RTW89_FW_LOG_COMP_TASK, + RTW89_FW_LOG_COMP_CNS, + RTW89_FW_LOG_COMP_H2C, + RTW89_FW_LOG_COMP_C2H, + RTW89_FW_LOG_COMP_TX, + RTW89_FW_LOG_COMP_RX, + RTW89_FW_LOG_COMP_IPSEC, + RTW89_FW_LOG_COMP_TIMER, + RTW89_FW_LOG_COMP_DBGPKT, + RTW89_FW_LOG_COMP_PS, + RTW89_FW_LOG_COMP_ERROR, + RTW89_FW_LOG_COMP_WOWLAN, + RTW89_FW_LOG_COMP_SECURE_BOOT, + RTW89_FW_LOG_COMP_BTC, + RTW89_FW_LOG_COMP_BB, + RTW89_FW_LOG_COMP_TWT, + RTW89_FW_LOG_COMP_RF, + RTW89_FW_LOG_COMP_MCC = 20, +}; + #define FWDL_SECTION_MAX_NUM 10 #define FWDL_SECTION_CHKSUM_LEN 8 #define FWDL_SECTION_PER_PKT_LEN 2020 @@ -913,6 +951,15 @@ do { \ #define SET_GENERAL_PKT_CTS2SELF_ID(h2c, val) \ le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(15, 8)) +#define SET_LOG_CFG_LEVEL(h2c, val) \ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)) +#define SET_LOG_CFG_PATH(h2c, val) \ + le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)) +#define SET_LOG_CFG_COMP(h2c, val) \ + le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(31, 0)) +#define SET_LOG_CFG_COMP_EXT(h2c, val) \ + le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(31, 0)) + #define SET_BA_CAM_VALID(h2c, val) \ le32p_replace_bits((__le32 *)h2c, val, BIT(0)) #define SET_BA_CAM_INIT_REQ(h2c, val) \ @@ -949,6 +996,161 @@ do { \ #define SET_LPS_PARM_LASTRPWM(h2c, val) \ le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(15, 8)) +enum rtw89_btc_btf_h2c_class { + BTFC_SET = 0x10, + BTFC_GET = 0x11, + BTFC_FW_EVENT = 0x12, +}; + +enum rtw89_btc_btf_set { + SET_REPORT_EN = 0x0, + SET_SLOT_TABLE, + SET_MREG_TABLE, + SET_CX_POLICY, + SET_GPIO_DBG, + SET_DRV_INFO, + SET_DRV_EVENT, + SET_BT_WREG_ADDR, + SET_BT_WREG_VAL, + SET_BT_RREG_ADDR, + SET_BT_WL_CH_INFO, + SET_BT_INFO_REPORT, + SET_BT_IGNORE_WLAN_ACT, + SET_BT_TX_PWR, + SET_BT_LNA_CONSTRAIN, + SET_BT_GOLDEN_RX_RANGE, + SET_BT_PSD_REPORT, + SET_H2C_TEST, + SET_MAX1, +}; + +enum rtw89_btc_cxdrvinfo { + CXDRVINFO_INIT = 0, + CXDRVINFO_ROLE, + CXDRVINFO_DBCC, + CXDRVINFO_SMAP, + CXDRVINFO_RFK, + CXDRVINFO_RUN, + CXDRVINFO_CTRL, + CXDRVINFO_SCAN, + CXDRVINFO_MAX, +}; + +#define RTW89_SET_FWCMD_CXHDR_TYPE(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 0, GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXHDR_LEN(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 1, GENMASK(7, 0)) + +#define RTW89_SET_FWCMD_CXINIT_ANT_TYPE(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 2, GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXINIT_ANT_NUM(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 3, GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXINIT_ANT_ISO(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 4, GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXINIT_ANT_POS(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 5, BIT(0)) +#define RTW89_SET_FWCMD_CXINIT_ANT_DIVERSITY(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 5, BIT(1)) +#define RTW89_SET_FWCMD_CXINIT_MOD_RFE(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 6, GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXINIT_MOD_CV(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 7, GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXINIT_MOD_BT_SOLO(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 8, BIT(0)) +#define RTW89_SET_FWCMD_CXINIT_MOD_BT_POS(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 8, BIT(1)) +#define RTW89_SET_FWCMD_CXINIT_MOD_SW_TYPE(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 8, BIT(2)) +#define RTW89_SET_FWCMD_CXINIT_WL_GCH(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 10, GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXINIT_WL_ONLY(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 11, BIT(0)) +#define RTW89_SET_FWCMD_CXINIT_WL_INITOK(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 11, BIT(1)) +#define RTW89_SET_FWCMD_CXINIT_DBCC_EN(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 11, BIT(2)) +#define RTW89_SET_FWCMD_CXINIT_CX_OTHER(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 11, BIT(3)) +#define RTW89_SET_FWCMD_CXINIT_BT_ONLY(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 11, BIT(4)) + +#define RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 2, GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXROLE_LINK_MODE(cmd, val) \ + RTW89_SET_FWCMD_UA8(cmd, val, 3, GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_NONE(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(0)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_STA(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(1)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_AP(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(2)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_VAP(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(3)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(4)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_ADHOC_MASTER(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(5)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_MESH(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(6)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_MONITOR(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(7)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_P2P_DEV(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(8)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GC(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(9)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_P2P_GO(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(10)) +#define RTW89_SET_FWCMD_CXROLE_ROLE_NAN(cmd, val) \ + RTW89_SET_FWCMD_UA16(cmd, val, 4, BIT(11)) +#define RTW89_SET_FWCMD_CXROLE_ACT_CONNECTED(cmd, val, n) \ + RTW89_SET_FWCMD_UA8(cmd, val, 6 + 12 * (n), BIT(0)) +#define RTW89_SET_FWCMD_CXROLE_ACT_PID(cmd, val, n) \ + RTW89_SET_FWCMD_UA8(cmd, val, 6 + 12 * (n), GENMASK(3, 1)) +#define RTW89_SET_FWCMD_CXROLE_ACT_PHY(cmd, val, n) \ + RTW89_SET_FWCMD_UA8(cmd, val, 6 + 12 * (n), BIT(4)) +#define RTW89_SET_FWCMD_CXROLE_ACT_NOA(cmd, val, n) \ + RTW89_SET_FWCMD_UA8(cmd, val, 6 + 12 * (n), BIT(5)) +#define RTW89_SET_FWCMD_CXROLE_ACT_BAND(cmd, val, n) \ + RTW89_SET_FWCMD_UA8(cmd, val, 6 + 12 * (n), GENMASK(7, 6)) +#define RTW89_SET_FWCMD_CXROLE_ACT_CLIENT_PS(cmd, val, n) \ + RTW89_SET_FWCMD_UA8(cmd, val, 7 + 12 * (n), BIT(0)) +#define RTW89_SET_FWCMD_CXROLE_ACT_BW(cmd, val, n) \ + RTW89_SET_FWCMD_UA8(cmd, val, 7 + 12 * (n), GENMASK(7, 1)) +#define RTW89_SET_FWCMD_CXROLE_ACT_ROLE(cmd, val, n) \ + RTW89_SET_FWCMD_UA8(cmd, val, 8 + 12 * (n), GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXROLE_ACT_CH(cmd, val, n) \ + RTW89_SET_FWCMD_UA8(cmd, val, 9 + 12 * (n), GENMASK(7, 0)) +#define RTW89_SET_FWCMD_CXROLE_ACT_TX_LVL(cmd, val, n) \ + RTW89_SET_FWCMD_UA16(cmd, val, 10 + 12 * (n), GENMASK(15, 0)) +#define RTW89_SET_FWCMD_CXROLE_ACT_RX_LVL(cmd, val, n) \ + RTW89_SET_FWCMD_UA16(cmd, val, 12 + 12 * (n), GENMASK(15, 0)) +#define RTW89_SET_FWCMD_CXROLE_ACT_TX_RATE(cmd, val, n) \ + RTW89_SET_FWCMD_UA16(cmd, val, 14 + 12 * (n), GENMASK(15, 0)) +#define RTW89_SET_FWCMD_CXROLE_ACT_RX_RATE(cmd, val, n) \ + RTW89_SET_FWCMD_UA16(cmd, val, 16 + 12 * (n), GENMASK(15, 0)) + +#define RTW89_SET_FWCMD_CXCTRL_MANUAL(cmd, val) \ + RTW89_SET_FWCMD_UA32(cmd, val, 2, BIT(0)) +#define RTW89_SET_FWCMD_CXCTRL_IGNORE_BT(cmd, val) \ + RTW89_SET_FWCMD_UA32(cmd, val, 2, BIT(1)) +#define RTW89_SET_FWCMD_CXCTRL_ALWAYS_FREERUN(cmd, val) \ + RTW89_SET_FWCMD_UA32(cmd, val, 2, BIT(2)) +#define RTW89_SET_FWCMD_CXCTRL_TRACE_STEP(cmd, val) \ + RTW89_SET_FWCMD_UA32(cmd, val, 2, GENMASK(18, 3)) + +#define RTW89_SET_FWCMD_CXRFK_STATE(cmd, val) \ + RTW89_SET_FWCMD_UA32(cmd, val, 2, GENMASK(1, 0)) +#define RTW89_SET_FWCMD_CXRFK_PATH_MAP(cmd, val) \ + RTW89_SET_FWCMD_UA32(cmd, val, 2, GENMASK(5, 2)) +#define RTW89_SET_FWCMD_CXRFK_PHY_MAP(cmd, val) \ + RTW89_SET_FWCMD_UA32(cmd, val, 2, GENMASK(7, 6)) +#define RTW89_SET_FWCMD_CXRFK_BAND(cmd, val) \ + RTW89_SET_FWCMD_UA32(cmd, val, 2, GENMASK(9, 8)) +#define RTW89_SET_FWCMD_CXRFK_TYPE(cmd, val) \ + RTW89_SET_FWCMD_UA32(cmd, val, 2, GENMASK(17, 10)) + +#define RTW89_C2H_HEADER_LEN 8 + #define RTW89_GET_C2H_CATEGORY(c2h) \ le32_get_bits(*((__le32 *)c2h), GENMASK(1, 0)) #define RTW89_GET_C2H_CLASS(c2h) \ @@ -958,6 +1160,9 @@ do { \ #define RTW89_GET_C2H_LEN(c2h) \ le32_get_bits(*((__le32 *)(c2h) + 1), GENMASK(13, 0)) +#define RTW89_GET_C2H_LOG_SRT_PRT(c2h) (char *)((__le32 *)(c2h) + 2) +#define RTW89_GET_C2H_LOG_LEN(len) ((len) - RTW89_C2H_HEADER_LEN) + #define RTW89_GET_MAC_C2H_DONE_ACK_CAT(c2h) \ le32_get_bits(*((__le32 *)(c2h) + 2), GENMASK(1, 0)) #define RTW89_GET_MAC_C2H_DONE_ACK_CLASS(c2h) \ @@ -1049,6 +1254,7 @@ struct rtw89_fw_h2c_rf_reg_info { /* CLASS 0 - FW INFO */ #define H2C_CL_FW_INFO 0x0 +#define H2C_FUNC_LOG_CFG 0x0 #define H2C_FUNC_MAC_GENERAL_PKT 0x1 /* CLASS 2 - PS */ @@ -1123,6 +1329,10 @@ int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u8 ac, u32 val); int rtw89_fw_h2c_set_ofld_cfg(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi); +int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rf_reg_info *info, u16 len, u8 page); @@ -1133,12 +1343,15 @@ int rtw89_fw_h2c_raw(struct rtw89_dev *rtwdev, const u8 *buf, u16 len); int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, u8 macid); int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, bool valid, u8 macid, struct ieee80211_ampdu_params *params); -int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, u8 macid); +int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, + struct rtw89_lps_parm *lps_param); struct sk_buff *rtw89_fw_h2c_alloc_skb_with_hdr(u32 len); struct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(u32 len); int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev, struct rtw89_mac_h2c_info *h2c_info, struct rtw89_mac_c2h_info *c2h_info); +int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable); +void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev); static __always_inline void RTW89_SET_FWCMD(u8 *cmd, u32 val, u8 offset, u32 mask) { @@ -1147,4 +1360,19 @@ static __always_inline void RTW89_SET_FWCMD(u8 *cmd, u32 val, u8 offset, u32 mas le32p_replace_bits((__le32 *)(cmd32 + offset), val, mask); } +static __always_inline void RTW89_SET_FWCMD_UA8(u8 *cmd, u8 val, u8 offset, u32 mask) +{ + u8p_replace_bits(cmd + offset, val, mask); +} + +static __always_inline void RTW89_SET_FWCMD_UA16(u8 *cmd, u16 val, u8 offset, u32 mask) +{ + le16p_replace_bits((__le16 *)(cmd + offset), val, mask); +} + +static __always_inline void RTW89_SET_FWCMD_UA32(u8 *cmd, u32 val, u8 offset, u32 mask) +{ + le32p_replace_bits((__le32 *)(cmd + offset), val, mask); +} + #endif diff --git a/mac.c b/mac.c index f32c3a36..e00652e1 100644 --- a/mac.c +++ b/mac.c @@ -3,10 +3,12 @@ */ #include "cam.h" +#include "debug.h" #include "fw.h" #include "mac.h" -#include "pci.h" +#include "ps.h" #include "reg.h" +#include "util.h" int rtw89_mac_check_mac_en(struct rtw89_dev *rtwdev, u8 mac_idx, enum rtw89_mac_hwmod_sel sel) @@ -37,9 +39,8 @@ int rtw89_mac_write_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 val) u8 lte_ctrl; int ret; - ret = read_poll_timeout_atomic(rtw89_read8, lte_ctrl, - (lte_ctrl & BIT(5)) != 0, 50, 50000, - false, rtwdev, R_AX_LTE_CTRL + 3); + ret = read_poll_timeout(rtw89_read8, lte_ctrl, (lte_ctrl & BIT(5)) != 0, + 50, 50000, false, rtwdev, R_AX_LTE_CTRL + 3); if (ret) rtw89_err(rtwdev, "[ERR]lte not ready(W)\n"); @@ -54,9 +55,8 @@ int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val) u8 lte_ctrl; int ret; - ret = read_poll_timeout_atomic(rtw89_read8, lte_ctrl, - (lte_ctrl & BIT(5)) != 0, 50, 50000, - false, rtwdev, R_AX_LTE_CTRL + 3); + ret = read_poll_timeout(rtw89_read8, lte_ctrl, (lte_ctrl & BIT(5)) != 0, + 50, 50000, false, rtwdev, R_AX_LTE_CTRL + 3); if (ret) rtw89_err(rtwdev, "[ERR]lte not ready(W)\n"); @@ -66,6 +66,375 @@ int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val) return ret; } +static +int dle_dfi_ctrl(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl) +{ + u32 ctrl_reg, data_reg, ctrl_data; + u32 val; + int ret; + + switch (ctrl->type) { + case DLE_CTRL_TYPE_WDE: + ctrl_reg = R_AX_WDE_DBG_FUN_INTF_CTL; + data_reg = R_AX_WDE_DBG_FUN_INTF_DATA; + ctrl_data = FIELD_PREP(B_AX_WDE_DFI_TRGSEL, ctrl->target) | + FIELD_PREP(B_AX_WDE_DFI_ADDR, ctrl->addr) | + B_AX_WDE_DFI_ACTIVE; + break; + case DLE_CTRL_TYPE_PLE: + ctrl_reg = R_AX_PLE_DBG_FUN_INTF_CTL; + data_reg = R_AX_PLE_DBG_FUN_INTF_DATA; + ctrl_data = FIELD_PREP(B_AX_PLE_DFI_TRGSEL, ctrl->target) | + FIELD_PREP(B_AX_PLE_DFI_ADDR, ctrl->addr) | + B_AX_PLE_DFI_ACTIVE; + break; + default: + rtw89_warn(rtwdev, "[ERR] dfi ctrl type %d\n", ctrl->type); + return -EINVAL; + } + + rtw89_write32(rtwdev, ctrl_reg, ctrl_data); + + ret = read_poll_timeout_atomic(rtw89_read32, val, !(val & B_AX_WDE_DFI_ACTIVE), + 1, 1000, false, rtwdev, ctrl_reg); + if (ret) { + rtw89_warn(rtwdev, "[ERR] dle dfi ctrl 0x%X set 0x%X timeout\n", + ctrl_reg, ctrl_data); + return ret; + } + + ctrl->out_data = rtw89_read32(rtwdev, data_reg); + return 0; +} + +static int dle_dfi_quota(struct rtw89_dev *rtwdev, + struct rtw89_mac_dle_dfi_quota *quota) +{ + struct rtw89_mac_dle_dfi_ctrl ctrl; + int ret; + + ctrl.type = quota->dle_type; + ctrl.target = DLE_DFI_TYPE_QUOTA; + ctrl.addr = quota->qtaid; + ret = dle_dfi_ctrl(rtwdev, &ctrl); + if (ret) { + rtw89_warn(rtwdev, "[ERR]dle_dfi_ctrl %d\n", ret); + return ret; + } + + quota->rsv_pgnum = FIELD_GET(B_AX_DLE_RSV_PGNUM, ctrl.out_data); + quota->use_pgnum = FIELD_GET(B_AX_DLE_USE_PGNUM, ctrl.out_data); + return 0; +} + +static int dle_dfi_qempty(struct rtw89_dev *rtwdev, + struct rtw89_mac_dle_dfi_qempty *qempty) +{ + struct rtw89_mac_dle_dfi_ctrl ctrl; + u32 ret; + + ctrl.type = qempty->dle_type; + ctrl.target = DLE_DFI_TYPE_QEMPTY; + ctrl.addr = qempty->grpsel; + ret = dle_dfi_ctrl(rtwdev, &ctrl); + if (ret) { + rtw89_warn(rtwdev, "[ERR]dle_dfi_ctrl %d\n", ret); + return ret; + } + + qempty->qempty = FIELD_GET(B_AX_DLE_QEMPTY_GRP, ctrl.out_data); + return 0; +} + +static void dump_err_status_dispatcher(struct rtw89_dev *rtwdev) +{ + rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ALWAYS_IMR=0x%08x ", + rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ALWAYS_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ALWAYS_IMR=0x%08x ", + rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ALWAYS_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ALWAYS_IMR=0x%08x ", + rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ALWAYS_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); +} + +static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev) +{ + struct rtw89_mac_dle_dfi_qempty qempty; + struct rtw89_mac_dle_dfi_quota quota; + struct rtw89_mac_dle_dfi_ctrl ctrl; + u32 val, not_empty, i; + int ret; + + qempty.dle_type = DLE_CTRL_TYPE_PLE; + qempty.grpsel = 0; + ret = dle_dfi_qempty(rtwdev, &qempty); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "DLE group0 empty: 0x%x\n", qempty.qempty); + + for (not_empty = ~qempty.qempty, i = 0; not_empty != 0; not_empty >>= 1, i++) { + if (!(not_empty & BIT(0))) + continue; + ctrl.type = DLE_CTRL_TYPE_PLE; + ctrl.target = DLE_DFI_TYPE_QLNKTBL; + ctrl.addr = (QLNKTBL_ADDR_INFO_SEL_0 ? QLNKTBL_ADDR_INFO_SEL : 0) | + FIELD_PREP(QLNKTBL_ADDR_TBL_IDX_MASK, i); + ret = dle_dfi_ctrl(rtwdev, &ctrl); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "qidx%d pktcnt = %ld\n", i, + FIELD_GET(QLNKTBL_DATA_SEL1_PKT_CNT_MASK, + ctrl.out_data)); + } + + quota.dle_type = DLE_CTRL_TYPE_PLE; + quota.qtaid = 6; + ret = dle_dfi_quota(rtwdev, "a); + if (ret) + rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__); + else + rtw89_info(rtwdev, "quota6 rsv/use: 0x%x/0x%x\n", + quota.rsv_pgnum, quota.use_pgnum); + + val = rtw89_read32(rtwdev, R_AX_PLE_QTA6_CFG); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]min_pgnum=0x%lx\n", + FIELD_GET(B_AX_PLE_Q6_MIN_SIZE_MASK, val)); + rtw89_info(rtwdev, "[PLE][CMAC0_RX]max_pgnum=0x%lx\n", + FIELD_GET(B_AX_PLE_Q6_MAX_SIZE_MASK, val)); + + dump_err_status_dispatcher(rtwdev); +} + +static void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err) +{ + u32 dbg, event; + + dbg = rtw89_read32(rtwdev, R_AX_SER_DBG_INFO); + event = FIELD_GET(B_AX_L0_TO_L1_EVENT_MASK, dbg); + + switch (event) { + case MAC_AX_L0_TO_L1_RX_QTA_LOST: + rtw89_info(rtwdev, "quota lost!\n"); + rtw89_mac_dump_qta_lost(rtwdev); + break; + default: + break; + } +} + +static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, + enum mac_ax_err_info err) +{ + u32 dmac_err, cmac_err; + + if (err != MAC_AX_ERR_L1_ERR_DMAC && + err != MAC_AX_ERR_L0_PROMOTE_TO_L1) + return; + + rtw89_info(rtwdev, "--->\nerr=0x%x\n", err); + rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); + + cmac_err = rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR); + rtw89_info(rtwdev, "R_AX_CMAC_ERR_ISR =0x%08x\n", cmac_err); + dmac_err = rtw89_read32(rtwdev, R_AX_DMAC_ERR_ISR); + rtw89_info(rtwdev, "R_AX_DMAC_ERR_ISR =0x%08x\n", dmac_err); + + if (dmac_err) { + rtw89_info(rtwdev, "R_AX_WDE_ERR_FLAG_CFG =0x%08x ", + rtw89_read32(rtwdev, R_AX_WDE_ERR_FLAG_CFG)); + rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_CFG =0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_CFG)); + } + + if (dmac_err & B_AX_WDRLS_ERR_FLAG) { + rtw89_info(rtwdev, "R_AX_WDRLS_ERR_IMR =0x%08x ", + rtw89_read32(rtwdev, R_AX_WDRLS_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_WDRLS_ERR_ISR =0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDRLS_ERR_ISR)); + } + + if (dmac_err & B_AX_WSEC_ERR_FLAG) { + rtw89_info(rtwdev, "R_AX_SEC_ERR_IMR_ISR =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_DEBUG)); + rtw89_info(rtwdev, "SEC_local_Register 0x9D00 =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); + rtw89_info(rtwdev, "SEC_local_Register 0x9D04 =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); + rtw89_info(rtwdev, "SEC_local_Register 0x9D10 =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); + rtw89_info(rtwdev, "SEC_local_Register 0x9D14 =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); + rtw89_info(rtwdev, "SEC_local_Register 0x9D18 =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_CAM_WDATA)); + rtw89_info(rtwdev, "SEC_local_Register 0x9D20 =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); + rtw89_info(rtwdev, "SEC_local_Register 0x9D24 =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); + rtw89_info(rtwdev, "SEC_local_Register 0x9D28 =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TRX_PKT_CNT)); + rtw89_info(rtwdev, "SEC_local_Register 0x9D2C =0x%08x\n", + rtw89_read32(rtwdev, R_AX_SEC_TRX_BLK_CNT)); + } + + if (dmac_err & B_AX_MPDU_ERR_FLAG) { + rtw89_info(rtwdev, "R_AX_MPDU_TX_ERR_IMR =0x%08x ", + rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_MPDU_TX_ERR_ISR =0x%08x\n", + rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_MPDU_RX_ERR_IMR =0x%08x ", + rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_MPDU_RX_ERR_ISR =0x%08x\n", + rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_ISR)); + } + + if (dmac_err & B_AX_STA_SCHEDULER_ERR_FLAG) { + rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR =0x%08x ", + rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR= 0x%08x\n", + rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); + } + + if (dmac_err & B_AX_WDE_DLE_ERR_FLAG) { + rtw89_info(rtwdev, "R_AX_WDE_ERR_IMR=0x%08x ", + rtw89_read32(rtwdev, R_AX_WDE_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_WDE_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_PLE_ERR_IMR=0x%08x ", + rtw89_read32(rtwdev, R_AX_PLE_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); + dump_err_status_dispatcher(rtwdev); + } + + if (dmac_err & B_AX_TXPKTCTRL_ERR_FLAG) { + rtw89_info(rtwdev, "R_AX_TXPKTCTL_ERR_IMR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR)); + rtw89_info(rtwdev, "R_AX_TXPKTCTL_ERR_IMR_ISR_B1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR_B1)); + } + + if (dmac_err & B_AX_PLE_DLE_ERR_FLAG) { + rtw89_info(rtwdev, "R_AX_WDE_ERR_IMR=0x%08x ", + rtw89_read32(rtwdev, R_AX_WDE_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_WDE_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_PLE_ERR_IMR=0x%08x ", + rtw89_read32(rtwdev, R_AX_PLE_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); + rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_0)); + rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_1)); + rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_2)); + rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_STATUS)); + rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_0)); + rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_1)); + rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_2)); + rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS)); + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); + rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", + rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); + dump_err_status_dispatcher(rtwdev); + } + + if (dmac_err & B_AX_PKTIN_ERR_FLAG) { + rtw89_info(rtwdev, "R_AX_PKTIN_ERR_IMR =0x%08x ", + rtw89_read32(rtwdev, R_AX_PKTIN_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_PKTIN_ERR_ISR =0x%08x\n", + rtw89_read32(rtwdev, R_AX_PKTIN_ERR_ISR)); + rtw89_info(rtwdev, "R_AX_PKTIN_ERR_IMR =0x%08x ", + rtw89_read32(rtwdev, R_AX_PKTIN_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_PKTIN_ERR_ISR =0x%08x\n", + rtw89_read32(rtwdev, R_AX_PKTIN_ERR_ISR)); + } + + if (dmac_err & B_AX_DISPATCH_ERR_FLAG) + dump_err_status_dispatcher(rtwdev); + + if (dmac_err & B_AX_DLE_CPUIO_ERR_FLAG) { + rtw89_info(rtwdev, "R_AX_CPUIO_ERR_IMR=0x%08x ", + rtw89_read32(rtwdev, R_AX_CPUIO_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_CPUIO_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_CPUIO_ERR_ISR)); + } + + if (dmac_err & BIT(11)) { + rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_IMR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR_ISR)); + } + + if (cmac_err & B_AX_SCHEDULE_TOP_ERR_IND) { + rtw89_info(rtwdev, "R_AX_SCHEDULE_ERR_IMR=0x%08x ", + rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_SCHEDULE_ERR_ISR=0x%04x\n", + rtw89_read16(rtwdev, R_AX_SCHEDULE_ERR_ISR)); + } + + if (cmac_err & B_AX_PTCL_TOP_ERR_IND) { + rtw89_info(rtwdev, "R_AX_PTCL_IMR0=0x%08x ", + rtw89_read32(rtwdev, R_AX_PTCL_IMR0)); + rtw89_info(rtwdev, "R_AX_PTCL_ISR0=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PTCL_ISR0)); + } + + if (cmac_err & B_AX_DMA_TOP_ERR_IND) { + rtw89_info(rtwdev, "R_AX_DLE_CTRL=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DLE_CTRL)); + } + + if (cmac_err & B_AX_PHYINTF_ERR_IND) { + rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_IMR=0x%04x\n", + rtw89_read16(rtwdev, R_AX_PHYINFO_ERR_IMR)); + } + + if (cmac_err & B_AX_TXPWR_CTRL_ERR_IND) { + rtw89_info(rtwdev, "R_AX_TXPWR_IMR=0x%08x ", + rtw89_read32(rtwdev, R_AX_TXPWR_IMR)); + rtw89_info(rtwdev, "R_AX_TXPWR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_TXPWR_ISR)); + } + + if (cmac_err & B_AX_WMAC_RX_ERR_IND) { + rtw89_info(rtwdev, "R_AX_DBGSEL_TRXPTCL=0x%08x ", + rtw89_read32(rtwdev, R_AX_DBGSEL_TRXPTCL)); + rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR)); + } + + if (cmac_err & B_AX_WMAC_TX_ERR_IND) { + rtw89_info(rtwdev, "R_AX_TMAC_ERR_IMR_ISR=0x%08x ", + rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR)); + rtw89_info(rtwdev, "R_AX_DBGSEL_TRXPTCL=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DBGSEL_TRXPTCL)); + } + + rtwdev->hci.ops->dump_err_status(rtwdev); + + if (err == MAC_AX_ERR_L0_PROMOTE_TO_L1) + rtw89_mac_dump_l0_to_l1(rtwdev, err); + + rtw89_info(rtwdev, "<---\n"); +} + u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) { u32 err; @@ -81,6 +450,9 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) err = rtw89_read32(rtwdev, R_AX_HALT_C2H); rtw89_write32(rtwdev, R_AX_HALT_C2H_CTRL, 0); + rtw89_fw_st_dbg_dump(rtwdev); + rtw89_mac_dump_err_status(rtwdev, err); + return err; } EXPORT_SYMBOL(rtw89_mac_get_err_status); @@ -628,7 +1000,7 @@ static int rtw89_mac_check_cpwm_state(struct rtw89_dev *rtwdev, void rtw89_mac_power_mode_change(struct rtw89_dev *rtwdev, bool enter) { enum rtw89_rpwm_req_pwr_state state; - u8 ret; + int ret; if (enter) state = rtw89_mac_get_req_pwr_state(rtwdev); @@ -657,8 +1029,8 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) else cfg_seq = chip->pwr_off_seq; - if ((rtw89_read8(rtwdev, R_AX_WCPU_FW_CTRL) & 0xE0) == 0xE0) - rtw89_mac_send_rpwm(rtwdev, RTW89_MAC_RPWM_REQ_PWR_STATE_ACTIVE); + if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) + rtw89_leave_ps_mode(rtwdev); val = rtw89_read8(rtwdev, 0x3F1) & 0x3; if (on && val == PWR_ACT) { @@ -1522,16 +1894,11 @@ static int rx_fltr_init(struct rtw89_dev *rtwdev, u8 mac_idx) if (ret) return ret; } - mac_ftlr = B_AX_A_A1_MATCH | B_AX_A_BC | B_AX_A_MC | - B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH | - B_AX_A_MC_LIST_CAM_MATCH | - u32_encode_bits(3, B_AX_UID_FILTER_MASK) | - B_AX_A_BCN_CHK_EN; + mac_ftlr = rtwdev->hal.rx_fltr; plcp_ftlr = B_AX_CCK_CRC_CHK | B_AX_CCK_SIG_CHK | B_AX_LSIG_PARITY_CHK | B_AX_SIGA_CRC_CHK | B_AX_VHT_SU_SIGB_CRC_CHK | B_AX_VHT_MU_SIGB_CRC_CHK | B_AX_HE_SIGB_CRC_CHK; - rtwdev->hal.rx_fltr = mac_ftlr; rtw89_write32(rtwdev, rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, mac_idx), mac_ftlr); rtw89_write16(rtwdev, rtw89_mac_reg_by_idx(R_AX_PLCP_HDR_FLTR, mac_idx), @@ -1551,27 +1918,27 @@ static int cca_ctrl_init(struct rtw89_dev *rtwdev, u8 mac_idx) reg = rtw89_mac_reg_by_idx(R_AX_CCA_CONTROL, mac_idx); val = rtw89_read32(rtwdev, reg); - val |= (B_AX_TB_CHK_TX_NAV | B_AX_TB_CHK_BASIC_NAV | - B_AX_TB_CHK_BTCCA | B_AX_TB_CHK_EDCCA | - B_AX_TB_CHK_CCA_S80 | B_AX_TB_CHK_CCA_S40 | - B_AX_TB_CHK_CCA_S20 | B_AX_TB_CHK_CCA_P20 | - B_AX_SIFS_CHK_BTCCA | B_AX_SIFS_CHK_EDCCA | - B_AX_SIFS_CHK_CCA_P20 | - B_AX_CTN_CHK_TXNAV | B_AX_CTN_CHK_INTRA_NAV | - B_AX_CTN_CHK_BASIC_NAV | B_AX_CTN_CHK_BTCCA | - B_AX_CTN_CHK_EDCCA | B_AX_CTN_CHK_CCA_S80 | - B_AX_CTN_CHK_CCA_S40 | B_AX_CTN_CHK_CCA_S20 | - B_AX_CTN_CHK_CCA_P20); - val &= ~(B_AX_SIFS_CHK_CCA_S80 | B_AX_SIFS_CHK_CCA_S40 | B_AX_SIFS_CHK_CCA_S20); + val |= (B_AX_TB_CHK_BASIC_NAV | B_AX_TB_CHK_BTCCA | + B_AX_TB_CHK_EDCCA | B_AX_TB_CHK_CCA_P20 | + B_AX_SIFS_CHK_BTCCA | B_AX_SIFS_CHK_CCA_P20 | + B_AX_CTN_CHK_TXNAV | B_AX_CTN_CHK_INTRA_NAV | + B_AX_CTN_CHK_BASIC_NAV | B_AX_CTN_CHK_BTCCA | + B_AX_CTN_CHK_EDCCA | B_AX_CTN_CHK_CCA_S80 | + B_AX_CTN_CHK_CCA_S40 | B_AX_CTN_CHK_CCA_S20 | + B_AX_CTN_CHK_CCA_P20); + val &= ~(B_AX_TB_CHK_TX_NAV | B_AX_TB_CHK_CCA_S80 | + B_AX_TB_CHK_CCA_S40 | B_AX_TB_CHK_CCA_S20 | + B_AX_SIFS_CHK_CCA_S80 | B_AX_SIFS_CHK_CCA_S40 | + B_AX_SIFS_CHK_CCA_S20 | B_AX_SIFS_CHK_EDCCA); rtw89_write32(rtwdev, reg, val); reg = rtw89_mac_reg_by_idx(R_AX_RSP_CHK_SIG, mac_idx); val = rtw89_read32(rtwdev, reg); val |= (B_AX_RSP_CHK_TX_NAV | B_AX_RSP_CHK_INTRA_NAV | - B_AX_RSP_CHK_BASIC_NAV | B_AX_RSP_CHK_SEC_CCA_80 | - B_AX_RSP_CHK_SEC_CCA_40 | B_AX_RSP_CHK_SEC_CCA_20 | - B_AX_RSP_CHK_BTCCA | B_AX_RSP_CHK_EDCCA | - B_AX_RSP_CHK_CCA); + B_AX_RSP_CHK_BASIC_NAV | B_AX_RSP_CHK_SEC_CCA_80 | + B_AX_RSP_CHK_SEC_CCA_40 | B_AX_RSP_CHK_SEC_CCA_20 | + B_AX_RSP_CHK_BTCCA | B_AX_RSP_CHK_EDCCA | + B_AX_RSP_CHK_CCA); rtw89_write32(rtwdev, reg, val); return 0; @@ -1606,6 +1973,41 @@ static int tmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) return 0; } +static int trxptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx) +{ + u32 reg, val, sifs; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_0, mac_idx); + val = rtw89_read32(rtwdev, reg); + val &= ~B_AX_WMAC_SPEC_SIFS_CCK_MASK; + val |= FIELD_PREP(B_AX_WMAC_SPEC_SIFS_CCK_MASK, WMAC_SPEC_SIFS_CCK); + + switch (rtwdev->chip->chip_id) { + case RTL8852A: + sifs = WMAC_SPEC_SIFS_OFDM_52A; + break; + case RTL8852B: + sifs = WMAC_SPEC_SIFS_OFDM_52B; + break; + default: + sifs = WMAC_SPEC_SIFS_OFDM_52C; + break; + } + val &= ~B_AX_WMAC_SPEC_SIFS_OFDM_MASK; + val |= FIELD_PREP(B_AX_WMAC_SPEC_SIFS_OFDM_MASK, sifs); + rtw89_write32(rtwdev, reg, val); + + reg = rtw89_mac_reg_by_idx(R_AX_RXTRIG_TEST_USER_2, mac_idx); + rtw89_write32_set(rtwdev, reg, B_AX_RXTRIG_FCSCHK_EN); + + return 0; +} + static int rmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) { #define TRXCFG_RMAC_CCA_TO 32 @@ -1779,6 +2181,12 @@ static int cmac_init(struct rtw89_dev *rtwdev, u8 mac_idx) return ret; } + ret = trxptcl_init(rtwdev, mac_idx); + if (ret) { + rtw89_err(rtwdev, "[ERR]CMAC%d TRXPTCL init %d\n", mac_idx, ret); + return ret; + } + ret = rmac_init(rtwdev, mac_idx); if (ret) { rtw89_err(rtwdev, "[ERR]CMAC%d RMAC init %d\n", mac_idx, ret); @@ -2229,7 +2637,7 @@ static int set_host_rpr(struct rtw89_dev *rtwdev) B_AX_RLSRPT0_FLTR_MAP_MASK); } - rtw89_write32_mask(rtwdev, R_AX_RLSRPT0_CFG1, B_AX_RLSRPT0_AGGNUM_MASK, 121); + rtw89_write32_mask(rtwdev, R_AX_RLSRPT0_CFG1, B_AX_RLSRPT0_AGGNUM_MASK, 30); rtw89_write32_mask(rtwdev, R_AX_RLSRPT0_CFG1, B_AX_RLSRPT0_TO_MASK, 255); return 0; @@ -2674,6 +3082,7 @@ static void rtw89_mac_port_cfg_tbtt_early(struct rtw89_dev *rtwdev, static void rtw89_mac_port_cfg_bss_color(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); static const u32 masks[RTW89_PORT_NUM] = { B_AX_BSS_COLOB_AX_PORT_0_MASK, B_AX_BSS_COLOB_AX_PORT_1_MASK, B_AX_BSS_COLOB_AX_PORT_2_MASK, B_AX_BSS_COLOB_AX_PORT_3_MASK, @@ -2682,8 +3091,9 @@ static void rtw89_mac_port_cfg_bss_color(struct rtw89_dev *rtwdev, u8 port = rtwvif->port; u32 reg_base; u32 reg; - u8 bss_color = 0; + u8 bss_color; + bss_color = vif->bss_conf.he_bss_color.color; reg_base = port >= 4 ? R_AX_PTCL_BSS_COLOR_1 : R_AX_PTCL_BSS_COLOR_0; reg = rtw89_mac_reg_by_idx(reg_base, rtwvif->mac_idx); rtw89_write32_mask(rtwdev, reg, masks[port], bss_color); @@ -2736,45 +3146,73 @@ static void rtw89_mac_port_cfg_bcn_early(struct rtw89_dev *rtwdev, BCN_ERLY_DEF); } -void rtw_restore_vif_cfg_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +static +int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - struct rtw89_dev *rtwdev = data; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; int ret; ret = rtw89_mac_port_update(rtwdev, rtwvif); if (ret) - return; + return ret; rtw89_mac_dmac_tbl_init(rtwdev, rtwvif->mac_id); rtw89_mac_cmac_tbl_init(rtwdev, rtwvif->mac_id); ret = rtw89_set_macid_pause(rtwdev, rtwvif->mac_id, false); if (ret) - return; + return ret; ret = rtw89_fw_h2c_vif_maintain(rtwdev, rtwvif, RTW89_VIF_CREATE); - return; + if (ret) + return ret; ret = rtw89_cam_init(rtwdev, rtwvif); if (ret) - return; + return ret; ret = rtw89_fw_h2c_cam(rtwdev, rtwvif); if (ret) - return; + return ret; ret = rtw89_fw_h2c_default_cmac_tbl(rtwdev, rtwvif->mac_id); if (ret) - return; + return ret; + + return 0; } -void rtw_remove_vif_cfg_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +static +int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +{ + int ret; + + ret = rtw89_fw_h2c_vif_maintain(rtwdev, rtwvif, RTW89_VIF_REMOVE); + if (ret) + return ret; + + rtw89_cam_deinit(rtwdev, rtwvif); + + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif); + if (ret) + return ret; + + return 0; +} + +void rtw89_restore_vif_cfg_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = data; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - rtw89_fw_h2c_vif_maintain(rtwdev, rtwvif, RTW89_VIF_REMOVE); + rtw89_mac_vif_init(rtwdev, rtwvif); +} + +void rtw89_remove_vif_cfg_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct rtw89_dev *rtwdev = data; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + + rtw89_mac_vif_deinit(rtwdev, rtwvif); } int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) @@ -2801,7 +3239,7 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif); rtw89_mac_port_cfg_hiq_drop(rtwdev, rtwvif); rtw89_mac_port_cfg_func_en(rtwdev, rtwvif); - udelay(BCN_ERLY_SET_DLY); + fsleep(BCN_ERLY_SET_DLY); rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif); return 0; @@ -2816,30 +3254,7 @@ int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) if (rtwvif->mac_id == RTW89_MAX_MAC_ID_NUM) return -ENOSPC; - ret = rtw89_mac_port_update(rtwdev, rtwvif); - if (ret) - goto release_mac_id; - - rtw89_mac_dmac_tbl_init(rtwdev, rtwvif->mac_id); - rtw89_mac_cmac_tbl_init(rtwdev, rtwvif->mac_id); - - ret = rtw89_set_macid_pause(rtwdev, rtwvif->mac_id, false); - if (ret) - goto release_mac_id; - - ret = rtw89_fw_h2c_vif_maintain(rtwdev, rtwvif, RTW89_VIF_CREATE); - if (ret) - goto release_mac_id; - - ret = rtw89_cam_init(rtwdev, rtwvif); - if (ret) - goto release_mac_id; - - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif); - if (ret) - goto release_mac_id; - - ret = rtw89_fw_h2c_default_cmac_tbl(rtwdev, rtwvif->mac_id); + ret = rtw89_mac_vif_init(rtwdev, rtwvif); if (ret) goto release_mac_id; @@ -2853,19 +3268,9 @@ int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - int ret = 0; - - ret = rtw89_fw_h2c_vif_maintain(rtwdev, rtwvif, RTW89_VIF_REMOVE); - if (ret) - goto release_mac_id; - - rtw89_cam_deinit(rtwdev, rtwvif); - - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif); - if (ret) - goto release_mac_id; + int ret; -release_mac_id: + ret = rtw89_mac_vif_deinit(rtwdev, rtwvif); rtw89_core_release_bit_map(rtwdev->mac_id_map, rtwvif->mac_id); return ret; @@ -2902,6 +3307,8 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) static void rtw89_mac_c2h_log(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) { + rtw89_info(rtwdev, "%*s", RTW89_GET_C2H_LOG_LEN(len), + RTW89_GET_C2H_LOG_SRT_PRT(c2h->data)); } static void (*rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev, @@ -3039,9 +3446,12 @@ void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop) bool empty; int ret; + if (!test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) + return; + ret = read_poll_timeout(dle_is_txq_empty, empty, empty, - 10000, 100000, false, rtwdev); - if (ret) + 10000, 200000, false, rtwdev); + if (ret && !drop && (rtwdev->total_sta_assoc || rtwdev->scanning)) rtw89_info(rtwdev, "timed out to flush queues\n"); } @@ -3277,6 +3687,7 @@ static void rtw89_mac_bfee_ctrl(struct rtw89_dev *rtwdev, u8 mac_idx, bool en) static int rtw89_mac_init_bfee(struct rtw89_dev *rtwdev, u8 mac_idx) { u32 reg; + u32 val32; int ret; ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); @@ -3292,10 +3703,9 @@ static int rtw89_mac_init_bfee(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write32(rtwdev, reg, CSI_RRSC_BMAP); reg = rtw89_mac_reg_by_idx(R_AX_BFMEE_RESP_OPTION, mac_idx); - rtw89_write32_mask(rtwdev, reg, B_AX_BFMEE_BFRP_RX_STANDBY_TIMER_MASK, - BFRP_RX_STANDBY_TIMER); - rtw89_write32_mask(rtwdev, reg, B_AX_BFMEE_NDP_RX_STANDBY_TIMER_MASK, - NDP_RX_STANDBY_TIMER); + val32 = FIELD_PREP(B_AX_BFMEE_BFRP_RX_STANDBY_TIMER_MASK, BFRP_RX_STANDBY_TIMER); + val32 |= FIELD_PREP(B_AX_BFMEE_NDP_RX_STANDBY_TIMER_MASK, NDP_RX_STANDBY_TIMER); + rtw89_write32(rtwdev, reg, val32); rtw89_mac_bfee_ctrl(rtwdev, mac_idx, true); reg = rtw89_mac_reg_by_idx(R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx); @@ -3526,7 +3936,7 @@ void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev) iter_data.rtwdev = rtwdev; iter_data.en = en; - rtw89_iterate_vifs_atomic(rtwdev, rtw89_mac_bfee_ctrl_iter, &iter_data); + rtw89_iterate_vifs(rtwdev, rtw89_mac_bfee_ctrl_iter, &iter_data, false); } static int @@ -3637,3 +4047,24 @@ int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev, return ret; } + +int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool en) +{ + u8 mac_idx = rtwvif->mac_idx; + u16 set = B_AX_MUEDCA_EN_0 | B_AX_SET_MUEDCATIMER_TF_0; + u32 reg; + u32 ret; + + ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); + if (ret) + return ret; + + reg = rtw89_mac_reg_by_idx(R_AX_MUEDCA_EN, mac_idx); + if (en) + rtw89_write16_set(rtwdev, reg, set); + else + rtw89_write16_clr(rtwdev, reg, set); + + return 0; +} diff --git a/mac.h b/mac.h index 2bcd8004..efff7cbb 100644 --- a/mac.h +++ b/mac.h @@ -149,6 +149,23 @@ enum rtw89_mac_dle_ple_quota_id { PLE_QTAID_CPUIO = 10, }; +enum rtw89_mac_dle_ctrl_type { + DLE_CTRL_TYPE_WDE = 0, + DLE_CTRL_TYPE_PLE = 1, + DLE_CTRL_TYPE_NUM = 2, +}; + +enum rtw89_mac_ax_l0_to_l1_event { + MAC_AX_L0_TO_L1_CHIF_IDLE = 0, + MAC_AX_L0_TO_L1_CMAC_DMA_IDLE = 1, + MAC_AX_L0_TO_L1_RLS_PKID = 2, + MAC_AX_L0_TO_L1_PTCL_IDLE = 3, + MAC_AX_L0_TO_L1_RX_QTA_LOST = 4, + MAC_AX_L0_TO_L1_DLE_STAT_HANG = 5, + MAC_AX_L0_TO_L1_PCIE_STUCK = 6, + MAC_AX_L0_TO_L1_EVENT_MAX = 15, +}; + enum rtw89_mac_dbg_port_sel { /* CMAC 0 related */ RTW89_DBG_PORT_SEL_PTCL_C0 = 0, @@ -425,6 +442,7 @@ enum rtw89_mac_bf_rrsc_rate { #define TMAC_DBG_SEL_C1 0xB5 #define RMAC_DBG_SEL_C1 0xB6 #define TRXPTCL_DBG_SEL_C1 0xB7 +#define FW_PROG_CNTR_DBG_SEL 0xF2 #define PCIE_TXDMA_DBG_SEL 0x30 #define PCIE_RXDMA_DBG_SEL 0x31 #define PCIE_CVT_DBG_SEL 0x32 @@ -463,6 +481,32 @@ struct rtw89_mac_dbg_port_info { u32 rd_msk; }; +#define QLNKTBL_ADDR_INFO_SEL BIT(0) +#define QLNKTBL_ADDR_INFO_SEL_0 0 +#define QLNKTBL_ADDR_INFO_SEL_1 1 +#define QLNKTBL_ADDR_TBL_IDX_MASK GENMASK(10, 1) +#define QLNKTBL_DATA_SEL1_PKT_CNT_MASK GENMASK(11, 0) + +struct rtw89_mac_dle_dfi_ctrl { + enum rtw89_mac_dle_ctrl_type type; + u32 target; + u32 addr; + u32 out_data; +}; + +struct rtw89_mac_dle_dfi_quota { + enum rtw89_mac_dle_ctrl_type dle_type; + u32 qtaid; + u16 rsv_pgnum; + u16 use_pgnum; +}; + +struct rtw89_mac_dle_dfi_qempty { + enum rtw89_mac_dle_ctrl_type dle_type; + u32 grpsel; + u32 qempty; +}; + /* Define DBG and recovery enum */ enum mac_ax_err_info { /* Get error info */ @@ -478,6 +522,7 @@ enum mac_ax_err_info { MAC_AX_ERR_L1_RESET_DISABLE_DMAC_DONE = 0x1001, MAC_AX_ERR_L1_RESET_RECOVERY_DONE = 0x1002, MAC_AX_ERR_L1_PROMOTE_TO_L2 = 0x1010, + MAC_AX_ERR_L1_RCVY_STOP_DONE = 0x1011, /* L2 */ /* address hole (master) */ @@ -599,11 +644,15 @@ enum mac_ax_err_info { MAC_AX_ERR_L2_ERR_APB_BBRF_TO_RX4281 = 0x2360, MAC_AX_ERR_L2_ERR_APB_BBRF_TO_OTHERS = 0x2370, MAC_AX_ERR_L2_RESET_DONE = 0x2400, + MAC_AX_ERR_CPU_EXCEPTION = 0x3000, MAC_AX_GET_ERR_MAX, + MAC_AX_DUMP_SHAREBUFF_INDICATOR = 0x80000000, /* set error info */ MAC_AX_ERR_L1_DISABLE_EN = 0x0001, MAC_AX_ERR_L1_RCVY_EN = 0x0002, + MAC_AX_ERR_L1_RCVY_STOP_REQ = 0x0003, + MAC_AX_ERR_L1_RCVY_START_REQ = 0x0004, MAC_AX_ERR_L0_CFG_NOTIFY = 0x0010, MAC_AX_ERR_L0_CFG_DIS_NOTIFY = 0x0011, MAC_AX_ERR_L0_CFG_HANDSHAKE = 0x0012, @@ -791,8 +840,10 @@ void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif * void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, bool disconnect); void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev); -void rtw_restore_vif_cfg_iter(void *data, u8 *mac, struct ieee80211_vif *vif); -void rtw_remove_vif_cfg_iter(void *data, u8 *mac, struct ieee80211_vif *vif); +void rtw89_restore_vif_cfg_iter(void *data, u8 *mac, struct ieee80211_vif *vif); +void rtw89_remove_vif_cfg_iter(void *data, u8 *mac, struct ieee80211_vif *vif); +int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool en); static inline void rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev) { diff --git a/mac80211.c b/mac80211.c index 82a5e1ab..b6e37f6b 100644 --- a/mac80211.c +++ b/mac80211.c @@ -10,6 +10,8 @@ #include "phy.h" #include "ps.h" #include "reg.h" +#include "sar.h" +#include "ser.h" static void rtw89_ops_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, @@ -64,19 +66,17 @@ static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed) struct rtw89_dev *rtwdev = hw->priv; mutex_lock(&rtwdev->mutex); - rtw89_leave_ps_mode(rtwdev); if ((changed & IEEE80211_CONF_CHANGE_IDLE) && - !(hw->conf.flags & IEEE80211_CONF_IDLE)) { + !(hw->conf.flags & IEEE80211_CONF_IDLE)) rtw89_leave_ips(rtwdev); - } if (changed & IEEE80211_CONF_CHANGE_PS) { if (hw->conf.flags & IEEE80211_CONF_PS) { rtwdev->lps_enabled = true; } else { - rtw89_leave_lps(rtwdev); + rtw89_leave_lps(rtwdev, true); rtwdev->lps_enabled = false; } } @@ -101,7 +101,6 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw, int ret = 0; mutex_lock(&rtwdev->mutex); - rtw89_leave_ps_mode(rtwdev); rtw89_traffic_stats_init(rtwdev, &rtwvif->stats); @@ -141,13 +140,10 @@ static void rtw89_ops_remove_interface(struct ieee80211_hw *hw, struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; mutex_lock(&rtwdev->mutex); - rtw89_leave_ps_mode(rtwdev); - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_STOP); rtw89_mac_remove_vif(rtwdev, rtwvif); rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); - mutex_unlock(&rtwdev->mutex); } @@ -159,7 +155,6 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, struct rtw89_dev *rtwdev = hw->priv; mutex_lock(&rtwdev->mutex); - rtw89_leave_ps_mode(rtwdev); *new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL | @@ -277,6 +272,8 @@ static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev, FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_AIFS_MASK, aifs); reg = rtw89_mac_reg_by_idx(ac_to_mu_edca_param[ac], rtwvif->mac_idx); rtw89_write32(rtwdev, reg, val); + + rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif, true); } static void __rtw89_conf_tx(struct rtw89_dev *rtwdev, @@ -295,6 +292,23 @@ static void rtw89_conf_tx(struct rtw89_dev *rtwdev, __rtw89_conf_tx(rtwdev, rtwvif, ac); } +static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf) +{ + struct ieee80211_sta *sta; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + sta = ieee80211_find_sta(vif, conf->bssid); + if (!sta) { + rtw89_err(rtwdev, "can't find sta to set sta_assoc state\n"); + return; + } + rtw89_core_sta_assoc(rtwdev, vif, sta); +} + static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, @@ -304,12 +318,15 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; mutex_lock(&rtwdev->mutex); - rtw89_leave_ps_mode(rtwdev); if (changed & BSS_CHANGED_ASSOC) { - rtw89_phy_set_bss_color(rtwdev, vif); - rtw89_mac_port_update(rtwdev, rtwvif); + if (conf->assoc) { + rtw89_station_mode_sta_assoc(rtwdev, vif, conf); + rtw89_phy_set_bss_color(rtwdev, vif); + rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif); + rtw89_mac_port_update(rtwdev, rtwvif); + } } if (changed & BSS_CHANGED_BSSID) { @@ -338,12 +355,9 @@ static int rtw89_ops_conf_tx(struct ieee80211_hw *hw, struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; mutex_lock(&rtwdev->mutex); - rtw89_leave_ps_mode(rtwdev); - rtwvif->tx_params[ac] = *params; __rtw89_conf_tx(rtwdev, rtwvif, ac); - mutex_unlock(&rtwdev->mutex); return 0; @@ -357,15 +371,16 @@ static int __rtw89_ops_sta_state(struct ieee80211_hw *hw, { struct rtw89_dev *rtwdev = hw->priv; - rtw89_leave_ps_mode(rtwdev); - if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) return rtw89_core_sta_add(rtwdev, vif, sta); if (old_state == IEEE80211_STA_AUTH && - new_state == IEEE80211_STA_ASSOC) + new_state == IEEE80211_STA_ASSOC) { + if (vif->type == NL80211_IFTYPE_STATION) + return 0; /* defer to bss_info_changed to have vif info */ return rtw89_core_sta_assoc(rtwdev, vif, sta); + } if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH) @@ -392,9 +407,7 @@ static int rtw89_ops_sta_state(struct ieee80211_hw *hw, int ret; mutex_lock(&rtwdev->mutex); - rtw89_leave_ps_mode(rtwdev); - ret = __rtw89_ops_sta_state(hw, vif, sta, old_state, new_state); mutex_unlock(&rtwdev->mutex); @@ -410,7 +423,6 @@ static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, int ret = 0; mutex_lock(&rtwdev->mutex); - rtw89_leave_ps_mode(rtwdev); switch (cmd) { @@ -426,7 +438,7 @@ static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, rtw89_hci_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1, false); rtw89_mac_flush_txq(rtwdev, BIT(rtwdev->hw->queues) - 1, false); - ret = rtw89_cam_sec_key_del(rtwdev, vif, sta, key); + ret = rtw89_cam_sec_key_del(rtwdev, vif, sta, key, true); if (ret) { rtw89_err(rtwdev, "failed to remove key from sec cam\n"); goto out; @@ -489,7 +501,6 @@ static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); - if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0); mutex_unlock(&rtwdev->mutex); @@ -514,12 +525,86 @@ static void rtw89_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct rtw89_dev *rtwdev = hw->priv; mutex_lock(&rtwdev->mutex); - rtw89_leave_lps(rtwdev); + rtw89_leave_lps(rtwdev, false); rtw89_hci_flush_queues(rtwdev, queues, drop); rtw89_mac_flush_txq(rtwdev, queues, drop); mutex_unlock(&rtwdev->mutex); } +struct rtw89_iter_bitrate_mask_data { + struct rtw89_dev *rtwdev; + struct ieee80211_vif *vif; + const struct cfg80211_bitrate_mask *mask; +}; + +static void rtw89_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_iter_bitrate_mask_data *br_data = data; + struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif); + + if (vif != br_data->vif) + return; + + rtwsta->use_cfg_mask = true; + rtwsta->mask = *br_data->mask; + rtw89_phy_ra_updata_sta(br_data->rtwdev, sta); +} + +static void rtw89_ra_mask_info_update(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct rtw89_iter_bitrate_mask_data br_data = { .rtwdev = rtwdev, + .vif = vif, + .mask = mask}; + + ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_ra_mask_info_update_iter, + &br_data); +} + +static int rtw89_ops_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct rtw89_dev *rtwdev = hw->priv; + + mutex_lock(&rtwdev->mutex); + rtw89_ra_mask_info_update(rtwdev, vif, mask); + mutex_unlock(&rtwdev->mutex); + + return 0; +} + +static +int rtw89_ops_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_hal *hal = &rtwdev->hal; + + if (rx_ant != hw->wiphy->available_antennas_rx) + return -EINVAL; + + mutex_lock(&rtwdev->mutex); + hal->antenna_tx = tx_ant; + hal->antenna_rx = rx_ant; + mutex_unlock(&rtwdev->mutex); + + return 0; +} + +static +int rtw89_ops_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_hal *hal = &rtwdev->hal; + + *tx_ant = hal->antenna_tx; + *rx_ant = hal->antenna_rx; + + return 0; +} + static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac_addr) @@ -529,7 +614,7 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); rtwdev->scanning = true; - rtw89_leave_lps(rtwdev); + rtw89_leave_lps(rtwdev, false); rtw89_btc_ntfy_scan_start(rtwdev, RTW89_PHY_0, hal->current_band_type); mutex_unlock(&rtwdev->mutex); } @@ -545,6 +630,15 @@ static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } +static void rtw89_ops_reconfig_complete(struct ieee80211_hw *hw, + enum ieee80211_reconfig_type reconfig_type) +{ + struct rtw89_dev *rtwdev = hw->priv; + + if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART) + rtw89_ser_recfg_done(rtwdev); +} + const struct ieee80211_ops rtw89_ops = { .tx = rtw89_ops_tx, .wake_tx_queue = rtw89_ops_wake_tx_queue, @@ -562,7 +656,14 @@ const struct ieee80211_ops rtw89_ops = { .set_rts_threshold = rtw89_ops_set_rts_threshold, .sta_statistics = rtw89_ops_sta_statistics, .flush = rtw89_ops_flush, + .set_bitrate_mask = rtw89_ops_set_bitrate_mask, + .set_antenna = rtw89_ops_set_antenna, + .get_antenna = rtw89_ops_get_antenna, .sw_scan_start = rtw89_ops_sw_scan_start, .sw_scan_complete = rtw89_ops_sw_scan_complete, + .reconfig_complete = rtw89_ops_reconfig_complete, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) + .set_sar_specs = rtw89_ops_set_sar_specs, +#endif }; EXPORT_SYMBOL(rtw89_ops); diff --git a/pci.c b/pci.c index cbb80708..c4de5542 100644 --- a/pci.c +++ b/pci.c @@ -106,7 +106,8 @@ static void rtw89_pci_isr_txch_dma(struct rtw89_dev *rtwdev, cnt = rtw89_pci_txbd_recalc(rtwdev, tx_ring); if (!cnt) - rtw89_warn(rtwdev, "No TXBD consumed after DMA kicked off\n"); + rtw89_debug(rtwdev, RTW89_DBG_TXRX, + "No fwcmd TXBD consumed after DMA kicked off\n"); rtw89_pci_release_fwcmd(rtwdev, rtwpci, cnt); spin_unlock_bh(&rtwpci->trx_lock); @@ -360,7 +361,7 @@ static void rtw89_pci_tx_status(struct rtw89_dev *rtwdev, } } - ieee80211_tx_status_irqsafe(rtwdev->hw, skb); + ieee80211_tx_status_ni(rtwdev->hw, skb); } static void rtw89_pci_reclaim_txbd(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring) @@ -850,7 +851,7 @@ static void __pci_flush_txch(struct rtw89_dev *rtwdev, u8 txch, bool drop) * helper. Instead, we can ensure a reasonable polling times, so we * just use for loop with udelay here. */ - for (i = 0; i < 30; i++) { + for (i = 0; i < 60; i++) { cur_idx = rtw89_read32(rtwdev, bd_ring->addr_idx); cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx); if (cur_rp == bd_ring->wp) @@ -1210,7 +1211,7 @@ static u32 rtw89_pci_ops_read32_cmac(struct rtw89_dev *rtwdev, u32 addr) if (val != RTW89_R32_DEAD) return val; if (count >= MAC_REG_POOL_COUNT) { - rtw89_warn(rtwdev, "addr 0x%x = 0xdeadbeef\n", addr); + rtw89_warn(rtwdev, "addr %#x = %#x\n", addr, val); return RTW89_R32_DEAD; } rtw89_pci_ops_write32(rtwdev, R_AX_CK_EN, B_AX_CMAC_ALLCKEN); @@ -1332,7 +1333,7 @@ rtw89_read16_mdio(struct rtw89_dev *rtwdev, u8 addr, u8 speed, u16 *val) ret = rtw89_pci_check_mdio(rtwdev, addr, speed, B_AX_MDIO_RFLAG); if (ret) { - rtw89_err(rtwdev, "[ERR]MDIO R16 0x%X fail!\n", addr); + rtw89_err(rtwdev, "[ERR]MDIO R16 0x%X fail ret=%d!\n", addr, ret); return ret; } *val = rtw89_read16(rtwdev, R_AX_MDIO_RDATA); @@ -1348,7 +1349,7 @@ rtw89_write16_mdio(struct rtw89_dev *rtwdev, u8 addr, u16 data, u8 speed) rtw89_write16(rtwdev, R_AX_MDIO_WDATA, data); ret = rtw89_pci_check_mdio(rtwdev, addr, speed, B_AX_MDIO_WFLAG); if (ret) { - rtw89_err(rtwdev, "[ERR]MDIO W16 0x%X = %x fail!\n", addr, data); + rtw89_err(rtwdev, "[ERR]MDIO W16 0x%X = %x fail ret=%d!\n", addr, data, ret); return ret; } @@ -1426,12 +1427,42 @@ static int rtw89_dbi_read8(struct rtw89_dev *rtwdev, u16 addr, u8 *value) *value = rtw89_read8(rtwdev, read_addr); } else { WARN(1, "failed to read DBI register, addr=0x%04x\n", addr); - ret = -EIO; + ret = -EIO; } return ret; } +static int rtw89_dbi_write8_set(struct rtw89_dev *rtwdev, u16 addr, u8 bit) +{ + u8 value; + int ret; + + ret = rtw89_dbi_read8(rtwdev, addr, &value); + if (ret) + return ret; + + value |= bit; + ret = rtw89_dbi_write8(rtwdev, addr, value); + + return ret; +} + +static int rtw89_dbi_write8_clr(struct rtw89_dev *rtwdev, u16 addr, u8 bit) +{ + u8 value; + int ret; + + ret = rtw89_dbi_read8(rtwdev, addr, &value); + if (ret) + return ret; + + value &= ~bit; + ret = rtw89_dbi_write8(rtwdev, addr, value); + + return ret; +} + static int __get_target(struct rtw89_dev *rtwdev, u16 *target, enum rtw89_pcie_phy phy_rate) { @@ -1442,11 +1473,11 @@ __get_target(struct rtw89_dev *rtwdev, u16 *target, enum rtw89_pcie_phy phy_rate ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &val); if (ret) return ret; - ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val & ~BIT(12), + ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val & ~B_AX_CLK_CALIB_EN, phy_rate); if (ret) return ret; - ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val | BIT(12), + ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val | B_AX_CLK_CALIB_EN, phy_rate); if (ret) return ret; @@ -1456,7 +1487,7 @@ __get_target(struct rtw89_dev *rtwdev, u16 *target, enum rtw89_pcie_phy phy_rate ret = rtw89_read16_mdio(rtwdev, RAC_CTRL_PPR_V1, phy_rate, &tar); if (ret) return ret; - ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val & ~BIT(12), + ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val & ~B_AX_CLK_CALIB_EN, phy_rate); if (ret) return ret; @@ -1480,18 +1511,22 @@ static int rtw89_pci_auto_refclk_cal(struct rtw89_dev *rtwdev, bool autook_en) bool l1_flag = false; int ret = 0; + if ((rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv == CHIP_CBV) || + rtwdev->chip->chip_id == RTL8852C) + return 0; + ret = rtw89_dbi_read8(rtwdev, RTW89_PCIE_PHY_RATE, &val8); if (ret) { rtw89_err(rtwdev, "[ERR]dbi_r8_pcie %X\n", RTW89_PCIE_PHY_RATE); return ret; } - if (FIELD_GET(GENMASK(1, 0), val8) == 0x1) { + if (FIELD_GET(RTW89_PCIE_PHY_RATE_MASK, val8) == 0x1) { phy_rate = PCIE_PHY_GEN1; - } else if (FIELD_GET(GENMASK(1, 0), val8) == 0x2) { + } else if (FIELD_GET(RTW89_PCIE_PHY_RATE_MASK, val8) == 0x2) { phy_rate = PCIE_PHY_GEN2; } else { - rtw89_err(rtwdev, "[ERR]PCIe PHY rate not support\n"); + rtw89_err(rtwdev, "[ERR]PCIe PHY rate %#x not support\n", val8); return -EOPNOTSUPP; } /* Disable L1BD */ @@ -1517,9 +1552,9 @@ static int rtw89_pci_auto_refclk_cal(struct rtw89_dev *rtwdev, bool autook_en) goto end; } - if (val16 & BIT(13)) { + if (val16 & B_AX_CALIB_EN) { ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, - val16 & ~BIT(13), phy_rate); + val16 & ~B_AX_CALIB_EN, phy_rate); if (ret) { rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1); goto end; @@ -1529,13 +1564,13 @@ static int rtw89_pci_auto_refclk_cal(struct rtw89_dev *rtwdev, bool autook_en) if (!autook_en) goto end; /* Set div */ - ret = rtw89_write16_mdio_clr(rtwdev, RAC_CTRL_PPR_V1, BIT(15) | BIT(14), phy_rate); + ret = rtw89_write16_mdio_clr(rtwdev, RAC_CTRL_PPR_V1, B_AX_DIV, phy_rate); if (ret) { rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1); goto end; } - /* Obtain div and margin */ + /* Obtain div and margin */ ret = __get_target(rtwdev, &tar, phy_rate); if (ret) { rtw89_err(rtwdev, "[ERR]1st get target fail %d\n", ret); @@ -1569,7 +1604,7 @@ static int rtw89_pci_auto_refclk_cal(struct rtw89_dev *rtwdev, bool autook_en) goto end; } - val16 |= u16_encode_bits(div_set, GENMASK(15, 14)); + val16 |= u16_encode_bits(div_set, B_AX_DIV); ret = rtw89_write16_mdio(rtwdev, RAC_CTRL_PPR_V1, val16, phy_rate); if (ret) { @@ -1593,7 +1628,7 @@ static int rtw89_pci_auto_refclk_cal(struct rtw89_dev *rtwdev, bool autook_en) } /* Enable function */ - ret = rtw89_write16_mdio_set(rtwdev, RAC_CTRL_PPR_V1, BIT(13), phy_rate); + ret = rtw89_write16_mdio_set(rtwdev, RAC_CTRL_PPR_V1, B_AX_CALIB_EN, phy_rate); if (ret) { rtw89_err(rtwdev, "[ERR]mdio_w16_pcie %X\n", RAC_CTRL_PPR_V1); goto end; @@ -1622,11 +1657,11 @@ static int rtw89_pci_deglitch_setting(struct rtw89_dev *rtwdev) if (rtwdev->chip->chip_id != RTL8852A) return 0; - ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA24, GENMASK(11, 8), + ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA24, B_AX_DEGLITCH, PCIE_PHY_GEN1); if (ret) return ret; - ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA24, GENMASK(11, 8), + ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA24, B_AX_DEGLITCH, PCIE_PHY_GEN2); if (ret) return ret; @@ -1654,13 +1689,13 @@ static u32 rtw89_pci_l2_rxen_lat(struct rtw89_dev *rtwdev) if (rtwdev->chip->chip_id == RTL8852C) return 0; - ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA26, GENMASK(15, 14), + ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA26, B_AX_RXEN, PCIE_PHY_GEN1); if (ret) return ret; - ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA26, GENMASK(11, 8), - PCIE_PHY_GEN1); + ret = rtw89_write16_mdio_clr(rtwdev, RAC_ANA26, B_AX_RXEN, + PCIE_PHY_GEN2); if (ret) return ret; @@ -1771,7 +1806,7 @@ static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev) B_AX_PCIE_AUXCLK_GATE); lbc = rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG); - lbc = u32_replace_bits(lbc, RTW89_MAC_LBC_TMR_2MS, B_AX_LBC_TIMER); + lbc = u32_replace_bits(lbc, RTW89_MAC_LBC_TMR_128US, B_AX_LBC_TIMER); lbc |= B_AX_LBC_FLAG | B_AX_LBC_EN; rtw89_write32(rtwdev, R_AX_LBC_WATCHDOG, lbc); @@ -2481,46 +2516,38 @@ static void rtw89_pci_free_irq(struct rtw89_dev *rtwdev, static void rtw89_pci_clkreq_set(struct rtw89_dev *rtwdev, bool enable) { - u8 value; int ret; if (rtw89_pci_disable_clkreq) return; - ret = rtw89_dbi_read8(rtwdev, RTW89_PCIE_L1_CTRL, &value); - if (ret) { - rtw89_err(rtwdev, "failed to read CLKREQ_L1, ret=%d", ret); - return; - } - if (enable) - value |= RTW89_PCIE_BIT_CLK; + ret = rtw89_dbi_write8_set(rtwdev, RTW89_PCIE_L1_CTRL, + RTW89_PCIE_BIT_CLK); else - value &= ~RTW89_PCIE_BIT_CLK; - - rtw89_dbi_write8(rtwdev, RTW89_PCIE_L1_CTRL, value); + ret = rtw89_dbi_write8_clr(rtwdev, RTW89_PCIE_L1_CTRL, + RTW89_PCIE_BIT_CLK); + if (ret) + rtw89_err(rtwdev, "failed to %s CLKREQ_L1, ret=%d", + enable ? "set" : "unset", ret); } static void rtw89_pci_aspm_set(struct rtw89_dev *rtwdev, bool enable) { - u8 value; int ret; if (rtw89_pci_disable_aspm_l1) return; - ret = rtw89_dbi_read8(rtwdev, RTW89_PCIE_L1_CTRL, &value); - if (ret) { - rtw89_err(rtwdev, "failed to read ASPM, ret=%d", ret); - return; - } - if (enable) - value |= RTW89_PCIE_BIT_L1; + ret = rtw89_dbi_write8_set(rtwdev, RTW89_PCIE_L1_CTRL, + RTW89_PCIE_BIT_L1); else - value &= ~RTW89_PCIE_BIT_L1; - - rtw89_dbi_write8(rtwdev, RTW89_PCIE_L1_CTRL, value); + ret = rtw89_dbi_write8_clr(rtwdev, RTW89_PCIE_L1_CTRL, + RTW89_PCIE_BIT_L1); + if (ret) + rtw89_err(rtwdev, "failed to %s ASPM L1, ret=%d", + enable ? "set" : "unset", ret); } static void rtw89_pci_link_ps(struct rtw89_dev *rtwdev, bool enter) @@ -2576,26 +2603,22 @@ static void rtw89_pci_link_cfg(struct rtw89_dev *rtwdev) rtwpci->link_ctrl = link_ctrl; } -static void rtw_pci_l1ss_set(struct rtw89_dev *rtwdev, bool enable) +static void rtw89_pci_l1ss_set(struct rtw89_dev *rtwdev, bool enable) { - u8 value; int ret; - ret = rtw89_dbi_read8(rtwdev, RTW89_PCIE_TIMER_CTRL, &value); - if (ret) { - rtw89_err(rtwdev, "failed to read L1SS, ret=%d", ret); - return; - } - if (enable) - value |= RTW89_PCIE_BIT_L1SUB; + ret = rtw89_dbi_write8_set(rtwdev, RTW89_PCIE_TIMER_CTRL, + RTW89_PCIE_BIT_L1SUB); else - value &= ~RTW89_PCIE_BIT_L1SUB; - - rtw89_dbi_write8(rtwdev, RTW89_PCIE_TIMER_CTRL, value); + ret = rtw89_dbi_write8_clr(rtwdev, RTW89_PCIE_TIMER_CTRL, + RTW89_PCIE_BIT_L1SUB); + if (ret) + rtw89_err(rtwdev, "failed to %s L1SS, ret=%d", + enable ? "set" : "unset", ret); } -static void rtw_pci_l1ss_cfg(struct rtw89_dev *rtwdev) +static void rtw89_pci_l1ss_cfg(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; struct pci_dev *pdev = rtwpci->pdev; @@ -2611,7 +2634,7 @@ static void rtw_pci_l1ss_cfg(struct rtw89_dev *rtwdev) pci_read_config_dword(pdev, l1ss_cap_ptr + PCI_L1SS_CTL1, &l1ss_ctrl); if (l1ss_ctrl & PCI_L1SS_CTL1_L1SS_MASK) - rtw_pci_l1ss_set(rtwdev, true); + rtw89_pci_l1ss_set(rtwdev, true); } static void rtw89_pci_ctrl_dma_all_pcie(struct rtw89_dev *rtwdev, u8 en) @@ -2652,8 +2675,31 @@ static int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev) static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev) { + u32 val, dma_rst = 0; + int ret; + rtw89_pci_ctrl_dma_all_pcie(rtwdev, MAC_AX_FUNC_DIS); - return rtw89_pci_poll_io_idle(rtwdev); + ret = rtw89_pci_poll_io_idle(rtwdev); + if (ret) { + val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG); + rtw89_debug(rtwdev, RTW89_DBG_HCI, + "[PCIe] poll_io_idle fail, before 0x%08x: 0x%08x\n", + R_AX_DBG_ERR_FLAG, val); + if (val & B_AX_TX_STUCK || val & B_AX_PCIE_TXBD_LEN0) + dma_rst |= B_AX_HCI_TXDMA_EN; + if (val & B_AX_RX_STUCK) + dma_rst |= B_AX_HCI_RXDMA_EN; + val = rtw89_read32(rtwdev, R_AX_HCI_FUNC_EN); + rtw89_write32(rtwdev, R_AX_HCI_FUNC_EN, val & ~dma_rst); + rtw89_write32(rtwdev, R_AX_HCI_FUNC_EN, val | dma_rst); + ret = rtw89_pci_poll_io_idle(rtwdev); + val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG); + rtw89_debug(rtwdev, RTW89_DBG_HCI, + "[PCIe] poll_io_idle fail, after 0x%08x: 0x%08x\n", + R_AX_DBG_ERR_FLAG, val); + } + + return ret; } static void rtw89_pci_ctrl_hci_dma_en(struct rtw89_dev *rtwdev, u8 en) @@ -2699,19 +2745,20 @@ static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev) return ret; } -static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev, u8 step) +static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev, + enum rtw89_lv1_rcvy_step step) { int ret; switch (step) { - case MAC_AX_LV1_RCVY_STEP_1: + case RTW89_LV1_RCVY_STEP_1: ret = rtw89_pci_lv1rst_stop_dma(rtwdev); if (ret) rtw89_err(rtwdev, "lv1 rcvy pci stop dma fail\n"); break; - case MAC_AX_LV1_RCVY_STEP_2: + case RTW89_LV1_RCVY_STEP_2: ret = rtw89_pci_lv1rst_start_dma(rtwdev); if (ret) rtw89_err(rtwdev, "lv1 rcvy pci start dma fail\n"); @@ -2724,6 +2771,16 @@ static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev, u8 step) return ret; } +static void rtw89_pci_ops_dump_err_status(struct rtw89_dev *rtwdev) +{ + rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX =0x%08x\n", + rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX)); + rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG)); + rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n", + rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG)); +} + static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) { struct rtw89_dev *rtwdev = container_of(napi, struct rtw89_dev, napi); @@ -2752,6 +2809,56 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) return ret; } +static int __maybe_unused rtw89_pci_suspend(struct device *dev) +{ + struct ieee80211_hw *hw = dev_get_drvdata(dev); + struct rtw89_dev *rtwdev = hw->priv; + + rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, + B_AX_PCIE_DIS_L2_CTRL_LDO_HCI); + rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_B6); + rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); + rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_B6); + rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, + B_AX_PCIE_PERST_KEEP_REG | B_AX_PCIE_TRAIN_KEEP_REG); + + return 0; +} + +static void rtw89_pci_l2_hci_ldo(struct rtw89_dev *rtwdev) +{ + if (rtwdev->chip->chip_id == RTL8852C) + return; + + /* Hardware need write the reg twice to ensure the setting work */ + rtw89_dbi_write8_set(rtwdev, RTW89_PCIE_RST_MSTATE, + RTW89_PCIE_BIT_CFG_RST_MSTATE); + rtw89_dbi_write8_set(rtwdev, RTW89_PCIE_RST_MSTATE, + RTW89_PCIE_BIT_CFG_RST_MSTATE); +} + +static int __maybe_unused rtw89_pci_resume(struct device *dev) +{ + struct ieee80211_hw *hw = dev_get_drvdata(dev); + struct rtw89_dev *rtwdev = hw->priv; + + rtw89_write32_set(rtwdev, R_AX_SYS_SDIO_CTRL, + B_AX_PCIE_DIS_L2_CTRL_LDO_HCI); + rtw89_write32_set(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_B6); + rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); + rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_WLOCK_1C_B6); + rtw89_write32_clr(rtwdev, R_AX_PCIE_INIT_CFG1, + B_AX_PCIE_PERST_KEEP_REG | B_AX_PCIE_TRAIN_KEEP_REG); + rtw89_pci_l2_hci_ldo(rtwdev); + rtw89_pci_link_cfg(rtwdev); + rtw89_pci_l1ss_cfg(rtwdev); + + return 0; +} + +SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume); +EXPORT_SYMBOL(rtw89_pm_ops); + static const struct rtw89_hci_ops rtw89_pci_ops = { .tx_write = rtw89_pci_ops_tx_write, .tx_kick_off = rtw89_pci_ops_tx_kick_off, @@ -2774,6 +2881,7 @@ static const struct rtw89_hci_ops rtw89_pci_ops = { .check_and_reclaim_tx_resource = rtw89_pci_check_and_reclaim_tx_resource, .mac_lv1_rcvy = rtw89_pci_ops_mac_lv1_recovery, + .dump_err_status = rtw89_pci_ops_dump_err_status, .napi_poll = rtw89_pci_napi_poll, }; @@ -2835,7 +2943,7 @@ static int rtw89_pci_probe(struct pci_dev *pdev, } rtw89_pci_link_cfg(rtwdev); - rtw_pci_l1ss_cfg(rtwdev); + rtw89_pci_l1ss_cfg(rtwdev); ret = rtw89_core_register(rtwdev); if (ret) { @@ -2873,9 +2981,6 @@ static void rtw89_pci_remove(struct pci_dev *pdev) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct rtw89_dev *rtwdev; - if (!hw) - return; - rtwdev = hw->priv; rtw89_pci_free_irq(rtwdev, pdev); @@ -2898,6 +3003,7 @@ static struct pci_driver rtw89_pci_driver = { .id_table = rtw89_pci_id_table, .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, + .driver.pm = &rtw89_pm_ops, }; module_pci_driver(rtw89_pci_driver); diff --git a/pci.h b/pci.h index cc135345..cdc1f0ca 100644 --- a/pci.h +++ b/pci.h @@ -15,8 +15,13 @@ #define RAC_ANA19 0x19 #define RAC_ANA1F 0x1F #define RAC_ANA24 0x24 +#define B_AX_DEGLITCH GENMASK(11, 8) #define RAC_ANA26 0x26 +#define B_AX_RXEN GENMASK(15, 14) #define RAC_CTRL_PPR_V1 0x30 +#define B_AX_CLK_CALIB_EN BIT(12) +#define B_AX_CALIB_EN BIT(13) +#define B_AX_DIV GENMASK(15, 14) #define RAC_SET_PPR_V1 0x31 #define R_AX_DBI_FLAG 0x1090 @@ -27,6 +32,9 @@ #define R_AX_DBI_WDATA 0x1094 #define R_AX_DBI_RDATA 0x1098 +#define R_AX_MDIO_WDATA 0x10A4 +#define R_AX_MDIO_RDATA 0x10A6 + #define RTW89_PCI_WR_RETRY_CNT 20 /* Interrupts */ @@ -274,7 +282,35 @@ #define B_AX_PCIE_TXRST_KEEP_REG BIT(22) #define B_AX_DIS_RXDMA_PRE BIT(2) -#define R_AX_PCIE_RX_PREF_ADV 0x13F4 +#define R_AX_PCIE_INIT_CFG2 0x1004 +#define B_AX_WD_ITVL_IDLE GENMASK(27, 24) +#define B_AX_WD_ITVL_ACT GENMASK(19, 16) + +#define R_AX_PCIE_PS_CTRL 0x1008 +#define B_AX_L1OFF_PWR_OFF_EN BIT(5) + +#define R_AX_DBG_ERR_FLAG 0x11C4 +#define B_AX_PCIE_RPQ_FULL BIT(29) +#define B_AX_PCIE_RXQ_FULL BIT(28) +#define B_AX_CPL_STATUS_MASK GENMASK(27, 25) +#define B_AX_RX_STUCK BIT(22) +#define B_AX_TX_STUCK BIT(21) +#define B_AX_PCIEDBG_TXERR0 BIT(16) +#define B_AX_PCIE_RXP1_ERR0 BIT(4) +#define B_AX_PCIE_TXBD_LEN0 BIT(1) +#define B_AX_PCIE_TXBD_4KBOUD_LENERR BIT(0) + +#define R_AX_LBC_WATCHDOG 0x11D8 +#define B_AX_LBC_TIMER GENMASK(7, 4) +#define B_AX_LBC_FLAG BIT(1) +#define B_AX_LBC_EN BIT(0) + +#define R_AX_PCIE_EXP_CTRL 0x13F0 +#define B_AX_EN_CHKDSC_NO_RX_STUCK BIT(20) +#define B_AX_MAX_TAG_NUM GENMASK(18, 16) +#define B_AX_SIC_EN_FORCE_CLKREQ BIT(4) + +#define R_AX_PCIE_RX_PREF_ADV 0x13F4 #define B_AX_RXDMA_PREF_ADV_EN BIT(0) #define RTW89_PCI_TXBD_NUM_MAX 256 @@ -293,7 +329,10 @@ #define RTW89_PCIE_BIT_CLK BIT(4) #define RTW89_PCIE_BIT_L1 BIT(3) #define RTW89_PCIE_CLK_CTRL 0x0725 +#define RTW89_PCIE_RST_MSTATE 0x0B48 +#define RTW89_PCIE_BIT_CFG_RST_MSTATE BIT(0) #define RTW89_PCIE_PHY_RATE 0x82 +#define RTW89_PCIE_PHY_RATE_MASK GENMASK(1, 0) #define INTF_INTGRA_MINREF_V1 90 #define INTF_INTGRA_HOSTREF_V1 100 @@ -308,11 +347,6 @@ enum mac_ax_func_sw { MAC_AX_FUNC_EN, }; -enum mac_ax_lv1_rcvy_step { - MAC_AX_LV1_RCVY_STEP_1 = 0, - MAC_AX_LV1_RCVY_STEP_2 -}; - enum rtw89_pcie_clkdly_hw { PCIE_CLKDLY_HW_0 = 0, PCIE_CLKDLY_HW_30US = 0x1, @@ -572,4 +606,6 @@ static inline bool rtw89_pci_ltr_is_err_reg_val(u32 val) return val == 0xffffffff || val == 0xeaeaeaea; } +extern const struct dev_pm_ops rtw89_pm_ops; + #endif diff --git a/phy.c b/phy.c index 15153842..11b0f8be 100644 --- a/phy.c +++ b/phy.c @@ -5,7 +5,9 @@ #include "debug.h" #include "fw.h" #include "phy.h" +#include "ps.h" #include "reg.h" +#include "sar.h" static u16 get_max_amsdu_len(struct rtw89_dev *rtwdev, const struct rtw89_ra_report *report) @@ -119,6 +121,55 @@ static u64 rtw89_phy_ra_mask_rssi(struct rtw89_dev *rtwdev, u8 rssi, return 0xffffffffffffffffULL; } +static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) +{ + struct rtw89_hal *hal = &rtwdev->hal; + struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); + struct cfg80211_bitrate_mask *mask = &rtwsta->mask; + enum nl80211_band band; + u64 cfg_mask; + + if (!rtwsta->use_cfg_mask) + return -1; + + switch (hal->current_band_type) { + case RTW89_BAND_2G: + band = NL80211_BAND_2GHZ; + cfg_mask = u64_encode_bits(mask->control[NL80211_BAND_2GHZ].legacy, + RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES); + break; + case RTW89_BAND_5G: + band = NL80211_BAND_5GHZ; + cfg_mask = u64_encode_bits(mask->control[NL80211_BAND_5GHZ].legacy, + RA_MASK_OFDM_RATES); + break; + default: + rtw89_warn(rtwdev, "unhandled band type %d\n", hal->current_band_type); + return -1; + } + + if (sta->he_cap.has_he) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) + cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[0], + RA_MASK_HE_1SS_RATES); + cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[1], + RA_MASK_HE_2SS_RATES); +#endif + } else if (sta->vht_cap.vht_supported) { + cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0], + RA_MASK_VHT_1SS_RATES); + cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1], + RA_MASK_VHT_2SS_RATES); + } else if (sta->ht_cap.ht_supported) { + cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0], + RA_MASK_HT_1SS_RATES); + cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1], + RA_MASK_HT_2SS_RATES); + } + + return cfg_mask; +} + static const u64 rtw89_ra_mask_ht_rates[4] = {RA_MASK_HT_1SS_RATES, RA_MASK_HT_2SS_RATES, RA_MASK_HT_3SS_RATES, RA_MASK_HT_4SS_RATES}; @@ -211,8 +262,10 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, ra_mask = RA_MASK_CCK_RATES; } - if (mode != RTW89_RA_MODE_CCK) + if (mode != RTW89_RA_MODE_CCK) { ra_mask &= rtw89_phy_ra_mask_rssi(rtwdev, rssi, 0); + ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta); + } switch (sta->bandwidth) { case IEEE80211_STA_RX_BW_80: @@ -258,9 +311,8 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, ra->csi_mode = csi_mode; } -static void rtw89_phy_ra_updata_sta_iter(void *data, struct ieee80211_sta *sta) +void rtw89_phy_ra_updata_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta) { - struct rtw89_dev *rtwdev = (struct rtw89_dev *)data; struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; struct rtw89_ra_info *ra = &rtwsta->ra; @@ -277,6 +329,13 @@ static void rtw89_phy_ra_updata_sta_iter(void *data, struct ieee80211_sta *sta) rtw89_fw_h2c_ra(rtwdev, ra, false); } +static void rtw89_phy_ra_updata_sta_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_dev *rtwdev = (struct rtw89_dev *)data; + + rtw89_phy_ra_updata_sta(rtwdev, sta); +} + void rtw89_phy_ra_update(struct rtw89_dev *rtwdev) { ieee80211_iterate_stations_atomic(rtwdev->hw, @@ -430,6 +489,7 @@ bool rtw89_phy_write_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, rtw89_phy_write32_mask(rtwdev, direct_addr, mask, data); + /* delay to ensure writing properly */ udelay(1); return true; @@ -914,7 +974,11 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 ch_idx = rtw89_channel_to_idx(rtwdev, ch); u8 band = rtwdev->hal.current_band_type; u8 regd = rtw89_regd_get(rtwdev, band); - s8 lmt = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) + s8 lmt = 0, sar; +#else + s8 lmt; +#endif switch (band) { case RTW89_BAND_2G: @@ -928,7 +992,14 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, return 0; } - return _phy_txpwr_rf_to_mac(rtwdev, lmt); + lmt = _phy_txpwr_rf_to_mac(rtwdev, lmt); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) + sar = rtw89_query_sar(rtwdev); + + return min(lmt, sar); +#else + return lmt; +#endif } #define __fill_txpwr_limit_nonbf_bf(ptr, bw, ntx, rs, ch) \ @@ -1036,7 +1107,11 @@ static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 ch_idx = rtw89_channel_to_idx(rtwdev, ch); u8 band = rtwdev->hal.current_band_type; u8 regd = rtw89_regd_get(rtwdev, band); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) + s8 lmt_ru = 0, sar; +#else s8 lmt_ru = 0; +#endif switch (band) { case RTW89_BAND_2G: @@ -1050,7 +1125,14 @@ static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, return 0; } - return _phy_txpwr_rf_to_mac(rtwdev, lmt_ru); + lmt_ru = _phy_txpwr_rf_to_mac(rtwdev, lmt_ru); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) + sar = rtw89_query_sar(rtwdev); + + return min(lmt_ru, sar); +#else + return lmt_ru; +#endif } static void @@ -1206,6 +1288,7 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta) ra_report->hw_rate = FIELD_PREP(RTW89_HW_RATE_MASK_MOD, mode) | FIELD_PREP(RTW89_HW_RATE_MASK_VAL, rate); sta->max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report); + rtwsta->max_agg_wait = sta->max_rc_amsdu_len / 1500 - 1; } static void @@ -1276,22 +1359,25 @@ static void rtw89_phy_cfo_set_xcap_reg(struct rtw89_dev *rtwdev, bool sc_xo, } static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, - u8 crystal_cap) + u8 crystal_cap, bool force) { struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; u8 sc_xi_val, sc_xo_val; - if (cfo->crystal_cap == crystal_cap) + if (!force && cfo->crystal_cap == crystal_cap) return; - + crystal_cap = clamp_t(u8, crystal_cap, 0, 127); rtw89_phy_cfo_set_xcap_reg(rtwdev, true, crystal_cap); rtw89_phy_cfo_set_xcap_reg(rtwdev, false, crystal_cap); sc_xo_val = rtw89_phy_cfo_get_xcap_reg(rtwdev, true); sc_xi_val = rtw89_phy_cfo_get_xcap_reg(rtwdev, false); cfo->crystal_cap = sc_xi_val; + cfo->x_cap_ofst = (s8)((int)cfo->crystal_cap - cfo->def_x_cap); rtw89_debug(rtwdev, RTW89_DBG_CFO, "Set sc_xi=0x%x\n", sc_xi_val); rtw89_debug(rtwdev, RTW89_DBG_CFO, "Set sc_xo=0x%x\n", sc_xo_val); + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Get xcap_ofst=%d\n", + cfo->x_cap_ofst); rtw89_debug(rtwdev, RTW89_DBG_CFO, "Set xcap OK\n"); } @@ -1301,15 +1387,47 @@ static void rtw89_phy_cfo_reset(struct rtw89_dev *rtwdev) u8 cap; cfo->def_x_cap = cfo->crystal_cap_default & B_AX_XTAL_SC_MSK; - cfo->is_adjust = true; + cfo->is_adjust = false; if (cfo->crystal_cap == cfo->def_x_cap) return; cap = cfo->crystal_cap; cap += (cap > cfo->def_x_cap ? -1 : 1); - rtw89_phy_cfo_set_crystal_cap(rtwdev, cap); - + rtw89_phy_cfo_set_crystal_cap(rtwdev, cap, false); rtw89_debug(rtwdev, RTW89_DBG_CFO, - "X-cap approach to init-val (0x%x)\n", cfo->crystal_cap); + "(0x%x) approach to dflt_val=(0x%x)\n", cfo->crystal_cap, + cfo->def_x_cap); +} + +static void rtw89_dcfo_comp(struct rtw89_dev *rtwdev, s32 curr_cfo) +{ + bool is_linked = rtwdev->total_sta_assoc > 0; + s32 cfo_avg_312; + s32 dcfo_comp; + int sign; + + if (!is_linked) { + rtw89_debug(rtwdev, RTW89_DBG_CFO, "DCFO: is_linked=%d\n", + is_linked); + return; + } + rtw89_debug(rtwdev, RTW89_DBG_CFO, "DCFO: curr_cfo=%d\n", curr_cfo); + if (curr_cfo == 0) + return; + dcfo_comp = rtw89_phy_read32_mask(rtwdev, R_DCFO, B_DCFO); + sign = curr_cfo > 0 ? 1 : -1; + cfo_avg_312 = (curr_cfo << 3) / 5 + sign * dcfo_comp; + rtw89_debug(rtwdev, RTW89_DBG_CFO, "DCFO: avg_cfo=%d\n", cfo_avg_312); + if (rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv == CHIP_CBV) + cfo_avg_312 = -cfo_avg_312; + rtw89_phy_set_phy_regs(rtwdev, R_DCFO_COMP_S0, B_DCFO_COMP_S0_MSK, + cfo_avg_312); +} + +static void rtw89_dcfo_comp_init(struct rtw89_dev *rtwdev) +{ + rtw89_phy_set_phy_regs(rtwdev, R_DCFO_OPT, B_DCFO_OPT_EN, 1); + rtw89_phy_set_phy_regs(rtwdev, R_DCFO_WEIGHT, B_DCFO_WEIGHT_MSK, 8); + rtw89_write32_clr(rtwdev, R_AX_PWR_UL_CTRL2, B_AX_PWR_UL_CFO_MSK); } static void rtw89_phy_cfo_init(struct rtw89_dev *rtwdev) @@ -1317,180 +1435,188 @@ static void rtw89_phy_cfo_init(struct rtw89_dev *rtwdev) struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; struct rtw89_efuse *efuse = &rtwdev->efuse; - cfo->crystal_cap_default = efuse->xtal_cap; - cfo->crystal_cap = cfo->crystal_cap_default & B_AX_XTAL_SC_MSK; + cfo->crystal_cap_default = efuse->xtal_cap & B_AX_XTAL_SC_MSK; + cfo->crystal_cap = cfo->crystal_cap_default; cfo->def_x_cap = cfo->crystal_cap; - cfo->is_adjust = true; + cfo->is_adjust = false; + cfo->x_cap_ofst = 0; + cfo->rtw89_multi_cfo_mode = RTW89_TP_BASED_AVG_MODE; cfo->apply_compensation = false; cfo->residual_cfo_acc = 0; - rtw89_debug(rtwdev, RTW89_DBG_CFO, "Default xcap=%0x\n", cfo->crystal_cap_default); + rtw89_phy_cfo_set_crystal_cap(rtwdev, cfo->crystal_cap_default, true); + rtw89_phy_set_phy_regs(rtwdev, R_DCFO, B_DCFO, 1); + rtw89_dcfo_comp_init(rtwdev); + cfo->cfo_timer_ms = 2000; + cfo->cfo_trig_by_timer_en = false; + cfo->phy_cfo_trk_cnt = 0; + cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_NORMAL; } -static void rtw89_phy_digital_cfo_compensation(struct rtw89_dev *rtwdev) -{ - struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; - s16 cfo_avg_312p5khz; - - rtw89_debug(rtwdev, RTW89_DBG_CFO, "Digital cfo compensation\n"); - rtw89_debug(rtwdev, RTW89_DBG_CFO, "Residual cfo: ((%dK))\n", - cfo->cfo_avg_pre >> 2); - - cfo->residual_cfo_acc = cfo->residual_cfo_acc + cfo->cfo_avg_pre; - cfo_avg_312p5khz = -1 * (s16)(cfo->residual_cfo_acc << 10) / 625; - - rtw89_debug(rtwdev, RTW89_DBG_CFO, - "r_cfo_comp_312p5khz=0x%x\n", - (s16)(cfo_avg_312p5khz & B_CFO_COMP_VAL_MSK)); - - cfo_avg_312p5khz &= B_CFO_COMP_VAL_MSK; - rtw89_phy_write32_mask(rtwdev, R_CFO_COMP_SEG0_L, B_CFO_COMP_VAL_MSK, - cfo_avg_312p5khz); - rtw89_phy_write32_mask(rtwdev, R_CFO_COMP_SEG1_L, B_CFO_COMP_VAL_MSK, - cfo_avg_312p5khz); - rtw89_phy_write32_mask(rtwdev, R_CFO_COMP_SEG0_H, - B_CFO_COMP_WEIGHT_MSK, CFO_COMP_WEIGHT); - rtw89_phy_write32_mask(rtwdev, R_CFO_COMP_SEG1_H, - B_CFO_COMP_WEIGHT_MSK, CFO_COMP_WEIGHT); - rtw89_phy_write32_mask(rtwdev, R_CFO_COMP_SEG0_CTRL, - B_CFO_COMP_VALID_BIT, 1); - rtw89_phy_write32_mask(rtwdev, R_CFO_COMP_SEG1_CTRL, - B_CFO_COMP_VALID_BIT, 1); - rtw89_write32_clr(rtwdev, R_AX_PWR_UL_CTRL2, B_AX_PWR_UL_CTRL2_MSK); -} - -static void rtw89_phy_cfo_crystal_cap_adjust(struct rtw89_dev *rtwdev) +static void rtw89_phy_cfo_crystal_cap_adjust(struct rtw89_dev *rtwdev, + s32 curr_cfo) { struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; s8 crystal_cap = cfo->crystal_cap; - int cfo_previous, sign; + s32 cfo_abs = abs(curr_cfo); + int sign; - cfo_previous = abs(cfo->cfo_avg_pre); if (!cfo->is_adjust) { - if (cfo_previous > CFO_TRK_ENABLE_TH) + if (cfo_abs > CFO_TRK_ENABLE_TH) cfo->is_adjust = true; - } - - sign = cfo->cfo_avg_pre > 0 ? 1 : -1; - if (cfo->is_adjust) { - cfo_previous = abs(cfo->cfo_avg_pre); - if (cfo_previous > CFO_TRK_STOP_TH_4) - crystal_cap += 7 * sign; - else if (cfo_previous > CFO_TRK_STOP_TH_3) - crystal_cap += 5 * sign; - else if (cfo_previous > CFO_TRK_STOP_TH_2) - crystal_cap += 3 * sign; - else if (cfo_previous > CFO_TRK_STOP_TH) - crystal_cap += 1 * sign; - else if (cfo_previous <= CFO_TRK_STOP_TH) + } else { + if (cfo_abs < CFO_TRK_STOP_TH) cfo->is_adjust = false; + } + if (!cfo->is_adjust) { + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Stop CFO tracking\n"); + return; + } + sign = curr_cfo > 0 ? 1 : -1; + if (cfo_abs > CFO_TRK_STOP_TH_4) + crystal_cap += 7 * sign; + else if (cfo_abs > CFO_TRK_STOP_TH_3) + crystal_cap += 5 * sign; + else if (cfo_abs > CFO_TRK_STOP_TH_2) + crystal_cap += 3 * sign; + else if (cfo_abs > CFO_TRK_STOP_TH_1) + crystal_cap += 1 * sign; + else + return; + rtw89_phy_cfo_set_crystal_cap(rtwdev, (u8)crystal_cap, false); + rtw89_debug(rtwdev, RTW89_DBG_CFO, + "X_cap{Curr,Default}={0x%x,0x%x}\n", + cfo->crystal_cap, cfo->def_x_cap); +} - if (crystal_cap > B_AX_XTAL_SC_MSK) - crystal_cap = B_AX_XTAL_SC_MSK; - else if (crystal_cap < 0) - crystal_cap = 0; - rtw89_phy_cfo_set_crystal_cap(rtwdev, (u8)crystal_cap); - - rtw89_debug(rtwdev, RTW89_DBG_CFO, - "X_cap{Curr,Default}={0x%x,0x%x}\n", - cfo->crystal_cap, cfo->def_x_cap); +static s32 rtw89_phy_average_cfo_calc(struct rtw89_dev *rtwdev) +{ + struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; + s32 cfo_khz_all = 0; + s32 cfo_cnt_all = 0; + s32 cfo_all_avg = 0; + u8 i; - } else { - if (cfo->apply_compensation) - rtw89_phy_digital_cfo_compensation(rtwdev); + if (rtwdev->total_sta_assoc != 1) + return 0; + rtw89_debug(rtwdev, RTW89_DBG_CFO, "one_entry_only\n"); + for (i = 0; i < CFO_TRACK_MAX_USER; i++) { + if (cfo->cfo_cnt[i] == 0) + continue; + cfo_khz_all += cfo->cfo_tail[i]; + cfo_cnt_all += cfo->cfo_cnt[i]; + cfo_all_avg = phy_div(cfo_khz_all, cfo_cnt_all); + cfo->pre_cfo_avg[i] = cfo->cfo_avg[i]; } + rtw89_debug(rtwdev, RTW89_DBG_CFO, + "CFO track for macid = %d\n", i); + rtw89_debug(rtwdev, RTW89_DBG_CFO, + "Total cfo=%dK, pkt_cnt=%d, avg_cfo=%dK\n", + cfo_khz_all, cfo_cnt_all, cfo_all_avg); + return cfo_all_avg; } -static void rtw89_phy_average_cfo_calc(struct rtw89_dev *rtwdev) +static s32 rtw89_phy_multi_sta_cfo_calc(struct rtw89_dev *rtwdev) { struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; - s32 cfo_khz_avg[CFO_TRACK_MAX_USER] = {0}; - s32 cfo_max = 0, cfo_min = U16_MAX, cfo_khz_all = 0; - s32 cnt_max = 0, cnt_min = U16_MAX, cfo_cnt_all = 0; - s16 val; - u8 cnt_max_macid = 0, cnt_min_macid = 0; - u8 cfo_max_macid = 0, cfo_min_macid = 0, i; - - rtw89_debug(rtwdev, RTW89_DBG_CFO, "one_entry_only=%d\n", - rtwdev->total_sta_assoc == 1); + struct rtw89_traffic_stats *stats = &rtwdev->stats; + s32 target_cfo = 0; + s32 cfo_khz_all = 0; + s32 cfo_khz_all_tp_wgt = 0; + s32 cfo_avg = 0; + s32 max_cfo_lb = BIT(31); + s32 min_cfo_ub = GENMASK(30, 0); + u16 cfo_cnt_all = 0; + u8 active_entry_cnt = 0; + u8 sta_cnt = 0; + u32 tp_all = 0; + u64 active_entry = 0; + u8 i; + u8 cfo_tol = 0; - if (rtwdev->total_sta_assoc == 1) { + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Multi entry cfo_trk\n"); + if (cfo->rtw89_multi_cfo_mode == RTW89_PKT_BASED_AVG_MODE) { + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Pkt based avg mode\n"); for (i = 0; i < CFO_TRACK_MAX_USER; i++) { if (cfo->cfo_cnt[i] == 0) continue; cfo_khz_all += cfo->cfo_tail[i]; cfo_cnt_all += cfo->cfo_cnt[i]; - if (cfo_cnt_all == 0) - cfo->cfo_avg_pre = 0; - else - cfo->cfo_avg_pre = cfo_khz_all / cfo_cnt_all; - } - rtw89_debug(rtwdev, RTW89_DBG_CFO, - "CFO track for one entry only\n"); - rtw89_debug(rtwdev, RTW89_DBG_CFO, - "Total cfo=(%dK), pkt_cnt=(%d), avg_cfo=(%dK)\n", - cfo_khz_all >> 2, cfo_cnt_all, - cfo->cfo_avg_pre >> 2); - return; - } - - for (i = 0; i < CFO_TRACK_MAX_USER; i++) { - if (cfo->cfo_cnt[i] == 0) - continue; - - cfo_khz_all += cfo->cfo_tail[i]; - cfo_cnt_all += cfo->cfo_cnt[i]; - if (cfo->cfo_cnt[i] == 0) - cfo_khz_avg[i] = 0; - else - cfo_khz_avg[i] = cfo->cfo_tail[i] / cfo->cfo_cnt[i]; - - if (cfo->cfo_cnt[i] > cnt_max) { - cnt_max = cfo->cfo_cnt[i]; - cnt_max_macid = i; - } - if (cfo->cfo_cnt[i] < cnt_min) { - cnt_min = cfo->cfo_cnt[i]; - cnt_min_macid = i; + cfo_avg = phy_div(cfo_khz_all, (s32)cfo_cnt_all); + rtw89_debug(rtwdev, RTW89_DBG_CFO, + "Msta cfo=%d, pkt_cnt=%d, avg_cfo=%d\n", + cfo_khz_all, cfo_cnt_all, cfo_avg); + target_cfo = cfo_avg; } - if (cfo_khz_avg[i] > cfo_max) { - cfo_max = cfo_khz_avg[i]; - cfo_max_macid = i; + } else if (cfo->rtw89_multi_cfo_mode == RTW89_ENTRY_BASED_AVG_MODE) { + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Entry based avg mode\n"); + for (i = 0; i < CFO_TRACK_MAX_USER; i++) { + if (cfo->cfo_cnt[i] == 0) + continue; + active_entry |= BIT_ULL(i); + cfo->cfo_avg[i] = phy_div(cfo->cfo_tail[i], + (s32)cfo->cfo_cnt[i]); + cfo_khz_all += cfo->cfo_avg[i]; + rtw89_debug(rtwdev, RTW89_DBG_CFO, + "Macid=%d, cfo_avg=%d\n", i, + cfo->cfo_avg[i]); } - if (cfo_khz_avg[i] < cfo_min) { - cfo_min = cfo_khz_avg[i]; - cfo_min_macid = i; + sta_cnt = rtwdev->total_sta_assoc; + cfo_avg = phy_div(cfo_khz_all, (s32)sta_cnt); + rtw89_debug(rtwdev, RTW89_DBG_CFO, + "Msta cfo_acc=%d, ent_cnt=%d, avg_cfo=%d\n", + cfo_khz_all, sta_cnt, cfo_avg); + target_cfo = cfo_avg; + } else if (cfo->rtw89_multi_cfo_mode == RTW89_TP_BASED_AVG_MODE) { + rtw89_debug(rtwdev, RTW89_DBG_CFO, "TP based avg mode\n"); + cfo_tol = cfo->sta_cfo_tolerance; + for (i = 0; i < CFO_TRACK_MAX_USER; i++) { + sta_cnt++; + if (cfo->cfo_cnt[i] != 0) { + cfo->cfo_avg[i] = phy_div(cfo->cfo_tail[i], + (s32)cfo->cfo_cnt[i]); + active_entry_cnt++; + } else { + cfo->cfo_avg[i] = cfo->pre_cfo_avg[i]; + } + max_cfo_lb = max(cfo->cfo_avg[i] - cfo_tol, max_cfo_lb); + min_cfo_ub = min(cfo->cfo_avg[i] + cfo_tol, min_cfo_ub); + cfo_khz_all += cfo->cfo_avg[i]; + /* need tp for each entry */ + rtw89_debug(rtwdev, RTW89_DBG_CFO, + "[%d] cfo_avg=%d, tp=tbd\n", + i, cfo->cfo_avg[i]); + if (sta_cnt >= rtwdev->total_sta_assoc) + break; } - } + tp_all = stats->rx_throughput; /* need tp for each entry */ + cfo_avg = phy_div(cfo_khz_all_tp_wgt, (s32)tp_all); - rtw89_debug(rtwdev, RTW89_DBG_CFO, - "cnt macid = {%d, %d}, cfo macid = {%d, %d}\n", - cnt_min_macid, cnt_max_macid, cfo_min_macid, cfo_max_macid); - - /* Multi-sta CFO tracking strategy */ - val = (s16)abs(cfo_max - cfo_min); - if (val < MAX_CFO_TOLERANCE || val > (MAX_CFO_TOLERANCE << 1)) { - rtw89_debug(rtwdev, RTW89_DBG_CFO, - "CFO track for only pri-user\n"); - rtw89_debug(rtwdev, RTW89_DBG_CFO, - "Total cfo=(%dK), pkt_cnt=(%d), avg_cfo=(%dK)\n", - cfo->cfo_tail[cnt_max_macid] >> 2, - cfo->cfo_cnt[cnt_max_macid], - cfo_khz_avg[cnt_max_macid] >> 2); - cfo->cfo_avg_pre = cfo_khz_avg[cnt_max_macid]; - } else { + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Assoc sta cnt=%d\n", + sta_cnt); + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Active sta cnt=%d\n", + active_entry_cnt); rtw89_debug(rtwdev, RTW89_DBG_CFO, - "CFO track for average of all user\n"); - rtw89_debug(rtwdev, RTW89_DBG_CFO, - "Total cfo=(%dK), pkt_cnt=(%d), avg_cfo=(%dK)\n", - cfo_khz_all >> 2, cfo_cnt_all, - cfo->cfo_avg_pre >> 2); - if (cfo_cnt_all == 0) - cfo->cfo_avg_pre = 0; - else - cfo->cfo_avg_pre = cfo_khz_all / cfo_cnt_all; + "Msta cfo with tp_wgt=%d, avg_cfo=%d\n", + cfo_khz_all_tp_wgt, cfo_avg); + rtw89_debug(rtwdev, RTW89_DBG_CFO, "cfo_lb=%d,cfo_ub=%d\n", + max_cfo_lb, min_cfo_ub); + if (max_cfo_lb <= min_cfo_ub) { + rtw89_debug(rtwdev, RTW89_DBG_CFO, + "cfo win_size=%d\n", + min_cfo_ub - max_cfo_lb); + target_cfo = clamp(cfo_avg, max_cfo_lb, min_cfo_ub); + } else { + rtw89_debug(rtwdev, RTW89_DBG_CFO, + "No intersection of cfo torlence windows\n"); + target_cfo = phy_div(cfo_khz_all, (s32)sta_cnt); + } + for (i = 0; i < CFO_TRACK_MAX_USER; i++) + cfo->pre_cfo_avg[i] = cfo->cfo_avg[i]; } + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Target cfo=%d\n", target_cfo); + return target_cfo; } static void rtw89_phy_cfo_statistics_reset(struct rtw89_dev *rtwdev) @@ -1504,29 +1630,119 @@ static void rtw89_phy_cfo_statistics_reset(struct rtw89_dev *rtwdev) cfo->cfo_avg_pre = 0; } -void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev) +static void rtw89_phy_cfo_dm(struct rtw89_dev *rtwdev) { struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; + s32 new_cfo = 0; + bool x_cap_update = false; + u8 pre_x_cap = cfo->crystal_cap; - if (rtwdev->total_sta_assoc != 1) { + rtw89_debug(rtwdev, RTW89_DBG_CFO, "CFO:total_sta_assoc=%d\n", + rtwdev->total_sta_assoc); + if (rtwdev->total_sta_assoc == 0) { rtw89_phy_cfo_reset(rtwdev); - rtw89_debug(rtwdev, RTW89_DBG_CFO, "total_sta_assoc = %d\n", - rtwdev->total_sta_assoc); return; } - + if (cfo->packet_count == 0) { + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Pkt cnt = 0\n"); + return; + } if (cfo->packet_count == cfo->packet_count_pre) { - rtw89_debug(rtwdev, RTW89_DBG_CFO, - "Pkt cnt doesn't change\n"); + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Pkt cnt doesn't change\n"); return; } - - cfo->packet_count_pre = cfo->packet_count; - rtw89_phy_average_cfo_calc(rtwdev); - rtw89_phy_cfo_crystal_cap_adjust(rtwdev); + if (rtwdev->total_sta_assoc == 1) + new_cfo = rtw89_phy_average_cfo_calc(rtwdev); + else + new_cfo = rtw89_phy_multi_sta_cfo_calc(rtwdev); + if (new_cfo == 0) { + rtw89_debug(rtwdev, RTW89_DBG_CFO, "curr_cfo=0\n"); + return; + } + rtw89_phy_cfo_crystal_cap_adjust(rtwdev, new_cfo); + cfo->cfo_avg_pre = new_cfo; + x_cap_update = cfo->crystal_cap == pre_x_cap ? false : true; + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Xcap_up=%d\n", x_cap_update); + rtw89_debug(rtwdev, RTW89_DBG_CFO, "Xcap: D:%x C:%x->%x, ofst=%d\n", + cfo->def_x_cap, pre_x_cap, cfo->crystal_cap, + cfo->x_cap_ofst); + if (x_cap_update) { + if (new_cfo > 0) + new_cfo -= CFO_SW_COMP_FINE_TUNE; + else + new_cfo += CFO_SW_COMP_FINE_TUNE; + } + rtw89_dcfo_comp(rtwdev, new_cfo); rtw89_phy_cfo_statistics_reset(rtwdev); } +void rtw89_phy_cfo_track_work(struct work_struct *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + cfo_track_work.work); + struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; + + mutex_lock(&rtwdev->mutex); + if (!cfo->cfo_trig_by_timer_en) + goto out; + rtw89_leave_ps_mode(rtwdev); + rtw89_phy_cfo_dm(rtwdev); + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->cfo_track_work, + msecs_to_jiffies(cfo->cfo_timer_ms)); +out: + mutex_unlock(&rtwdev->mutex); +} + +static void rtw89_phy_cfo_start_work(struct rtw89_dev *rtwdev) +{ + struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; + + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->cfo_track_work, + msecs_to_jiffies(cfo->cfo_timer_ms)); +} + +void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev) +{ + struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking; + struct rtw89_traffic_stats *stats = &rtwdev->stats; + + switch (cfo->phy_cfo_status) { + case RTW89_PHY_DCFO_STATE_NORMAL: + if (stats->tx_throughput >= CFO_TP_UPPER) { + cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_ENHANCE; + cfo->cfo_trig_by_timer_en = true; + cfo->cfo_timer_ms = CFO_COMP_PERIOD; + rtw89_phy_cfo_start_work(rtwdev); + } + break; + case RTW89_PHY_DCFO_STATE_ENHANCE: + if (cfo->phy_cfo_trk_cnt >= CFO_PERIOD_CNT) { + cfo->phy_cfo_trk_cnt = 0; + cfo->cfo_trig_by_timer_en = false; + } + if (cfo->cfo_trig_by_timer_en == 1) + cfo->phy_cfo_trk_cnt++; + if (stats->tx_throughput <= CFO_TP_LOWER) { + cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_NORMAL; + cfo->phy_cfo_trk_cnt = 0; + cfo->cfo_trig_by_timer_en = false; + } + break; + default: + cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_NORMAL; + cfo->phy_cfo_trk_cnt = 0; + break; + } + rtw89_debug(rtwdev, RTW89_DBG_CFO, + "[CFO]WatchDog tp=%d,state=%d,timer_en=%d,trk_cnt=%d,thermal=%ld\n", + stats->tx_throughput, cfo->phy_cfo_status, + cfo->cfo_trig_by_timer_en, cfo->phy_cfo_trk_cnt, + ewma_thermal_read(&rtwdev->phystat.avg_thermal[0])); + if (cfo->cfo_trig_by_timer_en) + return; + rtw89_phy_cfo_dm(rtwdev); +} + void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val, struct rtw89_rx_phy_ppdu *phy_ppdu) { diff --git a/phy.h b/phy.h index e8ec71ad..9ec48f6a 100644 --- a/phy.h +++ b/phy.h @@ -19,6 +19,7 @@ #define get_phy_cond_rfe(addr) FIELD_GET(GENMASK(23, 16), addr) #define get_phy_cond_pkg(addr) FIELD_GET(GENMASK(15, 8), addr) #define get_phy_cond_cv(addr) FIELD_GET(GENMASK(7, 0), addr) +#define phy_div(a, b) ({typeof(b) _b = (b); (_b) ? ((a) / (_b)) : 0; }) #define PHY_COND_BRANCH_IF 0x8 #define PHY_COND_BRANCH_ELIF 0x9 #define PHY_COND_BRANCH_ELSE 0xa @@ -43,11 +44,17 @@ #define RA_MASK_HE_3SS_RATES GENMASK_ULL(47, 36) #define RA_MASK_HE_4SS_RATES GENMASK_ULL(59, 48) -#define CFO_TRK_ENABLE_TH 4 -#define CFO_TRK_STOP_TH_4 120 -#define CFO_TRK_STOP_TH_3 80 -#define CFO_TRK_STOP_TH_2 40 -#define CFO_TRK_STOP_TH 4 +#define CFO_TRK_ENABLE_TH (5 << 2) +#define CFO_TRK_STOP_TH_4 (30 << 2) +#define CFO_TRK_STOP_TH_3 (20 << 2) +#define CFO_TRK_STOP_TH_2 (10 << 2) +#define CFO_TRK_STOP_TH_1 (00 << 2) +#define CFO_TRK_STOP_TH (5 << 2) +#define CFO_SW_COMP_FINE_TUNE (2 << 2) +#define CFO_PERIOD_CNT 15 +#define CFO_TP_UPPER 100 +#define CFO_TP_LOWER 50 +#define CFO_COMP_PERIOD 250 #define CFO_COMP_WEIGHT 8 #define MAX_CFO_TOLERANCE 30 @@ -280,9 +287,11 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 bw, u8 ntx, u8 rs, u8 bf, u8 ch); void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta); void rtw89_phy_ra_update(struct rtw89_dev *rtwdev); +void rtw89_phy_ra_updata_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta); void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len, u8 class, u8 func); void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev); +void rtw89_phy_cfo_track_work(struct work_struct *work); void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val, struct rtw89_rx_phy_ppdu *phy_ppdu); void rtw89_phy_stat_track(struct rtw89_dev *rtwdev); @@ -292,4 +301,5 @@ void rtw89_phy_set_phy_regs(struct rtw89_dev *rtwdev, u32 addr, u32 mask, void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev); void rtw89_phy_dig(struct rtw89_dev *rtwdev); void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); + #endif diff --git a/ps.c b/ps.c index 5c1777cc..45585093 100644 --- a/ps.c +++ b/ps.c @@ -9,6 +9,7 @@ #include "mac.h" #include "ps.h" #include "reg.h" +#include "util.h" static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid) { @@ -50,25 +51,25 @@ static void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id) { - struct rtw89_lps_parm *lps_param = &rtwdev->lps_parm; - - lps_param->macid = mac_id; - lps_param->psmode = RTW89_MAC_AX_PS_MODE_LEGACY; - lps_param->lastrpwm = RTW89_LAST_RPWM_PS; + struct rtw89_lps_parm lps_param = { + .macid = mac_id, + .psmode = RTW89_MAC_AX_PS_MODE_LEGACY, + .lastrpwm = RTW89_LAST_RPWM_PS, + }; rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL); - rtw89_fw_h2c_lps_parm(rtwdev, mac_id); + rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); } static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, u8 mac_id) { - struct rtw89_lps_parm *lps_param = &rtwdev->lps_parm; - - lps_param->macid = mac_id; - lps_param->psmode = RTW89_MAC_AX_PS_MODE_ACTIVE; - lps_param->lastrpwm = RTW89_LAST_RPWM_ACTIVE; + struct rtw89_lps_parm lps_param = { + .macid = mac_id, + .psmode = RTW89_MAC_AX_PS_MODE_ACTIVE, + .lastrpwm = RTW89_LAST_RPWM_ACTIVE, + }; - rtw89_fw_h2c_lps_parm(rtwdev, mac_id); + rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); rtw89_fw_leave_lps_check(rtwdev, 0); rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); } @@ -92,7 +93,7 @@ void rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id) rtw89_hci_link_ps(rtwdev, true); } -static void rtw_leave_lps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +static void rtw89_leave_lps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = data; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; @@ -104,7 +105,7 @@ static void rtw_leave_lps_iter(void *data, u8 *mac, struct ieee80211_vif *vif) __rtw89_leave_lps(rtwdev, rtwvif->mac_id); } -void rtw89_leave_lps(struct rtw89_dev *rtwdev) +void rtw89_leave_lps(struct rtw89_dev *rtwdev, bool held_vifmtx) { lockdep_assert_held(&rtwdev->mutex); @@ -112,14 +113,14 @@ void rtw89_leave_lps(struct rtw89_dev *rtwdev) return; rtw89_hci_link_ps(rtwdev, false); - rtw89_iterate_vifs_atomic(rtwdev, rtw_leave_lps_iter, rtwdev); + rtw89_iterate_vifs(rtwdev, rtw89_leave_lps_iter, rtwdev, held_vifmtx); } void rtw89_enter_ips(struct rtw89_dev *rtwdev) { set_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); - rtw89_iterate_vifs_atomic(rtwdev, rtw_remove_vif_cfg_iter, rtwdev); + rtw89_iterate_vifs(rtwdev, rtw89_remove_vif_cfg_iter, rtwdev, false); rtw89_core_stop(rtwdev); rtw89_hci_link_ps(rtwdev, true); @@ -136,7 +137,7 @@ void rtw89_leave_ips(struct rtw89_dev *rtwdev) rtw89_set_channel(rtwdev); - rtw89_iterate_vifs_atomic(rtwdev, rtw_restore_vif_cfg_iter, rtwdev); + rtw89_iterate_vifs(rtwdev, rtw89_restore_vif_cfg_iter, rtwdev, false); clear_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); } @@ -144,5 +145,5 @@ void rtw89_leave_ips(struct rtw89_dev *rtwdev) void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl) { if (btc_ctrl) - rtw89_leave_lps(rtwdev); + rtw89_leave_lps(rtwdev, false); } diff --git a/ps.h b/ps.h index a057f7d8..d5e36316 100644 --- a/ps.h +++ b/ps.h @@ -6,7 +6,7 @@ #define __RTW89_PS_H_ void rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id); -void rtw89_leave_lps(struct rtw89_dev *rtwdev); +void rtw89_leave_lps(struct rtw89_dev *rtwdev, bool held_vifmtx); void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); void rtw89_enter_ips(struct rtw89_dev *rtwdev); void rtw89_leave_ips(struct rtw89_dev *rtwdev); diff --git a/reg.h b/reg.h index 6c63369b..51b59691 100644 --- a/reg.h +++ b/reg.h @@ -18,6 +18,10 @@ #define R_AX_SYS_CLK_CTRL 0x0008 #define B_AX_CPU_CLK_EN BIT(14) +#define R_AX_RSV_CTRL 0x001C +#define B_AX_R_DIS_PRST BIT(6) +#define B_AX_WLOCK_1C_B6 BIT(5) + #define R_AX_EFUSE_CTRL_1 0x0038 #define B_AX_EF_PGPD_MASK GENMASK(30, 28) #define B_AX_EF_RDT BIT(27) @@ -121,6 +125,11 @@ #define R_AX_LDM 0x01E8 #define B_AX_LDM_32K_EN BIT(31) +#define R_AX_UDM0 0x01F0 +#define R_AX_UDM1 0x01F4 +#define R_AX_UDM2 0x01F8 +#define R_AX_UDM3 0x01FC + #define R_AX_XTAL_ON_CTRL0 0x0280 #define B_AX_XTAL_SC_LPS BIT(31) #define B_AX_XTAL_SC_XO_MSK GENMASK(23, 17) @@ -137,16 +146,6 @@ #define R_AX_FILTER_MODEL_ADDR 0x0C04 -#define R_AX_PCIE_INIT_CFG2 0x1004 -#define B_AX_WD_ITVL_IDLE GENMASK(27, 24) -#define B_AX_WD_ITVL_ACT GENMASK(19, 16) - -#define R_AX_PCIE_PS_CTRL 0x1008 -#define B_AX_L1OFF_PWR_OFF_EN BIT(5) - -#define R_AX_MDIO_WDATA 0x10A4 -#define R_AX_MDIO_RDATA 0x10A6 - #define R_AX_PCIE_DBG_CTRL 0x11C0 #define B_AX_DBG_SEL GENMASK(23, 16) #define B_AX_LOOPBACK_DBG_SEL GENMASK(15, 13) @@ -155,16 +154,6 @@ #define B_AX_ASFF_FULL_NO_STK BIT(1) #define B_AX_EN_STUCK_DBG BIT(0) -#define R_AX_LBC_WATCHDOG 0x11D8 -#define B_AX_LBC_TIMER GENMASK(7, 4) -#define B_AX_LBC_FLAG BIT(1) -#define B_AX_LBC_EN BIT(0) - -#define R_AX_PCIE_EXP_CTRL 0x13F0 -#define B_AX_EN_CHKDSC_NO_RX_STUCK BIT(20) -#define B_AX_MAX_TAG_NUM GENMASK(18, 16) -#define B_AX_SIC_EN_FORCE_CLKREQ BIT(4) - #define R_AX_PHYREG_SET 0x8040 #define PHYREG_SET_ALL_CYCLE 0x8 @@ -259,6 +248,9 @@ #define R_AX_LTR_ACTIVE_LATENCY 0x841C +#define R_AX_SER_DBG_INFO 0x8424 +#define B_AX_L0_TO_L1_EVENT_MASK GENMASK(31, 28) + #define R_AX_DLE_EMPTY0 0x8430 #define B_AX_PLE_EMPTY_QTA_DMAC_CPUIO BIT(26) #define B_AX_PLE_EMPTY_QTA_DMAC_MPDU_TX BIT(25) @@ -282,6 +274,17 @@ #define B_AX_WDE_EMPTY_QUE_CMAC0_ALL_AC BIT(0) #define R_AX_DMAC_ERR_ISR 0x8524 +#define B_AX_DLE_CPUIO_ERR_FLAG BIT(10) +#define B_AX_APB_BRIDGE_ERR_FLAG BIT(9) +#define B_AX_DISPATCH_ERR_FLAG BIT(8) +#define B_AX_PKTIN_ERR_FLAG BIT(7) +#define B_AX_PLE_DLE_ERR_FLAG BIT(6) +#define B_AX_TXPKTCTRL_ERR_FLAG BIT(5) +#define B_AX_WDE_DLE_ERR_FLAG BIT(4) +#define B_AX_STA_SCHEDULER_ERR_FLAG BIT(3) +#define B_AX_MPDU_ERR_FLAG BIT(2) +#define B_AX_WSEC_ERR_FLAG BIT(1) +#define B_AX_WDRLS_ERR_FLAG BIT(0) #define R_AX_DISPATCHER_GLOBAL_SETTING_0 0x8800 #define B_AX_PL_PAGE_128B_SEL BIT(9) @@ -299,6 +302,8 @@ #define R_AX_CPU_DISPATCHER_ERR_IMR 0x8854 #define B_AX_CPU_SHIFT_EN_ERR_INT_EN BIT(25) +#define R_AX_OTHER_DISPATCHER_ERR_IMR 0x8858 + #define R_AX_HCI_FC_CTRL 0x8A00 #define B_AX_HCI_FC_CH12_FULL_COND_MASK GENMASK(11, 10) #define B_AX_HCI_FC_WP_CH811_FULL_COND_MASK GENMASK(9, 8) @@ -376,6 +381,8 @@ #define B_AX_WDE_START_BOUND_MASK GENMASK(13, 8) #define B_AX_WDE_PAGE_SEL_MASK 0x3 #define B_AX_WDE_FREE_PAGE_NUM_MASK GENMASK(28, 16) +#define R_AX_WDE_ERR_FLAG_CFG 0x8C34 +#define R_AX_WDE_ERR_IMR 0x8C38 #define R_AX_WDE_ERR_ISR 0x8C3C #define B_AX_WDE_MAX_SIZE_MASK GENMASK(27, 16) @@ -391,6 +398,7 @@ #define B_AX_DLE_FREE_TAILPG GENMASK(27, 16) #define B_AX_DLE_USE_PGNUM GENMASK(27, 16) #define B_AX_DLE_RSV_PGNUM GENMASK(11, 0) +#define B_AX_DLE_QEMPTY_GRP GENMASK(31, 0) #define R_AX_WDE_INI_STATUS 0x8D00 #define B_AX_WDE_Q_MGN_INI_RDY BIT(1) @@ -407,6 +415,7 @@ #define B_AX_PLE_START_BOUND_MASK GENMASK(13, 8) #define B_AX_PLE_PAGE_SEL_MASK 0x3 #define B_AX_PLE_FREE_PAGE_NUM_MASK GENMASK(28, 16) +#define R_AX_PLE_ERR_FLAG_CFG 0x9034 #define R_AX_PLE_ERR_IMR 0x9038 #define B_AX_PLE_GETNPG_STRPG_ERR_INT_EN BIT(5) @@ -421,6 +430,8 @@ #define R_AX_PLE_QTA4_CFG 0x9050 #define R_AX_PLE_QTA5_CFG 0x9054 #define R_AX_PLE_QTA6_CFG 0x9058 +#define B_AX_PLE_Q6_MAX_SIZE_MASK GENMASK(27, 16) +#define B_AX_PLE_Q6_MIN_SIZE_MASK GENMASK(11, 0) #define R_AX_PLE_QTA7_CFG 0x905C #define R_AX_PLE_QTA8_CFG 0x9060 #define R_AX_PLE_QTA9_CFG 0x9064 @@ -502,15 +513,18 @@ #define R_AX_PL_CPUQ_OP_STATUS 0x983C #define B_AX_CPUQ_OP_STAT_DONE BIT(31) #define B_AX_CPUQ_OP_PKTID_MASK GENMASK(11, 0) +#define R_AX_CPUIO_ERR_IMR 0x9840 #define R_AX_CPUIO_ERR_ISR 0x9844 #define R_AX_SEC_ERR_IMR_ISR 0x991C #define R_AX_PKTIN_SETTING 0x9A00 #define B_AX_WD_ADDR_INFO_LENGTH BIT(1) +#define R_AX_PKTIN_ERR_IMR 0x9A20 #define R_AX_PKTIN_ERR_ISR 0x9A24 #define R_AX_MPDU_TX_ERR_ISR 0x9BF0 +#define R_AX_MPDU_TX_ERR_IMR 0x9BF4 #define R_AX_MPDU_PROC 0x9C00 #define B_AX_A_ICV_ERR BIT(1) @@ -531,6 +545,7 @@ #define TRXCFG_MPDU_PROC_CUT_CTRL 0x010E05F0 #define R_AX_MPDU_RX_ERR_ISR 0x9CF0 +#define R_AX_MPDU_RX_ERR_IMR 0x9CF4 #define R_AX_SEC_ENG_CTRL 0x9D00 #define B_AX_TX_PARTIAL_MODE BIT(11) @@ -548,6 +563,15 @@ #define B_AX_APPEND_ICV BIT(1) #define B_AX_APPEND_MIC BIT(0) +#define R_AX_SEC_CAM_ACCESS 0x9D10 +#define R_AX_SEC_CAM_RDATA 0x9D14 +#define R_AX_SEC_CAM_WDATA 0x9D18 +#define R_AX_SEC_DEBUG 0x9D1C +#define R_AX_SEC_TX_DEBUG 0x9D20 +#define R_AX_SEC_RX_DEBUG 0x9D24 +#define R_AX_SEC_TRX_PKT_CNT 0x9D28 +#define R_AX_SEC_TRX_BLK_CNT 0x9D2C + #define R_AX_SS_CTRL 0x9E10 #define B_AX_SS_INIT_DONE_1 BIT(31) #define B_AX_SS_WARM_INIT_FLG BIT(29) @@ -569,6 +593,7 @@ #define B_AX_SS_MACID127_96_PAUSE_SH 0 #define B_AX_SS_MACID127_96_PAUSE_MSK 0xffffffffL +#define R_AX_STA_SCHEDULER_ERR_IMR 0x9EF0 #define R_AX_STA_SCHEDULER_ERR_ISR 0x9EF4 #define R_AX_TXPKTCTL_ERR_IMR_ISR 0x9F1C @@ -651,6 +676,13 @@ #define R_AX_CMAC_ERR_ISR 0xC164 #define R_AX_CMAC_ERR_ISR_C1 0xE164 +#define B_AX_WMAC_TX_ERR_IND BIT(7) +#define B_AX_WMAC_RX_ERR_IND BIT(6) +#define B_AX_TXPWR_CTRL_ERR_IND BIT(5) +#define B_AX_PHYINTF_ERR_IND BIT(4) +#define B_AX_DMA_TOP_ERR_IND BIT(3) +#define B_AX_PTCL_TOP_ERR_IND BIT(1) +#define B_AX_SCHEDULE_TOP_ERR_IND BIT(0) #define R_AX_MACID_SLEEP_0 0xC2C0 #define R_AX_MACID_SLEEP_0_C1 0xE2C0 @@ -719,6 +751,12 @@ #define R_AX_MUEDCA_VO_PARAM_0 0xC35C #define R_AX_MUEDCA_VO_PARAM_0_C1 0xE35C +#define R_AX_MUEDCA_EN 0xC370 +#define R_AX_MUEDCA_EN_C1 0xE370 +#define B_AX_MUEDCA_WMM_SEL BIT(8) +#define B_AX_SET_MUEDCATIMER_TF_0 BIT(4) +#define B_AX_MUEDCA_EN_0 BIT(0) + #define R_AX_CCA_CONTROL 0xC390 #define R_AX_CCA_CONTROL_C1 0xE390 #define B_AX_TB_CHK_TX_NAV BIT(31) @@ -1016,6 +1054,9 @@ #define R_AX_DLE_CTRL_C1 0xE800 #define B_AX_NO_RESERVE_PAGE_ERR_IMR BIT(23) #define B_AX_RXDATA_FSM_HANG_ERROR_IMR BIT(15) +#define R_AX_RXDMA_PKT_INFO_0 0xC814 +#define R_AX_RXDMA_PKT_INFO_1 0xC818 +#define R_AX_RXDMA_PKT_INFO_2 0xC81C #define R_AX_TCR1 0xCA04 #define R_AX_TCR1_C1 0xEA04 @@ -1082,11 +1123,24 @@ #define B_AX_WMAC_EN_TXACKBA_INTXOP BIT(16) #define B_AX_WMAC_SPEC_SIFS_OFDM_MASK GENMASK(15, 8) #define B_AX_WMAC_SPEC_SIFS_CCK_MASK GENMASK(7, 0) +#define WMAC_SPEC_SIFS_OFDM_52A 0x15 +#define WMAC_SPEC_SIFS_OFDM_52B 0x11 +#define WMAC_SPEC_SIFS_OFDM_52C 0x11 +#define WMAC_SPEC_SIFS_CCK 0xA #define R_AX_MAC_LOOPBACK 0xCC20 #define R_AX_MAC_LOOPBACK_C1 0xEC20 #define B_AX_MACLBK_EN BIT(0) +#define R_AX_RXTRIG_TEST_USER_2 0xCCB0 +#define R_AX_RXTRIG_TEST_USER_2_C1 0xECB0 +#define B_AX_RXTRIG_MACID_MASK GENMASK(31, 24) +#define B_AX_RXTRIG_RU26_DIS BIT(21) +#define B_AX_RXTRIG_FCSCHK_EN BIT(20) +#define B_AX_RXTRIG_PORT_SEL_MASK GENMASK(19, 17) +#define B_AX_RXTRIG_EN BIT(16) +#define B_AX_RXTRIG_USERINFO_2_MASK GENMASK(15, 0) + #define R_AX_WMAC_TX_TF_INFO_0 0xCCD0 #define R_AX_WMAC_TX_TF_INFO_0_C1 0xECD0 #define B_AX_WMAC_TX_TF_INFO_SEL GENMASK(2, 0) @@ -1133,7 +1187,7 @@ #define B_AX_BFMEE_BFRP_RX_STANDBY_TIMER_MASK GENMASK(23, 20) #define B_AX_MU_BFRPTSEG_SEL_MASK GENMASK(18, 17) #define B_AX_BFMEE_NDP_RXSTDBY_SEL BIT(16) -#define BFRP_RX_STANDBY_TIMER 0x8 +#define BFRP_RX_STANDBY_TIMER 0x0 #define NDP_RX_STANDBY_TIMER 0xFF #define B_AX_BFMEE_HE_NDPA_EN BIT(2) #define B_AX_BFMEE_VHT_NDPA_EN BIT(1) @@ -1218,6 +1272,11 @@ #define B_AX_A_BC BIT(2) #define B_AX_A_A1_MATCH BIT(1) #define B_AX_SNIFFER_MODE BIT(0) +#define DEFAULT_AX_RX_FLTR (B_AX_A_A1_MATCH | B_AX_A_BC | B_AX_A_MC | \ + B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH | \ + B_AX_A_MC_LIST_CAM_MATCH | \ + u32_encode_bits(3, B_AX_UID_FILTER_MASK) | \ + B_AX_A_BCN_CHK_EN) #define R_AX_CTRL_FLTR 0xCE24 #define R_AX_CTRL_FLTR_C1 0xEE24 @@ -1304,9 +1363,16 @@ #define B_AX_TXAGC_BT_EN BIT(1) #define B_AX_TXAGC_BT_MSK GENMASK(11, 3) +#define R_AX_PWR_UL_CTRL0 0xD240 #define R_AX_PWR_UL_CTRL2 0xD248 +#define B_AX_PWR_UL_CFO_MSK GENMASK(2, 0) #define B_AX_PWR_UL_CTRL2_MSK 0x07700007 - +#define R_AX_PWR_UL_TB_CTRL 0xD288 +#define B_AX_PWR_UL_TB_CTRL_EN BIT(31) +#define R_AX_PWR_UL_TB_1T 0xD28C +#define B_AX_PWR_UL_TB_1T_MSK GENMASK(4, 0) +#define R_AX_PWR_UL_TB_2T 0xD290 +#define B_AX_PWR_UL_TB_2T_MSK GENMASK(4, 0) #define R_AX_PWR_BY_RATE 0xD2C0 #define R_AX_PWR_BY_RATE_MAX 0xD2E8 #define R_AX_PWR_LMT 0xD2EC @@ -1314,12 +1380,17 @@ #define R_AX_PWR_RU_LMT 0xD33C #define R_AX_PWR_RU_LMT_MAX 0xD368 +#define R_AX_TXPWR_IMR 0xD9E0 +#define R_AX_TXPWR_IMR_C1 0xF9E0 #define R_AX_TXPWR_ISR 0xD9E4 #define R_AX_TXPWR_ISR_C1 0xF9E4 #define R_AX_BTC_CFG 0xDA00 #define B_AX_BTC_DIS_BTC_CLK_G BIT(2) +#define R_AX_BTC_WL_PRI_MSK 0xDA10 +#define B_AX_BTC_PTA_WL_PRI_MASK_BCNQ BIT(8) + #define R_AX_BTC_FUNC_EN 0xDA20 #define R_AX_BTC_FUNC_EN_C1 0xFA20 #define B_AX_PTA_EDCCA_EN BIT(1) @@ -1734,6 +1805,8 @@ #define R_S1_ADDCK 0x3E00 #define B_S1_ADDCK_I GENMASK(9, 0) #define B_S1_ADDCK_Q GENMASK(19, 10) +#define R_DCFO 0x4264 +#define B_DCFO GENMASK(1, 0) #define R_SEG0CSI 0x42AC #define B_SEG0CSI_IDX GENMASK(10, 0) #define R_SEG0CSI_EN 0x42C4 @@ -1745,6 +1818,12 @@ #define R_CFO_TRK0 0x4404 #define R_CFO_TRK1 0x440C #define B_CFO_TRK_MSK GENMASK(14, 10) +#define R_DCFO_COMP_S0 0x448C +#define B_DCFO_COMP_S0_MSK GENMASK(11, 0) +#define R_DCFO_WEIGHT 0x4490 +#define B_DCFO_WEIGHT_MSK GENMASK(27, 24) +#define R_DCFO_OPT 0x4494 +#define B_DCFO_OPT_EN BIT(29) #define R_BANDEDGE 0x4498 #define B_BANDEDGE_EN BIT(30) #define R_TXPATH_SEL 0x458C diff --git a/regd.c b/regd.c index 8c8152ae..f00b94ec 100644 --- a/regd.c +++ b/regd.c @@ -3,6 +3,7 @@ */ #include "debug.h" +#include "ps.h" #define COUNTRY_REGD(_alpha2, _txpwr_regd_2g, _txpwr_regd_5g) \ {.alpha2 = (_alpha2), \ @@ -331,6 +332,7 @@ void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request struct rtw89_dev *rtwdev = hw->priv; mutex_lock(&rtwdev->mutex); + rtw89_leave_ps_mode(rtwdev); if (wiphy->regd) { rtw89_debug(rtwdev, RTW89_DBG_REGD, diff --git a/regd.h b/regd.h new file mode 100644 index 00000000..5d457833 --- /dev/null +++ b/regd.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#ifndef __RTW_REGD_H_ +#define __RTW_REGD_H_ + +#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR +#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR +enum rtw_chplan_id { + RTW_CHPLAN_ETSI1_NULL = 0x21, + RTW_CHPLAN_WORLD_ETSI1 = 0x26, + RTW_CHPLAN_MKK1_MKK1 = 0x27, + RTW_CHPLAN_IC1_IC2 = 0x2B, + RTW_CHPLAN_WORLD_CHILE1 = 0x2D, + RTW_CHPLAN_WORLD_FCC3 = 0x30, + RTW_CHPLAN_WORLD_FCC5 = 0x32, + RTW_CHPLAN_FCC1_FCC7 = 0x34, + RTW_CHPLAN_WORLD_ETSI2 = 0x35, + RTW_CHPLAN_WORLD_ETSI3 = 0x36, + RTW_CHPLAN_ETSI1_ETSI12 = 0x3D, + RTW_CHPLAN_KCC1_KCC2 = 0x3E, + RTW_CHPLAN_ETSI1_ETSI4 = 0x42, + RTW_CHPLAN_FCC1_NCC3 = 0x44, + RTW_CHPLAN_WORLD_ACMA1 = 0x45, + RTW_CHPLAN_WORLD_ETSI6 = 0x47, + RTW_CHPLAN_WORLD_ETSI7 = 0x48, + RTW_CHPLAN_WORLD_ETSI8 = 0x49, + RTW_CHPLAN_KCC1_KCC3 = 0x4B, + RTW_CHPLAN_WORLD_ETSI10 = 0x51, + RTW_CHPLAN_WORLD_ETSI14 = 0x59, + RTW_CHPLAN_FCC2_FCC7 = 0x61, + RTW_CHPLAN_FCC2_FCC1 = 0x62, + RTW_CHPLAN_WORLD_ETSI15 = 0x63, + RTW_CHPLAN_WORLD_FCC7 = 0x73, + RTW_CHPLAN_FCC2_FCC17 = 0x74, + RTW_CHPLAN_WORLD_ETSI20 = 0x75, + RTW_CHPLAN_FCC2_FCC11 = 0x76, + RTW_CHPLAN_REALTEK_DEFINE = 0x7f, +}; + +struct country_code_to_enum_rd { + u16 countrycode; + const char *iso_name; +}; + +enum country_code_type { + COUNTRY_CODE_FCC = 0, + COUNTRY_CODE_IC = 1, + COUNTRY_CODE_ETSI = 2, + COUNTRY_CODE_SPAIN = 3, + COUNTRY_CODE_FRANCE = 4, + COUNTRY_CODE_MKK = 5, + COUNTRY_CODE_MKK1 = 6, + COUNTRY_CODE_ISRAEL = 7, + COUNTRY_CODE_TELEC = 8, + COUNTRY_CODE_MIC = 9, + COUNTRY_CODE_GLOBAL_DOMAIN = 10, + COUNTRY_CODE_WORLD_WIDE_13 = 11, + COUNTRY_CODE_TELEC_NETGEAR = 12, + COUNTRY_CODE_WORLD_WIDE_13_5G_ALL = 13, + + /* new channel plan above this */ + COUNTRY_CODE_MAX +}; + +int rtw_regd_init(struct rtw_dev *rtwdev, + void (*reg_notifier)(struct wiphy *wiphy, + struct regulatory_request *request)); +void rtw_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request); +#endif diff --git a/rtw8852a.c b/rtw8852a.c index d4a08292..7769e8b5 100644 --- a/rtw8852a.c +++ b/rtw8852a.c @@ -1313,6 +1313,31 @@ static u32 rtw8852a_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev, return (tssi_ofst_cw << 18) | (pwr_cw << 9) | (ref & GENMASK(8, 0)); } +static +void rtw8852a_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, + s16 pw_ofst, enum rtw89_mac_idx mac_idx) +{ + s32 val_1t = 0; + s32 val_2t = 0; + u32 reg; + + if (pw_ofst < -16 || pw_ofst > 15) { + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[ULTB] Err pwr_offset=%d\n", + pw_ofst); + return; + } + reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_CTRL, mac_idx); + rtw89_write32_set(rtwdev, reg, B_AX_PWR_UL_TB_CTRL_EN); + val_1t = (s32)pw_ofst; + reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_1T, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MSK, val_1t); + val_2t = max(val_1t - 3, -16); + reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_2T, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_MSK, val_2t); + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[ULTB] Set TB pwr_offset=(%d, %d)\n", + val_1t, val_2t); +} + static void rtw8852a_set_txpwr_ref(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -1499,6 +1524,10 @@ rtw8852a_init_txpwr_unit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) if (ret) return ret; + ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL0, 0x0002f8ff); + if (ret) + return ret; + return 0; } @@ -1749,6 +1778,7 @@ static void rtw8852a_btc_init_cfg(struct rtw89_dev *rtwdev) /* set WL Tx response = Hi-Pri */ chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_TX_RESP, true); + chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_BEACON, true); /* set rf gnt debug off */ rtw89_write_rf(rtwdev, RF_PATH_A, RR_WLSEL, 0xfffff, 0x0); @@ -1773,7 +1803,6 @@ static void rtw8852a_btc_init_cfg(struct rtw89_dev *rtwdev) /* enable BT counter 0xda40[16,2] = 2b'11 */ rtw89_write32_set(rtwdev, R_AX_CSR_MODE, B_AX_BT_CNT_REST | B_AX_STATIS_BT_EN); - rtw89_mac_cfg_ctrl_path(rtwdev, false); btc->cx.wl.status.map.init_ok = true; } @@ -1781,19 +1810,25 @@ static void rtw8852a_btc_set_wl_pri(struct rtw89_dev *rtwdev, u8 map, bool state) { u32 bitmap = 0; + u32 reg = 0; switch (map) { case BTC_PRI_MASK_TX_RESP: + reg = R_BTC_BT_COEX_MSK_TABLE; bitmap = B_BTC_PRI_MASK_TX_RESP_V1; break; + case BTC_PRI_MASK_BEACON: + reg = R_AX_BTC_WL_PRI_MSK; + bitmap = B_AX_BTC_PTA_WL_PRI_MASK_BCNQ; + break; default: return; } if (state) - rtw89_write32_set(rtwdev, R_BTC_BT_COEX_MSK_TABLE, bitmap); + rtw89_write32_set(rtwdev, reg, bitmap); else - rtw89_write32_clr(rtwdev, R_BTC_BT_COEX_MSK_TABLE, bitmap); + rtw89_write32_clr(rtwdev, reg, bitmap); } static inline u32 __btc_ctrl_val_all_time(u32 ctrl) @@ -1895,18 +1930,18 @@ static struct rtw89_btc_rf_trx_para rtw89_btc_8852a_rf_dl[] = { }; static struct rtw89_btc_fbtc_mreg rtw89_btc_8852a_mon_reg[] = { - {REG_MAC, 4, 0xda24}, - {REG_MAC, 4, 0xda28}, - {REG_MAC, 4, 0xda2c}, - {REG_MAC, 4, 0xda30}, - {REG_MAC, 4, 0xda4c}, - {REG_MAC, 4, 0xda10}, - {REG_MAC, 4, 0xda20}, - {REG_MAC, 4, 0xda34}, - {REG_MAC, 4, 0xcef4}, - {REG_MAC, 4, 0x8424}, - {REG_BB, 4, 0x980}, - {REG_BT_MODEM, 4, 0x178}, + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda24), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda28), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda2c), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda30), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda4c), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda10), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda20), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda34), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xcef4), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0x8424), + RTW89_DEF_FBTC_MREG(REG_BB, 4, 0x980), + RTW89_DEF_FBTC_MREG(REG_BT_MODEM, 4, 0x178), }; static @@ -1980,6 +2015,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .ctrl_btg = rtw8852a_ctrl_btg, .query_ppdu = rtw8852a_query_ppdu, .bb_ctrl_btc_preagc = rtw8852a_bb_ctrl_btc_preagc, + .set_txpwr_ul_tb_offset = rtw8852a_set_txpwr_ul_tb_offset, .btc_set_rfe = rtw8852a_btc_set_rfe, .btc_init_cfg = rtw8852a_btc_init_cfg, diff --git a/rtw8852a_rfk.c b/rtw8852a_rfk.c index 0ca851fb..23932784 100644 --- a/rtw8852a_rfk.c +++ b/rtw8852a_rfk.c @@ -1020,9 +1020,9 @@ static bool _iqk_nbrxk(struct rtw89_dev *rtwdev, u32 idxrxgain_a = 0x1a0; u32 idxattc2_a = 0x00; u32 idxattc1_a = 0x5; - u32 idxrxgain_g = 0x1CC; - u32 idxattc2_g = 0x0; - u32 idxattc1_g = 0x1; + u32 idxrxgain_g = 0x1E0; + u32 idxattc2_g = 0x15; + u32 idxattc1_g = 0x0; bool fail = false; switch (iqk_info->iqk_band[path]) { @@ -1407,7 +1407,7 @@ void _iqk_by_path(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) _iqk_rxclk_setting(rtwdev, path); _iqk_rxk_setting(rtwdev, path); - if (iqk_info->is_nbiqk || rtwdev->dbcc_en) + if (iqk_info->is_nbiqk || rtwdev->dbcc_en || iqk_info->iqk_band[path] == RTW89_BAND_2G) iqk_info->iqk_rx_fail[0][path] = _iqk_nbrxk(rtwdev, phy_idx, path); else iqk_info->iqk_rx_fail[0][path] = _rxk_group_sel(rtwdev, phy_idx, path); diff --git a/sar.c b/sar.c new file mode 100644 index 00000000..527e144f --- /dev/null +++ b/sar.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2019-2020 Realtek Corporation + */ + +#include "debug.h" +#include "sar.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) +static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev, s32 *cfg) +{ + struct rtw89_sar_cfg_common *rtwsar = &rtwdev->sar.cfg_common; + enum rtw89_subband subband = rtwdev->hal.current_subband; + + if (!rtwsar->set[subband]) + return -ENODATA; + + *cfg = rtwsar->cfg[subband]; + return 0; +} + +static const +struct rtw89_sar_handler rtw89_sar_handlers[RTW89_SAR_SOURCE_NR] = { + [RTW89_SAR_SOURCE_COMMON] = { + .descr_sar_source = "RTW89_SAR_SOURCE_COMMON", + .txpwr_factor_sar = 2, + .query_sar_config = rtw89_query_sar_config_common, + }, +}; + +#define rtw89_sar_set_src(_dev, _src, _cfg_name, _cfg_data) \ + do { \ + typeof(_src) _s = (_src); \ + typeof(_dev) _d = (_dev); \ + BUILD_BUG_ON(!rtw89_sar_handlers[_s].descr_sar_source); \ + BUILD_BUG_ON(!rtw89_sar_handlers[_s].query_sar_config); \ + lockdep_assert_held(&_d->mutex); \ + _d->sar._cfg_name = *(_cfg_data); \ + _d->sar.src = _s; \ + } while (0) + +static s8 rtw89_txpwr_sar_to_mac(struct rtw89_dev *rtwdev, u8 fct, s32 cfg) +{ + const u8 fct_mac = rtwdev->chip->txpwr_factor_mac; + s32 cfg_mac; + + cfg_mac = fct > fct_mac ? + cfg >> (fct - fct_mac) : cfg << (fct_mac - fct); + + return (s8)clamp_t(s32, cfg_mac, + RTW89_SAR_TXPWR_MAC_MIN, + RTW89_SAR_TXPWR_MAC_MAX); +} + +s8 rtw89_query_sar(struct rtw89_dev *rtwdev) +{ + const enum rtw89_sar_sources src = rtwdev->sar.src; + /* its members are protected by rtw89_sar_set_src() */ + const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src]; + int ret; + s32 cfg; + u8 fct; + + lockdep_assert_held(&rtwdev->mutex); + + if (src == RTW89_SAR_SOURCE_NONE) + return RTW89_SAR_TXPWR_MAC_MAX; + + ret = sar_hdl->query_sar_config(rtwdev, &cfg); + if (ret) + return RTW89_SAR_TXPWR_MAC_MAX; + + fct = sar_hdl->txpwr_factor_sar; + + return rtw89_txpwr_sar_to_mac(rtwdev, fct, cfg); +} + +void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev) +{ + const enum rtw89_sar_sources src = rtwdev->sar.src; + /* its members are protected by rtw89_sar_set_src() */ + const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src]; + const u8 fct_mac = rtwdev->chip->txpwr_factor_mac; + int ret; + s32 cfg; + u8 fct; + + lockdep_assert_held(&rtwdev->mutex); + + if (src == RTW89_SAR_SOURCE_NONE) { + seq_puts(m, "no SAR is applied\n"); + return; + } + + seq_printf(m, "source: %d (%s)\n", src, sar_hdl->descr_sar_source); + + ret = sar_hdl->query_sar_config(rtwdev, &cfg); + if (ret) { + seq_printf(m, "config: return code: %d\n", ret); + seq_printf(m, "assign: max setting: %d (unit: 1/%lu dBm)\n", + RTW89_SAR_TXPWR_MAC_MAX, BIT(fct_mac)); + return; + } + + fct = sar_hdl->txpwr_factor_sar; + + seq_printf(m, "config: %d (unit: 1/%lu dBm)\n", cfg, BIT(fct)); +} + +static int rtw89_apply_sar_common(struct rtw89_dev *rtwdev, + const struct rtw89_sar_cfg_common *sar) +{ + enum rtw89_sar_sources src; + int ret = 0; + + mutex_lock(&rtwdev->mutex); + + src = rtwdev->sar.src; + if (src != RTW89_SAR_SOURCE_NONE && src != RTW89_SAR_SOURCE_COMMON) { + rtw89_warn(rtwdev, "SAR source: %d is in use", src); + ret = -EBUSY; + goto exit; + } + + rtw89_sar_set_src(rtwdev, RTW89_SAR_SOURCE_COMMON, cfg_common, sar); + rtw89_chip_set_txpwr(rtwdev); + +exit: + mutex_unlock(&rtwdev->mutex); + return ret; +} + +static const u8 rtw89_common_sar_subband_map[] = { + RTW89_CH_2G, + RTW89_CH_5G_BAND_1, + RTW89_CH_5G_BAND_3, + RTW89_CH_5G_BAND_4, +}; + +static const struct cfg80211_sar_freq_ranges rtw89_common_sar_freq_ranges[] = { + { .start_freq = 2412, .end_freq = 2484, }, + { .start_freq = 5180, .end_freq = 5320, }, + { .start_freq = 5500, .end_freq = 5720, }, + { .start_freq = 5745, .end_freq = 5825, }, +}; + +static_assert(ARRAY_SIZE(rtw89_common_sar_subband_map) == + ARRAY_SIZE(rtw89_common_sar_freq_ranges)); + +const struct cfg80211_sar_capa rtw89_sar_capa = { + .type = NL80211_SAR_TYPE_POWER, + .num_freq_ranges = ARRAY_SIZE(rtw89_common_sar_freq_ranges), + .freq_ranges = rtw89_common_sar_freq_ranges, +}; + +int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar) +{ + struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_sar_cfg_common sar_common = {0}; + u8 fct; + u32 freq_start; + u32 freq_end; + u32 band; + s32 power; + u32 i, idx; + + if (sar->type != NL80211_SAR_TYPE_POWER) + return -EINVAL; + + fct = rtw89_sar_handlers[RTW89_SAR_SOURCE_COMMON].txpwr_factor_sar; + + for (i = 0; i < sar->num_sub_specs; i++) { + idx = sar->sub_specs[i].freq_range_index; + if (idx >= ARRAY_SIZE(rtw89_common_sar_freq_ranges)) + return -EINVAL; + + freq_start = rtw89_common_sar_freq_ranges[idx].start_freq; + freq_end = rtw89_common_sar_freq_ranges[idx].end_freq; + band = rtw89_common_sar_subband_map[idx]; + power = sar->sub_specs[i].power; + + rtw89_info(rtwdev, "On freq %u to %u, ", freq_start, freq_end); + rtw89_info(rtwdev, "set SAR power limit %d (unit: 1/%lu dBm)\n", + power, BIT(fct)); + + sar_common.set[band] = true; + sar_common.cfg[band] = power; + } + + return rtw89_apply_sar_common(rtwdev, &sar_common); +} +#endif diff --git a/sar.h b/sar.h new file mode 100644 index 00000000..37fe7112 --- /dev/null +++ b/sar.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2019-2020 Realtek Corporation + */ + +#ifndef __RTW89_SAR_H__ +#define __RTW89_SAR_H__ + +#include "core.h" +#include + +#define RTW89_SAR_TXPWR_MAC_MAX S8_MAX +#define RTW89_SAR_TXPWR_MAC_MIN S8_MIN + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) +struct rtw89_sar_handler { + const char *descr_sar_source; + u8 txpwr_factor_sar; + int (*query_sar_config)(struct rtw89_dev *rtwdev, s32 *cfg); +}; + +extern const struct cfg80211_sar_capa rtw89_sar_capa; + +s8 rtw89_query_sar(struct rtw89_dev *rtwdev); +void rtw89_print_sar(struct seq_file *m, struct rtw89_dev *rtwdev); +int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar); +#endif + +#endif diff --git a/ser.c b/ser.c index 58a55751..887edd6d 100644 --- a/ser.c +++ b/ser.c @@ -2,9 +2,14 @@ /* Copyright(c) 2019-2020 Realtek Corporation */ +#include "cam.h" +#include "debug.h" #include "mac.h" -#include "pci.h" +#include "ps.h" #include "ser.h" +#include "util.h" + +#define SER_RECFG_TIMEOUT 1000 enum ser_evt { SER_EV_NONE, @@ -14,6 +19,8 @@ enum ser_evt { SER_EV_DO_RECOVERY, /* M3 */ SER_EV_MAC_RESET_DONE, /* M5 */ SER_EV_L2_RESET, + SER_EV_L2_RECFG_DONE, + SER_EV_L2_RECFG_TIMEOUT, SER_EV_M3_TIMEOUT, SER_EV_FW_M5_TIMEOUT, SER_EV_L0_RESET, @@ -66,6 +73,8 @@ static void ser_state_run(struct rtw89_ser *ser, u8 evt) rtw89_debug(rtwdev, RTW89_DBG_SER, "ser: %s receive %s\n", ser_st_name(ser), ser_ev_name(ser, evt)); + + rtw89_leave_lps(rtwdev, false); ser->st_tbl[ser->state].st_func(ser, evt); } @@ -204,6 +213,23 @@ static void drv_resume_rx(struct rtw89_ser *ser) clear_bit(RTW89_SER_DRV_STOP_RX, ser->flags); } +static void ser_reset_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct rtw89_dev *rtwdev = (struct rtw89_dev *)data; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + + rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); + rtwvif->net_type = RTW89_NET_TYPE_NO_LINK; + rtwvif->trigger = false; +} + +static void ser_reset_mac_binding(struct rtw89_dev *rtwdev) +{ + rtw89_cam_reset_keys(rtwdev); + rtw89_core_release_all_bits_map(rtwdev->mac_id_map, RTW89_MAX_MAC_ID_NUM); + rtw89_iterate_vifs(rtwdev, ser_reset_vif_iter, rtwdev, false); +} + /* hal function */ static int hal_enable_dma(struct rtw89_ser *ser) { @@ -216,8 +242,7 @@ static int hal_enable_dma(struct rtw89_ser *ser) if (!rtwdev->hci.ops->mac_lv1_rcvy) return -EIO; - ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, - MAC_AX_LV1_RCVY_STEP_2); + ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_2); if (!ret) clear_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); @@ -232,8 +257,7 @@ static int hal_stop_dma(struct rtw89_ser *ser) if (!rtwdev->hci.ops->mac_lv1_rcvy) return -EIO; - ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, - MAC_AX_LV1_RCVY_STEP_1); + ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_1); if (!ret) set_bit(RTW89_SER_HAL_STOP_DMA, ser->flags); @@ -325,6 +349,9 @@ static void ser_do_hci_st_hdl(struct rtw89_ser *ser, u8 evt) break; case SER_EV_FW_M5_TIMEOUT: + ser_state_goto(ser, SER_L2_RESET_ST); + break; + case SER_EV_MAC_RESET_DONE: ser_state_goto(ser, SER_IDLE_ST); break; @@ -340,12 +367,30 @@ static void ser_do_hci_st_hdl(struct rtw89_ser *ser, u8 evt) static void ser_l2_reset_st_hdl(struct rtw89_ser *ser, u8 evt) { + struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); + switch (evt) { case SER_EV_STATE_IN: + mutex_lock(&rtwdev->mutex); + ser_reset_mac_binding(rtwdev); + rtw89_core_stop(rtwdev); + mutex_unlock(&rtwdev->mutex); + + ieee80211_restart_hw(rtwdev->hw); + ser_set_alarm(ser, SER_RECFG_TIMEOUT, SER_EV_L2_RECFG_TIMEOUT); + break; + + case SER_EV_L2_RECFG_TIMEOUT: + rtw89_info(rtwdev, "Err: ser L2 re-config timeout\n"); + fallthrough; + case SER_EV_L2_RECFG_DONE: ser_state_goto(ser, SER_IDLE_ST); break; case SER_EV_STATE_OUT: + ser_del_alarm(ser); + break; + default: break; } @@ -359,6 +404,8 @@ static struct event_ent ser_ev_tbl[] = { {SER_EV_DO_RECOVERY, "SER_EV_DO_RECOVERY m3"}, {SER_EV_MAC_RESET_DONE, "SER_EV_MAC_RESET_DONE m5"}, {SER_EV_L2_RESET, "SER_EV_L2_RESET"}, + {SER_EV_L2_RECFG_DONE, "SER_EV_L2_RECFG_DONE"}, + {SER_EV_L2_RECFG_TIMEOUT, "SER_EV_L2_RECFG_TIMEOUT"}, {SER_EV_M3_TIMEOUT, "SER_EV_M3_TIMEOUT"}, {SER_EV_FW_M5_TIMEOUT, "SER_EV_FW_M5_TIMEOUT"}, {SER_EV_L0_RESET, "SER_EV_L0_RESET"}, @@ -400,6 +447,11 @@ int rtw89_ser_deinit(struct rtw89_dev *rtwdev) return 0; } +void rtw89_ser_recfg_done(struct rtw89_dev *rtwdev) +{ + ser_send_msg(&rtwdev->ser, SER_EV_L2_RECFG_DONE); +} + int rtw89_ser_notify(struct rtw89_dev *rtwdev, u32 err) { u8 event = SER_EV_NONE; @@ -423,6 +475,10 @@ int rtw89_ser_notify(struct rtw89_dev *rtwdev, u32 err) event = SER_EV_L0_RESET; break; default: + if (err == MAC_AX_ERR_L1_PROMOTE_TO_L2 || + (err >= MAC_AX_ERR_L2_ERR_AH_DMA && + err <= MAC_AX_GET_ERR_MAX)) + event = SER_EV_L2_RESET; break; } diff --git a/ser.h b/ser.h index fa501a36..6b8e6201 100644 --- a/ser.h +++ b/ser.h @@ -9,6 +9,7 @@ int rtw89_ser_init(struct rtw89_dev *rtwdev); int rtw89_ser_deinit(struct rtw89_dev *rtwdev); int rtw89_ser_notify(struct rtw89_dev *rtwdev, u32 err); +void rtw89_ser_recfg_done(struct rtw89_dev *rtwdev); #endif /* __SER_H__*/ diff --git a/txrx.h b/txrx.h index 51663928..0dc99cbc 100644 --- a/txrx.h +++ b/txrx.h @@ -55,6 +55,8 @@ RTW89_SET_TXWD(txdesc, val, 0x02, GENMASK(13, 0)) /* TX WD BODY DWORD 3 */ +#define RTW89_SET_TXWD_BODY_BK(txdesc, val) \ + RTW89_SET_TXWD(txdesc, val, 0x03, BIT(13)) #define RTW89_SET_TXWD_BODY_AGG_EN(txdesc, val) \ RTW89_SET_TXWD(txdesc, val, 0x03, BIT(12)) #define RTW89_SET_TXWD_BODY_SW_SEQ(txdesc, val) \ @@ -77,6 +79,8 @@ RTW89_SET_TXWD(txdesc, val, 0x6, BIT(10)) /* TX WD INFO DWORD 1 */ +#define RTW89_SET_TXWD_INFO_A_CTRL_BSR(txdesc, val) \ + RTW89_SET_TXWD(txdesc, val, 0x7, BIT(14)) #define RTW89_SET_TXWD_INFO_MAX_AGGNUM(txdesc, val) \ RTW89_SET_TXWD(txdesc, val, 0x7, GENMASK(7, 0)) diff --git a/util.c b/util.c new file mode 100644 index 00000000..a0650bb8 --- /dev/null +++ b/util.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2019-2020 Realtek Corporation + */ + +#include "util.h" + +static void +__rtw89_vifs_collect_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct list_head *vif_list = (struct list_head *)data; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + + list_add_tail(&rtwvif->list, vif_list); +} + +void __rtw89_iterate_vifs(struct rtw89_dev *rtwdev, + void (*iterator)(void *data, u8 *mac, + struct ieee80211_vif *vif), + void *data) +{ + struct ieee80211_vif *vif; + struct rtw89_vif *rtwvif; + LIST_HEAD(vif_list); + + /* iflist_mtx & mutex are held */ + lockdep_assert_held(&rtwdev->mutex); + + /* Since iflist_mtx is held, we can use vif outside of iterator */ + ieee80211_iterate_active_interfaces_atomic(rtwdev->hw, + IEEE80211_IFACE_ITER_NORMAL, __rtw89_vifs_collect_iter, + &vif_list); + + list_for_each_entry(rtwvif, &vif_list, list) { + vif = rtwvif_to_vif(rtwvif); + iterator(data, vif->addr, vif); + } +} diff --git a/util.h b/util.h new file mode 100644 index 00000000..935ceecd --- /dev/null +++ b/util.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + * Copyright(c) 2019-2020 Realtek Corporation + */ +#ifndef __RTW89_UTIL_H__ +#define __RTW89_UTIL_H__ + +#include "core.h" + +#define rtw89_iterate_vifs_bh(rtwdev, iterator, data) \ + ieee80211_iterate_active_interfaces_atomic((rtwdev)->hw, \ + IEEE80211_IFACE_ITER_NORMAL, iterator, data) +void __rtw89_iterate_vifs(struct rtw89_dev *rtwdev, + void (*iterator)(void *data, u8 *mac, + struct ieee80211_vif *vif), + void *data); +static inline +void rtw89_iterate_vifs(struct rtw89_dev *rtwdev, + void (*iterator)(void *data, u8 *mac, + struct ieee80211_vif *vif), + void *data, bool held_vifmtx) +{ + if (!held_vifmtx) { + ieee80211_iterate_active_interfaces((rtwdev)->hw, + IEEE80211_IFACE_ITER_NORMAL, iterator, data); + return; + } + + __rtw89_iterate_vifs(rtwdev, iterator, data); +} + +#endif