rtw88: update Realtek's rtw88 driver.

This version is based on
https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-testing.git
2a220a15be657a24868368892e3e2caba2115283 (tag: wt-2023-08-06)
and was committed to FreeBSD main as
90aac0d83b.
This commit is contained in:
Bjoern A. Zeeb 2024-06-10 10:35:57 +00:00
parent 2ed35f15d8
commit 1f3bff0d30
58 changed files with 5340 additions and 742 deletions

78
Makefile Normal file
View file

@ -0,0 +1,78 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
obj-$(CONFIG_RTW88_CORE) += rtw88_core.o
rtw88_core-y += main.o \
mac80211.o \
util.o \
debug.o \
tx.o \
rx.o \
mac.o \
phy.o \
coex.o \
efuse.o \
fw.o \
ps.o \
sec.o \
bf.o \
sar.o \
regd.o
rtw88_core-$(CONFIG_PM) += wow.o
obj-$(CONFIG_RTW88_8822B) += rtw88_8822b.o
rtw88_8822b-objs := rtw8822b.o rtw8822b_table.o
obj-$(CONFIG_RTW88_8822BE) += rtw88_8822be.o
rtw88_8822be-objs := rtw8822be.o
obj-$(CONFIG_RTW88_8822BS) += rtw88_8822bs.o
rtw88_8822bs-objs := rtw8822bs.o
obj-$(CONFIG_RTW88_8822BU) += rtw88_8822bu.o
rtw88_8822bu-objs := rtw8822bu.o
obj-$(CONFIG_RTW88_8822C) += rtw88_8822c.o
rtw88_8822c-objs := rtw8822c.o rtw8822c_table.o
obj-$(CONFIG_RTW88_8822CE) += rtw88_8822ce.o
rtw88_8822ce-objs := rtw8822ce.o
obj-$(CONFIG_RTW88_8822CS) += rtw88_8822cs.o
rtw88_8822cs-objs := rtw8822cs.o
obj-$(CONFIG_RTW88_8822CU) += rtw88_8822cu.o
rtw88_8822cu-objs := rtw8822cu.o
obj-$(CONFIG_RTW88_8723D) += rtw88_8723d.o
rtw88_8723d-objs := rtw8723d.o rtw8723d_table.o
obj-$(CONFIG_RTW88_8723DE) += rtw88_8723de.o
rtw88_8723de-objs := rtw8723de.o
obj-$(CONFIG_RTW88_8723DS) += rtw88_8723ds.o
rtw88_8723ds-objs := rtw8723ds.o
obj-$(CONFIG_RTW88_8723DU) += rtw88_8723du.o
rtw88_8723du-objs := rtw8723du.o
obj-$(CONFIG_RTW88_8821C) += rtw88_8821c.o
rtw88_8821c-objs := rtw8821c.o rtw8821c_table.o
obj-$(CONFIG_RTW88_8821CE) += rtw88_8821ce.o
rtw88_8821ce-objs := rtw8821ce.o
obj-$(CONFIG_RTW88_8821CS) += rtw88_8821cs.o
rtw88_8821cs-objs := rtw8821cs.o
obj-$(CONFIG_RTW88_8821CU) += rtw88_8821cu.o
rtw88_8821cu-objs := rtw8821cu.o
obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o
rtw88_pci-objs := pci.o
obj-$(CONFIG_RTW88_SDIO) += rtw88_sdio.o
rtw88_sdio-objs := sdio.o
obj-$(CONFIG_RTW88_USB) += rtw88_usb.o
rtw88_usb-objs := usb.o

19
bf.c
View file

@ -30,11 +30,11 @@ void rtw_bf_disassoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf) struct ieee80211_bss_conf *bss_conf)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct ieee80211_hw *hw = rtwdev->hw; struct ieee80211_hw *hw = rtwdev->hw;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
struct rtw_bfee *bfee = &rtwvif->bfee; struct rtw_bfee *bfee = &rtwvif->bfee;
struct rtw_bf_info *bfinfo = &rtwdev->bf_info; struct rtw_bf_info *bfinfo = &rtwdev->bf_info;
struct rtw_chip_info *chip = rtwdev->chip;
struct ieee80211_sta *sta; struct ieee80211_sta *sta;
struct ieee80211_sta_vht_cap *vht_cap; struct ieee80211_sta_vht_cap *vht_cap;
struct ieee80211_sta_vht_cap *ic_vht_cap; struct ieee80211_sta_vht_cap *ic_vht_cap;
@ -49,25 +49,29 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
sta = ieee80211_find_sta(vif, bssid); sta = ieee80211_find_sta(vif, bssid);
if (!sta) { if (!sta) {
rcu_read_unlock();
rtw_warn(rtwdev, "failed to find station entry for bss %pM\n", rtw_warn(rtwdev, "failed to find station entry for bss %pM\n",
bssid); bssid);
goto out_unlock; return;
} }
ic_vht_cap = &hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap; ic_vht_cap = &hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap;
vht_cap = &sta->vht_cap; vht_cap = &sta->deflink.vht_cap;
rcu_read_unlock();
if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) &&
(vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) { (vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
if (bfinfo->bfer_mu_cnt >= chip->bfer_mu_max_num) { if (bfinfo->bfer_mu_cnt >= chip->bfer_mu_max_num) {
rtw_dbg(rtwdev, RTW_DBG_BF, "mu bfer number over limit\n"); rtw_dbg(rtwdev, RTW_DBG_BF, "mu bfer number over limit\n");
goto out_unlock; return;
} }
ether_addr_copy(bfee->mac_addr, bssid); ether_addr_copy(bfee->mac_addr, bssid);
bfee->role = RTW_BFEE_MU; bfee->role = RTW_BFEE_MU;
bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7); bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7);
bfee->aid = bss_conf->aid; bfee->aid = vif->cfg.aid;
bfinfo->bfer_mu_cnt++; bfinfo->bfer_mu_cnt++;
rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true); rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true);
@ -75,7 +79,7 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
(vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
if (bfinfo->bfer_su_cnt >= chip->bfer_su_max_num) { if (bfinfo->bfer_su_cnt >= chip->bfer_su_max_num) {
rtw_dbg(rtwdev, RTW_DBG_BF, "su bfer number over limit\n"); rtw_dbg(rtwdev, RTW_DBG_BF, "su bfer number over limit\n");
goto out_unlock; return;
} }
sound_dim = vht_cap->cap & sound_dim = vht_cap->cap &
@ -98,9 +102,6 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true); rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true);
} }
out_unlock:
rcu_read_unlock();
} }
void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev, void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev,

381
coex.c
View file

@ -13,7 +13,7 @@
static u8 rtw_coex_next_rssi_state(struct rtw_dev *rtwdev, u8 pre_state, static u8 rtw_coex_next_rssi_state(struct rtw_dev *rtwdev, u8 pre_state,
u8 rssi, u8 rssi_thresh) u8 rssi, u8 rssi_thresh)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
u8 tol = chip->rssi_tolerance; u8 tol = chip->rssi_tolerance;
u8 next_state; u8 next_state;
@ -36,7 +36,7 @@ static u8 rtw_coex_next_rssi_state(struct rtw_dev *rtwdev, u8 pre_state,
static void rtw_coex_limited_tx(struct rtw_dev *rtwdev, static void rtw_coex_limited_tx(struct rtw_dev *rtwdev,
bool tx_limit_en, bool ampdu_limit_en) bool tx_limit_en, bool ampdu_limit_en)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
u8 num_of_active_port = 1; u8 num_of_active_port = 1;
@ -211,6 +211,10 @@ static void rtw_coex_wl_ccklock_detect(struct rtw_dev *rtwdev)
bool is_cck_lock_rate = false; bool is_cck_lock_rate = false;
if (coex_stat->wl_coex_mode != COEX_WLINK_2G1PORT &&
coex_stat->wl_coex_mode != COEX_WLINK_2GFREE)
return;
if (coex_dm->bt_status == COEX_BTSTATUS_INQ_PAGE || if (coex_dm->bt_status == COEX_BTSTATUS_INQ_PAGE ||
coex_stat->bt_setup_link) { coex_stat->bt_setup_link) {
coex_stat->wl_cck_lock = false; coex_stat->wl_cck_lock = false;
@ -361,7 +365,7 @@ static void rtw_coex_set_wl_pri_mask(struct rtw_dev *rtwdev, u8 bitmap,
void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set) void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
u16 val = 0x2; u16 val = 0x2;
@ -396,7 +400,7 @@ EXPORT_SYMBOL(rtw_coex_write_scbd);
static u16 rtw_coex_read_scbd(struct rtw_dev *rtwdev) static u16 rtw_coex_read_scbd(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
if (!chip->scbd_support) if (!chip->scbd_support)
return 0; return 0;
@ -406,7 +410,7 @@ static u16 rtw_coex_read_scbd(struct rtw_dev *rtwdev)
static void rtw_coex_check_rfk(struct rtw_dev *rtwdev) static void rtw_coex_check_rfk(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_rfe *coex_rfe = &coex->rfe; struct rtw_coex_rfe *coex_rfe = &coex->rfe;
@ -460,9 +464,32 @@ static void rtw_coex_gnt_workaround(struct rtw_dev *rtwdev, bool force, u8 mode)
rtw_coex_set_gnt_fix(rtwdev); rtw_coex_set_gnt_fix(rtwdev);
} }
static void rtw_coex_monitor_bt_ctr(struct rtw_dev *rtwdev)
{
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat;
u32 tmp;
tmp = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS);
coex_stat->hi_pri_tx = FIELD_GET(MASKLWORD, tmp);
coex_stat->hi_pri_rx = FIELD_GET(MASKHWORD, tmp);
tmp = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS_1);
coex_stat->lo_pri_tx = FIELD_GET(MASKLWORD, tmp);
coex_stat->lo_pri_rx = FIELD_GET(MASKHWORD, tmp);
rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL,
BIT_R_GRANTALL_WLMASK | BIT_STATIS_BT_EN);
rtw_dbg(rtwdev, RTW_DBG_COEX,
"[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n",
coex_stat->hi_pri_rx, coex_stat->hi_pri_tx,
coex_stat->lo_pri_rx, coex_stat->lo_pri_tx);
}
static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev) static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
@ -497,10 +524,10 @@ static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev)
static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason) static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_traffic_stats *stats = &rtwdev->stats; struct rtw_traffic_stats *stats = &rtwdev->stats;
bool is_5G = false; bool is_5G = false;
bool wl_busy = false; bool wl_busy = false;
@ -606,7 +633,7 @@ static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev,
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct sk_buff *skb_resp = NULL; struct sk_buff *skb_resp = NULL;
mutex_lock(&coex->mutex); lockdep_assert_held(&rtwdev->mutex);
rtw_fw_query_bt_mp_info(rtwdev, req); rtw_fw_query_bt_mp_info(rtwdev, req);
@ -623,7 +650,6 @@ static struct sk_buff *rtw_coex_info_request(struct rtw_dev *rtwdev,
} }
out: out:
mutex_unlock(&coex->mutex);
return skb_resp; return skb_resp;
} }
@ -679,10 +705,10 @@ static const char *rtw_coex_get_bt_status_string(u8 bt_status)
static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev) static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_chip_info *chip = rtwdev->chip;
u8 i; u8 i;
u8 rssi_state; u8 rssi_state;
u8 rssi_step; u8 rssi_step;
@ -779,8 +805,10 @@ static void rtw_coex_update_bt_link_info(struct rtw_dev *rtwdev)
static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type) static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm; struct rtw_coex_dm *coex_dm = &rtwdev->coex.dm;
struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
u8 link = 0; u8 link = 0;
u8 center_chan = 0; u8 center_chan = 0;
u8 bw; u8 bw;
@ -791,7 +819,9 @@ static void rtw_coex_update_wl_ch_info(struct rtw_dev *rtwdev, u8 type)
if (type != COEX_MEDIA_DISCONNECT) if (type != COEX_MEDIA_DISCONNECT)
center_chan = rtwdev->hal.current_channel; center_chan = rtwdev->hal.current_channel;
if (center_chan == 0) { if (center_chan == 0 ||
(efuse->share_ant && center_chan <= 14 &&
coex_stat->wl_coex_mode != COEX_WLINK_2GFREE)) {
link = 0; link = 0;
center_chan = 0; center_chan = 0;
bw = 0; bw = 0;
@ -902,7 +932,7 @@ EXPORT_SYMBOL(rtw_coex_write_indirect_reg);
static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control) static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_hw_reg *btg_reg = chip->btg_reg; const struct rtw_hw_reg *btg_reg = chip->btg_reg;
if (wifi_control) { if (wifi_control) {
@ -930,10 +960,27 @@ static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state)
rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0300, state); rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0300, state);
} }
static void rtw_coex_mimo_ps(struct rtw_dev *rtwdev, bool force, bool state)
{
struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
if (!force && state == coex_stat->wl_mimo_ps)
return;
coex_stat->wl_mimo_ps = state;
rtw_set_txrx_1ss(rtwdev, state);
rtw_coex_update_wl_ch_info(rtwdev, (u8)coex_stat->wl_connected);
rtw_dbg(rtwdev, RTW_DBG_COEX,
"[BTCoex], %s(): state = %d\n", __func__, state);
}
static void rtw_btc_wltoggle_table_a(struct rtw_dev *rtwdev, bool force, static void rtw_btc_wltoggle_table_a(struct rtw_dev *rtwdev, bool force,
u8 table_case) u8 table_case)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
u8 h2c_para[6] = {0}; u8 h2c_para[6] = {0};
u32 table_wl = 0x5a5a5a5a; u32 table_wl = 0x5a5a5a5a;
@ -1017,9 +1064,9 @@ static void rtw_coex_set_table(struct rtw_dev *rtwdev, bool force, u32 table0,
static void rtw_coex_table(struct rtw_dev *rtwdev, bool force, u8 type) static void rtw_coex_table(struct rtw_dev *rtwdev, bool force, u8 type)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
@ -1087,9 +1134,9 @@ static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type,
static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2, static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,
u8 byte3, u8 byte4, u8 byte5) u8 byte3, u8 byte4, u8 byte5)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
u8 ps_type = COEX_PS_WIFI_NATIVE; u8 ps_type = COEX_PS_WIFI_NATIVE;
bool ap_enable = false; bool ap_enable = false;
@ -1106,7 +1153,8 @@ static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,
ps_type = COEX_PS_WIFI_NATIVE; ps_type = COEX_PS_WIFI_NATIVE;
rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0); rtw_coex_power_save_state(rtwdev, ps_type, 0x0, 0x0);
} else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { } else if ((byte1 & BIT(4) && !(byte1 & BIT(5))) ||
coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
rtw_dbg(rtwdev, RTW_DBG_COEX, rtw_dbg(rtwdev, RTW_DBG_COEX,
"[BTCoex], %s(): Force LPS (byte1 = 0x%x)\n", __func__, "[BTCoex], %s(): Force LPS (byte1 = 0x%x)\n", __func__,
byte1); byte1);
@ -1144,10 +1192,10 @@ static void rtw_coex_set_tdma(struct rtw_dev *rtwdev, u8 byte1, u8 byte2,
static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase) static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
u8 n, type; u8 n, type;
bool turn_on; bool turn_on;
@ -1477,8 +1525,8 @@ static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev)
static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev) static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@ -1500,11 +1548,11 @@ static void rtw_coex_action_coex_all_off(struct rtw_dev *rtwdev)
static void rtw_coex_action_freerun(struct rtw_dev *rtwdev) static void rtw_coex_action_freerun(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 level = 0; u8 level = 0;
bool bt_afh_loss = true; bool bt_afh_loss = true;
@ -1545,8 +1593,8 @@ static void rtw_coex_action_freerun(struct rtw_dev *rtwdev)
static void rtw_coex_action_rf4ce(struct rtw_dev *rtwdev) static void rtw_coex_action_rf4ce(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@ -1570,8 +1618,8 @@ static void rtw_coex_action_rf4ce(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@ -1595,10 +1643,10 @@ static void rtw_coex_action_bt_whql_test(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
u32 slot_type = 0; u32 slot_type = 0;
@ -1635,11 +1683,11 @@ static void rtw_coex_action_bt_relink(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex_rfe *coex_rfe = &coex->rfe; struct rtw_coex_rfe *coex_rfe = &coex->rfe;
u8 table_case = 0xff, tdma_case = 0xff; u8 table_case = 0xff, tdma_case = 0xff;
@ -1704,10 +1752,10 @@ static void rtw_coex_action_bt_idle(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
bool wl_hi_pri = false; bool wl_hi_pri = false;
u8 table_case, tdma_case; u8 table_case, tdma_case;
u32 slot_type = 0; u32 slot_type = 0;
@ -1802,12 +1850,60 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev)
rtw_coex_tdma(rtwdev, false, tdma_case | slot_type); rtw_coex_tdma(rtwdev, false, tdma_case | slot_type);
} }
static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_game_hid(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_coex_dm *coex_dm = &coex->dm;
u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
if (efuse->share_ant) {
coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;
if (coex_stat->bt_whck_test)
table_case = 2;
else if (coex_stat->wl_linkscan_proc || coex_stat->bt_hid_exist)
table_case = 33;
else if (coex_stat->bt_setup_link || coex_stat->bt_inq_page)
table_case = 0;
else if (coex_stat->bt_a2dp_exist)
table_case = 34;
else
table_case = 33;
tdma_case = 0;
} else {
if (COEX_RSSI_HIGH(coex_dm->wl_rssi_state[1]))
tdma_case = 112;
else
tdma_case = 113;
table_case = 121;
}
if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[6]);
else
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[5]);
} else {
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
}
rtw_coex_table(rtwdev, false, table_case);
rtw_coex_tdma(rtwdev, false, tdma_case);
}
static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@ -1816,13 +1912,8 @@ static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev)
if (efuse->share_ant) { if (efuse->share_ant) {
/* Shared-Ant */ /* Shared-Ant */
if (coex_stat->bt_multi_link) {
table_case = 10;
tdma_case = 17;
} else {
table_case = 10; table_case = 10;
tdma_case = 5; tdma_case = 5;
}
} else { } else {
/* Non-Shared-Ant */ /* Non-Shared-Ant */
if (coex_stat->bt_multi_link) { if (coex_stat->bt_multi_link) {
@ -1840,10 +1931,10 @@ static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
u32 slot_type = 0; u32 slot_type = 0;
bool bt_multi_link_remain = false, is_toggle_table = false; bool bt_multi_link_remain = false, is_toggle_table = false;
@ -1923,11 +2014,11 @@ static void rtw_coex_action_bt_hid(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
u32 slot_type = 0; u32 slot_type = 0;
@ -1965,10 +2056,10 @@ static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
bool ap_enable = false; bool ap_enable = false;
@ -2004,10 +2095,10 @@ static void rtw_coex_action_bt_a2dpsink(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@ -2041,11 +2132,11 @@ static void rtw_coex_action_bt_pan(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case, interval = 0; u8 table_case, tdma_case, interval = 0;
u32 slot_type = 0; u32 slot_type = 0;
bool is_toggle_table = false; bool is_toggle_table = false;
@ -2098,10 +2189,10 @@ static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
bool wl_cpt_test = false, bt_cpt_test = false; bool wl_cpt_test = false, bt_cpt_test = false;
@ -2155,10 +2246,10 @@ static void rtw_coex_action_bt_a2dp_pan(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@ -2190,10 +2281,10 @@ static void rtw_coex_action_bt_pan_hid(struct rtw_dev *rtwdev)
static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev) static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@ -2224,8 +2315,10 @@ static void rtw_coex_action_bt_a2dp_pan_hid(struct rtw_dev *rtwdev)
static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev) static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip; struct rtw_coex_stat *coex_stat = &coex->stat;
u8 table_case, tdma_case; u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@ -2235,6 +2328,9 @@ static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)
rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false); rtw_coex_write_scbd(rtwdev, COEX_SCBD_FIX2M, false);
if (coex_stat->bt_game_hid_exist && coex_stat->wl_linkscan_proc)
coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;
if (efuse->share_ant) { if (efuse->share_ant) {
/* Shared-Ant */ /* Shared-Ant */
table_case = 0; table_case = 0;
@ -2251,8 +2347,8 @@ static void rtw_coex_action_wl_under5g(struct rtw_dev *rtwdev)
static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev) static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@ -2275,9 +2371,10 @@ static void rtw_coex_action_wl_only(struct rtw_dev *rtwdev)
static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev) static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip; struct rtw_coex_stat *coex_stat = &coex->stat;
u8 table_case, tdma_case; u8 table_case, tdma_case;
if (coex->under_5g) if (coex->under_5g)
@ -2286,7 +2383,6 @@ static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G);
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
if (efuse->share_ant) { if (efuse->share_ant) {
/* Shared-Ant */ /* Shared-Ant */
@ -2298,16 +2394,26 @@ static void rtw_coex_action_wl_native_lps(struct rtw_dev *rtwdev)
tdma_case = 100; tdma_case = 100;
} }
if (coex_stat->bt_game_hid_exist) {
coex_stat->wl_coex_mode = COEX_WLINK_2GFREE;
if (coex_stat->wl_tput_dir == COEX_WL_TPUT_TX)
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_tx[6]);
else
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[5]);
} else {
rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]);
}
rtw_coex_table(rtwdev, false, table_case); rtw_coex_table(rtwdev, false, table_case);
rtw_coex_tdma(rtwdev, false, tdma_case); rtw_coex_tdma(rtwdev, false, tdma_case);
} }
static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev) static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
u32 slot_type = 0; u32 slot_type = 0;
@ -2344,8 +2450,8 @@ static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev)
static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev) static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 table_case, tdma_case; u8 table_case, tdma_case;
rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__); rtw_dbg(rtwdev, RTW_DBG_COEX, "[BTCoex], %s()\n", __func__);
@ -2421,6 +2527,7 @@ static void rtw_coex_action_wl_connected(struct rtw_dev *rtwdev)
static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason) static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
@ -2494,6 +2601,11 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
goto exit; goto exit;
} }
if (coex_stat->bt_game_hid_exist && coex_stat->wl_connected) {
rtw_coex_action_bt_game_hid(rtwdev);
goto exit;
}
if (coex_stat->bt_whck_test) { if (coex_stat->bt_whck_test) {
rtw_coex_action_bt_whql_test(rtwdev); rtw_coex_action_bt_whql_test(rtwdev);
goto exit; goto exit;
@ -2530,6 +2642,18 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason)
} }
exit: exit:
if (chip->wl_mimo_ps_support) {
if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
if (coex_dm->reason == COEX_RSN_2GMEDIA)
rtw_coex_mimo_ps(rtwdev, true, true);
else
rtw_coex_mimo_ps(rtwdev, false, true);
} else {
rtw_coex_mimo_ps(rtwdev, false, false);
}
}
rtw_coex_gnt_workaround(rtwdev, false, coex_stat->wl_coex_mode); rtw_coex_gnt_workaround(rtwdev, false, coex_stat->wl_coex_mode);
rtw_coex_limited_wl(rtwdev); rtw_coex_limited_wl(rtwdev);
} }
@ -2877,9 +3001,9 @@ void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type)
void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex_dm *coex_dm = &coex->dm; struct rtw_coex_dm *coex_dm = &coex->dm;
u32 bt_relink_time; u32 bt_relink_time;
u8 i, rsp_source = 0, type; u8 i, rsp_source = 0, type;
@ -3139,6 +3263,135 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO); rtw_coex_run_coex(rtwdev, COEX_RSN_BTINFO);
} }
#define COEX_BT_HIDINFO_MTK 0x46
static const u8 coex_bt_hidinfo_ps[] = {0x57, 0x69, 0x72};
static const u8 coex_bt_hidinfo_xb[] = {0x58, 0x62, 0x6f};
void rtw_coex_bt_hid_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_hid *hidinfo;
struct rtw_coex_hid_info_a *hida;
struct rtw_coex_hid_handle_list *hl, *bhl;
u8 sub_id = buf[2], gamehid_cnt = 0, handle, i;
bool cur_game_hid_exist, complete;
if (!chip->wl_mimo_ps_support &&
(sub_id == COEX_BT_HIDINFO_LIST || sub_id == COEX_BT_HIDINFO_A))
return;
rtw_dbg(rtwdev, RTW_DBG_COEX,
"[BTCoex], HID info notify, sub_id = 0x%x\n", sub_id);
switch (sub_id) {
case COEX_BT_HIDINFO_LIST:
hl = &coex_stat->hid_handle_list;
bhl = (struct rtw_coex_hid_handle_list *)buf;
if (!memcmp(hl, bhl, sizeof(*hl)))
return;
coex_stat->hid_handle_list = *bhl;
memset(&coex_stat->hid_info, 0, sizeof(coex_stat->hid_info));
for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
hidinfo = &coex_stat->hid_info[i];
if (hl->handle[i] != COEX_BT_HIDINFO_NOTCON &&
hl->handle[i] != 0)
hidinfo->hid_handle = hl->handle[i];
}
break;
case COEX_BT_HIDINFO_A:
hida = (struct rtw_coex_hid_info_a *)buf;
handle = hida->handle;
for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
hidinfo = &coex_stat->hid_info[i];
if (hidinfo->hid_handle == handle) {
hidinfo->hid_vendor = hida->vendor;
memcpy(hidinfo->hid_name, hida->name,
sizeof(hidinfo->hid_name));
hidinfo->hid_info_completed = true;
break;
}
}
break;
}
for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
hidinfo = &coex_stat->hid_info[i];
complete = hidinfo->hid_info_completed;
handle = hidinfo->hid_handle;
if (!complete || handle == COEX_BT_HIDINFO_NOTCON ||
handle == 0 || handle >= COEX_BT_BLE_HANDLE_THRS) {
hidinfo->is_game_hid = false;
continue;
}
if (hidinfo->hid_vendor == COEX_BT_HIDINFO_MTK) {
if ((memcmp(hidinfo->hid_name,
coex_bt_hidinfo_ps,
COEX_BT_HIDINFO_NAME)) == 0)
hidinfo->is_game_hid = true;
else if ((memcmp(hidinfo->hid_name,
coex_bt_hidinfo_xb,
COEX_BT_HIDINFO_NAME)) == 0)
hidinfo->is_game_hid = true;
else
hidinfo->is_game_hid = false;
} else {
hidinfo->is_game_hid = false;
}
if (hidinfo->is_game_hid)
gamehid_cnt++;
}
if (gamehid_cnt > 0)
cur_game_hid_exist = true;
else
cur_game_hid_exist = false;
if (cur_game_hid_exist != coex_stat->bt_game_hid_exist) {
coex_stat->bt_game_hid_exist = cur_game_hid_exist;
rtw_dbg(rtwdev, RTW_DBG_COEX,
"[BTCoex], HID info changed!bt_game_hid_exist = %d!\n",
coex_stat->bt_game_hid_exist);
rtw_coex_run_coex(rtwdev, COEX_RSN_BTSTATUS);
}
}
void rtw_coex_query_bt_hid_list(struct rtw_dev *rtwdev)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat;
struct rtw_coex_hid *hidinfo;
u8 i, handle;
bool complete;
if (!chip->wl_mimo_ps_support || coex_stat->wl_under_ips ||
(coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl))
return;
if (!coex_stat->bt_hid_exist &&
!((coex_stat->bt_info_lb2 & COEX_INFO_CONNECTION) &&
(coex_stat->hi_pri_tx + coex_stat->hi_pri_rx >
COEX_BT_GAMEHID_CNT)))
return;
rtw_fw_coex_query_hid_info(rtwdev, COEX_BT_HIDINFO_LIST, 0);
for (i = 0; i < COEX_BT_HIDINFO_HANDLE_NUM; i++) {
hidinfo = &coex_stat->hid_info[i];
complete = hidinfo->hid_info_completed;
handle = hidinfo->hid_handle;
if (handle == 0 || handle == COEX_BT_HIDINFO_NOTCON ||
handle >= COEX_BT_BLE_HANDLE_THRS || complete)
continue;
rtw_fw_coex_query_hid_info(rtwdev,
COEX_BT_HIDINFO_A,
handle);
}
}
void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length)
{ {
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
@ -3175,6 +3428,17 @@ void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type)
rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS); rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS);
} }
void rtw_coex_wl_status_check(struct rtw_dev *rtwdev)
{
struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat;
if ((coex_stat->wl_under_lps && !coex_stat->wl_force_lps_ctrl) ||
coex_stat->wl_under_ips)
return;
rtw_coex_monitor_bt_ctr(rtwdev);
}
void rtw_coex_bt_relink_work(struct work_struct *work) void rtw_coex_bt_relink_work(struct work_struct *work)
{ {
struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
@ -3317,7 +3581,7 @@ static const char *rtw_coex_get_reason_string(u8 reason)
static u8 rtw_coex_get_table_index(struct rtw_dev *rtwdev, u32 wl_reg_6c0, static u8 rtw_coex_get_table_index(struct rtw_dev *rtwdev, u32 wl_reg_6c0,
u32 wl_reg_6c4) u32 wl_reg_6c4)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
u8 ans = 0xFF; u8 ans = 0xFF;
u8 n, i; u8 n, i;
@ -3353,8 +3617,8 @@ static u8 rtw_coex_get_table_index(struct rtw_dev *rtwdev, u32 wl_reg_6c0,
static u8 rtw_coex_get_tdma_index(struct rtw_dev *rtwdev, u8 *tdma_para) static u8 rtw_coex_get_tdma_index(struct rtw_dev *rtwdev, u8 *tdma_para)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw_chip_info *chip = rtwdev->chip;
u8 ans = 0xFF; u8 ans = 0xFF;
u8 n, i, j; u8 n, i, j;
u8 load_cur_tab_val; u8 load_cur_tab_val;
@ -3471,7 +3735,7 @@ static int rtw_coex_val_info(struct rtw_dev *rtwdev,
static void rtw_coex_set_coexinfo_hw(struct rtw_dev *rtwdev, struct seq_file *m) static void rtw_coex_set_coexinfo_hw(struct rtw_dev *rtwdev, struct seq_file *m)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_reg_domain *reg; const struct rtw_reg_domain *reg;
char addr_info[INFO_SIZE]; char addr_info[INFO_SIZE];
int n_addr = 0; int n_addr = 0;
@ -3637,6 +3901,7 @@ static const char *rtw_coex_get_wl_coex_mode(u8 coex_wl_link_mode)
switch (coex_wl_link_mode) { switch (coex_wl_link_mode) {
case_WLINK(2G1PORT); case_WLINK(2G1PORT);
case_WLINK(5G); case_WLINK(5G);
case_WLINK(2GFREE);
default: default:
return "Unknown"; return "Unknown";
} }
@ -3644,7 +3909,7 @@ static const char *rtw_coex_get_wl_coex_mode(u8 coex_wl_link_mode)
void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m) void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_dm_info *dm_info = &rtwdev->dm_info; struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_stat *coex_stat = &coex->stat;
@ -3658,7 +3923,6 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
u16 score_board_WB, score_board_BW; u16 score_board_WB, score_board_BW;
u32 wl_reg_6c0, wl_reg_6c4, wl_reg_6c8, wl_reg_778, wl_reg_6cc; u32 wl_reg_6c0, wl_reg_6c4, wl_reg_6c8, wl_reg_778, wl_reg_6cc;
u32 lte_coex, bt_coex; u32 lte_coex, bt_coex;
u32 bt_hi_pri, bt_lo_pri;
int i; int i;
score_board_BW = rtw_coex_read_scbd(rtwdev); score_board_BW = rtw_coex_read_scbd(rtwdev);
@ -3669,17 +3933,6 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
wl_reg_6cc = rtw_read32(rtwdev, REG_BT_COEX_TABLE_H); wl_reg_6cc = rtw_read32(rtwdev, REG_BT_COEX_TABLE_H);
wl_reg_778 = rtw_read8(rtwdev, REG_BT_STAT_CTRL); wl_reg_778 = rtw_read8(rtwdev, REG_BT_STAT_CTRL);
bt_hi_pri = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS);
bt_lo_pri = rtw_read32(rtwdev, REG_BT_ACT_STATISTICS_1);
rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL,
BIT_R_GRANTALL_WLMASK | BIT_STATIS_BT_EN);
coex_stat->hi_pri_tx = FIELD_GET(MASKLWORD, bt_hi_pri);
coex_stat->hi_pri_rx = FIELD_GET(MASKHWORD, bt_hi_pri);
coex_stat->lo_pri_tx = FIELD_GET(MASKLWORD, bt_lo_pri);
coex_stat->lo_pri_rx = FIELD_GET(MASKHWORD, bt_lo_pri);
sys_lte = rtw_read8(rtwdev, 0x73); sys_lte = rtw_read8(rtwdev, 0x73);
lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38); lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38);
bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54); bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54);
@ -3803,7 +4056,7 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m)
rtwdev->stats.tx_throughput, rtwdev->stats.rx_throughput); rtwdev->stats.tx_throughput, rtwdev->stats.rx_throughput);
seq_printf(m, "%-40s = %u/ %u/ %u\n", seq_printf(m, "%-40s = %u/ %u/ %u\n",
"IPS/ Low Power/ PS mode", "IPS/ Low Power/ PS mode",
test_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags), !test_bit(RTW_FLAG_POWERON, rtwdev->flags),
test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags), test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags),
rtwdev->lps_conf.mode); rtwdev->lps_conf.mode);

19
coex.h
View file

@ -11,6 +11,7 @@
#define COEX_MIN_DELAY 10 /* delay unit in ms */ #define COEX_MIN_DELAY 10 /* delay unit in ms */
#define COEX_RFK_TIMEOUT 600 /* RFK timeout in ms */ #define COEX_RFK_TIMEOUT 600 /* RFK timeout in ms */
#define COEX_BT_GAMEHID_CNT 800
#define COEX_RF_OFF 0x0 #define COEX_RF_OFF 0x0
#define COEX_RF_ON 0x1 #define COEX_RF_ON 0x1
@ -172,6 +173,7 @@ enum coex_bt_profile {
enum coex_wl_link_mode { enum coex_wl_link_mode {
COEX_WLINK_2G1PORT = 0x0, COEX_WLINK_2G1PORT = 0x0,
COEX_WLINK_5G = 0x3, COEX_WLINK_5G = 0x3,
COEX_WLINK_2GFREE = 0x7,
COEX_WLINK_MAX COEX_WLINK_MAX
}; };
@ -325,7 +327,7 @@ struct coex_rf_para {
static inline void rtw_coex_set_init(struct rtw_dev *rtwdev) static inline void rtw_coex_set_init(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_init(rtwdev); chip->ops->coex_set_init(rtwdev);
} }
@ -333,7 +335,7 @@ static inline void rtw_coex_set_init(struct rtw_dev *rtwdev)
static inline static inline
void rtw_coex_set_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type, u8 pos_type) void rtw_coex_set_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type, u8 pos_type)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
if (!chip->ops->coex_set_ant_switch) if (!chip->ops->coex_set_ant_switch)
return; return;
@ -343,28 +345,28 @@ void rtw_coex_set_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type, u8 pos_type)
static inline void rtw_coex_set_gnt_fix(struct rtw_dev *rtwdev) static inline void rtw_coex_set_gnt_fix(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_gnt_fix(rtwdev); chip->ops->coex_set_gnt_fix(rtwdev);
} }
static inline void rtw_coex_set_gnt_debug(struct rtw_dev *rtwdev) static inline void rtw_coex_set_gnt_debug(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_gnt_debug(rtwdev); chip->ops->coex_set_gnt_debug(rtwdev);
} }
static inline void rtw_coex_set_rfe_type(struct rtw_dev *rtwdev) static inline void rtw_coex_set_rfe_type(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_rfe_type(rtwdev); chip->ops->coex_set_rfe_type(rtwdev);
} }
static inline void rtw_coex_set_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr) static inline void rtw_coex_set_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_wl_tx_power(rtwdev, wl_pwr); chip->ops->coex_set_wl_tx_power(rtwdev, wl_pwr);
} }
@ -372,7 +374,7 @@ static inline void rtw_coex_set_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr)
static inline static inline
void rtw_coex_set_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) void rtw_coex_set_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->coex_set_wl_rx_gain(rtwdev, low_gain); chip->ops->coex_set_wl_rx_gain(rtwdev, low_gain);
} }
@ -401,9 +403,12 @@ void rtw_coex_scan_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type); void rtw_coex_connect_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type); void rtw_coex_media_status_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length); void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
void rtw_coex_bt_hid_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length); void rtw_coex_wl_fwdbginfo_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length);
void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type); void rtw_coex_switchband_notify(struct rtw_dev *rtwdev, u8 type);
void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type); void rtw_coex_wl_status_change_notify(struct rtw_dev *rtwdev, u32 type);
void rtw_coex_wl_status_check(struct rtw_dev *rtwdev);
void rtw_coex_query_bt_hid_list(struct rtw_dev *rtwdev);
void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m); void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m);
static inline bool rtw_coex_disabled(struct rtw_dev *rtwdev) static inline bool rtw_coex_disabled(struct rtw_dev *rtwdev)

97
debug.c
View file

