Merge tag 'rtw-next-2025-05-16' of https://github.com/pkshih/rtw

Ping-Ke Shih says:
==================
rtw-next patches for v6.16

Some fixes and refinements across drivers, and regular development of
MLO and STA + P2P concurrency. Major changes are listed below.

rtw88:

 * improve throughput for RTL8814AU

rtw89:

 * support MLO

 * improve user experience for STA + P2P concurrency

 * dynamic antenna gain (DAG) with different power by antenna

 * load SAR tables from ACPI
==================

Link: https://patch.msgid.link/17e74675-70cc-43d7-a797-afb937030d34@RTEXMBS04.realtek.com.tw/
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg
2025-05-16 08:57:57 +02:00
85 changed files with 3743 additions and 685 deletions

View File

@@ -58,17 +58,6 @@ void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr,
}
EXPORT_SYMBOL(rtl_rfreg_delay);
void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data)
{
if (addr >= 0xf9 && addr <= 0xfe) {
rtl_addr_delay(addr);
} else {
rtl_set_bbreg(hw, addr, MASKDWORD, data);
udelay(1);
}
}
EXPORT_SYMBOL(rtl_bb_delay);
static void rtl_fw_do_work(const struct firmware *firmware, void *context,
bool is_wow)
{

View File

@@ -58,7 +58,6 @@ void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context);
void rtl_addr_delay(u32 addr);
void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr,
u32 mask, u32 data);
void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data);
bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb);
bool rtl_btc_status_false(void);
void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igval);

View File

@@ -155,6 +155,16 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
((u8)init_aspm) == (PCI_EXP_LNKCTL_ASPM_L0S |
PCI_EXP_LNKCTL_ASPM_L1 | PCI_EXP_LNKCTL_CCC))
ppsc->support_aspm = false;
/* RTL8723BE found on some ASUSTek laptops, such as F441U and
* X555UQ with subsystem ID 11ad:1723 are known to output large
* amounts of PCIe AER errors during and after boot up, causing
* heavy lags, poor network throughput, and occasional lock-ups.
*/
if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8723BE &&
(rtlpci->pdev->subsystem_vendor == 0x11ad &&
rtlpci->pdev->subsystem_device == 0x1723))
ppsc->support_aspm = false;
}
static bool _rtl_pci_platform_switch_device_pci_aspm(

View File

@@ -2055,11 +2055,6 @@ void rtl92d_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
RTPRINT(rtlpriv, FINIT, INIT_IQK, "LCK:Finish!!!\n");
}
void rtl92d_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta)
{
return;
}
static bool _rtl92d_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
u32 cmdtableidx, u32 cmdtablesz, enum swchnlcmd_id cmdid,
u32 para1, u32 para2, u32 msdelay)

View File

@@ -83,7 +83,6 @@ void rtl92d_phy_set_poweron(struct ieee80211_hw *hw);
bool rtl92d_phy_check_poweroff(struct ieee80211_hw *hw);
void rtl92d_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t);
void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw);
void rtl92d_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta);
void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw);
void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel);

View File

@@ -2445,11 +2445,6 @@ void rtl92du_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
RTPRINT(rtlpriv, FINIT, INIT_IQK, "LCK:Finish!!!\n");
}
void rtl92du_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta)
{
/* Nothing to do. */
}
u8 rtl92du_phy_sw_chnl(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);

View File

@@ -24,7 +24,6 @@ void rtl92du_phy_set_poweron(struct ieee80211_hw *hw);
bool rtl92du_phy_check_poweroff(struct ieee80211_hw *hw);
void rtl92du_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t);
void rtl92du_update_bbrf_configuration(struct ieee80211_hw *hw);
void rtl92du_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta);
void rtl92du_phy_iq_calibrate(struct ieee80211_hw *hw);
void rtl92du_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel);
void rtl92du_phy_init_pa_bias(struct ieee80211_hw *hw);

View File

@@ -2926,10 +2926,6 @@ void rtl92ee_phy_lc_calibrate(struct ieee80211_hw *hw)
rtlphy->lck_inprogress = false;
}
void rtl92ee_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta)
{
}
void rtl92ee_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
{
_rtl92ee_phy_set_rfpath_switch(hw, bmain, false);

View File

@@ -119,7 +119,6 @@ void rtl92ee_phy_set_bw_mode(struct ieee80211_hw *hw,
void rtl92ee_phy_sw_chnl_callback(struct ieee80211_hw *hw);
u8 rtl92ee_phy_sw_chnl(struct ieee80211_hw *hw);
void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
void rtl92ee_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta);
void rtl92ee_phy_lc_calibrate(struct ieee80211_hw *hw);
void rtl92ee_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
bool rtl92ee_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,

View File

@@ -4586,10 +4586,6 @@ void rtl8821ae_phy_lc_calibrate(struct ieee80211_hw *hw)
{
}
void rtl8821ae_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta)
{
}
void rtl8821ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
{
_rtl8821ae_phy_set_rfpath_switch(hw, bmain);

View File

@@ -214,7 +214,6 @@ void rtl8821ae_phy_iq_calibrate(struct ieee80211_hw *hw,
bool b_recovery);
void rtl8812ae_phy_iq_calibrate(struct ieee80211_hw *hw,
bool b_recovery);
void rtl8821ae_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta);
void rtl8821ae_phy_lc_calibrate(struct ieee80211_hw *hw);
void rtl8821ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,

View File

@@ -1077,15 +1077,3 @@ void rtl_usb_disconnect(struct usb_interface *intf)
ieee80211_free_hw(hw);
}
EXPORT_SYMBOL(rtl_usb_disconnect);
int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message)
{
return 0;
}
EXPORT_SYMBOL(rtl_usb_suspend);
int rtl_usb_resume(struct usb_interface *pusb_intf)
{
return 0;
}
EXPORT_SYMBOL(rtl_usb_resume);

View File

@@ -138,7 +138,5 @@ int rtl_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id,
const struct rtl_hal_cfg *rtl92cu_hal_cfg);
void rtl_usb_disconnect(struct usb_interface *intf);
int rtl_usb_suspend(struct usb_interface *pusb_intf, pm_message_t message);
int rtl_usb_resume(struct usb_interface *pusb_intf);
#endif

View File

@@ -309,7 +309,7 @@ static void rtw_coex_tdma_timer_base(struct rtw_dev *rtwdev, u8 type)
{
struct rtw_coex *coex = &rtwdev->coex;
struct rtw_coex_stat *coex_stat = &coex->stat;
u8 para[2] = {0};
u8 para[6] = {};
u8 times;
u16 tbtt_interval = coex_stat->wl_beacon_interval;

View File

@@ -1466,7 +1466,7 @@ void rtw_add_rsvd_page_sta(struct rtw_dev *rtwdev,
int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,
u8 *buf, u32 size)
{
u8 bckp[2];
u8 bckp[3];
u8 val;
u16 rsvd_pg_head;
u32 bcn_valid_addr;
@@ -1478,6 +1478,8 @@ int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,
if (!size)
return -EINVAL;
bckp[2] = rtw_read8(rtwdev, REG_BCN_CTRL);
if (rtw_chip_wcpu_11n(rtwdev)) {
rtw_write32_set(rtwdev, REG_DWBCN0_CTRL, BIT_BCN_VALID);
} else {
@@ -1491,6 +1493,9 @@ int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,
val |= BIT_ENSWBCN >> 8;
rtw_write8(rtwdev, REG_CR + 1, val);
rtw_write8(rtwdev, REG_BCN_CTRL,
(bckp[2] & ~BIT_EN_BCN_FUNCTION) | BIT_DIS_TSF_UDT);
if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE) {
val = rtw_read8(rtwdev, REG_FWHW_TXQ_CTRL + 2);
bckp[1] = val;
@@ -1521,6 +1526,7 @@ int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr,
rsvd_pg_head = rtwdev->fifo.rsvd_boundary;
rtw_write16(rtwdev, REG_FIFOPAGE_CTRL_2,
rsvd_pg_head | BIT_BCN_VALID_V1);
rtw_write8(rtwdev, REG_BCN_CTRL, bckp[2]);
if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE)
rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 2, bckp[1]);
rtw_write8(rtwdev, REG_CR + 1, bckp[0]);

View File

@@ -19,6 +19,8 @@ struct rtw_hci_ops {
void (*link_ps)(struct rtw_dev *rtwdev, bool enter);
void (*interface_cfg)(struct rtw_dev *rtwdev);
void (*dynamic_rx_agg)(struct rtw_dev *rtwdev, bool enable);
void (*write_firmware_page)(struct rtw_dev *rtwdev, u32 page,
const u8 *data, u32 size);
int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
@@ -79,6 +81,12 @@ static inline void rtw_hci_dynamic_rx_agg(struct rtw_dev *rtwdev, bool enable)
rtwdev->hci.ops->dynamic_rx_agg(rtwdev, enable);
}
static inline void rtw_hci_write_firmware_page(struct rtw_dev *rtwdev, u32 page,
const u8 *data, u32 size)
{
rtwdev->hci.ops->write_firmware_page(rtwdev, page, data, size);
}
static inline int
rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size)
{

View File

@@ -856,8 +856,8 @@ static void en_download_firmware_legacy(struct rtw_dev *rtwdev, bool en)
}
}
static void
write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size)
void rtw_write_firmware_page(struct rtw_dev *rtwdev, u32 page,
const u8 *data, u32 size)
{
u32 val32;
u32 block_nr;
@@ -887,6 +887,7 @@ write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size)
rtw_write32(rtwdev, write_addr, le32_to_cpu(remain_data));
}
}
EXPORT_SYMBOL(rtw_write_firmware_page);
static int
download_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size)
@@ -904,11 +905,13 @@ download_firmware_legacy(struct rtw_dev *rtwdev, const u8 *data, u32 size)
rtw_write8_set(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT);
for (page = 0; page < total_page; page++) {
write_firmware_page(rtwdev, page, data, DLFW_PAGE_SIZE_LEGACY);
rtw_hci_write_firmware_page(rtwdev, page, data,
DLFW_PAGE_SIZE_LEGACY);
data += DLFW_PAGE_SIZE_LEGACY;
}
if (last_page_size)
write_firmware_page(rtwdev, page, data, last_page_size);
rtw_hci_write_firmware_page(rtwdev, page, data,
last_page_size);
if (!check_hw_ready(rtwdev, REG_MCUFW_CTRL, BIT_FWDL_CHK_RPT, 1)) {
rtw_err(rtwdev, "failed to check download firmware report\n");

View File

@@ -34,6 +34,8 @@ int rtw_pwr_seq_parser(struct rtw_dev *rtwdev,
const struct rtw_pwr_seq_cmd * const *cmd_seq);
int rtw_mac_power_on(struct rtw_dev *rtwdev);
void rtw_mac_power_off(struct rtw_dev *rtwdev);
void rtw_write_firmware_page(struct rtw_dev *rtwdev, u32 page,
const u8 *data, u32 size);
int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw);
int rtw_mac_init(struct rtw_dev *rtwdev);
void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop);

View File

@@ -396,6 +396,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
if (rtw_bf_support)
rtw_bf_assoc(rtwdev, vif, conf);
rtw_set_ampdu_factor(rtwdev, vif, conf);
rtw_fw_beacon_filter_config(rtwdev, true, vif);
} else {
rtw_leave_lps(rtwdev);

View File

@@ -2242,7 +2242,8 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, SUPPORTS_PS);
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
if (rtwdev->chip->amsdu_in_ampdu)
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
ieee80211_hw_set(hw, TX_AMSDU);
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
@@ -2447,6 +2448,38 @@ void rtw_core_enable_beacon(struct rtw_dev *rtwdev, bool enable)
}
}
void rtw_set_ampdu_factor(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
const struct rtw_chip_ops *ops = rtwdev->chip->ops;
struct ieee80211_sta *sta;
u8 factor = 0xff;
if (!ops->set_ampdu_factor)
return;
rcu_read_lock();
sta = ieee80211_find_sta(vif, bss_conf->bssid);
if (!sta) {
rcu_read_unlock();
rtw_warn(rtwdev, "%s: failed to find station %pM\n",
__func__, bss_conf->bssid);
return;
}
if (sta->deflink.vht_cap.vht_supported)
factor = u32_get_bits(sta->deflink.vht_cap.cap,
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK);
else if (sta->deflink.ht_cap.ht_supported)
factor = sta->deflink.ht_cap.ampdu_factor;
rcu_read_unlock();
if (factor != 0xff)
ops->set_ampdu_factor(rtwdev, factor);
}
MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek 802.11ac wireless core module");
MODULE_LICENSE("Dual BSD/GPL");

View File

