summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/realtek/rtw89/mac80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/mac80211.c')
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac80211.c89
1 files changed, 77 insertions, 12 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 7b04183a3a5d..f39ca1c2ed10 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -220,6 +220,8 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
if (ret)
goto unset_link;
+ rtwdev->pure_monitor_mode_vif = vif->type == NL80211_IFTYPE_MONITOR ?
+ rtwvif : NULL;
rtw89_recalc_lps(rtwdev);
return 0;
@@ -267,6 +269,8 @@ bottom:
rtw89_core_release_bit_map(rtwdev->hw_port, port);
rtw89_release_mac_id(rtwdev, macid);
+ rtwdev->pure_monitor_mode_vif = NULL;
+
rtw89_recalc_lps(rtwdev);
rtw89_enter_ips_by_hwflags(rtwdev);
}
@@ -303,7 +307,6 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw,
u64 multicast)
{
struct rtw89_dev *rtwdev = hw->priv;
- const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
u32 rx_fltr;
lockdep_assert_wiphy(hw->wiphy);
@@ -365,16 +368,10 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw,
rx_fltr &= ~B_AX_A_A1_MATCH;
}
- rtw89_write32_mask(rtwdev,
- rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
- B_AX_RX_FLTR_CFG_MASK,
- rx_fltr);
+ rtw89_mac_set_rx_fltr(rtwdev, RTW89_MAC_0, rx_fltr);
if (!rtwdev->dbcc_en)
return;
- rtw89_write32_mask(rtwdev,
- rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_1),
- B_AX_RX_FLTR_CFG_MASK,
- rx_fltr);
+ rtw89_mac_set_rx_fltr(rtwdev, RTW89_MAC_1, rx_fltr);
}
static const u8 ac_to_fw_idx[IEEE80211_NUM_ACS] = {
@@ -718,6 +715,17 @@ static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ARP_FILTER)
rtwvif->ip_addr = vif->cfg.arp_addr_list[0];
+
+ if (changed & BSS_CHANGED_MLD_VALID_LINKS) {
+ struct rtw89_vif_link *cur = rtw89_get_designated_link(rtwvif);
+
+ rtw89_chip_rfk_channel(rtwdev, cur);
+
+ if (hweight16(vif->active_links) == 1)
+ rtwvif->mlo_mode = RTW89_MLO_MODE_MLSR;
+ else
+ rtwvif->mlo_mode = RTW89_MLO_MODE_EMLSR;
+ }
}
static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw,
@@ -744,7 +752,7 @@ static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID) {
ether_addr_copy(rtwvif_link->bssid, conf->bssid);
rtw89_cam_bssid_changed(rtwdev, rtwvif_link);
- rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL);
+ rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL, RTW89_ROLE_INFO_CHANGE);
WRITE_ONCE(rtwvif_link->sync_bcn_tsf, 0);
}
@@ -803,7 +811,7 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw,
rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, NULL);
rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, NULL, RTW89_ROLE_TYPE_CHANGE);
rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true);
- rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL);
+ rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL, RTW89_ROLE_TYPE_CHANGE);
rtw89_chip_rfk_channel(rtwdev, rtwvif_link);
if (RTW89_CHK_FW_FEATURE(NOTIFY_AP_INFO, &rtwdev->fw)) {
@@ -954,6 +962,7 @@ static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
}
break;
case DISABLE_KEY:
+ flush_work(&rtwdev->txq_work);
rtw89_hci_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1,
false);
rtw89_mac_flush_txq(rtwdev, BIT(rtwdev->hw->queues) - 1, false);
@@ -1132,12 +1141,17 @@ int rtw89_ops_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, u3
{
struct rtw89_dev *rtwdev = hw->priv;
struct rtw89_hal *hal = &rtwdev->hal;
+ const struct rtw89_chip_info *chip;
lockdep_assert_wiphy(hw->wiphy);
+ chip = rtwdev->chip;
+
if (hal->ant_diversity) {
if (tx_ant != rx_ant || hweight32(tx_ant) != 1)
return -EINVAL;
+ } else if (chip->ops->cfg_txrx_path) {
+ /* With cfg_txrx_path ops, chips can configure rx_ant */
} else if (rx_ant != hw->wiphy->available_antennas_rx && rx_ant != hal->antenna_rx) {
return -EINVAL;
}
@@ -1531,10 +1545,29 @@ static bool rtw89_ops_can_activate_links(struct ieee80211_hw *hw,
u16 active_links)
{
struct rtw89_dev *rtwdev = hw->priv;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ u16 current_links = vif->active_links;
+ struct rtw89_vif_ml_trans trans = {
+ .mediate_links = current_links | active_links,
+ .links_to_del = current_links & ~active_links,
+ .links_to_add = active_links & ~current_links,
+ };
lockdep_assert_wiphy(hw->wiphy);
- return rtw89_can_work_on_links(rtwdev, vif, active_links);
+ if (!rtw89_can_work_on_links(rtwdev, vif, active_links))
+ return false;
+
+ /*
+ * Leave LPS at the beginning of ieee80211_set_active_links().
+ * Because the entire process takes the same lock as our track
+ * work, LPS will not enter during ieee80211_set_active_links().
+ */
+ rtw89_leave_lps(rtwdev);
+
+ rtwvif->ml_trans = trans;
+
+ return true;
}
static void __rtw89_ops_clr_vif_links(struct rtw89_dev *rtwdev,
@@ -1579,6 +1612,36 @@ static int __rtw89_ops_set_vif_links(struct rtw89_dev *rtwdev,
return 0;
}
+static void rtw89_vif_cfg_fw_links(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ unsigned long links, bool en)
+{
+ struct rtw89_vif_link *rtwvif_link;
+ unsigned int link_id;
+
+ for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ rtwvif_link = rtwvif->links[link_id];
+ if (unlikely(!rtwvif_link))
+ continue;
+
+ rtw89_fw_h2c_mlo_link_cfg(rtwdev, rtwvif_link, en);
+ }
+}
+
+static void rtw89_vif_update_fw_links(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ u16 current_links)
+{
+ struct rtw89_vif_ml_trans *trans = &rtwvif->ml_trans;
+
+ /* Do follow-up when all updating links exist. */
+ if (current_links != trans->mediate_links)
+ return;
+
+ rtw89_vif_cfg_fw_links(rtwdev, rtwvif, trans->links_to_del, false);
+ rtw89_vif_cfg_fw_links(rtwdev, rtwvif, trans->links_to_add, true);
+}
+
static
int rtw89_ops_change_vif_links(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -1620,6 +1683,8 @@ int rtw89_ops_change_vif_links(struct ieee80211_hw *hw,
if (rtwdev->scanning)
rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
+ rtw89_vif_update_fw_links(rtwdev, rtwvif, old_links);
+
if (!old_links)
__rtw89_ops_clr_vif_links(rtwdev, rtwvif,
BIT(RTW89_VIF_IDLE_LINK_ID));