@ -144,7 +144,9 @@ static int rtw_debugfs_get_rf_read(struct seq_file *m, void *v)
addr = debugfs_priv->rf_addr; addr = debugfs_priv->rf_addr;
mask = debugfs_priv->rf_mask; mask = debugfs_priv->rf_mask;
mutex_lock(&rtwdev->mutex);
val = rtw_read_rf(rtwdev, path, addr, mask); val = rtw_read_rf(rtwdev, path, addr, mask);
mutex_unlock(&rtwdev->mutex);
seq_printf(m, "rf_read path:%d addr:0x%08x mask:0x%08x val=0x%08x\n", seq_printf(m, "rf_read path:%d addr:0x%08x mask:0x%08x val=0x%08x\n",
path, addr, mask, val); path, addr, mask, val);
@ -181,8 +183,8 @@ static int rtw_debugfs_copy_from_user(char tmp[], int size,
tmp_len = (count > size - 1 ? size - 1 : count); tmp_len = (count > size - 1 ? size - 1 : count);
if (!buffer || copy_from_user(tmp, buffer, tmp_len)) if (copy_from_user(tmp, buffer, tmp_len))
return count; return -EFAULT;
tmp[tmp_len] = '\0'; tmp[tmp_len] = '\0';
@ -199,13 +201,16 @@ static ssize_t rtw_debugfs_set_read_reg(struct file *filp,
char tmp[32 + 1]; char tmp[32 + 1];
u32 addr, len; u32 addr, len;
int num; int num;
int ret;
rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 2); ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 2);
if (ret)
return ret;
num = sscanf(tmp, "%x %x", &addr, &len); num = sscanf(tmp, "%x %x", &addr, &len);
if (num != 2) if (num != 2)
return count; return -EINVAL;
if (len != 1 && len != 2 && len != 4) { if (len != 1 && len != 2 && len != 4) {
rtw_warn(rtwdev, "read reg setting wrong len\n"); rtw_warn(rtwdev, "read reg setting wrong len\n");
@ -269,11 +274,7 @@ static int rtw_debugfs_get_rsvd_page(struct seq_file *m, void *v)
for (i = 0 ; i < buf_size ; i += 8) { for (i = 0 ; i < buf_size ; i += 8) {
if (i % page_size == 0) if (i % page_size == 0)
seq_printf(m, "PAGE %d\n", (i + offset) / page_size); seq_printf(m, "PAGE %d\n", (i + offset) / page_size);
seq_printf(m, "%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", seq_printf(m, "%8ph\n", buf + i);
*(buf + i), *(buf + i + 1),
*(buf + i + 2), *(buf + i + 3),
*(buf + i + 4), *(buf + i + 5),
*(buf + i + 6), *(buf + i + 7));
} }
vfree(buf); vfree(buf);
@ -290,8 +291,11 @@ static ssize_t rtw_debugfs_set_rsvd_page(struct file *filp,
char tmp[32 + 1]; char tmp[32 + 1];
u32 offset, page_num; u32 offset, page_num;
int num; int num;
int ret;
rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 2); ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 2);
if (ret)
return ret;
num = sscanf(tmp, "%d %d", &offset, &page_num); num = sscanf(tmp, "%d %d", &offset, &page_num);
@ -316,8 +320,11 @@ static ssize_t rtw_debugfs_set_single_input(struct file *filp,
char tmp[32 + 1]; char tmp[32 + 1];
u32 input; u32 input;
int num; int num;
int ret;
rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1);
if (ret)
return ret;
num = kstrtoint(tmp, 0, &input); num = kstrtoint(tmp, 0, &input);
@ -340,14 +347,17 @@ static ssize_t rtw_debugfs_set_write_reg(struct file *filp,
char tmp[32 + 1]; char tmp[32 + 1];
u32 addr, val, len; u32 addr, val, len;
int num; int num;
int ret;
rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3);
if (ret)
return ret;
/* write BB/MAC register */ /* write BB/MAC register */
num = sscanf(tmp, "%x %x %x", &addr, &val, &len); num = sscanf(tmp, "%x %x %x", &addr, &val, &len);
if (num != 3) if (num != 3)
return count; return -EINVAL;
switch (len) { switch (len) {
case 1: case 1:
@ -383,18 +393,23 @@ static ssize_t rtw_debugfs_set_h2c(struct file *filp,
char tmp[32 + 1]; char tmp[32 + 1];
u8 param[8]; u8 param[8];
int num; int num;
int ret;
rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3);
if (ret)
return ret;
num = sscanf(tmp, "%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx", num = sscanf(tmp, "%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx",
&param[0], &param[1], &param[2], &param[3], &param[0], &param[1], &param[2], &param[3],
&param[4], &param[5], &param[6], &param[7]); &param[4], &param[5], &param[6], &param[7]);
if (num != 8) { if (num != 8) {
rtw_info(rtwdev, "invalid H2C command format for debug\n"); rtw_warn(rtwdev, "invalid H2C command format for debug\n");
return -EINVAL; return -EINVAL;
} }
mutex_lock(&rtwdev->mutex);
rtw_fw_h2c_cmd_dbg(rtwdev, param); rtw_fw_h2c_cmd_dbg(rtwdev, param);
mutex_unlock(&rtwdev->mutex);
return count; return count;
} }
@ -408,17 +423,22 @@ static ssize_t rtw_debugfs_set_rf_write(struct file *filp,
char tmp[32 + 1]; char tmp[32 + 1];
u32 path, addr, mask, val; u32 path, addr, mask, val;
int num; int num;
int ret;
rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 4); ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 4);
if (ret)
return ret;
num = sscanf(tmp, "%x %x %x %x", &path, &addr, &mask, &val); num = sscanf(tmp, "%x %x %x %x", &path, &addr, &mask, &val);
if (num != 4) { if (num != 4) {
rtw_warn(rtwdev, "invalid args, [path] [addr] [mask] [val]\n"); rtw_warn(rtwdev, "invalid args, [path] [addr] [mask] [val]\n");
return count; return -EINVAL;
} }
mutex_lock(&rtwdev->mutex);
rtw_write_rf(rtwdev, path, addr, mask, val); rtw_write_rf(rtwdev, path, addr, mask, val);
mutex_unlock(&rtwdev->mutex);
rtw_dbg(rtwdev, RTW_DBG_DEBUGFS, rtw_dbg(rtwdev, RTW_DBG_DEBUGFS,
"write_rf path:%d addr:0x%08x mask:0x%08x, val:0x%08x\n", "write_rf path:%d addr:0x%08x mask:0x%08x, val:0x%08x\n",
path, addr, mask, val); path, addr, mask, val);
@ -436,14 +456,17 @@ static ssize_t rtw_debugfs_set_rf_read(struct file *filp,
char tmp[32 + 1]; char tmp[32 + 1];
u32 path, addr, mask; u32 path, addr, mask;
int num; int num;
int ret;
rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3);
if (ret)
return ret;
num = sscanf(tmp, "%x %x %x", &path, &addr, &mask); num = sscanf(tmp, "%x %x %x", &path, &addr, &mask);
if (num != 3) { if (num != 3) {
rtw_warn(rtwdev, "invalid args, [path] [addr] [mask] [val]\n"); rtw_warn(rtwdev, "invalid args, [path] [addr] [mask] [val]\n");
return count; return -EINVAL;
} }
debugfs_priv->rf_path = path; debugfs_priv->rf_path = path;
@ -465,7 +488,9 @@ static ssize_t rtw_debugfs_set_fix_rate(struct file *filp,
char tmp[32 + 1]; char tmp[32 + 1];
int ret; int ret;
rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1);
if (ret)
return ret;
ret = kstrtou8(tmp, 0, &fix_rate); ret = kstrtou8(tmp, 0, &fix_rate);
if (ret) { if (ret) {
@ -523,6 +548,8 @@ static int rtw_debug_get_rf_dump(struct seq_file *m, void *v)
u32 addr, offset, data; u32 addr, offset, data;
u8 path; u8 path;
mutex_lock(&rtwdev->mutex);
for (path = 0; path < rtwdev->hal.rf_path_num; path++) { for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
seq_printf(m, "RF path:%d\n", path); seq_printf(m, "RF path:%d\n", path);
for (addr = 0; addr < 0x100; addr += 4) { for (addr = 0; addr < 0x100; addr += 4) {
@ -537,6 +564,8 @@ static int rtw_debug_get_rf_dump(struct seq_file *m, void *v)
seq_puts(m, "\n"); seq_puts(m, "\n");
} }
mutex_unlock(&rtwdev->mutex);
return 0; return 0;
} }
@ -625,11 +654,13 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v)
struct rtw_debugfs_priv *debugfs_priv = m->private; struct rtw_debugfs_priv *debugfs_priv = m->private;
struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
struct rtw_hal *hal = &rtwdev->hal; struct rtw_hal *hal = &rtwdev->hal;
u8 path, rate; u8 path, rate, bw, ch, regd;
struct rtw_power_params pwr_param = {0}; struct rtw_power_params pwr_param = {0};
u8 bw = hal->current_band_width;
u8 ch = hal->current_channel; mutex_lock(&rtwdev->mutex);
u8 regd = rtw_regd_get(rtwdev); bw = hal->current_band_width;
ch = hal->current_channel;
regd = rtw_regd_get(rtwdev);
seq_printf(m, "channel: %u\n", ch); seq_printf(m, "channel: %u\n", ch);
seq_printf(m, "bandwidth: %u\n", bw); seq_printf(m, "bandwidth: %u\n", bw);
@ -671,6 +702,7 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v)
} }
mutex_unlock(&hal->tx_power_mutex); mutex_unlock(&hal->tx_power_mutex);
mutex_unlock(&rtwdev->mutex);
return 0; return 0;
} }
@ -715,8 +747,10 @@ static int rtw_debugfs_get_phy_info(struct seq_file *m, void *v)
seq_printf(m, "Current CH(fc) = %u\n", rtwdev->hal.current_channel); seq_printf(m, "Current CH(fc) = %u\n", rtwdev->hal.current_channel);
seq_printf(m, "Current BW = %u\n", rtwdev->hal.current_band_width); seq_printf(m, "Current BW = %u\n", rtwdev->hal.current_band_width);
seq_printf(m, "Current IGI = 0x%x\n", dm_info->igi_history[0]); seq_printf(m, "Current IGI = 0x%x\n", dm_info->igi_history[0]);
seq_printf(m, "TP {Tx, Rx} = {%u, %u}Mbps\n\n", seq_printf(m, "TP {Tx, Rx} = {%u, %u}Mbps\n",
stats->tx_throughput, stats->rx_throughput); stats->tx_throughput, stats->rx_throughput);
seq_printf(m, "1SS for TX and RX = %c\n\n", rtwdev->hal.txrx_1ss ?
'Y' : 'N');
seq_puts(m, "==========[Tx Phy Info]========\n"); seq_puts(m, "==========[Tx Phy Info]========\n");
seq_puts(m, "[Tx Rate] = "); seq_puts(m, "[Tx Rate] = ");
@ -830,7 +864,9 @@ static int rtw_debugfs_get_coex_info(struct seq_file *m, void *v)
struct rtw_debugfs_priv *debugfs_priv = m->private; struct rtw_debugfs_priv *debugfs_priv = m->private;
struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
mutex_lock(&rtwdev->mutex);
rtw_coex_display_coex_info(rtwdev, m); rtw_coex_display_coex_info(rtwdev, m);
mutex_unlock(&rtwdev->mutex);
return 0; return 0;
} }
@ -847,7 +883,9 @@ static ssize_t rtw_debugfs_set_coex_enable(struct file *filp,
bool enable; bool enable;
int ret; int ret;
rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1);
if (ret)
return ret;
ret = kstrtobool(tmp, &enable); ret = kstrtobool(tmp, &enable);
if (ret) { if (ret) {
@ -917,7 +955,9 @@ static ssize_t rtw_debugfs_set_fw_crash(struct file *filp,
bool input; bool input;
int ret; int ret;
rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1);
if (ret)
return ret;
ret = kstrtobool(tmp, &input); ret = kstrtobool(tmp, &input);
if (ret) if (ret)
@ -1025,6 +1065,8 @@ static void dump_gapk_status(struct rtw_dev *rtwdev, struct seq_file *m)
dm_info->dm_flags & BIT(RTW_DM_CAP_TXGAPK) ? '-' : '+', dm_info->dm_flags & BIT(RTW_DM_CAP_TXGAPK) ? '-' : '+',
rtw_dm_cap_strs[RTW_DM_CAP_TXGAPK]); rtw_dm_cap_strs[RTW_DM_CAP_TXGAPK]);
mutex_lock(&rtwdev->mutex);
for (path = 0; path < rtwdev->hal.rf_path_num; path++) { for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
val = rtw_read_rf(rtwdev, path, RF_GAINTX, RFREG_MASK); val = rtw_read_rf(rtwdev, path, RF_GAINTX, RFREG_MASK);
seq_printf(m, "path %d:\n0x%x = 0x%x\n", path, RF_GAINTX, val); seq_printf(m, "path %d:\n0x%x = 0x%x\n", path, RF_GAINTX, val);
@ -1034,6 +1076,7 @@ static void dump_gapk_status(struct rtw_dev *rtwdev, struct seq_file *m)
txgapk->rf3f_fs[path][i], i); txgapk->rf3f_fs[path][i], i);
seq_puts(m, "\n"); seq_puts(m, "\n");
} }
mutex_unlock(&rtwdev->mutex);
} }
static int rtw_debugfs_get_dm_cap(struct seq_file *m, void *v) static int rtw_debugfs_get_dm_cap(struct seq_file *m, void *v)

View file

@ -23,6 +23,8 @@ enum rtw_debug_mask {
RTW_DBG_PATH_DIV = 0x00004000, RTW_DBG_PATH_DIV = 0x00004000,
RTW_DBG_ADAPTIVITY = 0x00008000, RTW_DBG_ADAPTIVITY = 0x00008000,
RTW_DBG_HW_SCAN = 0x00010000, RTW_DBG_HW_SCAN = 0x00010000,
RTW_DBG_STATE = 0x00020000,
RTW_DBG_SDIO = 0x00040000,
RTW_DBG_ALL = 0xffffffff RTW_DBG_ALL = 0xffffffff
}; };

View file

@ -86,7 +86,7 @@ static int rtw_dump_logical_efuse_map(struct rtw_dev *rtwdev, u8 *phy_map,
static int rtw_dump_physical_efuse_map(struct rtw_dev *rtwdev, u8 *map) static int rtw_dump_physical_efuse_map(struct rtw_dev *rtwdev, u8 *map)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
u32 size = rtwdev->efuse.physical_size; u32 size = rtwdev->efuse.physical_size;
u32 efuse_ctl; u32 efuse_ctl;
u32 addr; u32 addr;
@ -145,7 +145,7 @@ EXPORT_SYMBOL(rtw_read8_physical_efuse);
int rtw_parse_efuse_map(struct rtw_dev *rtwdev) int rtw_parse_efuse_map(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
u32 phy_size = efuse->physical_size; u32 phy_size = efuse->physical_size;
u32 log_size = efuse->logical_size; u32 log_size = efuse->logical_size;

318
fw.c
View file

@ -14,6 +14,8 @@
#include "util.h" #include "util.h"
#include "wow.h" #include "wow.h"
#include "ps.h" #include "ps.h"
#include "phy.h"
#include "mac.h"
static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev,
struct sk_buff *skb) struct sk_buff *skb)
@ -116,7 +118,7 @@ static void rtw_fw_ra_report_iter(void *data, struct ieee80211_sta *sta)
si->ra_report.desc_rate = rate; si->ra_report.desc_rate = rate;
si->ra_report.bit_rate = bit_rate; si->ra_report.bit_rate = bit_rate;
sta->max_rc_amsdu_len = get_max_amsdu_len(bit_rate); sta->deflink.agg.max_rc_amsdu_len = get_max_amsdu_len(bit_rate);
} }
static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload, static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload,
@ -138,7 +140,7 @@ struct rtw_beacon_filter_iter_data {
u8 *payload; u8 *payload;
}; };
static void rtw_fw_bcn_filter_notify_vif_iter(void *data, u8 *mac, static void rtw_fw_bcn_filter_notify_vif_iter(void *data,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct rtw_beacon_filter_iter_data *iter_data = data; struct rtw_beacon_filter_iter_data *iter_data = data;
@ -233,6 +235,9 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb)
case C2H_BT_INFO: case C2H_BT_INFO:
rtw_coex_bt_info_notify(rtwdev, c2h->payload, len); rtw_coex_bt_info_notify(rtwdev, c2h->payload, len);
break; break;
case C2H_BT_HID_INFO:
rtw_coex_bt_hid_info_notify(rtwdev, c2h->payload, len);
break;
case C2H_WLAN_INFO: case C2H_WLAN_INFO:
rtw_coex_wl_fwdbginfo_notify(rtwdev, c2h->payload, len); rtw_coex_wl_fwdbginfo_notify(rtwdev, c2h->payload, len);
break; break;
@ -303,21 +308,17 @@ void rtw_fw_c2h_cmd_isr(struct rtw_dev *rtwdev)
} }
EXPORT_SYMBOL(rtw_fw_c2h_cmd_isr); EXPORT_SYMBOL(rtw_fw_c2h_cmd_isr);
static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev, static void rtw_fw_send_h2c_command_register(struct rtw_dev *rtwdev,
u8 *h2c) struct rtw_h2c_register *h2c)
{ {
u8 box;
u8 box_state;
u32 box_reg, box_ex_reg; u32 box_reg, box_ex_reg;
int idx; u8 box_state, box;
int ret; int ret;
rtw_dbg(rtwdev, RTW_DBG_FW, rtw_dbg(rtwdev, RTW_DBG_FW, "send H2C content %08x %08x\n", h2c->w0,
"send H2C content %02x%02x%02x%02x %02x%02x%02x%02x\n", h2c->w1);
h2c[3], h2c[2], h2c[1], h2c[0],
h2c[7], h2c[6], h2c[5], h2c[4]);
spin_lock(&rtwdev->h2c.lock); lockdep_assert_held(&rtwdev->mutex);
box = rtwdev->h2c.last_box_num; box = rtwdev->h2c.last_box_num;
switch (box) { switch (box) {
@ -339,7 +340,7 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
break; break;
default: default:
WARN(1, "invalid h2c mail box number\n"); WARN(1, "invalid h2c mail box number\n");
goto out; return;
} }
ret = read_poll_timeout_atomic(rtw_read8, box_state, ret = read_poll_timeout_atomic(rtw_read8, box_state,
@ -348,19 +349,69 @@ static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
if (ret) { if (ret) {
rtw_err(rtwdev, "failed to send h2c command\n"); rtw_err(rtwdev, "failed to send h2c command\n");
goto out; return;
} }
for (idx = 0; idx < 4; idx++) rtw_write32(rtwdev, box_ex_reg, h2c->w1);
rtw_write8(rtwdev, box_reg + idx, h2c[idx]); rtw_write32(rtwdev, box_reg, h2c->w0);
for (idx = 0; idx < 4; idx++)
rtw_write8(rtwdev, box_ex_reg + idx, h2c[idx + 4]);
if (++rtwdev->h2c.last_box_num >= 4) if (++rtwdev->h2c.last_box_num >= 4)
rtwdev->h2c.last_box_num = 0; rtwdev->h2c.last_box_num = 0;
}
out: static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
spin_unlock(&rtwdev->h2c.lock); u8 *h2c)
{
struct rtw_h2c_cmd *h2c_cmd = (struct rtw_h2c_cmd *)h2c;
u8 box;
u8 box_state;
u32 box_reg, box_ex_reg;
int ret;
rtw_dbg(rtwdev, RTW_DBG_FW,
"send H2C content %02x%02x%02x%02x %02x%02x%02x%02x\n",
h2c[3], h2c[2], h2c[1], h2c[0],
h2c[7], h2c[6], h2c[5], h2c[4]);
lockdep_assert_held(&rtwdev->mutex);
box = rtwdev->h2c.last_box_num;
switch (box) {
case 0:
box_reg = REG_HMEBOX0;
box_ex_reg = REG_HMEBOX0_EX;
break;
case 1:
box_reg = REG_HMEBOX1;
box_ex_reg = REG_HMEBOX1_EX;
break;
case 2:
box_reg = REG_HMEBOX2;
box_ex_reg = REG_HMEBOX2_EX;
break;
case 3:
box_reg = REG_HMEBOX3;
box_ex_reg = REG_HMEBOX3_EX;
break;
default:
WARN(1, "invalid h2c mail box number\n");
return;
}
ret = read_poll_timeout_atomic(rtw_read8, box_state,
!((box_state >> box) & 0x1), 100, 3000,
false, rtwdev, REG_HMETFR);
if (ret) {
rtw_err(rtwdev, "failed to send h2c command\n");
return;
}
rtw_write32(rtwdev, box_ex_reg, le32_to_cpu(h2c_cmd->msg_ext));
rtw_write32(rtwdev, box_reg, le32_to_cpu(h2c_cmd->msg));
if (++rtwdev->h2c.last_box_num >= 4)
rtwdev->h2c.last_box_num = 0;
} }
void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c) void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c)
@ -372,15 +423,13 @@ static void rtw_fw_send_h2c_packet(struct rtw_dev *rtwdev, u8 *h2c_pkt)
{ {
int ret; int ret;
spin_lock(&rtwdev->h2c.lock); lockdep_assert_held(&rtwdev->mutex);
FW_OFFLOAD_H2C_SET_SEQ_NUM(h2c_pkt, rtwdev->h2c.seq); FW_OFFLOAD_H2C_SET_SEQ_NUM(h2c_pkt, rtwdev->h2c.seq);
ret = rtw_hci_write_data_h2c(rtwdev, h2c_pkt, H2C_PKT_SIZE); ret = rtw_hci_write_data_h2c(rtwdev, h2c_pkt, H2C_PKT_SIZE);
if (ret) if (ret)
rtw_err(rtwdev, "failed to send h2c packet\n"); rtw_err(rtwdev, "failed to send h2c packet\n");
rtwdev->h2c.seq++; rtwdev->h2c.seq++;
spin_unlock(&rtwdev->h2c.lock);
} }
void void
@ -470,6 +519,23 @@ void rtw_fw_query_bt_info(struct rtw_dev *rtwdev)
rtw_fw_send_h2c_command(rtwdev, h2c_pkt); rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
} }
void rtw_fw_default_port(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif)
{
struct rtw_h2c_register h2c = {};
if (rtwvif->net_type != RTW_NET_MGD_LINKED)
return;
/* Leave LPS before default port H2C so FW timer is correct */
rtw_leave_lps(rtwdev);
h2c.w0 = u32_encode_bits(H2C_CMD_DEFAULT_PORT, RTW_H2C_W0_CMDID) |
u32_encode_bits(rtwvif->port, RTW_H2C_DEFAULT_PORT_W0_PORTID) |
u32_encode_bits(rtwvif->mac_id, RTW_H2C_DEFAULT_PORT_W0_MACID);
rtw_fw_send_h2c_command_register(rtwdev, &h2c);
}
void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw) void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw)
{ {
u8 h2c_pkt[H2C_PKT_SIZE] = {0}; u8 h2c_pkt[H2C_PKT_SIZE] = {0};
@ -538,6 +604,18 @@ void rtw_fw_coex_tdma_type(struct rtw_dev *rtwdev,
rtw_fw_send_h2c_command(rtwdev, h2c_pkt); rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
} }
void rtw_fw_coex_query_hid_info(struct rtw_dev *rtwdev, u8 sub_id, u8 data)
{
u8 h2c_pkt[H2C_PKT_SIZE] = {0};
SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_QUERY_BT_HID_INFO);
SET_COEX_QUERY_HID_INFO_SUBID(h2c_pkt, sub_id);
SET_COEX_QUERY_HID_INFO_DATA1(h2c_pkt, data);
rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
}
void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data) void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data)
{ {
u8 h2c_pkt[H2C_PKT_SIZE] = {0}; u8 h2c_pkt[H2C_PKT_SIZE] = {0};
@ -570,10 +648,10 @@ void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si)
rtw_fw_send_h2c_command(rtwdev, h2c_pkt); rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
} }
void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
bool reset_ra_mask)
{ {
u8 h2c_pkt[H2C_PKT_SIZE] = {0}; u8 h2c_pkt[H2C_PKT_SIZE] = {0};
bool no_update = si->updated;
bool disable_pt = true; bool disable_pt = true;
SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_RA_INFO); SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_RA_INFO);
@ -584,7 +662,7 @@ void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si)
SET_RA_INFO_SGI_EN(h2c_pkt, si->sgi_enable); SET_RA_INFO_SGI_EN(h2c_pkt, si->sgi_enable);
SET_RA_INFO_BW_MODE(h2c_pkt, si->bw_mode); SET_RA_INFO_BW_MODE(h2c_pkt, si->bw_mode);
SET_RA_INFO_LDPC(h2c_pkt, !!si->ldpc_en); SET_RA_INFO_LDPC(h2c_pkt, !!si->ldpc_en);
SET_RA_INFO_NO_UPDATE(h2c_pkt, no_update); SET_RA_INFO_NO_UPDATE(h2c_pkt, !reset_ra_mask);
SET_RA_INFO_VHT_EN(h2c_pkt, si->vht_enable); SET_RA_INFO_VHT_EN(h2c_pkt, si->vht_enable);
SET_RA_INFO_DIS_PT(h2c_pkt, disable_pt); SET_RA_INFO_DIS_PT(h2c_pkt, disable_pt);
SET_RA_INFO_RA_MASK0(h2c_pkt, (si->ra_mask & 0xff)); SET_RA_INFO_RA_MASK0(h2c_pkt, (si->ra_mask & 0xff));
@ -593,7 +671,6 @@ void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si)
SET_RA_INFO_RA_MASK3(h2c_pkt, (si->ra_mask & 0xff000000) >> 24); SET_RA_INFO_RA_MASK3(h2c_pkt, (si->ra_mask & 0xff000000) >> 24);
si->init_ra_lv = 0; si->init_ra_lv = 0;
si->updated = true;
rtw_fw_send_h2c_command(rtwdev, h2c_pkt); rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
} }
@ -635,7 +712,7 @@ void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect,
s32 threshold = bss_conf->cqm_rssi_thold + rssi_offset; s32 threshold = bss_conf->cqm_rssi_thold + rssi_offset;
u8 h2c_pkt[H2C_PKT_SIZE] = {0}; u8 h2c_pkt[H2C_PKT_SIZE] = {0};
if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER) || !si) if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER))
return; return;
if (!connect) { if (!connect) {
@ -645,6 +722,10 @@ void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect,
return; return;
} }
if (!si)
return;
SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P0); SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P0);
ether_addr_copy(&h2c_pkt[1], bss_conf->bssid); ether_addr_copy(&h2c_pkt[1], bss_conf->bssid);
rtw_fw_send_h2c_command(rtwdev, h2c_pkt); rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
@ -804,6 +885,16 @@ void rtw_fw_set_nlo_info(struct rtw_dev *rtwdev, bool enable)
rtw_fw_send_h2c_command(rtwdev, h2c_pkt); rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
} }
void rtw_fw_set_recover_bt_device(struct rtw_dev *rtwdev)
{
u8 h2c_pkt[H2C_PKT_SIZE] = {0};
SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_RECOVER_BT_DEV);
SET_RECOVER_BT_DEV_EN(h2c_pkt, 1);
rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
}
void rtw_fw_set_pg_info(struct rtw_dev *rtwdev) void rtw_fw_set_pg_info(struct rtw_dev *rtwdev)
{ {
struct rtw_lps_conf *conf = &rtwdev->lps_conf; struct rtw_lps_conf *conf = &rtwdev->lps_conf;
@ -886,7 +977,7 @@ void rtw_send_rsvd_page_h2c(struct rtw_dev *rtwdev)
static struct sk_buff *rtw_nlo_info_get(struct ieee80211_hw *hw) static struct sk_buff *rtw_nlo_info_get(struct ieee80211_hw *hw)
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_pno_request *pno_req = &rtwdev->wow.pno_req; struct rtw_pno_request *pno_req = &rtwdev->wow.pno_req;
struct rtw_nlo_info_hdr *nlo_hdr; struct rtw_nlo_info_hdr *nlo_hdr;
struct cfg80211_ssid *ssid; struct cfg80211_ssid *ssid;
@ -941,7 +1032,7 @@ static struct sk_buff *rtw_nlo_info_get(struct ieee80211_hw *hw)
static struct sk_buff *rtw_cs_channel_info_get(struct ieee80211_hw *hw) static struct sk_buff *rtw_cs_channel_info_get(struct ieee80211_hw *hw)
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_pno_request *pno_req = &rtwdev->wow.pno_req; struct rtw_pno_request *pno_req = &rtwdev->wow.pno_req;
struct ieee80211_channel *channels = pno_req->channels; struct ieee80211_channel *channels = pno_req->channels;
struct sk_buff *skb; struct sk_buff *skb;
@ -975,7 +1066,7 @@ static struct sk_buff *rtw_cs_channel_info_get(struct ieee80211_hw *hw)
static struct sk_buff *rtw_lps_pg_dpk_get(struct ieee80211_hw *hw) static struct sk_buff *rtw_lps_pg_dpk_get(struct ieee80211_hw *hw)
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info; struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info;
struct rtw_lps_pg_dpk_hdr *dpk_hdr; struct rtw_lps_pg_dpk_hdr *dpk_hdr;
struct sk_buff *skb; struct sk_buff *skb;
@ -1000,7 +1091,7 @@ static struct sk_buff *rtw_lps_pg_dpk_get(struct ieee80211_hw *hw)
static struct sk_buff *rtw_lps_pg_info_get(struct ieee80211_hw *hw) static struct sk_buff *rtw_lps_pg_info_get(struct ieee80211_hw *hw)
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_lps_conf *conf = &rtwdev->lps_conf; struct rtw_lps_conf *conf = &rtwdev->lps_conf;
struct rtw_lps_pg_info_hdr *pg_info_hdr; struct rtw_lps_pg_info_hdr *pg_info_hdr;
struct rtw_wow_param *rtw_wow = &rtwdev->wow; struct rtw_wow_param *rtw_wow = &rtwdev->wow;
@ -1033,6 +1124,7 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw,
struct rtw_vif *rtwvif; struct rtw_vif *rtwvif;
struct sk_buff *skb_new; struct sk_buff *skb_new;
struct cfg80211_ssid *ssid; struct cfg80211_ssid *ssid;
u16 tim_offset = 0;
if (rsvd_pkt->type == RSVD_DUMMY) { if (rsvd_pkt->type == RSVD_DUMMY) {
skb_new = alloc_skb(1, GFP_KERNEL); skb_new = alloc_skb(1, GFP_KERNEL);
@ -1051,7 +1143,8 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw,
switch (rsvd_pkt->type) { switch (rsvd_pkt->type) {
case RSVD_BEACON: case RSVD_BEACON:
skb_new = ieee80211_beacon_get(hw, vif); skb_new = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL, 0);
rsvd_pkt->tim_offset = tim_offset;
break; break;
case RSVD_PS_POLL: case RSVD_PS_POLL:
skb_new = ieee80211_pspoll_get(hw, vif); skb_new = ieee80211_pspoll_get(hw, vif);
@ -1060,10 +1153,10 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw,
skb_new = ieee80211_proberesp_get(hw, vif); skb_new = ieee80211_proberesp_get(hw, vif);
break; break;
case RSVD_NULL: case RSVD_NULL:
skb_new = ieee80211_nullfunc_get(hw, vif, false); skb_new = ieee80211_nullfunc_get(hw, vif, -1, false);
break; break;
case RSVD_QOS_NULL: case RSVD_QOS_NULL:
skb_new = ieee80211_nullfunc_get(hw, vif, true); skb_new = ieee80211_nullfunc_get(hw, vif, -1, true);
break; break;
case RSVD_LPS_PG_DPK: case RSVD_LPS_PG_DPK:
skb_new = rtw_lps_pg_dpk_get(hw); skb_new = rtw_lps_pg_dpk_get(hw);
@ -1102,7 +1195,7 @@ static void rtw_fill_rsvd_page_desc(struct rtw_dev *rtwdev, struct sk_buff *skb,
enum rtw_rsvd_packet_type type) enum rtw_rsvd_packet_type type)
{ {
struct rtw_tx_pkt_info pkt_info = {0}; struct rtw_tx_pkt_info pkt_info = {0};
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
u8 *pkt_desc; u8 *pkt_desc;
rtw_tx_rsvd_page_pkt_info_update(rtwdev, &pkt_info, skb, type); rtw_tx_rsvd_page_pkt_info_update(rtwdev, &pkt_info, skb, type);
@ -1368,6 +1461,10 @@ static void rtw_build_rsvd_page_iter(void *data, u8 *mac,
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
struct rtw_rsvd_page *rsvd_pkt; struct rtw_rsvd_page *rsvd_pkt;
/* AP not yet started, don't gather its rsvd pages */
if (vif->type == NL80211_IFTYPE_AP && !rtwdev->ap_active)
return;
list_for_each_entry(rsvd_pkt, &rtwvif->rsvd_page_list, vif_list) { list_for_each_entry(rsvd_pkt, &rtwvif->rsvd_page_list, vif_list) {
if (rsvd_pkt->type == RSVD_BEACON) if (rsvd_pkt->type == RSVD_BEACON)
list_add(&rsvd_pkt->build_list, list_add(&rsvd_pkt->build_list,
@ -1413,7 +1510,7 @@ static int __rtw_build_rsvd_page_from_vifs(struct rtw_dev *rtwdev)
static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, u32 *size) static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, u32 *size)
{ {
struct ieee80211_hw *hw = rtwdev->hw; struct ieee80211_hw *hw = rtwdev->hw;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct sk_buff *iter; struct sk_buff *iter;
struct rtw_rsvd_page *rsvd_pkt; struct rtw_rsvd_page *rsvd_pkt;
u32 page = 0; u32 page = 0;
@ -1582,6 +1679,17 @@ int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev)
return ret; return ret;
} }
void rtw_fw_update_beacon_work(struct work_struct *work)
{
struct rtw_dev *rtwdev = container_of(work, struct rtw_dev,
update_beacon_work);
mutex_lock(&rtwdev->mutex);
rtw_fw_download_rsvd_page(rtwdev);
rtw_send_rsvd_page_h2c(rtwdev);
mutex_unlock(&rtwdev->mutex);
}
static void rtw_fw_read_fifo_page(struct rtw_dev *rtwdev, u32 offset, u32 size, static void rtw_fw_read_fifo_page(struct rtw_dev *rtwdev, u32 offset, u32 size,
u32 *buf, u32 residue, u16 start_pg) u32 *buf, u32 residue, u16 start_pg)
{ {
@ -1617,7 +1725,7 @@ static void rtw_fw_read_fifo_page(struct rtw_dev *rtwdev, u32 offset, u32 size,
static void rtw_fw_read_fifo(struct rtw_dev *rtwdev, enum rtw_fw_fifo_sel sel, static void rtw_fw_read_fifo(struct rtw_dev *rtwdev, enum rtw_fw_fifo_sel sel,
u32 offset, u32 size, u32 *buf) u32 offset, u32 size, u32 *buf)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
u32 start_pg, residue; u32 start_pg, residue;
if (sel >= RTW_FW_FIFO_MAX) { if (sel >= RTW_FW_FIFO_MAX) {
@ -1676,7 +1784,7 @@ int rtw_fw_dump_fifo(struct rtw_dev *rtwdev, u8 fifo_sel, u32 addr, u32 size,
static void __rtw_fw_update_pkt(struct rtw_dev *rtwdev, u8 pkt_id, u16 size, static void __rtw_fw_update_pkt(struct rtw_dev *rtwdev, u8 pkt_id, u16 size,
u8 location) u8 location)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
u8 h2c_pkt[H2C_PKT_SIZE] = {0}; u8 h2c_pkt[H2C_PKT_SIZE] = {0};
u16 total_size = H2C_PKT_HDR_SIZE + H2C_PKT_UPDATE_PKT_LEN; u16 total_size = H2C_PKT_HDR_SIZE + H2C_PKT_UPDATE_PKT_LEN;
@ -1766,7 +1874,7 @@ void rtw_fw_adaptivity(struct rtw_dev *rtwdev)
SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_ADAPTIVITY); SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_ADAPTIVITY);
SET_ADAPTIVITY_MODE(h2c_pkt, dm_info->edcca_mode); SET_ADAPTIVITY_MODE(h2c_pkt, dm_info->edcca_mode);
SET_ADAPTIVITY_OPTION(h2c_pkt, 2); SET_ADAPTIVITY_OPTION(h2c_pkt, 1);
SET_ADAPTIVITY_IGI(h2c_pkt, dm_info->igi_history[0]); SET_ADAPTIVITY_IGI(h2c_pkt, dm_info->igi_history[0]);
SET_ADAPTIVITY_L2H(h2c_pkt, dm_info->l2h_th_ini); SET_ADAPTIVITY_L2H(h2c_pkt, dm_info->l2h_th_ini);
SET_ADAPTIVITY_DENSITY(h2c_pkt, dm_info->scan_density); SET_ADAPTIVITY_DENSITY(h2c_pkt, dm_info->scan_density);
@ -1784,12 +1892,12 @@ void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start)
rtw_fw_send_h2c_command(rtwdev, h2c_pkt); rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
} }
static void rtw_append_probe_req_ie(struct rtw_dev *rtwdev, struct sk_buff *skb, static int rtw_append_probe_req_ie(struct rtw_dev *rtwdev, struct sk_buff *skb,
struct sk_buff_head *list, struct sk_buff_head *list, u8 *bands,
struct rtw_vif *rtwvif) struct rtw_vif *rtwvif)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct ieee80211_scan_ies *ies = rtwvif->scan_ies; struct ieee80211_scan_ies *ies = rtwvif->scan_ies;
struct rtw_chip_info *chip = rtwdev->chip;
struct sk_buff *new; struct sk_buff *new;
u8 idx; u8 idx;
@ -1797,25 +1905,37 @@ static void rtw_append_probe_req_ie(struct rtw_dev *rtwdev, struct sk_buff *skb,
if (!(BIT(idx) & chip->band)) if (!(BIT(idx) & chip->band))
continue; continue;
new = skb_copy(skb, GFP_KERNEL); new = skb_copy(skb, GFP_KERNEL);
if (!new)
return -ENOMEM;
skb_put_data(new, ies->ies[idx], ies->len[idx]); skb_put_data(new, ies->ies[idx], ies->len[idx]);
skb_put_data(new, ies->common_ies, ies->common_ie_len); skb_put_data(new, ies->common_ies, ies->common_ie_len);
skb_queue_tail(list, new); skb_queue_tail(list, new);
} (*bands)++;
} }
static int _rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, u8 num_ssids, return 0;
}
static int _rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, u8 num_probes,
struct sk_buff_head *probe_req_list) struct sk_buff_head *probe_req_list)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct sk_buff *skb, *tmp; struct sk_buff *skb, *tmp;
u8 page_offset = 1, *buf, page_size = chip->page_size; u8 page_offset = 1, *buf, page_size = chip->page_size;
u8 pages = page_offset + num_ssids * RTW_PROBE_PG_CNT;
u16 pg_addr = rtwdev->fifo.rsvd_h2c_info_addr, loc; u16 pg_addr = rtwdev->fifo.rsvd_h2c_info_addr, loc;
u16 buf_offset = page_size * page_offset; u16 buf_offset = page_size * page_offset;
u8 tx_desc_sz = chip->tx_pkt_desc_sz; u8 tx_desc_sz = chip->tx_pkt_desc_sz;
u8 page_cnt, pages;
unsigned int pkt_len; unsigned int pkt_len;
int ret; int ret;
if (rtw_fw_feature_ext_check(&rtwdev->fw, FW_FEATURE_EXT_OLD_PAGE_NUM))
page_cnt = RTW_OLD_PROBE_PG_CNT;
else
page_cnt = RTW_PROBE_PG_CNT;
pages = page_offset + num_probes * page_cnt;
buf = kzalloc(page_size * pages, GFP_KERNEL); buf = kzalloc(page_size * pages, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
@ -1824,7 +1944,7 @@ static int _rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, u8 num_ssids,
skb_queue_walk_safe(probe_req_list, skb, tmp) { skb_queue_walk_safe(probe_req_list, skb, tmp) {
skb_unlink(skb, probe_req_list); skb_unlink(skb, probe_req_list);
rtw_fill_rsvd_page_desc(rtwdev, skb, RSVD_PROBE_REQ); rtw_fill_rsvd_page_desc(rtwdev, skb, RSVD_PROBE_REQ);
if (skb->len > page_size * RTW_PROBE_PG_CNT) { if (skb->len > page_size * page_cnt) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
@ -1834,8 +1954,8 @@ static int _rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, u8 num_ssids,
loc = pg_addr - rtwdev->fifo.rsvd_boundary + page_offset; loc = pg_addr - rtwdev->fifo.rsvd_boundary + page_offset;
__rtw_fw_update_pkt(rtwdev, RTW_PACKET_PROBE_REQ, pkt_len, loc); __rtw_fw_update_pkt(rtwdev, RTW_PACKET_PROBE_REQ, pkt_len, loc);
buf_offset += RTW_PROBE_PG_CNT * page_size; buf_offset += page_cnt * page_size;
page_offset += RTW_PROBE_PG_CNT; page_offset += page_cnt;
kfree_skb(skb); kfree_skb(skb);
} }
@ -1848,6 +1968,8 @@ static int _rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, u8 num_ssids,
rtwdev->scan_info.probe_pg_size = page_offset; rtwdev->scan_info.probe_pg_size = page_offset;
out: out:
kfree(buf); kfree(buf);
skb_queue_walk_safe(probe_req_list, skb, tmp)
kfree_skb(skb);
return ret; return ret;
} }
@ -1857,8 +1979,9 @@ static int rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev,
{ {
struct cfg80211_scan_request *req = rtwvif->scan_req; struct cfg80211_scan_request *req = rtwvif->scan_req;
struct sk_buff_head list; struct sk_buff_head list;
struct sk_buff *skb; struct sk_buff *skb, *tmp;
u8 num = req->n_ssids, i; u8 num = req->n_ssids, i, bands = 0;
int ret;
skb_queue_head_init(&list); skb_queue_head_init(&list);
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
@ -1866,11 +1989,25 @@ static int rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev,
req->ssids[i].ssid, req->ssids[i].ssid,
req->ssids[i].ssid_len, req->ssids[i].ssid_len,
req->ie_len); req->ie_len);
rtw_append_probe_req_ie(rtwdev, skb, &list, rtwvif); if (!skb) {
ret = -ENOMEM;
goto out;
}
ret = rtw_append_probe_req_ie(rtwdev, skb, &list, &bands,
rtwvif);
if (ret)
goto out;
kfree_skb(skb); kfree_skb(skb);
} }
return _rtw_hw_scan_update_probe_req(rtwdev, num, &list); return _rtw_hw_scan_update_probe_req(rtwdev, num * bands, &list);
out:
skb_queue_walk_safe(&list, skb, tmp)
kfree_skb(skb);
return ret;
} }
static int rtw_add_chan_info(struct rtw_dev *rtwdev, struct rtw_chan_info *info, static int rtw_add_chan_info(struct rtw_dev *rtwdev, struct rtw_chan_info *info,
@ -1996,6 +2133,9 @@ void rtw_hw_scan_start(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
rtwvif->scan_req = req; rtwvif->scan_req = req;
ieee80211_stop_queues(rtwdev->hw); ieee80211_stop_queues(rtwdev->hw);
rtw_leave_lps_deep(rtwdev);
rtw_hci_flush_all_queues(rtwdev, false);
rtw_mac_flush_all_queues(rtwdev, false);
if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
get_random_mask_addr(mac_addr, req->mac_addr, get_random_mask_addr(mac_addr, req->mac_addr,
req->mac_addr_mask); req->mac_addr_mask);
@ -2014,7 +2154,10 @@ void rtw_hw_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct cfg80211_scan_info info = { struct cfg80211_scan_info info = {
.aborted = aborted, .aborted = aborted,
}; };
struct rtw_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw_hal *hal = &rtwdev->hal;
struct rtw_vif *rtwvif; struct rtw_vif *rtwvif;
u8 chan = scan_info->op_chan;
if (!vif) if (!vif)
return; return;
@ -2022,12 +2165,15 @@ void rtw_hw_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
rtwdev->hal.rcr |= BIT_CBSSID_BCN; rtwdev->hal.rcr |= BIT_CBSSID_BCN;
rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr); rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr);
rtw_core_scan_complete(rtwdev, vif); rtw_core_scan_complete(rtwdev, vif, true);
rtwvif = (struct rtw_vif *)vif->drv_priv;
if (chan)
rtw_store_op_chan(rtwdev, false);
rtw_phy_set_tx_power_level(rtwdev, hal->current_channel);
ieee80211_wake_queues(rtwdev->hw); ieee80211_wake_queues(rtwdev->hw);
ieee80211_scan_completed(rtwdev->hw, &info); ieee80211_scan_completed(rtwdev->hw, &info);
rtwvif = (struct rtw_vif *)vif->drv_priv;
rtwvif->scan_req = NULL; rtwvif->scan_req = NULL;
rtwvif->scan_ies = NULL; rtwvif->scan_ies = NULL;
rtwdev->scan_info.scanning_vif = NULL; rtwdev->scan_info.scanning_vif = NULL;
@ -2065,6 +2211,7 @@ int rtw_hw_scan_offload(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
bool enable) bool enable)
{ {
struct rtw_vif *rtwvif = vif ? (struct rtw_vif *)vif->drv_priv : NULL; struct rtw_vif *rtwvif = vif ? (struct rtw_vif *)vif->drv_priv : NULL;
struct rtw_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw_ch_switch_option cs_option = {0}; struct rtw_ch_switch_option cs_option = {0};
struct rtw_chan_list chan_list = {0}; struct rtw_chan_list chan_list = {0};
int ret = 0; int ret = 0;
@ -2073,7 +2220,7 @@ int rtw_hw_scan_offload(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
return -EINVAL; return -EINVAL;
cs_option.switch_en = enable; cs_option.switch_en = enable;
cs_option.back_op_en = rtwvif->net_type == RTW_NET_MGD_LINKED; cs_option.back_op_en = scan_info->op_chan != 0;
if (enable) { if (enable) {
ret = rtw_hw_scan_prehandle(rtwdev, rtwvif, &chan_list); ret = rtw_hw_scan_prehandle(rtwdev, rtwvif, &chan_list);
if (ret) if (ret)
@ -2081,11 +2228,19 @@ int rtw_hw_scan_offload(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
} }
rtw_fw_set_scan_offload(rtwdev, &cs_option, rtwvif, &chan_list); rtw_fw_set_scan_offload(rtwdev, &cs_option, rtwvif, &chan_list);
out: out:
if (rtwdev->ap_active) {
ret = rtw_download_beacon(rtwdev);
if (ret)
rtw_err(rtwdev, "HW scan download beacon failed\n");
}
return ret; return ret;
} }
void rtw_hw_scan_abort(struct rtw_dev *rtwdev, struct ieee80211_vif *vif) void rtw_hw_scan_abort(struct rtw_dev *rtwdev)
{ {
struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD)) if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD))
return; return;
@ -2109,17 +2264,36 @@ void rtw_hw_scan_status_report(struct rtw_dev *rtwdev, struct sk_buff *skb)
rtw_hw_scan_complete(rtwdev, vif, aborted); rtw_hw_scan_complete(rtwdev, vif, aborted);
if (aborted) if (aborted)
rtw_info(rtwdev, "HW scan aborted with code: %d\n", rc); rtw_dbg(rtwdev, RTW_DBG_HW_SCAN, "HW scan aborted with code: %d\n", rc);
} }
void rtw_store_op_chan(struct rtw_dev *rtwdev) void rtw_store_op_chan(struct rtw_dev *rtwdev, bool backup)
{ {
struct rtw_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw_hal *hal = &rtwdev->hal; struct rtw_hal *hal = &rtwdev->hal;
u8 band;
if (backup) {
scan_info->op_chan = hal->current_channel; scan_info->op_chan = hal->current_channel;
scan_info->op_bw = hal->current_band_width; scan_info->op_bw = hal->current_band_width;
scan_info->op_pri_ch_idx = hal->current_primary_channel_index; scan_info->op_pri_ch_idx = hal->current_primary_channel_index;
scan_info->op_pri_ch = hal->primary_channel;
} else {
band = scan_info->op_chan > 14 ? RTW_BAND_5G : RTW_BAND_2G;
rtw_update_channel(rtwdev, scan_info->op_chan,
scan_info->op_pri_ch,
band, scan_info->op_bw);
}
}
void rtw_clear_op_chan(struct rtw_dev *rtwdev)
{
struct rtw_hw_scan_info *scan_info = &rtwdev->scan_info;
scan_info->op_chan = 0;
scan_info->op_bw = 0;
scan_info->op_pri_ch_idx = 0;
scan_info->op_pri_ch = 0;
} }
static bool rtw_is_op_chan(struct rtw_dev *rtwdev, u8 channel) static bool rtw_is_op_chan(struct rtw_dev *rtwdev, u8 channel)
@ -2134,7 +2308,10 @@ void rtw_hw_scan_chan_switch(struct rtw_dev *rtwdev, struct sk_buff *skb)
struct rtw_hal *hal = &rtwdev->hal; struct rtw_hal *hal = &rtwdev->hal;
struct rtw_c2h_cmd *c2h; struct rtw_c2h_cmd *c2h;
enum rtw_scan_notify_id id; enum rtw_scan_notify_id id;
u8 chan, status; u8 chan, band, status;
if (!test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
return;
c2h = get_c2h_from_skb(skb); c2h = get_c2h_from_skb(skb);
chan = GET_CHAN_SWITCH_CENTRAL_CH(c2h->payload); chan = GET_CHAN_SWITCH_CENTRAL_CH(c2h->payload);
@ -2142,10 +2319,14 @@ void rtw_hw_scan_chan_switch(struct rtw_dev *rtwdev, struct sk_buff *skb)
status = GET_CHAN_SWITCH_STATUS(c2h->payload); status = GET_CHAN_SWITCH_STATUS(c2h->payload);
if (id == RTW_SCAN_NOTIFY_ID_POSTSWITCH) { if (id == RTW_SCAN_NOTIFY_ID_POSTSWITCH) {
if (rtw_is_op_chan(rtwdev, chan)) band = chan > 14 ? RTW_BAND_5G : RTW_BAND_2G;
rtw_update_channel(rtwdev, chan, chan, band,
RTW_CHANNEL_WIDTH_20);
if (rtw_is_op_chan(rtwdev, chan)) {
rtw_store_op_chan(rtwdev, false);
ieee80211_wake_queues(rtwdev->hw); ieee80211_wake_queues(rtwdev->hw);
hal->current_channel = chan; rtw_core_enable_beacon(rtwdev, true);
hal->current_band_type = chan > 14 ? RTW_BAND_5G : RTW_BAND_2G; }
} else if (id == RTW_SCAN_NOTIFY_ID_PRESWITCH) { } else if (id == RTW_SCAN_NOTIFY_ID_PRESWITCH) {
if (IS_CH_5G_BAND(chan)) { if (IS_CH_5G_BAND(chan)) {
rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_5G); rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_5G);
@ -2158,9 +2339,16 @@ void rtw_hw_scan_chan_switch(struct rtw_dev *rtwdev, struct sk_buff *skb)
chan_type = COEX_SWITCH_TO_24G_NOFORSCAN; chan_type = COEX_SWITCH_TO_24G_NOFORSCAN;
rtw_coex_switchband_notify(rtwdev, chan_type); rtw_coex_switchband_notify(rtwdev, chan_type);
} }
if (rtw_is_op_chan(rtwdev, chan)) /* The channel of C2H RTW_SCAN_NOTIFY_ID_PRESWITCH is next
* channel that hardware will switch. We need to stop queue
* if next channel is non-op channel.
*/
if (!rtw_is_op_chan(rtwdev, chan) &&
rtw_is_op_chan(rtwdev, hal->current_channel)) {
rtw_core_enable_beacon(rtwdev, false);
ieee80211_stop_queues(rtwdev->hw); ieee80211_stop_queues(rtwdev->hw);
} }
}
rtw_dbg(rtwdev, RTW_DBG_HW_SCAN, rtw_dbg(rtwdev, RTW_DBG_HW_SCAN,
"Chan switch: %x, id: %x, status: %x\n", chan, id, status); "Chan switch: %x, id: %x, status: %x\n", chan, id, status);