@@ -878,6 +878,7 @@ struct rtw_chip_ops {
u32 antenna_rx);
void (*cfg_ldo25)(struct rtw_dev *rtwdev, bool enable);
void (*efuse_grant)(struct rtw_dev *rtwdev, bool enable);
void (*set_ampdu_factor)(struct rtw_dev *rtwdev, u8 factor);
void (*false_alarm_statistics)(struct rtw_dev *rtwdev);
void (*phy_calibration)(struct rtw_dev *rtwdev);
void (*dpk_track)(struct rtw_dev *rtwdev);
@@ -1229,6 +1230,7 @@ struct rtw_chip_info {
u16 fw_fifo_addr[RTW_FW_FIFO_MAX];
const struct rtw_fwcd_segs *fwcd_segs;
bool amsdu_in_ampdu;
u8 usb_tx_agg_desc_num;
bool hw_feature_report;
u8 c2h_ra_report_size;
@@ -2272,4 +2274,6 @@ void rtw_update_channel(struct rtw_dev *rtwdev, u8 center_channel,
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);
void rtw_set_ampdu_factor(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf);
#endif

View File

@@ -12,6 +12,7 @@
#include "fw.h"
#include "ps.h"
#include "debug.h"
#include "mac.h"
static bool rtw_disable_msi;
static bool rtw_pci_disable_aspm;
@@ -1602,6 +1603,7 @@ static const struct rtw_hci_ops rtw_pci_ops = {
.link_ps = rtw_pci_link_ps,
.interface_cfg = rtw_pci_interface_cfg,
.dynamic_rx_agg = NULL,
.write_firmware_page = rtw_write_firmware_page,
.read8 = rtw_pci_read8,
.read16 = rtw_pci_read16,

View File

@@ -519,15 +519,6 @@ static const struct rtw_rqpn rqpn_table_8703b[] = {
RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH},
};
/* Default power index table for RTL8703B, used if EFUSE does not
* contain valid data. Replaces EFUSE data from offset 0x10 (start of
* txpwr_idx_table).
*/
static const u8 rtw8703b_txpwr_idx_table[] = {
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D,
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02
};
static void try_mac_from_devicetree(struct rtw_dev *rtwdev)
{
struct device_node *node = rtwdev->dev->of_node;
@@ -544,15 +535,9 @@ static void try_mac_from_devicetree(struct rtw_dev *rtwdev)
}
}
#define DBG_EFUSE_FIX(rtwdev, name) \
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "Fixed invalid EFUSE value: " \
# name "=0x%x\n", rtwdev->efuse.name)
static int rtw8703b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
u8 *pwr = (u8 *)efuse->txpwr_idx_table;
bool valid = false;
int ret;
ret = rtw8723x_read_efuse(rtwdev, log_map);
@@ -562,51 +547,6 @@ static int rtw8703b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
if (!is_valid_ether_addr(efuse->addr))
try_mac_from_devicetree(rtwdev);
/* If TX power index table in EFUSE is invalid, fall back to
* built-in table.
*/
for (int i = 0; i < ARRAY_SIZE(rtw8703b_txpwr_idx_table); i++)
if (pwr[i] != 0xff) {
valid = true;
break;
}
if (!valid) {
for (int i = 0; i < ARRAY_SIZE(rtw8703b_txpwr_idx_table); i++)
pwr[i] = rtw8703b_txpwr_idx_table[i];
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"Replaced invalid EFUSE TX power index table.");
rtw8723x_debug_txpwr_limit(rtwdev,
efuse->txpwr_idx_table, 2);
}
/* Override invalid antenna settings. */
if (efuse->bt_setting == 0xff) {
/* shared antenna */
efuse->bt_setting |= BIT(0);
/* RF path A */
efuse->bt_setting &= ~BIT(6);
DBG_EFUSE_FIX(rtwdev, bt_setting);
}
/* Override invalid board options: The coex code incorrectly
* assumes that if bits 6 & 7 are set the board doesn't
* support coex. Regd is also derived from rf_board_option and
* should be 0 if there's no valid data.
*/
if (efuse->rf_board_option == 0xff) {
efuse->regd = 0;
efuse->rf_board_option &= GENMASK(5, 0);
DBG_EFUSE_FIX(rtwdev, rf_board_option);
}
/* Override invalid crystal cap setting, default comes from
* vendor driver. Chip specific.
*/
if (efuse->crystal_cap == 0xff) {
efuse->crystal_cap = 0x20;
DBG_EFUSE_FIX(rtwdev, crystal_cap);
}
return 0;
}
@@ -1904,6 +1844,7 @@ static const struct rtw_chip_ops rtw8703b_ops = {
.set_antenna = NULL,
.cfg_ldo25 = rtw8723x_cfg_ldo25,
.efuse_grant = rtw8723x_efuse_grant,
.set_ampdu_factor = NULL,
.false_alarm_statistics = rtw8723x_false_alarm_statistics,
.phy_calibration = rtw8703b_phy_calibration,
.dpk_track = NULL,

View File

@@ -19,7 +19,7 @@ static const struct sdio_device_id rtw_8723cs_id_table[] = {
MODULE_DEVICE_TABLE(sdio, rtw_8723cs_id_table);
static struct sdio_driver rtw_8723cs_driver = {
.name = "rtw8723cs",
.name = KBUILD_MODNAME,
.id_table = rtw_8723cs_id_table,
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,

View File

@@ -1404,6 +1404,7 @@ static const struct rtw_chip_ops rtw8723d_ops = {
.set_antenna = NULL,
.cfg_ldo25 = rtw8723x_cfg_ldo25,
.efuse_grant = rtw8723x_efuse_grant,
.set_ampdu_factor = NULL,
.false_alarm_statistics = rtw8723x_false_alarm_statistics,
.phy_calibration = rtw8723d_phy_calibration,
.cck_pd_set = rtw8723d_phy_cck_pd_set,

View File

@@ -17,7 +17,7 @@ static const struct pci_device_id rtw_8723de_id_table[] = {
MODULE_DEVICE_TABLE(pci, rtw_8723de_id_table);
static struct pci_driver rtw_8723de_driver = {
.name = "rtw_8723de",
.name = KBUILD_MODNAME,
.id_table = rtw_8723de_id_table,
.probe = rtw_pci_probe,
.remove = rtw_pci_remove,

View File

@@ -25,7 +25,7 @@ static const struct sdio_device_id rtw_8723ds_id_table[] = {
MODULE_DEVICE_TABLE(sdio, rtw_8723ds_id_table);
static struct sdio_driver rtw_8723ds_driver = {
.name = "rtw_8723ds",
.name = KBUILD_MODNAME,
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.id_table = rtw_8723ds_id_table,

View File

@@ -24,7 +24,7 @@ static int rtw8723du_probe(struct usb_interface *intf,
}
static struct usb_driver rtw_8723du_driver = {
.name = "rtw_8723du",
.name = KBUILD_MODNAME,
.id_table = rtw_8723du_id_table,
.probe = rtw8723du_probe,
.disconnect = rtw_usb_disconnect,

View File

@@ -69,6 +69,9 @@ static void __rtw8723x_lck(struct rtw_dev *rtwdev)
#define DBG_EFUSE_2BYTE(rtwdev, map, name) \
rtw_dbg(rtwdev, RTW_DBG_EFUSE, # name "=0x%02x%02x\n", \
(map)->name[0], (map)->name[1])
#define DBG_EFUSE_FIX(rtwdev, name) \
rtw_dbg(rtwdev, RTW_DBG_EFUSE, "Fixed invalid EFUSE value: " \
# name "=0x%x\n", rtwdev->efuse.name)
static void rtw8723xe_efuse_debug(struct rtw_dev *rtwdev,
struct rtw8723x_efuse *map)
@@ -238,10 +241,21 @@ static void rtw8723xs_efuse_parsing(struct rtw_efuse *efuse,
ether_addr_copy(efuse->addr, map->s.mac_addr);
}
/* Default power index table for RTL8703B/RTL8723D, used if EFUSE does
* not contain valid data. Replaces EFUSE data from offset 0x10 (start
* of txpwr_idx_table).
*/
static const u8 rtw8723x_txpwr_idx_table[] = {
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D,
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02
};
static int __rtw8723x_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
{
struct rtw_efuse *efuse = &rtwdev->efuse;
u8 *pwr = (u8 *)efuse->txpwr_idx_table;
struct rtw8723x_efuse *map;
bool valid = false;
int i;
map = (struct rtw8723x_efuse *)log_map;
@@ -279,6 +293,51 @@ static int __rtw8723x_read_efuse(struct rtw_dev *rtwdev, u8 *log_map)
return -EOPNOTSUPP;
}
/* If TX power index table in EFUSE is invalid, fall back to
* built-in table.
*/
for (i = 0; i < ARRAY_SIZE(rtw8723x_txpwr_idx_table); i++)
if (pwr[i] != 0xff) {
valid = true;
break;
}
if (!valid) {
for (i = 0; i < ARRAY_SIZE(rtw8723x_txpwr_idx_table); i++)
pwr[i] = rtw8723x_txpwr_idx_table[i];
rtw_dbg(rtwdev, RTW_DBG_EFUSE,
"Replaced invalid EFUSE TX power index table.");
rtw8723x_debug_txpwr_limit(rtwdev,
efuse->txpwr_idx_table, 2);
}
/* Override invalid antenna settings. */
if (efuse->bt_setting == 0xff) {
/* shared antenna */
efuse->bt_setting |= BIT(0);
/* RF path A */
efuse->bt_setting &= ~BIT(6);
DBG_EFUSE_FIX(rtwdev, bt_setting);
}
/* Override invalid board options: The coex code incorrectly
* assumes that if bits 6 & 7 are set the board doesn't
* support coex. Regd is also derived from rf_board_option and
* should be 0 if there's no valid data.
*/
if (efuse->rf_board_option == 0xff) {
efuse->regd = 0;
efuse->rf_board_option &= GENMASK(5, 0);
DBG_EFUSE_FIX(rtwdev, rf_board_option);
}
/* Override invalid crystal cap setting, default comes from
* vendor driver. Chip specific.
*/
if (efuse->crystal_cap == 0xff) {
efuse->crystal_cap = 0x20;
DBG_EFUSE_FIX(rtwdev, crystal_cap);
}
return 0;
}

View File

@@ -925,6 +925,7 @@ static const struct rtw_chip_ops rtw8812a_ops = {
.set_tx_power_index = rtw88xxa_set_tx_power_index,
.cfg_ldo25 = rtw8812a_cfg_ldo25,
.efuse_grant = rtw88xxa_efuse_grant,
.set_ampdu_factor = NULL,
.false_alarm_statistics = rtw88xxa_false_alarm_statistics,
.phy_calibration = rtw8812a_phy_calibration,
.cck_pd_set = rtw88xxa_phy_cck_pd_set,
@@ -1075,6 +1076,7 @@ const struct rtw_chip_info rtw8812a_hw_spec = {
.rfe_defs = rtw8812a_rfe_defs,
.rfe_defs_size = ARRAY_SIZE(rtw8812a_rfe_defs),
.rx_ldpc = false,
.amsdu_in_ampdu = true,
.hw_feature_report = false,
.c2h_ra_report_size = 4,
.old_datarate_fb_limit = true,

View File

@@ -82,7 +82,7 @@ static const struct usb_device_id rtw_8812au_id_table[] = {
MODULE_DEVICE_TABLE(usb, rtw_8812au_id_table);
static struct usb_driver rtw_8812au_driver = {
.name = "rtw_8812au",
.name = KBUILD_MODNAME,
.id_table = rtw_8812au_id_table,
.probe = rtw_usb_probe,
.disconnect = rtw_usb_disconnect,

View File

@@ -1332,6 +1332,16 @@ static void rtw8814a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable)
{
}
/* Without this RTL8814A sends too many frames and (some?) 11n AP
* can't handle it, resulting in low TX speed. Other chips seem fine.
*/
static void rtw8814a_set_ampdu_factor(struct rtw_dev *rtwdev, u8 factor)
{
factor = min_t(u8, factor, IEEE80211_VHT_MAX_AMPDU_256K);
rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, (8192 << factor) - 1);
}
static void rtw8814a_false_alarm_statistics(struct rtw_dev *rtwdev)
{
struct rtw_dm_info *dm_info = &rtwdev->dm_info;
@@ -2051,6 +2061,7 @@ static const struct rtw_chip_ops rtw8814a_ops = {
.set_antenna = NULL,
.cfg_ldo25 = rtw8814a_cfg_ldo25,
.efuse_grant = rtw8814a_efuse_grant,
.set_ampdu_factor = rtw8814a_set_ampdu_factor,
.false_alarm_statistics = rtw8814a_false_alarm_statistics,
.phy_calibration = rtw8814a_phy_calibration,
.cck_pd_set = rtw8814a_phy_cck_pd_set,
@@ -2189,6 +2200,7 @@ const struct rtw_chip_info rtw8814a_hw_spec = {
.rx_ldpc = true,
.max_power_index = 0x3f,
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_2,
.amsdu_in_ampdu = false, /* RX speed is better without AMSDU */
.usb_tx_agg_desc_num = 3,
.hw_feature_report = false,
.c2h_ra_report_size = 6,

View File

@@ -17,7 +17,7 @@ static const struct pci_device_id rtw_8814ae_id_table[] = {
MODULE_DEVICE_TABLE(pci, rtw_8814ae_id_table);
static struct pci_driver rtw_8814ae_driver = {
.name = "rtw_8814ae",
.name = KBUILD_MODNAME,
.id_table = rtw_8814ae_id_table,
.probe = rtw_pci_probe,
.remove = rtw_pci_remove,

View File

@@ -42,7 +42,7 @@ static const struct usb_device_id rtw_8814au_id_table[] = {
MODULE_DEVICE_TABLE(usb, rtw_8814au_id_table);
static struct usb_driver rtw_8814au_driver = {
.name = "rtw_8814au",
.name = KBUILD_MODNAME,
.id_table = rtw_8814au_id_table,
.probe = rtw_usb_probe,
.disconnect = rtw_usb_disconnect,

View File

@@ -871,6 +871,7 @@ static const struct rtw_chip_ops rtw8821a_ops = {
.set_tx_power_index = rtw88xxa_set_tx_power_index,
.cfg_ldo25 = rtw8821a_cfg_ldo25,
.efuse_grant = rtw88xxa_efuse_grant,
.set_ampdu_factor = NULL,
.false_alarm_statistics = rtw88xxa_false_alarm_statistics,
.phy_calibration = rtw8821a_phy_calibration,
.cck_pd_set = rtw88xxa_phy_cck_pd_set,
@@ -1175,6 +1176,7 @@ const struct rtw_chip_info rtw8821a_hw_spec = {
.rfe_defs = rtw8821a_rfe_defs,
.rfe_defs_size = ARRAY_SIZE(rtw8821a_rfe_defs),
.rx_ldpc = false,
.amsdu_in_ampdu = true,
.hw_feature_report = false,
.c2h_ra_report_size = 4,
.old_datarate_fb_limit = true,

View File

@@ -66,7 +66,7 @@ static const struct usb_device_id rtw_8821au_id_table[] = {
MODULE_DEVICE_TABLE(usb, rtw_8821au_id_table);
static struct usb_driver rtw_8821au_driver = {
.name = "rtw_8821au",
.name = KBUILD_MODNAME,
.id_table = rtw_8821au_id_table,
.probe = rtw_usb_probe,
.disconnect = rtw_usb_disconnect,

View File

@@ -1668,6 +1668,7 @@ static const struct rtw_chip_ops rtw8821c_ops = {
.set_antenna = NULL,
.set_tx_power_index = rtw8821c_set_tx_power_index,
.cfg_ldo25 = rtw8821c_cfg_ldo25,
.set_ampdu_factor = NULL,
.false_alarm_statistics = rtw8821c_false_alarm_statistics,
.phy_calibration = rtw8821c_phy_calibration,
.cck_pd_set = rtw8821c_phy_cck_pd_set,
@@ -1990,6 +1991,7 @@ const struct rtw_chip_info rtw8821c_hw_spec = {
.band = RTW_BAND_2G | RTW_BAND_5G,
.page_size = TX_PAGE_SIZE,
.dig_min = 0x1c,
.amsdu_in_ampdu = true,
.usb_tx_agg_desc_num = 3,
.hw_feature_report = true,
.c2h_ra_report_size = 7,

View File

@@ -21,7 +21,7 @@ static const struct pci_device_id rtw_8821ce_id_table[] = {
MODULE_DEVICE_TABLE(pci, rtw_8821ce_id_table);
static struct pci_driver rtw_8821ce_driver = {
.name = "rtw_8821ce",
.name = KBUILD_MODNAME,
.id_table = rtw_8821ce_id_table,
.probe = rtw_pci_probe,
.remove = rtw_pci_remove,

View File

@@ -20,7 +20,7 @@ static const struct sdio_device_id rtw_8821cs_id_table[] = {
MODULE_DEVICE_TABLE(sdio, rtw_8821cs_id_table);
static struct sdio_driver rtw_8821cs_driver = {
.name = "rtw_8821cs",
.name = KBUILD_MODNAME,
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.id_table = rtw_8821cs_id_table,

View File

@@ -48,7 +48,7 @@ static int rtw_8821cu_probe(struct usb_interface *intf,
}
static struct usb_driver rtw_8821cu_driver = {
.name = "rtw_8821cu",
.name = KBUILD_MODNAME,
.id_table = rtw_8821cu_id_table,
.probe = rtw_8821cu_probe,
.disconnect = rtw_usb_disconnect,

View File

@@ -2158,6 +2158,7 @@ static const struct rtw_chip_ops rtw8822b_ops = {
.set_tx_power_index = rtw8822b_set_tx_power_index,
.set_antenna = rtw8822b_set_antenna,
.cfg_ldo25 = rtw8822b_cfg_ldo25,
.set_ampdu_factor = NULL,
.false_alarm_statistics = rtw8822b_false_alarm_statistics,
.phy_calibration = rtw8822b_phy_calibration,
.pwr_track = rtw8822b_pwr_track,
@@ -2531,6 +2532,7 @@ const struct rtw_chip_info rtw8822b_hw_spec = {
.band = RTW_BAND_2G | RTW_BAND_5G,
.page_size = TX_PAGE_SIZE,
.dig_min = 0x1c,
.amsdu_in_ampdu = true,
.usb_tx_agg_desc_num = 3,
.hw_feature_report = true,
.c2h_ra_report_size = 7,

View File

@@ -17,7 +17,7 @@ static const struct pci_device_id rtw_8822be_id_table[] = {
MODULE_DEVICE_TABLE(pci, rtw_8822be_id_table);
static struct pci_driver rtw_8822be_driver = {
.name = "rtw_8822be",
.name = KBUILD_MODNAME,
.id_table = rtw_8822be_id_table,
.probe = rtw_pci_probe,
.remove = rtw_pci_remove,

View File

@@ -20,7 +20,7 @@ static const struct sdio_device_id rtw_8822bs_id_table[] = {
MODULE_DEVICE_TABLE(sdio, rtw_8822bs_id_table);
static struct sdio_driver rtw_8822bs_driver = {
.name = "rtw_8822bs",
.name = KBUILD_MODNAME,
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.id_table = rtw_8822bs_id_table,

View File

@@ -77,6 +77,8 @@ static const struct usb_device_id rtw_8822bu_id_table[] = {
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Mercusys MA30N */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3322, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* D-Link DWA-T185 rev. A1 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0411, 0x03d1, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* BUFFALO WI-U2-866DM */
{},
};
MODULE_DEVICE_TABLE(usb, rtw_8822bu_id_table);
@@ -88,7 +90,7 @@ static int rtw8822bu_probe(struct usb_interface *intf,
}
static struct usb_driver rtw_8822bu_driver = {
.name = "rtw_8822bu",
.name = KBUILD_MODNAME,
.id_table = rtw_8822bu_id_table,
.probe = rtw8822bu_probe,
.disconnect = rtw_usb_disconnect,

View File

@@ -3951,7 +3951,8 @@ static void rtw8822c_dpk_cal_coef1(struct rtw_dev *rtwdev)
rtw_write32(rtwdev, REG_NCTL0, 0x00001148);
rtw_write32(rtwdev, REG_NCTL0, 0x00001149);
check_hw_ready(rtwdev, 0x2d9c, MASKBYTE0, 0x55);
if (!check_hw_ready(rtwdev, 0x2d9c, MASKBYTE0, 0x55))
rtw_warn(rtwdev, "DPK stuck, performance may be suboptimal");
rtw_write8(rtwdev, 0x1b10, 0x0);
rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SUBPAGE, 0x0000000c);
@@ -4968,6 +4969,7 @@ static const struct rtw_chip_ops rtw8822c_ops = {
.set_tx_power_index = rtw8822c_set_tx_power_index,
.set_antenna = rtw8822c_set_antenna,
.cfg_ldo25 = rtw8822c_cfg_ldo25,
.set_ampdu_factor = NULL,
.false_alarm_statistics = rtw8822c_false_alarm_statistics,
.dpk_track = rtw8822c_dpk_track,
.phy_calibration = rtw8822c_phy_calibration,
@@ -5349,6 +5351,7 @@ const struct rtw_chip_info rtw8822c_hw_spec = {
.band = RTW_BAND_2G | RTW_BAND_5G,
.page_size = TX_PAGE_SIZE,
.dig_min = 0x20,
.amsdu_in_ampdu = true,
.usb_tx_agg_desc_num = 3,
.hw_feature_report = true,
.c2h_ra_report_size = 7,

View File

@@ -21,7 +21,7 @@ static const struct pci_device_id rtw_8822ce_id_table[] = {
MODULE_DEVICE_TABLE(pci, rtw_8822ce_id_table);
static struct pci_driver rtw_8822ce_driver = {
.name = "rtw_8822ce",
.name = KBUILD_MODNAME,
.id_table = rtw_8822ce_id_table,
.probe = rtw_pci_probe,
.remove = rtw_pci_remove,

View File

@@ -20,7 +20,7 @@ static const struct sdio_device_id rtw_8822cs_id_table[] = {
MODULE_DEVICE_TABLE(sdio, rtw_8822cs_id_table);
static struct sdio_driver rtw_8822cs_driver = {
.name = "rtw_8822cs",
.name = KBUILD_MODNAME,
.probe = rtw_sdio_probe,
.remove = rtw_sdio_remove,
.id_table = rtw_8822cs_id_table,

View File

@@ -32,7 +32,7 @@ static int rtw8822cu_probe(struct usb_interface *intf,
}
static struct usb_driver rtw_8822cu_driver = {
.name = "rtw_8822cu",
.name = KBUILD_MODNAME,
.id_table = rtw_8822cu_id_table,
.probe = rtw8822cu_probe,
.disconnect = rtw_usb_disconnect,

View File

@@ -10,6 +10,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include "main.h"
#include "mac.h"
#include "debug.h"
#include "fw.h"
#include "ps.h"
@@ -677,12 +678,22 @@ static void rtw_sdio_enable_rx_aggregation(struct rtw_dev *rtwdev)
{
u8 size, timeout;
if (rtw_chip_wcpu_11n(rtwdev)) {
switch (rtwdev->chip->id) {
case RTW_CHIP_TYPE_8703B:
case RTW_CHIP_TYPE_8821A:
case RTW_CHIP_TYPE_8812A:
size = 0x6;
timeout = 0x6;
} else {
break;
case RTW_CHIP_TYPE_8723D:
size = 0xa;
timeout = 0x3;
rtw_write8_set(rtwdev, REG_RXDMA_AGG_PG_TH + 3, BIT(7));
break;
default:
size = 0xff;
timeout = 0x1;
break;
}
/* Make the firmware honor the size limit configured below */
@@ -718,10 +729,7 @@ static u8 rtw_sdio_get_tx_qsel(struct rtw_dev *rtwdev, struct sk_buff *skb,
case RTW_TX_QUEUE_H2C:
return TX_DESC_QSEL_H2C;
case RTW_TX_QUEUE_MGMT:
if (rtw_chip_wcpu_11n(rtwdev))
return TX_DESC_QSEL_HIGH;
else
return TX_DESC_QSEL_MGMT;
return TX_DESC_QSEL_MGMT;
case RTW_TX_QUEUE_HI0:
return TX_DESC_QSEL_HIGH;
default:
@@ -1157,6 +1165,7 @@ static const struct rtw_hci_ops rtw_sdio_ops = {
.link_ps = rtw_sdio_link_ps,
.interface_cfg = rtw_sdio_interface_cfg,
.dynamic_rx_agg = NULL,
.write_firmware_page = rtw_write_firmware_page,
.read8 = rtw_sdio_read8,
.read16 = rtw_sdio_read16,
@@ -1227,10 +1236,7 @@ static void rtw_sdio_process_tx_queue(struct rtw_dev *rtwdev,
return;
}
if (queue <= RTW_TX_QUEUE_VO)
rtw_sdio_indicate_tx_status(rtwdev, skb);
else
dev_kfree_skb_any(skb);
rtw_sdio_indicate_tx_status(rtwdev, skb);
}
static void rtw_sdio_tx_handler(struct work_struct *work)
@@ -1298,7 +1304,6 @@ static void rtw_sdio_deinit_tx(struct rtw_dev *rtwdev)
struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv;
int i;
flush_workqueue(rtwsdio->txwq);
destroy_workqueue(rtwsdio->txwq);
kfree(rtwsdio->tx_handler_data);

View File

@@ -139,7 +139,7 @@ static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len)
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
addr, 0, data, len, 30000);
addr, 0, data, len, 500);
if (ret < 0 && ret != -ENODEV && count++ < 4)
rtw_err(rtwdev, "write register 0x%x failed with %d\n",
addr, ret);
@@ -165,6 +165,60 @@ static void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
rtw_usb_write(rtwdev, addr, val, 4);
}
static void rtw_usb_write_firmware_page(struct rtw_dev *rtwdev, u32 page,
const u8 *data, u32 size)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
struct usb_device *udev = rtwusb->udev;
u32 addr = FW_START_ADDR_LEGACY;
u8 *data_dup, *buf;
u32 n, block_size;
int ret;
switch (rtwdev->chip->id) {
case RTW_CHIP_TYPE_8723D:
block_size = 254;
break;
default:
block_size = 196;
break;
}
data_dup = kmemdup(data, size, GFP_KERNEL);
if (!data_dup)
return;
buf = data_dup;
rtw_write32_mask(rtwdev, REG_MCUFW_CTRL, BIT_ROM_PGE, page);
while (size > 0) {
if (size >= block_size)
n = block_size;
else if (size >= 8)
n = 8;
else
n = 1;
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
addr, 0, buf, n, 500);
if (ret != n) {
if (ret != -ENODEV)
rtw_err(rtwdev,
"write 0x%x len %d failed: %d\n",
addr, n, ret);
break;
}
addr += n;
buf += n;
size -= n;
}
kfree(data_dup);
}
static int dma_mapping_to_ep(enum rtw_dma_mapping dma_mapping)
{
switch (dma_mapping) {
@@ -866,6 +920,7 @@ static void rtw_usb_dynamic_rx_agg(struct rtw_dev *rtwdev, bool enable)
case RTW_CHIP_TYPE_8822C:
case RTW_CHIP_TYPE_8822B:
case RTW_CHIP_TYPE_8821C:
case RTW_CHIP_TYPE_8814A:
rtw_usb_dynamic_rx_agg_v1(rtwdev, enable);
break;
case RTW_CHIP_TYPE_8821A:
@@ -891,6 +946,7 @@ static const struct rtw_hci_ops rtw_usb_ops = {
.link_ps = rtw_usb_link_ps,
.interface_cfg = rtw_usb_interface_cfg,
.dynamic_rx_agg = rtw_usb_dynamic_rx_agg,
.write_firmware_page = rtw_usb_write_firmware_page,
.write8 = rtw_usb_write8,
.write16 = rtw_usb_write16,
@@ -948,7 +1004,6 @@ static void rtw_usb_deinit_rx(struct rtw_dev *rtwdev)
skb_queue_purge(&rtwusb->rx_queue);
flush_workqueue(rtwusb->rxwq);
destroy_workqueue(rtwusb->rxwq);
skb_queue_purge(&rtwusb->rx_free_queue);
@@ -977,7 +1032,6 @@ static void rtw_usb_deinit_tx(struct rtw_dev *rtwdev)
{
struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
flush_workqueue(rtwusb->txwq);
destroy_workqueue(rtwusb->txwq);
rtw_usb_tx_queue_purge(rtwusb);
}
@@ -1094,7 +1148,8 @@ static int rtw_usb_switch_mode_new(struct rtw_dev *rtwdev)
static bool rtw_usb3_chip_old(u8 chip_id)
{
return chip_id == RTW_CHIP_TYPE_8812A;
return chip_id == RTW_CHIP_TYPE_8812A ||
chip_id == RTW_CHIP_TYPE_8814A;
}
static bool rtw_usb3_chip_new(u8 chip_id)

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,11 @@
#include "core.h"
struct rtw89_acpi_data {
u32 len;
u8 buf[] __counted_by(len);
};
enum rtw89_acpi_dsm_func {
RTW89_ACPI_DSM_FUNC_IDN_BAND_SUP = 2,
RTW89_ACPI_DSM_FUNC_6G_DIS = 3,
@@ -26,6 +31,13 @@ enum rtw89_acpi_policy_mode {
RTW89_ACPI_POLICY_ALLOW = 1,
};
enum rtw89_acpi_conf_tas {
RTW89_ACPI_CONF_TAS_US = BIT(0),
RTW89_ACPI_CONF_TAS_CA = BIT(1),
RTW89_ACPI_CONF_TAS_KR = BIT(2),
RTW89_ACPI_CONF_TAS_OTHERS = BIT(7),
};
struct rtw89_acpi_country_code {
/* below are allowed:
* * ISO alpha2 country code
@@ -54,12 +66,21 @@ struct rtw89_acpi_policy_6ghz_sp {
u8 rsvd;
} __packed;
struct rtw89_acpi_policy_tas {
u8 signature[4];
u8 revision;
u8 enable;
u8 enabled_countries;
u8 rsvd[3];
} __packed;
struct rtw89_acpi_dsm_result {
union {
u8 value;
/* caller needs to free it after using */
struct rtw89_acpi_policy_6ghz *policy_6ghz;
struct rtw89_acpi_policy_6ghz_sp *policy_6ghz_sp;
struct rtw89_acpi_policy_tas *policy_tas;
} u;
};
@@ -70,10 +91,179 @@ struct rtw89_acpi_rtag_result {
u8 ant_gain_table[RTW89_ANT_GAIN_CHAIN_NUM][RTW89_ANT_GAIN_SUBBAND_NR];
} __packed;
enum rtw89_acpi_sar_cid {
RTW89_ACPI_SAR_CID_HP = 0x5048,
RTW89_ACPI_SAR_CID_RT = 0x5452,
};
enum rtw89_acpi_sar_rev {
RTW89_ACPI_SAR_REV_LEGACY = 1,
RTW89_ACPI_SAR_REV_HAS_6GHZ = 2,
};
#define RTW89_ACPI_SAR_ANT_NR_STD 4
#define RTW89_ACPI_SAR_ANT_NR_SML 2
#define RTW89_ACPI_METHOD_STATIC_SAR "WRDS"
#define RTW89_ACPI_METHOD_DYNAMIC_SAR "RWRD"
#define RTW89_ACPI_METHOD_DYNAMIC_SAR_INDICATOR "RWSI"
#define RTW89_ACPI_METHOD_GEO_SAR "RWGS"
struct rtw89_acpi_sar_std_legacy {
u8 v[RTW89_ACPI_SAR_ANT_NR_STD][RTW89_ACPI_SAR_SUBBAND_NR_LEGACY];
} __packed;
struct rtw89_acpi_sar_std_has_6ghz {
u8 v[RTW89_ACPI_SAR_ANT_NR_STD][RTW89_ACPI_SAR_SUBBAND_NR_HAS_6GHZ];
} __packed;
struct rtw89_acpi_sar_sml_legacy {
u8 v[RTW89_ACPI_SAR_ANT_NR_SML][RTW89_ACPI_SAR_SUBBAND_NR_LEGACY];
} __packed;
struct rtw89_acpi_sar_sml_has_6ghz {
u8 v[RTW89_ACPI_SAR_ANT_NR_SML][RTW89_ACPI_SAR_SUBBAND_NR_HAS_6GHZ];
} __packed;
struct rtw89_acpi_static_sar_hdr {
__le16 cid;
u8 rev;
u8 content[];
} __packed;
struct rtw89_acpi_dynamic_sar_hdr {
__le16 cid;
u8 rev;
u8 cnt;
u8 content[];
} __packed;
struct rtw89_acpi_sar_identifier {
enum rtw89_acpi_sar_cid cid;
enum rtw89_acpi_sar_rev rev;
u8 size;
};
/* for rtw89_acpi_sar_identifier::size */
#define RTW89_ACPI_SAR_SIZE_MAX U8_MAX
#define RTW89_ACPI_SAR_SIZE_OF(type) \
(BUILD_BUG_ON_ZERO(sizeof(struct rtw89_acpi_sar_ ## type) > \
RTW89_ACPI_SAR_SIZE_MAX) + \
sizeof(struct rtw89_acpi_sar_ ## type))
struct rtw89_acpi_sar_recognition {
struct rtw89_acpi_sar_identifier id;
const struct rtw89_acpi_geo_sar_handler *geo;
u8 (*rfpath_to_antidx)(enum rtw89_rf_path rfpath);
s16 (*normalize)(u8 v);
void (*load)(struct rtw89_dev *rtwdev,
const struct rtw89_acpi_sar_recognition *rec,
const void *content,
struct rtw89_sar_entry_from_acpi *ent);
};
struct rtw89_acpi_geo_sar_hp_val {
u8 max;
s8 delta[RTW89_ACPI_SAR_ANT_NR_STD];
} __packed;
struct rtw89_acpi_geo_sar_hp_legacy_entry {
struct rtw89_acpi_geo_sar_hp_val val_2ghz;
struct rtw89_acpi_geo_sar_hp_val val_5ghz;
} __packed;
struct rtw89_acpi_geo_sar_hp_has_6ghz_entry {
struct rtw89_acpi_geo_sar_hp_val val_2ghz;
struct rtw89_acpi_geo_sar_hp_val val_5ghz;
struct rtw89_acpi_geo_sar_hp_val val_6ghz;
} __packed;
enum rtw89_acpi_geo_sar_regd_hp {
RTW89_ACPI_GEO_SAR_REGD_HP_FCC = 0,
RTW89_ACPI_GEO_SAR_REGD_HP_ETSI = 1,
RTW89_ACPI_GEO_SAR_REGD_HP_WW = 2,
RTW89_ACPI_GEO_SAR_REGD_NR_HP,
};
struct rtw89_acpi_geo_sar_hp_legacy {
struct rtw89_acpi_geo_sar_hp_legacy_entry
entries[RTW89_ACPI_GEO_SAR_REGD_NR_HP];
} __packed;
struct rtw89_acpi_geo_sar_hp_has_6ghz {
struct rtw89_acpi_geo_sar_hp_has_6ghz_entry
entries[RTW89_ACPI_GEO_SAR_REGD_NR_HP];
} __packed;
struct rtw89_acpi_geo_sar_rt_val {
u8 max;
s8 delta;
} __packed;
struct rtw89_acpi_geo_sar_rt_legacy_entry {
struct rtw89_acpi_geo_sar_rt_val val_2ghz;
struct rtw89_acpi_geo_sar_rt_val val_5ghz;
} __packed;
struct rtw89_acpi_geo_sar_rt_has_6ghz_entry {
struct rtw89_acpi_geo_sar_rt_val val_2ghz;
struct rtw89_acpi_geo_sar_rt_val val_5ghz;
struct rtw89_acpi_geo_sar_rt_val val_6ghz;
} __packed;
enum rtw89_acpi_geo_sar_regd_rt {
RTW89_ACPI_GEO_SAR_REGD_RT_FCC = 0,
RTW89_ACPI_GEO_SAR_REGD_RT_ETSI = 1,
RTW89_ACPI_GEO_SAR_REGD_RT_MKK = 2,
RTW89_ACPI_GEO_SAR_REGD_RT_IC = 3,
RTW89_ACPI_GEO_SAR_REGD_RT_KCC = 4,
RTW89_ACPI_GEO_SAR_REGD_RT_WW = 5,
RTW89_ACPI_GEO_SAR_REGD_NR_RT,
};
struct rtw89_acpi_geo_sar_rt_legacy {
struct rtw89_acpi_geo_sar_rt_legacy_entry
entries[RTW89_ACPI_GEO_SAR_REGD_NR_RT];
} __packed;
struct rtw89_acpi_geo_sar_rt_has_6ghz {
struct rtw89_acpi_geo_sar_rt_has_6ghz_entry
entries[RTW89_ACPI_GEO_SAR_REGD_NR_RT];
} __packed;
struct rtw89_acpi_geo_sar_handler {
u8 data_size;
void (*load)(struct rtw89_dev *rtwdev,
const void *content,
enum rtw89_regulation_type regd,
struct rtw89_sar_entry_from_acpi *ent);
};
/* for rtw89_acpi_geo_sar_handler::data_size */
#define RTW89_ACPI_GEO_SAR_SIZE_MAX U8_MAX
#define RTW89_ACPI_GEO_SAR_SIZE_OF(type) \
(BUILD_BUG_ON_ZERO(sizeof(struct rtw89_acpi_geo_sar_ ## type) > \
RTW89_ACPI_GEO_SAR_SIZE_MAX) + \
sizeof(struct rtw89_acpi_geo_sar_ ## type))
enum rtw89_acpi_sar_subband rtw89_acpi_sar_get_subband(struct rtw89_dev *rtwdev,
u32 center_freq);
enum rtw89_band rtw89_acpi_sar_subband_to_band(struct rtw89_dev *rtwdev,
enum rtw89_acpi_sar_subband subband);
int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
enum rtw89_acpi_dsm_func func,
struct rtw89_acpi_dsm_result *res);
int rtw89_acpi_evaluate_rtag(struct rtw89_dev *rtwdev,
struct rtw89_acpi_rtag_result *res);
int rtw89_acpi_evaluate_sar(struct rtw89_dev *rtwdev,
struct rtw89_sar_cfg_acpi *cfg);
int rtw89_acpi_evaluate_dynamic_sar_indicator(struct rtw89_dev *rtwdev,
struct rtw89_sar_cfg_acpi *cfg,
bool *changed);
#endif

View File

@@ -6,6 +6,7 @@
#include "debug.h"
#include "fw.h"
#include "mac.h"
#include "ps.h"
static struct sk_buff *
rtw89_cam_get_sec_key_cmd(struct rtw89_dev *rtwdev,
@@ -469,11 +470,17 @@ int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev,
bool ext_key = false;
int ret;
if (ieee80211_vif_is_mld(vif) && !chip->hw_mlo_bmc_crypto &&
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return -EOPNOTSUPP;
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
rtw89_leave_ips_by_hwflags(rtwdev);
hw_key_type = RTW89_SEC_KEY_TYPE_WEP40;
break;
case WLAN_CIPHER_SUITE_WEP104:
rtw89_leave_ips_by_hwflags(rtwdev);
hw_key_type = RTW89_SEC_KEY_TYPE_WEP104;
break;
case WLAN_CIPHER_SUITE_TKIP:

View File

@@ -189,9 +189,10 @@ void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
}
void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
enum rtw89_chanctx_idx idx,
struct rtw89_vif_link *rtwvif_link,
const struct cfg80211_chan_def *chandef)
{
enum rtw89_chanctx_idx idx = rtwvif_link->chanctx_idx;
struct rtw89_hal *hal = &rtwdev->hal;
enum rtw89_chanctx_idx cur;
@@ -205,6 +206,7 @@ void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
}
hal->roc_chandef = *chandef;
hal->roc_link_index = rtw89_vif_link_inst_get_index(rtwvif_link);
} else {
cur = atomic_cmpxchg(&hal->roc_chanctx_idx, idx,
RTW89_CHANCTX_IDLE);
@@ -339,11 +341,10 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
roc_idx = atomic_read(&hal->roc_chanctx_idx);
if (roc_idx != RTW89_CHANCTX_IDLE) {
/* ROC is ongoing (given ROC runs on RTW89_ROC_BY_LINK_INDEX).
* If @link_index is the same as RTW89_ROC_BY_LINK_INDEX, get
* the ongoing ROC chanctx.
/* ROC is ongoing (given ROC runs on @hal->roc_link_index).
* If @link_index is the same, get the ongoing ROC chanctx.
*/
if (link_index == RTW89_ROC_BY_LINK_INDEX)
if (link_index == hal->roc_link_index)
chanctx_idx = roc_idx;
}
@@ -358,12 +359,41 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev,
}
EXPORT_SYMBOL(__rtw89_mgnt_chan_get);
static enum rtw89_mlo_dbcc_mode
rtw89_entity_sel_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws)
{
if (rtwdev->chip->chip_gen != RTW89_CHIP_BE)
return MLO_DBCC_NOT_SUPPORT;
switch (active_hws) {
case BIT(0):
return MLO_2_PLUS_0_1RF;
case BIT(1):
return MLO_0_PLUS_2_1RF;
case BIT(0) | BIT(1):
default:
return MLO_1_PLUS_1_1RF;
}
}
static
void rtw89_entity_recalc_mlo_dbcc_mode(struct rtw89_dev *rtwdev, u8 active_hws)
{
enum rtw89_mlo_dbcc_mode mode;
mode = rtw89_entity_sel_mlo_dbcc_mode(rtwdev, active_hws);
rtwdev->mlo_dbcc_mode = mode;
rtw89_debug(rtwdev, RTW89_DBG_STATE, "recalc mlo dbcc mode to %d\n", mode);
}
static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt;
struct rtw89_vif_link *link;
struct rtw89_vif *role;
u8 active_hws = 0;
u8 pos = 0;
int i, j;
@@ -412,10 +442,13 @@ static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev)
continue;
mgnt->chanctx_tbl[pos][i] = link->chanctx_idx;
active_hws |= BIT(i);
}
mgnt->active_roles[pos++] = role;
}
rtw89_entity_recalc_mlo_dbcc_mode(rtwdev, active_hws);
}
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
@@ -557,7 +590,9 @@ static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev,
u64 sync_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf);
u32 remainder;
if (tsf < sync_tsf) {
if (role->is_go) {
sync_tsf = 0;
} else if (tsf < sync_tsf) {
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC get tbtt ofst: tsf might not update yet\n");
sync_tsf = 0;
@@ -691,19 +726,13 @@ static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta)
struct rtw89_vif *target = mcc_role->rtwvif_link->rtwvif;
struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
struct rtw89_vif *rtwvif = rtwsta->rtwvif;
struct rtw89_dev *rtwdev = rtwsta->rtwdev;
struct rtw89_sta_link *rtwsta_link;
u8 macid;
if (rtwvif != target)
return;
rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
if (unlikely(!rtwsta_link)) {
rtw89_err(rtwdev, "mcc sta macid: find no link on HW-0\n");
return;
}
rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwsta_link->mac_id);
macid = rtw89_sta_get_main_macid(rtwsta);
rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, macid);
}
static void rtw89_mcc_fill_role_macid_bitmap(struct rtw89_dev *rtwdev,
@@ -747,9 +776,11 @@ static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev,
int ret;
int i;
if (!mcc_role->is_go && !mcc_role->is_gc)
if (!mcc_role->is_gc)
return;
rtw89_p2p_noa_once_recalc(rtwvif_link);
rcu_read_lock();
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
@@ -785,6 +816,9 @@ static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev,
}
tsf_lmt = (tsf & GENMASK_ULL(63, 32)) | start_time;
if (tsf_lmt < tsf)
tsf_lmt += roundup_u64(tsf - tsf_lmt, interval);
max_toa_us = rtw89_mcc_get_tbtt_ofst(rtwdev, mcc_role, tsf_lmt);
max_dur_us = interval - duration;
max_tob_us = max_dur_us - max_toa_us;
@@ -929,6 +963,15 @@ static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev)
return 0;
}
static bool rtw89_mcc_can_courtesy(const struct rtw89_mcc_role *provider,
const struct rtw89_mcc_role *receiver)
{
if (provider->is_go || receiver->is_gc)
return false;
return true;
}
static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev,
const struct rtw89_mcc_pattern *new)
{
@@ -937,37 +980,44 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev,
struct rtw89_mcc_role *aux = &mcc->role_aux;
struct rtw89_mcc_config *config = &mcc->config;
struct rtw89_mcc_pattern *pattern = &config->pattern;
struct rtw89_mcc_courtesy_cfg *crtz;
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC assign pattern: ref {%d | %d}, aux {%d | %d}\n",
new->tob_ref, new->toa_ref, new->tob_aux, new->toa_aux);
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC pattern plan: %d\n", new->plan);
*pattern = *new;
memset(&pattern->courtesy, 0, sizeof(pattern->courtesy));
if (pattern->tob_aux <= 0 || pattern->toa_aux <= 0) {
pattern->courtesy.macid_tgt = aux->rtwvif_link->mac_id;
pattern->courtesy.macid_src = ref->rtwvif_link->mac_id;
pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
pattern->courtesy.enable = true;
} else if (pattern->tob_ref <= 0 || pattern->toa_ref <= 0) {
pattern->courtesy.macid_tgt = ref->rtwvif_link->mac_id;
pattern->courtesy.macid_src = aux->rtwvif_link->mac_id;
pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
pattern->courtesy.enable = true;
if (RTW89_MCC_REQ_COURTESY(pattern, aux) && rtw89_mcc_can_courtesy(ref, aux)) {
crtz = &pattern->courtesy.ref;
ref->crtz = crtz;
crtz->macid_tgt = aux->rtwvif_link->mac_id;
crtz->slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC courtesy ref: tgt %d, slot %d\n",
crtz->macid_tgt, crtz->slot_num);
} else {
ref->crtz = NULL;
}
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC pattern flags: plan %d, courtesy_en %d\n",
pattern->plan, pattern->courtesy.enable);
if (RTW89_MCC_REQ_COURTESY(pattern, ref) && rtw89_mcc_can_courtesy(aux, ref)) {
crtz = &pattern->courtesy.aux;
aux->crtz = crtz;
if (!pattern->courtesy.enable)
return;
crtz->macid_tgt = ref->rtwvif_link->mac_id;
crtz->slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC pattern courtesy: tgt %d, src %d, slot %d\n",
pattern->courtesy.macid_tgt, pattern->courtesy.macid_src,
pattern->courtesy.slot_num);
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC courtesy aux: tgt %d, slot %d\n",
crtz->macid_tgt, crtz->slot_num);
} else {
aux->crtz = NULL;
}
}
/* The follow-up roughly shows the relationship between the parameters
@@ -992,6 +1042,7 @@ static void __rtw89_mcc_calc_pattern_loose(struct rtw89_dev *rtwdev,
struct rtw89_mcc_role *ref = &mcc->role_ref;
struct rtw89_mcc_role *aux = &mcc->role_aux;
struct rtw89_mcc_config *config = &mcc->config;
u16 mcc_intvl = config->mcc_interval;
u16 bcn_ofst = config->beacon_offset;
u16 bt_dur_in_mid = 0;
u16 max_bcn_ofst;
@@ -1025,7 +1076,7 @@ static void __rtw89_mcc_calc_pattern_loose(struct rtw89_dev *rtwdev,
res = bcn_ofst - bt_dur_in_mid;
upper = min_t(s16, ref->duration, res);
lower = 0;
lower = max_t(s16, 0, ref->duration - (mcc_intvl - bcn_ofst));
if (ref->limit.enable) {
upper = min_t(s16, upper, ref->limit.max_toa);
@@ -1136,6 +1187,107 @@ static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev,
return 0;
}
static void __rtw89_mcc_fill_ptrn_anchor_ref(struct rtw89_dev *rtwdev,
struct rtw89_mcc_pattern *ptrn,
bool small_bcn_ofst)
{
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_role *ref = &mcc->role_ref;
struct rtw89_mcc_role *aux = &mcc->role_aux;
struct rtw89_mcc_config *config = &mcc->config;
u16 bcn_ofst = config->beacon_offset;
u16 ref_tob;
u16 ref_toa;
if (ref->limit.enable) {
ref_tob = ref->limit.max_tob;
ref_toa = ref->limit.max_toa;
} else {
ref_tob = ref->duration / 2;
ref_toa = ref->duration / 2;
}
if (small_bcn_ofst) {
ptrn->toa_ref = ref_toa;
ptrn->tob_ref = ref->duration - ptrn->toa_ref;
} else {
ptrn->tob_ref = ref_tob;
ptrn->toa_ref = ref->duration - ptrn->tob_ref;
}
ptrn->tob_aux = bcn_ofst - ptrn->toa_ref;
ptrn->toa_aux = aux->duration - ptrn->tob_aux;
}
static void __rtw89_mcc_fill_ptrn_anchor_aux(struct rtw89_dev *rtwdev,
struct rtw89_mcc_pattern *ptrn,
bool small_bcn_ofst)
{
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_role *ref = &mcc->role_ref;
struct rtw89_mcc_role *aux = &mcc->role_aux;
struct rtw89_mcc_config *config = &mcc->config;
u16 bcn_ofst = config->beacon_offset;
u16 aux_tob;
u16 aux_toa;
if (aux->limit.enable) {
aux_tob = aux->limit.max_tob;
aux_toa = aux->limit.max_toa;
} else {
aux_tob = aux->duration / 2;
aux_toa = aux->duration / 2;
}
if (small_bcn_ofst) {
ptrn->tob_aux = aux_tob;
ptrn->toa_aux = aux->duration - ptrn->tob_aux;
} else {
ptrn->toa_aux = aux_toa;
ptrn->tob_aux = aux->duration - ptrn->toa_aux;
}
ptrn->toa_ref = bcn_ofst - ptrn->tob_aux;
ptrn->tob_ref = ref->duration - ptrn->toa_ref;
}
static int __rtw89_mcc_calc_pattern_anchor(struct rtw89_dev *rtwdev,
struct rtw89_mcc_pattern *ptrn,
bool hdl_bt)
{
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_role *ref = &mcc->role_ref;
struct rtw89_mcc_role *aux = &mcc->role_aux;
struct rtw89_mcc_config *config = &mcc->config;
u16 mcc_intvl = config->mcc_interval;
u16 bcn_ofst = config->beacon_offset;
bool small_bcn_ofst;
if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_TIME)
small_bcn_ofst = true;
else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_TIME)
small_bcn_ofst = false;
else
return -EPERM;
*ptrn = (typeof(*ptrn)){
.plan = hdl_bt ? RTW89_MCC_PLAN_TAIL_BT : RTW89_MCC_PLAN_NO_BT,
};
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC calc ptrn_ac: plan %d, bcn_ofst %d\n",
ptrn->plan, bcn_ofst);
if (ref->is_go || ref->is_gc)
__rtw89_mcc_fill_ptrn_anchor_ref(rtwdev, ptrn, small_bcn_ofst);
else if (aux->is_go || aux->is_gc)
__rtw89_mcc_fill_ptrn_anchor_aux(rtwdev, ptrn, small_bcn_ofst);
else
__rtw89_mcc_fill_ptrn_anchor_ref(rtwdev, ptrn, small_bcn_ofst);
return 0;
}
static int rtw89_mcc_calc_pattern(struct rtw89_dev *rtwdev, bool hdl_bt)
{
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
@@ -1189,6 +1341,10 @@ static int rtw89_mcc_calc_pattern(struct rtw89_dev *rtwdev, bool hdl_bt)
goto done;
}
ret = __rtw89_mcc_calc_pattern_anchor(rtwdev, &ptrn, hdl_bt);
if (!ret)
goto done;
__rtw89_mcc_calc_pattern_loose(rtwdev, &ptrn, hdl_bt);
done:
@@ -1439,88 +1595,41 @@ static bool rtw89_mcc_duration_decision_on_bt(struct rtw89_dev *rtwdev)
return false;
}
static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev,
struct rtw89_mcc_role *tgt,
struct rtw89_mcc_role *src,
bool ref_is_src)
{
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_config *config = &mcc->config;
u16 beacon_offset_us = ieee80211_tu_to_usec(config->beacon_offset);
u32 bcn_intvl_src_us = ieee80211_tu_to_usec(src->beacon_interval);
u32 cur_tbtt_ofst_src;
u32 tsf_ofst_tgt;
u32 remainder;
u64 tbtt_tgt;
u64 tsf_src;
int ret;
ret = rtw89_mac_port_get_tsf(rtwdev, src->rtwvif_link, &tsf_src);
if (ret) {
rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
return;
}
cur_tbtt_ofst_src = rtw89_mcc_get_tbtt_ofst(rtwdev, src, tsf_src);
if (ref_is_src)
tbtt_tgt = tsf_src - cur_tbtt_ofst_src + beacon_offset_us;
else
tbtt_tgt = tsf_src - cur_tbtt_ofst_src +
(bcn_intvl_src_us - beacon_offset_us);
div_u64_rem(tbtt_tgt, bcn_intvl_src_us, &remainder);
tsf_ofst_tgt = bcn_intvl_src_us - remainder;
config->sync.macid_tgt = tgt->rtwvif_link->mac_id;
config->sync.band_tgt = tgt->rtwvif_link->mac_idx;
config->sync.port_tgt = tgt->rtwvif_link->port;
config->sync.macid_src = src->rtwvif_link->mac_id;
config->sync.band_src = src->rtwvif_link->mac_idx;
config->sync.port_src = src->rtwvif_link->port;
config->sync.offset = tsf_ofst_tgt / 1024;
config->sync.enable = true;
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC sync tbtt: tgt %d, src %d, offset %d\n",
config->sync.macid_tgt, config->sync.macid_src,
config->sync.offset);
rtw89_mac_port_tsf_sync(rtwdev, tgt->rtwvif_link, src->rtwvif_link,
config->sync.offset);
}
static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev)
{
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_role *ref = &mcc->role_ref;
struct rtw89_mcc_role *aux = &mcc->role_aux;
struct rtw89_mcc_config *config = &mcc->config;
u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval);
u32 tob_ref_us = ieee80211_tu_to_usec(config->pattern.tob_ref);
struct rtw89_vif_link *rtwvif_link = ref->rtwvif_link;
s32 tob_ref_us = ieee80211_tu_to_usec(config->pattern.tob_ref);
u64 tsf, start_tsf;
u32 cur_tbtt_ofst;
u64 min_time;
u64 tsf_aux;
int ret;
ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf);
if (ret) {
rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
if (rtw89_concurrent_via_mrc(rtwdev))
ret = __mrc_fw_req_tsf(rtwdev, &tsf, &tsf_aux);
else
ret = __mcc_fw_req_tsf(rtwdev, &tsf, &tsf_aux);
if (ret)
return ret;
}
min_time = tsf;
if (ref->is_go)
if (ref->is_go || aux->is_go)
min_time += ieee80211_tu_to_usec(RTW89_MCC_SHORT_TRIGGER_TIME);
else
min_time += ieee80211_tu_to_usec(RTW89_MCC_LONG_TRIGGER_TIME);
cur_tbtt_ofst = rtw89_mcc_get_tbtt_ofst(rtwdev, ref, tsf);
start_tsf = tsf - cur_tbtt_ofst + bcn_intvl_ref_us - tob_ref_us;
while (start_tsf < min_time)
start_tsf += bcn_intvl_ref_us;
if (start_tsf < min_time)
start_tsf += roundup_u64(min_time - start_tsf, bcn_intvl_ref_us);
config->start_tsf = start_tsf;
config->start_tsf_in_aux_domain = tsf_aux + start_tsf - tsf;
return 0;
}
@@ -1537,13 +1646,11 @@ static int rtw89_mcc_fill_config(struct rtw89_dev *rtwdev)
switch (mcc->mode) {
case RTW89_MCC_MODE_GO_STA:
config->beacon_offset = RTW89_MCC_DFLT_BCN_OFST_TIME;
config->beacon_offset = rtw89_mcc_get_bcn_ofst(rtwdev);
if (ref->is_go) {
rtw89_mcc_sync_tbtt(rtwdev, ref, aux, false);
config->mcc_interval = ref->beacon_interval;
rtw89_mcc_set_duration_go_sta(rtwdev, ref, aux);
} else {
rtw89_mcc_sync_tbtt(rtwdev, aux, ref, true);
config->mcc_interval = aux->beacon_interval;
rtw89_mcc_set_duration_go_sta(rtwdev, aux, ref);
}
@@ -1573,10 +1680,8 @@ static int rtw89_mcc_fill_config(struct rtw89_dev *rtwdev)
static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role)
{
const struct rtw89_mcc_courtesy_cfg *crtz = role->crtz;
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_config *config = &mcc->config;
struct rtw89_mcc_pattern *pattern = &config->pattern;
struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;
struct rtw89_mcc_policy *policy = &role->policy;
struct rtw89_fw_mcc_add_req req = {};
const struct rtw89_chan *chan;
@@ -1599,9 +1704,9 @@ static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ro
req.duration = role->duration;
req.btc_in_2g = false;
if (courtesy->enable && courtesy->macid_src == req.macid) {
req.courtesy_target = courtesy->macid_tgt;
req.courtesy_num = courtesy->slot_num;
if (crtz) {
req.courtesy_target = crtz->macid_tgt;
req.courtesy_num = crtz->slot_num;
req.courtesy_en = true;
}
@@ -1781,26 +1886,23 @@ static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev,
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_role *ref = &mcc->role_ref;
struct rtw89_mcc_role *aux = &mcc->role_aux;
struct rtw89_mcc_config *config = &mcc->config;
struct rtw89_mcc_pattern *pattern = &config->pattern;
struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;
struct rtw89_fw_mrc_add_slot_arg *slot_arg_src;
u8 slot_idx_tgt;
if (!courtesy->enable)
return;
if (courtesy->macid_src == ref->rtwvif_link->mac_id) {
if (ref->crtz) {
slot_arg_src = &arg->slots[ref->slot_idx];
slot_idx_tgt = aux->slot_idx;
} else {
slot_arg_src = &arg->slots[aux->slot_idx];
slot_idx_tgt = ref->slot_idx;
slot_arg_src->courtesy_target = aux->slot_idx;
slot_arg_src->courtesy_period = ref->crtz->slot_num;
slot_arg_src->courtesy_en = true;
}
slot_arg_src->courtesy_target = slot_idx_tgt;
slot_arg_src->courtesy_period = courtesy->slot_num;
slot_arg_src->courtesy_en = true;
if (aux->crtz) {
slot_arg_src = &arg->slots[aux->slot_idx];
slot_arg_src->courtesy_target = ref->slot_idx;
slot_arg_src->courtesy_period = aux->crtz->slot_num;
slot_arg_src->courtesy_en = true;
}
}
static int __mrc_fw_start(struct rtw89_dev *rtwdev, bool replace)
@@ -2000,30 +2102,24 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)
struct rtw89_mcc_role *ref = &mcc->role_ref;
struct rtw89_mcc_role *aux = &mcc->role_aux;
struct rtw89_mcc_config *config = &mcc->config;
struct rtw89_mcc_pattern *pattern = &config->pattern;
struct rtw89_mcc_sync *sync = &config->sync;
struct ieee80211_p2p_noa_desc noa_desc = {};
u64 start_time = config->start_tsf;
u32 interval = config->mcc_interval;
struct rtw89_vif_link *rtwvif_go;
u64 start_time;
u32 duration;
if (mcc->mode != RTW89_MCC_MODE_GO_STA)
return;
if (ref->is_go) {
start_time = config->start_tsf;
rtwvif_go = ref->rtwvif_link;
start_time += ieee80211_tu_to_usec(ref->duration);
duration = config->mcc_interval - ref->duration;
} else if (aux->is_go) {
start_time = config->start_tsf_in_aux_domain;
rtwvif_go = aux->rtwvif_link;
start_time += ieee80211_tu_to_usec(pattern->tob_ref) +
ieee80211_tu_to_usec(config->beacon_offset) +
ieee80211_tu_to_usec(pattern->toa_aux);
duration = config->mcc_interval - aux->duration;
/* convert time domain from sta(ref) to GO(aux) */
start_time += ieee80211_tu_to_usec(sync->offset);
} else {
rtw89_debug(rtwdev, RTW89_DBG_CHAN,
"MCC find no GO: skip updating beacon NoA\n");
@@ -2127,6 +2223,12 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
}
struct rtw89_mcc_stop_sel {
struct {
const struct rtw89_vif_link *target;
} hint;
/* selection content */
bool filled;
u8 mac_id;
u8 slot_idx;
};
@@ -2136,6 +2238,7 @@ static void rtw89_mcc_stop_sel_fill(struct rtw89_mcc_stop_sel *sel,
{
sel->mac_id = mcc_role->rtwvif_link->mac_id;
sel->slot_idx = mcc_role->slot_idx;
sel->filled = true;
}
static int rtw89_mcc_stop_sel_iterator(struct rtw89_dev *rtwdev,
@@ -2145,23 +2248,41 @@ static int rtw89_mcc_stop_sel_iterator(struct rtw89_dev *rtwdev,
{
struct rtw89_mcc_stop_sel *sel = data;
if (mcc_role->rtwvif_link == sel->hint.target) {
rtw89_mcc_stop_sel_fill(sel, mcc_role);
return 1; /* break iteration */
}
if (sel->filled)
return 0;
if (!mcc_role->rtwvif_link->chanctx_assigned)
return 0;
rtw89_mcc_stop_sel_fill(sel, mcc_role);
return 1; /* break iteration */
return 0;
}
static void rtw89_mcc_stop(struct rtw89_dev *rtwdev)
static void rtw89_mcc_stop(struct rtw89_dev *rtwdev,
const struct rtw89_chanctx_pause_parm *pause)
{
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_role *ref = &mcc->role_ref;
struct rtw89_mcc_stop_sel sel;
struct rtw89_mcc_stop_sel sel = {
.hint.target = pause ? pause->trigger : NULL,
};
int ret;
if (!pause) {
wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwdev->chanctx_work);
bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES);
}
/* by default, stop at ref */
rtw89_mcc_stop_sel_fill(&sel, ref);
rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_stop_sel_iterator, &sel);
if (!sel.filled)
rtw89_mcc_stop_sel_fill(&sel, ref);
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC stop at <macid %d>\n", sel.mac_id);
@@ -2193,6 +2314,7 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev)
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_config *config = &mcc->config;
struct rtw89_mcc_config old_cfg = *config;
bool courtesy_changed;
bool sync_changed;
int ret;
@@ -2205,8 +2327,15 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev)
if (ret)
return ret;
if (memcmp(&old_cfg.pattern.courtesy, &config->pattern.courtesy,
sizeof(old_cfg.pattern.courtesy)) == 0)
courtesy_changed = false;
else
courtesy_changed = true;
if (old_cfg.pattern.plan != RTW89_MCC_PLAN_NO_BT ||
config->pattern.plan != RTW89_MCC_PLAN_NO_BT) {
config->pattern.plan != RTW89_MCC_PLAN_NO_BT ||
courtesy_changed) {
if (rtw89_concurrent_via_mrc(rtwdev))
ret = __mrc_fw_start(rtwdev, true);
else
@@ -2238,7 +2367,7 @@ static void rtw89_mcc_track(struct rtw89_dev *rtwdev)
struct rtw89_mcc_info *mcc = &rtwdev->mcc;
struct rtw89_mcc_config *config = &mcc->config;
struct rtw89_mcc_pattern *pattern = &config->pattern;
s16 tolerance;
u16 tolerance;
u16 bcn_ofst;
u16 diff;
@@ -2246,18 +2375,25 @@ static void rtw89_mcc_track(struct rtw89_dev *rtwdev)
return;
bcn_ofst = rtw89_mcc_get_bcn_ofst(rtwdev);
if (bcn_ofst == config->beacon_offset)
return;
if (bcn_ofst > config->beacon_offset) {
diff = bcn_ofst - config->beacon_offset;
if (pattern->tob_aux < 0)
tolerance = -pattern->tob_aux;
else
else if (pattern->toa_aux > 0)
tolerance = pattern->toa_aux;
else
return; /* no chance to improve */
} else {
diff = config->beacon_offset - bcn_ofst;
if (pattern->toa_aux < 0)
tolerance = -pattern->toa_aux;
else
else if (pattern->tob_aux > 0)
tolerance = pattern->tob_aux;
else
return; /* no chance to improve */
}
if (diff <= tolerance)
@@ -2504,7 +2640,7 @@ void rtw89_chanctx_track(struct rtw89_dev *rtwdev)
}
void rtw89_chanctx_pause(struct rtw89_dev *rtwdev,
enum rtw89_chanctx_pause_reasons rsn)
const struct rtw89_chanctx_pause_parm *pause_parm)
{
struct rtw89_hal *hal = &rtwdev->hal;
enum rtw89_entity_mode mode;
@@ -2514,12 +2650,12 @@ void rtw89_chanctx_pause(struct rtw89_dev *rtwdev,
if (hal->entity_pause)
return;
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx pause (rsn: %d)\n", rsn);
rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx pause (rsn: %d)\n", pause_parm->rsn);
mode = rtw89_get_entity_mode(rtwdev);
switch (mode) {
case RTW89_ENTITY_MODE_MCC:
rtw89_mcc_stop(rtwdev);
rtw89_mcc_stop(rtwdev, pause_parm);
break;
default:
break;
@@ -2744,7 +2880,7 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
cur = rtw89_get_entity_mode(rtwdev);
switch (cur) {
case RTW89_ENTITY_MODE_MCC:
rtw89_mcc_stop(rtwdev);
rtw89_mcc_stop(rtwdev, NULL);
break;
default:
break;

View File

@@ -31,6 +31,14 @@
#define RTW89_MCC_DFLT_TX_NULL_EARLY 3
#define RTW89_MCC_DFLT_COURTESY_SLOT 3
#define RTW89_MCC_REQ_COURTESY_TIME 5
#define RTW89_MCC_REQ_COURTESY(pattern, role) \
({ \
const struct rtw89_mcc_pattern *p = pattern; \
p->tob_ ## role <= RTW89_MCC_REQ_COURTESY_TIME || \
p->toa_ ## role <= RTW89_MCC_REQ_COURTESY_TIME; \
})
#define NUM_OF_RTW89_MCC_ROLES 2
enum rtw89_chanctx_pause_reasons {
@@ -38,6 +46,11 @@ enum rtw89_chanctx_pause_reasons {
RTW89_CHANCTX_PAUSE_REASON_ROC,
};
struct rtw89_chanctx_pause_parm {
const struct rtw89_vif_link *trigger;
enum rtw89_chanctx_pause_reasons rsn;
};
struct rtw89_chanctx_cb_parm {
int (*cb)(struct rtw89_dev *rtwdev, void *data);
void *data;
@@ -95,7 +108,7 @@ void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
enum rtw89_chanctx_idx idx,
const struct cfg80211_chan_def *chandef);
void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
enum rtw89_chanctx_idx idx,
struct rtw89_vif_link *rtwvif_link,
const struct cfg80211_chan_def *chandef);
void rtw89_entity_init(struct rtw89_dev *rtwdev);
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev);
@@ -105,7 +118,7 @@ void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev,
enum rtw89_chanctx_changes change);
void rtw89_chanctx_track(struct rtw89_dev *rtwdev);
void rtw89_chanctx_pause(struct rtw89_dev *rtwdev,
enum rtw89_chanctx_pause_reasons rsn);
const struct rtw89_chanctx_pause_parm *parm);
void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev,
const struct rtw89_chanctx_cb_parm *cb_parm);

View File

@@ -203,6 +203,23 @@ static const struct ieee80211_iface_combination rtw89_iface_combs[] = {
},
};
static const u8 rtw89_ext_capa_sta[] = {
[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
};
static const struct wiphy_iftype_ext_capab rtw89_iftypes_ext_capa[] = {
{
.iftype = NL80211_IFTYPE_STATION,
.extended_capabilities = rtw89_ext_capa_sta,
.extended_capabilities_mask = rtw89_ext_capa_sta,
.extended_capabilities_len = sizeof(rtw89_ext_capa_sta),
/* relevant only if EHT is supported */
.eml_capabilities = 0,
.mld_capa_and_ops = 0,
},
};
#define RTW89_6GHZ_SPAN_HEAD 6145
#define RTW89_6GHZ_SPAN_IDX(center_freq) \
((((int)(center_freq) - RTW89_6GHZ_SPAN_HEAD) / 5) / 2)
@@ -211,6 +228,8 @@ static const struct ieee80211_iface_combination rtw89_iface_combs[] = {
[RTW89_6GHZ_SPAN_IDX(center_freq)] = { \
.sar_subband_low = RTW89_SAR_6GHZ_ ## subband_l, \
.sar_subband_high = RTW89_SAR_6GHZ_ ## subband_h, \
.acpi_sar_subband_low = RTW89_ACPI_SAR_6GHZ_ ## subband_l, \
.acpi_sar_subband_high = RTW89_ACPI_SAR_6GHZ_ ## subband_h, \
.ant_gain_subband_low = RTW89_ANT_GAIN_6GHZ_ ## subband_l, \
.ant_gain_subband_high = RTW89_ANT_GAIN_6GHZ_ ## subband_h, \
}
@@ -639,9 +658,17 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev,
static u8 rtw89_core_tx_get_mac_id(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req)
{
struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link;
struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link;
if (desc_info->mlo && !desc_info->sw_mld) {
if (rtwsta_link)
return rtw89_sta_get_main_macid(rtwsta_link->rtwsta);
else
return rtw89_vif_get_main_macid(rtwvif_link->rtwvif);
}
if (!rtwsta_link)
return rtwvif_link->mac_id;
@@ -671,7 +698,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
struct sk_buff *skb = tx_req->skb;
u8 qsel, ch_dma;
qsel = desc_info->hiq ? RTW89_TX_QSEL_B0_HI : RTW89_TX_QSEL_B0_MGMT;
qsel = rtw89_core_get_qsel_mgmt(rtwdev, tx_req);
ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
desc_info->qsel = qsel;
@@ -1104,39 +1131,23 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
return 0;
}
int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel)
static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct rtw89_sta_link *rtwsta_link,
struct sk_buff *skb, int *qsel, bool sw_mld)
{
struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
struct rtw89_core_tx_request tx_req = {0};
struct rtw89_sta_link *rtwsta_link = NULL;
struct rtw89_vif_link *rtwvif_link;
struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link);
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct rtw89_core_tx_request tx_req = {};
int ret;
/* By default, driver writes tx via the link on HW-0. And then,
* according to links' status, HW can change tx to another link.
*/
if (rtwsta) {
rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
if (unlikely(!rtwsta_link)) {
rtw89_err(rtwdev, "tx: find no sta link on HW-0\n");
return -ENOLINK;
}
}
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
if (unlikely(!rtwvif_link)) {
rtw89_err(rtwdev, "tx: find no vif link on HW-0\n");
return -ENOLINK;
}
tx_req.skb = skb;
tx_req.vif = vif;
tx_req.sta = sta;
tx_req.rtwvif_link = rtwvif_link;
tx_req.rtwsta_link = rtwsta_link;
tx_req.desc_info.sw_mld = sw_mld;
rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true);
rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true);
@@ -1155,6 +1166,33 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
return 0;
}
int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel)
{
struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
struct rtw89_sta_link *rtwsta_link = NULL;
struct rtw89_vif_link *rtwvif_link;
if (rtwsta) {
rtwsta_link = rtw89_get_designated_link(rtwsta);
if (unlikely(!rtwsta_link)) {
rtw89_err(rtwdev, "tx: find no sta designated link\n");
return -ENOLINK;
}
rtwvif_link = rtwsta_link->rtwvif_link;
} else {
rtwvif_link = rtw89_get_designated_link(rtwvif);
if (unlikely(!rtwvif_link)) {
rtw89_err(rtwdev, "tx: find no vif designated link\n");
return -ENOLINK;
}
}
return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false);
}
static __le32 rtw89_build_txwd_body0(struct rtw89_tx_desc_info *desc_info)
{
u32 dword = FIELD_PREP(RTW89_TXWD_BODY0_WP_OFFSET, desc_info->wp_offset) |
@@ -1382,7 +1420,9 @@ static __le32 rtw89_build_txwd_body2_v2(struct rtw89_tx_desc_info *desc_info)
static __le32 rtw89_build_txwd_body3_v2(struct rtw89_tx_desc_info *desc_info)
{
u32 dword = FIELD_PREP(BE_TXD_BODY3_WIFI_SEQ, desc_info->seq);
u32 dword = FIELD_PREP(BE_TXD_BODY3_WIFI_SEQ, desc_info->seq) |
FIELD_PREP(BE_TXD_BODY3_MLO_FLAG, desc_info->mlo) |
FIELD_PREP(BE_TXD_BODY3_IS_MLD_SW_EN, desc_info->sw_mld);
return cpu_to_le32(dword);
}
@@ -1635,10 +1675,7 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data,
u8 evm_pos = 0;
int i;
/* FIXME: For single link, taking link on HW-0 here is okay. But, when
* enabling multiple active links, we should determine the right link.
*/
rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
rtwsta_link = rtw89_sta_get_link_inst(rtwsta, phy_ppdu->phy_idx);
if (unlikely(!rtwsta_link))
return;
@@ -2058,10 +2095,21 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev,
break;
if (aid == vif->cfg.aid) {
enum nl80211_he_ru_alloc rua = rtw89_he_rua_to_ru_alloc(tf_rua >> 1);
enum nl80211_he_ru_alloc rua;
rtwvif->stats.rx_tf_acc++;
rtwdev->stats.rx_tf_acc++;
/* The following only required for HE trigger frame, but we
* cannot use UL HE-SIG-A2 reserved subfield to identify it
* since some 11ax APs will fill it with all 0s, which will
* be misunderstood as EHT trigger frame.
*/
if (bss_conf->eht_support)
break;
rua = rtw89_he_rua_to_ru_alloc(tf_rua >> 1);
if (tf_bw == IEEE80211_TRIGGER_ULBW_160_80P80MHZ &&
rua <= NL80211_RATE_INFO_HE_RU_ALLOC_106)
rtwvif_link->pwr_diff_en = true;
@@ -2152,8 +2200,10 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat;
struct rtw89_rx_desc_info *desc_info = iter_data->desc_info;
struct sk_buff *skb = iter_data->skb;
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct rtw89_rx_phy_ppdu *phy_ppdu = iter_data->phy_ppdu;
bool is_mld = ieee80211_vif_is_mld(vif);
struct ieee80211_bss_conf *bss_conf;
struct rtw89_vif_link *rtwvif_link;
const u8 *bssid = iter_data->bssid;
@@ -2165,10 +2215,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
rcu_read_lock();
/* FIXME: For single link, taking link on HW-0 here is okay. But, when
* enabling multiple active links, we should determine the right link.
*/
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, desc_info->bb_sel);
if (unlikely(!rtwvif_link))
goto out;
@@ -2184,6 +2231,11 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
if (!ether_addr_equal(bss_conf->bssid, bssid))
goto out;
if (is_mld) {
rx_status->link_valid = true;
rx_status->link_id = rtwvif_link->link_id;
}
if (ieee80211_is_beacon(hdr->frame_control)) {
if (vif->type == NL80211_IFTYPE_STATION &&
!test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) {
@@ -2482,7 +2534,8 @@ static void rtw89_core_rx_process_ppdu_sts(struct rtw89_dev *rtwdev,
.len = skb->len,
.to_self = desc_info->addr1_match,
.rate = desc_info->data_rate,
.mac_id = desc_info->mac_id};
.mac_id = desc_info->mac_id,
.phy_idx = desc_info->bb_sel};
int ret;
if (desc_info->mac_info_valid) {
@@ -2593,6 +2646,7 @@ void rtw89_core_query_rxdesc_v2(struct rtw89_dev *rtwdev,
desc_info->shift = le32_get_bits(rxd_s->dword0, BE_RXD_SHIFT_MASK);
desc_info->long_rxdesc = le32_get_bits(rxd_s->dword0, BE_RXD_LONG_RXD);
desc_info->pkt_type = le32_get_bits(rxd_s->dword0, BE_RXD_RPKT_TYPE_MASK);
desc_info->bb_sel = le32_get_bits(rxd_s->dword0, BE_RXD_BB_SEL);
if (desc_info->pkt_type == RTW89_CORE_RX_TYPE_PPDU_STAT)
desc_info->mac_info_valid = true;
@@ -2665,10 +2719,7 @@ void rtw89_core_stats_sta_rx_status_iter(void *data, struct ieee80211_sta *sta)
struct rtw89_sta_link *rtwsta_link;
u8 mac_id = iter_data->mac_id;
/* FIXME: For single link, taking link on HW-0 here is okay. But, when
* enabling multiple active links, we should determine the right link.
*/
rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
rtwsta_link = rtw89_sta_get_link_inst(rtwsta, desc_info->bb_sel);
if (unlikely(!rtwsta_link))
return;
@@ -3117,9 +3168,9 @@ static bool rtw89_core_txq_agg_wait(struct rtw89_dev *rtwdev,
if (!rtwsta)
return false;
rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
rtwsta_link = rtw89_get_designated_link(rtwsta);
if (unlikely(!rtwsta_link)) {
rtw89_err(rtwdev, "agg wait: find no link on HW-0\n");
rtw89_err(rtwdev, "agg wait: find no designated link\n");
return false;
}
@@ -3284,8 +3335,10 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
{
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
int link_id = ieee80211_vif_is_mld(vif) ? rtwvif_link->link_id : -1;
struct rtw89_sta_link *rtwsta_link;
struct ieee80211_sta *sta;
struct ieee80211_hdr *hdr;
struct rtw89_sta *rtwsta;
struct sk_buff *skb;
int ret, qsel;
@@ -3298,6 +3351,7 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
ret = -EINVAL;
goto out;
}
rtwsta = sta_to_rtwsta(sta);
skb = ieee80211_nullfunc_get(rtwdev->hw, vif, link_id, qos);
if (!skb) {
@@ -3309,7 +3363,13 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
if (ps)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel);
rtwsta_link = rtwsta->links[rtwvif_link->link_id];
if (unlikely(!rtwsta_link)) {
ret = -ENOLINK;
goto out;
}
ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true);
if (ret) {
rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret);
dev_kfree_skb_any(skb);
@@ -3329,6 +3389,9 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_chanctx_pause_parm pause_parm = {
.rsn = RTW89_CHANCTX_PAUSE_REASON_ROC,
};
struct ieee80211_hw *hw = rtwdev->hw;
struct rtw89_roc *roc = &rtwvif->roc;
struct rtw89_vif_link *rtwvif_link;
@@ -3342,14 +3405,16 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_leave_ips_by_hwflags(rtwdev);
rtw89_leave_lps(rtwdev);
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, RTW89_ROC_BY_LINK_INDEX);
rtwvif_link = rtw89_get_designated_link(rtwvif);
if (unlikely(!rtwvif_link)) {
rtw89_err(rtwdev, "roc start: find no link on HW-%u\n",
RTW89_ROC_BY_LINK_INDEX);
rtw89_err(rtwdev, "roc start: find no designated link\n");
return;
}
rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_ROC);
roc->link_id = rtwvif_link->link_id;
pause_parm.trigger = rtwvif_link;
rtw89_chanctx_pause(rtwdev, &pause_parm);
ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, true);
if (ret)
@@ -3369,7 +3434,7 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
}
cfg80211_chandef_create(&roc_chan, &roc->chan, NL80211_CHAN_NO_HT);
rtw89_config_roc_chandef(rtwdev, rtwvif_link->chanctx_idx, &roc_chan);
rtw89_config_roc_chandef(rtwdev, rtwvif_link, &roc_chan);
rtw89_set_channel(rtwdev);
reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx);
@@ -3398,10 +3463,10 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_leave_ips_by_hwflags(rtwdev);
rtw89_leave_lps(rtwdev);
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, RTW89_ROC_BY_LINK_INDEX);
rtwvif_link = rtwvif->links[roc->link_id];
if (unlikely(!rtwvif_link)) {
rtw89_err(rtwdev, "roc end: find no link on HW-%u\n",
RTW89_ROC_BY_LINK_INDEX);
rtw89_err(rtwdev, "roc end: find no link (link id %u)\n",
roc->link_id);
return;
}
@@ -3409,7 +3474,7 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rtwdev->hal.rx_fltr);
roc->state = RTW89_ROC_IDLE;
rtw89_config_roc_chandef(rtwdev, rtwvif_link->chanctx_idx, NULL);
rtw89_config_roc_chandef(rtwdev, rtwvif_link, NULL);
rtw89_chanctx_proceed(rtwdev, NULL);
ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, false);
if (ret)
@@ -3577,6 +3642,98 @@ void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
ewma_tp_init(&stats->rx_ewma_tp);
}
#define RTW89_MLSR_GOTO_2GHZ_THRESHOLD -53
#define RTW89_MLSR_EXIT_2GHZ_THRESHOLD -38
static void rtw89_core_mlsr_link_decision(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif)
{
unsigned int sel_link_id = IEEE80211_MLD_MAX_NUM_LINKS;
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
struct rtw89_vif_link *rtwvif_link;
const struct rtw89_chan *chan;
unsigned long usable_links;
unsigned int link_id;
u8 decided_bands;
u8 rssi;
rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi);
if (unlikely(!rssi))
return;
if (RTW89_RSSI_RAW_TO_DBM(rssi) >= RTW89_MLSR_EXIT_2GHZ_THRESHOLD)
decided_bands = BIT(RTW89_BAND_5G) | BIT(RTW89_BAND_6G);
else if (RTW89_RSSI_RAW_TO_DBM(rssi) <= RTW89_MLSR_GOTO_2GHZ_THRESHOLD)
decided_bands = BIT(RTW89_BAND_2G);
else
return;
usable_links = ieee80211_vif_usable_links(vif);
rtwvif_link = rtw89_get_designated_link(rtwvif);
if (unlikely(!rtwvif_link))
goto select;
chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx);
if (decided_bands & BIT(chan->band_type))
return;
usable_links &= ~BIT(rtwvif_link->link_id);
select:
rcu_read_lock();
for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct ieee80211_bss_conf *link_conf;
struct ieee80211_channel *channel;
enum rtw89_band band;
link_conf = rcu_dereference(vif->link_conf[link_id]);
if (unlikely(!link_conf))
continue;
channel = link_conf->chanreq.oper.chan;
if (unlikely(!channel))
continue;
band = rtw89_nl80211_to_hw_band(channel->band);
if (decided_bands & BIT(band)) {
sel_link_id = link_id;
break;
}
}
rcu_read_unlock();
if (sel_link_id == IEEE80211_MLD_MAX_NUM_LINKS)
return;
rtw89_core_mlsr_switch(rtwdev, rtwvif, sel_link_id);
}
static void rtw89_core_mlo_track(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
struct ieee80211_vif *vif;
struct rtw89_vif *rtwvif;
if (hal->disabled_dm_bitmap & BIT(RTW89_DM_MLO))
return;
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
vif = rtwvif_to_vif(rtwvif);
if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif))
continue;
switch (rtwvif->mlo_mode) {
case RTW89_MLO_MODE_MLSR:
rtw89_core_mlsr_link_decision(rtwdev, rtwvif);
break;
default:
break;
}
}
}
static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work)
{
struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
@@ -3615,9 +3772,10 @@ static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work)
rtw89_phy_antdiv_track(rtwdev);
rtw89_phy_ul_tb_ctrl_track(rtwdev);
rtw89_phy_edcca_track(rtwdev);
rtw89_tas_track(rtwdev);
rtw89_sar_track(rtwdev);
rtw89_chanctx_track(rtwdev);
rtw89_core_rfkill_poll(rtwdev, false);
rtw89_core_mlo_track(rtwdev);
if (rtwdev->lps_enabled && !rtwdev->btc.lps)
rtw89_enter_lps_track(rtwdev);
@@ -3846,6 +4004,9 @@ int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev,
if (vif->type == NL80211_IFTYPE_STATION)
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, false);
if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT)
rtw89_p2p_noa_once_deinit(rtwvif_link);
return 0;
}
@@ -4361,17 +4522,18 @@ static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev,
#define RTW89_SBAND_IFTYPES_NR 2
static void rtw89_init_he_eht_cap(struct rtw89_dev *rtwdev,
enum nl80211_band band,
struct ieee80211_supported_band *sband)
static int rtw89_init_he_eht_cap(struct rtw89_dev *rtwdev,
enum nl80211_band band,
struct ieee80211_supported_band *sband)
{
struct ieee80211_sband_iftype_data *iftype_data;
enum nl80211_iftype iftype;
int idx = 0;
iftype_data = kcalloc(RTW89_SBAND_IFTYPES_NR, sizeof(*iftype_data), GFP_KERNEL);
iftype_data = devm_kcalloc(rtwdev->dev, RTW89_SBAND_IFTYPES_NR,
sizeof(*iftype_data), GFP_KERNEL);
if (!iftype_data)
return;
return -ENOMEM;
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
switch (iftype) {
@@ -4396,77 +4558,75 @@ static void rtw89_init_he_eht_cap(struct rtw89_dev *rtwdev,
}
_ieee80211_set_sband_iftype_data(sband, iftype_data, idx);
return 0;
}
static struct ieee80211_supported_band *
rtw89_core_sband_dup(struct rtw89_dev *rtwdev,
const struct ieee80211_supported_band *sband)
{
struct ieee80211_supported_band *dup;
dup = devm_kmemdup(rtwdev->dev, sband, sizeof(*sband), GFP_KERNEL);
if (!dup)
return NULL;
dup->channels = devm_kmemdup(rtwdev->dev, sband->channels,
sizeof(*sband->channels) * sband->n_channels,
GFP_KERNEL);
if (!dup->channels)
return NULL;
dup->bitrates = devm_kmemdup(rtwdev->dev, sband->bitrates,
sizeof(*sband->bitrates) * sband->n_bitrates,
GFP_KERNEL);
if (!dup->bitrates)
return NULL;
return dup;
}
static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev)
{
struct ieee80211_hw *hw = rtwdev->hw;
struct ieee80211_supported_band *sband_2ghz = NULL, *sband_5ghz = NULL;
struct ieee80211_supported_band *sband_6ghz = NULL;
u32 size = sizeof(struct ieee80211_supported_band);
struct ieee80211_supported_band *sband;
u8 support_bands = rtwdev->chip->support_bands;
int ret;
if (support_bands & BIT(NL80211_BAND_2GHZ)) {
sband_2ghz = kmemdup(&rtw89_sband_2ghz, size, GFP_KERNEL);
if (!sband_2ghz)
goto err;
rtw89_init_ht_cap(rtwdev, &sband_2ghz->ht_cap);
rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_2GHZ, sband_2ghz);
hw->wiphy->bands[NL80211_BAND_2GHZ] = sband_2ghz;
sband = rtw89_core_sband_dup(rtwdev, &rtw89_sband_2ghz);
if (!sband)
return -ENOMEM;
rtw89_init_ht_cap(rtwdev, &sband->ht_cap);
ret = rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_2GHZ, sband);
if (ret)
return ret;
hw->wiphy->bands[NL80211_BAND_2GHZ] = sband;
}
if (support_bands & BIT(NL80211_BAND_5GHZ)) {
sband_5ghz = kmemdup(&rtw89_sband_5ghz, size, GFP_KERNEL);
if (!sband_5ghz)
goto err;
rtw89_init_ht_cap(rtwdev, &sband_5ghz->ht_cap);
rtw89_init_vht_cap(rtwdev, &sband_5ghz->vht_cap);
rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_5GHZ, sband_5ghz);
hw->wiphy->bands[NL80211_BAND_5GHZ] = sband_5ghz;
sband = rtw89_core_sband_dup(rtwdev, &rtw89_sband_5ghz);
if (!sband)
return -ENOMEM;
rtw89_init_ht_cap(rtwdev, &sband->ht_cap);
rtw89_init_vht_cap(rtwdev, &sband->vht_cap);
ret = rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_5GHZ, sband);
if (ret)
return ret;
hw->wiphy->bands[NL80211_BAND_5GHZ] = sband;
}
if (support_bands & BIT(NL80211_BAND_6GHZ)) {
sband_6ghz = kmemdup(&rtw89_sband_6ghz, size, GFP_KERNEL);
if (!sband_6ghz)
goto err;
rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_6GHZ, sband_6ghz);
hw->wiphy->bands[NL80211_BAND_6GHZ] = sband_6ghz;
sband = rtw89_core_sband_dup(rtwdev, &rtw89_sband_6ghz);
if (!sband)
return -ENOMEM;
ret = rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_6GHZ, sband);
if (ret)
return ret;
hw->wiphy->bands[NL80211_BAND_6GHZ] = sband;
}
return 0;
err:
hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL;
hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL;
hw->wiphy->bands[NL80211_BAND_6GHZ] = NULL;
if (sband_2ghz)
kfree((__force void *)sband_2ghz->iftype_data);
if (sband_5ghz)
kfree((__force void *)sband_5ghz->iftype_data);
if (sband_6ghz)
kfree((__force void *)sband_6ghz->iftype_data);
kfree(sband_2ghz);
kfree(sband_5ghz);
kfree(sband_6ghz);
return -ENOMEM;
}
static void rtw89_core_clr_supported_band(struct rtw89_dev *rtwdev)
{
struct ieee80211_hw *hw = rtwdev->hw;
if (hw->wiphy->bands[NL80211_BAND_2GHZ])
kfree((__force void *)hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data);
if (hw->wiphy->bands[NL80211_BAND_5GHZ])
kfree((__force void *)hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data);
if (hw->wiphy->bands[NL80211_BAND_6GHZ])
kfree((__force void *)hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data);
kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]);
kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]);
kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]);
hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL;
hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL;
hw->wiphy->bands[NL80211_BAND_6GHZ] = NULL;
}
static void rtw89_core_ppdu_sts_init(struct rtw89_dev *rtwdev)
@@ -4774,6 +4934,7 @@ struct rtw89_vif_link *rtw89_vif_set_link(struct rtw89_vif *rtwvif,
set_bit(index, rtwvif->links_inst_map);
rtwvif->links[link_id] = rtwvif_link;
list_add_tail(&rtwvif_link->dlink_schd, &rtwvif->dlink_pool);
return rtwvif_link;
err:
@@ -4794,6 +4955,7 @@ void rtw89_vif_unset_link(struct rtw89_vif *rtwvif, unsigned int link_id)
index = rtw89_vif_link_inst_get_index(link);
clear_bit(index, rtwvif->links_inst_map);
*container = NULL;
list_del(&link->dlink_schd);
}
struct rtw89_sta_link *rtw89_sta_set_link(struct rtw89_sta *rtwsta,
@@ -4824,6 +4986,7 @@ struct rtw89_sta_link *rtw89_sta_set_link(struct rtw89_sta *rtwsta,
set_bit(index, rtwsta->links_inst_map);
rtwsta->links[link_id] = rtwsta_link;
list_add_tail(&rtwsta_link->dlink_schd, &rtwsta->dlink_pool);
return rtwsta_link;
err:
@@ -4844,6 +5007,7 @@ void rtw89_sta_unset_link(struct rtw89_sta *rtwsta, unsigned int link_id)
index = rtw89_sta_link_inst_get_index(link);
clear_bit(index, rtwsta->links_inst_map);
*container = NULL;
list_del(&link->dlink_schd);
}
int rtw89_core_init(struct rtw89_dev *rtwdev)
@@ -4860,6 +5024,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
continue;
INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]);
}
INIT_LIST_HEAD(&rtwdev->scan_info.chan_list);
INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work);
INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work);
INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work);
@@ -4880,6 +5045,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
rtwdev->total_sta_assoc = 0;
rtw89_init_wait(&rtwdev->mcc.wait);
rtw89_init_wait(&rtwdev->mlo.wait);
rtw89_init_wait(&rtwdev->mac.fw_ofld_wait);
rtw89_init_wait(&rtwdev->wow.wait);
rtw89_init_wait(&rtwdev->mac.ps_wait);
@@ -4901,7 +5067,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) {
rtwdev->dbcc_en = true;
rtwdev->mac.qta_mode = RTW89_QTA_DBCC;
rtwdev->mlo_dbcc_mode = MLO_2_PLUS_0_1RF;
rtwdev->mlo_dbcc_mode = MLO_1_PLUS_1_1RF;
}
rtwdev->bbs[RTW89_PHY_0].phy_idx = RTW89_PHY_0;
@@ -4919,7 +5085,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
rtw89_ser_init(rtwdev);
rtw89_entity_init(rtwdev);
rtw89_tas_init(rtwdev);
rtw89_sar_init(rtwdev);
rtw89_phy_ant_gain_init(rtwdev);
return 0;
@@ -4945,9 +5111,6 @@ void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwv
struct rtw89_bb_ctx *bb = rtw89_get_bb_ctx(rtwdev, rtwvif_link->phy_idx);
rtwdev->scanning = true;
rtw89_leave_lps(rtwdev);
if (hw_scan)
rtw89_leave_ips_by_hwflags(rtwdev);
ether_addr_copy(rtwvif_link->mac_addr, mac_addr);
rtw89_btc_ntfy_scan_start(rtwdev, rtwvif_link->phy_idx, chan->band_type);
@@ -5062,6 +5225,76 @@ static void rtw89_core_setup_rfe_parms(struct rtw89_dev *rtwdev)
rtw89_load_txpwr_table(rtwdev, rtwdev->rfe_parms->byr_tbl);
}
int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
unsigned int link_id)
{
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
u16 usable_links = ieee80211_vif_usable_links(vif);
u16 active_links = vif->active_links;
struct rtw89_vif_link *target, *cur;
int ret;
lockdep_assert_wiphy(rtwdev->hw->wiphy);
if (unlikely(!ieee80211_vif_is_mld(vif)))
return -EOPNOTSUPP;
if (unlikely(!(usable_links & BIT(link_id)))) {
rtw89_warn(rtwdev, "%s: link id %u is not usable\n", __func__,
link_id);
return -ENOLINK;
}
if (active_links == BIT(link_id))
return 0;
rtw89_debug(rtwdev, RTW89_DBG_STATE, "%s: switch to link id %u MLSR\n",
__func__, link_id);
rtw89_leave_lps(rtwdev);
ieee80211_stop_queues(rtwdev->hw);
flush_work(&rtwdev->txq_work);
cur = rtw89_get_designated_link(rtwvif);
ret = ieee80211_set_active_links(vif, active_links | BIT(link_id));
if (ret) {
rtw89_err(rtwdev, "%s: failed to activate link id %u\n",
__func__, link_id);
goto wake_queue;
}
target = rtwvif->links[link_id];
if (unlikely(!target)) {
rtw89_err(rtwdev, "%s: failed to confirm link id %u\n",
__func__, link_id);
ieee80211_set_active_links(vif, active_links);
ret = -EFAULT;
goto wake_queue;
}
if (likely(cur))
rtw89_fw_h2c_mlo_link_cfg(rtwdev, cur, false);
rtw89_fw_h2c_mlo_link_cfg(rtwdev, target, true);
ret = ieee80211_set_active_links(vif, BIT(link_id));
if (ret)
rtw89_err(rtwdev, "%s: failed to inactivate links 0x%x\n",
__func__, active_links);
rtw89_chip_rfk_channel(rtwdev, target);
rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR;
wake_queue:
ieee80211_wake_queues(rtwdev->hw);
return ret;
}
static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
@@ -5305,8 +5538,11 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
if (chip->chip_gen == RTW89_CHIP_BE)
hw->wiphy->flags |= WIPHY_FLAG_DISABLE_WEXT;
if (rtwdev->support_mlo)
if (rtwdev->support_mlo) {
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO;
hw->wiphy->iftype_ext_capab = rtw89_iftypes_ext_capa;
hw->wiphy->num_iftype_ext_capab = ARRAY_SIZE(rtw89_iftypes_ext_capa);
}
hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
@@ -5337,7 +5573,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
ret = rtw89_regd_setup(rtwdev);
if (ret) {
rtw89_err(rtwdev, "failed to set up regd\n");
goto err_free_supported_band;
return ret;
}
hw->wiphy->sar_capa = &rtw89_sar_capa;
@@ -5345,7 +5581,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
ret = ieee80211_register_hw(hw);
if (ret) {
rtw89_err(rtwdev, "failed to register hw\n");
goto err_free_supported_band;
return ret;
}
ret = rtw89_regd_init_hint(rtwdev);
@@ -5360,8 +5596,6 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
err_unregister_hw:
ieee80211_unregister_hw(hw);
err_free_supported_band:
rtw89_core_clr_supported_band(rtwdev);
return ret;
}
@@ -5372,7 +5606,6 @@ static void rtw89_core_unregister_hw(struct rtw89_dev *rtwdev)
rtw89_rfkill_polling_deinit(rtwdev);
ieee80211_unregister_hw(hw);
rtw89_core_clr_supported_band(rtwdev);
}
int rtw89_core_register(struct rtw89_dev *rtwdev)
@@ -5440,13 +5673,13 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
if (!hw)
goto err;
/* TODO: When driver MLO arch. is done, determine whether to support MLO
* according to the following conditions.
* 1. run with chanctx_ops
* 2. chip->support_link_num != 0
* 3. FW feature supports AP_LINK_PS
/* Currently, our AP_LINK_PS handling only works for non-MLD softap
* or MLD-single-link softap. If RTW89_MLD_NON_STA_LINK_NUM enlarges,
* please tweak entire AP_LINKS_PS handling before supporting MLO.
*/
support_mlo = false;
support_mlo = !no_chanctx && chip->support_link_num &&
RTW89_CHK_FW_FEATURE(NOTIFY_AP_INFO, &early_fw) &&
RTW89_MLD_NON_STA_LINK_NUM == 1;
hw->wiphy->iface_combinations = rtw89_iface_combs;

View File

@@ -798,6 +798,7 @@ struct rtw89_rx_phy_ppdu {
u8 rssi[RF_PATH_MAX];
u8 mac_id;
u8 chan_idx;
u8 phy_idx;
u8 ie;
u16 rate;
u8 rpl_avg;
@@ -1174,6 +1175,7 @@ struct rtw89_tx_desc_info {
bool ldpc;
bool upd_wlan_hdr;
bool mlo;
bool sw_mld;
};
struct rtw89_core_tx_request {
@@ -3379,6 +3381,7 @@ struct rtw89_sec_cam_entry {
struct rtw89_sta_link {
struct rtw89_sta *rtwsta;
struct list_head dlink_schd;
unsigned int link_id;
u8 mac_id;
@@ -3445,14 +3448,13 @@ enum rtw89_roc_state {
RTW89_ROC_MGMT,
};
#define RTW89_ROC_BY_LINK_INDEX 0
struct rtw89_roc {
struct ieee80211_channel chan;
struct wiphy_delayed_work roc_work;
enum ieee80211_roc_type type;
enum rtw89_roc_state state;
int duration;
unsigned int link_id;
};
#define RTW89_P2P_MAX_NOA_NUM 2
@@ -3483,8 +3485,17 @@ struct rtw89_p2p_noa_setter {
u8 noa_index;
};
struct rtw89_ps_noa_once_handler {
bool in_duration;
u64 tsf_begin;
u64 tsf_end;
struct wiphy_delayed_work set_work;
struct wiphy_delayed_work clr_work;
};
struct rtw89_vif_link {
struct rtw89_vif *rtwvif;
struct list_head dlink_schd;
unsigned int link_id;
bool chanctx_assigned; /* only valid when running with chanctx_ops */
@@ -3507,6 +3518,7 @@ struct rtw89_vif_link {
u8 hit_rule;
u8 last_noa_nr;
u64 sync_bcn_tsf;
bool rand_tsf_done;
bool trigger;
bool lsig_txop;
u8 tgt_ind;
@@ -3527,6 +3539,7 @@ struct rtw89_vif_link {
struct rtw89_phy_rate_pattern rate_pattern;
struct list_head general_pkt_list;
struct rtw89_p2p_noa_setter p2p_noa;
struct rtw89_ps_noa_once_handler noa_once;
};
enum rtw89_lv1_rcvy_step {
@@ -3986,7 +3999,11 @@ struct rtw89_rfe_parms {
struct rtw89_txpwr_rule_2ghz rule_2ghz;
struct rtw89_txpwr_rule_5ghz rule_5ghz;
struct rtw89_txpwr_rule_6ghz rule_6ghz;
struct rtw89_txpwr_rule_2ghz rule_da_2ghz;
struct rtw89_txpwr_rule_5ghz rule_da_5ghz;
struct rtw89_txpwr_rule_6ghz rule_da_6ghz;
struct rtw89_tx_shape tx_shape;
bool has_da;
};
struct rtw89_rfe_parms_conf {
@@ -4081,9 +4098,15 @@ struct rtw89_rfe_data {
struct rtw89_txpwr_lmt_2ghz_data lmt_2ghz;
struct rtw89_txpwr_lmt_5ghz_data lmt_5ghz;
struct rtw89_txpwr_lmt_6ghz_data lmt_6ghz;
struct rtw89_txpwr_lmt_2ghz_data da_lmt_2ghz;
struct rtw89_txpwr_lmt_5ghz_data da_lmt_5ghz;
struct rtw89_txpwr_lmt_6ghz_data da_lmt_6ghz;
struct rtw89_txpwr_lmt_ru_2ghz_data lmt_ru_2ghz;
struct rtw89_txpwr_lmt_ru_5ghz_data lmt_ru_5ghz;
struct rtw89_txpwr_lmt_ru_6ghz_data lmt_ru_6ghz;
struct rtw89_txpwr_lmt_ru_2ghz_data da_lmt_ru_2ghz;
struct rtw89_txpwr_lmt_ru_5ghz_data da_lmt_ru_5ghz;
struct rtw89_txpwr_lmt_ru_6ghz_data da_lmt_ru_6ghz;
struct rtw89_tx_shape_lmt_data tx_shape_lmt;
struct rtw89_tx_shape_lmt_ru_data tx_shape_lmt_ru;
struct rtw89_rfe_parms rfe_parms;
@@ -4284,12 +4307,14 @@ struct rtw89_chip_info {
bool support_rnr;
bool support_ant_gain;
bool support_tas;
bool support_sar_by_ant;
bool ul_tb_waveform_ctrl;
bool ul_tb_pwr_diff;
bool rx_freq_frome_ie;
bool hw_sec_hdr;
bool hw_mgmt_tx_encrypt;
bool hw_tkip_crypto;
bool hw_mlo_bmc_crypto;
u8 rf_path_num;
u8 tx_nss;
u8 rx_nss;
@@ -4494,6 +4519,7 @@ enum rtw89_fw_feature {
RTW89_FW_FEATURE_LPS_CH_INFO,
RTW89_FW_FEATURE_NO_PHYCAP_P1,
RTW89_FW_FEATURE_NO_POWER_DIFFERENCE,
RTW89_FW_FEATURE_BEACON_LOSS_COUNT_V1,
};
struct rtw89_fw_suit {
@@ -4606,6 +4632,7 @@ struct rtw89_cam_info {
enum rtw89_sar_sources {
RTW89_SAR_SOURCE_NONE,
RTW89_SAR_SOURCE_COMMON,
RTW89_SAR_SOURCE_ACPI,
RTW89_SAR_SOURCE_NR,
};
@@ -4630,8 +4657,62 @@ struct rtw89_sar_cfg_common {
s32 cfg[RTW89_SAR_SUBBAND_NR];
};
enum rtw89_acpi_sar_subband {
RTW89_ACPI_SAR_2GHZ_SUBBAND,
RTW89_ACPI_SAR_5GHZ_SUBBAND_1, /* U-NII-1 */
RTW89_ACPI_SAR_5GHZ_SUBBAND_2, /* U-NII-2 */
RTW89_ACPI_SAR_5GHZ_SUBBAND_2E, /* U-NII-2-Extended */
RTW89_ACPI_SAR_5GHZ_SUBBAND_3_4, /* U-NII-3 and U-NII-4 */
RTW89_ACPI_SAR_6GHZ_SUBBAND_5_L, /* U-NII-5 lower part */
RTW89_ACPI_SAR_6GHZ_SUBBAND_5_H, /* U-NII-5 higher part */
RTW89_ACPI_SAR_6GHZ_SUBBAND_6, /* U-NII-6 */
RTW89_ACPI_SAR_6GHZ_SUBBAND_7_L, /* U-NII-7 lower part */
RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H, /* U-NII-7 higher part */
RTW89_ACPI_SAR_6GHZ_SUBBAND_8, /* U-NII-8 */
NUM_OF_RTW89_ACPI_SAR_SUBBAND,
RTW89_ACPI_SAR_SUBBAND_NR_LEGACY = RTW89_ACPI_SAR_5GHZ_SUBBAND_3_4 + 1,
RTW89_ACPI_SAR_SUBBAND_NR_HAS_6GHZ = RTW89_ACPI_SAR_6GHZ_SUBBAND_8 + 1,
};
#define TXPWR_FACTOR_OF_RTW89_ACPI_SAR 3 /* unit: 0.125 dBm */
#define MAX_VAL_OF_RTW89_ACPI_SAR S16_MAX
#define MIN_VAL_OF_RTW89_ACPI_SAR S16_MIN
#define MAX_NUM_OF_RTW89_ACPI_SAR_TBL 6
#define NUM_OF_RTW89_ACPI_SAR_RF_PATH (RF_PATH_B + 1)
struct rtw89_sar_entry_from_acpi {
s16 v[NUM_OF_RTW89_ACPI_SAR_SUBBAND][NUM_OF_RTW89_ACPI_SAR_RF_PATH];
};
struct rtw89_sar_table_from_acpi {
/* If this table is active, must fill all fields according to either
* configuration in BIOS or some default values for SAR to work well.
*/
struct rtw89_sar_entry_from_acpi entries[RTW89_REGD_NUM];
};
struct rtw89_sar_indicator_from_acpi {
bool enable_sync;
unsigned int fields;
u8 (*rfpath_to_antidx)(enum rtw89_rf_path rfpath);
/* Select among @tables of container, rtw89_sar_cfg_acpi, by path.
* Not design with pointers since addresses will be invalid after
* sync content with local container instance.
*/
u8 tblsel[NUM_OF_RTW89_ACPI_SAR_RF_PATH];
};
struct rtw89_sar_cfg_acpi {
u8 downgrade_2tx;
unsigned int valid_num;
struct rtw89_sar_table_from_acpi tables[MAX_NUM_OF_RTW89_ACPI_SAR_TBL];
struct rtw89_sar_indicator_from_acpi indicator;
};
struct rtw89_sar_info {
/* used to decide how to acces SAR cfg union */
/* used to decide how to access SAR cfg union */
enum rtw89_sar_sources src;
/* reserved for different knids of SAR cfg struct.
@@ -4639,6 +4720,7 @@ struct rtw89_sar_info {
*/
union {
struct rtw89_sar_cfg_common cfg_common;
struct rtw89_sar_cfg_acpi cfg_acpi;
};
};
@@ -4674,11 +4756,14 @@ struct rtw89_ant_gain_info {
struct rtw89_6ghz_span {
enum rtw89_sar_subband sar_subband_low;
enum rtw89_sar_subband sar_subband_high;
enum rtw89_acpi_sar_subband acpi_sar_subband_low;
enum rtw89_acpi_sar_subband acpi_sar_subband_high;
enum rtw89_ant_gain_subband ant_gain_subband_low;
enum rtw89_ant_gain_subband ant_gain_subband_high;
};
#define RTW89_SAR_SPAN_VALID(span) ((span)->sar_subband_high)
#define RTW89_ACPI_SAR_SPAN_VALID(span) ((span)->acpi_sar_subband_high)
#define RTW89_ANT_GAIN_SPAN_VALID(span) ((span)->ant_gain_subband_high)
enum rtw89_tas_state {
@@ -4692,6 +4777,7 @@ enum rtw89_tas_state {
struct rtw89_tas_info {
u16 tx_ratio_history[RTW89_TAS_TX_RATIO_WINDOW];
u64 txpwr_history[RTW89_TAS_TXPWR_WINDOW];
u8 enabled_countries;
u8 txpwr_head_idx;
u8 txpwr_tail_idx;
u8 tx_ratio_idx;
@@ -4765,6 +4851,7 @@ enum rtw89_dm_type {
RTW89_DM_DYNAMIC_EDCCA,
RTW89_DM_THERMAL_PROTECT,
RTW89_DM_TAS,
RTW89_DM_MLO,
};
#define RTW89_THERMAL_PROT_LV_MAX 5
@@ -4786,6 +4873,7 @@ struct rtw89_hal {
bool no_mcs_12_13;
atomic_t roc_chanctx_idx;
u8 roc_link_index;
DECLARE_BITMAP(changes, NUM_OF_RTW89_CHANCTX_CHANGES);
DECLARE_BITMAP(entity_map, NUM_OF_RTW89_CHANCTX);
@@ -5207,6 +5295,8 @@ struct rtw89_regulatory_info {
const struct rtw89_regd *regd;
enum rtw89_reg_6ghz_power reg_6ghz_power;
struct rtw89_reg_6ghz_tpe reg_6ghz_tpe;
bool txpwr_uk_follow_etsi;
DECLARE_BITMAP(block_unii4, RTW89_REGD_MAX_COUNTRY_NUM);
DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM);
DECLARE_BITMAP(block_6ghz_sp, RTW89_REGD_MAX_COUNTRY_NUM);
@@ -5360,9 +5450,10 @@ struct rtw89_early_h2c {
struct rtw89_hw_scan_info {
struct rtw89_vif_link *scanning_vif;
struct list_head pkt_list[NUM_NL80211_BANDS];
struct list_head chan_list;
struct rtw89_chan op_chan;
bool connected;
bool abort;
u32 last_chan_idx;
};
enum rtw89_phy_bb_gain_band {
@@ -5574,6 +5665,8 @@ struct rtw89_mcc_role {
struct rtw89_mcc_policy policy;
struct rtw89_mcc_limit limit;
const struct rtw89_mcc_courtesy_cfg *crtz;
/* only valid when running with FW MRC mechanism */
u8 slot_idx;
@@ -5591,13 +5684,16 @@ struct rtw89_mcc_bt_role {
u16 duration; /* TU */
};
struct rtw89_mcc_courtesy {
bool enable;
struct rtw89_mcc_courtesy_cfg {
u8 slot_num;
u8 macid_src;
u8 macid_tgt;
};
struct rtw89_mcc_courtesy {
struct rtw89_mcc_courtesy_cfg ref;
struct rtw89_mcc_courtesy_cfg aux;
};
enum rtw89_mcc_plan {
RTW89_MCC_PLAN_TAIL_BT,
RTW89_MCC_PLAN_MID_BT,
@@ -5631,6 +5727,7 @@ struct rtw89_mcc_config {
struct rtw89_mcc_pattern pattern;
struct rtw89_mcc_sync sync;
u64 start_tsf;
u64 start_tsf_in_aux_domain;
u16 mcc_interval; /* TU */
u16 beacon_offset; /* TU */
};
@@ -5651,6 +5748,16 @@ struct rtw89_mcc_info {
struct rtw89_mcc_config config;
};
enum rtw89_mlo_mode {
RTW89_MLO_MODE_MLSR = 0,
NUM_OF_RTW89_MLO_MODE,
};
struct rtw89_mlo_info {
struct rtw89_wait_info wait;
};
struct rtw89_dev {
struct ieee80211_hw *hw;
struct device *dev;
@@ -5666,6 +5773,7 @@ struct rtw89_dev {
const struct rtw89_rfe_parms *rfe_parms;
struct rtw89_hal hal;
struct rtw89_mcc_info mcc;
struct rtw89_mlo_info mlo;
struct rtw89_mac_info mac;
struct rtw89_fw_info fw;
struct rtw89_hci_info hci;
@@ -5802,6 +5910,9 @@ struct rtw89_vif {
struct rtw89_roc roc;
bool offchan;
enum rtw89_mlo_mode mlo_mode;
struct list_head dlink_pool;
u8 links_inst_valid_num;
DECLARE_BITMAP(links_inst_map, __RTW89_MLD_MAX_LINK_NUM);
struct rtw89_vif_link *links[IEEE80211_MLD_MAX_NUM_LINKS];
@@ -5841,6 +5952,7 @@ struct rtw89_sta {
DECLARE_BITMAP(pairwise_sec_cam_map, RTW89_MAX_SEC_CAM_NUM);
struct list_head dlink_pool;
u8 links_inst_valid_num;
DECLARE_BITMAP(links_inst_map, __RTW89_MLD_MAX_LINK_NUM);
struct rtw89_sta_link *links[IEEE80211_MLD_MAX_NUM_LINKS];
@@ -5936,6 +6048,12 @@ rtw89_assoc_link_rcu_dereference(struct rtw89_dev *rtwdev, u8 macid)
return rcu_dereference(rtwdev->assoc_link_on_macid[macid]);
}
#define rtw89_get_designated_link(links_holder) \
({ \
typeof(links_holder) p = links_holder; \
list_first_entry_or_null(&p->dlink_pool, typeof(*p->links_inst), dlink_schd); \
})
static inline int rtw89_hci_tx_write(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req)
{
@@ -6825,9 +6943,14 @@ static inline void rtw89_load_txpwr_table(struct rtw89_dev *rtwdev,
static inline u8 rtw89_regd_get(struct rtw89_dev *rtwdev, u8 band)
{
const struct rtw89_regd *regd = rtwdev->regulatory.regd;
const struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
const struct rtw89_regd *regd = regulatory->regd;
u8 txpwr_regd = regd->txpwr_regd[band];
return regd->txpwr_regd[band];
if (regulatory->txpwr_uk_follow_etsi && txpwr_regd == RTW89_UK)
return RTW89_ETSI;
return txpwr_regd;
}
static inline void rtw89_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en,
@@ -7185,6 +7308,7 @@ void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate);
int rtw89_regd_setup(struct rtw89_dev *rtwdev);
int rtw89_regd_init_hint(struct rtw89_dev *rtwdev);
const char *rtw89_regd_get_string(enum rtw89_regulation_type regd);
void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
struct rtw89_traffic_stats *stats);
int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond);
@@ -7206,5 +7330,7 @@ void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct ieee80211_bss_conf *bss_conf);
void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event);
int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
unsigned int link_id);
#endif

View File

@@ -85,6 +85,7 @@ struct rtw89_debugfs {
struct rtw89_debugfs_priv phy_info;
struct rtw89_debugfs_priv stations;
struct rtw89_debugfs_priv disable_dm;
struct rtw89_debugfs_priv mlo_mode;
};
struct rtw89_debugfs_iter_data {
@@ -854,45 +855,21 @@ static ssize_t __print_txpwr_map(struct rtw89_dev *rtwdev, char *buf, size_t buf
return p - buf;
}
#define case_REGD(_regd) \
case RTW89_ ## _regd: \
p += scnprintf(p, end - p, #_regd "\n"); \
break
static int __print_regd(struct rtw89_dev *rtwdev, char *buf, size_t bufsz,
const struct rtw89_chan *chan)
{
const struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
char *p = buf, *end = buf + bufsz;
u8 band = chan->band_type;
u8 regd = rtw89_regd_get(rtwdev, band);
switch (regd) {
default:
p += scnprintf(p, end - p, "UNKNOWN: %d\n", regd);
break;
case_REGD(WW);
case_REGD(ETSI);
case_REGD(FCC);
case_REGD(MKK);
case_REGD(NA);
case_REGD(IC);
case_REGD(KCC);
case_REGD(NCC);
case_REGD(CHILE);
case_REGD(ACMA);
case_REGD(MEXICO);
case_REGD(UKRAINE);
case_REGD(CN);
case_REGD(QATAR);
case_REGD(UK);
case_REGD(THAILAND);
}
p += scnprintf(p, end - p, "%s\n", rtw89_regd_get_string(regd));
p += scnprintf(p, end - p, "\t(txpwr UK follow ETSI: %s)\n",
str_yes_no(regulatory->txpwr_uk_follow_etsi));
return p - buf;
}
#undef case_REGD
struct dbgfs_txpwr_table {
const struct txpwr_map *byr;
const struct txpwr_map *lmt;
@@ -949,6 +926,7 @@ ssize_t rtw89_debug_priv_txpwr_table_get(struct rtw89_dev *rtwdev,
char *buf, size_t bufsz)
{
enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
struct rtw89_sar_parm sar_parm = {};
const struct dbgfs_txpwr_table *tbl;
const struct rtw89_chan *chan;
char *p = buf, *end = buf + bufsz;
@@ -958,11 +936,12 @@ ssize_t rtw89_debug_priv_txpwr_table_get(struct rtw89_dev *rtwdev,
rtw89_leave_ps_mode(rtwdev);
chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
sar_parm.center_freq = chan->freq;
p += rtw89_debug_priv_txpwr_table_get_regd(rtwdev, p, end - p, chan);
p += scnprintf(p, end - p, "[SAR]\n");
p += rtw89_print_sar(rtwdev, p, end - p, chan->freq);
p += rtw89_print_sar(rtwdev, p, end - p, &sar_parm);
p += scnprintf(p, end - p, "[TAS]\n");
p += rtw89_print_tas(rtwdev, p, end - p);
@@ -3993,14 +3972,16 @@ static int rtw89_dump_pkt_offload(char *buf, size_t bufsz, struct list_head *pkt
static int rtw89_vif_link_ids_get(struct rtw89_dev *rtwdev,
char *buf, size_t bufsz, u8 *mac,
struct rtw89_vif_link *rtwvif_link)
struct rtw89_vif_link *rtwvif_link,
bool designated)
{
struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam;
char *p = buf, *end = buf + bufsz;
p += scnprintf(p, end - p, " [%u] %pM\n", rtwvif_link->mac_id,
rtwvif_link->mac_addr);
p += scnprintf(p, end - p, "\tlink_id=%u\n", rtwvif_link->link_id);
p += scnprintf(p, end - p, "\tlink_id=%u%s\n", rtwvif_link->link_id,
designated ? " (*)" : "");
p += scnprintf(p, end - p, "\tbssid_cam_idx=%u\n",
bssid_cam->bssid_cam_idx);
p += rtw89_dump_addr_cam(rtwdev, p, end - p, &rtwvif_link->addr_cam);
@@ -4017,15 +3998,19 @@ void rtw89_vif_ids_get_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
(struct rtw89_debugfs_iter_data *)data;
struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
struct rtw89_dev *rtwdev = rtwvif->rtwdev;
struct rtw89_vif_link *designated_link;
struct rtw89_vif_link *rtwvif_link;
size_t bufsz = iter_data->bufsz;
char *buf = iter_data->buf;
char *p = buf, *end = buf + bufsz;
unsigned int link_id;
designated_link = rtw89_get_designated_link(rtwvif);
p += scnprintf(p, end - p, "VIF %pM\n", rtwvif->mac_addr);
rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
p += rtw89_vif_link_ids_get(rtwdev, p, end - p, mac, rtwvif_link);
p += rtw89_vif_link_ids_get(rtwdev, p, end - p, mac, rtwvif_link,
rtwvif_link == designated_link);
rtw89_debugfs_iter_data_next(iter_data, p, end - p, p - buf);
}
@@ -4055,7 +4040,8 @@ static int rtw89_dump_ba_cam(struct rtw89_dev *rtwdev,
static int rtw89_sta_link_ids_get(struct rtw89_dev *rtwdev,
char *buf, size_t bufsz,
struct rtw89_sta_link *rtwsta_link)
struct rtw89_sta_link *rtwsta_link,
bool designated)
{
struct ieee80211_link_sta *link_sta;
char *p = buf, *end = buf + bufsz;
@@ -4069,7 +4055,8 @@ static int rtw89_sta_link_ids_get(struct rtw89_dev *rtwdev,
rcu_read_unlock();
p += scnprintf(p, end - p, "\tlink_id=%u\n", rtwsta_link->link_id);
p += scnprintf(p, end - p, "\tlink_id=%u%s\n", rtwsta_link->link_id,
designated ? " (*)" : "");
p += rtw89_dump_addr_cam(rtwdev, p, end - p, &rtwsta_link->addr_cam);
p += rtw89_dump_ba_cam(rtwdev, p, end - p, rtwsta_link);
@@ -4082,16 +4069,20 @@ static void rtw89_sta_ids_get_iter(void *data, struct ieee80211_sta *sta)
(struct rtw89_debugfs_iter_data *)data;
struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
struct rtw89_dev *rtwdev = rtwsta->rtwdev;
struct rtw89_sta_link *designated_link;
struct rtw89_sta_link *rtwsta_link;
size_t bufsz = iter_data->bufsz;
char *buf = iter_data->buf;
char *p = buf, *end = buf + bufsz;
unsigned int link_id;
designated_link = rtw89_get_designated_link(rtwsta);
p += scnprintf(p, end - p, "STA %pM %s\n", sta->addr,
sta->tdls ? "(TDLS)" : "");
rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id)
p += rtw89_sta_link_ids_get(rtwdev, p, end - p, rtwsta_link);
p += rtw89_sta_link_ids_get(rtwdev, p, end - p, rtwsta_link,
rtwsta_link == designated_link);
rtw89_debugfs_iter_data_next(iter_data, p, end - p, p - buf);
}
@@ -4146,6 +4137,35 @@ static ssize_t rtw89_debug_priv_stations_get(struct rtw89_dev *rtwdev,
return p - buf;
}
static void rtw89_debug_disable_dm_cfg_bmap(struct rtw89_dev *rtwdev, u32 new)
{
struct rtw89_hal *hal = &rtwdev->hal;
u32 old = hal->disabled_dm_bitmap;
if (new == old)
return;
hal->disabled_dm_bitmap = new;
rtw89_debug(rtwdev, RTW89_DBG_STATE, "Disable DM: 0x%x -> 0x%x\n", old, new);
}
static void rtw89_debug_disable_dm_set_flag(struct rtw89_dev *rtwdev, u8 flag)
{
struct rtw89_hal *hal = &rtwdev->hal;
u32 cur = hal->disabled_dm_bitmap;
rtw89_debug_disable_dm_cfg_bmap(rtwdev, cur | BIT(flag));
}
static void rtw89_debug_disable_dm_clr_flag(struct rtw89_dev *rtwdev, u8 flag)
{
struct rtw89_hal *hal = &rtwdev->hal;
u32 cur = hal->disabled_dm_bitmap;
rtw89_debug_disable_dm_cfg_bmap(rtwdev, cur & ~BIT(flag));
}
#define DM_INFO(type) {RTW89_DM_ ## type, #type}
static const struct rtw89_disabled_dm_info {
@@ -4155,6 +4175,7 @@ static const struct rtw89_disabled_dm_info {
DM_INFO(DYNAMIC_EDCCA),
DM_INFO(THERMAL_PROTECT),
DM_INFO(TAS),
DM_INFO(MLO),
};
static ssize_t
@@ -4188,7 +4209,6 @@ rtw89_debug_priv_disable_dm_set(struct rtw89_dev *rtwdev,
struct rtw89_debugfs_priv *debugfs_priv,
const char *buf, size_t count)
{
struct rtw89_hal *hal = &rtwdev->hal;
u32 conf;
int ret;
@@ -4196,7 +4216,83 @@ rtw89_debug_priv_disable_dm_set(struct rtw89_dev *rtwdev,
if (ret)
return -EINVAL;
hal->disabled_dm_bitmap = conf;
rtw89_debug_disable_dm_cfg_bmap(rtwdev, conf);
return count;
}
static void rtw89_debug_mlo_mode_set_mlsr(struct rtw89_dev *rtwdev,
unsigned int link_id)
{
struct ieee80211_vif *vif;
struct rtw89_vif *rtwvif;
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
vif = rtwvif_to_vif(rtwvif);
if (!ieee80211_vif_is_mld(vif))
continue;
rtw89_core_mlsr_switch(rtwdev, rtwvif, link_id);
}
}
static ssize_t
rtw89_debug_priv_mlo_mode_get(struct rtw89_dev *rtwdev,
struct rtw89_debugfs_priv *debugfs_priv,
char *buf, size_t bufsz)
{
bool mlo_dm_dis = rtwdev->hal.disabled_dm_bitmap & BIT(RTW89_DM_MLO);
char *p = buf, *end = buf + bufsz;
struct ieee80211_vif *vif;
struct rtw89_vif *rtwvif;
int count = 0;
p += scnprintf(p, end - p, "MLD(s) status: (MLO DM: %s)\n",
str_disable_enable(mlo_dm_dis));
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
vif = rtwvif_to_vif(rtwvif);
if (!ieee80211_vif_is_mld(vif))
continue;
p += scnprintf(p, end - p,
"\t#%u: MLO mode %x, valid 0x%x, active 0x%x\n",
count++, rtwvif->mlo_mode, vif->valid_links,
vif->active_links);
}
if (count == 0)
p += scnprintf(p, end - p, "\t(None)\n");
return p - buf;
}
static ssize_t
rtw89_debug_priv_mlo_mode_set(struct rtw89_dev *rtwdev,
struct rtw89_debugfs_priv *debugfs_priv,
const char *buf, size_t count)
{
u8 num, mlo_mode;
u32 argv;
num = sscanf(buf, "%hhx %u", &mlo_mode, &argv);
if (num != 2)
return -EINVAL;
rtw89_debug_disable_dm_set_flag(rtwdev, RTW89_DM_MLO);
rtw89_debug(rtwdev, RTW89_DBG_STATE, "Set MLO mode to %x\n", mlo_mode);
switch (mlo_mode) {
case RTW89_MLO_MODE_MLSR:
rtw89_debug_mlo_mode_set_mlsr(rtwdev, argv);
break;
default:
rtw89_debug(rtwdev, RTW89_DBG_STATE, "Unsupported MLO mode\n");
rtw89_debug_disable_dm_clr_flag(rtwdev, RTW89_DM_MLO);
return -EOPNOTSUPP;
}
return count;
}
@@ -4257,7 +4353,8 @@ static const struct rtw89_debugfs rtw89_debugfs_templ = {
.fw_log_manual = rtw89_debug_priv_set(fw_log_manual, WLOCK),
.phy_info = rtw89_debug_priv_get(phy_info),
.stations = rtw89_debug_priv_get(stations, RLOCK),
.disable_dm = rtw89_debug_priv_set_and_get(disable_dm),
.disable_dm = rtw89_debug_priv_set_and_get(disable_dm, RWLOCK),
.mlo_mode = rtw89_debug_priv_set_and_get(mlo_mode, RWLOCK),
};
#define rtw89_debugfs_add(name, mode, fopname, parent) \
@@ -4302,6 +4399,7 @@ void rtw89_debugfs_add_sec1(struct rtw89_dev *rtwdev, struct dentry *debugfs_top
rtw89_debugfs_add_r(phy_info);
rtw89_debugfs_add_r(stations);
rtw89_debugfs_add_rw(disable_dm);
rtw89_debugfs_add_rw(mlo_mode);
}
void rtw89_debugfs_init(struct rtw89_dev *rtwdev)

View File

@@ -15,6 +15,8 @@
#include "util.h"
#include "wow.h"
static bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev);
struct rtw89_eapol_2_of_2 {
u8 gtkbody[14];
u8 key_des_ver;
@@ -554,7 +556,7 @@ const struct rtw89_mfw_hdr *rtw89_mfw_get_hdr_ptr(struct rtw89_dev *rtwdev,
if (sizeof(*mfw_hdr) > firmware->size)
return NULL;
mfw_hdr = (const struct rtw89_mfw_hdr *)firmware->data;
mfw_hdr = (const struct rtw89_mfw_hdr *)&firmware->data[0];
if (mfw_hdr->sig != RTW89_MFW_SIG)
return NULL;
@@ -850,6 +852,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
__CFG_FW_FEAT(RTL8922A, lt, 0, 35, 49, 0, RFK_PRE_NOTIFY_V1),
__CFG_FW_FEAT(RTL8922A, lt, 0, 35, 51, 0, NO_PHYCAP_P1),
__CFG_FW_FEAT(RTL8922A, lt, 0, 35, 64, 0, NO_POWER_DIFFERENCE),
__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1),
};
static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
@@ -1018,7 +1021,7 @@ int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev,
}
n_regs = le32_to_cpu(elm->size) / sizeof(tbl->regs[0]);
regs = kcalloc(n_regs, sizeof(tbl->regs[0]), GFP_KERNEL);
regs = kcalloc(n_regs, sizeof(*regs), GFP_KERNEL);
if (!regs)
goto out;
@@ -1298,6 +1301,18 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, lmt_6ghz.conf) }, NULL,
},
[RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_2GHZ] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, da_lmt_2ghz.conf) }, NULL,
},
[RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_5GHZ] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, da_lmt_5ghz.conf) }, NULL,
},
[RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_6GHZ] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, da_lmt_6ghz.conf) }, NULL,
},
[RTW89_FW_ELEMENT_ID_TXPWR_LMT_RU_2GHZ] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, lmt_ru_2ghz.conf) }, NULL,
@@ -1310,6 +1325,18 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, lmt_ru_6ghz.conf) }, NULL,
},
[RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_2GHZ] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, da_lmt_ru_2ghz.conf) }, NULL,
},
[RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_5GHZ] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, da_lmt_ru_5ghz.conf) }, NULL,
},
[RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_6GHZ] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, da_lmt_ru_6ghz.conf) }, NULL,
},
[RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, tx_shape_lmt.conf) }, NULL,
@@ -2483,7 +2510,7 @@ int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable)
if (enable)
comp = BIT(RTW89_FW_LOG_COMP_INIT) | BIT(RTW89_FW_LOG_COMP_TASK) |
BIT(RTW89_FW_LOG_COMP_PS) | BIT(RTW89_FW_LOG_COMP_ERROR) |
BIT(RTW89_FW_LOG_COMP_SCAN);
BIT(RTW89_FW_LOG_COMP_MLO) | BIT(RTW89_FW_LOG_COMP_SCAN);
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LOG_CFG_LEN);
if (!skb) {
@@ -3065,8 +3092,8 @@ static void __rtw89_fw_h2c_set_tx_path(struct rtw89_dev *rtwdev,
ntx_path = RF_A;
map_b = 0;
} else {
ntx_path = hal->antenna_tx ? hal->antenna_tx : RF_B;
map_b = hal->antenna_tx == RF_AB ? 1 : 0;
ntx_path = hal->antenna_tx ? hal->antenna_tx : RF_AB;
map_b = ntx_path == RF_AB ? 1 : 0;
}
SET_CMC_TBL_NTX_PATH_EN(skb->data, ntx_path);
@@ -4004,8 +4031,9 @@ rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_li
int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
struct rtw89_sta_link *rtwsta_link, bool dis_conn)
{
struct sk_buff *skb;
u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id;
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
bool is_mld = ieee80211_vif_is_mld(vif);
u8 self_role = rtwvif_link->self_role;
enum rtw89_fw_sta_type sta_type;
u8 net_type = rtwvif_link->net_type;
@@ -4013,6 +4041,9 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwv
struct rtw89_h2c_join *h2c;
u32 len = sizeof(*h2c);
bool format_v1 = false;
struct sk_buff *skb;
u8 main_mac_id;
bool init_ps;
int ret;
if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) {
@@ -4054,8 +4085,28 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwv
h2c_v1 = (struct rtw89_h2c_join_v1 *)skb->data;
sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif_link, rtwsta_link);
init_ps = rtwvif_link != rtw89_get_designated_link(rtwvif_link->rtwvif);
if (rtwsta_link)
main_mac_id = rtw89_sta_get_main_macid(rtwsta_link->rtwsta);
else
main_mac_id = rtw89_vif_get_main_macid(rtwvif_link->rtwvif);
h2c_v1->w1 = le32_encode_bits(sta_type, RTW89_H2C_JOININFO_W1_STA_TYPE) |
le32_encode_bits(is_mld, RTW89_H2C_JOININFO_W1_IS_MLD) |
le32_encode_bits(main_mac_id, RTW89_H2C_JOININFO_W1_MAIN_MACID) |
le32_encode_bits(RTW89_H2C_JOININFO_MLO_MODE_MLSR,
RTW89_H2C_JOININFO_W1_MLO_MODE) |
le32_encode_bits(0, RTW89_H2C_JOININFO_W1_EMLSR_CAB) |
le32_encode_bits(0, RTW89_H2C_JOININFO_W1_NSTR_EN) |
le32_encode_bits(init_ps, RTW89_H2C_JOININFO_W1_INIT_PWR_STATE) |
le32_encode_bits(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_256US,
RTW89_H2C_JOININFO_W1_EMLSR_PADDING) |
le32_encode_bits(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_256US,
RTW89_H2C_JOININFO_W1_EMLSR_TRANS_DELAY) |
le32_encode_bits(0, RTW89_H2C_JOININFO_W2_MACID_EXT) |
le32_encode_bits(0, RTW89_H2C_JOININFO_W2_MAIN_MACID_EXT);
h2c_v1->w1 = le32_encode_bits(sta_type, RTW89_H2C_JOININFO_W1_STA_TYPE);
h2c_v1->w2 = 0;
done:
@@ -4339,6 +4390,7 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev,
struct rtw89_h2c_bcnfltr *h2c;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
u8 max_cnt, cnt;
int ret;
if (!RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw))
@@ -4367,12 +4419,20 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev,
skb_put(skb, len);
h2c = (struct rtw89_h2c_bcnfltr *)skb->data;
if (RTW89_CHK_FW_FEATURE(BEACON_LOSS_COUNT_V1, &rtwdev->fw))
max_cnt = BIT(7) - 1;
else
max_cnt = BIT(4) - 1;
cnt = min(RTW89_BCN_LOSS_CNT, max_cnt);
h2c->w0 = le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_RSSI) |
le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_BCN) |
le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_EN) |
le32_encode_bits(RTW89_BCN_FLTR_OFFLOAD_MODE_DEFAULT,
RTW89_H2C_BCNFLTR_W0_MODE) |
le32_encode_bits(RTW89_BCN_LOSS_CNT, RTW89_H2C_BCNFLTR_W0_BCN_LOSS_CNT) |
le32_encode_bits(cnt >> 4, RTW89_H2C_BCNFLTR_W0_BCN_LOSS_CNT_H3) |
le32_encode_bits(cnt & 0xf, RTW89_H2C_BCNFLTR_W0_BCN_LOSS_CNT_L4) |
le32_encode_bits(hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) |
le32_encode_bits(thold + MAX_RSSI,
RTW89_H2C_BCNFLTR_W0_RSSI_THRESHOLD) |
@@ -5298,12 +5358,12 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id,
}
static
int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num,
struct list_head *chan_list)
int rtw89_fw_h2c_scan_list_offload_ax(struct rtw89_dev *rtwdev, int ch_num,
struct list_head *chan_list)
{
struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
struct rtw89_h2c_chinfo_elem *elem;
struct rtw89_mac_chinfo *ch_info;
struct rtw89_mac_chinfo_ax *ch_info;
struct rtw89_h2c_chinfo *h2c;
struct sk_buff *skb;
unsigned int cond;
@@ -5477,7 +5537,7 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
return 0;
}
#define RTW89_SCAN_DELAY_TSF_UNIT 104800
#define RTW89_SCAN_DELAY_TSF_UNIT 1000000
int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev,
struct rtw89_scan_option *option,
struct rtw89_vif_link *rtwvif_link,
@@ -5741,7 +5801,7 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
RTW89_H2C_SCANOFLD_BE_OPCH_W2_PKTS_CTRL) |
le32_encode_bits(0,
RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF) |
le32_encode_bits(2,
le32_encode_bits(rtw89_is_mlo_1_1(rtwdev) ? 1 : 2,
RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS);
opch->w3 = le32_encode_bits(RTW89_SCANOFLD_PKT_NONE,
@@ -6525,7 +6585,7 @@ void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev)
rtw89_fw_prog_cnt_dump(rtwdev);
}
static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev)
static void rtw89_hw_scan_release_pkt_list(struct rtw89_dev *rtwdev)
{
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
struct rtw89_pktofld_info *info, *tmp;
@@ -6544,6 +6604,23 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev)
}
}
static void rtw89_hw_scan_cleanup(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
mac->free_chan_list(rtwdev);
rtw89_hw_scan_release_pkt_list(rtwdev);
rtwvif->scan_req = NULL;
rtwvif->scan_ies = NULL;
scan_info->scanning_vif = NULL;
scan_info->abort = false;
scan_info->connected = false;
}
static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev,
struct cfg80211_scan_request *req,
struct rtw89_pktofld_info *info,
@@ -6612,7 +6689,8 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
}
static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
struct rtw89_vif_link *rtwvif_link,
const u8 *mac_addr)
{
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
@@ -6621,7 +6699,7 @@ static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
int ret;
for (i = 0; i < num; i++) {
skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr,
skb = ieee80211_probereq_get(rtwdev->hw, mac_addr,
req->ssids[i].ssid,
req->ssids[i].ssid_len,
req->ie_len);
@@ -6638,10 +6716,10 @@ static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev,
return 0;
}
static int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev,
struct ieee80211_scan_ies *ies,
struct cfg80211_scan_request *req,
struct rtw89_mac_chinfo *ch_info)
static int rtw89_update_6ghz_rnr_chan_ax(struct rtw89_dev *rtwdev,
struct ieee80211_scan_ies *ies,
struct cfg80211_scan_request *req,
struct rtw89_mac_chinfo_ax *ch_info)
{
struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif;
struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
@@ -6713,7 +6791,7 @@ static int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev,
static void rtw89_pno_scan_add_chan_ax(struct rtw89_dev *rtwdev,
int chan_type, int ssid_num,
struct rtw89_mac_chinfo *ch_info)
struct rtw89_mac_chinfo_ax *ch_info)
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct rtw89_pktofld_info *info;
@@ -6761,9 +6839,9 @@ static void rtw89_pno_scan_add_chan_ax(struct rtw89_dev *rtwdev,
}
}
static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
int ssid_num,
struct rtw89_mac_chinfo *ch_info)
static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type,
int ssid_num,
struct rtw89_mac_chinfo_ax *ch_info)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif;
@@ -6794,7 +6872,7 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
}
}
ret = rtw89_update_6ghz_rnr_chan(rtwdev, ies, req, ch_info);
ret = rtw89_update_6ghz_rnr_chan_ax(rtwdev, ies, req, ch_info);
if (ret)
rtw89_warn(rtwdev, "RNR fails: %d\n", ret);
@@ -6950,7 +7028,7 @@ int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
{
struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config;
struct rtw89_mac_chinfo *ch_info, *tmp;
struct rtw89_mac_chinfo_ax *ch_info, *tmp;
struct ieee80211_channel *channel;
struct list_head chan_list;
int list_len;
@@ -6984,7 +7062,7 @@ int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
rtw89_pno_scan_add_chan_ax(rtwdev, type, nd_config->n_match_sets, ch_info);
list_add_tail(&ch_info->list, &chan_list);
}
ret = rtw89_fw_h2c_scan_list_offload(rtwdev, list_len, &chan_list);
ret = rtw89_fw_h2c_scan_list_offload_ax(rtwdev, list_len, &chan_list);
out:
list_for_each_entry_safe(ch_info, tmp, &chan_list, list) {
@@ -6995,24 +7073,24 @@ int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
return ret;
}
int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected)
int rtw89_hw_scan_prep_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_mac_chinfo *ch_info, *tmp;
struct rtw89_mac_chinfo_ax *ch_info, *tmp;
struct ieee80211_channel *channel;
struct list_head chan_list;
bool random_seq = req->flags & NL80211_SCAN_FLAG_RANDOM_SN;
int list_len, off_chan_time = 0;
enum rtw89_chan_type type;
int ret = 0;
int off_chan_time = 0;
int ret;
u32 idx;
INIT_LIST_HEAD(&chan_list);
for (idx = rtwdev->scan_info.last_chan_idx, list_len = 0;
idx < req->n_channels && list_len < RTW89_SCAN_LIST_LIMIT_AX;
idx++, list_len++) {
for (idx = 0; idx < req->n_channels; idx++) {
channel = req->channels[idx];
ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
if (!ch_info) {
@@ -7039,9 +7117,9 @@ int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
type = RTW89_CHAN_DFS;
else
type = RTW89_CHAN_ACTIVE;
rtw89_hw_scan_add_chan(rtwdev, type, req->n_ssids, ch_info);
rtw89_hw_scan_add_chan_ax(rtwdev, type, req->n_ssids, ch_info);
if (connected &&
if (scan_info->connected &&
off_chan_time + ch_info->period > RTW89_OFF_CHAN_TIME) {
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) {
@@ -7053,16 +7131,16 @@ int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
type = RTW89_CHAN_OPERATE;
tmp->period = req->duration_mandatory ?
req->duration : RTW89_CHANNEL_TIME;
rtw89_hw_scan_add_chan(rtwdev, type, 0, tmp);
rtw89_hw_scan_add_chan_ax(rtwdev, type, 0, tmp);
list_add_tail(&tmp->list, &chan_list);
off_chan_time = 0;
list_len++;
}
list_add_tail(&ch_info->list, &chan_list);
off_chan_time += ch_info->period;
}
rtwdev->scan_info.last_chan_idx = idx;
ret = rtw89_fw_h2c_scan_list_offload(rtwdev, list_len, &chan_list);
list_splice_tail(&chan_list, &scan_info->chan_list);
return 0;
out:
list_for_each_entry_safe(ch_info, tmp, &chan_list, list) {
@@ -7073,6 +7151,46 @@ int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
return ret;
}
void rtw89_hw_scan_free_chan_list_ax(struct rtw89_dev *rtwdev)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_mac_chinfo_ax *ch_info, *tmp;
list_for_each_entry_safe(ch_info, tmp, &scan_info->chan_list, list) {
list_del(&ch_info->list);
kfree(ch_info);
}
}
int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_mac_chinfo_ax *ch_info, *tmp;
unsigned int list_len = 0;
struct list_head list;
int ret;
INIT_LIST_HEAD(&list);
list_for_each_entry_safe(ch_info, tmp, &scan_info->chan_list, list) {
list_move_tail(&ch_info->list, &list);
list_len++;
if (list_len == RTW89_SCAN_LIST_LIMIT_AX)
break;
}
ret = rtw89_fw_h2c_scan_list_offload_ax(rtwdev, list_len, &list);
list_for_each_entry_safe(ch_info, tmp, &list, list) {
list_del(&ch_info->list);
kfree(ch_info);
}
return ret;
}
int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
@@ -7126,25 +7244,24 @@ int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
return ret;
}
int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected)
int rtw89_hw_scan_prep_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_mac_chinfo_be *ch_info, *tmp;
struct ieee80211_channel *channel;
struct list_head chan_list;
enum rtw89_chan_type type;
int list_len, ret;
bool random_seq;
int ret;
u32 idx;
random_seq = !!(req->flags & NL80211_SCAN_FLAG_RANDOM_SN);
INIT_LIST_HEAD(&chan_list);
for (idx = rtwdev->scan_info.last_chan_idx, list_len = 0;
idx < req->n_channels && list_len < RTW89_SCAN_LIST_LIMIT_BE;
idx++, list_len++) {
for (idx = 0; idx < req->n_channels; idx++) {
channel = req->channels[idx];
ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
if (!ch_info) {
@@ -7174,9 +7291,8 @@ int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
list_add_tail(&ch_info->list, &chan_list);
}
rtwdev->scan_info.last_chan_idx = idx;
ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list,
rtwvif_link);
list_splice_tail(&chan_list, &scan_info->chan_list);
return 0;
out:
list_for_each_entry_safe(ch_info, tmp, &chan_list, list) {
@@ -7187,51 +7303,182 @@ int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
return ret;
}
void rtw89_hw_scan_free_chan_list_be(struct rtw89_dev *rtwdev)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_mac_chinfo_be *ch_info, *tmp;
list_for_each_entry_safe(ch_info, tmp, &scan_info->chan_list, list) {
list_del(&ch_info->list);
kfree(ch_info);
}
}
int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_mac_chinfo_be *ch_info, *tmp;
unsigned int list_len = 0;
struct list_head list;
int ret;
INIT_LIST_HEAD(&list);
list_for_each_entry_safe(ch_info, tmp, &scan_info->chan_list, list) {
list_move_tail(&ch_info->list, &list);
list_len++;
if (list_len == RTW89_SCAN_LIST_LIMIT_BE)
break;
}
ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &list,
rtwvif_link);
list_for_each_entry_safe(ch_info, tmp, &list, list) {
list_del(&ch_info->list);
kfree(ch_info);
}
return ret;
}
static int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected)
struct rtw89_vif_link *rtwvif_link,
const u8 *mac_addr)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
int ret;
ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif_link);
ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif_link, mac_addr);
if (ret) {
rtw89_err(rtwdev, "Update probe request failed\n");
goto out;
}
ret = mac->add_chan_list(rtwdev, rtwvif_link, connected);
ret = mac->prep_chan_list(rtwdev, rtwvif_link);
out:
return ret;
}
void rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct ieee80211_scan_request *scan_req)
static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
u16 tu)
{
struct ieee80211_p2p_noa_desc noa_desc = {};
u64 tsf;
int ret;
ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf);
if (ret) {
rtw89_warn(rtwdev, "%s: failed to get tsf\n", __func__);
return;
}
noa_desc.start_time = cpu_to_le32(tsf);
noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(tu));
noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(tu));
noa_desc.count = 1;
rtw89_p2p_noa_renew(rtwvif_link);
rtw89_p2p_noa_append(rtwvif_link, &noa_desc);
rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link);
}
static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev,
const struct cfg80211_scan_request *req)
{
const struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt;
const struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_mac_chinfo_ax *chinfo_ax;
struct rtw89_mac_chinfo_be *chinfo_be;
struct rtw89_vif_link *rtwvif_link;
struct list_head *pos, *tmp;
struct ieee80211_vif *vif;
struct rtw89_vif *rtwvif;
u16 tu = 0;
lockdep_assert_wiphy(rtwdev->hw->wiphy);
list_for_each_safe(pos, tmp, &scan_info->chan_list) {
switch (chip->chip_gen) {
case RTW89_CHIP_AX:
chinfo_ax = list_entry(pos, typeof(*chinfo_ax), list);
tu += chinfo_ax->period;
break;
case RTW89_CHIP_BE:
chinfo_be = list_entry(pos, typeof(*chinfo_be), list);
tu += chinfo_be->period;
break;
default:
rtw89_warn(rtwdev, "%s: invalid chip gen %d\n",
__func__, chip->chip_gen);
return;
}
}
if (unlikely(tu == 0)) {
rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN,
"%s: cannot estimate needed TU\n", __func__);
return;
}
list_for_each_entry(rtwvif, &mgnt->active_list, mgnt_entry) {
unsigned int link_id;
vif = rtwvif_to_vif(rtwvif);
if (vif->type != NL80211_IFTYPE_AP || !vif->p2p)
continue;
rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id)
rtw89_hw_scan_update_link_beacon_noa(rtwdev, rtwvif_link, tu);
}
}
int rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct ieee80211_scan_request *scan_req)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev);
struct cfg80211_scan_request *req = &scan_req->req;
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
rtwvif_link->chanctx_idx);
struct rtw89_vif *rtwvif = rtwvif_link->rtwvif;
struct rtw89_chanctx_pause_parm pause_parm = {
.rsn = RTW89_CHANCTX_PAUSE_REASON_HW_SCAN,
.trigger = rtwvif_link,
};
u32 rx_fltr = rtwdev->hal.rx_fltr;
u8 mac_addr[ETH_ALEN];
u32 reg;
int ret;
/* clone op and keep it during scan */
rtwdev->scan_info.op_chan = *chan;
rtwdev->scan_info.connected = rtw89_is_any_vif_connected_or_connecting(rtwdev);
rtwdev->scan_info.scanning_vif = rtwvif_link;
rtwdev->scan_info.last_chan_idx = 0;
rtwdev->scan_info.abort = false;
rtwvif->scan_ies = &scan_req->ies;
rtwvif->scan_req = req;
ieee80211_stop_queues(rtwdev->hw);
rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, false);
if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
get_random_mask_addr(mac_addr, req->mac_addr,
req->mac_addr_mask);
else
ether_addr_copy(mac_addr, rtwvif_link->mac_addr);
ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif_link, mac_addr);
if (ret) {
rtw89_hw_scan_cleanup(rtwdev, rtwvif_link);
return ret;
}
ieee80211_stop_queues(rtwdev->hw);
rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, false);
rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, true);
rx_fltr &= ~B_AX_A_BCN_CHK_EN;
@@ -7241,7 +7488,12 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rx_fltr);
rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_HW_SCAN);
rtw89_chanctx_pause(rtwdev, &pause_parm);
if (mode == RTW89_ENTITY_MODE_MCC)
rtw89_hw_scan_update_beacon_noa(rtwdev, req);
return 0;
}
struct rtw89_hw_scan_complete_cb_data {
@@ -7252,20 +7504,16 @@ struct rtw89_hw_scan_complete_cb_data {
static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
struct rtw89_hw_scan_complete_cb_data *cb_data = data;
struct rtw89_vif_link *rtwvif_link = cb_data->rtwvif_link;
struct cfg80211_scan_info info = {
.aborted = cb_data->aborted,
};
struct rtw89_vif *rtwvif;
u32 reg;
if (!rtwvif_link)
return -EINVAL;
rtwvif = rtwvif_link->rtwvif;
reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx);
rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rtwdev->hal.rx_fltr);
@@ -7275,12 +7523,7 @@ static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data)
rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, true);
rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true);
rtw89_release_pkt_list(rtwdev);
rtwvif->scan_req = NULL;
rtwvif->scan_ies = NULL;
scan_info->last_chan_idx = 0;
scan_info->scanning_vif = NULL;
scan_info->abort = false;
rtw89_hw_scan_cleanup(rtwdev, rtwvif_link);
return 0;
}
@@ -7355,11 +7598,11 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev,
if (!rtwvif_link)
return -EINVAL;
connected = rtw89_is_any_vif_connected_or_connecting(rtwdev);
connected = rtwdev->scan_info.connected;
opt.enable = enable;
opt.target_ch_mode = connected;
if (enable) {
ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif_link, connected);
ret = mac->add_chan_list(rtwdev, rtwvif_link);
if (ret)
goto out;
}
@@ -8719,6 +8962,47 @@ int rtw89_fw_h2c_ap_info_refcount(struct rtw89_dev *rtwdev, bool en)
return 0;
}
int rtw89_fw_h2c_mlo_link_cfg(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable)
{
struct rtw89_wait_info *wait = &rtwdev->mlo.wait;
struct rtw89_h2c_mlo_link_cfg *h2c;
u8 mac_id = rtwvif_link->mac_id;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
unsigned int cond;
int ret;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for mlo link cfg\n");
return -ENOMEM;
}
skb_put(skb, len);
h2c = (struct rtw89_h2c_mlo_link_cfg *)skb->data;
h2c->w0 = le32_encode_bits(mac_id, RTW89_H2C_MLO_LINK_CFG_W0_MACID) |
le32_encode_bits(enable, RTW89_H2C_MLO_LINK_CFG_W0_OPTION);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
H2C_CL_MLO,
H2C_FUNC_MLO_LINK_CFG, 0, 0,
len);
cond = RTW89_MLO_WAIT_COND(mac_id, H2C_FUNC_MLO_LINK_CFG);
ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
if (ret) {
rtw89_err(rtwdev, "mlo link cfg (%s link id %u) failed: %d\n",
str_enable_disable(enable), rtwvif_link->link_id, ret);
return ret;
}
return 0;
}
static bool __fw_txpwr_entry_zero_ext(const void *ext_ptr, u8 ext_len)
{
static const u8 zeros[U8_MAX] = {};
@@ -9106,6 +9390,26 @@ void rtw89_fw_load_tx_shape_lmt_ru(struct rtw89_tx_shape_lmt_ru_data *data)
}
}
static bool rtw89_fw_has_da_txpwr_table(struct rtw89_dev *rtwdev,
const struct rtw89_rfe_parms *parms)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
if (chip->support_bands & BIT(NL80211_BAND_2GHZ) &&
!(parms->rule_da_2ghz.lmt && parms->rule_da_2ghz.lmt_ru))
return false;
if (chip->support_bands & BIT(NL80211_BAND_5GHZ) &&
!(parms->rule_da_5ghz.lmt && parms->rule_da_5ghz.lmt_ru))
return false;
if (chip->support_bands & BIT(NL80211_BAND_6GHZ) &&
!(parms->rule_da_6ghz.lmt && parms->rule_da_6ghz.lmt_ru))
return false;
return true;
}
const struct rtw89_rfe_parms *
rtw89_load_rfe_data_from_fw(struct rtw89_dev *rtwdev,
const struct rtw89_rfe_parms *init)
@@ -9142,6 +9446,21 @@ rtw89_load_rfe_data_from_fw(struct rtw89_dev *rtwdev,
parms->rule_6ghz.lmt = &rfe_data->lmt_6ghz.v;
}
if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_2ghz.conf)) {
rtw89_fw_load_txpwr_lmt_2ghz(&rfe_data->da_lmt_2ghz);
parms->rule_da_2ghz.lmt = &rfe_data->da_lmt_2ghz.v;
}
if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_5ghz.conf)) {
rtw89_fw_load_txpwr_lmt_5ghz(&rfe_data->da_lmt_5ghz);
parms->rule_da_5ghz.lmt = &rfe_data->da_lmt_5ghz.v;
}
if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_6ghz.conf)) {
rtw89_fw_load_txpwr_lmt_6ghz(&rfe_data->da_lmt_6ghz);
parms->rule_da_6ghz.lmt = &rfe_data->da_lmt_6ghz.v;
}
if (rtw89_txpwr_conf_valid(&rfe_data->lmt_ru_2ghz.conf)) {
rtw89_fw_load_txpwr_lmt_ru_2ghz(&rfe_data->lmt_ru_2ghz);
parms->rule_2ghz.lmt_ru = &rfe_data->lmt_ru_2ghz.v;
@@ -9157,6 +9476,21 @@ rtw89_load_rfe_data_from_fw(struct rtw89_dev *rtwdev,
parms->rule_6ghz.lmt_ru = &rfe_data->lmt_ru_6ghz.v;
}
if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_ru_2ghz.conf)) {
rtw89_fw_load_txpwr_lmt_ru_2ghz(&rfe_data->da_lmt_ru_2ghz);
parms->rule_da_2ghz.lmt_ru = &rfe_data->da_lmt_ru_2ghz.v;
}
if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_ru_5ghz.conf)) {
rtw89_fw_load_txpwr_lmt_ru_5ghz(&rfe_data->da_lmt_ru_5ghz);
parms->rule_da_5ghz.lmt_ru = &rfe_data->da_lmt_ru_5ghz.v;
}
if (rtw89_txpwr_conf_valid(&rfe_data->da_lmt_ru_6ghz.conf)) {
rtw89_fw_load_txpwr_lmt_ru_6ghz(&rfe_data->da_lmt_ru_6ghz);
parms->rule_da_6ghz.lmt_ru = &rfe_data->da_lmt_ru_6ghz.v;
}
if (rtw89_txpwr_conf_valid(&rfe_data->tx_shape_lmt.conf)) {
rtw89_fw_load_tx_shape_lmt(&rfe_data->tx_shape_lmt);
parms->tx_shape.lmt = &rfe_data->tx_shape_lmt.v;
@@ -9167,5 +9501,7 @@ rtw89_load_rfe_data_from_fw(struct rtw89_dev *rtwdev,
parms->tx_shape.lmt_ru = &rfe_data->tx_shape_lmt_ru.v;
}
parms->has_da = rtw89_fw_has_da_txpwr_table(rtwdev, parms);
return parms;
}