61
fw.h
View file

@ -41,12 +41,14 @@
#define RTW_EX_CH_INFO_HDR_SIZE 2 #define RTW_EX_CH_INFO_HDR_SIZE 2
#define RTW_SCAN_WIDTH 0 #define RTW_SCAN_WIDTH 0
#define RTW_PRI_CH_IDX 1 #define RTW_PRI_CH_IDX 1
#define RTW_PROBE_PG_CNT 2 #define RTW_OLD_PROBE_PG_CNT 2
#define RTW_PROBE_PG_CNT 4
enum rtw_c2h_cmd_id { enum rtw_c2h_cmd_id {
C2H_CCX_TX_RPT = 0x03, C2H_CCX_TX_RPT = 0x03,
C2H_BT_INFO = 0x09, C2H_BT_INFO = 0x09,
C2H_BT_MP_INFO = 0x0b, C2H_BT_MP_INFO = 0x0b,
C2H_BT_HID_INFO = 0x45,
C2H_RA_RPT = 0x0c, C2H_RA_RPT = 0x0c,
C2H_HW_FEATURE_REPORT = 0x19, C2H_HW_FEATURE_REPORT = 0x19,
C2H_WLAN_INFO = 0x27, C2H_WLAN_INFO = 0x27,
@ -79,6 +81,22 @@ struct rtw_c2h_adaptivity {
u8 option; u8 option;
} __packed; } __packed;
struct rtw_h2c_register {
u32 w0;
u32 w1;
} __packed;
#define RTW_H2C_W0_CMDID GENMASK(7, 0)
/* H2C_CMD_DEFAULT_PORT command */
#define RTW_H2C_DEFAULT_PORT_W0_PORTID GENMASK(15, 8)
#define RTW_H2C_DEFAULT_PORT_W0_MACID GENMASK(23, 16)
struct rtw_h2c_cmd {
__le32 msg;
__le32 msg_ext;
} __packed;
enum rtw_rsvd_packet_type { enum rtw_rsvd_packet_type {
RSVD_BEACON, RSVD_BEACON,
RSVD_DUMMY, RSVD_DUMMY,
@ -119,6 +137,10 @@ enum rtw_fw_feature {
FW_FEATURE_MAX = BIT(31), FW_FEATURE_MAX = BIT(31),
}; };
enum rtw_fw_feature_ext {
FW_FEATURE_EXT_OLD_PAGE_NUM = BIT(0),
};
enum rtw_beacon_filter_offload_mode { enum rtw_beacon_filter_offload_mode {
BCN_FILTER_OFFLOAD_MODE_0 = 0, BCN_FILTER_OFFLOAD_MODE_0 = 0,
BCN_FILTER_OFFLOAD_MODE_1, BCN_FILTER_OFFLOAD_MODE_1,
@ -171,6 +193,7 @@ struct rtw_rsvd_page {
struct sk_buff *skb; struct sk_buff *skb;
enum rtw_rsvd_packet_type type; enum rtw_rsvd_packet_type type;
u8 page; u8 page;
u16 tim_offset;
bool add_txdesc; bool add_txdesc;
struct cfg80211_ssid *ssid; struct cfg80211_ssid *ssid;
u16 probe_req_size; u16 probe_req_size;
@ -321,6 +344,11 @@ struct rtw_fw_hdr_legacy {
__le32 rsvd5; __le32 rsvd5;
} __packed; } __packed;
#define RTW_FW_VER_CODE(ver, sub_ver, idx) \
(((ver) << 16) | ((sub_ver) << 8) | (idx))
#define RTW_FW_SUIT_VER_CODE(s) \
RTW_FW_VER_CODE((s).version, (s).sub_version, (s).sub_index)
/* C2H */ /* C2H */
#define GET_CCX_REPORT_SEQNUM_V0(c2h_payload) (c2h_payload[6] & 0xfc) #define GET_CCX_REPORT_SEQNUM_V0(c2h_payload) (c2h_payload[6] & 0xfc)
#define GET_CCX_REPORT_STATUS_V0(c2h_payload) (c2h_payload[0] & 0xc0) #define GET_CCX_REPORT_STATUS_V0(c2h_payload) (c2h_payload[0] & 0xc0)
@ -513,6 +541,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define H2C_CMD_MEDIA_STATUS_RPT 0x01 #define H2C_CMD_MEDIA_STATUS_RPT 0x01
#define H2C_CMD_SET_PWR_MODE 0x20 #define H2C_CMD_SET_PWR_MODE 0x20
#define H2C_CMD_LPS_PG_INFO 0x2b #define H2C_CMD_LPS_PG_INFO 0x2b
#define H2C_CMD_DEFAULT_PORT 0x2c
#define H2C_CMD_RA_INFO 0x40 #define H2C_CMD_RA_INFO 0x40
#define H2C_CMD_RSSI_MONITOR 0x42 #define H2C_CMD_RSSI_MONITOR 0x42
#define H2C_CMD_BCN_FILTER_OFFLOAD_P0 0x56 #define H2C_CMD_BCN_FILTER_OFFLOAD_P0 0x56
@ -529,6 +558,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define H2C_CMD_QUERY_BT_MP_INFO 0x67 #define H2C_CMD_QUERY_BT_MP_INFO 0x67
#define H2C_CMD_BT_WIFI_CONTROL 0x69 #define H2C_CMD_BT_WIFI_CONTROL 0x69
#define H2C_CMD_WIFI_CALIBRATION 0x6d #define H2C_CMD_WIFI_CALIBRATION 0x6d
#define H2C_CMD_QUERY_BT_HID_INFO 0x73
#define H2C_CMD_KEEP_ALIVE 0x03 #define H2C_CMD_KEEP_ALIVE 0x03
#define H2C_CMD_DISCONNECT_DECISION 0x04 #define H2C_CMD_DISCONNECT_DECISION 0x04
@ -537,6 +567,8 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define H2C_CMD_AOAC_GLOBAL_INFO 0x82 #define H2C_CMD_AOAC_GLOBAL_INFO 0x82
#define H2C_CMD_NLO_INFO 0x8C #define H2C_CMD_NLO_INFO 0x8C
#define H2C_CMD_RECOVER_BT_DEV 0xD1
#define SET_H2C_CMD_ID_CLASS(h2c_pkt, value) \ #define SET_H2C_CMD_ID_CLASS(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(7, 0)) le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(7, 0))
@ -681,6 +713,11 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define SET_BT_WIFI_CONTROL_DATA5(h2c_pkt, value) \ #define SET_BT_WIFI_CONTROL_DATA5(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16)) le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16))
#define SET_COEX_QUERY_HID_INFO_SUBID(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8))
#define SET_COEX_QUERY_HID_INFO_DATA1(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_KEEP_ALIVE_ENABLE(h2c_pkt, value) \ #define SET_KEEP_ALIVE_ENABLE(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8)) le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define SET_KEEP_ALIVE_ADOPT(h2c_pkt, value) \ #define SET_KEEP_ALIVE_ADOPT(h2c_pkt, value) \
@ -731,6 +768,9 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define SET_NLO_LOC_NLO_INFO(h2c_pkt, value) \ #define SET_NLO_LOC_NLO_INFO(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16)) le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16))
#define SET_RECOVER_BT_DEV_EN(h2c_pkt, value) \
le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
#define GET_FW_DUMP_LEN(_header) \ #define GET_FW_DUMP_LEN(_header) \
le32_get_bits(*((__le32 *)(_header) + 0x00), GENMASK(15, 0)) le32_get_bits(*((__le32 *)(_header) + 0x00), GENMASK(15, 0))
#define GET_FW_DUMP_SEQ(_header) \ #define GET_FW_DUMP_SEQ(_header) \
@ -762,11 +802,18 @@ static inline bool rtw_fw_feature_check(struct rtw_fw_state *fw,
return !!(fw->feature & feature); return !!(fw->feature & feature);
} }
static inline bool rtw_fw_feature_ext_check(struct rtw_fw_state *fw,
enum rtw_fw_feature_ext feature)
{
return !!(fw->feature_ext & feature);
}
void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset, void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
struct sk_buff *skb); struct sk_buff *skb);
void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb); void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb);
void rtw_fw_send_general_info(struct rtw_dev *rtwdev); void rtw_fw_send_general_info(struct rtw_dev *rtwdev);
void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev); void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev);
void rtw_fw_default_port(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif);
void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para); void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para);
void rtw_fw_inform_rfk_status(struct rtw_dev *rtwdev, bool start); void rtw_fw_inform_rfk_status(struct rtw_dev *rtwdev, bool start);
@ -780,9 +827,12 @@ void rtw_fw_force_bt_tx_power(struct rtw_dev *rtwdev, u8 bt_pwr_dec_lvl);
void rtw_fw_bt_ignore_wlan_action(struct rtw_dev *rtwdev, bool enable); void rtw_fw_bt_ignore_wlan_action(struct rtw_dev *rtwdev, bool enable);
void rtw_fw_coex_tdma_type(struct rtw_dev *rtwdev, void rtw_fw_coex_tdma_type(struct rtw_dev *rtwdev,
u8 para1, u8 para2, u8 para3, u8 para4, u8 para5); u8 para1, u8 para2, u8 para3, u8 para4, u8 para5);
void rtw_fw_coex_query_hid_info(struct rtw_dev *rtwdev, u8 sub_id, u8 data);
void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data); void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data);
void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si); void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si);
void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si); void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
bool reset_ra_mask);
void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool conn); void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool conn);
void rtw_fw_update_wl_phy_info(struct rtw_dev *rtwdev); void rtw_fw_update_wl_phy_info(struct rtw_dev *rtwdev);
void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect, void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect,
@ -798,6 +848,7 @@ void rtw_add_rsvd_page_pno(struct rtw_dev *rtwdev,
void rtw_add_rsvd_page_sta(struct rtw_dev *rtwdev, void rtw_add_rsvd_page_sta(struct rtw_dev *rtwdev,
struct rtw_vif *rtwvif); struct rtw_vif *rtwvif);
int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev); int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev);
void rtw_fw_update_beacon_work(struct work_struct *work);
void rtw_send_rsvd_page_h2c(struct rtw_dev *rtwdev); void rtw_send_rsvd_page_h2c(struct rtw_dev *rtwdev);
int rtw_dump_drv_rsvd_page(struct rtw_dev *rtwdev, int rtw_dump_drv_rsvd_page(struct rtw_dev *rtwdev,
u32 offset, u32 size, u32 *buf); u32 offset, u32 size, u32 *buf);
@ -810,6 +861,7 @@ void rtw_fw_set_aoac_global_info_cmd(struct rtw_dev *rtwdev,
u8 group_key_enc); u8 group_key_enc);
void rtw_fw_set_nlo_info(struct rtw_dev *rtwdev, bool enable); void rtw_fw_set_nlo_info(struct rtw_dev *rtwdev, bool enable);
void rtw_fw_set_recover_bt_device(struct rtw_dev *rtwdev);
void rtw_fw_update_pkt_probe_req(struct rtw_dev *rtwdev, void rtw_fw_update_pkt_probe_req(struct rtw_dev *rtwdev,
struct cfg80211_ssid *ssid); struct cfg80211_ssid *ssid);
void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable); void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable);
@ -819,7 +871,8 @@ int rtw_fw_dump_fifo(struct rtw_dev *rtwdev, u8 fifo_sel, u32 addr, u32 size,
u32 *buffer); u32 *buffer);
void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start); void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start);
void rtw_fw_adaptivity(struct rtw_dev *rtwdev); void rtw_fw_adaptivity(struct rtw_dev *rtwdev);
void rtw_store_op_chan(struct rtw_dev *rtwdev); void rtw_store_op_chan(struct rtw_dev *rtwdev, bool backup);
void rtw_clear_op_chan(struct rtw_dev *rtwdev);
void rtw_hw_scan_start(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, void rtw_hw_scan_start(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_scan_request *req); struct ieee80211_scan_request *req);
void rtw_hw_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, void rtw_hw_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
@ -828,5 +881,5 @@ int rtw_hw_scan_offload(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
bool enable); bool enable);
void rtw_hw_scan_status_report(struct rtw_dev *rtwdev, struct sk_buff *skb); void rtw_hw_scan_status_report(struct rtw_dev *rtwdev, struct sk_buff *skb);
void rtw_hw_scan_chan_switch(struct rtw_dev *rtwdev, struct sk_buff *skb); void rtw_hw_scan_chan_switch(struct rtw_dev *rtwdev, struct sk_buff *skb);
void rtw_hw_scan_abort(struct rtw_dev *rtwdev, struct ieee80211_vif *vif); void rtw_hw_scan_abort(struct rtw_dev *rtwdev);
#endif #endif

9
hci.h
View file

@ -166,12 +166,11 @@ static inline u32
rtw_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, rtw_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask) u32 addr, u32 mask)
{ {
unsigned long flags;
u32 val; u32 val;
spin_lock_irqsave(&rtwdev->rf_lock, flags); lockdep_assert_held(&rtwdev->mutex);
val = rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask); val = rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask);
spin_unlock_irqrestore(&rtwdev->rf_lock, flags);
return val; return val;
} }
@ -180,11 +179,9 @@ static inline void
rtw_write_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, rtw_write_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data) u32 addr, u32 mask, u32 data)
{ {
unsigned long flags; lockdep_assert_held(&rtwdev->mutex);
spin_lock_irqsave(&rtwdev->rf_lock, flags);
rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data); rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data);
spin_unlock_irqrestore(&rtwdev->rf_lock, flags);
} }
static inline u32 static inline u32

123
mac.c
View file