View File

@@ -199,6 +199,7 @@ enum rtw89_fw_log_comp {
RTW89_FW_LOG_COMP_TWT,
RTW89_FW_LOG_COMP_RF,
RTW89_FW_LOG_COMP_MCC = 20,
RTW89_FW_LOG_COMP_MLO = 26,
RTW89_FW_LOG_COMP_SCAN = 28,
};
@@ -333,9 +334,9 @@ struct rtw89_fw_macid_pause_sleep_grp {
#define RTW89_SCAN_LIST_LIMIT_AX RTW89_SCAN_LIST_LIMIT(RTW89_MAC_CHINFO_SIZE)
#define RTW89_SCAN_LIST_LIMIT_BE RTW89_SCAN_LIST_LIMIT(RTW89_MAC_CHINFO_SIZE_BE)
#define RTW89_BCN_LOSS_CNT 10
#define RTW89_BCN_LOSS_CNT 60
struct rtw89_mac_chinfo {
struct rtw89_mac_chinfo_ax {
u8 period;
u8 dwell_time;
u8 central_ch;
@@ -1636,6 +1637,8 @@ struct rtw89_h2c_join_v1 {
#define RTW89_H2C_JOININFO_W1_IS_MLD BIT(3)
#define RTW89_H2C_JOININFO_W1_MAIN_MACID GENMASK(11, 4)
#define RTW89_H2C_JOININFO_W1_MLO_MODE BIT(12)
#define RTW89_H2C_JOININFO_MLO_MODE_MLMR 0
#define RTW89_H2C_JOININFO_MLO_MODE_MLSR 1
#define RTW89_H2C_JOININFO_W1_EMLSR_CAB BIT(13)
#define RTW89_H2C_JOININFO_W1_NSTR_EN BIT(14)
#define RTW89_H2C_JOININFO_W1_INIT_PWR_STATE BIT(15)
@@ -2863,6 +2866,13 @@ struct rtw89_h2c_fwips {
#define RTW89_H2C_FW_IPS_W0_MACID GENMASK(7, 0)
#define RTW89_H2C_FW_IPS_W0_ENABLE BIT(8)
struct rtw89_h2c_mlo_link_cfg {
__le32 w0;
};
#define RTW89_H2C_MLO_LINK_CFG_W0_MACID GENMASK(15, 0)
#define RTW89_H2C_MLO_LINK_CFG_W0_OPTION GENMASK(19, 16)
static inline void RTW89_SET_FWCMD_P2P_MACID(void *cmd, u32 val)
{
le32p_replace_bits((__le32 *)cmd, val, GENMASK(7, 0));
@@ -3562,6 +3572,7 @@ struct rtw89_c2h_done_ack {
#define RTW89_C2H_DONE_ACK_W2_CLASS GENMASK(7, 2)
#define RTW89_C2H_DONE_ACK_W2_FUNC GENMASK(15, 8)
#define RTW89_C2H_DONE_ACK_W2_H2C_RETURN GENMASK(23, 16)
#define RTW89_C2H_SCAN_DONE_ACK_RETURN GENMASK(5, 0)
#define RTW89_C2H_DONE_ACK_W2_H2C_SEQ GENMASK(31, 24)
#define RTW89_GET_MAC_C2H_REV_ACK_CAT(c2h) \
@@ -3620,6 +3631,19 @@ struct rtw89_c2h_ra_rpt {
#define RTW89_C2H_RA_RPT_W3_MD_SEL_B2 BIT(15)
#define RTW89_C2H_RA_RPT_W3_BW_B2 BIT(16)
struct rtw89_c2h_fw_scan_rpt {
struct rtw89_c2h_hdr hdr;
u8 phy_idx;
u8 band;
u8 center_ch;
u8 ofdm_pd_idx; /* in unit of 2 dBm */
#define PD_LOWER_BOUND_BASE 102
s8 cck_pd_idx;
u8 rsvd0;
u8 rsvd1;
u8 rsvd2;
} __packed;
/* For WiFi 6 chips:
* VHT, HE, HT-old: [6:4]: NSS, [3:0]: MCS
* HT-new: [6:5]: NA, [4:0]: MCS
@@ -3717,6 +3741,25 @@ static_assert(sizeof(struct rtw89_mac_mcc_tsf_rpt) <= RTW89_COMPLETION_BUF_SIZE)
#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_HIGH(c2h) \
le32_get_bits(*((const __le32 *)(c2h) + 4), GENMASK(31, 0))
struct rtw89_c2h_mlo_link_cfg_rpt {
struct rtw89_c2h_hdr hdr;
__le32 w2;
} __packed;
#define RTW89_C2H_MLO_LINK_CFG_RPT_W2_MACID GENMASK(15, 0)
#define RTW89_C2H_MLO_LINK_CFG_RPT_W2_STATUS GENMASK(19, 16)
enum rtw89_c2h_mlo_link_status {
RTW89_C2H_MLO_LINK_CFG_IDLE = 0,
RTW89_C2H_MLO_LINK_CFG_DONE = 1,
RTW89_C2H_MLO_LINK_CFG_ISSUE_NULL_FAIL = 2,
RTW89_C2H_MLO_LINK_CFG_TX_NULL_FAIL = 3,
RTW89_C2H_MLO_LINK_CFG_ROLE_NOT_EXIST = 4,
RTW89_C2H_MLO_LINK_CFG_NULL_1_TIMEOUT = 5,
RTW89_C2H_MLO_LINK_CFG_NULL_0_TIMEOUT = 6,
RTW89_C2H_MLO_LINK_CFG_RUNNING = 0xff,
};
struct rtw89_mac_mrc_tsf_rpt {
unsigned int num;
u64 tsfs[RTW89_MAC_MRC_MAX_REQ_TSF_NUM];
@@ -3813,7 +3856,8 @@ struct rtw89_h2c_bcnfltr {
#define RTW89_H2C_BCNFLTR_W0_MON_BCN BIT(1)
#define RTW89_H2C_BCNFLTR_W0_MON_EN BIT(2)
#define RTW89_H2C_BCNFLTR_W0_MODE GENMASK(4, 3)
#define RTW89_H2C_BCNFLTR_W0_BCN_LOSS_CNT GENMASK(11, 8)
#define RTW89_H2C_BCNFLTR_W0_BCN_LOSS_CNT_H3 GENMASK(7, 5)
#define RTW89_H2C_BCNFLTR_W0_BCN_LOSS_CNT_L4 GENMASK(11, 8)
#define RTW89_H2C_BCNFLTR_W0_RSSI_HYST GENMASK(15, 12)
#define RTW89_H2C_BCNFLTR_W0_RSSI_THRESHOLD GENMASK(23, 16)
#define RTW89_H2C_BCNFLTR_W0_MAC_ID GENMASK(31, 24)
@@ -3891,6 +3935,12 @@ enum rtw89_fw_element_id {
RTW89_FW_ELEMENT_ID_TXPWR_TRK = 18,
RTW89_FW_ELEMENT_ID_RFKLOG_FMT = 19,
RTW89_FW_ELEMENT_ID_REGD = 20,
RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_2GHZ = 21,
RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_5GHZ = 22,
RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_6GHZ = 23,
RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_2GHZ = 24,
RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_5GHZ = 25,
RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_6GHZ = 26,
RTW89_FW_ELEMENT_ID_NUM,
};
@@ -4229,6 +4279,26 @@ enum rtw89_mcc_h2c_func {
#define RTW89_MCC_WAIT_COND(group, func) \
((group) * NUM_OF_RTW89_MCC_H2C_FUNC + (func))
/* CLASS 20 - MLO */
#define H2C_CL_MLO 0x14
enum rtw89_mlo_h2c_func {
H2C_FUNC_MLO_TBL_CFG = 0x0,
H2C_FUNC_MLO_STA_CFG = 0x1,
H2C_FUNC_MLO_TTLM = 0x2,
H2C_FUNC_MLO_DM_CFG = 0x3,
H2C_FUNC_MLO_EMLSR_STA_CFG = 0x4,
H2C_FUNC_MLO_MCMLO_RELINK_DROP = 0x5,
H2C_FUNC_MLO_MCMLO_SN_SYNC = 0x6,
H2C_FUNC_MLO_RELINK = 0x7,
H2C_FUNC_MLO_LINK_CFG = 0x8,
H2C_FUNC_MLO_DM_DBG = 0x9,
NUM_OF_RTW89_MLO_H2C_FUNC,
};
#define RTW89_MLO_WAIT_COND(macid, func) \
((macid) * NUM_OF_RTW89_MLO_H2C_FUNC + (func))
/* CLASS 24 - MRC */
#define H2C_CL_MRC 0x18
enum rtw89_mrc_h2c_func {
@@ -4715,9 +4785,9 @@ int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev,
struct rtw89_mac_c2h_info *c2h_info);
int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable);
void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev);
void rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct ieee80211_scan_request *scan_req);
int rtw89_hw_scan_start(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
struct ieee80211_scan_request *scan_req);
void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link,
bool aborted);
@@ -4726,12 +4796,18 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev,
bool enable);
void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
int rtw89_hw_scan_prep_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
void rtw89_hw_scan_free_chan_list_ax(struct rtw89_dev *rtwdev);
int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected);
struct rtw89_vif_link *rtwvif_link);
int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
int rtw89_hw_scan_prep_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
void rtw89_hw_scan_free_chan_list_be(struct rtw89_dev *rtwdev);
int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected);
struct rtw89_vif_link *rtwvif_link);
int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev);
@@ -4800,6 +4876,8 @@ int rtw89_fw_h2c_mrc_sync(struct rtw89_dev *rtwdev,
int rtw89_fw_h2c_mrc_upd_duration(struct rtw89_dev *rtwdev,
const struct rtw89_fw_mrc_upd_duration_arg *arg);
int rtw89_fw_h2c_ap_info_refcount(struct rtw89_dev *rtwdev, bool en);
int rtw89_fw_h2c_mlo_link_cfg(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link,
bool enable);
static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev)
{

View File

@@ -4631,11 +4631,17 @@ static void rtw89_mac_port_tsf_sync_rand(struct rtw89_dev *rtwdev,
if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif_link == rtwvif_src)
return;
if (rtwvif_link->rand_tsf_done)
goto out;
/* adjust offset randomly to avoid beacon conflict */
offset = offset - offset / 4 + get_random_u32() % (offset / 2);
rtw89_mac_port_tsf_sync(rtwdev, rtwvif_link, rtwvif_src,
(*n_offset) * offset);
rtwvif_link->rand_tsf_done = true;
out:
(*n_offset)++;
}
@@ -4866,6 +4872,8 @@ void rtw89_mac_set_he_tb(struct rtw89_dev *rtwdev,
void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
{
rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif_link);
rtwvif_link->rand_tsf_done = false;
}
int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link)
@@ -4899,11 +4907,11 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb,
struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif;
struct rtw89_vif *rtwvif;
struct rtw89_chan new;
u32 last_chan = rtwdev->scan_info.last_chan_idx, report_tsf;
u16 actual_period, expect_period;
u8 reason, status, tx_fail, band;
u8 mac_idx, sw_def, fw_def;
u8 ver = U8_MAX;
u32 report_tsf;
u16 chan;
int ret;
@@ -4962,7 +4970,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb,
return;
if (rtwvif_link && rtwvif->scan_req &&
last_chan < rtwvif->scan_req->n_channels) {
!list_empty(&rtwdev->scan_info.chan_list)) {
ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true);
if (ret) {
rtw89_hw_scan_abort(rtwdev, rtwvif_link);
@@ -5017,7 +5025,8 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l
switch (type) {
case RTW89_BCN_FLTR_BEACON_LOSS:
if (!rtwdev->scanning && !rtwvif->offchan)
if (!rtwdev->scanning && !rtwvif->offchan &&
!rtwvif_link->noa_once.in_duration)
ieee80211_connection_loss(vif);
else
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true);
@@ -5110,12 +5119,14 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le
return;
case H2C_FUNC_ADD_SCANOFLD_CH:
cond = RTW89_SCANOFLD_WAIT_COND_ADD_CH;
h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN;
break;
case H2C_FUNC_SCANOFLD:
cond = RTW89_SCANOFLD_WAIT_COND_START;
break;
case H2C_FUNC_SCANOFLD_BE:
cond = RTW89_SCANOFLD_BE_WAIT_COND_START;
h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN;
break;
}
@@ -5398,6 +5409,27 @@ rtw89_mac_c2h_wow_aoac_rpt(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 le
rtw89_complete_cond(wait, RTW89_WOW_WAIT_COND_AOAC, &data);
}
static void
rtw89_mac_c2h_mlo_link_cfg_stat(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
{
const struct rtw89_c2h_mlo_link_cfg_rpt *c2h_rpt;
struct rtw89_wait_info *wait = &rtwdev->mlo.wait;
struct rtw89_completion_data data = {};
unsigned int cond;
u16 mac_id;
u8 status;
c2h_rpt = (const struct rtw89_c2h_mlo_link_cfg_rpt *)c2h->data;
mac_id = le32_get_bits(c2h_rpt->w2, RTW89_C2H_MLO_LINK_CFG_RPT_W2_MACID);
status = le32_get_bits(c2h_rpt->w2, RTW89_C2H_MLO_LINK_CFG_RPT_W2_STATUS);
data.err = status == RTW89_C2H_MLO_LINK_CFG_ROLE_NOT_EXIST ||
status == RTW89_C2H_MLO_LINK_CFG_RUNNING;
cond = RTW89_MLO_WAIT_COND(mac_id, H2C_FUNC_MLO_LINK_CFG);
rtw89_complete_cond(wait, cond, &data);
}
static void
rtw89_mac_c2h_mrc_status_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
{
@@ -5552,6 +5584,18 @@ void (* const rtw89_mac_c2h_mcc_handler[])(struct rtw89_dev *rtwdev,
[RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT] = rtw89_mac_c2h_mcc_status_rpt,
};
static
void (* const rtw89_mac_c2h_mlo_handler[])(struct rtw89_dev *rtwdev,
struct sk_buff *c2h, u32 len) = {
[RTW89_MAC_C2H_FUNC_MLO_GET_TBL] = NULL,
[RTW89_MAC_C2H_FUNC_MLO_EMLSR_TRANS_DONE] = NULL,
[RTW89_MAC_C2H_FUNC_MLO_EMLSR_STA_CFG_DONE] = NULL,
[RTW89_MAC_C2H_FUNC_MCMLO_RELINK_RPT] = NULL,
[RTW89_MAC_C2H_FUNC_MCMLO_SN_SYNC_RPT] = NULL,
[RTW89_MAC_C2H_FUNC_MLO_LINK_CFG_STAT] = rtw89_mac_c2h_mlo_link_cfg_stat,
[RTW89_MAC_C2H_FUNC_MLO_DM_DBG_DUMP] = NULL,
};
static
void (* const rtw89_mac_c2h_mrc_handler[])(struct rtw89_dev *rtwdev,
struct sk_buff *c2h, u32 len) = {
@@ -5621,6 +5665,8 @@ bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
}
case RTW89_MAC_C2H_CLASS_MCC:
return true;
case RTW89_MAC_C2H_CLASS_MLO:
return true;
case RTW89_MAC_C2H_CLASS_MRC:
return true;
case RTW89_MAC_C2H_CLASS_WOW:
@@ -5654,6 +5700,10 @@ void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
if (func < NUM_OF_RTW89_MAC_C2H_FUNC_MCC)
handler = rtw89_mac_c2h_mcc_handler[func];
break;
case RTW89_MAC_C2H_CLASS_MLO:
if (func < NUM_OF_RTW89_MAC_C2H_FUNC_MLO)
handler = rtw89_mac_c2h_mlo_handler[func];
break;
case RTW89_MAC_C2H_CLASS_MRC:
if (func < NUM_OF_RTW89_MAC_C2H_FUNC_MRC)
handler = rtw89_mac_c2h_mrc_handler[func];
@@ -6889,6 +6939,8 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
.is_txq_empty = mac_is_txq_empty_ax,
.prep_chan_list = rtw89_hw_scan_prep_chan_list_ax,
.free_chan_list = rtw89_hw_scan_free_chan_list_ax,
.add_chan_list = rtw89_hw_scan_add_chan_list_ax,
.add_chan_list_pno = rtw89_pno_scan_add_chan_list_ax,
.scan_offload = rtw89_fw_h2c_scan_offload_ax,

View File

@@ -370,6 +370,7 @@ enum rtw89_mac_mem_sel {
RTW89_MAC_MEM_TXD_FIFO_0_V1,
RTW89_MAC_MEM_TXD_FIFO_1_V1,
RTW89_MAC_MEM_WD_PAGE,
RTW89_MAC_MEM_MLD_TBL,
/* keep last */
RTW89_MAC_MEM_NUM,
@@ -427,6 +428,18 @@ enum rtw89_mac_c2h_mcc_func {
NUM_OF_RTW89_MAC_C2H_FUNC_MCC,
};
enum rtw89_mac_c2h_mlo_func {
RTW89_MAC_C2H_FUNC_MLO_GET_TBL = 0x0,
RTW89_MAC_C2H_FUNC_MLO_EMLSR_TRANS_DONE = 0x1,
RTW89_MAC_C2H_FUNC_MLO_EMLSR_STA_CFG_DONE = 0x2,
RTW89_MAC_C2H_FUNC_MCMLO_RELINK_RPT = 0x3,
RTW89_MAC_C2H_FUNC_MCMLO_SN_SYNC_RPT = 0x4,
RTW89_MAC_C2H_FUNC_MLO_LINK_CFG_STAT = 0x5,
RTW89_MAC_C2H_FUNC_MLO_DM_DBG_DUMP = 0x6,
NUM_OF_RTW89_MAC_C2H_FUNC_MLO,
};
enum rtw89_mac_c2h_mrc_func {
RTW89_MAC_C2H_FUNC_MRC_TSF_RPT = 0,
RTW89_MAC_C2H_FUNC_MRC_STATUS_RPT = 1,
@@ -453,6 +466,7 @@ enum rtw89_mac_c2h_class {
RTW89_MAC_C2H_CLASS_WOW = 0x3,
RTW89_MAC_C2H_CLASS_MCC = 0x4,
RTW89_MAC_C2H_CLASS_FWDBG = 0x5,
RTW89_MAC_C2H_CLASS_MLO = 0xc,
RTW89_MAC_C2H_CLASS_MRC = 0xe,
RTW89_MAC_C2H_CLASS_AP = 0x18,
RTW89_MAC_C2H_CLASS_MAX,
@@ -1031,8 +1045,11 @@ struct rtw89_mac_gen_def {
bool (*is_txq_empty)(struct rtw89_dev *rtwdev);
int (*prep_chan_list)(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
void (*free_chan_list)(struct rtw89_dev *rtwdev);
int (*add_chan_list)(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool connected);
struct rtw89_vif_link *rtwvif_link);
int (*add_chan_list_pno)(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link);
int (*scan_offload)(struct rtw89_dev *rtwdev,

View File

@@ -114,11 +114,14 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev,
wiphy_work_init(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work);
INIT_LIST_HEAD(&rtwvif_link->general_pkt_list);
rtw89_p2p_noa_once_init(rtwvif_link);
rtwvif_link->hit_rule = 0;
rtwvif_link->bcn_hit_cond = 0;
rtwvif_link->chanctx_assigned = false;
rtwvif_link->chanctx_idx = RTW89_CHANCTX_0;
rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT;
rtwvif_link->rand_tsf_done = false;
rcu_read_lock();
@@ -142,6 +145,8 @@ static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev,
wiphy_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->update_beacon_work);
rtw89_p2p_noa_once_deinit(rtwvif_link);
rtw89_leave_ps_mode(rtwdev);
rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, NULL, BTC_ROLE_STOP);
@@ -186,6 +191,7 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
if (!rtw89_rtwvif_in_list(rtwdev, rtwvif)) {
list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list);
INIT_LIST_HEAD(&rtwvif->mgnt_entry);
INIT_LIST_HEAD(&rtwvif->dlink_pool);
}
ether_addr_copy(rtwvif->mac_addr, vif->addr);
@@ -479,6 +485,8 @@ static int __rtw89_ops_sta_add(struct rtw89_dev *rtwdev,
int i;
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR;
/* for station mode, assign the mac_id from itself */
macid = rtw89_vif_get_main_macid(rtwvif);
} else {
@@ -494,6 +502,8 @@ static int __rtw89_ops_sta_add(struct rtw89_dev *rtwdev,
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
rtw89_core_txq_init(rtwdev, sta->txq[i]);
INIT_LIST_HEAD(&rtwsta->dlink_pool);
skb_queue_head_init(&rtwsta->roc_queue);
bitmap_zero(rtwsta->pairwise_sec_cam_map, RTW89_MAX_SEC_CAM_NUM);
@@ -1018,7 +1028,7 @@ static void rtw89_ops_sta_statistics(struct ieee80211_hw *hw,
struct rtw89_sta *rtwsta = sta_to_rtwsta(sta);
struct rtw89_sta_link *rtwsta_link;
rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0);
rtwsta_link = rtw89_get_designated_link(rtwsta);
if (unlikely(!rtwsta_link))
return;
@@ -1153,12 +1163,14 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw,
lockdep_assert_wiphy(hw->wiphy);
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
rtwvif_link = rtw89_get_designated_link(rtwvif);
if (unlikely(!rtwvif_link)) {
rtw89_err(rtwdev, "sw scan start: find no link on HW-0\n");
rtw89_err(rtwdev, "sw scan start: find no designated link\n");
return;
}
rtw89_leave_lps(rtwdev);
rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, false);
}
@@ -1171,9 +1183,9 @@ static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw,
lockdep_assert_wiphy(hw->wiphy);
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
rtwvif_link = rtw89_get_designated_link(rtwvif);
if (unlikely(!rtwvif_link)) {
rtw89_err(rtwdev, "sw scan complete: find no link on HW-0\n");
rtw89_err(rtwdev, "sw scan complete: find no designated link\n");
return;
}
@@ -1205,13 +1217,19 @@ static int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (rtwdev->scanning || rtwvif->offchan)
return -EBUSY;
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
rtwvif_link = rtw89_get_designated_link(rtwvif);
if (unlikely(!rtwvif_link)) {
rtw89_err(rtwdev, "hw scan: find no link on HW-0\n");
rtw89_err(rtwdev, "hw scan: find no designated link\n");
return -ENOLINK;
}
rtw89_hw_scan_start(rtwdev, rtwvif_link, req);
rtw89_leave_lps(rtwdev);
rtw89_leave_ips_by_hwflags(rtwdev);
ret = rtw89_hw_scan_start(rtwdev, rtwvif_link, req);
if (ret)
return ret;
ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true);
if (ret) {
rtw89_hw_scan_abort(rtwdev, rtwvif_link);
@@ -1236,9 +1254,9 @@ static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw,
if (!rtwdev->scanning)
return;
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
rtwvif_link = rtw89_get_designated_link(rtwvif);
if (unlikely(!rtwvif_link)) {
rtw89_err(rtwdev, "cancel hw scan: find no link on HW-0\n");
rtw89_err(rtwdev, "cancel hw scan: find no designated link\n");
return;
}

View File

@@ -29,6 +29,7 @@ static const u32 rtw89_mac_mem_base_addrs_be[RTW89_MAC_MEM_NUM] = {
[RTW89_MAC_MEM_CPU_LOCAL] = CPU_LOCAL_BASE_ADDR_BE,
[RTW89_MAC_MEM_BSSID_CAM] = BSSID_CAM_BASE_ADDR_BE,
[RTW89_MAC_MEM_WD_PAGE] = WD_PAGE_BASE_ADDR_BE,
[RTW89_MAC_MEM_MLD_TBL] = MLD_TBL_BASE_ADDR_BE,
};
static const struct rtw89_port_reg rtw89_port_base_be = {
@@ -2636,6 +2637,8 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = {
.is_txq_empty = mac_is_txq_empty_be,
.prep_chan_list = rtw89_hw_scan_prep_chan_list_be,
.free_chan_list = rtw89_hw_scan_free_chan_list_be,
.add_chan_list = rtw89_hw_scan_add_chan_list_be,
.add_chan_list_pno = rtw89_pno_scan_add_chan_list_be,
.scan_offload = rtw89_fw_h2c_scan_offload_be,

View File

@@ -228,7 +228,7 @@ int rtw89_pci_sync_skb_for_device_and_validate_rx_info(struct rtw89_dev *rtwdev,
struct sk_buff *skb)
{
struct rtw89_pci_rx_info *rx_info = RTW89_PCI_RX_SKB_CB(skb);
int rx_tag_retry = 100;
int rx_tag_retry = 1000;
int ret;
do {
@@ -3105,17 +3105,26 @@ static bool rtw89_pci_is_dac_compatible_bridge(struct rtw89_dev *rtwdev)
return false;
}
static void rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev)
static int rtw89_pci_cfg_dac(struct rtw89_dev *rtwdev, bool force)
{
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
struct pci_dev *pdev = rtwpci->pdev;
int ret;
u8 val;
if (!rtwpci->enable_dac)
return;
if (!rtwpci->enable_dac && !force)
return 0;
if (!rtw89_pci_chip_is_manual_dac(rtwdev))
return;
return 0;
rtw89_pci_config_byte_set(rtwdev, RTW89_PCIE_L1_CTRL, RTW89_PCIE_BIT_EN_64BITS);
/* Configure DAC only via PCI config API, not DBI interfaces */
ret = pci_read_config_byte(pdev, RTW89_PCIE_L1_CTRL, &val);
if (ret)
return ret;
val |= RTW89_PCIE_BIT_EN_64BITS;
return pci_write_config_byte(pdev, RTW89_PCIE_L1_CTRL, val);
}
static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
@@ -3133,13 +3142,16 @@ static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
}
if (!rtw89_pci_is_dac_compatible_bridge(rtwdev))
goto no_dac;
goto try_dac_done;
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
if (!ret) {
rtwpci->enable_dac = true;
rtw89_pci_cfg_dac(rtwdev);
} else {
ret = rtw89_pci_cfg_dac(rtwdev, true);
if (!ret) {
rtwpci->enable_dac = true;
goto try_dac_done;
}
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (ret) {
rtw89_err(rtwdev,
@@ -3147,7 +3159,7 @@ static int rtw89_pci_setup_mapping(struct rtw89_dev *rtwdev,
goto err_release_regions;
}
}
no_dac:
try_dac_done:
resource_len = pci_resource_len(pdev, bar_id);
rtwpci->mmap = pci_iomap(pdev, bar_id, resource_len);
@@ -4302,7 +4314,7 @@ static void rtw89_pci_l2_hci_ldo(struct rtw89_dev *rtwdev)
void rtw89_pci_basic_cfg(struct rtw89_dev *rtwdev, bool resume)
{
if (resume)
rtw89_pci_cfg_dac(rtwdev);
rtw89_pci_cfg_dac(rtwdev, false);
rtw89_pci_disable_eq(rtwdev);
rtw89_pci_filter_out(rtwdev);

View File

@@ -2034,19 +2034,10 @@ static s8 rtw89_phy_ant_gain_query(struct rtw89_dev *rtwdev,
ant_gain->offset[path][subband_h]);
}
static s8 rtw89_phy_ant_gain_offset(struct rtw89_dev *rtwdev, u8 band, u32 center_freq)
static s8 rtw89_phy_ant_gain_offset(struct rtw89_dev *rtwdev, u32 center_freq)
{
struct rtw89_ant_gain_info *ant_gain = &rtwdev->ant_gain;
const struct rtw89_chip_info *chip = rtwdev->chip;
u8 regd = rtw89_regd_get(rtwdev, band);
s8 offset_patha, offset_pathb;
if (!chip->support_ant_gain)
return 0;
if (ant_gain->block_country || !(ant_gain->regd_enabled & BIT(regd)))
return 0;
offset_patha = rtw89_phy_ant_gain_query(rtwdev, RF_PATH_A, center_freq);
offset_pathb = rtw89_phy_ant_gain_query(rtwdev, RF_PATH_B, center_freq);
@@ -2056,18 +2047,31 @@ static s8 rtw89_phy_ant_gain_offset(struct rtw89_dev *rtwdev, u8 band, u32 cente
return max(offset_patha, offset_pathb);
}
static bool rtw89_can_apply_ant_gain(struct rtw89_dev *rtwdev, u8 band)
{
const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms;
struct rtw89_ant_gain_info *ant_gain = &rtwdev->ant_gain;
const struct rtw89_chip_info *chip = rtwdev->chip;
u8 regd = rtw89_regd_get(rtwdev, band);
if (!chip->support_ant_gain)
return false;
if (ant_gain->block_country || !(ant_gain->regd_enabled & BIT(regd)))
return false;
if (!rfe_parms->has_da)
return false;
return true;
}
s16 rtw89_phy_ant_gain_pwr_offset(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan)
{
struct rtw89_ant_gain_info *ant_gain = &rtwdev->ant_gain;
const struct rtw89_chip_info *chip = rtwdev->chip;
u8 regd = rtw89_regd_get(rtwdev, chan->band_type);
s8 offset_patha, offset_pathb;
if (!chip->support_ant_gain)
return 0;
if (ant_gain->block_country || !(ant_gain->regd_enabled & BIT(regd)))
if (!rtw89_can_apply_ant_gain(rtwdev, chan->band_type))
return 0;
if (RTW89_CHK_FW_FEATURE(NO_POWER_DIFFERENCE, &rtwdev->fw))
@@ -2083,14 +2087,10 @@ EXPORT_SYMBOL(rtw89_phy_ant_gain_pwr_offset);
int rtw89_print_ant_gain(struct rtw89_dev *rtwdev, char *buf, size_t bufsz,
const struct rtw89_chan *chan)
{
struct rtw89_ant_gain_info *ant_gain = &rtwdev->ant_gain;
const struct rtw89_chip_info *chip = rtwdev->chip;
u8 regd = rtw89_regd_get(rtwdev, chan->band_type);
char *p = buf, *end = buf + bufsz;
s8 offset_patha, offset_pathb;
if (!(chip->support_ant_gain && (ant_gain->regd_enabled & BIT(regd))) ||
ant_gain->block_country) {
if (!rtw89_can_apply_ant_gain(rtwdev, chan->band_type)) {
p += scnprintf(p, end - p, "no DAG is applied\n");
goto out;
}
@@ -2255,20 +2255,31 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
u8 bw, u8 ntx, u8 rs, u8 bf, u8 ch)
{
const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms;
const struct rtw89_txpwr_rule_2ghz *rule_da_2ghz = &rfe_parms->rule_da_2ghz;
const struct rtw89_txpwr_rule_5ghz *rule_da_5ghz = &rfe_parms->rule_da_5ghz;
const struct rtw89_txpwr_rule_6ghz *rule_da_6ghz = &rfe_parms->rule_da_6ghz;
const struct rtw89_txpwr_rule_2ghz *rule_2ghz = &rfe_parms->rule_2ghz;
const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz;
const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz;
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
bool has_ant_gain = rtw89_can_apply_ant_gain(rtwdev, band);
u32 freq = ieee80211_channel_to_frequency(ch, nl_band);
u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch);
s8 lmt = 0, da_lmt = S8_MAX, sar, offset = 0;
u8 regd = rtw89_regd_get(rtwdev, band);
u8 reg6 = regulatory->reg_6ghz_power;
s8 lmt = 0, sar, offset;
struct rtw89_sar_parm sar_parm = {
.center_freq = freq,
.ntx = ntx,
};
s8 cstr;
switch (band) {
case RTW89_BAND_2G:
if (has_ant_gain)
da_lmt = (*rule_da_2ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
lmt = (*rule_2ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
if (lmt)
break;
@@ -2276,6 +2287,9 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
lmt = (*rule_2ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx];
break;
case RTW89_BAND_5G:
if (has_ant_gain)
da_lmt = (*rule_da_5ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
lmt = (*rule_5ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx];
if (lmt)
break;
@@ -2283,6 +2297,9 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
lmt = (*rule_5ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx];
break;
case RTW89_BAND_6G:
if (has_ant_gain)
da_lmt = (*rule_da_6ghz->lmt)[bw][ntx][rs][bf][regd][reg6][ch_idx];
lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][regd][reg6][ch_idx];
if (lmt)
break;
@@ -2296,9 +2313,12 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band,
return 0;
}
offset = rtw89_phy_ant_gain_offset(rtwdev, band, freq);
lmt = rtw89_phy_txpwr_rf_to_mac(rtwdev, lmt + offset);
sar = rtw89_query_sar(rtwdev, freq);
da_lmt = da_lmt ?: S8_MAX;
if (da_lmt != S8_MAX)
offset = rtw89_phy_ant_gain_offset(rtwdev, freq);
lmt = rtw89_phy_txpwr_rf_to_mac(rtwdev, min(lmt + offset, da_lmt));
sar = rtw89_query_sar(rtwdev, &sar_parm);
cstr = rtw89_phy_get_tpe_constraint(rtwdev, band);
return min3(lmt, sar, cstr);
@@ -2515,20 +2535,31 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
u8 ru, u8 ntx, u8 ch)
{
const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms;
const struct rtw89_txpwr_rule_2ghz *rule_da_2ghz = &rfe_parms->rule_da_2ghz;
const struct rtw89_txpwr_rule_5ghz *rule_da_5ghz = &rfe_parms->rule_da_5ghz;
const struct rtw89_txpwr_rule_6ghz *rule_da_6ghz = &rfe_parms->rule_da_6ghz;
const struct rtw89_txpwr_rule_2ghz *rule_2ghz = &rfe_parms->rule_2ghz;
const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz;
const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz;
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band);
bool has_ant_gain = rtw89_can_apply_ant_gain(rtwdev, band);
u32 freq = ieee80211_channel_to_frequency(ch, nl_band);
u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch);
s8 lmt_ru = 0, da_lmt_ru = S8_MAX, sar, offset = 0;
u8 regd = rtw89_regd_get(rtwdev, band);
u8 reg6 = regulatory->reg_6ghz_power;
s8 lmt_ru = 0, sar, offset;
struct rtw89_sar_parm sar_parm = {
.center_freq = freq,
.ntx = ntx,
};
s8 cstr;
switch (band) {
case RTW89_BAND_2G:
if (has_ant_gain)
da_lmt_ru = (*rule_da_2ghz->lmt_ru)[ru][ntx][regd][ch_idx];
lmt_ru = (*rule_2ghz->lmt_ru)[ru][ntx][regd][ch_idx];
if (lmt_ru)
break;
@@ -2536,6 +2567,9 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
lmt_ru = (*rule_2ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx];
break;
case RTW89_BAND_5G:
if (has_ant_gain)
da_lmt_ru = (*rule_da_5ghz->lmt_ru)[ru][ntx][regd][ch_idx];
lmt_ru = (*rule_5ghz->lmt_ru)[ru][ntx][regd][ch_idx];
if (lmt_ru)
break;
@@ -2543,6 +2577,9 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
lmt_ru = (*rule_5ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx];
break;
case RTW89_BAND_6G:
if (has_ant_gain)
da_lmt_ru = (*rule_da_6ghz->lmt_ru)[ru][ntx][regd][reg6][ch_idx];
lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][regd][reg6][ch_idx];
if (lmt_ru)
break;
@@ -2556,9 +2593,12 @@ s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band,
return 0;
}
offset = rtw89_phy_ant_gain_offset(rtwdev, band, freq);
lmt_ru = rtw89_phy_txpwr_rf_to_mac(rtwdev, lmt_ru + offset);
sar = rtw89_query_sar(rtwdev, freq);
da_lmt_ru = da_lmt_ru ?: S8_MAX;
if (da_lmt_ru != S8_MAX)
offset = rtw89_phy_ant_gain_offset(rtwdev, freq);
lmt_ru = rtw89_phy_txpwr_rf_to_mac(rtwdev, min(lmt_ru + offset, da_lmt_ru));
sar = rtw89_query_sar(rtwdev, &sar_parm);
cstr = rtw89_phy_get_tpe_constraint(rtwdev, band);
return min3(lmt_ru, sar, cstr);
@@ -3015,6 +3055,35 @@ void (* const rtw89_phy_c2h_ra_handler[])(struct rtw89_dev *rtwdev,
[RTW89_PHY_C2H_FUNC_TXSTS] = NULL,
};
static void
rtw89_phy_c2h_lowrt_rty(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
{
}
static void
rtw89_phy_c2h_fw_scan_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
{
const struct rtw89_c2h_fw_scan_rpt *c2h_rpt =
(const struct rtw89_c2h_fw_scan_rpt *)c2h->data;
rtw89_debug(rtwdev, RTW89_DBG_DIG,
"%s: band: %u, op_chan: %u, PD_low_bd(ofdm, cck): (-%d, %d), phy_idx: %u\n",
__func__, c2h_rpt->band, c2h_rpt->center_ch,
PD_LOWER_BOUND_BASE - (c2h_rpt->ofdm_pd_idx << 1),
c2h_rpt->cck_pd_idx, c2h_rpt->phy_idx);
}
static
void (* const rtw89_phy_c2h_dm_handler[])(struct rtw89_dev *rtwdev,
struct sk_buff *c2h, u32 len) = {
[RTW89_PHY_C2H_DM_FUNC_FW_TEST] = NULL,
[RTW89_PHY_C2H_DM_FUNC_FW_TRIG_TX_RPT] = NULL,
[RTW89_PHY_C2H_DM_FUNC_SIGB] = NULL,
[RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY] = rtw89_phy_c2h_lowrt_rty,
[RTW89_PHY_C2H_DM_FUNC_MCC_DIG] = NULL,
[RTW89_PHY_C2H_DM_FUNC_FW_SCAN] = rtw89_phy_c2h_fw_scan_rpt,
};
static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
enum rtw89_phy_c2h_rfk_log_func func,
void *content, u16 len)
@@ -3550,9 +3619,9 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
handler = rtw89_phy_c2h_rfk_report_handler[func];
break;
case RTW89_PHY_C2H_CLASS_DM:
if (func == RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY)
return;
fallthrough;
if (func < ARRAY_SIZE(rtw89_phy_c2h_dm_handler))
handler = rtw89_phy_c2h_dm_handler[func];
break;
default:
rtw89_info(rtwdev, "PHY c2h class %d not support\n", class);
return;

View File

@@ -164,6 +164,7 @@ enum rtw89_phy_c2h_dm_func {
RTW89_PHY_C2H_DM_FUNC_SIGB,
RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY,
RTW89_PHY_C2H_DM_FUNC_MCC_DIG,
RTW89_PHY_C2H_DM_FUNC_FW_SCAN = 0xc,
RTW89_PHY_C2H_DM_FUNC_NUM,
};
@@ -935,6 +936,20 @@ static inline s8 rtw89_phy_txpwr_dbm_to_mac(struct rtw89_dev *rtwdev, s8 dbm)
return clamp_t(s16, dbm << chip->txpwr_factor_mac, -64, 63);
}
static inline s16 rtw89_phy_txpwr_mac_to_rf(struct rtw89_dev *rtwdev, s8 txpwr_mac)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
return txpwr_mac << (chip->txpwr_factor_rf - chip->txpwr_factor_mac);
}
static inline s16 rtw89_phy_txpwr_mac_to_bb(struct rtw89_dev *rtwdev, s8 txpwr_mac)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
return txpwr_mac << (chip->txpwr_factor_bb - chip->txpwr_factor_mac);
}
void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link);
void rtw89_phy_ra_update(struct rtw89_dev *rtwdev);
void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta,

View File

@@ -362,7 +362,7 @@ static void rtw89_phy_bb_wrap_force_cr_init(struct rtw89_dev *rtwdev,
rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_RU_ENON, 0);
rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_RU_ON, 0);
addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_FORCE_MACID, mac_idx);
rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_MACID_ON, 0);
rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_MACID_ALL, 0);
addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_COEX_CTRL, mac_idx);
rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_COEX_ON, 0);
addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_RATE_CTRL, mac_idx);

View File

@@ -382,3 +382,150 @@ u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data)
tail = ie->noa_desc + setter->noa_count;
return tail - *data;
}
static void rtw89_ps_noa_once_set_work(struct wiphy *wiphy, struct wiphy_work *work)
{
struct rtw89_ps_noa_once_handler *noa_once =
container_of(work, struct rtw89_ps_noa_once_handler, set_work.work);
lockdep_assert_wiphy(wiphy);
noa_once->in_duration = true;
}
static void rtw89_ps_noa_once_clr_work(struct wiphy *wiphy, struct wiphy_work *work)
{
struct rtw89_ps_noa_once_handler *noa_once =
container_of(work, struct rtw89_ps_noa_once_handler, clr_work.work);
struct rtw89_vif_link *rtwvif_link =
container_of(noa_once, struct rtw89_vif_link, noa_once);
struct rtw89_dev *rtwdev = rtwvif_link->rtwvif->rtwdev;
lockdep_assert_wiphy(wiphy);
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true);
noa_once->in_duration = false;
}
void rtw89_p2p_noa_once_init(struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_ps_noa_once_handler *noa_once = &rtwvif_link->noa_once;
noa_once->in_duration = false;
noa_once->tsf_begin = 0;
noa_once->tsf_end = 0;
wiphy_delayed_work_init(&noa_once->set_work, rtw89_ps_noa_once_set_work);
wiphy_delayed_work_init(&noa_once->clr_work, rtw89_ps_noa_once_clr_work);
}
static void rtw89_p2p_noa_once_cancel(struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_ps_noa_once_handler *noa_once = &rtwvif_link->noa_once;
struct rtw89_dev *rtwdev = rtwvif_link->rtwvif->rtwdev;
struct wiphy *wiphy = rtwdev->hw->wiphy;
wiphy_delayed_work_cancel(wiphy, &noa_once->set_work);
wiphy_delayed_work_cancel(wiphy, &noa_once->clr_work);
}
void rtw89_p2p_noa_once_deinit(struct rtw89_vif_link *rtwvif_link)
{
rtw89_p2p_noa_once_cancel(rtwvif_link);
rtw89_p2p_noa_once_init(rtwvif_link);
}
void rtw89_p2p_noa_once_recalc(struct rtw89_vif_link *rtwvif_link)
{
struct rtw89_ps_noa_once_handler *noa_once = &rtwvif_link->noa_once;
struct rtw89_dev *rtwdev = rtwvif_link->rtwvif->rtwdev;
const struct ieee80211_p2p_noa_desc *noa_desc;
struct wiphy *wiphy = rtwdev->hw->wiphy;
struct ieee80211_bss_conf *bss_conf;
u64 tsf_begin = U64_MAX, tsf_end;
u64 set_delay_us = 0;
u64 clr_delay_us = 0;
u32 start_time;
u32 interval;
u32 duration;
u64 tsf;
int ret;
int i;
lockdep_assert_wiphy(wiphy);
ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf);
if (ret) {
rtw89_warn(rtwdev, "%s: failed to get tsf\n", __func__);
return;
}
rcu_read_lock();
bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true);
for (i = 0; i < ARRAY_SIZE(bss_conf->p2p_noa_attr.desc); i++) {
bool first = tsf_begin == U64_MAX;
u64 tmp;
noa_desc = &bss_conf->p2p_noa_attr.desc[i];
if (noa_desc->count == 0 || noa_desc->count == 255)
continue;
start_time = le32_to_cpu(noa_desc->start_time);
interval = le32_to_cpu(noa_desc->interval);
duration = le32_to_cpu(noa_desc->duration);
if (unlikely(duration == 0 ||
(noa_desc->count > 1 && interval == 0)))
continue;
tmp = start_time + interval * (noa_desc->count - 1) + duration;
tmp = (tsf & GENMASK_ULL(63, 32)) + tmp;
if (unlikely(tmp <= tsf))
continue;
tsf_end = first ? tmp : max(tsf_end, tmp);
tmp = (tsf & GENMASK_ULL(63, 32)) | start_time;
tsf_begin = first ? tmp : min(tsf_begin, tmp);
}
rcu_read_unlock();
if (tsf_begin == U64_MAX)
return;
rtw89_p2p_noa_once_cancel(rtwvif_link);
if (noa_once->tsf_end > tsf) {
tsf_begin = min(tsf_begin, noa_once->tsf_begin);
tsf_end = max(tsf_end, noa_once->tsf_end);
}
clr_delay_us = min_t(u64, tsf_end - tsf, UINT_MAX);
if (tsf_begin <= tsf) {
noa_once->in_duration = true;
goto out;
}
set_delay_us = tsf_begin - tsf;
if (unlikely(set_delay_us > UINT_MAX)) {
rtw89_warn(rtwdev, "%s: unhandled begin\n", __func__);
set_delay_us = 0;
clr_delay_us = 0;
rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true);
noa_once->in_duration = false;
}
out:
if (set_delay_us)
wiphy_delayed_work_queue(wiphy, &noa_once->set_work,
usecs_to_jiffies(set_delay_us));
if (clr_delay_us)
wiphy_delayed_work_queue(wiphy, &noa_once->clr_work,
usecs_to_jiffies(clr_delay_us));
noa_once->tsf_begin = tsf_begin;
noa_once->tsf_end = tsf_end;
}