@ -7,6 +7,7 @@
#include "reg.h" #include "reg.h"
#include "fw.h" #include "fw.h"
#include "debug.h" #include "debug.h"
#include "sdio.h"
void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw, void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw,
u8 primary_ch_idx) u8 primary_ch_idx)
@ -60,6 +61,7 @@ EXPORT_SYMBOL(rtw_set_channel_mac);
static int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev) static int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev)
{ {
unsigned int retry;
u32 value32; u32 value32;
u8 value8; u8 value8;
@ -75,7 +77,29 @@ static int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev)
switch (rtw_hci_type(rtwdev)) { switch (rtw_hci_type(rtwdev)) {
case RTW_HCI_TYPE_PCIE: case RTW_HCI_TYPE_PCIE:
rtw_write32_set(rtwdev, REG_HCI_OPT_CTRL, BIT_BT_DIG_CLK_EN); rtw_write32_set(rtwdev, REG_HCI_OPT_CTRL, BIT_USB_SUS_DIS);
break;
case RTW_HCI_TYPE_SDIO:
rtw_write8_clr(rtwdev, REG_SDIO_HSUS_CTRL, BIT_HCI_SUS_REQ);
for (retry = 0; retry < RTW_PWR_POLLING_CNT; retry++) {
if (rtw_read8(rtwdev, REG_SDIO_HSUS_CTRL) & BIT_HCI_RESUME_RDY)
break;
usleep_range(10, 50);
}
if (retry == RTW_PWR_POLLING_CNT) {
rtw_err(rtwdev, "failed to poll REG_SDIO_HSUS_CTRL[1]");
return -ETIMEDOUT;
}
if (rtw_sdio_is_sdio30_supported(rtwdev))
rtw_write8_set(rtwdev, REG_HCI_OPT_CTRL + 2,
BIT_SDIO_PAD_E5 >> 16);
else
rtw_write8_clr(rtwdev, REG_HCI_OPT_CTRL + 2,
BIT_SDIO_PAD_E5 >> 16);
break; break;
case RTW_HCI_TYPE_USB: case RTW_HCI_TYPE_USB:
break; break;
@ -217,10 +241,13 @@ static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
cut_mask = cut_version_to_mask(cut); cut_mask = cut_version_to_mask(cut);
switch (rtw_hci_type(rtwdev)) { switch (rtw_hci_type(rtwdev)) {
case RTW_HCI_TYPE_PCIE: case RTW_HCI_TYPE_PCIE:
intf_mask = BIT(2); intf_mask = RTW_PWR_INTF_PCI_MSK;
break; break;
case RTW_HCI_TYPE_USB: case RTW_HCI_TYPE_USB:
intf_mask = BIT(1); intf_mask = RTW_PWR_INTF_USB_MSK;
break;
case RTW_HCI_TYPE_SDIO:
intf_mask = RTW_PWR_INTF_SDIO_MSK;
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -233,7 +260,7 @@ static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
ret = rtw_sub_pwr_seq_parser(rtwdev, intf_mask, cut_mask, cmd); ret = rtw_sub_pwr_seq_parser(rtwdev, intf_mask, cut_mask, cmd);
if (ret) if (ret)
return -EBUSY; return ret;
idx++; idx++;
} while (1); } while (1);
@ -243,10 +270,12 @@ static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_pwr_seq_cmd **pwr_seq; const struct rtw_pwr_seq_cmd **pwr_seq;
u32 imr = 0;
u8 rpwm; u8 rpwm;
bool cur_pwr; bool cur_pwr;
int ret;
if (rtw_chip_wcpu_11ac(rtwdev)) { if (rtw_chip_wcpu_11ac(rtwdev)) {
rpwm = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); rpwm = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
@ -269,11 +298,24 @@ static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on)
if (pwr_on == cur_pwr) if (pwr_on == cur_pwr)
return -EALREADY; return -EALREADY;
pwr_seq = pwr_on ? chip->pwr_on_seq : chip->pwr_off_seq; if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) {
if (rtw_pwr_seq_parser(rtwdev, pwr_seq)) imr = rtw_read32(rtwdev, REG_SDIO_HIMR);
return -EINVAL; rtw_write32(rtwdev, REG_SDIO_HIMR, 0);
}
return 0; if (!pwr_on)
clear_bit(RTW_FLAG_POWERON, rtwdev->flags);
pwr_seq = pwr_on ? chip->pwr_on_seq : chip->pwr_off_seq;
ret = rtw_pwr_seq_parser(rtwdev, pwr_seq);
if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO)
rtw_write32(rtwdev, REG_SDIO_HIMR, imr);
if (!ret && pwr_on)
set_bit(RTW_FLAG_POWERON, rtwdev->flags);
return ret;
} }
static int __rtw_mac_init_system_cfg(struct rtw_dev *rtwdev) static int __rtw_mac_init_system_cfg(struct rtw_dev *rtwdev)
@ -335,6 +377,11 @@ int rtw_mac_power_on(struct rtw_dev *rtwdev)
ret = rtw_mac_power_switch(rtwdev, true); ret = rtw_mac_power_switch(rtwdev, true);
if (ret == -EALREADY) { if (ret == -EALREADY) {
rtw_mac_power_switch(rtwdev, false); rtw_mac_power_switch(rtwdev, false);
ret = rtw_mac_pre_system_cfg(rtwdev);
if (ret)
goto err;
ret = rtw_mac_power_switch(rtwdev, true); ret = rtw_mac_power_switch(rtwdev, true);
if (ret) if (ret)
goto err; goto err;
@ -439,6 +486,9 @@ static void download_firmware_reg_backup(struct rtw_dev *rtwdev,
rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, 0x200); rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, 0x200);
rtw_write32(rtwdev, REG_RQPN_CTRL_2, bckp[bckp_idx - 1].val); rtw_write32(rtwdev, REG_RQPN_CTRL_2, bckp[bckp_idx - 1].val);
if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO)
rtw_read32(rtwdev, REG_SDIO_FREE_TXPG);
/* Disable beacon related functions */ /* Disable beacon related functions */
tmp = rtw_read8(rtwdev, REG_BCN_CTRL); tmp = rtw_read8(rtwdev, REG_BCN_CTRL);
bckp[bckp_idx].len = 1; bckp[bckp_idx].len = 1;
@ -587,7 +637,7 @@ static int
download_firmware_to_mem(struct rtw_dev *rtwdev, const u8 *data, download_firmware_to_mem(struct rtw_dev *rtwdev, const u8 *data,
u32 src, u32 dst, u32 size) u32 src, u32 dst, u32 size)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
u32 desc_size = chip->tx_pkt_desc_sz; u32 desc_size = chip->tx_pkt_desc_sz;
u8 first_part; u8 first_part;
u32 mem_offset; u32 mem_offset;
@ -744,8 +794,10 @@ static int __rtw_download_firmware(struct rtw_dev *rtwdev,
wlan_cpu_enable(rtwdev, true); wlan_cpu_enable(rtwdev, true);
if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) {
return -EBUSY; ret = -EBUSY;
goto dlfw_fail;
}
ret = download_firmware_validate(rtwdev); ret = download_firmware_validate(rtwdev);
if (ret) if (ret)
@ -906,7 +958,8 @@ static int __rtw_download_firmware_legacy(struct rtw_dev *rtwdev,
return ret; return ret;
} }
int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) static
int _rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw)
{ {
if (rtw_chip_wcpu_11n(rtwdev)) if (rtw_chip_wcpu_11n(rtwdev))
return __rtw_download_firmware_legacy(rtwdev, fw); return __rtw_download_firmware_legacy(rtwdev, fw);
@ -914,6 +967,21 @@ int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw)
return __rtw_download_firmware(rtwdev, fw); return __rtw_download_firmware(rtwdev, fw);
} }
int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw)
{
int ret;
ret = _rtw_download_firmware(rtwdev, fw);
if (ret)
return ret;
if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE &&
rtwdev->chip->id == RTW_CHIP_TYPE_8821C)
rtw_fw_set_recover_bt_device(rtwdev);
return 0;
}
static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues) static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues)
{ {
const struct rtw_rqpn *rqpn = rtwdev->fifo.rqpn; const struct rtw_rqpn *rqpn = rtwdev->fifo.rqpn;
@ -934,7 +1002,7 @@ static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues)
static void __rtw_mac_flush_prio_queue(struct rtw_dev *rtwdev, static void __rtw_mac_flush_prio_queue(struct rtw_dev *rtwdev,
u32 prio_queue, bool drop) u32 prio_queue, bool drop)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_prioq_addr *addr; const struct rtw_prioq_addr *addr;
bool wsize; bool wsize;
u16 avail_page, rsvd_page; u16 avail_page, rsvd_page;
@ -996,7 +1064,7 @@ void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop)
static int txdma_queue_mapping(struct rtw_dev *rtwdev) static int txdma_queue_mapping(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_rqpn *rqpn = NULL; const struct rtw_rqpn *rqpn = NULL;
u16 txdma_pq_map = 0; u16 txdma_pq_map = 0;
@ -1014,6 +1082,9 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev)
else else
return -EINVAL; return -EINVAL;
break; break;
case RTW_HCI_TYPE_SDIO:
rqpn = &chip->rqpn_table[0];
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -1032,18 +1103,25 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev)
if (rtw_chip_wcpu_11ac(rtwdev)) if (rtw_chip_wcpu_11ac(rtwdev))
rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL);
if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) {
rtw_read32(rtwdev, REG_SDIO_FREE_TXPG);
rtw_write32(rtwdev, REG_SDIO_TX_CTRL, 0);
} else if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB) {
rtw_write8_set(rtwdev, REG_TXDMA_PQ_MAP, BIT_RXDMA_ARBBW_EN);
}
return 0; return 0;
} }
static int set_trx_fifo_info(struct rtw_dev *rtwdev) static int set_trx_fifo_info(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_fifo_conf *fifo = &rtwdev->fifo; struct rtw_fifo_conf *fifo = &rtwdev->fifo;
struct rtw_chip_info *chip = rtwdev->chip;
u16 cur_pg_addr; u16 cur_pg_addr;
u8 csi_buf_pg_num = chip->csi_buf_pg_num; u8 csi_buf_pg_num = chip->csi_buf_pg_num;
/* config rsvd page num */ /* config rsvd page num */
fifo->rsvd_drv_pg_num = 8; fifo->rsvd_drv_pg_num = chip->rsvd_drv_pg_num;
fifo->txff_pg_num = chip->txff_size >> 7; fifo->txff_pg_num = chip->txff_size >> 7;
if (rtw_chip_wcpu_11n(rtwdev)) if (rtw_chip_wcpu_11n(rtwdev))
fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num; fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num;
@ -1092,8 +1170,8 @@ static int __priority_queue_cfg(struct rtw_dev *rtwdev,
const struct rtw_page_table *pg_tbl, const struct rtw_page_table *pg_tbl,
u16 pubq_num) u16 pubq_num)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_fifo_conf *fifo = &rtwdev->fifo; struct rtw_fifo_conf *fifo = &rtwdev->fifo;
struct rtw_chip_info *chip = rtwdev->chip;
rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, pg_tbl->hq_num); rtw_write16(rtwdev, REG_FIFOPAGE_INFO_1, pg_tbl->hq_num);
rtw_write16(rtwdev, REG_FIFOPAGE_INFO_2, pg_tbl->lq_num); rtw_write16(rtwdev, REG_FIFOPAGE_INFO_2, pg_tbl->lq_num);
@ -1123,8 +1201,8 @@ static int __priority_queue_cfg_legacy(struct rtw_dev *rtwdev,
const struct rtw_page_table *pg_tbl, const struct rtw_page_table *pg_tbl,
u16 pubq_num) u16 pubq_num)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_fifo_conf *fifo = &rtwdev->fifo; struct rtw_fifo_conf *fifo = &rtwdev->fifo;
struct rtw_chip_info *chip = rtwdev->chip;
u32 val32; u32 val32;
val32 = BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num); val32 = BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num);
@ -1149,8 +1227,8 @@ static int __priority_queue_cfg_legacy(struct rtw_dev *rtwdev,
static int priority_queue_cfg(struct rtw_dev *rtwdev) static int priority_queue_cfg(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_fifo_conf *fifo = &rtwdev->fifo; struct rtw_fifo_conf *fifo = &rtwdev->fifo;
struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_page_table *pg_tbl = NULL; const struct rtw_page_table *pg_tbl = NULL;
u16 pubq_num; u16 pubq_num;
int ret; int ret;
@ -1173,6 +1251,9 @@ static int priority_queue_cfg(struct rtw_dev *rtwdev)
else else
return -EINVAL; return -EINVAL;
break; break;
case RTW_HCI_TYPE_SDIO:
pg_tbl = &chip->page_table[0];
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -1277,7 +1358,7 @@ static int rtw_drv_info_cfg(struct rtw_dev *rtwdev)
int rtw_mac_init(struct rtw_dev *rtwdev) int rtw_mac_init(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
int ret; int ret;
ret = rtw_init_trx_cfg(rtwdev); ret = rtw_init_trx_cfg(rtwdev);

1
mac.h
View file

@ -7,7 +7,6 @@
#define RTW_HW_PORT_NUM 5 #define RTW_HW_PORT_NUM 5
#define cut_version_to_mask(cut) (0x1 << ((cut) + 1)) #define cut_version_to_mask(cut) (0x1 << ((cut) + 1))
#define SDIO_LOCAL_OFFSET 0x10250000
#define DDMA_POLLING_COUNT 1000 #define DDMA_POLLING_COUNT 1000
#define C2H_PKT_BUF 256 #define C2H_PKT_BUF 256
#define REPORT_BUF 128 #define REPORT_BUF 128

View file

@ -43,6 +43,10 @@ static void rtw_ops_wake_tx_queue(struct ieee80211_hw *hw,
list_add_tail(&rtwtxq->list, &rtwdev->txqs); list_add_tail(&rtwtxq->list, &rtwdev->txqs);
spin_unlock_bh(&rtwdev->txq_lock); spin_unlock_bh(&rtwdev->txq_lock);
/* ensure to dequeue EAPOL (4/4) at the right time */
if (txq->ac == IEEE80211_AC_VO)
__rtw_tx_work(rtwdev);
else
queue_work(rtwdev->tx_wq, &rtwdev->tx_work); queue_work(rtwdev->tx_wq, &rtwdev->tx_work);
} }
@ -72,6 +76,9 @@ static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed)
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
int ret = 0; int ret = 0;
/* let previous ips work finish to ensure we don't leave ips twice */
cancel_work_sync(&rtwdev->ips_work);
mutex_lock(&rtwdev->mutex); mutex_lock(&rtwdev->mutex);
rtw_leave_lps_deep(rtwdev); rtw_leave_lps_deep(rtwdev);
@ -85,20 +92,12 @@ static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed)
} }
} }
if (changed & IEEE80211_CONF_CHANGE_PS) {
if (hw->conf.flags & IEEE80211_CONF_PS) {
rtwdev->ps_enabled = true;
} else {
rtwdev->ps_enabled = false;
rtw_leave_lps(rtwdev);
}
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
rtw_set_channel(rtwdev); rtw_set_channel(rtwdev);
if ((changed & IEEE80211_CONF_CHANGE_IDLE) && if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
(hw->conf.flags & IEEE80211_CONF_IDLE)) (hw->conf.flags & IEEE80211_CONF_IDLE) &&
!test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
rtw_enter_ips(rtwdev); rtw_enter_ips(rtwdev);
out: out:
@ -151,25 +150,32 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
enum rtw_net_type net_type; enum rtw_net_type net_type;
u32 config = 0; u32 config = 0;
u8 port = 0; u8 port;
u8 bcn_ctrl = 0; u8 bcn_ctrl = 0;
if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER)) if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER))
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
IEEE80211_VIF_SUPPORTS_CQM_RSSI; IEEE80211_VIF_SUPPORTS_CQM_RSSI;
rtwvif->port = port;
rtwvif->stats.tx_unicast = 0; rtwvif->stats.tx_unicast = 0;
rtwvif->stats.rx_unicast = 0; rtwvif->stats.rx_unicast = 0;
rtwvif->stats.tx_cnt = 0; rtwvif->stats.tx_cnt = 0;
rtwvif->stats.rx_cnt = 0; rtwvif->stats.rx_cnt = 0;
rtwvif->scan_req = NULL; rtwvif->scan_req = NULL;
memset(&rtwvif->bfee, 0, sizeof(struct rtw_bfee)); memset(&rtwvif->bfee, 0, sizeof(struct rtw_bfee));
rtwvif->conf = &rtw_vif_port[port];
rtw_txq_init(rtwdev, vif->txq); rtw_txq_init(rtwdev, vif->txq);
INIT_LIST_HEAD(&rtwvif->rsvd_page_list); INIT_LIST_HEAD(&rtwvif->rsvd_page_list);
mutex_lock(&rtwdev->mutex); mutex_lock(&rtwdev->mutex);
port = find_first_zero_bit(rtwdev->hw_port, RTW_PORT_NUM);
if (port >= RTW_PORT_NUM) {
mutex_unlock(&rtwdev->mutex);
return -EINVAL;
}
set_bit(port, rtwdev->hw_port);
rtwvif->port = port;
rtwvif->conf = &rtw_vif_port[port];
rtw_leave_lps_deep(rtwdev); rtw_leave_lps_deep(rtwdev);
switch (vif->type) { switch (vif->type) {
@ -191,6 +197,7 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
clear_bit(rtwvif->port, rtwdev->hw_port);
mutex_unlock(&rtwdev->mutex); mutex_unlock(&rtwdev->mutex);
return -EINVAL; return -EINVAL;
} }
@ -202,10 +209,12 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
rtwvif->bcn_ctrl = bcn_ctrl; rtwvif->bcn_ctrl = bcn_ctrl;
config |= PORT_SET_BCN_CTRL; config |= PORT_SET_BCN_CTRL;
rtw_vif_port_config(rtwdev, rtwvif, config); rtw_vif_port_config(rtwdev, rtwvif, config);
rtw_core_port_switch(rtwdev, vif);
rtw_recalc_lps(rtwdev, vif);
mutex_unlock(&rtwdev->mutex); mutex_unlock(&rtwdev->mutex);
rtw_info(rtwdev, "start vif %pM on port %d\n", vif->addr, rtwvif->port); rtw_dbg(rtwdev, RTW_DBG_STATE, "start vif %pM on port %d\n", vif->addr, rtwvif->port);
return 0; return 0;
} }
@ -216,7 +225,7 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw,
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
u32 config = 0; u32 config = 0;
rtw_info(rtwdev, "stop vif %pM on port %d\n", vif->addr, rtwvif->port); rtw_dbg(rtwdev, RTW_DBG_STATE, "stop vif %pM on port %d\n", vif->addr, rtwvif->port);
mutex_lock(&rtwdev->mutex); mutex_lock(&rtwdev->mutex);
@ -232,6 +241,8 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw,
rtwvif->bcn_ctrl = 0; rtwvif->bcn_ctrl = 0;
config |= PORT_SET_BCN_CTRL; config |= PORT_SET_BCN_CTRL;
rtw_vif_port_config(rtwdev, rtwvif, config); rtw_vif_port_config(rtwdev, rtwvif, config);
clear_bit(rtwvif->port, rtwdev->hw_port);
rtw_recalc_lps(rtwdev, NULL);
mutex_unlock(&rtwdev->mutex); mutex_unlock(&rtwdev->mutex);
} }
@ -242,7 +253,7 @@ static int rtw_ops_change_interface(struct ieee80211_hw *hw,
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
rtw_info(rtwdev, "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n", rtw_dbg(rtwdev, RTW_DBG_STATE, "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n",
vif->addr, vif->type, type, vif->p2p, p2p); vif->addr, vif->type, type, vif->p2p, p2p);
rtw_ops_remove_interface(hw, vif); rtw_ops_remove_interface(hw, vif);
@ -352,7 +363,7 @@ static void rtw_conf_tx(struct rtw_dev *rtwdev,
static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *conf, struct ieee80211_bss_conf *conf,
u32 changed) u64 changed)
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
@ -366,15 +377,15 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ASSOC) { if (changed & BSS_CHANGED_ASSOC) {
rtw_vif_assoc_changed(rtwvif, conf); rtw_vif_assoc_changed(rtwvif, conf);
if (conf->assoc) { if (vif->cfg.assoc) {
rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_FINISH); rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_FINISH);
rtw_fw_download_rsvd_page(rtwdev); rtw_fw_download_rsvd_page(rtwdev);
rtw_send_rsvd_page_h2c(rtwdev); rtw_send_rsvd_page_h2c(rtwdev);
rtw_coex_media_status_notify(rtwdev, conf->assoc); rtw_fw_default_port(rtwdev, rtwvif);
rtw_coex_media_status_notify(rtwdev, vif->cfg.assoc);
if (rtw_bf_support) if (rtw_bf_support)
rtw_bf_assoc(rtwdev, vif, conf); rtw_bf_assoc(rtwdev, vif, conf);
rtw_store_op_chan(rtwdev);
} else { } else {
rtw_leave_lps(rtwdev); rtw_leave_lps(rtwdev);
rtw_bf_disassoc(rtwdev, vif, conf); rtw_bf_disassoc(rtwdev, vif, conf);
@ -382,7 +393,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
* when disconnected by peer * when disconnected by peer
*/ */
if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
rtw_hw_scan_abort(rtwdev, vif); rtw_hw_scan_abort(rtwdev);
} }
config |= PORT_SET_NET_TYPE; config |= PORT_SET_NET_TYPE;
@ -392,6 +404,10 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID) { if (changed & BSS_CHANGED_BSSID) {
ether_addr_copy(rtwvif->bssid, conf->bssid); ether_addr_copy(rtwvif->bssid, conf->bssid);
config |= PORT_SET_BSSID; config |= PORT_SET_BSSID;
if (!rtw_core_check_sta_active(rtwdev))
rtw_clear_op_chan(rtwdev);
else
rtw_store_op_chan(rtwdev, true);
} }
if (changed & BSS_CHANGED_BEACON_INT) { if (changed & BSS_CHANGED_BEACON_INT) {
@ -399,8 +415,11 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
coex_stat->wl_beacon_interval = conf->beacon_int; coex_stat->wl_beacon_interval = conf->beacon_int;
} }
if (changed & BSS_CHANGED_BEACON) if (changed & BSS_CHANGED_BEACON) {
rtw_set_dtim_period(rtwdev, conf->dtim_period);
rtw_fw_download_rsvd_page(rtwdev); rtw_fw_download_rsvd_page(rtwdev);
rtw_send_rsvd_page_h2c(rtwdev);
}
if (changed & BSS_CHANGED_BEACON_ENABLED) { if (changed & BSS_CHANGED_BEACON_ENABLED) {
if (conf->enable_beacon) if (conf->enable_beacon)
@ -419,13 +438,48 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ERP_SLOT) if (changed & BSS_CHANGED_ERP_SLOT)
rtw_conf_tx(rtwdev, rtwvif); rtw_conf_tx(rtwdev, rtwvif);
if (changed & BSS_CHANGED_PS)
rtw_recalc_lps(rtwdev, NULL);
rtw_vif_port_config(rtwdev, rtwvif, config); rtw_vif_port_config(rtwdev, rtwvif, config);
mutex_unlock(&rtwdev->mutex); mutex_unlock(&rtwdev->mutex);
} }
static int rtw_ops_start_ap(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct rtw_dev *rtwdev = hw->priv;
const struct rtw_chip_info *chip = rtwdev->chip;
mutex_lock(&rtwdev->mutex);
rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD);
rtwdev->ap_active = true;
rtw_store_op_chan(rtwdev, true);
chip->ops->phy_calibration(rtwdev);
mutex_unlock(&rtwdev->mutex);
return 0;
}
static void rtw_ops_stop_ap(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_write32_clr(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD);
rtwdev->ap_active = false;
if (!rtw_core_check_sta_active(rtwdev))
rtw_clear_op_chan(rtwdev);
mutex_unlock(&rtwdev->mutex);
}
static int rtw_ops_conf_tx(struct ieee80211_hw *hw, static int rtw_ops_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 ac, struct ieee80211_vif *vif,
unsigned int link_id, u16 ac,
const struct ieee80211_tx_queue_params *params) const struct ieee80211_tx_queue_params *params)
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
@ -463,14 +517,24 @@ static int rtw_ops_sta_remove(struct ieee80211_hw *hw,
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
rtw_fw_beacon_filter_config(rtwdev, false, vif);
mutex_lock(&rtwdev->mutex); mutex_lock(&rtwdev->mutex);
rtw_fw_beacon_filter_config(rtwdev, false, vif);
rtw_sta_remove(rtwdev, sta, true); rtw_sta_remove(rtwdev, sta, true);
mutex_unlock(&rtwdev->mutex); mutex_unlock(&rtwdev->mutex);
return 0; return 0;
} }
static int rtw_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set)
{
struct rtw_dev *rtwdev = hw->priv;
ieee80211_queue_work(hw, &rtwdev->update_beacon_work);
return 0;
}
static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key) struct ieee80211_key_conf *key)
@ -614,7 +678,7 @@ static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw,
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex); mutex_lock(&rtwdev->mutex);
rtw_core_scan_complete(rtwdev, vif); rtw_core_scan_complete(rtwdev, vif, false);
mutex_unlock(&rtwdev->mutex); mutex_unlock(&rtwdev->mutex);
} }
@ -691,7 +755,7 @@ static void rtw_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta)
} }
si->use_cfg_mask = true; si->use_cfg_mask = true;
rtw_update_sta_info(br_data->rtwdev, si); rtw_update_sta_info(br_data->rtwdev, si, true);
} }
static void rtw_ra_mask_info_update(struct rtw_dev *rtwdev, static void rtw_ra_mask_info_update(struct rtw_dev *rtwdev,
@ -703,7 +767,7 @@ static void rtw_ra_mask_info_update(struct rtw_dev *rtwdev,
br_data.rtwdev = rtwdev; br_data.rtwdev = rtwdev;
br_data.vif = vif; br_data.vif = vif;
br_data.mask = mask; br_data.mask = mask;
rtw_iterate_stas_atomic(rtwdev, rtw_ra_mask_info_update_iter, &br_data); rtw_iterate_stas(rtwdev, rtw_ra_mask_info_update_iter, &br_data);
} }
static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw, static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw,
@ -712,7 +776,9 @@ static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw,
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_ra_mask_info_update(rtwdev, vif, mask); rtw_ra_mask_info_update(rtwdev, vif, mask);
mutex_unlock(&rtwdev->mutex);
return 0; return 0;
} }
@ -722,7 +788,7 @@ static int rtw_ops_set_antenna(struct ieee80211_hw *hw,
u32 rx_antenna) u32 rx_antenna)
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
int ret; int ret;
if (!chip->ops->set_antenna) if (!chip->ops->set_antenna)
@ -813,7 +879,7 @@ static int rtw_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
rtw_hw_scan_start(rtwdev, vif, req); rtw_hw_scan_start(rtwdev, vif, req);
ret = rtw_hw_scan_offload(rtwdev, vif, true); ret = rtw_hw_scan_offload(rtwdev, vif, true);
if (ret) { if (ret) {
rtw_hw_scan_abort(rtwdev, vif); rtw_hw_scan_abort(rtwdev);
rtw_err(rtwdev, "HW scan failed with status: %d\n", ret); rtw_err(rtwdev, "HW scan failed with status: %d\n", ret);
} }
mutex_unlock(&rtwdev->mutex); mutex_unlock(&rtwdev->mutex);
@ -833,7 +899,7 @@ static void rtw_ops_cancel_hw_scan(struct ieee80211_hw *hw,
return; return;
mutex_lock(&rtwdev->mutex); mutex_lock(&rtwdev->mutex);
rtw_hw_scan_abort(rtwdev, vif); rtw_hw_scan_abort(rtwdev);
mutex_unlock(&rtwdev->mutex); mutex_unlock(&rtwdev->mutex);
} }
@ -842,11 +908,24 @@ static int rtw_ops_set_sar_specs(struct ieee80211_hw *hw,
{ {
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
mutex_lock(&rtwdev->mutex);
rtw_set_sar_specs(rtwdev, sar); rtw_set_sar_specs(rtwdev, sar);
mutex_unlock(&rtwdev->mutex);
return 0; return 0;
} }
static void rtw_ops_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u32 changed)
{
struct rtw_dev *rtwdev = hw->priv;
struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
if (changed & IEEE80211_RC_BW_CHANGED)
ieee80211_queue_work(rtwdev->hw, &si->rc_work);
}
const struct ieee80211_ops rtw_ops = { const struct ieee80211_ops rtw_ops = {
.tx = rtw_ops_tx, .tx = rtw_ops_tx,
.wake_tx_queue = rtw_ops_wake_tx_queue, .wake_tx_queue = rtw_ops_wake_tx_queue,
@ -858,9 +937,12 @@ const struct ieee80211_ops rtw_ops = {
.change_interface = rtw_ops_change_interface, .change_interface = rtw_ops_change_interface,
.configure_filter = rtw_ops_configure_filter, .configure_filter = rtw_ops_configure_filter,
.bss_info_changed = rtw_ops_bss_info_changed, .bss_info_changed = rtw_ops_bss_info_changed,
.start_ap = rtw_ops_start_ap,
.stop_ap = rtw_ops_stop_ap,
.conf_tx = rtw_ops_conf_tx, .conf_tx = rtw_ops_conf_tx,
.sta_add = rtw_ops_sta_add, .sta_add = rtw_ops_sta_add,
.sta_remove = rtw_ops_sta_remove, .sta_remove = rtw_ops_sta_remove,
.set_tim = rtw_ops_set_tim,
.set_key = rtw_ops_set_key, .set_key = rtw_ops_set_key,
.ampdu_action = rtw_ops_ampdu_action, .ampdu_action = rtw_ops_ampdu_action,
.can_aggregate_in_amsdu = rtw_ops_can_aggregate_in_amsdu, .can_aggregate_in_amsdu = rtw_ops_can_aggregate_in_amsdu,
@ -876,6 +958,7 @@ const struct ieee80211_ops rtw_ops = {
.reconfig_complete = rtw_reconfig_complete, .reconfig_complete = rtw_reconfig_complete,
.hw_scan = rtw_ops_hw_scan, .hw_scan = rtw_ops_hw_scan,
.cancel_hw_scan = rtw_ops_cancel_hw_scan, .cancel_hw_scan = rtw_ops_cancel_hw_scan,
.sta_rc_update = rtw_ops_sta_rc_update,
.set_sar_specs = rtw_ops_set_sar_specs, .set_sar_specs = rtw_ops_set_sar_specs,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = rtw_ops_suspend, .suspend = rtw_ops_suspend,

640
main.c

File diff suppressed because it is too large Load diff

146
main.h
View file

@ -17,13 +17,11 @@
#include "util.h" #include "util.h"
#define RTW_NAPI_WEIGHT_NUM 64
#define RTW_MAX_MAC_ID_NUM 32 #define RTW_MAX_MAC_ID_NUM 32
#define RTW_MAX_SEC_CAM_NUM 32 #define RTW_MAX_SEC_CAM_NUM 32
#define MAX_PG_CAM_BACKUP_NUM 8 #define MAX_PG_CAM_BACKUP_NUM 8
#define RTW_SCAN_MAX_SSIDS 4 #define RTW_SCAN_MAX_SSIDS 4
#define RTW_SCAN_MAX_IE_LEN 128
#define RTW_MAX_PATTERN_NUM 12 #define RTW_MAX_PATTERN_NUM 12
#define RTW_MAX_PATTERN_MASK_SIZE 16 #define RTW_MAX_PATTERN_MASK_SIZE 16
@ -34,6 +32,7 @@
#define RFREG_MASK 0xfffff #define RFREG_MASK 0xfffff
#define INV_RF_DATA 0xffffffff #define INV_RF_DATA 0xffffffff
#define TX_PAGE_SIZE_SHIFT 7 #define TX_PAGE_SIZE_SHIFT 7
#define TX_PAGE_SIZE (1 << TX_PAGE_SIZE_SHIFT)
#define RTW_CHANNEL_WIDTH_MAX 3 #define RTW_CHANNEL_WIDTH_MAX 3
#define RTW_RF_PATH_MAX 4 #define RTW_RF_PATH_MAX 4
@ -357,7 +356,7 @@ enum rtw_flags {
RTW_FLAG_RUNNING, RTW_FLAG_RUNNING,
RTW_FLAG_FW_RUNNING, RTW_FLAG_FW_RUNNING,
RTW_FLAG_SCANNING, RTW_FLAG_SCANNING,
RTW_FLAG_INACTIVE_PS, RTW_FLAG_POWERON,
RTW_FLAG_LEISURE_PS, RTW_FLAG_LEISURE_PS,
RTW_FLAG_LEISURE_PS_DEEP, RTW_FLAG_LEISURE_PS_DEEP,
RTW_FLAG_DIG_DISABLE, RTW_FLAG_DIG_DISABLE,
@ -396,6 +395,15 @@ enum rtw_snr {
RTW_SNR_NUM RTW_SNR_NUM
}; };
enum rtw_port {
RTW_PORT_0 = 0,
RTW_PORT_1 = 1,
RTW_PORT_2 = 2,
RTW_PORT_3 = 3,
RTW_PORT_4 = 4,
RTW_PORT_NUM
};
enum rtw_wow_flags { enum rtw_wow_flags {
RTW_WOW_FLAG_EN_MAGIC_PKT, RTW_WOW_FLAG_EN_MAGIC_PKT,
RTW_WOW_FLAG_EN_REKEY_PKT, RTW_WOW_FLAG_EN_REKEY_PKT,
@ -503,20 +511,10 @@ struct rtw_txpwr_idx {
struct rtw_5g_txpwr_idx pwr_idx_5g; struct rtw_5g_txpwr_idx pwr_idx_5g;
}; };
struct rtw_timer_list {
struct timer_list timer;
void (*function)(void *data);
void *args;
};
struct rtw_channel_params { struct rtw_channel_params {
u8 center_chan; u8 center_chan;
u8 primary_chan;
u8 bandwidth; u8 bandwidth;
u8 primary_chan_idx;
/* center channel by different available bandwidth,
* val of (bw > current bandwidth) is invalid
*/
u8 cch_by_bw[RTW_MAX_CHANNEL_WIDTH + 1];
}; };
struct rtw_hw_reg { struct rtw_hw_reg {
@ -580,6 +578,7 @@ struct rtw_tx_pkt_info {
u32 tx_pkt_size; u32 tx_pkt_size;
u8 offset; u8 offset;
u8 pkt_offset; u8 pkt_offset;
u8 tim_offset;
u8 mac_id; u8 mac_id;
u8 rate_id; u8 rate_id;
u8 rate; u8 rate;
@ -729,15 +728,14 @@ struct rtw_ra_report {
struct rtw_txq { struct rtw_txq {
struct list_head list; struct list_head list;
unsigned long flags; unsigned long flags;
unsigned long last_push;
}; };
#define RTW_BC_MC_MACID 1 #define RTW_BC_MC_MACID 1
DECLARE_EWMA(rssi, 10, 16); DECLARE_EWMA(rssi, 10, 16);
struct rtw_sta_info { struct rtw_sta_info {
struct rtw_dev *rtwdev;
struct ieee80211_sta *sta; struct ieee80211_sta *sta;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
@ -748,12 +746,10 @@ struct rtw_sta_info {
u8 rate_id; u8 rate_id;
enum rtw_bandwidth bw_mode; enum rtw_bandwidth bw_mode;
enum rtw_rf_type rf_type; enum rtw_rf_type rf_type;
enum rtw_wireless_set wireless_set;
u8 stbc_en:2; u8 stbc_en:2;
u8 ldpc_en:2; u8 ldpc_en:2;
bool sgi_enable; bool sgi_enable;
bool vht_enable; bool vht_enable;
bool updated;
u8 init_ra_lv; u8 init_ra_lv;
u64 ra_mask; u64 ra_mask;
@ -763,6 +759,8 @@ struct rtw_sta_info {
bool use_cfg_mask; bool use_cfg_mask;
struct cfg80211_bitrate_mask *mask; struct cfg80211_bitrate_mask *mask;
struct work_struct rc_work;
}; };
enum rtw_bfee_role { enum rtw_bfee_role {
@ -796,6 +794,7 @@ struct rtw_bf_info {
struct rtw_vif { struct rtw_vif {
enum rtw_net_type net_type; enum rtw_net_type net_type;
u16 aid; u16 aid;
u8 mac_id; /* for STA mode only */
u8 mac_addr[ETH_ALEN]; u8 mac_addr[ETH_ALEN];
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
u8 port; u8 port;
@ -874,6 +873,12 @@ struct rtw_chip_ops {
enum rtw_bb_path tx_path_1ss, enum rtw_bb_path tx_path_1ss,
enum rtw_bb_path tx_path_cck, enum rtw_bb_path tx_path_cck,
bool is_tx2_path); bool is_tx2_path);
void (*config_txrx_mode)(struct rtw_dev *rtwdev, u8 tx_path,
u8 rx_path, bool is_tx2_path);
/* for USB/SDIO only */
void (*fill_txdesc_checksum)(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc);
/* for coex */ /* for coex */
void (*coex_set_init)(struct rtw_dev *rtwdev); void (*coex_set_init)(struct rtw_dev *rtwdev);
@ -1167,6 +1172,7 @@ struct rtw_chip_info {
u32 txff_size; u32 txff_size;
u32 rxff_size; u32 rxff_size;
u32 fw_rxff_size; u32 fw_rxff_size;
u16 rsvd_drv_pg_num;
u8 band; u8 band;
u8 page_size; u8 page_size;
u8 csi_buf_pg_num; u8 csi_buf_pg_num;
@ -1177,6 +1183,7 @@ struct rtw_chip_info {
bool rx_ldpc; bool rx_ldpc;
bool tx_stbc; bool tx_stbc;
u8 max_power_index; u8 max_power_index;
u8 ampdu_density;
u16 fw_fifo_addr[RTW_FW_FIFO_MAX]; u16 fw_fifo_addr[RTW_FW_FIFO_MAX];
const struct rtw_fwcd_segs *fwcd_segs; const struct rtw_fwcd_segs *fwcd_segs;
@ -1230,9 +1237,7 @@ struct rtw_chip_info {
const char *wow_fw_name; const char *wow_fw_name;
const struct wiphy_wowlan_support *wowlan_stub; const struct wiphy_wowlan_support *wowlan_stub;
const u8 max_sched_scan_ssids; const u8 max_sched_scan_ssids;
const u16 max_scan_ie_len;
/* for 8821c set channel */
u32 ch_param[3];
/* coex paras */ /* coex paras */
u32 coex_para_ver; u32 coex_para_ver;
@ -1240,6 +1245,7 @@ struct rtw_chip_info {
bool scbd_support; bool scbd_support;
bool new_scbd10_def; /* true: fix 2M(8822c) */ bool new_scbd10_def; /* true: fix 2M(8822c) */
bool ble_hid_profile_support; bool ble_hid_profile_support;
bool wl_mimo_ps_support;
u8 pstdma_type; /* 0: LPSoff, 1:LPSon */ u8 pstdma_type; /* 0: LPSoff, 1:LPSon */
u8 bt_rssi_type; u8 bt_rssi_type;
u8 ant_isolation; u8 ant_isolation;
@ -1352,6 +1358,42 @@ struct rtw_coex_dm {
#define COEX_BTINFO_LENGTH_MAX 10 #define COEX_BTINFO_LENGTH_MAX 10
#define COEX_BTINFO_LENGTH 7 #define COEX_BTINFO_LENGTH 7
#define COEX_BT_HIDINFO_LIST 0x0
#define COEX_BT_HIDINFO_A 0x1
#define COEX_BT_HIDINFO_NAME 3
#define COEX_BT_HIDINFO_LENGTH 6
#define COEX_BT_HIDINFO_HANDLE_NUM 4
#define COEX_BT_HIDINFO_C2H_HANDLE 0
#define COEX_BT_HIDINFO_C2H_VENDOR 1
#define COEX_BT_BLE_HANDLE_THRS 0x10
#define COEX_BT_HIDINFO_NOTCON 0xff
struct rtw_coex_hid {
u8 hid_handle;
u8 hid_vendor;
u8 hid_name[COEX_BT_HIDINFO_NAME];
bool hid_info_completed;
bool is_game_hid;
};
struct rtw_coex_hid_handle_list {
u8 cmd_id;
u8 len;
u8 subid;
u8 handle_cnt;
u8 handle[COEX_BT_HIDINFO_HANDLE_NUM];
} __packed;
struct rtw_coex_hid_info_a {
u8 cmd_id;
u8 len;
u8 subid;
u8 handle;
u8 vendor;
u8 name[COEX_BT_HIDINFO_NAME];
} __packed;
struct rtw_coex_stat { struct rtw_coex_stat {
bool bt_disabled; bool bt_disabled;
bool bt_disabled_pre; bool bt_disabled_pre;
@ -1382,6 +1424,8 @@ struct rtw_coex_stat {
bool bt_slave; bool bt_slave;
bool bt_418_hid_exist; bool bt_418_hid_exist;
bool bt_ble_hid_exist; bool bt_ble_hid_exist;
bool bt_game_hid_exist;
bool bt_hid_handle_cnt;
bool bt_mailbox_reply; bool bt_mailbox_reply;
bool wl_under_lps; bool wl_under_lps;
@ -1402,6 +1446,7 @@ struct rtw_coex_stat {
bool wl_connecting; bool wl_connecting;
bool wl_slot_toggle; bool wl_slot_toggle;
bool wl_slot_toggle_change; /* if toggle to no-toggle */ bool wl_slot_toggle_change; /* if toggle to no-toggle */
bool wl_mimo_ps;
u32 bt_supported_version; u32 bt_supported_version;
u32 bt_supported_feature; u32 bt_supported_feature;
@ -1459,11 +1504,12 @@ struct rtw_coex_stat {
u32 darfrc; u32 darfrc;
u32 darfrch; u32 darfrch;
struct rtw_coex_hid hid_info[COEX_BT_HIDINFO_HANDLE_NUM];
struct rtw_coex_hid_handle_list hid_handle_list;
}; };
struct rtw_coex { struct rtw_coex {
/* protects coex info request section */
struct mutex mutex;
struct sk_buff_head queue; struct sk_buff_head queue;
wait_queue_head_t wait; wait_queue_head_t wait;
@ -1811,6 +1857,8 @@ struct rtw_fw_state {
u8 sub_index; u8 sub_index;
u16 h2c_version; u16 h2c_version;
u32 feature; u32 feature;
u32 feature_ext;
enum rtw_fw_type type;
}; };
enum rtw_sar_sources { enum rtw_sar_sources {
@ -1828,7 +1876,7 @@ enum rtw_sar_bands {
RTW_SAR_BAND_NR, RTW_SAR_BAND_NR,
}; };
/* the union is reserved for other knids of SAR sources /* the union is reserved for other kinds of SAR sources
* which might not re-use same format with array common. * which might not re-use same format with array common.
*/ */
union rtw_sar_cfg { union rtw_sar_cfg {
@ -1847,13 +1895,16 @@ struct rtw_hal {
u8 cut_version; u8 cut_version;
u8 mp_chip; u8 mp_chip;
u8 oem_id; u8 oem_id;
u8 pkg_type;
struct rtw_phy_cond phy_cond; struct rtw_phy_cond phy_cond;
bool rfe_btg;
u8 ps_mode; u8 ps_mode;
u8 current_channel; u8 current_channel;
u8 current_primary_channel_index; u8 current_primary_channel_index;
u8 current_band_width; u8 current_band_width;
u8 current_band_type; u8 current_band_type;
u8 primary_channel;
/* center channel for different available bandwidth, /* center channel for different available bandwidth,
* val of (bw > current_band_width) is invalid * val of (bw > current_band_width) is invalid
@ -1867,6 +1918,7 @@ struct rtw_hal {
u32 antenna_tx; u32 antenna_tx;
u32 antenna_rx; u32 antenna_rx;
u8 bfee_sts_cap; u8 bfee_sts_cap;
bool txrx_1ss;
/* protect tx power section */ /* protect tx power section */
struct mutex tx_power_mutex; struct mutex tx_power_mutex;
@ -1891,6 +1943,9 @@ struct rtw_hal {
enum rtw_sar_bands sar_band; enum rtw_sar_bands sar_band;
struct rtw_sar sar; struct rtw_sar sar;
/* for 8821c set channel */
u32 ch_param[3];
}; };
struct rtw_path_div { struct rtw_path_div {
@ -1921,6 +1976,7 @@ struct rtw_hw_scan_info {
struct ieee80211_vif *scanning_vif; struct ieee80211_vif *scanning_vif;
u8 probe_pg_size; u8 probe_pg_size;
u8 op_pri_ch_idx; u8 op_pri_ch_idx;
u8 op_pri_ch;
u8 op_chan; u8 op_chan;
u8 op_bw; u8 op_bw;
}; };
@ -1932,7 +1988,7 @@ struct rtw_dev {
struct rtw_hci hci; struct rtw_hci hci;
struct rtw_hw_scan_info scan_info; struct rtw_hw_scan_info scan_info;
struct rtw_chip_info *chip; const struct rtw_chip_info *chip;
struct rtw_hal hal; struct rtw_hal hal;
struct rtw_fifo_conf fifo; struct rtw_fifo_conf fifo;
struct rtw_fw_state fw; struct rtw_fw_state fw;
@ -1948,9 +2004,6 @@ struct rtw_dev {
/* ensures exclusive access from mac80211 callbacks */ /* ensures exclusive access from mac80211 callbacks */
struct mutex mutex; struct mutex mutex;
/* read/write rf register */
spinlock_t rf_lock;
/* watch dog every 2 sec */ /* watch dog every 2 sec */
struct delayed_work watch_dog_work; struct delayed_work watch_dog_work;
u32 watch_dog_cnt; u32 watch_dog_cnt;
@ -1960,7 +2013,9 @@ struct rtw_dev {
/* c2h cmd queue & handler work */ /* c2h cmd queue & handler work */
struct sk_buff_head c2h_queue; struct sk_buff_head c2h_queue;
struct work_struct c2h_work; struct work_struct c2h_work;
struct work_struct ips_work;
struct work_struct fw_recovery_work; struct work_struct fw_recovery_work;
struct work_struct update_beacon_work;
/* used to protect txqs list */ /* used to protect txqs list */
spinlock_t txq_lock; spinlock_t txq_lock;
@ -1972,10 +2027,8 @@ struct rtw_dev {
struct rtw_tx_report tx_report; struct rtw_tx_report tx_report;
struct { struct {
/* incicate the mail box to use with fw */ /* indicate the mail box to use with fw */
u8 last_box_num; u8 last_box_num;
/* protect to send h2c to fw */
spinlock_t lock;
u32 seq; u32 seq;
} h2c; } h2c;
@ -1990,6 +2043,7 @@ struct rtw_dev {
u8 sta_cnt; u8 sta_cnt;
u32 rts_threshold; u32 rts_threshold;
DECLARE_BITMAP(hw_port, RTW_PORT_NUM);
DECLARE_BITMAP(mac_id_map, RTW_MAX_MAC_ID_NUM); DECLARE_BITMAP(mac_id_map, RTW_MAX_MAC_ID_NUM);
DECLARE_BITMAP(flags, NUM_OF_RTW_FLAGS); DECLARE_BITMAP(flags, NUM_OF_RTW_FLAGS);
@ -2001,6 +2055,7 @@ struct rtw_dev {
bool need_rfk; bool need_rfk;
struct completion fw_scan_density; struct completion fw_scan_density;
bool ap_active;
/* hci related data, must be last */ /* hci related data, must be last */
u8 priv[] __aligned(sizeof(void *)); u8 priv[] __aligned(sizeof(void *));
@ -2084,7 +2139,22 @@ static inline int rtw_chip_dump_fw_crash(struct rtw_dev *rtwdev)
return 0; return 0;
} }
static inline
enum nl80211_band rtw_hw_to_nl80211_band(enum rtw_supported_band hw_band)
{
switch (hw_band) {
default:
case RTW_BAND_2G:
return NL80211_BAND_2GHZ;
case RTW_BAND_5G:
return NL80211_BAND_5GHZ;
case RTW_BAND_60G:
return NL80211_BAND_60GHZ;
}
}
void rtw_set_rx_freq_band(struct rtw_rx_pkt_stat *pkt_stat, u8 channel); void rtw_set_rx_freq_band(struct rtw_rx_pkt_stat *pkt_stat, u8 channel);
void rtw_set_dtim_period(struct rtw_dev *rtwdev, int dtim_period);
void rtw_get_channel_params(struct cfg80211_chan_def *chandef, void rtw_get_channel_params(struct cfg80211_chan_def *chandef,
struct rtw_channel_params *ch_param); struct rtw_channel_params *ch_param);
bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target); bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target);
@ -2098,10 +2168,12 @@ void rtw_chip_prepare_tx(struct rtw_dev *rtwdev);
void rtw_vif_port_config(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif, void rtw_vif_port_config(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif,
u32 config); u32 config);
void rtw_tx_report_purge_timer(struct timer_list *t); void rtw_tx_report_purge_timer(struct timer_list *t);
void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si); void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si,
bool reset_ra_mask);
void rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif, void rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif,
const u8 *mac_addr, bool hw_scan); const u8 *mac_addr, bool hw_scan);
void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif); void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
bool hw_scan);
int rtw_core_start(struct rtw_dev *rtwdev); int rtw_core_start(struct rtw_dev *rtwdev);
void rtw_core_stop(struct rtw_dev *rtwdev); void rtw_core_stop(struct rtw_dev *rtwdev);
int rtw_chip_info_setup(struct rtw_dev *rtwdev); int rtw_chip_info_setup(struct rtw_dev *rtwdev);
@ -2121,5 +2193,11 @@ void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start);
int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size,
u32 fwcd_item); u32 fwcd_item);
int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size); int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size);
void rtw_set_txrx_1ss(struct rtw_dev *rtwdev, bool config_1ss);
void rtw_update_channel(struct rtw_dev *rtwdev, u8 center_channel,
u8 primary_channel, enum rtw_supported_band band,
enum rtw_bandwidth bandwidth);
void rtw_core_port_switch(struct rtw_dev *rtwdev, struct ieee80211_vif *vif);
bool rtw_core_check_sta_active(struct rtw_dev *rtwdev);
void rtw_core_enable_beacon(struct rtw_dev *rtwdev, bool enable);
#endif #endif

97
pci.c
View file

@ -30,7 +30,8 @@ static u32 rtw_pci_tx_queue_idx_addr[] = {
[RTW_TX_QUEUE_H2C] = RTK_PCI_TXBD_IDX_H2CQ, [RTW_TX_QUEUE_H2C] = RTK_PCI_TXBD_IDX_H2CQ,
}; };
static u8 rtw_pci_get_tx_qsel(struct sk_buff *skb, u8 queue) static u8 rtw_pci_get_tx_qsel(struct sk_buff *skb,
enum rtw_tx_queue_type queue)
{ {
switch (queue) { switch (queue) {
case RTW_TX_QUEUE_BCN: case RTW_TX_QUEUE_BCN:
@ -88,13 +89,6 @@ static void rtw_pci_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
writel(val, rtwpci->mmap + addr); writel(val, rtwpci->mmap + addr);
} }
static inline void *rtw_pci_get_tx_desc(struct rtw_pci_tx_ring *tx_ring, u8 idx)
{
int offset = tx_ring->r.desc_size * idx;
return tx_ring->r.head + offset;
}
static void rtw_pci_free_tx_ring_skbs(struct rtw_dev *rtwdev, static void rtw_pci_free_tx_ring_skbs(struct rtw_dev *rtwdev,
struct rtw_pci_tx_ring *tx_ring) struct rtw_pci_tx_ring *tx_ring)
{ {
@ -322,7 +316,7 @@ static int rtw_pci_init_trx_ring(struct rtw_dev *rtwdev)
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
struct rtw_pci_tx_ring *tx_ring; struct rtw_pci_tx_ring *tx_ring;
struct rtw_pci_rx_ring *rx_ring; struct rtw_pci_rx_ring *rx_ring;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
int i = 0, j = 0, tx_alloced = 0, rx_alloced = 0; int i = 0, j = 0, tx_alloced = 0, rx_alloced = 0;
int tx_desc_size, rx_desc_size; int tx_desc_size, rx_desc_size;
u32 len; u32 len;
@ -542,7 +536,7 @@ static int rtw_pci_setup(struct rtw_dev *rtwdev)
static void rtw_pci_dma_release(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci) static void rtw_pci_dma_release(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci)
{ {
struct rtw_pci_tx_ring *tx_ring; struct rtw_pci_tx_ring *tx_ring;
u8 queue; enum rtw_tx_queue_type queue;
rtw_pci_reset_trx_ring(rtwdev); rtw_pci_reset_trx_ring(rtwdev);
for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) { for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) {
@ -608,8 +602,8 @@ static void rtw_pci_deep_ps_enter(struct rtw_dev *rtwdev)
{ {
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
struct rtw_pci_tx_ring *tx_ring; struct rtw_pci_tx_ring *tx_ring;
enum rtw_tx_queue_type queue;
bool tx_empty = true; bool tx_empty = true;
u8 queue;
if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE)) if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE))
goto enter_deep_ps; goto enter_deep_ps;
@ -669,34 +663,6 @@ static void rtw_pci_deep_ps(struct rtw_dev *rtwdev, bool enter)
spin_unlock_bh(&rtwpci->irq_lock); spin_unlock_bh(&rtwpci->irq_lock);
} }
static u8 ac_to_hwq[] = {
[IEEE80211_AC_VO] = RTW_TX_QUEUE_VO,
[IEEE80211_AC_VI] = RTW_TX_QUEUE_VI,
[IEEE80211_AC_BE] = RTW_TX_QUEUE_BE,
[IEEE80211_AC_BK] = RTW_TX_QUEUE_BK,
};
static_assert(ARRAY_SIZE(ac_to_hwq) == IEEE80211_NUM_ACS);
static u8 rtw_hw_queue_mapping(struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
u8 q_mapping = skb_get_queue_mapping(skb);
u8 queue;
if (unlikely(ieee80211_is_beacon(fc)))
queue = RTW_TX_QUEUE_BCN;
else if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)))
queue = RTW_TX_QUEUE_MGMT;
else if (WARN_ON_ONCE(q_mapping >= ARRAY_SIZE(ac_to_hwq)))
queue = ac_to_hwq[IEEE80211_AC_BE];
else
queue = ac_to_hwq[q_mapping];
return queue;
}
static void rtw_pci_release_rsvd_page(struct rtw_pci *rtwpci, static void rtw_pci_release_rsvd_page(struct rtw_pci *rtwpci,
struct rtw_pci_tx_ring *ring) struct rtw_pci_tx_ring *ring)
{ {
@ -718,7 +684,7 @@ static void rtw_pci_dma_check(struct rtw_dev *rtwdev,
u32 idx) u32 idx)
{ {
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_pci_rx_buffer_desc *buf_desc; struct rtw_pci_rx_buffer_desc *buf_desc;
u32 desc_sz = chip->rx_buf_desc_sz; u32 desc_sz = chip->rx_buf_desc_sz;
u16 total_pkt_size; u16 total_pkt_size;
@ -772,8 +738,9 @@ static void __rtw_pci_flush_queues(struct rtw_dev *rtwdev, u32 pci_queues,
u8 q; u8 q;
for (q = 0; q < RTK_MAX_TX_QUEUE_NUM; q++) { for (q = 0; q < RTK_MAX_TX_QUEUE_NUM; q++) {
/* It may be not necessary to flush BCN and H2C tx queues. */ /* Unnecessary to flush BCN, H2C and HI tx queues. */
if (q == RTW_TX_QUEUE_BCN || q == RTW_TX_QUEUE_H2C) if (q == RTW_TX_QUEUE_BCN || q == RTW_TX_QUEUE_H2C ||
q == RTW_TX_QUEUE_HI0)
continue; continue;
if (pci_queues & BIT(q)) if (pci_queues & BIT(q))
@ -794,13 +761,14 @@ static void rtw_pci_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop)
} else { } else {
for (i = 0; i < rtwdev->hw->queues; i++) for (i = 0; i < rtwdev->hw->queues; i++)
if (queues & BIT(i)) if (queues & BIT(i))
pci_queues |= BIT(ac_to_hwq[i]); pci_queues |= BIT(rtw_tx_ac_to_hwq(i));
} }
__rtw_pci_flush_queues(rtwdev, pci_queues, drop); __rtw_pci_flush_queues(rtwdev, pci_queues, drop);
} }
static void rtw_pci_tx_kick_off_queue(struct rtw_dev *rtwdev, u8 queue) static void rtw_pci_tx_kick_off_queue(struct rtw_dev *rtwdev,
enum rtw_tx_queue_type queue)
{ {
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
struct rtw_pci_tx_ring *ring; struct rtw_pci_tx_ring *ring;
@ -819,7 +787,7 @@ static void rtw_pci_tx_kick_off_queue(struct rtw_dev *rtwdev, u8 queue)
static void rtw_pci_tx_kick_off(struct rtw_dev *rtwdev) static void rtw_pci_tx_kick_off(struct rtw_dev *rtwdev)
{ {
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
u8 queue; enum rtw_tx_queue_type queue;
for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++)
if (test_and_clear_bit(queue, rtwpci->tx_queued)) if (test_and_clear_bit(queue, rtwpci->tx_queued))
@ -828,10 +796,11 @@ static void rtw_pci_tx_kick_off(struct rtw_dev *rtwdev)
static int rtw_pci_tx_write_data(struct rtw_dev *rtwdev, static int rtw_pci_tx_write_data(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info, struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb, u8 queue) struct sk_buff *skb,
enum rtw_tx_queue_type queue)
{ {
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_pci_tx_ring *ring; struct rtw_pci_tx_ring *ring;
struct rtw_pci_tx_data *tx_data; struct rtw_pci_tx_data *tx_data;
dma_addr_t dma; dma_addr_t dma;
@ -946,9 +915,9 @@ static int rtw_pci_tx_write(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info, struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb) struct sk_buff *skb)
{ {
enum rtw_tx_queue_type queue = rtw_tx_queue_mapping(skb);
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
struct rtw_pci_tx_ring *ring; struct rtw_pci_tx_ring *ring;
u8 queue = rtw_hw_queue_mapping(skb);
int ret; int ret;
ret = rtw_pci_tx_write_data(rtwdev, pkt_info, skb, queue); ret = rtw_pci_tx_write_data(rtwdev, pkt_info, skb, queue);
@ -1070,7 +1039,7 @@ static int rtw_pci_get_hw_rx_ring_nr(struct rtw_dev *rtwdev,
static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci, static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
u8 hw_queue, u32 limit) u8 hw_queue, u32 limit)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct napi_struct *napi = &rtwpci->napi; struct napi_struct *napi = &rtwpci->napi;
struct rtw_pci_rx_ring *ring = &rtwpci->rx_rings[RTW_RX_QUEUE_MPDU]; struct rtw_pci_rx_ring *ring = &rtwpci->rx_rings[RTW_RX_QUEUE_MPDU];
struct rtw_rx_pkt_stat pkt_stat; struct rtw_rx_pkt_stat pkt_stat;
@ -1422,7 +1391,7 @@ static void rtw_pci_link_ps(struct rtw_dev *rtwdev, bool enter)
static void rtw_pci_link_cfg(struct rtw_dev *rtwdev) static void rtw_pci_link_cfg(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
struct pci_dev *pdev = rtwpci->pdev; struct pci_dev *pdev = rtwpci->pdev;
u16 link_ctrl; u16 link_ctrl;
@ -1464,7 +1433,7 @@ static void rtw_pci_link_cfg(struct rtw_dev *rtwdev)
static void rtw_pci_interface_cfg(struct rtw_dev *rtwdev) static void rtw_pci_interface_cfg(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
switch (chip->id) { switch (chip->id) {
case RTW_CHIP_TYPE_8822C: case RTW_CHIP_TYPE_8822C:
@ -1479,12 +1448,15 @@ static void rtw_pci_interface_cfg(struct rtw_dev *rtwdev)
static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev) static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
const struct rtw_chip_info *chip = rtwdev->chip;
struct pci_dev *pdev = rtwpci->pdev;
const struct rtw_intf_phy_para *para; const struct rtw_intf_phy_para *para;
u16 cut; u16 cut;
u16 value; u16 value;
u16 offset; u16 offset;
int i; int i;
int ret;
cut = BIT(0) << rtwdev->hal.cut_version; cut = BIT(0) << rtwdev->hal.cut_version;
@ -1517,13 +1489,22 @@ static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev)
} }
rtw_pci_link_cfg(rtwdev); rtw_pci_link_cfg(rtwdev);
/* Disable 8821ce completion timeout by default */
if (chip->id == RTW_CHIP_TYPE_8821C) {
ret = pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_COMP_TMOUT_DIS);
if (ret)
rtw_err(rtwdev, "failed to set PCI cap, ret = %d\n",
ret);
}
} }
static int __maybe_unused rtw_pci_suspend(struct device *dev) static int __maybe_unused rtw_pci_suspend(struct device *dev)
{ {
struct ieee80211_hw *hw = dev_get_drvdata(dev); struct ieee80211_hw *hw = dev_get_drvdata(dev);
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 6) if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 6)
@ -1535,7 +1516,7 @@ static int __maybe_unused rtw_pci_resume(struct device *dev)
{ {
struct ieee80211_hw *hw = dev_get_drvdata(dev); struct ieee80211_hw *hw = dev_get_drvdata(dev);
struct rtw_dev *rtwdev = hw->priv; struct rtw_dev *rtwdev = hw->priv;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 6) if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 6)
@ -1565,7 +1546,6 @@ static int rtw_pci_claim(struct rtw_dev *rtwdev, struct pci_dev *pdev)
static void rtw_pci_declaim(struct rtw_dev *rtwdev, struct pci_dev *pdev) static void rtw_pci_declaim(struct rtw_dev *rtwdev, struct pci_dev *pdev)
{ {
pci_clear_master(pdev);
pci_disable_device(pdev); pci_disable_device(pdev);
} }
@ -1702,8 +1682,7 @@ static void rtw_pci_napi_init(struct rtw_dev *rtwdev)
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
init_dummy_netdev(&rtwpci->netdev); init_dummy_netdev(&rtwpci->netdev);
netif_napi_add(&rtwpci->netdev, &rtwpci->napi, rtw_pci_napi_poll, netif_napi_add(&rtwpci->netdev, &rtwpci->napi, rtw_pci_napi_poll);
RTW_NAPI_WEIGHT_NUM);
} }
static void rtw_pci_napi_deinit(struct rtw_dev *rtwdev) static void rtw_pci_napi_deinit(struct rtw_dev *rtwdev)
@ -1770,7 +1749,7 @@ int rtw_pci_probe(struct pci_dev *pdev,
} }
/* Disable PCIe ASPM L1 while doing NAPI poll for 8821CE */ /* Disable PCIe ASPM L1 while doing NAPI poll for 8821CE */
if (pdev->device == 0xc821 && bridge->vendor == PCI_VENDOR_ID_INTEL) if (rtwdev->chip->id == RTW_CHIP_TYPE_8821C && bridge->vendor == PCI_VENDOR_ID_INTEL)
rtwpci->rx_no_aspm = true; rtwpci->rx_no_aspm = true;
rtw_pci_phy_cfg(rtwdev); rtw_pci_phy_cfg(rtwdev);
@ -1833,7 +1812,7 @@ void rtw_pci_shutdown(struct pci_dev *pdev)
{ {
struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct rtw_dev *rtwdev; struct rtw_dev *rtwdev;
struct rtw_chip_info *chip; const struct rtw_chip_info *chip;
if (!hw) if (!hw)
return; return;

69
phy.c
View file

@ -138,7 +138,7 @@ EXPORT_SYMBOL(rtw_phy_set_edcca_th);
void rtw_phy_adaptivity_set_mode(struct rtw_dev *rtwdev) void rtw_phy_adaptivity_set_mode(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_dm_info *dm_info = &rtwdev->dm_info; struct rtw_dm_info *dm_info = &rtwdev->dm_info;
/* turn off in debugfs for debug usage */ /* turn off in debugfs for debug usage */
@ -165,7 +165,7 @@ void rtw_phy_adaptivity_set_mode(struct rtw_dev *rtwdev)
static void rtw_phy_adaptivity_init(struct rtw_dev *rtwdev) static void rtw_phy_adaptivity_init(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
rtw_phy_adaptivity_set_mode(rtwdev); rtw_phy_adaptivity_set_mode(rtwdev);
if (chip->ops->adaptivity_init) if (chip->ops->adaptivity_init)
@ -180,7 +180,7 @@ static void rtw_phy_adaptivity(struct rtw_dev *rtwdev)
static void rtw_phy_cfo_init(struct rtw_dev *rtwdev) static void rtw_phy_cfo_init(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
if (chip->ops->cfo_init) if (chip->ops->cfo_init)
chip->ops->cfo_init(rtwdev); chip->ops->cfo_init(rtwdev);
@ -199,7 +199,7 @@ static void rtw_phy_tx_path_div_init(struct rtw_dev *rtwdev)
void rtw_phy_init(struct rtw_dev *rtwdev) void rtw_phy_init(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_dm_info *dm_info = &rtwdev->dm_info; struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u32 addr, mask; u32 addr, mask;
@ -226,7 +226,7 @@ EXPORT_SYMBOL(rtw_phy_init);
void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi) void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_hal *hal = &rtwdev->hal; struct rtw_hal *hal = &rtwdev->hal;
u32 addr, mask; u32 addr, mask;
u8 path; u8 path;
@ -245,7 +245,7 @@ void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi)
static void rtw_phy_stat_false_alarm(struct rtw_dev *rtwdev) static void rtw_phy_stat_false_alarm(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->false_alarm_statistics(rtwdev); chip->ops->false_alarm_statistics(rtwdev);
} }
@ -300,7 +300,7 @@ static void rtw_phy_stat_rssi(struct rtw_dev *rtwdev)
data.rtwdev = rtwdev; data.rtwdev = rtwdev;
data.min_rssi = U8_MAX; data.min_rssi = U8_MAX;
rtw_iterate_stas_atomic(rtwdev, rtw_phy_stat_rssi_iter, &data); rtw_iterate_stas(rtwdev, rtw_phy_stat_rssi_iter, &data);
dm_info->pre_min_rssi = dm_info->min_rssi; dm_info->pre_min_rssi = dm_info->min_rssi;
dm_info->min_rssi = data.min_rssi; dm_info->min_rssi = data.min_rssi;
@ -536,7 +536,7 @@ static void rtw_phy_ra_info_update_iter(void *data, struct ieee80211_sta *sta)
struct rtw_dev *rtwdev = data; struct rtw_dev *rtwdev = data;
struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;
rtw_update_sta_info(rtwdev, si); rtw_update_sta_info(rtwdev, si, false);
} }
static void rtw_phy_ra_info_update(struct rtw_dev *rtwdev) static void rtw_phy_ra_info_update(struct rtw_dev *rtwdev)
@ -544,7 +544,7 @@ static void rtw_phy_ra_info_update(struct rtw_dev *rtwdev)
if (rtwdev->watch_dog_cnt & 0x3) if (rtwdev->watch_dog_cnt & 0x3)
return; return;
rtw_iterate_stas_atomic(rtwdev, rtw_phy_ra_info_update_iter, rtwdev); rtw_iterate_stas(rtwdev, rtw_phy_ra_info_update_iter, rtwdev);
} }
static u32 rtw_phy_get_rrsr_mask(struct rtw_dev *rtwdev, u8 rate_idx) static u32 rtw_phy_get_rrsr_mask(struct rtw_dev *rtwdev, u8 rate_idx)
@ -597,13 +597,13 @@ static void rtw_phy_rrsr_update(struct rtw_dev *rtwdev)
struct rtw_dm_info *dm_info = &rtwdev->dm_info; struct rtw_dm_info *dm_info = &rtwdev->dm_info;
dm_info->rrsr_mask_min = RRSR_RATE_ORDER_MAX; dm_info->rrsr_mask_min = RRSR_RATE_ORDER_MAX;
rtw_iterate_stas_atomic(rtwdev, rtw_phy_rrsr_mask_min_iter, rtwdev); rtw_iterate_stas(rtwdev, rtw_phy_rrsr_mask_min_iter, rtwdev);
rtw_write32(rtwdev, REG_RRSR, dm_info->rrsr_val_init & dm_info->rrsr_mask_min); rtw_write32(rtwdev, REG_RRSR, dm_info->rrsr_val_init & dm_info->rrsr_mask_min);
} }
static void rtw_phy_dpk_track(struct rtw_dev *rtwdev) static void rtw_phy_dpk_track(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
if (chip->ops->dpk_track) if (chip->ops->dpk_track)
chip->ops->dpk_track(rtwdev); chip->ops->dpk_track(rtwdev);
@ -659,7 +659,7 @@ EXPORT_SYMBOL(rtw_phy_parsing_cfo);
static void rtw_phy_cfo_track(struct rtw_dev *rtwdev) static void rtw_phy_cfo_track(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
if (chip->ops->cfo_track) if (chip->ops->cfo_track)
chip->ops->cfo_track(rtwdev); chip->ops->cfo_track(rtwdev);
@ -720,8 +720,8 @@ static u8 rtw_phy_cck_pd_lv(struct rtw_dev *rtwdev)
static void rtw_phy_cck_pd(struct rtw_dev *rtwdev) static void rtw_phy_cck_pd(struct rtw_dev *rtwdev)
{ {
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_dm_info *dm_info = &rtwdev->dm_info; struct rtw_dm_info *dm_info = &rtwdev->dm_info;
struct rtw_chip_info *chip = rtwdev->chip;
u32 cck_fa = dm_info->cck_fa_cnt; u32 cck_fa = dm_info->cck_fa_cnt;
u8 level; u8 level;
@ -816,23 +816,18 @@ static u8 rtw_phy_linear_2_db(u64 linear)
u8 j; u8 j;
u32 dB; u32 dB;
if (linear >= db_invert_table[11][7])
return 96; /* maximum 96 dB */
for (i = 0; i < 12; i++) { for (i = 0; i < 12; i++) {
if (i <= 2 && (linear << FRAC_BITS) <= db_invert_table[i][7])
break;
else if (i > 2 && linear <= db_invert_table[i][7])
break;
}
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
if (i <= 2 && (linear << FRAC_BITS) <= db_invert_table[i][j]) if (i <= 2 && (linear << FRAC_BITS) <= db_invert_table[i][j])
break; goto cnt;
else if (i > 2 && linear <= db_invert_table[i][j]) else if (i > 2 && linear <= db_invert_table[i][j])
break; goto cnt;
}
} }
return 96; /* maximum 96 dB */
cnt:
if (j == 0 && i == 0) if (j == 0 && i == 0)
goto end; goto end;
@ -900,7 +895,7 @@ u32 rtw_phy_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask) u32 addr, u32 mask)
{ {
struct rtw_hal *hal = &rtwdev->hal; struct rtw_hal *hal = &rtwdev->hal;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
const u32 *base_addr = chip->rf_base_addr; const u32 *base_addr = chip->rf_base_addr;
u32 val, direct_addr; u32 val, direct_addr;
@ -923,7 +918,7 @@ u32 rtw_phy_read_rf_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask) u32 addr, u32 mask)
{ {
struct rtw_hal *hal = &rtwdev->hal; struct rtw_hal *hal = &rtwdev->hal;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_rf_sipi_addr *rf_sipi_addr; const struct rtw_rf_sipi_addr *rf_sipi_addr;
const struct rtw_rf_sipi_addr *rf_sipi_addr_a; const struct rtw_rf_sipi_addr *rf_sipi_addr_a;
u32 val32; u32 val32;
@ -972,8 +967,8 @@ bool rtw_phy_write_rf_reg_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data) u32 addr, u32 mask, u32 data)
{ {
struct rtw_hal *hal = &rtwdev->hal; struct rtw_hal *hal = &rtwdev->hal;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
u32 *sipi_addr = chip->rf_sipi_addr; const u32 *sipi_addr = chip->rf_sipi_addr;
u32 data_and_addr; u32 data_and_addr;
u32 old_data = 0; u32 old_data = 0;
u32 shift; u32 shift;
@ -1012,7 +1007,7 @@ bool rtw_phy_write_rf_reg(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path,
u32 addr, u32 mask, u32 data) u32 addr, u32 mask, u32 data)
{ {
struct rtw_hal *hal = &rtwdev->hal; struct rtw_hal *hal = &rtwdev->hal;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
const u32 *base_addr = chip->rf_base_addr; const u32 *base_addr = chip->rf_base_addr;
u32 direct_addr; u32 direct_addr;
@ -1747,7 +1742,7 @@ EXPORT_SYMBOL(rtw_phy_cfg_rf);
static void rtw_load_rfk_table(struct rtw_dev *rtwdev) static void rtw_load_rfk_table(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info; struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info;
if (!chip->rfk_init_tbl) if (!chip->rfk_init_tbl)
@ -1766,7 +1761,7 @@ static void rtw_load_rfk_table(struct rtw_dev *rtwdev)
void rtw_phy_load_tables(struct rtw_dev *rtwdev) void rtw_phy_load_tables(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
u8 rf_path; u8 rf_path;
rtw_load_table(rtwdev, chip->mac_tbl); rtw_load_table(rtwdev, chip->mac_tbl);
@ -1875,7 +1870,7 @@ static u8 rtw_get_channel_group(u8 channel, u8 rate)
static s8 rtw_phy_get_dis_dpd_by_rate_diff(struct rtw_dev *rtwdev, u16 rate) static s8 rtw_phy_get_dis_dpd_by_rate_diff(struct rtw_dev *rtwdev, u16 rate)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
s8 dpd_diff = 0; s8 dpd_diff = 0;
if (!chip->en_dis_dpd) if (!chip->en_dis_dpd)
@ -1909,7 +1904,7 @@ static u8 rtw_phy_get_2g_tx_power_index(struct rtw_dev *rtwdev,
enum rtw_bandwidth bandwidth, enum rtw_bandwidth bandwidth,
u8 rate, u8 group) u8 rate, u8 group)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
u8 tx_power; u8 tx_power;
bool mcs_rate; bool mcs_rate;
bool above_2ss; bool above_2ss;
@ -1956,7 +1951,7 @@ static u8 rtw_phy_get_5g_tx_power_index(struct rtw_dev *rtwdev,
enum rtw_bandwidth bandwidth, enum rtw_bandwidth bandwidth,
u8 rate, u8 group) u8 rate, u8 group)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
u8 tx_power; u8 tx_power;
u8 upper, lower; u8 upper, lower;
bool mcs_rate; bool mcs_rate;
@ -2209,7 +2204,7 @@ static void rtw_phy_set_tx_power_level_by_path(struct rtw_dev *rtwdev,
void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel) void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_hal *hal = &rtwdev->hal; struct rtw_hal *hal = &rtwdev->hal;
u8 path; u8 path;
@ -2484,7 +2479,7 @@ static void rtw_phy_set_tx_path_by_reg(struct rtw_dev *rtwdev,
{ {
struct rtw_path_div *path_div = &rtwdev->dm_path_div; struct rtw_path_div *path_div = &rtwdev->dm_path_div;
enum rtw_bb_path tx_path_sel_cck = tx_path_sel_1ss; enum rtw_bb_path tx_path_sel_cck = tx_path_sel_1ss;
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
if (tx_path_sel_1ss == path_div->current_tx_path) if (tx_path_sel_1ss == path_div->current_tx_path)
return; return;
@ -2539,7 +2534,7 @@ static void rtw_phy_tx_path_diversity_2ss(struct rtw_dev *rtwdev)
void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev) void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
if (!chip->path_div_supported) if (!chip->path_div_supported)
return; return;

2
phy.h
View file

@ -114,7 +114,7 @@ const struct rtw_table name ## _tbl = { \
static inline const struct rtw_rfe_def *rtw_get_rfe_def(struct rtw_dev *rtwdev) static inline const struct rtw_rfe_def *rtw_get_rfe_def(struct rtw_dev *rtwdev)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
const struct rtw_rfe_def *rfe_def = NULL; const struct rtw_rfe_def *rfe_def = NULL;

57
ps.c
View file

@ -18,15 +18,16 @@ static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
if (ret) if (ret)
rtw_err(rtwdev, "leave idle state failed\n"); rtw_err(rtwdev, "leave idle state failed\n");
rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
rtw_set_channel(rtwdev); rtw_set_channel(rtwdev);
clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags);
return ret; return ret;
} }
int rtw_enter_ips(struct rtw_dev *rtwdev) int rtw_enter_ips(struct rtw_dev *rtwdev)
{ {
set_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags); if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags))
return 0;
rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER); rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
@ -36,8 +37,7 @@ int rtw_enter_ips(struct rtw_dev *rtwdev)
return 0; return 0;
} }
static void rtw_restore_port_cfg_iter(void *data, u8 *mac, static void rtw_restore_port_cfg_iter(void *data, struct ieee80211_vif *vif)
struct ieee80211_vif *vif)
{ {
struct rtw_dev *rtwdev = data; struct rtw_dev *rtwdev = data;
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
@ -50,6 +50,9 @@ int rtw_leave_ips(struct rtw_dev *rtwdev)
{ {
int ret; int ret;
if (test_bit(RTW_FLAG_POWERON, rtwdev->flags))
return 0;
rtw_hci_link_ps(rtwdev, false); rtw_hci_link_ps(rtwdev, false);
ret = rtw_ips_pwr_up(rtwdev); ret = rtw_ips_pwr_up(rtwdev);
@ -58,9 +61,7 @@ int rtw_leave_ips(struct rtw_dev *rtwdev)
return ret; return ret;
} }
rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev); rtw_iterate_vifs(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
return 0; return 0;
} }
@ -296,3 +297,45 @@ void rtw_leave_lps_deep(struct rtw_dev *rtwdev)
__rtw_leave_lps_deep(rtwdev); __rtw_leave_lps_deep(rtwdev);
} }
struct rtw_vif_recalc_lps_iter_data {
struct rtw_dev *rtwdev;
struct ieee80211_vif *found_vif;
int count;
};
static void __rtw_vif_recalc_lps(struct rtw_vif_recalc_lps_iter_data *data,
struct ieee80211_vif *vif)
{
if (data->count < 0)
return;
if (vif->type != NL80211_IFTYPE_STATION) {
data->count = -1;
return;
}
data->count++;
data->found_vif = vif;
}
static void rtw_vif_recalc_lps_iter(void *data, struct ieee80211_vif *vif)
{
__rtw_vif_recalc_lps(data, vif);
}
void rtw_recalc_lps(struct rtw_dev *rtwdev, struct ieee80211_vif *new_vif)
{
struct rtw_vif_recalc_lps_iter_data data = { .rtwdev = rtwdev };
if (new_vif)
__rtw_vif_recalc_lps(&data, new_vif);
rtw_iterate_vifs(rtwdev, rtw_vif_recalc_lps_iter, &data);
if (data.count == 1 && data.found_vif->cfg.ps) {
rtwdev->ps_enabled = true;
} else {
rtwdev->ps_enabled = false;
rtw_leave_lps(rtwdev);
}
}

2
ps.h
View file

@ -23,4 +23,6 @@ void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id);
void rtw_leave_lps(struct rtw_dev *rtwdev); void rtw_leave_lps(struct rtw_dev *rtwdev);
void rtw_leave_lps_deep(struct rtw_dev *rtwdev); void rtw_leave_lps_deep(struct rtw_dev *rtwdev);
enum rtw_lps_deep_mode rtw_get_lps_deep_mode(struct rtw_dev *rtwdev); enum rtw_lps_deep_mode rtw_get_lps_deep_mode(struct rtw_dev *rtwdev);
void rtw_recalc_lps(struct rtw_dev *rtwdev, struct ieee80211_vif *new_vif);
#endif #endif

17
reg.h
View file

@ -87,6 +87,7 @@
#define BIT_LTE_MUX_CTRL_PATH BIT(26) #define BIT_LTE_MUX_CTRL_PATH BIT(26)
#define REG_HCI_OPT_CTRL 0x0074 #define REG_HCI_OPT_CTRL 0x0074
#define BIT_USB_SUS_DIS BIT(8) #define BIT_USB_SUS_DIS BIT(8)
#define BIT_SDIO_PAD_E5 BIT(18)
#define REG_AFE_CTRL_4 0x0078 #define REG_AFE_CTRL_4 0x0078
#define BIT_CK320M_AFE_EN BIT(4) #define BIT_CK320M_AFE_EN BIT(4)
@ -184,6 +185,10 @@
#define BIT_TXDMA_VIQ_MAP(x) \ #define BIT_TXDMA_VIQ_MAP(x) \
(((x) & BIT_MASK_TXDMA_VIQ_MAP) << BIT_SHIFT_TXDMA_VIQ_MAP) (((x) & BIT_MASK_TXDMA_VIQ_MAP) << BIT_SHIFT_TXDMA_VIQ_MAP)
#define REG_TXDMA_PQ_MAP 0x010C #define REG_TXDMA_PQ_MAP 0x010C
#define BIT_RXDMA_ARBBW_EN BIT(0)
#define BIT_RXSHFT_EN BIT(1)
#define BIT_RXDMA_AGG_EN BIT(2)
#define BIT_TXDMA_BW_EN BIT(3)
#define BIT_SHIFT_TXDMA_BEQ_MAP 8 #define BIT_SHIFT_TXDMA_BEQ_MAP 8
#define BIT_MASK_TXDMA_BEQ_MAP 0x3 #define BIT_MASK_TXDMA_BEQ_MAP 0x3
#define BIT_TXDMA_BEQ_MAP(x) \ #define BIT_TXDMA_BEQ_MAP(x) \
@ -282,10 +287,18 @@
#define REG_H2C_TAIL 0x0248 #define REG_H2C_TAIL 0x0248
#define REG_H2C_READ_ADDR 0x024C #define REG_H2C_READ_ADDR 0x024C
#define REG_H2C_INFO 0x0254 #define REG_H2C_INFO 0x0254
#define REG_RXDMA_AGG_PG_TH 0x0280
#define BIT_RXDMA_AGG_PG_TH GENMASK(7, 0)
#define BIT_DMA_AGG_TO_V1 GENMASK(15, 8)
#define BIT_EN_PRE_CALC BIT(29)
#define REG_RXPKT_NUM 0x0284 #define REG_RXPKT_NUM 0x0284
#define BIT_RXDMA_REQ BIT(19) #define BIT_RXDMA_REQ BIT(19)
#define BIT_RW_RELEASE BIT(18) #define BIT_RW_RELEASE BIT(18)
#define BIT_RXDMA_IDLE BIT(17) #define BIT_RXDMA_IDLE BIT(17)
#define REG_RXDMA_STATUS 0x0288
#define REG_RXDMA_DPR 0x028C
#define REG_RXDMA_MODE 0x0290
#define BIT_DMA_MODE BIT(1)
#define REG_RXPKTNUM 0x02B0 #define REG_RXPKTNUM 0x02B0
#define REG_INT_MIG 0x0304 #define REG_INT_MIG 0x0304
@ -365,6 +378,7 @@
#define BIT_SIFS_BK_EN BIT(12) #define BIT_SIFS_BK_EN BIT(12)
#define REG_TXPAUSE 0x0522 #define REG_TXPAUSE 0x0522
#define BIT_AC_QUEUE GENMASK(7, 0) #define BIT_AC_QUEUE GENMASK(7, 0)
#define BIT_HIGH_QUEUE BIT(5)
#define REG_RD_CTRL 0x0524 #define REG_RD_CTRL 0x0524
#define BIT_EDCCA_MSK_CNTDOWN_EN BIT(11) #define BIT_EDCCA_MSK_CNTDOWN_EN BIT(11)
#define BIT_DIS_TXOP_CFE BIT(10) #define BIT_DIS_TXOP_CFE BIT(10)
@ -389,12 +403,15 @@
#define BIT_EN_FREE_CNT BIT(3) #define BIT_EN_FREE_CNT BIT(3)
#define BIT_DIS_SECOND_CCA (BIT(0) | BIT(1)) #define BIT_DIS_SECOND_CCA (BIT(0) | BIT(1))
#define REG_HIQ_NO_LMT_EN 0x5A7 #define REG_HIQ_NO_LMT_EN 0x5A7
#define REG_DTIM_COUNTER_ROOT 0x5A8
#define BIT_HIQ_NO_LMT_EN_ROOT BIT(0) #define BIT_HIQ_NO_LMT_EN_ROOT BIT(0)
#define REG_TIMER0_SRC_SEL 0x05B4 #define REG_TIMER0_SRC_SEL 0x05B4
#define BIT_TSFT_SEL_TIMER0 (BIT(4) | BIT(5) | BIT(6)) #define BIT_TSFT_SEL_TIMER0 (BIT(4) | BIT(5) | BIT(6))
#define REG_TCR 0x0604 #define REG_TCR 0x0604
#define BIT_PWRMGT_HWDATA_EN BIT(7) #define BIT_PWRMGT_HWDATA_EN BIT(7)
#define BIT_TCR_UPDATE_TIMIE BIT(5)
#define BIT_TCR_UPDATE_HGQMD BIT(4)
#define REG_RCR 0x0608 #define REG_RCR 0x0608
#define BIT_APP_FCS BIT(31) #define BIT_APP_FCS BIT(31)
#define BIT_APP_MIC BIT(30) #define BIT_APP_MIC BIT(30)

2
regd.c
View file

@ -479,6 +479,7 @@ void rtw_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request)
rtw_dbg(rtwdev, RTW_DBG_REGD, "regd state: %d -> %d\n", rtw_dbg(rtwdev, RTW_DBG_REGD, "regd state: %d -> %d\n",
rtwdev->regd.state, next_regd.state); rtwdev->regd.state, next_regd.state);
mutex_lock(&rtwdev->mutex);
rtwdev->regd = next_regd; rtwdev->regd = next_regd;
rtw_dbg_regd_dump(rtwdev, "get alpha2 %c%c from initiator %d: ", rtw_dbg_regd_dump(rtwdev, "get alpha2 %c%c from initiator %d: ",
request->alpha2[0], request->alpha2[0],
@ -487,6 +488,7 @@ void rtw_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request)
rtw_phy_adaptivity_set_mode(rtwdev); rtw_phy_adaptivity_set_mode(rtwdev);
rtw_phy_set_tx_power_level(rtwdev, hal->current_channel); rtw_phy_set_tx_power_level(rtwdev, hal->current_channel);
mutex_unlock(&rtwdev->mutex);
} }
u8 rtw_regd_get(struct rtw_dev *rtwdev) u8 rtw_regd_get(struct rtw_dev *rtwdev)

View file

@ -210,6 +210,18 @@ static void rtw8723de_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->e.mac_addr); ether_addr_copy(efuse->addr, map->e.mac_addr);
} }
static void rtw8723du_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8723d_efuse *map)
{
ether_addr_copy(efuse->addr, map->u.mac_addr);
}
static void rtw8723ds_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8723d_efuse *map)
{
ether_addr_copy(efuse->addr, map->s.mac_addr);
}
static int rtw8723d_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) static int rtw8723d_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{ {
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
@ -239,6 +251,12 @@ static int rtw8723d_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
case RTW_HCI_TYPE_PCIE: case RTW_HCI_TYPE_PCIE:
rtw8723de_efuse_parsing(efuse, map); rtw8723de_efuse_parsing(efuse, map);
break; break;
case RTW_HCI_TYPE_USB:
rtw8723du_efuse_parsing(efuse, map);
break;
case RTW_HCI_TYPE_SDIO:
rtw8723ds_efuse_parsing(efuse, map);
break;
default: default:
/* unsupported now */ /* unsupported now */
return -ENOTSUPP; return -ENOTSUPP;
@ -1945,6 +1963,26 @@ static void rtw8723d_pwr_track(struct rtw_dev *rtwdev)
dm_info->pwr_trk_triggered = false; dm_info->pwr_trk_triggered = false;
} }
static void rtw8723d_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
{
size_t words = 32 / 2; /* calculate the first 32 bytes (16 words) */
__le16 chksum = 0;
__le16 *data = (__le16 *)(txdesc);
struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)txdesc;
le32p_replace_bits(&tx_desc->w7, 0, RTW_TX_DESC_W7_TXDESC_CHECKSUM);
while (words--)
chksum ^= *data++;
chksum = ~chksum;
le32p_replace_bits(&tx_desc->w7, __le16_to_cpu(chksum),
RTW_TX_DESC_W7_TXDESC_CHECKSUM);
}
static struct rtw_chip_ops rtw8723d_ops = { static struct rtw_chip_ops rtw8723d_ops = {
.phy_set_param = rtw8723d_phy_set_param, .phy_set_param = rtw8723d_phy_set_param,
.read_efuse = rtw8723d_read_efuse, .read_efuse = rtw8723d_read_efuse,
@ -1965,6 +2003,7 @@ static struct rtw_chip_ops rtw8723d_ops = {
.config_bfee = NULL, .config_bfee = NULL,
.set_gid_table = NULL, .set_gid_table = NULL,
.cfg_csi_rate = NULL, .cfg_csi_rate = NULL,
.fill_txdesc_checksum = rtw8723d_fill_txdesc_checksum,
.coex_set_init = rtw8723d_coex_cfg_init, .coex_set_init = rtw8723d_coex_cfg_init,
.coex_set_ant_switch = NULL, .coex_set_ant_switch = NULL,
@ -2701,7 +2740,7 @@ static const struct rtw_reg_domain coex_info_hw_regs_8723d[] = {
{0x953, BIT(1), RTW_REG_DOMAIN_MAC8}, {0x953, BIT(1), RTW_REG_DOMAIN_MAC8},
}; };
struct rtw_chip_info rtw8723d_hw_spec = { const struct rtw_chip_info rtw8723d_hw_spec = {
.ops = &rtw8723d_ops, .ops = &rtw8723d_ops,
.id = RTW_CHIP_TYPE_8723D, .id = RTW_CHIP_TYPE_8723D,
.fw_name = "rtw88/rtw8723d_fw.bin", .fw_name = "rtw88/rtw8723d_fw.bin",
@ -2715,12 +2754,13 @@ struct rtw_chip_info rtw8723d_hw_spec = {
.ptct_efuse_size = 96 + 1, .ptct_efuse_size = 96 + 1,
.txff_size = 32768, .txff_size = 32768,
.rxff_size = 16384, .rxff_size = 16384,
.rsvd_drv_pg_num = 8,
.txgi_factor = 1, .txgi_factor = 1,
.is_pwr_by_rate_dec = true, .is_pwr_by_rate_dec = true,
.max_power_index = 0x3f, .max_power_index = 0x3f,
.csi_buf_pg_num = 0, .csi_buf_pg_num = 0,
.band = RTW_BAND_2G, .band = RTW_BAND_2G,
.page_size = 128, .page_size = TX_PAGE_SIZE,
.dig_min = 0x20, .dig_min = 0x20,
.ht_supported = true, .ht_supported = true,
.vht_supported = false, .vht_supported = false,
@ -2747,12 +2787,15 @@ struct rtw_chip_info rtw8723d_hw_spec = {
.rx_ldpc = false, .rx_ldpc = false,
.pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl, .pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl,
.iqk_threshold = 8, .iqk_threshold = 8,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
.coex_para_ver = 0x2007022f, .coex_para_ver = 0x2007022f,
.bt_desired_ver = 0x2f, .bt_desired_ver = 0x2f,
.scbd_support = true, .scbd_support = true,
.new_scbd10_def = true, .new_scbd10_def = true,
.ble_hid_profile_support = false, .ble_hid_profile_support = false,
.wl_mimo_ps_support = false,
.pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
.bt_rssi_type = COEX_BTRSSI_RATIO, .bt_rssi_type = COEX_BTRSSI_RATIO,
.ant_isolation = 15, .ant_isolation = 15,

View file

@ -41,6 +41,19 @@ struct rtw8723de_efuse {
u8 sub_device_id[2]; u8 sub_device_id[2];
}; };
struct rtw8723du_efuse {
u8 res4[48]; /* 0xd0 */
u8 vender_id[2]; /* 0x100 */
u8 product_id[2]; /* 0x102 */
u8 usb_option; /* 0x104 */
u8 mac_addr[ETH_ALEN]; /* 0x107 */
};
struct rtw8723ds_efuse {
u8 res4[0x4a]; /* 0xd0 */
u8 mac_addr[ETH_ALEN]; /* 0x11a */
};
struct rtw8723d_efuse { struct rtw8723d_efuse {
__le16 rtl_id; __le16 rtl_id;
u8 rsvd[2]; u8 rsvd[2];
@ -69,8 +82,14 @@ struct rtw8723d_efuse {
u8 rfe_option; u8 rfe_option;
u8 country_code[2]; u8 country_code[2];
u8 res[3]; u8 res[3];
union {
struct rtw8723de_efuse e; struct rtw8723de_efuse e;
struct rtw8723du_efuse u;
struct rtw8723ds_efuse s;
}; };
};
extern const struct rtw_chip_info rtw8723d_hw_spec;
/* phy status page0 */ /* phy status page0 */
#define GET_PHY_STAT_P0_PWDB(phy_stat) \ #define GET_PHY_STAT_P0_PWDB(phy_stat) \

View file

@ -5,7 +5,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include "pci.h" #include "pci.h"
#include "rtw8723de.h" #include "rtw8723d.h"
static const struct pci_device_id rtw_8723de_id_table[] = { static const struct pci_device_id rtw_8723de_id_table[] = {
{ {

View file

@ -1,10 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_8723DE_H_
#define __RTW_8723DE_H_
extern struct rtw_chip_info rtw8723d_hw_spec;
#endif

41
rtw8723ds.c Normal file
View file

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*/
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/module.h>
#include "main.h"
#include "rtw8723d.h"
#include "sdio.h"
static const struct sdio_device_id rtw_8723ds_id_table[] = {
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8723DS_1ANT),
.driver_data = (kernel_ulong_t)&rtw8723d_hw_spec,
},
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8723DS_2ANT),
.driver_data = (kernel_ulong_t)&rtw8723d_hw_spec,
},
{}
};
MODULE_DEVICE_TABLE(sdio, rtw_8723ds_id_table);
static struct sdio_driver rtw_8723ds_driver = {
.name = "rtw_8723ds",
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.id_table = rtw_8723ds_id_table,
.drv = {
.pm = &rtw_sdio_pm_ops,
.shutdown = rtw_sdio_shutdown,
}
};
module_sdio_driver(rtw_8723ds_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_DESCRIPTION("Realtek 802.11n wireless 8723ds driver");
MODULE_LICENSE("Dual BSD/GPL");

36
rtw8723du.c Normal file
View file

@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8723d.h"
#include "usb.h"
static const struct usb_device_id rtw_8723du_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd723, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8723d_hw_spec) }, /* 8723DU 1*1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd611, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8723d_hw_spec) }, /* Edimax EW-7611ULB V2 */
{ },
};
MODULE_DEVICE_TABLE(usb, rtw_8723du_id_table);
static int rtw8723du_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return rtw_usb_probe(intf, id);
}
static struct usb_driver rtw_8723du_driver = {
.name = "rtw_8723du",
.id_table = rtw_8723du_id_table,
.probe = rtw8723du_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8723du_driver);
MODULE_AUTHOR("Hans Ulli Kroll <linux@ulli-kroll.de>");
MODULE_DESCRIPTION("Realtek 802.11n wireless 8723du driver");
MODULE_LICENSE("Dual BSD/GPL");

View file

@ -26,6 +26,18 @@ static void rtw8821ce_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->e.mac_addr); ether_addr_copy(efuse->addr, map->e.mac_addr);
} }
static void rtw8821cu_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8821c_efuse *map)
{
ether_addr_copy(efuse->addr, map->u.mac_addr);
}
static void rtw8821cs_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8821c_efuse *map)
{
ether_addr_copy(efuse->addr, map->s.mac_addr);
}
enum rtw8821ce_rf_set { enum rtw8821ce_rf_set {
SWITCH_TO_BTG, SWITCH_TO_BTG,
SWITCH_TO_WLG, SWITCH_TO_WLG,
@ -35,13 +47,14 @@ enum rtw8821ce_rf_set {
static int rtw8821c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) static int rtw8821c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{ {
struct rtw_hal *hal = &rtwdev->hal;
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
struct rtw8821c_efuse *map; struct rtw8821c_efuse *map;
int i; int i;
map = (struct rtw8821c_efuse *)log_map; map = (struct rtw8821c_efuse *)log_map;
efuse->rfe_option = map->rfe_option; efuse->rfe_option = map->rfe_option & 0x1f;
efuse->rf_board_option = map->rf_board_option; efuse->rf_board_option = map->rf_board_option;
efuse->crystal_cap = map->xtal_k; efuse->crystal_cap = map->xtal_k;
efuse->pa_type_2g = map->pa_type; efuse->pa_type_2g = map->pa_type;
@ -58,6 +71,19 @@ static int rtw8821c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
efuse->tx_bb_swing_setting_2g = map->tx_bb_swing_setting_2g; efuse->tx_bb_swing_setting_2g = map->tx_bb_swing_setting_2g;
efuse->tx_bb_swing_setting_5g = map->tx_bb_swing_setting_5g; efuse->tx_bb_swing_setting_5g = map->tx_bb_swing_setting_5g;
hal->pkg_type = map->rfe_option & BIT(5) ? 1 : 0;
switch (efuse->rfe_option) {
case 0x2:
case 0x4:
case 0x7:
case 0xa:
case 0xc:
case 0xf:
hal->rfe_btg = true;
break;
}
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i]; efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i];
@ -68,6 +94,12 @@ static int rtw8821c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
case RTW_HCI_TYPE_PCIE: case RTW_HCI_TYPE_PCIE:
rtw8821ce_efuse_parsing(efuse, map); rtw8821ce_efuse_parsing(efuse, map);
break; break;
case RTW_HCI_TYPE_USB:
rtw8821cu_efuse_parsing(efuse, map);
break;
case RTW_HCI_TYPE_SDIO:
rtw8821cs_efuse_parsing(efuse, map);
break;
default: default:
/* unsupported now */ /* unsupported now */
return -ENOTSUPP; return -ENOTSUPP;
@ -125,6 +157,7 @@ static void rtw8821c_phy_bf_init(struct rtw_dev *rtwdev)
static void rtw8821c_phy_set_param(struct rtw_dev *rtwdev) static void rtw8821c_phy_set_param(struct rtw_dev *rtwdev)
{ {
struct rtw_hal *hal = &rtwdev->hal;
u8 crystal_cap, val; u8 crystal_cap, val;
/* power on BB/RF domain */ /* power on BB/RF domain */
@ -159,9 +192,9 @@ static void rtw8821c_phy_set_param(struct rtw_dev *rtwdev)
/* post init after header files config */ /* post init after header files config */
rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST); rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST);
rtwdev->chip->ch_param[0] = rtw_read32_mask(rtwdev, REG_TXSF2, MASKDWORD); hal->ch_param[0] = rtw_read32_mask(rtwdev, REG_TXSF2, MASKDWORD);
rtwdev->chip->ch_param[1] = rtw_read32_mask(rtwdev, REG_TXSF6, MASKDWORD); hal->ch_param[1] = rtw_read32_mask(rtwdev, REG_TXSF6, MASKDWORD);
rtwdev->chip->ch_param[2] = rtw_read32_mask(rtwdev, REG_TXFILTER, MASKDWORD); hal->ch_param[2] = rtw_read32_mask(rtwdev, REG_TXFILTER, MASKDWORD);
rtw_phy_init(rtwdev); rtw_phy_init(rtwdev);
rtwdev->dm_info.cck_pd_default = rtw_read8(rtwdev, REG_CSRATIO) & 0x1f; rtwdev->dm_info.cck_pd_default = rtw_read8(rtwdev, REG_CSRATIO) & 0x1f;
@ -276,6 +309,7 @@ static void rtw8821c_switch_rf_set(struct rtw_dev *rtwdev, u8 rf_set)
static void rtw8821c_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw) static void rtw8821c_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw)
{ {
struct rtw_hal *hal = &rtwdev->hal;
u32 rf_reg18; u32 rf_reg18;
rf_reg18 = rtw_read_rf(rtwdev, RF_PATH_A, 0x18, RFREG_MASK); rf_reg18 = rtw_read_rf(rtwdev, RF_PATH_A, 0x18, RFREG_MASK);
@ -307,11 +341,10 @@ static void rtw8821c_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw)
} }
if (channel <= 14) { if (channel <= 14) {
if (rtwdev->efuse.rfe_option == 0) if (hal->rfe_btg)
rtw8821c_switch_rf_set(rtwdev, SWITCH_TO_WLG);
else if (rtwdev->efuse.rfe_option == 2 ||
rtwdev->efuse.rfe_option == 4)
rtw8821c_switch_rf_set(rtwdev, SWITCH_TO_BTG); rtw8821c_switch_rf_set(rtwdev, SWITCH_TO_BTG);
else
rtw8821c_switch_rf_set(rtwdev, SWITCH_TO_WLG);
rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTDBG, BIT(6), 0x1); rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTDBG, BIT(6), 0x1);
rtw_write_rf(rtwdev, RF_PATH_A, 0x64, 0xf, 0xf); rtw_write_rf(rtwdev, RF_PATH_A, 0x64, 0xf, 0xf);
} else { } else {
@ -351,6 +384,7 @@ static void rtw8821c_set_channel_rxdfir(struct rtw_dev *rtwdev, u8 bw)
static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
u8 primary_ch_idx) u8 primary_ch_idx)
{ {
struct rtw_hal *hal = &rtwdev->hal;
u32 val32; u32 val32;
if (channel <= 14) { if (channel <= 14) {
@ -367,11 +401,11 @@ static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD, 0x00003667); rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD, 0x00003667);
} else { } else {
rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD, rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD,
rtwdev->chip->ch_param[0]); hal->ch_param[0]);
rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD, rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD,
rtwdev->chip->ch_param[1] & MASKLWORD); hal->ch_param[1] & MASKLWORD);
rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD, rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD,
rtwdev->chip->ch_param[2]); hal->ch_param[2]);
} }
} else if (channel > 35) { } else if (channel > 35) {
rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x1); rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x1);
@ -499,7 +533,7 @@ static s8 get_cck_rx_pwr(struct rtw_dev *rtwdev, u8 lna_idx, u8 vga_idx)
} }
if (lna_idx >= lna_gain_table_size) { if (lna_idx >= lna_gain_table_size) {
rtw_info(rtwdev, "incorrect lna index (%d)\n", lna_idx); rtw_warn(rtwdev, "incorrect lna index (%d)\n", lna_idx);
return -120; return -120;
} }
@ -512,6 +546,7 @@ static s8 get_cck_rx_pwr(struct rtw_dev *rtwdev, u8 lna_idx, u8 vga_idx)
static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status,
struct rtw_rx_pkt_stat *pkt_stat) struct rtw_rx_pkt_stat *pkt_stat)
{ {
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
s8 rx_power; s8 rx_power;
u8 lna_idx = 0; u8 lna_idx = 0;
u8 vga_idx = 0; u8 vga_idx = 0;
@ -523,6 +558,7 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status,
pkt_stat->rx_power[RF_PATH_A] = rx_power; pkt_stat->rx_power[RF_PATH_A] = rx_power;
pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1); pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1);
dm_info->rssi[RF_PATH_A] = pkt_stat->rssi;
pkt_stat->bw = RTW_CHANNEL_WIDTH_20; pkt_stat->bw = RTW_CHANNEL_WIDTH_20;
pkt_stat->signal_power = rx_power; pkt_stat->signal_power = rx_power;
} }
@ -530,6 +566,7 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status,
static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status,
struct rtw_rx_pkt_stat *pkt_stat) struct rtw_rx_pkt_stat *pkt_stat)
{ {
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
u8 rxsc, bw; u8 rxsc, bw;
s8 min_rx_power = -120; s8 min_rx_power = -120;
@ -549,6 +586,7 @@ static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status,
pkt_stat->rx_power[RF_PATH_A] = GET_PHY_STAT_P1_PWDB_A(phy_status) - 110; pkt_stat->rx_power[RF_PATH_A] = GET_PHY_STAT_P1_PWDB_A(phy_status) - 110;
pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1); pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1);
dm_info->rssi[RF_PATH_A] = pkt_stat->rssi;
pkt_stat->bw = bw; pkt_stat->bw = bw;
pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A], pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A],
min_rx_power); min_rx_power);
@ -1142,6 +1180,13 @@ static void rtw8821c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl)
dm_info->cck_pd_default + new_lvl * 2); dm_info->cck_pd_default + new_lvl * 2);
} }
static void rtw8821c_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
{
fill_txdesc_checksum_common(txdesc, 16);
}
static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = { static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = {
{0x0086, {0x0086,
RTW_PWR_CUT_ALL_MSK, RTW_PWR_CUT_ALL_MSK,
@ -1514,6 +1559,7 @@ static const struct rtw_rfe_def rtw8821c_rfe_defs[] = {
[0] = RTW_DEF_RFE(8821c, 0, 0), [0] = RTW_DEF_RFE(8821c, 0, 0),
[2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2), [2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2),
[4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2), [4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2),
[6] = RTW_DEF_RFE(8821c, 0, 0),
}; };
static struct rtw_hw_reg rtw8821c_dig[] = { static struct rtw_hw_reg rtw8821c_dig[] = {
@ -1588,6 +1634,7 @@ static struct rtw_chip_ops rtw8821c_ops = {
.config_bfee = rtw8821c_bf_config_bfee, .config_bfee = rtw8821c_bf_config_bfee,
.set_gid_table = rtw_bf_set_gid_table, .set_gid_table = rtw_bf_set_gid_table,
.cfg_csi_rate = rtw_bf_cfg_csi_rate, .cfg_csi_rate = rtw_bf_cfg_csi_rate,
.fill_txdesc_checksum = rtw8821c_fill_txdesc_checksum,
.coex_set_init = rtw8821c_coex_cfg_init, .coex_set_init = rtw8821c_coex_cfg_init,
.coex_set_ant_switch = rtw8821c_coex_cfg_ant_switch, .coex_set_ant_switch = rtw8821c_coex_cfg_ant_switch,
@ -1872,7 +1919,7 @@ static const struct rtw_reg_domain coex_info_hw_regs_8821c[] = {
{0x60A, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, {0x60A, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
}; };
struct rtw_chip_info rtw8821c_hw_spec = { const struct rtw_chip_info rtw8821c_hw_spec = {
.ops = &rtw8821c_ops, .ops = &rtw8821c_ops,
.id = RTW_CHIP_TYPE_8821C, .id = RTW_CHIP_TYPE_8821C,
.fw_name = "rtw88/rtw8821c_fw.bin", .fw_name = "rtw88/rtw8821c_fw.bin",
@ -1886,12 +1933,13 @@ struct rtw_chip_info rtw8821c_hw_spec = {
.ptct_efuse_size = 96, .ptct_efuse_size = 96,
.txff_size = 65536, .txff_size = 65536,
.rxff_size = 16384, .rxff_size = 16384,
.rsvd_drv_pg_num = 8,
.txgi_factor = 1, .txgi_factor = 1,
.is_pwr_by_rate_dec = true, .is_pwr_by_rate_dec = true,
.max_power_index = 0x3f, .max_power_index = 0x3f,
.csi_buf_pg_num = 0, .csi_buf_pg_num = 0,
.band = RTW_BAND_2G | RTW_BAND_5G, .band = RTW_BAND_2G | RTW_BAND_5G,
.page_size = 128, .page_size = TX_PAGE_SIZE,
.dig_min = 0x1c, .dig_min = 0x1c,
.ht_supported = true, .ht_supported = true,
.vht_supported = true, .vht_supported = true,
@ -1918,12 +1966,15 @@ struct rtw_chip_info rtw8821c_hw_spec = {
.iqk_threshold = 8, .iqk_threshold = 8,
.bfer_su_max_num = 2, .bfer_su_max_num = 2,
.bfer_mu_max_num = 1, .bfer_mu_max_num = 1,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_2,
.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
.coex_para_ver = 0x19092746, .coex_para_ver = 0x19092746,
.bt_desired_ver = 0x46, .bt_desired_ver = 0x46,
.scbd_support = true, .scbd_support = true,
.new_scbd10_def = false, .new_scbd10_def = false,
.ble_hid_profile_support = false, .ble_hid_profile_support = false,
.wl_mimo_ps_support = false,
.pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
.bt_rssi_type = COEX_BTRSSI_RATIO, .bt_rssi_type = COEX_BTRSSI_RATIO,
.ant_isolation = 15, .ant_isolation = 15,

View file

@ -9,6 +9,26 @@
#define RCR_VHT_ACK BIT(26) #define RCR_VHT_ACK BIT(26)
struct rtw8821cu_efuse {
u8 res4[4]; /* 0xd0 */
u8 usb_optional_function;
u8 res5[0x1e];
u8 res6[2];
u8 serial[0x0b]; /* 0xf5 */
u8 vid; /* 0x100 */
u8 res7;
u8 pid;
u8 res8[4];
u8 mac_addr[ETH_ALEN]; /* 0x107 */
u8 res9[2];
u8 vendor_name[0x07];
u8 res10[2];
u8 device_name[0x14];
u8 res11[0xcf];
u8 package_type; /* 0x1fb */
u8 res12[0x4];
};
struct rtw8821ce_efuse { struct rtw8821ce_efuse {
u8 mac_addr[ETH_ALEN]; /* 0xd0 */ u8 mac_addr[ETH_ALEN]; /* 0xd0 */
u8 vender_id[2]; u8 vender_id[2];
@ -45,6 +65,11 @@ struct rtw8821ce_efuse {
u8 res7; u8 res7;
}; };
struct rtw8821cs_efuse {
u8 res4[0x4a]; /* 0xd0 */
u8 mac_addr[ETH_ALEN]; /* 0x11a */
} __packed;
struct rtw8821c_efuse { struct rtw8821c_efuse {
__le16 rtl_id; __le16 rtl_id;
u8 res0[0x0e]; u8 res0[0x0e];
@ -73,6 +98,8 @@ struct rtw8821c_efuse {
u8 res[3]; u8 res[3];
union { union {
struct rtw8821ce_efuse e; struct rtw8821ce_efuse e;
struct rtw8821cu_efuse u;
struct rtw8821cs_efuse s;
}; };
}; };
@ -84,6 +111,8 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
rtw_write32_mask(rtwdev, addr + 0x200, mask, data); rtw_write32_mask(rtwdev, addr + 0x200, mask, data);
} }
extern const struct rtw_chip_info rtw8821c_hw_spec;
#define rtw_write32s_mask(rtwdev, addr, mask, data) \ #define rtw_write32s_mask(rtwdev, addr, mask, data) \
do { \ do { \
BUILD_BUG_ON((addr) < 0xC00 || (addr) >= 0xD00); \ BUILD_BUG_ON((addr) < 0xC00 || (addr) >= 0xD00); \

View file

@ -13,7 +13,7 @@ static const u32 rtw8821c_mac[] = {
0x04F, 0x00000001, 0x04F, 0x00000001,
0x029, 0x000000F9, 0x029, 0x000000F9,
0x420, 0x00000080, 0x420, 0x00000080,
0x421, 0x0000000F, 0x421, 0x0000001F,
0x428, 0x0000000A, 0x428, 0x0000000A,
0x429, 0x00000010, 0x429, 0x00000010,
0x430, 0x00000000, 0x430, 0x00000000,

View file

@ -5,9 +5,13 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include "pci.h" #include "pci.h"
#include "rtw8821ce.h" #include "rtw8821c.h"
static const struct pci_device_id rtw_8821ce_id_table[] = { static const struct pci_device_id rtw_8821ce_id_table[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xB821),
.driver_data = (kernel_ulong_t)&rtw8821c_hw_spec
},
{ {
PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xC821), PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xC821),
.driver_data = (kernel_ulong_t)&rtw8821c_hw_spec .driver_data = (kernel_ulong_t)&rtw8821c_hw_spec

View file

@ -1,10 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_8821CE_H_
#define __RTW_8821CE_H_
extern struct rtw_chip_info rtw8821c_hw_spec;
#endif

36
rtw8821cs.c Normal file
View file

@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*/
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/module.h>
#include "main.h"
#include "rtw8821c.h"
#include "sdio.h"
static const struct sdio_device_id rtw_8821cs_id_table[] = {
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8821CS),
.driver_data = (kernel_ulong_t)&rtw8821c_hw_spec,
},
{}
};
MODULE_DEVICE_TABLE(sdio, rtw_8821cs_id_table);
static struct sdio_driver rtw_8821cs_driver = {
.name = "rtw_8821cs",
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.id_table = rtw_8821cs_id_table,
.drv = {
.pm = &rtw_sdio_pm_ops,
.shutdown = rtw_sdio_shutdown,
}
};
module_sdio_driver(rtw_8821cs_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821cs driver");
MODULE_LICENSE("Dual BSD/GPL");

50
rtw8821cu.c Normal file
View file

@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8821c.h"
#include "usb.h"
static const struct usb_device_id rtw_8821cu_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb82b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb820, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc821, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc820, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc811, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8811CU */
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8811, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8811CU */
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x2006, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* TOTOLINK A650UA v3 */
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8821cu_id_table);
static int rtw_8821cu_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return rtw_usb_probe(intf, id);
}
static struct usb_driver rtw_8821cu_driver = {
.name = "rtw_8821cu",
.id_table = rtw_8821cu_id_table,
.probe = rtw_8821cu_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8821cu_driver);
MODULE_AUTHOR("Hans Ulli Kroll <linux@ulli-kroll.de>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821cu driver");
MODULE_LICENSE("Dual BSD/GPL");

View file

@ -26,6 +26,18 @@ static void rtw8822be_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->e.mac_addr); ether_addr_copy(efuse->addr, map->e.mac_addr);
} }
static void rtw8822bu_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8822b_efuse *map)
{
ether_addr_copy(efuse->addr, map->u.mac_addr);
}
static void rtw8822bs_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8822b_efuse *map)
{
ether_addr_copy(efuse->addr, map->s.mac_addr);
}
static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{ {
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
@ -56,6 +68,12 @@ static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
case RTW_HCI_TYPE_PCIE: case RTW_HCI_TYPE_PCIE:
rtw8822be_efuse_parsing(efuse, map); rtw8822be_efuse_parsing(efuse, map);
break; break;
case RTW_HCI_TYPE_USB:
rtw8822bu_efuse_parsing(efuse, map);
break;
case RTW_HCI_TYPE_SDIO:
rtw8822bs_efuse_parsing(efuse, map);
break;
default: default:
/* unsupported now */ /* unsupported now */
return -ENOTSUPP; return -ENOTSUPP;
@ -1012,12 +1030,12 @@ static int rtw8822b_set_antenna(struct rtw_dev *rtwdev,
antenna_tx, antenna_rx); antenna_tx, antenna_rx);
if (!rtw8822b_check_rf_path(antenna_tx)) { if (!rtw8822b_check_rf_path(antenna_tx)) {
rtw_info(rtwdev, "unsupported tx path 0x%x\n", antenna_tx); rtw_warn(rtwdev, "unsupported tx path 0x%x\n", antenna_tx);
return -EINVAL; return -EINVAL;
} }
if (!rtw8822b_check_rf_path(antenna_rx)) { if (!rtw8822b_check_rf_path(antenna_rx)) {
rtw_info(rtwdev, "unsupported rx path 0x%x\n", antenna_rx); rtw_warn(rtwdev, "unsupported rx path 0x%x\n", antenna_rx);
return -EINVAL; return -EINVAL;
} }
@ -1588,6 +1606,15 @@ static void rtw8822b_adaptivity(struct rtw_dev *rtwdev)
rtw_phy_set_edcca_th(rtwdev, l2h, h2l); rtw_phy_set_edcca_th(rtwdev, l2h, h2l);
} }
static void rtw8822b_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
{
size_t words = 32 / 2; /* calculate the first 32 bytes (16 words) */
fill_txdesc_checksum_common(txdesc, words);
}
static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = { static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = {
{0x0086, {0x0086,
RTW_PWR_CUT_ALL_MSK, RTW_PWR_CUT_ALL_MSK,
@ -2163,6 +2190,7 @@ static struct rtw_chip_ops rtw8822b_ops = {
.cfg_csi_rate = rtw_bf_cfg_csi_rate, .cfg_csi_rate = rtw_bf_cfg_csi_rate,
.adaptivity_init = rtw8822b_adaptivity_init, .adaptivity_init = rtw8822b_adaptivity_init,
.adaptivity = rtw8822b_adaptivity, .adaptivity = rtw8822b_adaptivity,
.fill_txdesc_checksum = rtw8822b_fill_txdesc_checksum,
.coex_set_init = rtw8822b_coex_cfg_init, .coex_set_init = rtw8822b_coex_cfg_init,
.coex_set_ant_switch = rtw8822b_coex_cfg_ant_switch, .coex_set_ant_switch = rtw8822b_coex_cfg_ant_switch,
@ -2497,7 +2525,7 @@ static struct rtw_hw_reg_offset rtw8822b_edcca_th[] = {
[EDCCA_TH_H2L_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE1}, .offset = 0}, [EDCCA_TH_H2L_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE1}, .offset = 0},
}; };
struct rtw_chip_info rtw8822b_hw_spec = { const struct rtw_chip_info rtw8822b_hw_spec = {
.ops = &rtw8822b_ops, .ops = &rtw8822b_ops,
.id = RTW_CHIP_TYPE_8822B, .id = RTW_CHIP_TYPE_8822B,
.fw_name = "rtw88/rtw8822b_fw.bin", .fw_name = "rtw88/rtw8822b_fw.bin",
@ -2512,12 +2540,13 @@ struct rtw_chip_info rtw8822b_hw_spec = {
.txff_size = 262144, .txff_size = 262144,
.rxff_size = 24576, .rxff_size = 24576,
.fw_rxff_size = 12288, .fw_rxff_size = 12288,
.rsvd_drv_pg_num = 8,
.txgi_factor = 1, .txgi_factor = 1,
.is_pwr_by_rate_dec = true, .is_pwr_by_rate_dec = true,
.max_power_index = 0x3f, .max_power_index = 0x3f,
.csi_buf_pg_num = 0, .csi_buf_pg_num = 0,
.band = RTW_BAND_2G | RTW_BAND_5G, .band = RTW_BAND_2G | RTW_BAND_5G,
.page_size = 128, .page_size = TX_PAGE_SIZE,
.dig_min = 0x1c, .dig_min = 0x1c,
.ht_supported = true, .ht_supported = true,
.vht_supported = true, .vht_supported = true,
@ -2548,12 +2577,15 @@ struct rtw_chip_info rtw8822b_hw_spec = {
.edcca_th = rtw8822b_edcca_th, .edcca_th = rtw8822b_edcca_th,
.l2h_th_ini_cs = 10 + EDCCA_IGI_BASE, .l2h_th_ini_cs = 10 + EDCCA_IGI_BASE,
.l2h_th_ini_ad = -14 + EDCCA_IGI_BASE, .l2h_th_ini_ad = -14 + EDCCA_IGI_BASE,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_2,
.max_scan_ie_len = IEEE80211_MAX_DATA_LEN,
.coex_para_ver = 0x20070206, .coex_para_ver = 0x20070206,
.bt_desired_ver = 0x6, .bt_desired_ver = 0x6,
.scbd_support = true, .scbd_support = true,
.new_scbd10_def = false, .new_scbd10_def = false,
.ble_hid_profile_support = false, .ble_hid_profile_support = false,
.wl_mimo_ps_support = false,
.pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
.bt_rssi_type = COEX_BTRSSI_RATIO, .bt_rssi_type = COEX_BTRSSI_RATIO,
.ant_isolation = 15, .ant_isolation = 15,

View file

@ -65,6 +65,11 @@ struct rtw8822be_efuse {
u8 res7; u8 res7;
}; };
struct rtw8822bs_efuse {
u8 res4[0x4a]; /* 0xd0 */
u8 mac_addr[ETH_ALEN]; /* 0x11a */
} __packed;
struct rtw8822b_efuse { struct rtw8822b_efuse {
__le16 rtl_id; __le16 rtl_id;
u8 res0[0x0e]; u8 res0[0x0e];
@ -92,8 +97,9 @@ struct rtw8822b_efuse {
u8 country_code[2]; u8 country_code[2];
u8 res[3]; u8 res[3];
union { union {
struct rtw8822bu_efuse u;
struct rtw8822be_efuse e; struct rtw8822be_efuse e;
struct rtw8822bu_efuse u;
struct rtw8822bs_efuse s;
}; };
}; };
@ -187,4 +193,6 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
#define REG_ANTWT 0x1904 #define REG_ANTWT 0x1904
#define REG_IQKFAILMSK 0x1bf0 #define REG_IQKFAILMSK 0x1bf0
extern const struct rtw_chip_info rtw8822b_hw_spec;
#endif #endif

View file

@ -5,7 +5,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include "pci.h" #include "pci.h"
#include "rtw8822be.h" #include "rtw8822b.h"
static const struct pci_device_id rtw_8822be_id_table[] = { static const struct pci_device_id rtw_8822be_id_table[] = {
{ {

View file

@ -1,10 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_8822BE_H_
#define __RTW_8822BE_H_
extern struct rtw_chip_info rtw8822b_hw_spec;
#endif

36
rtw8822bs.c Normal file
View file

@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) Jernej Skrabec <jernej.skrabec@gmail.com>
*/
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/module.h>
#include "main.h"
#include "rtw8822b.h"
#include "sdio.h"
static const struct sdio_device_id rtw_8822bs_id_table[] = {
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8822BS),
.driver_data = (kernel_ulong_t)&rtw8822b_hw_spec,
},
{}
};
MODULE_DEVICE_TABLE(sdio, rtw_8822bs_id_table);
static struct sdio_driver rtw_8822bs_driver = {
.name = "rtw_8822bs",
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.id_table = rtw_8822bs_id_table,
.drv = {
.pm = &rtw_sdio_pm_ops,
.shutdown = rtw_sdio_shutdown,
}
};
module_sdio_driver(rtw_8822bs_driver);
MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@gmail.com>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822bs driver");
MODULE_LICENSE("Dual BSD/GPL");

90
rtw8822bu.c Normal file
View file

@ -0,0 +1,90 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8822b.h"
#include "usb.h"
static const struct usb_device_id rtw_8822bu_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb812, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb82c, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x2102, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* CCNC */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xb822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822ULC */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xc822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822UTC */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xe822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax */
{ USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xf822, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822UAD */
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb81a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Default ID */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x1841, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS AC1300 USB-AC55 B1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x184c, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS U2 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x19aa, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS - USB-AC58 rev A1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x1870, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x1874, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Dlink - DWA-181 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331c, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Dlink - DWA-182 - D1 */
{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331f, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec)}, /* Dlink - DWA-183 D Ver */
{ USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0043, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Linksys WUSB6400M */
{ USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0045, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Linksys WUSB3600 v2 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x012d, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T3U v1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0138, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T3U Plus v1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0115, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T4U V3 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x012e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0116, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0117, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9055, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Netgear A6150 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0025, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Hawking HW12ACU */
{ USB_DEVICE_AND_INTERFACE_INFO(0x04ca, 0x8602, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* LiteOn */
{ USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x808a, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TRENDnet TEW-808UBM */
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8822bu_id_table);
static int rtw8822bu_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return rtw_usb_probe(intf, id);
}
static struct usb_driver rtw_8822bu_driver = {
.name = "rtw_8822bu",
.id_table = rtw_8822bu_id_table,
.probe = rtw8822bu_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8822bu_driver);
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822bu driver");
MODULE_LICENSE("Dual BSD/GPL");

View file

@ -29,6 +29,18 @@ static void rtw8822ce_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->e.mac_addr); ether_addr_copy(efuse->addr, map->e.mac_addr);
} }
static void rtw8822cu_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8822c_efuse *map)
{
ether_addr_copy(efuse->addr, map->u.mac_addr);
}
static void rtw8822cs_efuse_parsing(struct rtw_efuse *efuse,
struct rtw8822c_efuse *map)
{
ether_addr_copy(efuse->addr, map->s.mac_addr);
}
static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{ {
struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_efuse *efuse = &rtwdev->efuse;
@ -58,6 +70,12 @@ static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
case RTW_HCI_TYPE_PCIE: case RTW_HCI_TYPE_PCIE:
rtw8822ce_efuse_parsing(efuse, map); rtw8822ce_efuse_parsing(efuse, map);
break; break;
case RTW_HCI_TYPE_USB:
rtw8822cu_efuse_parsing(efuse, map);
break;
case RTW_HCI_TYPE_SDIO:
rtw8822cs_efuse_parsing(efuse, map);
break;
default: default:
/* unsupported now */ /* unsupported now */
return -ENOTSUPP; return -ENOTSUPP;
@ -2798,7 +2816,7 @@ static int rtw8822c_set_antenna(struct rtw_dev *rtwdev,
case BB_PATH_AB: case BB_PATH_AB:
break; break;
default: default:
rtw_info(rtwdev, "unsupported tx path 0x%x\n", antenna_tx); rtw_warn(rtwdev, "unsupported tx path 0x%x\n", antenna_tx);
return -EINVAL; return -EINVAL;
} }
@ -2808,7 +2826,7 @@ static int rtw8822c_set_antenna(struct rtw_dev *rtwdev,
case BB_PATH_AB: case BB_PATH_AB:
break; break;
default: default:
rtw_info(rtwdev, "unsupported rx path 0x%x\n", antenna_rx); rtw_warn(rtwdev, "unsupported rx path 0x%x\n", antenna_rx);
return -EINVAL; return -EINVAL;
} }
@ -2996,19 +3014,34 @@ static void rtw8822c_coex_cfg_gnt_fix(struct rtw_dev *rtwdev)
* enable "DAC off if GNT_WL = 0" for non-shared-antenna * enable "DAC off if GNT_WL = 0" for non-shared-antenna
* disable 0x1c30[22] = 0, * disable 0x1c30[22] = 0,
* enable: 0x1c30[22] = 1, 0x1c38[12] = 0, 0x1c38[28] = 1 * enable: 0x1c30[22] = 1, 0x1c38[12] = 0, 0x1c38[28] = 1
* */
* disable WL-S1 BB chage RF mode if GNT_BT if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
rtw_write8_mask(rtwdev, REG_ANAPAR + 2,
BIT_ANAPAR_BTPS >> 16, 0);
} else {
rtw_write8_mask(rtwdev, REG_ANAPAR + 2,
BIT_ANAPAR_BTPS >> 16, 1);
rtw_write8_mask(rtwdev, REG_RSTB_SEL + 1,
BIT_DAC_OFF_ENABLE, 0);
rtw_write8_mask(rtwdev, REG_RSTB_SEL + 3,
BIT_DAC_OFF_ENABLE, 1);
}
/* disable WL-S1 BB chage RF mode if GNT_BT
* since RF TRx mask can do it * since RF TRx mask can do it
*/ */
rtw_write8_mask(rtwdev, REG_ANAPAR + 2, BIT_ANAPAR_BTPS >> 16, 1); rtw_write8_mask(rtwdev, REG_IGN_GNTBT4,
rtw_write8_mask(rtwdev, REG_RSTB_SEL + 1, BIT_DAC_OFF_ENABLE, 0); BIT_PI_IGNORE_GNT_BT, 1);
rtw_write8_mask(rtwdev, REG_RSTB_SEL + 3, BIT_DAC_OFF_ENABLE, 1);
rtw_write8_mask(rtwdev, REG_IGN_GNTBT4, BIT_PI_IGNORE_GNT_BT, 1);
/* disable WL-S0 BB chage RF mode if wifi is at 5G, /* disable WL-S0 BB chage RF mode if wifi is at 5G,
* or antenna path is separated * or antenna path is separated
*/ */
if (coex_stat->wl_coex_mode == COEX_WLINK_5G || if (coex_stat->wl_coex_mode == COEX_WLINK_2GFREE) {
rtw_write8_mask(rtwdev, REG_IGN_GNT_BT1,
BIT_PI_IGNORE_GNT_BT, 1);
rtw_write8_mask(rtwdev, REG_NOMASK_TXBT,
BIT_NOMASK_TXBT_ENABLE, 1);
} else if (coex_stat->wl_coex_mode == COEX_WLINK_5G ||
coex->under_5g || !efuse->share_ant) { coex->under_5g || !efuse->share_ant) {
if (coex_stat->kt_ver >= 3) { if (coex_stat->kt_ver >= 3) {
rtw_write8_mask(rtwdev, REG_IGN_GNT_BT1, rtw_write8_mask(rtwdev, REG_IGN_GNT_BT1,
@ -4542,6 +4575,18 @@ static void rtw8822c_adaptivity(struct rtw_dev *rtwdev)
rtw_phy_set_edcca_th(rtwdev, l2h, h2l); rtw_phy_set_edcca_th(rtwdev, l2h, h2l);
} }
static void rtw8822c_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
{
const struct rtw_chip_info *chip = rtwdev->chip;
size_t words;
words = (pkt_info->pkt_offset * 8 + chip->tx_pkt_desc_sz) / 2;
fill_txdesc_checksum_common(txdesc, words);
}
static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822c[] = { static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822c[] = {
{0x0086, {0x0086,
RTW_PWR_CUT_ALL_MSK, RTW_PWR_CUT_ALL_MSK,
@ -4880,6 +4925,8 @@ static const struct rtw_rfe_def rtw8822c_rfe_defs[] = {
[0] = RTW_DEF_RFE(8822c, 0, 0), [0] = RTW_DEF_RFE(8822c, 0, 0),
[1] = RTW_DEF_RFE(8822c, 0, 0), [1] = RTW_DEF_RFE(8822c, 0, 0),
[2] = RTW_DEF_RFE(8822c, 0, 0), [2] = RTW_DEF_RFE(8822c, 0, 0),
[3] = RTW_DEF_RFE(8822c, 0, 0),
[4] = RTW_DEF_RFE(8822c, 0, 0),
[5] = RTW_DEF_RFE(8822c, 0, 5), [5] = RTW_DEF_RFE(8822c, 0, 5),
[6] = RTW_DEF_RFE(8822c, 0, 0), [6] = RTW_DEF_RFE(8822c, 0, 0),
}; };
@ -4962,6 +5009,8 @@ static struct rtw_chip_ops rtw8822c_ops = {
.cfo_init = rtw8822c_cfo_init, .cfo_init = rtw8822c_cfo_init,
.cfo_track = rtw8822c_cfo_track, .cfo_track = rtw8822c_cfo_track,
.config_tx_path = rtw8822c_config_tx_path, .config_tx_path = rtw8822c_config_tx_path,
.config_txrx_mode = rtw8822c_config_trx_mode,
.fill_txdesc_checksum = rtw8822c_fill_txdesc_checksum,
.coex_set_init = rtw8822c_coex_cfg_init, .coex_set_init = rtw8822c_coex_cfg_init,
.coex_set_ant_switch = NULL, .coex_set_ant_switch = NULL,
@ -5007,6 +5056,8 @@ static const struct coex_table_para table_sant_8822c[] = {
{0x66556aaa, 0x6a5a6aaa}, /*case-30*/ {0x66556aaa, 0x6a5a6aaa}, /*case-30*/
{0xffffffff, 0x5aaa5aaa}, {0xffffffff, 0x5aaa5aaa},
{0x56555555, 0x5a5a5aaa}, {0x56555555, 0x5a5a5aaa},
{0xdaffdaff, 0xdaffdaff},
{0xddffddff, 0xddffddff},
}; };
/* Non-Shared-Antenna Coex Table */ /* Non-Shared-Antenna Coex Table */
@ -5107,7 +5158,8 @@ static const struct coex_rf_para rf_para_tx_8822c[] = {
{8, 17, true, 4}, {8, 17, true, 4},
{7, 18, true, 4}, {7, 18, true, 4},
{6, 19, true, 4}, {6, 19, true, 4},
{5, 20, true, 4} {5, 20, true, 4},
{0, 21, true, 4} /* for gamg hid */
}; };
static const struct coex_rf_para rf_para_rx_8822c[] = { static const struct coex_rf_para rf_para_rx_8822c[] = {
@ -5116,7 +5168,8 @@ static const struct coex_rf_para rf_para_rx_8822c[] = {
{3, 24, true, 5}, {3, 24, true, 5},
{2, 26, true, 5}, {2, 26, true, 5},
{1, 27, true, 5}, {1, 27, true, 5},
{0, 28, true, 5} {0, 28, true, 5},
{0, 28, true, 5} /* for gamg hid */
}; };
static_assert(ARRAY_SIZE(rf_para_tx_8822c) == ARRAY_SIZE(rf_para_rx_8822c)); static_assert(ARRAY_SIZE(rf_para_tx_8822c) == ARRAY_SIZE(rf_para_rx_8822c));
@ -5290,7 +5343,7 @@ static const struct rtw_reg_domain coex_info_hw_regs_8822c[] = {
{0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, {0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
}; };
struct rtw_chip_info rtw8822c_hw_spec = { const struct rtw_chip_info rtw8822c_hw_spec = {
.ops = &rtw8822c_ops, .ops = &rtw8822c_ops,
.id = RTW_CHIP_TYPE_8822C, .id = RTW_CHIP_TYPE_8822C,
.fw_name = "rtw88/rtw8822c_fw.bin", .fw_name = "rtw88/rtw8822c_fw.bin",
@ -5305,12 +5358,13 @@ struct rtw_chip_info rtw8822c_hw_spec = {
.txff_size = 262144, .txff_size = 262144,
.rxff_size = 24576, .rxff_size = 24576,
.fw_rxff_size = 12288, .fw_rxff_size = 12288,
.rsvd_drv_pg_num = 16,
.txgi_factor = 2, .txgi_factor = 2,
.is_pwr_by_rate_dec = false, .is_pwr_by_rate_dec = false,
.max_power_index = 0x7f, .max_power_index = 0x7f,
.csi_buf_pg_num = 50, .csi_buf_pg_num = 50,
.band = RTW_BAND_2G | RTW_BAND_5G, .band = RTW_BAND_2G | RTW_BAND_5G,
.page_size = 128, .page_size = TX_PAGE_SIZE,
.dig_min = 0x20, .dig_min = 0x20,
.default_1ss_tx_path = BB_PATH_A, .default_1ss_tx_path = BB_PATH_A,
.path_div_supported = true, .path_div_supported = true,
@ -5348,17 +5402,20 @@ struct rtw_chip_info rtw8822c_hw_spec = {
.edcca_th = rtw8822c_edcca_th, .edcca_th = rtw8822c_edcca_th,
.l2h_th_ini_cs = 60, .l2h_th_ini_cs = 60,
.l2h_th_ini_ad = 45, .l2h_th_ini_ad = 45,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_2,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.wow_fw_name = "rtw88/rtw8822c_wow_fw.bin", .wow_fw_name = "rtw88/rtw8822c_wow_fw.bin",
.wowlan_stub = &rtw_wowlan_stub_8822c, .wowlan_stub = &rtw_wowlan_stub_8822c,
.max_sched_scan_ssids = 4, .max_sched_scan_ssids = 4,
#endif #endif
.coex_para_ver = 0x2103181c, .max_scan_ie_len = (RTW_PROBE_PG_CNT - 1) * TX_PAGE_SIZE,
.bt_desired_ver = 0x1c, .coex_para_ver = 0x22020720,
.bt_desired_ver = 0x20,
.scbd_support = true, .scbd_support = true,
.new_scbd10_def = true, .new_scbd10_def = true,
.ble_hid_profile_support = true, .ble_hid_profile_support = true,
.wl_mimo_ps_support = true,
.pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF,
.bt_rssi_type = COEX_BTRSSI_DBM, .bt_rssi_type = COEX_BTRSSI_DBM,
.ant_isolation = 15, .ant_isolation = 15,

View file

@ -16,6 +16,11 @@ struct rtw8822cu_efuse {
u8 res2[0x3d]; u8 res2[0x3d];
}; };
struct rtw8822cs_efuse {
u8 res0[0x4a]; /* 0x120 */
u8 mac_addr[ETH_ALEN]; /* 0x16a */
} __packed;
struct rtw8822ce_efuse { struct rtw8822ce_efuse {
u8 mac_addr[ETH_ALEN]; /* 0x120 */ u8 mac_addr[ETH_ALEN]; /* 0x120 */
u8 vender_id[2]; u8 vender_id[2];
@ -91,8 +96,9 @@ struct rtw8822c_efuse {
u8 res9; u8 res9;
u8 res10[0x42]; u8 res10[0x42];
union { union {
struct rtw8822cu_efuse u;
struct rtw8822ce_efuse e; struct rtw8822ce_efuse e;
struct rtw8822cu_efuse u;
struct rtw8822cs_efuse s;
}; };
}; };
@ -118,6 +124,8 @@ enum rtw8822c_dpk_one_shot_action {
void rtw8822c_parse_tbl_dpk(struct rtw_dev *rtwdev, void rtw8822c_parse_tbl_dpk(struct rtw_dev *rtwdev,
const struct rtw_table *tbl); const struct rtw_table *tbl);
extern const struct rtw_chip_info rtw8822c_hw_spec;
#define RTW_DECL_TABLE_DPK(name) \ #define RTW_DECL_TABLE_DPK(name) \
const struct rtw_table name ## _tbl = { \ const struct rtw_table name ## _tbl = { \
.data = name, \ .data = name, \

View file

@ -5,7 +5,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include "pci.h" #include "pci.h"
#include "rtw8822ce.h" #include "rtw8822c.h"
static const struct pci_device_id rtw_8822ce_id_table[] = { static const struct pci_device_id rtw_8822ce_id_table[] = {
{ {

View file

@ -1,10 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_8822CE_H_
#define __RTW_8822CE_H_
extern struct rtw_chip_info rtw8822c_hw_spec;
#endif

36
rtw8822cs.c Normal file
View file

@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*/
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/module.h>
#include "main.h"
#include "rtw8822c.h"
#include "sdio.h"
static const struct sdio_device_id rtw_8822cs_id_table[] = {
{
SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK,
SDIO_DEVICE_ID_REALTEK_RTW8822CS),
.driver_data = (kernel_ulong_t)&rtw8822c_hw_spec,
},
{}
};
MODULE_DEVICE_TABLE(sdio, rtw_8822cs_id_table);
static struct sdio_driver rtw_8822cs_driver = {
.name = "rtw_8822cs",
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.id_table = rtw_8822cs_id_table,
.drv = {
.pm = &rtw_sdio_pm_ops,
.shutdown = rtw_sdio_shutdown,
}
};
module_sdio_driver(rtw_8822cs_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822cs driver");
MODULE_LICENSE("Dual BSD/GPL");

44
rtw8822cu.c Normal file
View file

@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include "main.h"
#include "rtw8822c.h"
#include "usb.h"
static const struct usb_device_id rtw_8822cu_id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82c, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc812, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82e, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd820, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd82b, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0043, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, /* Alpha - Alpha */
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8822cu_id_table);
static int rtw8822bu_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return rtw_usb_probe(intf, id);
}
static struct usb_driver rtw_8822cu_driver = {
.name = "rtw_8822cu",
.id_table = rtw_8822cu_id_table,
.probe = rtw8822bu_probe,
.disconnect = rtw_usb_disconnect,
};
module_usb_driver(rtw_8822cu_driver);
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822cu driver");
MODULE_LICENSE("Dual BSD/GPL");

3
rx.c
View file

@ -158,7 +158,8 @@ void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev,
memset(rx_status, 0, sizeof(*rx_status)); memset(rx_status, 0, sizeof(*rx_status));
rx_status->freq = hw->conf.chandef.chan->center_freq; rx_status->freq = hw->conf.chandef.chan->center_freq;
rx_status->band = hw->conf.chandef.chan->band; rx_status->band = hw->conf.chandef.chan->band;
if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD)) if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD) &&
test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
rtw_set_rx_freq_by_pktstat(pkt_stat, rx_status); rtw_set_rx_freq_by_pktstat(pkt_stat, rx_status);
if (pkt_stat->crc_err) if (pkt_stat->crc_err)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;

2
sar.c
View file

@ -91,7 +91,7 @@ int rtw_set_sar_specs(struct rtw_dev *rtwdev,
return -EINVAL; return -EINVAL;
power = sar->sub_specs[i].power; power = sar->sub_specs[i].power;
rtw_info(rtwdev, "On freq %u to %u, set SAR %d in 1/%lu dBm\n", rtw_dbg(rtwdev, RTW_DBG_REGD, "On freq %u to %u, set SAR %d in 1/%lu dBm\n",
rtw_common_sar_freq_ranges[idx].start_freq, rtw_common_sar_freq_ranges[idx].start_freq,
rtw_common_sar_freq_ranges[idx].end_freq, rtw_common_sar_freq_ranges[idx].end_freq,
power, BIT(RTW_COMMON_SAR_FCT)); power, BIT(RTW_COMMON_SAR_FCT));

1404
sdio.c Normal file

File diff suppressed because it is too large Load diff

178
sdio.h Normal file
View file

@ -0,0 +1,178 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright (C) 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
* Copyright (C) 2021 Jernej Skrabec <jernej.skrabec@gmail.com>
*/
#ifndef __REG_SDIO_H_
#define __REG_SDIO_H_
/* I/O bus domain address mapping */
#define SDIO_LOCAL_OFFSET 0x10250000
#define WLAN_IOREG_OFFSET 0x10260000
#define FIRMWARE_FIFO_OFFSET 0x10270000
#define TX_HIQ_OFFSET 0x10310000
#define TX_MIQ_OFFSET 0x10320000
#define TX_LOQ_OFFSET 0x10330000
#define TX_EPQ_OFFSET 0x10350000
#define RX_RX0FF_OFFSET 0x10340000
#define RTW_SDIO_BUS_MSK 0xffff0000
#define SDIO_LOCAL_REG_MSK 0x00000fff
#define WLAN_IOREG_REG_MSK 0x0000ffff
/* SDIO Tx Control */
#define REG_SDIO_TX_CTRL (SDIO_LOCAL_OFFSET + 0x0000)
/*SDIO status timeout*/
#define REG_SDIO_TIMEOUT (SDIO_LOCAL_OFFSET + 0x0002)
/* SDIO Host Interrupt Mask */
#define REG_SDIO_HIMR (SDIO_LOCAL_OFFSET + 0x0014)
#define REG_SDIO_HIMR_RX_REQUEST BIT(0)
#define REG_SDIO_HIMR_AVAL BIT(1)
#define REG_SDIO_HIMR_TXERR BIT(2)
#define REG_SDIO_HIMR_RXERR BIT(3)
#define REG_SDIO_HIMR_TXFOVW BIT(4)
#define REG_SDIO_HIMR_RXFOVW BIT(5)
#define REG_SDIO_HIMR_TXBCNOK BIT(6)
#define REG_SDIO_HIMR_TXBCNERR BIT(7)
#define REG_SDIO_HIMR_BCNERLY_INT BIT(16)
#define REG_SDIO_HIMR_C2HCMD BIT(17)
#define REG_SDIO_HIMR_CPWM1 BIT(18)
#define REG_SDIO_HIMR_CPWM2 BIT(19)
#define REG_SDIO_HIMR_HSISR_IND BIT(20)
#define REG_SDIO_HIMR_GTINT3_IND BIT(21)
#define REG_SDIO_HIMR_GTINT4_IND BIT(22)
#define REG_SDIO_HIMR_PSTIMEOUT BIT(23)
#define REG_SDIO_HIMR_OCPINT BIT(24)
#define REG_SDIO_HIMR_ATIMEND BIT(25)
#define REG_SDIO_HIMR_ATIMEND_E BIT(26)
#define REG_SDIO_HIMR_CTWEND BIT(27)
/* the following two are RTL8188 SDIO Specific */
#define REG_SDIO_HIMR_MCU_ERR BIT(28)
#define REG_SDIO_HIMR_TSF_BIT32_TOGGLE BIT(29)
/* SDIO Host Interrupt Service Routine */
#define REG_SDIO_HISR (SDIO_LOCAL_OFFSET + 0x0018)
#define REG_SDIO_HISR_RX_REQUEST BIT(0)
#define REG_SDIO_HISR_AVAL BIT(1)
#define REG_SDIO_HISR_TXERR BIT(2)
#define REG_SDIO_HISR_RXERR BIT(3)
#define REG_SDIO_HISR_TXFOVW BIT(4)
#define REG_SDIO_HISR_RXFOVW BIT(5)
#define REG_SDIO_HISR_TXBCNOK BIT(6)
#define REG_SDIO_HISR_TXBCNERR BIT(7)
#define REG_SDIO_HISR_BCNERLY_INT BIT(16)
#define REG_SDIO_HISR_C2HCMD BIT(17)
#define REG_SDIO_HISR_CPWM1 BIT(18)
#define REG_SDIO_HISR_CPWM2 BIT(19)
#define REG_SDIO_HISR_HSISR_IND BIT(20)
#define REG_SDIO_HISR_GTINT3_IND BIT(21)
#define REG_SDIO_HISR_GTINT4_IND BIT(22)
#define REG_SDIO_HISR_PSTIMEOUT BIT(23)
#define REG_SDIO_HISR_OCPINT BIT(24)
#define REG_SDIO_HISR_ATIMEND BIT(25)
#define REG_SDIO_HISR_ATIMEND_E BIT(26)
#define REG_SDIO_HISR_CTWEND BIT(27)
/* the following two are RTL8188 SDIO Specific */
#define REG_SDIO_HISR_MCU_ERR BIT(28)
#define REG_SDIO_HISR_TSF_BIT32_TOGGLE BIT(29)
/* HCI Current Power Mode */
#define REG_SDIO_HCPWM (SDIO_LOCAL_OFFSET + 0x0019)
/* RXDMA Request Length */
#define REG_SDIO_RX0_REQ_LEN (SDIO_LOCAL_OFFSET + 0x001C)
/* OQT Free Page */
#define REG_SDIO_OQT_FREE_PG (SDIO_LOCAL_OFFSET + 0x001E)
/* Free Tx Buffer Page */
#define REG_SDIO_FREE_TXPG (SDIO_LOCAL_OFFSET + 0x0020)
/* HCI Current Power Mode 1 */
#define REG_SDIO_HCPWM1 (SDIO_LOCAL_OFFSET + 0x0024)
/* HCI Current Power Mode 2 */
#define REG_SDIO_HCPWM2 (SDIO_LOCAL_OFFSET + 0x0026)
/* Free Tx Page Sequence */
#define REG_SDIO_FREE_TXPG_SEQ (SDIO_LOCAL_OFFSET + 0x0028)
/* HTSF Information */
#define REG_SDIO_HTSFR_INFO (SDIO_LOCAL_OFFSET + 0x0030)
#define REG_SDIO_HCPWM1_V2 (SDIO_LOCAL_OFFSET + 0x0038)
/* H2C */
#define REG_SDIO_H2C (SDIO_LOCAL_OFFSET + 0x0060)
/* HCI Request Power Mode 1 */
#define REG_SDIO_HRPWM1 (SDIO_LOCAL_OFFSET + 0x0080)
/* HCI Request Power Mode 2 */
#define REG_SDIO_HRPWM2 (SDIO_LOCAL_OFFSET + 0x0082)
/* HCI Power Save Clock */
#define REG_SDIO_HPS_CLKR (SDIO_LOCAL_OFFSET + 0x0084)
/* SDIO HCI Suspend Control */
#define REG_SDIO_HSUS_CTRL (SDIO_LOCAL_OFFSET + 0x0086)
#define BIT_HCI_SUS_REQ BIT(0)
#define BIT_HCI_RESUME_RDY BIT(1)
/* SDIO Host Extension Interrupt Mask Always */
#define REG_SDIO_HIMR_ON (SDIO_LOCAL_OFFSET + 0x0090)
/* SDIO Host Extension Interrupt Status Always */
#define REG_SDIO_HISR_ON (SDIO_LOCAL_OFFSET + 0x0091)
#define REG_SDIO_INDIRECT_REG_CFG (SDIO_LOCAL_OFFSET + 0x0040)
#define BIT_SDIO_INDIRECT_REG_CFG_WORD BIT(16)
#define BIT_SDIO_INDIRECT_REG_CFG_DWORD BIT(17)
#define BIT_SDIO_INDIRECT_REG_CFG_WRITE BIT(18)
#define BIT_SDIO_INDIRECT_REG_CFG_READ BIT(19)
#define BIT_SDIO_INDIRECT_REG_CFG_UNK20 BIT(20)
#define REG_SDIO_INDIRECT_REG_DATA (SDIO_LOCAL_OFFSET + 0x0044)
/* Sdio Address for SDIO Local Reg, TRX FIFO, MAC Reg */
#define REG_SDIO_CMD_ADDR_MSK GENMASK(16, 13)
#define REG_SDIO_CMD_ADDR_SDIO_REG 0
#define REG_SDIO_CMD_ADDR_MAC_REG 8
#define REG_SDIO_CMD_ADDR_TXFF_HIGH 4
#define REG_SDIO_CMD_ADDR_TXFF_LOW 6
#define REG_SDIO_CMD_ADDR_TXFF_NORMAL 5
#define REG_SDIO_CMD_ADDR_TXFF_EXTRA 7
#define REG_SDIO_CMD_ADDR_RXFF 7
#define RTW_SDIO_BLOCK_SIZE 512
#define RTW_SDIO_ADDR_RX_RX0FF_GEN(_id) (0x0e000 | ((_id) & 0x3))
#define RTW_SDIO_DATA_PTR_ALIGN 8
struct sdio_func;
struct sdio_device_id;
struct rtw_sdio_tx_data {
u8 sn;
};
struct rtw_sdio_work_data {
struct work_struct work;
struct rtw_dev *rtwdev;
};
struct rtw_sdio {
struct sdio_func *sdio_func;
u32 irq_mask;
u8 rx_addr;
bool sdio3_bus_mode;
void *irq_thread;
struct workqueue_struct *txwq;
struct rtw_sdio_work_data *tx_handler_data;
struct sk_buff_head tx_queue[RTK_MAX_TX_QUEUE_NUM];
};
extern const struct dev_pm_ops rtw_sdio_pm_ops;
int rtw_sdio_probe(struct sdio_func *sdio_func,
const struct sdio_device_id *id);
void rtw_sdio_remove(struct sdio_func *sdio_func);
void rtw_sdio_shutdown(struct device *dev);
static inline bool rtw_sdio_is_sdio30_supported(struct rtw_dev *rtwdev)
{
struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv;
return rtwsdio->sdio3_bus_mode;
}
#endif

168
tx.c
View file

@ -34,45 +34,63 @@ void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb)
{ {
__le32 *txdesc = (__le32 *)skb->data; struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data;
bool more_data = false;
if (pkt_info->qsel == TX_DESC_QSEL_HIGH)
more_data = true;
tx_desc->w0 = le32_encode_bits(pkt_info->tx_pkt_size, RTW_TX_DESC_W0_TXPKTSIZE) |
le32_encode_bits(pkt_info->offset, RTW_TX_DESC_W0_OFFSET) |
le32_encode_bits(pkt_info->bmc, RTW_TX_DESC_W0_BMC) |
le32_encode_bits(pkt_info->ls, RTW_TX_DESC_W0_LS) |
le32_encode_bits(pkt_info->dis_qselseq, RTW_TX_DESC_W0_DISQSELSEQ);
tx_desc->w1 = le32_encode_bits(pkt_info->qsel, RTW_TX_DESC_W1_QSEL) |
le32_encode_bits(pkt_info->rate_id, RTW_TX_DESC_W1_RATE_ID) |
le32_encode_bits(pkt_info->sec_type, RTW_TX_DESC_W1_SEC_TYPE) |
le32_encode_bits(pkt_info->pkt_offset, RTW_TX_DESC_W1_PKT_OFFSET) |
le32_encode_bits(more_data, RTW_TX_DESC_W1_MORE_DATA);
tx_desc->w2 = le32_encode_bits(pkt_info->ampdu_en, RTW_TX_DESC_W2_AGG_EN) |
le32_encode_bits(pkt_info->report, RTW_TX_DESC_W2_SPE_RPT) |
le32_encode_bits(pkt_info->ampdu_density, RTW_TX_DESC_W2_AMPDU_DEN) |
le32_encode_bits(pkt_info->bt_null, RTW_TX_DESC_W2_BT_NULL);
tx_desc->w3 = le32_encode_bits(pkt_info->hw_ssn_sel, RTW_TX_DESC_W3_HW_SSN_SEL) |
le32_encode_bits(pkt_info->use_rate, RTW_TX_DESC_W3_USE_RATE) |
le32_encode_bits(pkt_info->dis_rate_fallback, RTW_TX_DESC_W3_DISDATAFB) |
le32_encode_bits(pkt_info->rts, RTW_TX_DESC_W3_USE_RTS) |
le32_encode_bits(pkt_info->nav_use_hdr, RTW_TX_DESC_W3_NAVUSEHDR) |
le32_encode_bits(pkt_info->ampdu_factor, RTW_TX_DESC_W3_MAX_AGG_NUM);
tx_desc->w4 = le32_encode_bits(pkt_info->rate, RTW_TX_DESC_W4_DATARATE);
tx_desc->w5 = le32_encode_bits(pkt_info->short_gi, RTW_TX_DESC_W5_DATA_SHORT) |
le32_encode_bits(pkt_info->bw, RTW_TX_DESC_W5_DATA_BW) |
le32_encode_bits(pkt_info->ldpc, RTW_TX_DESC_W5_DATA_LDPC) |
le32_encode_bits(pkt_info->stbc, RTW_TX_DESC_W5_DATA_STBC);
tx_desc->w6 = le32_encode_bits(pkt_info->sn, RTW_TX_DESC_W6_SW_DEFINE);
tx_desc->w8 = le32_encode_bits(pkt_info->en_hwseq, RTW_TX_DESC_W8_EN_HWSEQ);
tx_desc->w9 = le32_encode_bits(pkt_info->seq, RTW_TX_DESC_W9_SW_SEQ);
SET_TX_DESC_TXPKTSIZE(txdesc, pkt_info->tx_pkt_size);
SET_TX_DESC_OFFSET(txdesc, pkt_info->offset);
SET_TX_DESC_PKT_OFFSET(txdesc, pkt_info->pkt_offset);
SET_TX_DESC_QSEL(txdesc, pkt_info->qsel);
SET_TX_DESC_BMC(txdesc, pkt_info->bmc);
SET_TX_DESC_RATE_ID(txdesc, pkt_info->rate_id);
SET_TX_DESC_DATARATE(txdesc, pkt_info->rate);
SET_TX_DESC_DISDATAFB(txdesc, pkt_info->dis_rate_fallback);
SET_TX_DESC_USE_RATE(txdesc, pkt_info->use_rate);
SET_TX_DESC_SEC_TYPE(txdesc, pkt_info->sec_type);
SET_TX_DESC_DATA_BW(txdesc, pkt_info->bw);
SET_TX_DESC_SW_SEQ(txdesc, pkt_info->seq);
SET_TX_DESC_MAX_AGG_NUM(txdesc, pkt_info->ampdu_factor);
SET_TX_DESC_AMPDU_DENSITY(txdesc, pkt_info->ampdu_density);
SET_TX_DESC_DATA_STBC(txdesc, pkt_info->stbc);
SET_TX_DESC_DATA_LDPC(txdesc, pkt_info->ldpc);
SET_TX_DESC_AGG_EN(txdesc, pkt_info->ampdu_en);
SET_TX_DESC_LS(txdesc, pkt_info->ls);
SET_TX_DESC_DATA_SHORT(txdesc, pkt_info->short_gi);
SET_TX_DESC_SPE_RPT(txdesc, pkt_info->report);
SET_TX_DESC_SW_DEFINE(txdesc, pkt_info->sn);
SET_TX_DESC_USE_RTS(txdesc, pkt_info->rts);
if (pkt_info->rts) { if (pkt_info->rts) {
SET_TX_DESC_RTSRATE(txdesc, DESC_RATE24M); tx_desc->w4 |= le32_encode_bits(DESC_RATE24M, RTW_TX_DESC_W4_RTSRATE);
SET_TX_DESC_DATA_RTS_SHORT(txdesc, 1); tx_desc->w5 |= le32_encode_bits(1, RTW_TX_DESC_W5_DATA_RTS_SHORT);
} }
SET_TX_DESC_DISQSELSEQ(txdesc, pkt_info->dis_qselseq);
SET_TX_DESC_EN_HWSEQ(txdesc, pkt_info->en_hwseq); if (pkt_info->tim_offset)
SET_TX_DESC_HW_SSN_SEL(txdesc, pkt_info->hw_ssn_sel); tx_desc->w9 |= le32_encode_bits(1, RTW_TX_DESC_W9_TIM_EN) |
SET_TX_DESC_NAVUSEHDR(txdesc, pkt_info->nav_use_hdr); le32_encode_bits(pkt_info->tim_offset, RTW_TX_DESC_W9_TIM_OFFSET);
SET_TX_DESC_BT_NULL(txdesc, pkt_info->bt_null);
} }
EXPORT_SYMBOL(rtw_tx_fill_tx_desc); EXPORT_SYMBOL(rtw_tx_fill_tx_desc);
static u8 get_tx_ampdu_factor(struct ieee80211_sta *sta) static u8 get_tx_ampdu_factor(struct ieee80211_sta *sta)
{ {
u8 exp = sta->ht_cap.ampdu_factor; u8 exp = sta->deflink.ht_cap.ampdu_factor;
/* the least ampdu factor is 8K, and the value in the tx desc is the /* the least ampdu factor is 8K, and the value in the tx desc is the
* max aggregation num, which represents val * 2 packets can be * max aggregation num, which represents val * 2 packets can be
@ -83,7 +101,7 @@ static u8 get_tx_ampdu_factor(struct ieee80211_sta *sta)
static u8 get_tx_ampdu_density(struct ieee80211_sta *sta) static u8 get_tx_ampdu_density(struct ieee80211_sta *sta)
{ {
return sta->ht_cap.ampdu_density; return sta->deflink.ht_cap.ampdu_density;
} }
static u8 get_highest_ht_tx_rate(struct rtw_dev *rtwdev, static u8 get_highest_ht_tx_rate(struct rtw_dev *rtwdev,
@ -91,7 +109,7 @@ static u8 get_highest_ht_tx_rate(struct rtw_dev *rtwdev,
{ {
u8 rate; u8 rate;
if (rtwdev->hal.rf_type == RF_2T2R && sta->ht_cap.mcs.rx_mask[1] != 0) if (rtwdev->hal.rf_type == RF_2T2R && sta->deflink.ht_cap.mcs.rx_mask[1] != 0)
rate = DESC_RATEMCS15; rate = DESC_RATEMCS15;
else else
rate = DESC_RATEMCS7; rate = DESC_RATEMCS7;
@ -106,7 +124,7 @@ static u8 get_highest_vht_tx_rate(struct rtw_dev *rtwdev,
u8 rate; u8 rate;
u16 tx_mcs_map; u16 tx_mcs_map;
tx_mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.tx_mcs_map); tx_mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.tx_mcs_map);
if (efuse->hw_cap.nss == 1) { if (efuse->hw_cap.nss == 1) {
switch (tx_mcs_map & 0x3) { switch (tx_mcs_map & 0x3) {
case IEEE80211_VHT_MCS_SUPPORT_0_7: case IEEE80211_VHT_MCS_SUPPORT_0_7:
@ -340,11 +358,11 @@ static void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev,
if (info->control.use_rts || skb->len > hw->wiphy->rts_threshold) if (info->control.use_rts || skb->len > hw->wiphy->rts_threshold)
pkt_info->rts = true; pkt_info->rts = true;
if (sta->vht_cap.vht_supported) if (sta->deflink.vht_cap.vht_supported)
rate = get_highest_vht_tx_rate(rtwdev, sta); rate = get_highest_vht_tx_rate(rtwdev, sta);
else if (sta->ht_cap.ht_supported) else if (sta->deflink.ht_cap.ht_supported)
rate = get_highest_ht_tx_rate(rtwdev, sta); rate = get_highest_ht_tx_rate(rtwdev, sta);
else if (sta->supp_rates[0] <= 0xf) else if (sta->deflink.supp_rates[0] <= 0xf)
rate = DESC_RATE11M; rate = DESC_RATE11M;
else else
rate = DESC_RATE54M; rate = DESC_RATE54M;
@ -353,7 +371,7 @@ static void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev,
bw = si->bw_mode; bw = si->bw_mode;
rate_id = si->rate_id; rate_id = si->rate_id;
stbc = si->stbc_en; stbc = rtwdev->hal.txrx_1ss ? false : si->stbc_en;
ldpc = si->ldpc_en; ldpc = si->ldpc_en;
out: out:
@ -380,7 +398,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct rtw_sta_info *si; struct rtw_sta_info *si;
@ -420,7 +438,7 @@ void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev,
struct sk_buff *skb, struct sk_buff *skb,
enum rtw_rsvd_packet_type type) enum rtw_rsvd_packet_type type)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
bool bmc; bool bmc;
@ -448,6 +466,19 @@ void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev,
if (type == RSVD_QOS_NULL) if (type == RSVD_QOS_NULL)
pkt_info->bt_null = true; pkt_info->bt_null = true;
if (type == RSVD_BEACON) {
struct rtw_rsvd_page *rsvd_pkt;
int hdr_len;
rsvd_pkt = list_first_entry_or_null(&rtwdev->rsvd_page_list,
struct rtw_rsvd_page,
build_list);
if (rsvd_pkt && rsvd_pkt->tim_offset != 0) {
hdr_len = sizeof(struct ieee80211_hdr_3addr);
pkt_info->tim_offset = rsvd_pkt->tim_offset - hdr_len;
}
}
rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb); rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb);
/* TODO: need to change hw port and hw ssn sel for multiple vifs */ /* TODO: need to change hw port and hw ssn sel for multiple vifs */
@ -458,7 +489,7 @@ rtw_tx_write_data_rsvd_page_get(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info, struct rtw_tx_pkt_info *pkt_info,
u8 *buf, u32 size) u8 *buf, u32 size)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct sk_buff *skb; struct sk_buff *skb;
u32 tx_pkt_desc_sz; u32 tx_pkt_desc_sz;
u32 length; u32 length;
@ -484,7 +515,7 @@ rtw_tx_write_data_h2c_get(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info, struct rtw_tx_pkt_info *pkt_info,
u8 *buf, u32 size) u8 *buf, u32 size)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
struct sk_buff *skb; struct sk_buff *skb;
u32 tx_pkt_desc_sz; u32 tx_pkt_desc_sz;
u32 length; u32 length;
@ -575,8 +606,6 @@ static int rtw_txq_push_skb(struct rtw_dev *rtwdev,
rtw_err(rtwdev, "failed to write TX skb to HCI\n"); rtw_err(rtwdev, "failed to write TX skb to HCI\n");
return ret; return ret;
} }
rtwtxq->last_push = jiffies;
return 0; return 0;
} }
@ -618,9 +647,8 @@ static void rtw_txq_push(struct rtw_dev *rtwdev,
rcu_read_unlock(); rcu_read_unlock();
} }
void rtw_tx_work(struct work_struct *w) void __rtw_tx_work(struct rtw_dev *rtwdev)
{ {
struct rtw_dev *rtwdev = container_of(w, struct rtw_dev, tx_work);
struct rtw_txq *rtwtxq, *tmp; struct rtw_txq *rtwtxq, *tmp;
spin_lock_bh(&rtwdev->txq_lock); spin_lock_bh(&rtwdev->txq_lock);
@ -641,6 +669,13 @@ void rtw_tx_work(struct work_struct *w)
spin_unlock_bh(&rtwdev->txq_lock); spin_unlock_bh(&rtwdev->txq_lock);
} }
void rtw_tx_work(struct work_struct *w)
{
struct rtw_dev *rtwdev = container_of(w, struct rtw_dev, tx_work);
__rtw_tx_work(rtwdev);
}
void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq)
{ {
struct rtw_txq *rtwtxq; struct rtw_txq *rtwtxq;
@ -665,3 +700,44 @@ void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq)
list_del_init(&rtwtxq->list); list_del_init(&rtwtxq->list);
spin_unlock_bh(&rtwdev->txq_lock); spin_unlock_bh(&rtwdev->txq_lock);
} }
static const enum rtw_tx_queue_type ac_to_hwq[] = {
[IEEE80211_AC_VO] = RTW_TX_QUEUE_VO,
[IEEE80211_AC_VI] = RTW_TX_QUEUE_VI,
[IEEE80211_AC_BE] = RTW_TX_QUEUE_BE,
[IEEE80211_AC_BK] = RTW_TX_QUEUE_BK,
};
static_assert(ARRAY_SIZE(ac_to_hwq) == IEEE80211_NUM_ACS);
enum rtw_tx_queue_type rtw_tx_ac_to_hwq(enum ieee80211_ac_numbers ac)
{
if (WARN_ON(unlikely(ac >= IEEE80211_NUM_ACS)))
return RTW_TX_QUEUE_BE;
return ac_to_hwq[ac];
}
EXPORT_SYMBOL(rtw_tx_ac_to_hwq);
enum rtw_tx_queue_type rtw_tx_queue_mapping(struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
u8 q_mapping = skb_get_queue_mapping(skb);
enum rtw_tx_queue_type queue;
if (unlikely(ieee80211_is_beacon(fc)))
queue = RTW_TX_QUEUE_BCN;
else if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)))
queue = RTW_TX_QUEUE_MGMT;
else if (is_broadcast_ether_addr(hdr->addr1) ||
is_multicast_ether_addr(hdr->addr1))
queue = RTW_TX_QUEUE_HI0;
else if (WARN_ON_ONCE(q_mapping >= ARRAY_SIZE(ac_to_hwq)))
queue = ac_to_hwq[IEEE80211_AC_BE];
else
queue = ac_to_hwq[q_mapping];
return queue;
}
EXPORT_SYMBOL(rtw_tx_queue_mapping);

134
tx.h
View file

@ -9,64 +9,53 @@
#define RTW_TX_PROBE_TIMEOUT msecs_to_jiffies(500) #define RTW_TX_PROBE_TIMEOUT msecs_to_jiffies(500)
#define SET_TX_DESC_TXPKTSIZE(txdesc, value) \ struct rtw_tx_desc {
le32p_replace_bits((__le32 *)(txdesc) + 0x00, value, GENMASK(15, 0)) __le32 w0;
#define SET_TX_DESC_OFFSET(txdesc, value) \ __le32 w1;
le32p_replace_bits((__le32 *)(txdesc) + 0x00, value, GENMASK(23, 16)) __le32 w2;
#define SET_TX_DESC_PKT_OFFSET(txdesc, value) \ __le32 w3;
le32p_replace_bits((__le32 *)(txdesc) + 0x01, value, GENMASK(28, 24)) __le32 w4;
#define SET_TX_DESC_QSEL(txdesc, value) \ __le32 w5;
le32p_replace_bits((__le32 *)(txdesc) + 0x01, value, GENMASK(12, 8)) __le32 w6;
#define SET_TX_DESC_BMC(txdesc, value) \ __le32 w7;
le32p_replace_bits((__le32 *)(txdesc) + 0x00, value, BIT(24)) __le32 w8;
#define SET_TX_DESC_RATE_ID(txdesc, value) \ __le32 w9;
le32p_replace_bits((__le32 *)(txdesc) + 0x01, value, GENMASK(20, 16)) } __packed;
#define SET_TX_DESC_DATARATE(txdesc, value) \
le32p_replace_bits((__le32 *)(txdesc) + 0x04, value, GENMASK(6, 0)) #define RTW_TX_DESC_W0_TXPKTSIZE GENMASK(15, 0)
#define SET_TX_DESC_DISDATAFB(txdesc, value) \ #define RTW_TX_DESC_W0_OFFSET GENMASK(23, 16)
le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(10)) #define RTW_TX_DESC_W0_BMC BIT(24)
#define SET_TX_DESC_USE_RATE(txdesc, value) \ #define RTW_TX_DESC_W0_LS BIT(26)
le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(8)) #define RTW_TX_DESC_W0_DISQSELSEQ BIT(31)
#define SET_TX_DESC_SEC_TYPE(txdesc, value) \ #define RTW_TX_DESC_W1_QSEL GENMASK(12, 8)
le32p_replace_bits((__le32 *)(txdesc) + 0x01, value, GENMASK(23, 22)) #define RTW_TX_DESC_W1_RATE_ID GENMASK(20, 16)
#define SET_TX_DESC_DATA_BW(txdesc, value) \ #define RTW_TX_DESC_W1_SEC_TYPE GENMASK(23, 22)
le32p_replace_bits((__le32 *)(txdesc) + 0x05, value, GENMASK(6, 5)) #define RTW_TX_DESC_W1_PKT_OFFSET GENMASK(28, 24)
#define SET_TX_DESC_SW_SEQ(txdesc, value) \ #define RTW_TX_DESC_W1_MORE_DATA BIT(29)
le32p_replace_bits((__le32 *)(txdesc) + 0x09, value, GENMASK(23, 12)) #define RTW_TX_DESC_W2_AGG_EN BIT(12)
#define SET_TX_DESC_MAX_AGG_NUM(txdesc, value) \ #define RTW_TX_DESC_W2_SPE_RPT BIT(19)
le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, GENMASK(21, 17)) #define RTW_TX_DESC_W2_AMPDU_DEN GENMASK(22, 20)
#define SET_TX_DESC_USE_RTS(tx_desc, value) \ #define RTW_TX_DESC_W2_BT_NULL BIT(23)
le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(12)) #define RTW_TX_DESC_W3_HW_SSN_SEL GENMASK(7, 6)
#define SET_TX_DESC_RTSRATE(txdesc, value) \ #define RTW_TX_DESC_W3_USE_RATE BIT(8)
le32p_replace_bits((__le32 *)(txdesc) + 0x04, value, GENMASK(28, 24)) #define RTW_TX_DESC_W3_DISDATAFB BIT(10)
#define SET_TX_DESC_DATA_RTS_SHORT(txdesc, value) \ #define RTW_TX_DESC_W3_USE_RTS BIT(12)
le32p_replace_bits((__le32 *)(txdesc) + 0x05, value, BIT(12)) #define RTW_TX_DESC_W3_NAVUSEHDR BIT(15)
#define SET_TX_DESC_AMPDU_DENSITY(txdesc, value) \ #define RTW_TX_DESC_W3_MAX_AGG_NUM GENMASK(21, 17)
le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, GENMASK(22, 20)) #define RTW_TX_DESC_W4_DATARATE GENMASK(6, 0)
#define SET_TX_DESC_DATA_STBC(txdesc, value) \ #define RTW_TX_DESC_W4_RTSRATE GENMASK(28, 24)
le32p_replace_bits((__le32 *)(txdesc) + 0x05, value, GENMASK(9, 8)) #define RTW_TX_DESC_W5_DATA_SHORT BIT(4)
#define SET_TX_DESC_DATA_LDPC(txdesc, value) \ #define RTW_TX_DESC_W5_DATA_BW GENMASK(6, 5)
le32p_replace_bits((__le32 *)(txdesc) + 0x05, value, BIT(7)) #define RTW_TX_DESC_W5_DATA_LDPC BIT(7)
#define SET_TX_DESC_AGG_EN(txdesc, value) \ #define RTW_TX_DESC_W5_DATA_STBC GENMASK(9, 8)
le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(12)) #define RTW_TX_DESC_W5_DATA_RTS_SHORT BIT(12)
#define SET_TX_DESC_LS(txdesc, value) \ #define RTW_TX_DESC_W6_SW_DEFINE GENMASK(11, 0)
le32p_replace_bits((__le32 *)(txdesc) + 0x00, value, BIT(26)) #define RTW_TX_DESC_W7_TXDESC_CHECKSUM GENMASK(15, 0)
#define SET_TX_DESC_DATA_SHORT(txdesc, value) \ #define RTW_TX_DESC_W7_DMA_TXAGG_NUM GENMASK(31, 24)
le32p_replace_bits((__le32 *)(txdesc) + 0x05, value, BIT(4)) #define RTW_TX_DESC_W8_EN_HWSEQ BIT(15)
#define SET_TX_DESC_SPE_RPT(tx_desc, value) \ #define RTW_TX_DESC_W9_SW_SEQ GENMASK(23, 12)
le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(19)) #define RTW_TX_DESC_W9_TIM_EN BIT(7)
#define SET_TX_DESC_SW_DEFINE(tx_desc, value) \ #define RTW_TX_DESC_W9_TIM_OFFSET GENMASK(6, 0)
le32p_replace_bits((__le32 *)(txdesc) + 0x06, value, GENMASK(11, 0))
#define SET_TX_DESC_DISQSELSEQ(txdesc, value) \
le32p_replace_bits((__le32 *)(txdesc) + 0x00, value, BIT(31))
#define SET_TX_DESC_EN_HWSEQ(txdesc, value) \
le32p_replace_bits((__le32 *)(txdesc) + 0x08, value, BIT(15))
#define SET_TX_DESC_HW_SSN_SEL(txdesc, value) \
le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, GENMASK(7, 6))
#define SET_TX_DESC_NAVUSEHDR(txdesc, value) \
le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(15))
#define SET_TX_DESC_BT_NULL(txdesc, value) \
le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(23))
enum rtw_tx_desc_queue_select { enum rtw_tx_desc_queue_select {
TX_DESC_QSEL_TID0 = 0, TX_DESC_QSEL_TID0 = 0,
@ -99,6 +88,7 @@ void rtw_tx(struct rtw_dev *rtwdev,
void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq); void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq);
void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq); void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq);
void rtw_tx_work(struct work_struct *w); void rtw_tx_work(struct work_struct *w);
void __rtw_tx_work(struct rtw_dev *rtwdev);
void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info, struct rtw_tx_pkt_info *pkt_info,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
@ -119,4 +109,32 @@ rtw_tx_write_data_h2c_get(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info, struct rtw_tx_pkt_info *pkt_info,
u8 *buf, u32 size); u8 *buf, u32 size);
enum rtw_tx_queue_type rtw_tx_ac_to_hwq(enum ieee80211_ac_numbers ac);
enum rtw_tx_queue_type rtw_tx_queue_mapping(struct sk_buff *skb);
static inline
void fill_txdesc_checksum_common(u8 *txdesc, size_t words)
{
__le16 chksum = 0;
__le16 *data = (__le16 *)(txdesc);
struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)txdesc;
le32p_replace_bits(&tx_desc->w7, 0, RTW_TX_DESC_W7_TXDESC_CHECKSUM);
while (words--)
chksum ^= *data++;
le32p_replace_bits(&tx_desc->w7, __le16_to_cpu(chksum),
RTW_TX_DESC_W7_TXDESC_CHECKSUM);
}
static inline void rtw_tx_fill_txdesc_checksum(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *txdesc)
{
const struct rtw_chip_info *chip = rtwdev->chip;
chip->ops->fill_txdesc_checksum(rtwdev, pkt_info, txdesc);
}
#endif #endif