View File

@@ -22,6 +22,9 @@ void rtw89_p2p_noa_renew(struct rtw89_vif_link *rtwvif_link);
void rtw89_p2p_noa_append(struct rtw89_vif_link *rtwvif_link,
const struct ieee80211_p2p_noa_desc *desc);
u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data);
void rtw89_p2p_noa_once_init(struct rtw89_vif_link *rtwvif_link);
void rtw89_p2p_noa_once_deinit(struct rtw89_vif_link *rtwvif_link);
void rtw89_p2p_noa_once_recalc(struct rtw89_vif_link *rtwvif_link);
static inline void rtw89_leave_ips_by_hwflags(struct rtw89_dev *rtwdev)
{

View File

@@ -7601,7 +7601,15 @@
#define B_BE_PWR_FORCE_RU_ON BIT(18)
#define B_BE_PWR_FORCE_RU_ENON BIT(28)
#define R_BE_PWR_FORCE_MACID 0x11A48
#define B_BE_PWR_FORCE_MACID_ON BIT(9)
#define B_BE_PWR_FORCE_MACID_DBM_ON BIT(9)
#define B_BE_PWR_FORCE_MACID_DBM_VAL GENMASK(17, 10)
#define B_BE_PWR_FORCE_MACID_EN_VAL BIT(18)
#define B_BE_PWR_FORCE_MACID_EN_ON BIT(19)
#define B_BE_PWR_FORCE_MACID_ALL \
(B_BE_PWR_FORCE_MACID_DBM_ON | \
B_BE_PWR_FORCE_MACID_DBM_VAL | \
B_BE_PWR_FORCE_MACID_EN_VAL | \
B_BE_PWR_FORCE_MACID_EN_ON)
#define R_BE_PWR_REG_CTRL 0x11A50
#define B_BE_PWR_BT_EN BIT(23)
@@ -8737,8 +8745,10 @@
#define B_DPD_GDIS BIT(13)
#define B_IQK_RFC_ON BIT(1)
#define R_TXPWRB 0x56CC
#define R_P1_TXPWRB 0x76CC
#define B_TXPWRB_ON BIT(28)
#define B_TXPWRB_VAL GENMASK(27, 19)
#define B_TXPWRB_MAX GENMASK(8, 0)
#define R_DPD_OFT_EN 0x5800
#define B_DPD_OFT_EN BIT(28)
#define B_DPD_TSSI_CW GENMASK(26, 18)
@@ -9360,6 +9370,9 @@
#define R_TSSI_PWR_P0 0xE610
#define R_TSSI_PWR_P1 0xE710
#define B_TSSI_CONT_EN BIT(3)
#define R_P0_TXPWRB_BE 0xE61C
#define R_P1_TXPWRB_BE 0xE71C
#define B_TXPWRB_MAX_BE GENMASK(20, 12)
#define R_TSSI_MAP_OFST_P0 0xE620
#define R_TSSI_MAP_OFST_P1 0xE720
#define B_TSSI_MAP_OFST_OFDM GENMASK(17, 9)

View File

@@ -588,6 +588,38 @@ static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy)
kfree(sband);
}
#define RTW89_DEF_REGD_STR(regd) \
[RTW89_ ## regd] = #regd
static const char * const rtw89_regd_string[] = {
RTW89_DEF_REGD_STR(WW),
RTW89_DEF_REGD_STR(ETSI),
RTW89_DEF_REGD_STR(FCC),
RTW89_DEF_REGD_STR(MKK),
RTW89_DEF_REGD_STR(NA),
RTW89_DEF_REGD_STR(IC),
RTW89_DEF_REGD_STR(KCC),
RTW89_DEF_REGD_STR(ACMA),
RTW89_DEF_REGD_STR(NCC),
RTW89_DEF_REGD_STR(MEXICO),
RTW89_DEF_REGD_STR(CHILE),
RTW89_DEF_REGD_STR(UKRAINE),
RTW89_DEF_REGD_STR(CN),
RTW89_DEF_REGD_STR(QATAR),
RTW89_DEF_REGD_STR(UK),
RTW89_DEF_REGD_STR(THAILAND),
};
static_assert(ARRAY_SIZE(rtw89_regd_string) == RTW89_REGD_NUM);
const char *rtw89_regd_get_string(enum rtw89_regulation_type regd)
{
if (regd < 0 || regd >= RTW89_REGD_NUM)
return "(unknown)";
return rtw89_regd_string[regd];
}
int rtw89_regd_setup(struct rtw89_dev *rtwdev)
{
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
@@ -604,6 +636,7 @@ int rtw89_regd_setup(struct rtw89_dev *rtwdev)
}
regulatory->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT;
regulatory->txpwr_uk_follow_etsi = true;
if (!wiphy)
return -EINVAL;
@@ -726,11 +759,22 @@ static void rtw89_regd_apply_policy_tas(struct rtw89_dev *rtwdev)
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
const struct rtw89_regd *regd = regulatory->regd;
struct rtw89_tas_info *tas = &rtwdev->tas;
u8 tas_country;
if (!tas->enable)
return;
tas->block_regd = !test_bit(RTW89_REGD_FUNC_TAS, regd->func_bitmap);
if (memcmp("US", regd->alpha2, 2) == 0)
tas_country = RTW89_ACPI_CONF_TAS_US;
else if (memcmp("CA", regd->alpha2, 2) == 0)
tas_country = RTW89_ACPI_CONF_TAS_CA;
else if (memcmp("KR", regd->alpha2, 2) == 0)
tas_country = RTW89_ACPI_CONF_TAS_KR;
else
tas_country = RTW89_ACPI_CONF_TAS_OTHERS;
tas->block_regd = !(tas->enabled_countries & tas_country &&
test_bit(RTW89_REGD_FUNC_TAS, regd->func_bitmap));
}
static void rtw89_regd_apply_policy_ant_gain(struct rtw89_dev *rtwdev)

View File

@@ -2499,12 +2499,14 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
.support_unii4 = true,
.support_ant_gain = false,
.support_tas = false,
.support_sar_by_ant = false,
.ul_tb_waveform_ctrl = true,
.ul_tb_pwr_diff = false,
.rx_freq_frome_ie = true,
.hw_sec_hdr = false,
.hw_mgmt_tx_encrypt = false,
.hw_tkip_crypto = false,
.hw_mlo_bmc_crypto = false,
.rf_path_num = 1,
.tx_nss = 1,
.rx_nss = 1,

View File

@@ -2217,12 +2217,14 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.support_unii4 = false,
.support_ant_gain = false,
.support_tas = false,
.support_sar_by_ant = false,
.ul_tb_waveform_ctrl = false,
.ul_tb_pwr_diff = false,
.rx_freq_frome_ie = true,
.hw_sec_hdr = false,
.hw_mgmt_tx_encrypt = false,
.hw_tkip_crypto = false,
.hw_mlo_bmc_crypto = false,
.rf_path_num = 2,
.tx_nss = 2,
.rx_nss = 2,

View File

@@ -853,12 +853,14 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
.support_unii4 = true,
.support_ant_gain = true,
.support_tas = false,
.support_sar_by_ant = true,
.ul_tb_waveform_ctrl = true,
.ul_tb_pwr_diff = false,
.rx_freq_frome_ie = true,
.hw_sec_hdr = false,
.hw_mgmt_tx_encrypt = false,
.hw_tkip_crypto = false,
.hw_mlo_bmc_crypto = false,
.rf_path_num = 2,
.tx_nss = 2,
.rx_nss = 2,