913
usb.c Normal file
View file

@ -0,0 +1,913 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include "main.h"
#include "debug.h"
#include "reg.h"
#include "tx.h"
#include "rx.h"
#include "fw.h"
#include "ps.h"
#include "usb.h"
#define RTW_USB_MAX_RXQ_LEN 512
struct rtw_usb_txcb {
struct rtw_dev *rtwdev;
struct sk_buff_head tx_ack_queue;
};
static void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb,
struct sk_buff *skb, int agg_num)
{
struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data;
struct rtw_dev *rtwdev = rtwusb->rtwdev;
struct rtw_tx_pkt_info pkt_info;
le32p_replace_bits(&tx_desc->w7, agg_num, RTW_TX_DESC_W7_DMA_TXAGG_NUM);
pkt_info.pkt_offset = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_PKT_OFFSET);
rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data);
}
static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
struct usb_device *udev = rtwusb->udev;
__le32 *data;
unsigned long flags;
int idx, ret;
static int count;
spin_lock_irqsave(&rtwusb->usb_lock, flags);
idx = rtwusb->usb_data_index;
rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1);
spin_unlock_irqrestore(&rtwusb->usb_lock, flags);
data = &rtwusb->usb_data[idx];
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr,
RTW_USB_VENQT_CMD_IDX, data, len, 1000);
if (ret < 0 && ret != -ENODEV && count++ < 4)
rtw_err(rtwdev, "read register 0x%x failed with %d\n",
addr, ret);
return le32_to_cpu(*data);
}
static u8 rtw_usb_read8(struct rtw_dev *rtwdev, u32 addr)
{
return (u8)rtw_usb_read(rtwdev, addr, 1);
}
static u16 rtw_usb_read16(struct rtw_dev *rtwdev, u32 addr)
{
return (u16)rtw_usb_read(rtwdev, addr, 2);
}
static u32 rtw_usb_read32(struct rtw_dev *rtwdev, u32 addr)
{
return (u32)rtw_usb_read(rtwdev, addr, 4);
}
static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len)
{
struct rtw_usb *rtwusb = (struct rtw_usb *)rtwdev->priv;
struct usb_device *udev = rtwusb->udev;
unsigned long flags;
__le32 *data;
int idx, ret;
static int count;
spin_lock_irqsave(&rtwusb->usb_lock, flags);
idx = rtwusb->usb_data_index;
rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1);
spin_unlock_irqrestore(&rtwusb->usb_lock, flags);
data = &rtwusb->usb_data[idx];
*data = cpu_to_le32(val);
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
addr, 0, data, len, 30000);
if (ret < 0 && ret != -ENODEV && count++ < 4)
rtw_err(rtwdev, "write register 0x%x failed with %d\n",
addr, ret);
}
static void rtw_usb_write8(struct rtw_dev *rtwdev, u32 addr, u8 val)
{
rtw_usb_write(rtwdev, addr, val, 1);
}
static void rtw_usb_write16(struct rtw_dev *rtwdev, u32 addr, u16 val)
{
rtw_usb_write(rtwdev, addr, val, 2);
}
static void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
{
rtw_usb_write(rtwdev, addr, val, 4);
}
static int dma_mapping_to_ep(enum rtw_dma_mapping dma_mapping)
{
switch (dma_mapping) {
case RTW_DMA_MAPPING_HIGH:
return 0;
case RTW_DMA_MAPPING_NORMAL:
return 1;
case RTW_DMA_MAPPING_LOW:
return 2;
case RTW_DMA_MAPPING_EXTRA:
return 3;
default:
return -EINVAL;
}
}
static int rtw_usb_parse(struct rtw_dev *rtwdev,
struct usb_interface *interface)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
struct usb_host_interface *host_interface = &interface->altsetting[0];
struct usb_interface_descriptor *interface_desc = &host_interface->desc;
struct usb_endpoint_descriptor *endpoint;
int num_out_pipes = 0;
int i;
u8 num;
const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_rqpn *rqpn;
for (i = 0; i < interface_desc->bNumEndpoints; i++) {
endpoint = &host_interface->endpoint[i].desc;
num = usb_endpoint_num(endpoint);
if (usb_endpoint_dir_in(endpoint) &&
usb_endpoint_xfer_bulk(endpoint)) {
if (rtwusb->pipe_in) {
rtw_err(rtwdev, "IN pipes overflow\n");
return -EINVAL;
}
rtwusb->pipe_in = num;
}
if (usb_endpoint_dir_in(endpoint) &&
usb_endpoint_xfer_int(endpoint)) {
if (rtwusb->pipe_interrupt) {
rtw_err(rtwdev, "INT pipes overflow\n");
return -EINVAL;
}
rtwusb->pipe_interrupt = num;
}
if (usb_endpoint_dir_out(endpoint) &&
usb_endpoint_xfer_bulk(endpoint)) {
if (num_out_pipes >= ARRAY_SIZE(rtwusb->out_ep)) {
rtw_err(rtwdev, "OUT pipes overflow\n");
return -EINVAL;
}
rtwusb->out_ep[num_out_pipes++] = num;
}
}
rtwdev->hci.bulkout_num = num_out_pipes;
if (num_out_pipes < 1 || num_out_pipes > 4) {
rtw_err(rtwdev, "invalid number of endpoints %d\n", num_out_pipes);
return -EINVAL;
}
rqpn = &chip->rqpn_table[num_out_pipes];
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID0] = dma_mapping_to_ep(rqpn->dma_map_be);
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID1] = dma_mapping_to_ep(rqpn->dma_map_bk);
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID2] = dma_mapping_to_ep(rqpn->dma_map_bk);
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID3] = dma_mapping_to_ep(rqpn->dma_map_be);
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID4] = dma_mapping_to_ep(rqpn->dma_map_vi);
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID5] = dma_mapping_to_ep(rqpn->dma_map_vi);
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID6] = dma_mapping_to_ep(rqpn->dma_map_vo);
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID7] = dma_mapping_to_ep(rqpn->dma_map_vo);
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID8] = -EINVAL;
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID9] = -EINVAL;
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID10] = -EINVAL;
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID11] = -EINVAL;
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID12] = -EINVAL;
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID13] = -EINVAL;
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID14] = -EINVAL;
rtwusb->qsel_to_ep[TX_DESC_QSEL_TID15] = -EINVAL;
rtwusb->qsel_to_ep[TX_DESC_QSEL_BEACON] = dma_mapping_to_ep(rqpn->dma_map_hi);
rtwusb->qsel_to_ep[TX_DESC_QSEL_HIGH] = dma_mapping_to_ep(rqpn->dma_map_hi);
rtwusb->qsel_to_ep[TX_DESC_QSEL_MGMT] = dma_mapping_to_ep(rqpn->dma_map_mg);
rtwusb->qsel_to_ep[TX_DESC_QSEL_H2C] = dma_mapping_to_ep(rqpn->dma_map_hi);
return 0;
}
static void rtw_usb_write_port_tx_complete(struct urb *urb)
{
struct rtw_usb_txcb *txcb = urb->context;
struct rtw_dev *rtwdev = txcb->rtwdev;
struct ieee80211_hw *hw = rtwdev->hw;
while (true) {
struct sk_buff *skb = skb_dequeue(&txcb->tx_ack_queue);
struct ieee80211_tx_info *info;
struct rtw_usb_tx_data *tx_data;
if (!skb)
break;
info = IEEE80211_SKB_CB(skb);
tx_data = rtw_usb_get_tx_data(skb);
/* enqueue to wait for tx report */
if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn);
continue;
}
/* always ACK for others, then they won't be marked as drop */
ieee80211_tx_info_clear_status(info);
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
else
info->flags |= IEEE80211_TX_STAT_ACK;
ieee80211_tx_status_irqsafe(hw, skb);
}
kfree(txcb);
}
static int qsel_to_ep(struct rtw_usb *rtwusb, unsigned int qsel)
{
if (qsel >= ARRAY_SIZE(rtwusb->qsel_to_ep))
return -EINVAL;
return rtwusb->qsel_to_ep[qsel];
}
static int rtw_usb_write_port(struct rtw_dev *rtwdev, u8 qsel, struct sk_buff *skb,
usb_complete_t cb, void *context)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
struct usb_device *usbd = rtwusb->udev;
struct urb *urb;
unsigned int pipe;
int ret;
int ep = qsel_to_ep(rtwusb, qsel);
if (ep < 0)
return ep;
pipe = usb_sndbulkpipe(usbd, rtwusb->out_ep[ep]);
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb)
return -ENOMEM;
usb_fill_bulk_urb(urb, usbd, pipe, skb->data, skb->len, cb, context);
urb->transfer_flags |= URB_ZERO_PACKET;
ret = usb_submit_urb(urb, GFP_ATOMIC);
usb_free_urb(urb);
return ret;
}
static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list)
{
struct rtw_dev *rtwdev = rtwusb->rtwdev;
struct rtw_tx_desc *tx_desc;
struct rtw_usb_txcb *txcb;
struct sk_buff *skb_head;
struct sk_buff *skb_iter;
int agg_num = 0;
unsigned int align_next = 0;
u8 qsel;
if (skb_queue_empty(list))
return false;
txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC);
if (!txcb)
return false;
txcb->rtwdev = rtwdev;
skb_queue_head_init(&txcb->tx_ack_queue);
skb_iter = skb_dequeue(list);
if (skb_queue_empty(list)) {
skb_head = skb_iter;
goto queue;
}
skb_head = dev_alloc_skb(RTW_USB_MAX_XMITBUF_SZ);
if (!skb_head) {
skb_head = skb_iter;
goto queue;
}
while (skb_iter) {
unsigned long flags;
skb_put(skb_head, align_next);
skb_put_data(skb_head, skb_iter->data, skb_iter->len);
align_next = ALIGN(skb_iter->len, 8) - skb_iter->len;
agg_num++;
skb_queue_tail(&txcb->tx_ack_queue, skb_iter);
spin_lock_irqsave(&list->lock, flags);
skb_iter = skb_peek(list);
if (skb_iter && skb_iter->len + skb_head->len <= RTW_USB_MAX_XMITBUF_SZ)
__skb_unlink(skb_iter, list);
else
skb_iter = NULL;
spin_unlock_irqrestore(&list->lock, flags);
}
if (agg_num > 1)
rtw_usb_fill_tx_checksum(rtwusb, skb_head, agg_num);
queue:
skb_queue_tail(&txcb->tx_ack_queue, skb_head);
tx_desc = (struct rtw_tx_desc *)skb_head->data;
qsel = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_QSEL);
rtw_usb_write_port(rtwdev, qsel, skb_head, rtw_usb_write_port_tx_complete, txcb);
return true;
}
static void rtw_usb_tx_handler(struct work_struct *work)
{
struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, tx_work);
int i, limit;
for (i = ARRAY_SIZE(rtwusb->tx_queue) - 1; i >= 0; i--) {
for (limit = 0; limit < 200; limit++) {
struct sk_buff_head *list = &rtwusb->tx_queue[i];
if (!rtw_usb_tx_agg_skb(rtwusb, list))
break;
}
}
}
static void rtw_usb_tx_queue_purge(struct rtw_usb *rtwusb)
{
int i;
for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++)
skb_queue_purge(&rtwusb->tx_queue[i]);
}
static void rtw_usb_write_port_complete(struct urb *urb)
{
struct sk_buff *skb = urb->context;
dev_kfree_skb_any(skb);
}
static int rtw_usb_write_data(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
u8 *buf)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct sk_buff *skb;
unsigned int desclen, headsize, size;
u8 qsel;
int ret = 0;
size = pkt_info->tx_pkt_size;
qsel = pkt_info->qsel;
desclen = chip->tx_pkt_desc_sz;
headsize = pkt_info->offset ? pkt_info->offset : desclen;
skb = dev_alloc_skb(headsize + size);
if (unlikely(!skb))
return -ENOMEM;
skb_reserve(skb, headsize);
skb_put_data(skb, buf, size);
skb_push(skb, headsize);
memset(skb->data, 0, headsize);
rtw_tx_fill_tx_desc(pkt_info, skb);
rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data);
ret = rtw_usb_write_port(rtwdev, qsel, skb,
rtw_usb_write_port_complete, skb);
if (unlikely(ret))
rtw_err(rtwdev, "failed to do USB write, ret=%d\n", ret);
return ret;
}
static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf,
u32 size)
{
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_tx_pkt_info pkt_info = {0};
pkt_info.tx_pkt_size = size;
pkt_info.qsel = TX_DESC_QSEL_BEACON;
pkt_info.offset = chip->tx_pkt_desc_sz;
return rtw_usb_write_data(rtwdev, &pkt_info, buf);
}
static int rtw_usb_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size)
{
struct rtw_tx_pkt_info pkt_info = {0};
pkt_info.tx_pkt_size = size;
pkt_info.qsel = TX_DESC_QSEL_H2C;
return rtw_usb_write_data(rtwdev, &pkt_info, buf);
}
static u8 rtw_usb_tx_queue_mapping_to_qsel(struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
u8 qsel;
if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)))
qsel = TX_DESC_QSEL_MGMT;
else if (is_broadcast_ether_addr(hdr->addr1) ||
is_multicast_ether_addr(hdr->addr1))
qsel = TX_DESC_QSEL_HIGH;
else if (skb_get_queue_mapping(skb) <= IEEE80211_AC_BK)
qsel = skb->priority;
else
qsel = TX_DESC_QSEL_BEACON;
return qsel;
}
static int rtw_usb_tx_write(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct sk_buff *skb)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_usb_tx_data *tx_data;
u8 *pkt_desc;
int ep;
pkt_info->qsel = rtw_usb_tx_queue_mapping_to_qsel(skb);
pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
memset(pkt_desc, 0, chip->tx_pkt_desc_sz);
ep = qsel_to_ep(rtwusb, pkt_info->qsel);
rtw_tx_fill_tx_desc(pkt_info, skb);
rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data);
tx_data = rtw_usb_get_tx_data(skb);
tx_data->sn = pkt_info->sn;
skb_queue_tail(&rtwusb->tx_queue[ep], skb);
return 0;
}
static void rtw_usb_tx_kick_off(struct rtw_dev *rtwdev)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
queue_work(rtwusb->txwq, &rtwusb->tx_work);
}
static void rtw_usb_rx_handler(struct work_struct *work)
{
struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_work);
struct rtw_dev *rtwdev = rtwusb->rtwdev;
const struct rtw_chip_info *chip = rtwdev->chip;
struct rtw_rx_pkt_stat pkt_stat;
struct ieee80211_rx_status rx_status;
struct sk_buff *skb;
u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
u32 pkt_offset;
u8 *rx_desc;
int limit;
for (limit = 0; limit < 200; limit++) {
skb = skb_dequeue(&rtwusb->rx_queue);
if (!skb)
break;
rx_desc = skb->data;
chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat,
&rx_status);
pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
pkt_stat.shift;
if (pkt_stat.is_c2h) {
skb_put(skb, pkt_stat.pkt_len + pkt_offset);
rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb);
continue;
}
if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) {
dev_dbg_ratelimited(rtwdev->dev, "failed to get rx_queue, overflow\n");
dev_kfree_skb_any(skb);
continue;
}
skb_put(skb, pkt_stat.pkt_len);
skb_reserve(skb, pkt_offset);
memcpy(skb->cb, &rx_status, sizeof(rx_status));
ieee80211_rx_irqsafe(rtwdev->hw, skb);
}
}
static void rtw_usb_read_port_complete(struct urb *urb);
static void rtw_usb_rx_resubmit(struct rtw_usb *rtwusb, struct rx_usb_ctrl_block *rxcb)
{
struct rtw_dev *rtwdev = rtwusb->rtwdev;
int error;
rxcb->rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, GFP_ATOMIC);
if (!rxcb->rx_skb)
return;
usb_fill_bulk_urb(rxcb->rx_urb, rtwusb->udev,
usb_rcvbulkpipe(rtwusb->udev, rtwusb->pipe_in),
rxcb->rx_skb->data, RTW_USB_MAX_RECVBUF_SZ,
rtw_usb_read_port_complete, rxcb);
error = usb_submit_urb(rxcb->rx_urb, GFP_ATOMIC);
if (error) {
kfree_skb(rxcb->rx_skb);
if (error != -ENODEV)
rtw_err(rtwdev, "Err sending rx data urb %d\n",
error);
}
}
static void rtw_usb_read_port_complete(struct urb *urb)
{
struct rx_usb_ctrl_block *rxcb = urb->context;
struct rtw_dev *rtwdev = rxcb->rtwdev;
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
struct sk_buff *skb = rxcb->rx_skb;
if (urb->status == 0) {
if (urb->actual_length >= RTW_USB_MAX_RECVBUF_SZ ||
urb->actual_length < 24) {
rtw_err(rtwdev, "failed to get urb length:%d\n",
urb->actual_length);
if (skb)
dev_kfree_skb_any(skb);
} else {
skb_queue_tail(&rtwusb->rx_queue, skb);
queue_work(rtwusb->rxwq, &rtwusb->rx_work);
}
rtw_usb_rx_resubmit(rtwusb, rxcb);
} else {
switch (urb->status) {
case -EINVAL:
case -EPIPE:
case -ENODEV:
case -ESHUTDOWN:
case -ENOENT:
case -EPROTO:
case -EILSEQ:
case -ETIME:
case -ECOMM:
case -EOVERFLOW:
case -EINPROGRESS:
break;
default:
rtw_err(rtwdev, "status %d\n", urb->status);
break;
}
if (skb)
dev_kfree_skb_any(skb);
}
}
static void rtw_usb_cancel_rx_bufs(struct rtw_usb *rtwusb)
{
struct rx_usb_ctrl_block *rxcb;
int i;
for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
rxcb = &rtwusb->rx_cb[i];
if (rxcb->rx_urb)
usb_kill_urb(rxcb->rx_urb);
}
}
static void rtw_usb_free_rx_bufs(struct rtw_usb *rtwusb)
{
struct rx_usb_ctrl_block *rxcb;
int i;
for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
rxcb = &rtwusb->rx_cb[i];
if (rxcb->rx_urb) {
usb_kill_urb(rxcb->rx_urb);
usb_free_urb(rxcb->rx_urb);
}
}
}
static int rtw_usb_alloc_rx_bufs(struct rtw_usb *rtwusb)
{
int i;
for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i];
rxcb->rtwdev = rtwusb->rtwdev;
rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rxcb->rx_urb)
goto err;
}
return 0;
err:
rtw_usb_free_rx_bufs(rtwusb);
return -ENOMEM;
}
static int rtw_usb_setup(struct rtw_dev *rtwdev)
{
/* empty function for rtw_hci_ops */
return 0;
}
static int rtw_usb_start(struct rtw_dev *rtwdev)
{
return 0;
}
static void rtw_usb_stop(struct rtw_dev *rtwdev)
{
}
static void rtw_usb_deep_ps(struct rtw_dev *rtwdev, bool enter)
{
/* empty function for rtw_hci_ops */
}
static void rtw_usb_link_ps(struct rtw_dev *rtwdev, bool enter)
{
/* empty function for rtw_hci_ops */
}
static void rtw_usb_interface_cfg(struct rtw_dev *rtwdev)
{
/* empty function for rtw_hci_ops */
}
static struct rtw_hci_ops rtw_usb_ops = {
.tx_write = rtw_usb_tx_write,
.tx_kick_off = rtw_usb_tx_kick_off,
.setup = rtw_usb_setup,
.start = rtw_usb_start,
.stop = rtw_usb_stop,
.deep_ps = rtw_usb_deep_ps,
.link_ps = rtw_usb_link_ps,
.interface_cfg = rtw_usb_interface_cfg,
.write8 = rtw_usb_write8,
.write16 = rtw_usb_write16,
.write32 = rtw_usb_write32,
.read8 = rtw_usb_read8,
.read16 = rtw_usb_read16,
.read32 = rtw_usb_read32,
.write_data_rsvd_page = rtw_usb_write_data_rsvd_page,
.write_data_h2c = rtw_usb_write_data_h2c,
};
static int rtw_usb_init_rx(struct rtw_dev *rtwdev)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
int i;
rtwusb->rxwq = create_singlethread_workqueue("rtw88_usb: rx wq");
if (!rtwusb->rxwq) {
rtw_err(rtwdev, "failed to create RX work queue\n");
return -ENOMEM;
}
skb_queue_head_init(&rtwusb->rx_queue);
INIT_WORK(&rtwusb->rx_work, rtw_usb_rx_handler);
for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i];
rtw_usb_rx_resubmit(rtwusb, rxcb);
}
return 0;
}
static void rtw_usb_deinit_rx(struct rtw_dev *rtwdev)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
skb_queue_purge(&rtwusb->rx_queue);
flush_workqueue(rtwusb->rxwq);
destroy_workqueue(rtwusb->rxwq);
}
static int rtw_usb_init_tx(struct rtw_dev *rtwdev)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
int i;
rtwusb->txwq = create_singlethread_workqueue("rtw88_usb: tx wq");
if (!rtwusb->txwq) {
rtw_err(rtwdev, "failed to create TX work queue\n");
return -ENOMEM;
}
for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++)
skb_queue_head_init(&rtwusb->tx_queue[i]);
INIT_WORK(&rtwusb->tx_work, rtw_usb_tx_handler);
return 0;
}
static void rtw_usb_deinit_tx(struct rtw_dev *rtwdev)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
rtw_usb_tx_queue_purge(rtwusb);
flush_workqueue(rtwusb->txwq);
destroy_workqueue(rtwusb->txwq);
}
static int rtw_usb_intf_init(struct rtw_dev *rtwdev,
struct usb_interface *intf)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf));
int ret;
rtwusb->udev = udev;
ret = rtw_usb_parse(rtwdev, intf);
if (ret)
return ret;
rtwusb->usb_data = kcalloc(RTW_USB_MAX_RXTX_COUNT, sizeof(u32),
GFP_KERNEL);
if (!rtwusb->usb_data)
return -ENOMEM;
usb_set_intfdata(intf, rtwdev->hw);
SET_IEEE80211_DEV(rtwdev->hw, &intf->dev);
spin_lock_init(&rtwusb->usb_lock);
return 0;
}
static void rtw_usb_intf_deinit(struct rtw_dev *rtwdev,
struct usb_interface *intf)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
usb_put_dev(rtwusb->udev);
kfree(rtwusb->usb_data);
usb_set_intfdata(intf, NULL);
}
int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct rtw_dev *rtwdev;
struct ieee80211_hw *hw;
struct rtw_usb *rtwusb;
int drv_data_size;
int ret;
drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_usb);
hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops);
if (!hw)
return -ENOMEM;
rtwdev = hw->priv;
rtwdev->hw = hw;
rtwdev->dev = &intf->dev;
rtwdev->chip = (struct rtw_chip_info *)id->driver_info;
rtwdev->hci.ops = &rtw_usb_ops;
rtwdev->hci.type = RTW_HCI_TYPE_USB;
rtwusb = rtw_get_usb_priv(rtwdev);
rtwusb->rtwdev = rtwdev;
ret = rtw_usb_alloc_rx_bufs(rtwusb);
if (ret)
goto err_release_hw;
ret = rtw_core_init(rtwdev);
if (ret)
goto err_release_hw;
ret = rtw_usb_intf_init(rtwdev, intf);
if (ret) {
rtw_err(rtwdev, "failed to init USB interface\n");
goto err_deinit_core;
}
ret = rtw_usb_init_tx(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to init USB TX\n");
goto err_destroy_usb;
}
ret = rtw_usb_init_rx(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to init USB RX\n");
goto err_destroy_txwq;
}
ret = rtw_chip_info_setup(rtwdev);
if (ret) {
rtw_err(rtwdev, "failed to setup chip information\n");
goto err_destroy_rxwq;
}
ret = rtw_register_hw(rtwdev, rtwdev->hw);
if (ret) {
rtw_err(rtwdev, "failed to register hw\n");
goto err_destroy_rxwq;
}
return 0;
err_destroy_rxwq:
rtw_usb_deinit_rx(rtwdev);
err_destroy_txwq:
rtw_usb_deinit_tx(rtwdev);
err_destroy_usb:
rtw_usb_intf_deinit(rtwdev, intf);
err_deinit_core:
rtw_core_deinit(rtwdev);
err_release_hw:
ieee80211_free_hw(hw);
return ret;
}
EXPORT_SYMBOL(rtw_usb_probe);
void rtw_usb_disconnect(struct usb_interface *intf)
{
struct ieee80211_hw *hw = usb_get_intfdata(intf);
struct rtw_dev *rtwdev;
struct rtw_usb *rtwusb;
if (!hw)
return;
rtwdev = hw->priv;
rtwusb = rtw_get_usb_priv(rtwdev);
rtw_usb_cancel_rx_bufs(rtwusb);
rtw_unregister_hw(rtwdev, hw);
rtw_usb_deinit_tx(rtwdev);
rtw_usb_deinit_rx(rtwdev);
if (rtwusb->udev->state != USB_STATE_NOTATTACHED)
usb_reset_device(rtwusb->udev);
rtw_usb_free_rx_bufs(rtwusb);
rtw_usb_intf_deinit(rtwdev, intf);
rtw_core_deinit(rtwdev);
ieee80211_free_hw(hw);
}
EXPORT_SYMBOL(rtw_usb_disconnect);
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless USB driver");
MODULE_LICENSE("Dual BSD/GPL");

100
usb.h Normal file
View file

@ -0,0 +1,100 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright(c) 2018-2019 Realtek Corporation
*/
#ifndef __RTW_USB_H_
#define __RTW_USB_H_
#define FW_8192C_START_ADDRESS 0x1000
#define FW_8192C_END_ADDRESS 0x5fff
#define RTW_USB_MAX_RXTX_COUNT 128
#define RTW_USB_VENQT_MAX_BUF_SIZE 254
#define MAX_USBCTRL_VENDORREQ_TIMES 10
#define RTW_USB_CMD_READ 0xc0
#define RTW_USB_CMD_WRITE 0x40
#define RTW_USB_CMD_REQ 0x05
#define RTW_USB_VENQT_CMD_IDX 0x00
#define RTW_USB_TX_SEL_HQ BIT(0)
#define RTW_USB_TX_SEL_LQ BIT(1)
#define RTW_USB_TX_SEL_NQ BIT(2)
#define RTW_USB_TX_SEL_EQ BIT(3)
#define RTW_USB_BULK_IN_ADDR 0x80
#define RTW_USB_INT_IN_ADDR 0x81
#define RTW_USB_HW_QUEUE_ENTRY 8
#define RTW_USB_PACKET_OFFSET_SZ 8
#define RTW_USB_MAX_XMITBUF_SZ (1024 * 20)
#define RTW_USB_MAX_RECVBUF_SZ 32768
#define RTW_USB_RECVBUFF_ALIGN_SZ 8
#define RTW_USB_RXAGG_SIZE 6
#define RTW_USB_RXAGG_TIMEOUT 10
#define RTW_USB_RXCB_NUM 4
#define RTW_USB_EP_MAX 4
#define TX_DESC_QSEL_MAX 20
#define RTW_USB_VENDOR_ID_REALTEK 0x0bda
static inline struct rtw_usb *rtw_get_usb_priv(struct rtw_dev *rtwdev)
{
return (struct rtw_usb *)rtwdev->priv;
}
struct rx_usb_ctrl_block {
struct rtw_dev *rtwdev;
struct urb *rx_urb;
struct sk_buff *rx_skb;
};
struct rtw_usb_tx_data {
u8 sn;
};
struct rtw_usb {
struct rtw_dev *rtwdev;
struct usb_device *udev;
/* protects usb_data_index */
spinlock_t usb_lock;
__le32 *usb_data;
unsigned int usb_data_index;
u8 pipe_interrupt;
u8 pipe_in;
u8 out_ep[RTW_USB_EP_MAX];
int qsel_to_ep[TX_DESC_QSEL_MAX];
struct workqueue_struct *txwq, *rxwq;
struct sk_buff_head tx_queue[RTW_USB_EP_MAX];
struct work_struct tx_work;
struct rx_usb_ctrl_block rx_cb[RTW_USB_RXCB_NUM];
struct sk_buff_head rx_queue;
struct work_struct rx_work;
};
static inline struct rtw_usb_tx_data *rtw_usb_get_tx_data(struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
BUILD_BUG_ON(sizeof(struct rtw_usb_tx_data) >
sizeof(info->status.status_driver_data));
return (struct rtw_usb_tx_data *)info->status.status_driver_data;
}
int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id);
void rtw_usb_disconnect(struct usb_interface *intf);
#endif