View File

@@ -8,6 +8,7 @@
#include "phy.h"
#include "reg.h"
#include "rtw8852b_common.h"
#include "sar.h"
#include "util.h"
static const struct rtw89_reg3_def rtw8852bx_pmac_ht20_mcs7_tbl[] = {
@@ -1234,6 +1235,7 @@ static u32 rtw8852bx_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev,
u32_encode_bits(ref, B_DPD_REF);
}
/* @pwr_ofst (unit: 1/8 dBm): power of path A minus power of path B */
static void rtw8852bx_set_txpwr_ref(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy_idx, s16 pwr_ofst)
{
@@ -1336,6 +1338,27 @@ static void rtw8852bx_set_tx_shape(struct rtw89_dev *rtwdev,
tx_shape_ofdm);
}
static s16 rtw8852bx_get_txpwr_sar_diff(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan)
{
struct rtw89_sar_parm sar_parm = {
.center_freq = chan->freq,
.force_path = true,
};
s16 sar_bb_a, sar_bb_b;
s8 sar_mac;
sar_parm.path = RF_PATH_A;
sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
sar_bb_a = rtw89_phy_txpwr_mac_to_bb(rtwdev, sar_mac);
sar_parm.path = RF_PATH_B;
sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
sar_bb_b = rtw89_phy_txpwr_mac_to_bb(rtwdev, sar_mac);
return sar_bb_a - sar_bb_b;
}
static void rtw8852bx_set_txpwr_diff(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx)
@@ -1343,6 +1366,7 @@ static void rtw8852bx_set_txpwr_diff(struct rtw89_dev *rtwdev,
s16 pwr_ofst;
pwr_ofst = rtw89_phy_ant_gain_pwr_offset(rtwdev, chan);
pwr_ofst += rtw8852bx_get_txpwr_sar_diff(rtwdev, chan);
rtw8852bx_set_txpwr_ref(rtwdev, phy_idx, pwr_ofst);
}

View File

@@ -786,12 +786,14 @@ const struct rtw89_chip_info rtw8852bt_chip_info = {
.support_unii4 = true,
.support_ant_gain = true,
.support_tas = false,
.support_sar_by_ant = true,
.ul_tb_waveform_ctrl = true,
.ul_tb_pwr_diff = false,
.rx_freq_frome_ie = true,
.hw_sec_hdr = false,
.hw_mgmt_tx_encrypt = false,
.hw_tkip_crypto = true,
.hw_mlo_bmc_crypto = false,
.rf_path_num = 2,
.tx_nss = 2,
.rx_nss = 2,

View File

@@ -15,7 +15,7 @@
#include "sar.h"
#include "util.h"
#define RTW8852C_FW_FORMAT_MAX 1
#define RTW8852C_FW_FORMAT_MAX 2
#define RTW8852C_FW_BASENAME "rtw89/rtw8852c_fw"
#define RTW8852C_MODULE_FIRMWARE \
RTW8852C_FW_BASENAME "-" __stringify(RTW8852C_FW_FORMAT_MAX) ".bin"
@@ -2079,6 +2079,31 @@ static void rtw8852c_set_txpwr_diff(struct rtw89_dev *rtwdev,
rtw8852c_set_txpwr_ref(rtwdev, phy_idx, pwr_ofst);
}
static void rtw8852c_set_txpwr_sar_diff(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx)
{
struct rtw89_sar_parm sar_parm = {
.center_freq = chan->freq,
.force_path = true,
};
s16 sar_rf;
s8 sar_mac;
if (phy_idx != RTW89_PHY_0)
return;
sar_parm.path = RF_PATH_A;
sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
sar_rf = rtw89_phy_txpwr_mac_to_rf(rtwdev, sar_mac);
rtw89_phy_write32_mask(rtwdev, R_TXPWRB, B_TXPWRB_MAX, sar_rf);
sar_parm.path = RF_PATH_B;
sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
sar_rf = rtw89_phy_txpwr_mac_to_rf(rtwdev, sar_mac);
rtw89_phy_write32_mask(rtwdev, R_P1_TXPWRB, B_TXPWRB_MAX, sar_rf);
}
static void rtw8852c_set_txpwr(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx)
@@ -2089,6 +2114,7 @@ static void rtw8852c_set_txpwr(struct rtw89_dev *rtwdev,
rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx);
rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx);
rtw8852c_set_txpwr_diff(rtwdev, chan, phy_idx);
rtw8852c_set_txpwr_sar_diff(rtwdev, chan, phy_idx);
}
static void rtw8852c_set_txpwr_ctrl(struct rtw89_dev *rtwdev,
@@ -3014,12 +3040,14 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.support_unii4 = true,
.support_ant_gain = true,
.support_tas = true,
.support_sar_by_ant = true,
.ul_tb_waveform_ctrl = false,
.ul_tb_pwr_diff = true,
.rx_freq_frome_ie = false,
.hw_sec_hdr = true,
.hw_mgmt_tx_encrypt = true,
.hw_tkip_crypto = true,
.hw_mlo_bmc_crypto = false,
.rf_path_num = 2,
.tx_nss = 2,
.rx_nss = 2,

View File

@@ -12,6 +12,7 @@
#include "reg.h"
#include "rtw8922a.h"
#include "rtw8922a_rfk.h"
#include "sar.h"
#include "util.h"
#define RTW8922A_FW_FORMAT_MAX 3
@@ -2070,7 +2071,8 @@ static void __rtw8922a_rfk_init_late(struct rtw89_dev *rtwdev,
rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5);
rtw89_phy_rfk_dack_and_wait(rtwdev, phy_idx, chan, 58);
rtw89_phy_rfk_rxdck_and_wait(rtwdev, phy_idx, chan, false, 32);
if (!test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags))
rtw89_phy_rfk_rxdck_and_wait(rtwdev, phy_idx, chan, false, 128);
}
static void rtw8922a_rfk_init_late(struct rtw89_dev *rtwdev)
@@ -2233,6 +2235,31 @@ static void rtw8922a_set_tx_shape(struct rtw89_dev *rtwdev,
rtw8922a_bb_tx_triangular(rtwdev, true, phy_idx);
}
static void rtw8922a_set_txpwr_sar_diff(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx)
{
struct rtw89_sar_parm sar_parm = {
.center_freq = chan->freq,
.force_path = true,
};
s16 sar_rf;
s8 sar_mac;
if (phy_idx != RTW89_PHY_0)
return;
sar_parm.path = RF_PATH_A;
sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
sar_rf = rtw89_phy_txpwr_mac_to_rf(rtwdev, sar_mac);
rtw89_phy_write32_mask(rtwdev, R_P0_TXPWRB_BE, B_TXPWRB_MAX_BE, sar_rf);
sar_parm.path = RF_PATH_B;
sar_mac = rtw89_query_sar(rtwdev, &sar_parm);
sar_rf = rtw89_phy_txpwr_mac_to_rf(rtwdev, sar_mac);
rtw89_phy_write32_mask(rtwdev, R_P1_TXPWRB_BE, B_TXPWRB_MAX_BE, sar_rf);
}
static void rtw8922a_set_txpwr(struct rtw89_dev *rtwdev,
const struct rtw89_chan *chan,
enum rtw89_phy_idx phy_idx)
@@ -2244,6 +2271,7 @@ static void rtw8922a_set_txpwr(struct rtw89_dev *rtwdev,
rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx);
rtw8922a_set_txpwr_diff(rtwdev, chan, phy_idx);
rtw8922a_set_txpwr_ref(rtwdev, phy_idx);
rtw8922a_set_txpwr_sar_diff(rtwdev, chan, phy_idx);
}
static void rtw8922a_set_txpwr_ctrl(struct rtw89_dev *rtwdev,
@@ -2823,12 +2851,14 @@ const struct rtw89_chip_info rtw8922a_chip_info = {
.support_unii4 = true,
.support_ant_gain = true,
.support_tas = false,
.support_sar_by_ant = true,
.ul_tb_waveform_ctrl = false,
.ul_tb_pwr_diff = false,
.rx_freq_frome_ie = false,
.hw_sec_hdr = true,
.hw_mgmt_tx_encrypt = true,
.hw_tkip_crypto = true,
.hw_mlo_bmc_crypto = false,
.rf_path_num = 2,
.tx_nss = 2,
.rx_nss = 2,

View File

@@ -77,11 +77,6 @@ void rtw8922a_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy,
RR_CFGCH_BAND0 | RR_CFGCH_CH);
rf_reg[path][i] |= u32_encode_bits(central_ch, RR_CFGCH_CH);
if (band == RTW89_BAND_2G)
rtw89_write_rf(rtwdev, path, RR_SMD, RR_VCO2, 0x0);
else
rtw89_write_rf(rtwdev, path, RR_SMD, RR_VCO2, 0x1);
switch (band) {
case RTW89_BAND_2G:
default:

View File

@@ -57,10 +57,12 @@ static enum rtw89_sar_subband rtw89_sar_get_subband(struct rtw89_dev *rtwdev,
}
static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev,
u32 center_freq, s32 *cfg)
const struct rtw89_sar_parm *sar_parm,
s32 *cfg)
{
struct rtw89_sar_cfg_common *rtwsar = &rtwdev->sar.cfg_common;
enum rtw89_sar_subband subband_l, subband_h;
u32 center_freq = sar_parm->center_freq;
const struct rtw89_6ghz_span *span;
span = rtw89_get_6ghz_span(rtwdev, center_freq);
@@ -90,6 +92,93 @@ static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev,
return 0;
}
static const struct rtw89_sar_entry_from_acpi *
rtw89_sar_cfg_acpi_get_ent(const struct rtw89_sar_cfg_acpi *rtwsar,
enum rtw89_rf_path path,
enum rtw89_regulation_type regd)
{
const struct rtw89_sar_indicator_from_acpi *ind = &rtwsar->indicator;
const struct rtw89_sar_table_from_acpi *tbl;
u8 sel;
sel = ind->tblsel[path];
tbl = &rtwsar->tables[sel];
return &tbl->entries[regd];
}
static
s32 rtw89_sar_cfg_acpi_get_min(const struct rtw89_sar_entry_from_acpi *ent,
enum rtw89_rf_path path,
enum rtw89_acpi_sar_subband subband_low,
enum rtw89_acpi_sar_subband subband_high)
{
return min(ent->v[subband_low][path], ent->v[subband_high][path]);
}
static int rtw89_query_sar_config_acpi(struct rtw89_dev *rtwdev,
const struct rtw89_sar_parm *sar_parm,
s32 *cfg)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_sar_cfg_acpi *rtwsar = &rtwdev->sar.cfg_acpi;
const struct rtw89_sar_entry_from_acpi *ent_a, *ent_b;
enum rtw89_acpi_sar_subband subband_l, subband_h;
u32 center_freq = sar_parm->center_freq;
const struct rtw89_6ghz_span *span;
enum rtw89_regulation_type regd;
enum rtw89_band band;
s32 cfg_a, cfg_b;
span = rtw89_get_6ghz_span(rtwdev, center_freq);
if (span && RTW89_ACPI_SAR_SPAN_VALID(span)) {
subband_l = span->acpi_sar_subband_low;
subband_h = span->acpi_sar_subband_high;
} else {
subband_l = rtw89_acpi_sar_get_subband(rtwdev, center_freq);
subband_h = subband_l;
}
band = rtw89_acpi_sar_subband_to_band(rtwdev, subband_l);
regd = rtw89_regd_get(rtwdev, band);
ent_a = rtw89_sar_cfg_acpi_get_ent(rtwsar, RF_PATH_A, regd);
ent_b = rtw89_sar_cfg_acpi_get_ent(rtwsar, RF_PATH_B, regd);
cfg_a = rtw89_sar_cfg_acpi_get_min(ent_a, RF_PATH_A, subband_l, subband_h);
cfg_b = rtw89_sar_cfg_acpi_get_min(ent_b, RF_PATH_B, subband_l, subband_h);
if (chip->support_sar_by_ant) {
/* With declaration of support_sar_by_ant, relax the general
* SAR querying to return the maximum between paths. However,
* expect chip has dealt with the corresponding SAR settings
* by path. (To get SAR for a given path, chip can then query
* with force_path.)
*/
if (sar_parm->force_path) {
switch (sar_parm->path) {
default:
case RF_PATH_A:
*cfg = cfg_a;
break;
case RF_PATH_B:
*cfg = cfg_b;
break;
}
} else {
*cfg = max(cfg_a, cfg_b);
}
} else {
*cfg = min(cfg_a, cfg_b);
}
if (sar_parm->ntx == RTW89_2TX)
*cfg -= rtwsar->downgrade_2tx;
return 0;
}
static const
struct rtw89_sar_handler rtw89_sar_handlers[RTW89_SAR_SOURCE_NR] = {
[RTW89_SAR_SOURCE_COMMON] = {
@@ -97,6 +186,11 @@ struct rtw89_sar_handler rtw89_sar_handlers[RTW89_SAR_SOURCE_NR] = {
.txpwr_factor_sar = 2,
.query_sar_config = rtw89_query_sar_config_common,
},
[RTW89_SAR_SOURCE_ACPI] = {
.descr_sar_source = "RTW89_SAR_SOURCE_ACPI",
.txpwr_factor_sar = TXPWR_FACTOR_OF_RTW89_ACPI_SAR,
.query_sar_config = rtw89_query_sar_config_acpi,
},
};
#define rtw89_sar_set_src(_dev, _src, _cfg_name, _cfg_data) \
@@ -175,7 +269,7 @@ static const char *rtw89_tas_state_str(enum rtw89_tas_state state)
}
}
s8 rtw89_query_sar(struct rtw89_dev *rtwdev, u32 center_freq)
s8 rtw89_query_sar(struct rtw89_dev *rtwdev, const struct rtw89_sar_parm *sar_parm)
{
const enum rtw89_sar_sources src = rtwdev->sar.src;
/* its members are protected by rtw89_sar_set_src() */
@@ -191,7 +285,7 @@ s8 rtw89_query_sar(struct rtw89_dev *rtwdev, u32 center_freq)
if (src == RTW89_SAR_SOURCE_NONE)
return RTW89_SAR_TXPWR_MAC_MAX;
ret = sar_hdl->query_sar_config(rtwdev, center_freq, &cfg);
ret = sar_hdl->query_sar_config(rtwdev, sar_parm, &cfg);
if (ret)
return RTW89_SAR_TXPWR_MAC_MAX;
@@ -215,9 +309,10 @@ s8 rtw89_query_sar(struct rtw89_dev *rtwdev, u32 center_freq)
return rtw89_txpwr_sar_to_mac(rtwdev, fct, cfg);
}
EXPORT_SYMBOL(rtw89_query_sar);
int rtw89_print_sar(struct rtw89_dev *rtwdev, char *buf, size_t bufsz,
u32 center_freq)
const struct rtw89_sar_parm *sar_parm)
{
const enum rtw89_sar_sources src = rtwdev->sar.src;
/* its members are protected by rtw89_sar_set_src() */
@@ -238,7 +333,7 @@ int rtw89_print_sar(struct rtw89_dev *rtwdev, char *buf, size_t bufsz,
p += scnprintf(p, end - p, "source: %d (%s)\n", src,
sar_hdl->descr_sar_source);
ret = sar_hdl->query_sar_config(rtwdev, center_freq, &cfg);
ret = sar_hdl->query_sar_config(rtwdev, sar_parm, &cfg);
if (ret) {
p += scnprintf(p, end - p, "config: return code: %d\n", ret);
p += scnprintf(p, end - p,
@@ -252,6 +347,8 @@ int rtw89_print_sar(struct rtw89_dev *rtwdev, char *buf, size_t bufsz,
p += scnprintf(p, end - p, "config: %d (unit: 1/%lu dBm)\n", cfg,
BIT(fct));
p += scnprintf(p, end - p, "support different configs by antenna: %s\n",
str_yes_no(rtwdev->chip->support_sar_by_ant));
out:
return p - buf;
}
@@ -286,16 +383,7 @@ int rtw89_print_tas(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
static int rtw89_apply_sar_common(struct rtw89_dev *rtwdev,
const struct rtw89_sar_cfg_common *sar)
{
enum rtw89_sar_sources src;
lockdep_assert_wiphy(rtwdev->hw->wiphy);
src = rtwdev->sar.src;
if (src != RTW89_SAR_SOURCE_NONE && src != RTW89_SAR_SOURCE_COMMON) {
rtw89_warn(rtwdev, "SAR source: %d is in use", src);
return -EBUSY;
}
/* let common SAR have the highest priority; always apply it */
rtw89_sar_set_src(rtwdev, RTW89_SAR_SOURCE_COMMON, cfg_common, sar);
rtw89_core_set_chip_txpwr(rtwdev);
rtw89_tas_reset(rtwdev, false);
@@ -363,18 +451,92 @@ int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw,
return rtw89_apply_sar_common(rtwdev, &sar_common);
}
static void rtw89_apply_sar_acpi(struct rtw89_dev *rtwdev,
const struct rtw89_sar_cfg_acpi *sar)
{
const struct rtw89_sar_table_from_acpi *tbl;
const struct rtw89_sar_entry_from_acpi *ent;
enum rtw89_sar_sources src;
unsigned int i, j, k;
src = rtwdev->sar.src;
if (src != RTW89_SAR_SOURCE_NONE) {
rtw89_warn(rtwdev, "SAR source: %d is in use", src);
return;
}
rtw89_debug(rtwdev, RTW89_DBG_SAR,
"SAR-ACPI downgrade 2TX: %u (unit: 1/%lu dBm)\n",
sar->downgrade_2tx, BIT(TXPWR_FACTOR_OF_RTW89_ACPI_SAR));
for (i = 0; i < sar->valid_num; i++) {
tbl = &sar->tables[i];
for (j = 0; j < RTW89_REGD_NUM; j++) {
ent = &tbl->entries[j];
rtw89_debug(rtwdev, RTW89_DBG_SAR,
"SAR-ACPI-[%u] REGD-%s (unit: 1/%lu dBm)\n",
i, rtw89_regd_get_string(j),
BIT(TXPWR_FACTOR_OF_RTW89_ACPI_SAR));
for (k = 0; k < NUM_OF_RTW89_ACPI_SAR_SUBBAND; k++)
rtw89_debug(rtwdev, RTW89_DBG_SAR,
"On subband %u, { %d, %d }\n", k,
ent->v[k][RF_PATH_A], ent->v[k][RF_PATH_B]);
}
}
rtw89_sar_set_src(rtwdev, RTW89_SAR_SOURCE_ACPI, cfg_acpi, sar);
/* SAR via ACPI is only configured in the early initial phase, so
* it does not seem necessary to reset txpwr related things here.
*/
}
static void rtw89_set_sar_from_acpi(struct rtw89_dev *rtwdev)
{
struct rtw89_sar_cfg_acpi *cfg;
int ret;
lockdep_assert_wiphy(rtwdev->hw->wiphy);
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg)
return;
ret = rtw89_acpi_evaluate_sar(rtwdev, cfg);
if (ret) {
rtw89_debug(rtwdev, RTW89_DBG_SAR,
"evaluating ACPI SAR returns %d\n", ret);
goto out;
}
if (unlikely(!cfg->valid_num)) {
rtw89_debug(rtwdev, RTW89_DBG_SAR, "no valid SAR table from ACPI\n");
goto out;
}
rtw89_apply_sar_acpi(rtwdev, cfg);
out:
kfree(cfg);
}
static bool rtw89_tas_query_sar_config(struct rtw89_dev *rtwdev, s32 *cfg)
{
const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0);
const enum rtw89_sar_sources src = rtwdev->sar.src;
/* its members are protected by rtw89_sar_set_src() */
const struct rtw89_sar_handler *sar_hdl = &rtw89_sar_handlers[src];
struct rtw89_sar_parm sar_parm = {};
int ret;
if (src == RTW89_SAR_SOURCE_NONE)
return false;
ret = sar_hdl->query_sar_config(rtwdev, chan->freq, cfg);
sar_parm.center_freq = chan->freq;
ret = sar_hdl->query_sar_config(rtwdev, &sar_parm, cfg);
if (ret)
return false;
@@ -383,18 +545,27 @@ static bool rtw89_tas_query_sar_config(struct rtw89_dev *rtwdev, s32 *cfg)
return true;
}
static void rtw89_tas_state_update(struct rtw89_dev *rtwdev,
enum rtw89_tas_state state)
static bool __rtw89_tas_state_update(struct rtw89_dev *rtwdev,
enum rtw89_tas_state state)
{
struct rtw89_tas_info *tas = &rtwdev->tas;
if (tas->state == state)
return;
return false;
rtw89_debug(rtwdev, RTW89_DBG_SAR, "tas: switch state: %s -> %s\n",
rtw89_tas_state_str(tas->state), rtw89_tas_state_str(state));
tas->state = state;
return true;
}
static void rtw89_tas_state_update(struct rtw89_dev *rtwdev,
enum rtw89_tas_state state)
{
if (!__rtw89_tas_state_update(rtwdev, state))
return;
rtw89_core_set_chip_txpwr(rtwdev);
}
@@ -489,7 +660,7 @@ static void rtw89_tas_history_update(struct rtw89_dev *rtwdev)
rtw89_linear_to_db_quarter(div_u64(txpwr, PERCENT)));
}
static void rtw89_tas_rolling_average(struct rtw89_dev *rtwdev)
static bool rtw89_tas_rolling_average(struct rtw89_dev *rtwdev)
{
struct rtw89_tas_info *tas = &rtwdev->tas;
s32 dpr_on_threshold, dpr_off_threshold;
@@ -515,18 +686,18 @@ static void rtw89_tas_rolling_average(struct rtw89_dev *rtwdev)
else if (txpwr_avg < dpr_off_threshold)
state = RTW89_TAS_STATE_DPR_OFF;
else
return;
return false;
rtw89_tas_state_update(rtwdev, state);
return __rtw89_tas_state_update(rtwdev, state);
}
void rtw89_tas_init(struct rtw89_dev *rtwdev)
static void rtw89_tas_init(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_tas_info *tas = &rtwdev->tas;
const struct rtw89_acpi_policy_tas *ptr;
struct rtw89_acpi_dsm_result res = {};
int ret;
u8 val;
if (!chip->support_tas)
return;
@@ -538,8 +709,9 @@ void rtw89_tas_init(struct rtw89_dev *rtwdev)
return;
}
val = res.u.value;
switch (val) {
ptr = res.u.policy_tas;
switch (ptr->enable) {
case 0:
tas->enable = false;
break;
@@ -552,8 +724,13 @@ void rtw89_tas_init(struct rtw89_dev *rtwdev)
if (!tas->enable) {
rtw89_debug(rtwdev, RTW89_DBG_SAR, "TAS not enable\n");
return;
goto out;
}
tas->enabled_countries = ptr->enabled_countries;
out:
kfree(ptr);
}
void rtw89_tas_reset(struct rtw89_dev *rtwdev, bool force)
@@ -598,29 +775,28 @@ void rtw89_tas_reset(struct rtw89_dev *rtwdev, bool force)
"tas: band: %u, freq: %u\n", chan->band_type, chan->freq);
}
void rtw89_tas_track(struct rtw89_dev *rtwdev)
static bool rtw89_tas_track(struct rtw89_dev *rtwdev)
{
struct rtw89_tas_info *tas = &rtwdev->tas;
struct rtw89_hal *hal = &rtwdev->hal;
s32 cfg;
if (hal->disabled_dm_bitmap & BIT(RTW89_DM_TAS))
return;
return false;
if (!rtw89_tas_is_active(rtwdev))
return;
return false;
if (!rtw89_tas_query_sar_config(rtwdev, &cfg) || tas->block_regd) {
rtw89_tas_state_update(rtwdev, RTW89_TAS_STATE_STATIC_SAR);
return;
}
if (!rtw89_tas_query_sar_config(rtwdev, &cfg) || tas->block_regd)
return __rtw89_tas_state_update(rtwdev, RTW89_TAS_STATE_STATIC_SAR);
if (tas->pause)
return;
return false;
rtw89_tas_window_update(rtwdev);
rtw89_tas_history_update(rtwdev);
rtw89_tas_rolling_average(rtwdev);
return rtw89_tas_rolling_average(rtwdev);
}
void rtw89_tas_scan(struct rtw89_dev *rtwdev, bool start)
@@ -667,3 +843,51 @@ void rtw89_tas_chanctx_cb(struct rtw89_dev *rtwdev,
}
}
EXPORT_SYMBOL(rtw89_tas_chanctx_cb);
void rtw89_sar_init(struct rtw89_dev *rtwdev)
{
rtw89_set_sar_from_acpi(rtwdev);
rtw89_tas_init(rtwdev);
}
static bool rtw89_sar_track_acpi(struct rtw89_dev *rtwdev)
{
struct rtw89_sar_cfg_acpi *cfg = &rtwdev->sar.cfg_acpi;
struct rtw89_sar_indicator_from_acpi *ind = &cfg->indicator;
const enum rtw89_sar_sources src = rtwdev->sar.src;
bool changed;
int ret;
lockdep_assert_wiphy(rtwdev->hw->wiphy);
if (src != RTW89_SAR_SOURCE_ACPI)
return false;
if (!ind->enable_sync)
return false;
ret = rtw89_acpi_evaluate_dynamic_sar_indicator(rtwdev, cfg, &changed);
if (likely(!ret))
return changed;
rtw89_debug(rtwdev, RTW89_DBG_SAR,
"%s: failed to track indicator: %d; reset and disable\n",
__func__, ret);
memset(ind->tblsel, 0, sizeof(ind->tblsel));
ind->enable_sync = false;
return true;
}
void rtw89_sar_track(struct rtw89_dev *rtwdev)
{
unsigned int changes = 0;
changes += rtw89_sar_track_acpi(rtwdev);
changes += rtw89_tas_track(rtwdev);
if (!changes)
return;
rtw89_core_set_chip_txpwr(rtwdev);
}

View File

@@ -10,25 +10,34 @@
#define RTW89_SAR_TXPWR_MAC_MAX 63
#define RTW89_SAR_TXPWR_MAC_MIN -64
struct rtw89_sar_parm {
u32 center_freq;
enum rtw89_ntx ntx;
bool force_path;
enum rtw89_rf_path path;
};
struct rtw89_sar_handler {
const char *descr_sar_source;
u8 txpwr_factor_sar;
int (*query_sar_config)(struct rtw89_dev *rtwdev, u32 center_freq, s32 *cfg);
int (*query_sar_config)(struct rtw89_dev *rtwdev,
const struct rtw89_sar_parm *sar_parm, s32 *cfg);
};
extern const struct cfg80211_sar_capa rtw89_sar_capa;
s8 rtw89_query_sar(struct rtw89_dev *rtwdev, u32 center_freq);
s8 rtw89_query_sar(struct rtw89_dev *rtwdev, const struct rtw89_sar_parm *sar_parm);
int rtw89_print_sar(struct rtw89_dev *rtwdev, char *buf, size_t bufsz,
u32 center_freq);
const struct rtw89_sar_parm *sar_parm);
int rtw89_print_tas(struct rtw89_dev *rtwdev, char *buf, size_t bufsz);
int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw,
const struct cfg80211_sar_specs *sar);
void rtw89_tas_init(struct rtw89_dev *rtwdev);
void rtw89_tas_reset(struct rtw89_dev *rtwdev, bool force);
void rtw89_tas_track(struct rtw89_dev *rtwdev);
void rtw89_tas_scan(struct rtw89_dev *rtwdev, bool start);
void rtw89_tas_chanctx_cb(struct rtw89_dev *rtwdev,
enum rtw89_chanctx_state state);
void rtw89_sar_init(struct rtw89_dev *rtwdev);
void rtw89_sar_track(struct rtw89_dev *rtwdev);
#endif

View File

@@ -309,6 +309,9 @@ static void ser_reset_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif_link->port);
rtwvif_link->net_type = RTW89_NET_TYPE_NO_LINK;
rtwvif_link->trigger = false;
rtwvif_link->rand_tsf_done = false;
rtw89_p2p_noa_once_deinit(rtwvif_link);
}
}

View File

@@ -712,6 +712,25 @@ static inline u8 rtw89_core_get_qsel(struct rtw89_dev *rtwdev, u8 tid)
}
}
static inline u8
rtw89_core_get_qsel_mgmt(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req)
{
struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link;
if (desc_info->hiq) {
if (rtwvif_link->mac_idx == RTW89_MAC_1)
return RTW89_TX_QSEL_B1_HI;
else
return RTW89_TX_QSEL_B0_HI;
}
if (rtwvif_link->mac_idx == RTW89_MAC_1)
return RTW89_TX_QSEL_B1_MGMT;
else
return RTW89_TX_QSEL_B0_MGMT;
}
static inline u8 rtw89_core_get_ch_dma(struct rtw89_dev *rtwdev, u8 qsel)
{
switch (qsel) {
@@ -719,12 +738,24 @@ static inline u8 rtw89_core_get_ch_dma(struct rtw89_dev *rtwdev, u8 qsel)
rtw89_warn(rtwdev, "Cannot map qsel to dma: %d\n", qsel);
fallthrough;
case RTW89_TX_QSEL_BE_0:
case RTW89_TX_QSEL_BE_1:
case RTW89_TX_QSEL_BE_2:
case RTW89_TX_QSEL_BE_3:
return RTW89_TXCH_ACH0;
case RTW89_TX_QSEL_BK_0:
case RTW89_TX_QSEL_BK_1:
case RTW89_TX_QSEL_BK_2:
case RTW89_TX_QSEL_BK_3:
return RTW89_TXCH_ACH1;
case RTW89_TX_QSEL_VI_0:
case RTW89_TX_QSEL_VI_1:
case RTW89_TX_QSEL_VI_2:
case RTW89_TX_QSEL_VI_3:
return RTW89_TXCH_ACH2;
case RTW89_TX_QSEL_VO_0:
case RTW89_TX_QSEL_VO_1:
case RTW89_TX_QSEL_VO_2:
case RTW89_TX_QSEL_VO_3:
return RTW89_TXCH_ACH3;
case RTW89_TX_QSEL_B0_MGMT:
return RTW89_TXCH_CH8;

View File

@@ -1086,8 +1086,7 @@ static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev,
rtw89_wow_init_pno(rtwdev, wowlan->nd_config);
rtw89_for_each_rtwvif(rtwdev, rtwvif) {
/* use the link on HW-0 to do wow flow */
rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
rtwvif_link = rtw89_get_designated_link(rtwvif);
if (!rtwvif_link)
continue;