104
util.c
View file

@ -23,7 +23,7 @@ EXPORT_SYMBOL(check_hw_ready);
bool ltecoex_read_reg(struct rtw_dev *rtwdev, u16 offset, u32 *val) bool ltecoex_read_reg(struct rtw_dev *rtwdev, u16 offset, u32 *val)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_ltecoex_addr *ltecoex = chip->ltecoex_addr; const struct rtw_ltecoex_addr *ltecoex = chip->ltecoex_addr;
if (!check_hw_ready(rtwdev, ltecoex->ctrl, LTECOEX_READY, 1)) if (!check_hw_ready(rtwdev, ltecoex->ctrl, LTECOEX_READY, 1))
@ -37,7 +37,7 @@ bool ltecoex_read_reg(struct rtw_dev *rtwdev, u16 offset, u32 *val)
bool ltecoex_reg_write(struct rtw_dev *rtwdev, u16 offset, u32 value) bool ltecoex_reg_write(struct rtw_dev *rtwdev, u16 offset, u32 value)
{ {
struct rtw_chip_info *chip = rtwdev->chip; const struct rtw_chip_info *chip = rtwdev->chip;
const struct rtw_ltecoex_addr *ltecoex = chip->ltecoex_addr; const struct rtw_ltecoex_addr *ltecoex = chip->ltecoex_addr;
if (!check_hw_ready(rtwdev, ltecoex->ctrl, LTECOEX_READY, 1)) if (!check_hw_ready(rtwdev, ltecoex->ctrl, LTECOEX_READY, 1))
@ -105,3 +105,103 @@ void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss)
*mcs = rate - DESC_RATEMCS0; *mcs = rate - DESC_RATEMCS0;
} }
} }
struct rtw_stas_entry {
struct list_head list;
struct ieee80211_sta *sta;
};
struct rtw_iter_stas_data {
struct rtw_dev *rtwdev;
struct list_head list;
};
static void rtw_collect_sta_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw_iter_stas_data *iter_stas = data;
struct rtw_stas_entry *stas_entry;
stas_entry = kmalloc(sizeof(*stas_entry), GFP_ATOMIC);
if (!stas_entry)
return;
stas_entry->sta = sta;
list_add_tail(&stas_entry->list, &iter_stas->list);
}
void rtw_iterate_stas(struct rtw_dev *rtwdev,
void (*iterator)(void *data,
struct ieee80211_sta *sta),
void *data)
{
struct rtw_iter_stas_data iter_data;
struct rtw_stas_entry *sta_entry, *tmp;
/* &rtwdev->mutex makes sure no stations can be removed between
* collecting the stations and iterating over them.
*/
lockdep_assert_held(&rtwdev->mutex);
iter_data.rtwdev = rtwdev;
INIT_LIST_HEAD(&iter_data.list);
ieee80211_iterate_stations_atomic(rtwdev->hw, rtw_collect_sta_iter,
&iter_data);
list_for_each_entry_safe(sta_entry, tmp, &iter_data.list,
list) {
list_del_init(&sta_entry->list);
iterator(data, sta_entry->sta);
kfree(sta_entry);
}
}
struct rtw_vifs_entry {
struct list_head list;
struct ieee80211_vif *vif;
};
struct rtw_iter_vifs_data {
struct rtw_dev *rtwdev;
struct list_head list;
};
static void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct rtw_iter_vifs_data *iter_stas = data;
struct rtw_vifs_entry *vifs_entry;
vifs_entry = kmalloc(sizeof(*vifs_entry), GFP_ATOMIC);
if (!vifs_entry)
return;
vifs_entry->vif = vif;
list_add_tail(&vifs_entry->list, &iter_stas->list);
}
void rtw_iterate_vifs(struct rtw_dev *rtwdev,
void (*iterator)(void *data, struct ieee80211_vif *vif),
void *data)
{
struct rtw_iter_vifs_data iter_data;
struct rtw_vifs_entry *vif_entry, *tmp;
/* &rtwdev->mutex makes sure no interfaces can be removed between
* collecting the interfaces and iterating over them.
*/
lockdep_assert_held(&rtwdev->mutex);
iter_data.rtwdev = rtwdev;
INIT_LIST_HEAD(&iter_data.list);
ieee80211_iterate_active_interfaces_atomic(rtwdev->hw,
IEEE80211_IFACE_ITER_NORMAL,
rtw_collect_vif_iter, &iter_data);
list_for_each_entry_safe(vif_entry, tmp, &iter_data.list,
list) {
list_del_init(&vif_entry->list);
iterator(data, vif_entry->vif);
kfree(vif_entry);
}
}

11
util.h
View file

@ -7,9 +7,6 @@
struct rtw_dev; struct rtw_dev;
#define rtw_iterate_vifs(rtwdev, iterator, data) \
ieee80211_iterate_active_interfaces(rtwdev->hw, \
IEEE80211_IFACE_ITER_NORMAL, iterator, data)
#define rtw_iterate_vifs_atomic(rtwdev, iterator, data) \ #define rtw_iterate_vifs_atomic(rtwdev, iterator, data) \
ieee80211_iterate_active_interfaces_atomic(rtwdev->hw, \ ieee80211_iterate_active_interfaces_atomic(rtwdev->hw, \
IEEE80211_IFACE_ITER_NORMAL, iterator, data) IEEE80211_IFACE_ITER_NORMAL, iterator, data)
@ -20,6 +17,14 @@ struct rtw_dev;
#define rtw_iterate_keys_rcu(rtwdev, vif, iterator, data) \ #define rtw_iterate_keys_rcu(rtwdev, vif, iterator, data) \
ieee80211_iter_keys_rcu((rtwdev)->hw, vif, iterator, data) ieee80211_iter_keys_rcu((rtwdev)->hw, vif, iterator, data)
void rtw_iterate_vifs(struct rtw_dev *rtwdev,
void (*iterator)(void *data, struct ieee80211_vif *vif),
void *data);
void rtw_iterate_stas(struct rtw_dev *rtwdev,
void (*iterator)(void *data,
struct ieee80211_sta *sta),
void *data);
static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr) static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
{ {
__le16 fc = hdr->frame_control; __le16 fc = hdr->frame_control;

2
wow.c
View file

@ -592,7 +592,7 @@ static int rtw_wow_leave_no_link_ps(struct rtw_dev *rtwdev)
if (rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE) if (rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE)
rtw_leave_lps_deep(rtwdev); rtw_leave_lps_deep(rtwdev);
} else { } else {
if (test_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags)) { if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags)) {
rtw_wow->ips_enabled = true; rtw_wow->ips_enabled = true;
ret = rtw_leave_ips(rtwdev); ret = rtw_leave_ips(rtwdev);
if (ret) if (ret)