diff options
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/mac80211.c')
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/mac80211.c | 147 |
1 files changed, 129 insertions, 18 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index a322259f4cc4..fca9f82bb462 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -66,6 +66,9 @@ static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed) { struct rtw89_dev *rtwdev = hw->priv; + /* let previous ips work finish to ensure we don't leave ips twice */ + cancel_work_sync(&rtwdev->ips_work); + mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); @@ -102,14 +105,16 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw, int ret = 0; mutex_lock(&rtwdev->mutex); + rtwvif->rtwdev = rtwdev; list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list); + INIT_WORK(&rtwvif->update_beacon_work, rtw89_core_update_beacon_work); rtw89_leave_ps_mode(rtwdev); rtw89_traffic_stats_init(rtwdev, &rtwvif->stats); rtw89_vif_type_mapping(vif, false); rtwvif->port = rtw89_core_acquire_bit_map(rtwdev->hw_port, - RTW89_MAX_HW_PORT_NUM); - if (rtwvif->port == RTW89_MAX_HW_PORT_NUM) { + RTW89_PORT_NUM); + if (rtwvif->port == RTW89_PORT_NUM) { ret = -ENOSPC; goto out; } @@ -141,6 +146,8 @@ static void rtw89_ops_remove_interface(struct ieee80211_hw *hw, struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + cancel_work_sync(&rtwvif->update_beacon_work); + mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_STOP); @@ -161,7 +168,7 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, rtw89_leave_ps_mode(rtwdev); *new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL | - FIF_BCN_PRBRESP_PROMISC; + FIF_BCN_PRBRESP_PROMISC | FIF_PROBE_REQ; if (changed_flags & FIF_ALLMULTI) { if (*new_flags & FIF_ALLMULTI) @@ -192,6 +199,15 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, rtwdev->hal.rx_fltr |= B_AX_A_A1_MATCH; } } + if (changed_flags & FIF_PROBE_REQ) { + if (*new_flags & FIF_PROBE_REQ) { + rtwdev->hal.rx_fltr &= ~B_AX_A_BC_CAM_MATCH; + rtwdev->hal.rx_fltr &= ~B_AX_A_UC_CAM_MATCH; + } else { + rtwdev->hal.rx_fltr |= B_AX_A_BC_CAM_MATCH; + rtwdev->hal.rx_fltr |= B_AX_A_UC_CAM_MATCH; + } + } rtw89_write32_mask(rtwdev, rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0), @@ -311,6 +327,9 @@ static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, rtw89_err(rtwdev, "can't find sta to set sta_assoc state\n"); return; } + + rtw89_vif_type_mapping(vif, true); + rtw89_core_sta_assoc(rtwdev, vif, sta); } @@ -331,6 +350,13 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, rtw89_phy_set_bss_color(rtwdev, vif); rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif); rtw89_mac_port_update(rtwdev, rtwvif); + rtw89_store_op_chan(rtwdev); + } else { + /* Abort ongoing scan if cancel_scan isn't issued + * when disconnected by peer + */ + if (rtwdev->scanning) + rtw89_hw_scan_abort(rtwdev, vif); } } @@ -340,6 +366,9 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); } + if (changed & BSS_CHANGED_BEACON) + rtw89_fw_h2c_update_beacon(rtwdev, rtwvif); + if (changed & BSS_CHANGED_ERP_SLOT) rtw89_conf_tx(rtwdev, rtwvif); @@ -352,6 +381,49 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } +static int rtw89_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + + mutex_lock(&rtwdev->mutex); + ether_addr_copy(rtwvif->bssid, vif->bss_conf.bssid); + rtw89_cam_bssid_changed(rtwdev, rtwvif); + rtw89_mac_port_update(rtwdev, rtwvif); + rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); + rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_TYPE_CHANGE); + rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); + rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); + rtw89_chip_rfk_channel(rtwdev); + mutex_unlock(&rtwdev->mutex); + + return 0; +} + +static +void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + + mutex_lock(&rtwdev->mutex); + rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); + rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); + mutex_unlock(&rtwdev->mutex); +} + +static int rtw89_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set) +{ + struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + + ieee80211_queue_work(rtwdev->hw, &rtwvif->update_beacon_work); + + return 0; +} + static int rtw89_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 ac, const struct ieee80211_tx_queue_params *params) @@ -476,7 +548,6 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mutex_lock(&rtwdev->mutex); clear_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); - rtw89_fw_h2c_ba_cam(rtwdev, false, rtwsta->mac_id, params); mutex_unlock(&rtwdev->mutex); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; @@ -486,11 +557,17 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, rtwsta->ampdu_params[tid].agg_num = params->buf_size; rtwsta->ampdu_params[tid].amsdu = params->amsdu; rtw89_leave_ps_mode(rtwdev); - rtw89_fw_h2c_ba_cam(rtwdev, true, rtwsta->mac_id, params); mutex_unlock(&rtwdev->mutex); break; case IEEE80211_AMPDU_RX_START: + mutex_lock(&rtwdev->mutex); + rtw89_fw_h2c_ba_cam(rtwdev, rtwsta, true, params); + mutex_unlock(&rtwdev->mutex); + break; case IEEE80211_AMPDU_RX_STOP: + mutex_lock(&rtwdev->mutex); + rtw89_fw_h2c_ba_cam(rtwdev, rtwsta, false, params); + mutex_unlock(&rtwdev->mutex); break; default: WARN_ON(1); @@ -617,15 +694,9 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_hal *hal = &rtwdev->hal; mutex_lock(&rtwdev->mutex); - rtwdev->scanning = true; - rtw89_leave_lps(rtwdev); - rtw89_btc_ntfy_scan_start(rtwdev, RTW89_PHY_0, hal->current_band_type); - rtw89_chip_rfk_scan(rtwdev, true); - rtw89_hci_recalc_int_mit(rtwdev); - rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, mac_addr); + rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, false); mutex_unlock(&rtwdev->mutex); } @@ -633,14 +704,9 @@ static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; mutex_lock(&rtwdev->mutex); - rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); - rtw89_chip_rfk_scan(rtwdev, false); - rtw89_btc_ntfy_scan_finish(rtwdev, RTW89_PHY_0); - rtwdev->scanning = false; - rtwdev->dig.bypass_dig = true; + rtw89_core_scan_complete(rtwdev, vif, false); mutex_unlock(&rtwdev->mutex); } @@ -653,6 +719,46 @@ static void rtw89_ops_reconfig_complete(struct ieee80211_hw *hw, rtw89_ser_recfg_done(rtwdev); } +static int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *req) +{ + struct rtw89_dev *rtwdev = hw->priv; + int ret = 0; + + if (!rtwdev->fw.scan_offload) + return 1; + + if (rtwdev->scanning) + return -EBUSY; + + mutex_lock(&rtwdev->mutex); + rtw89_hw_scan_start(rtwdev, vif, req); + ret = rtw89_hw_scan_offload(rtwdev, vif, true); + if (ret) { + rtw89_hw_scan_abort(rtwdev, vif); + rtw89_err(rtwdev, "HW scan failed with status: %d\n", ret); + } + mutex_unlock(&rtwdev->mutex); + + return ret; +} + +static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtw89_dev *rtwdev = hw->priv; + + if (!rtwdev->fw.scan_offload) + return; + + if (!rtwdev->scanning) + return; + + mutex_lock(&rtwdev->mutex); + rtw89_hw_scan_abort(rtwdev, vif); + mutex_unlock(&rtwdev->mutex); +} + const struct ieee80211_ops rtw89_ops = { .tx = rtw89_ops_tx, .wake_tx_queue = rtw89_ops_wake_tx_queue, @@ -663,6 +769,9 @@ const struct ieee80211_ops rtw89_ops = { .remove_interface = rtw89_ops_remove_interface, .configure_filter = rtw89_ops_configure_filter, .bss_info_changed = rtw89_ops_bss_info_changed, + .start_ap = rtw89_ops_start_ap, + .stop_ap = rtw89_ops_stop_ap, + .set_tim = rtw89_ops_set_tim, .conf_tx = rtw89_ops_conf_tx, .sta_state = rtw89_ops_sta_state, .set_key = rtw89_ops_set_key, @@ -676,6 +785,8 @@ const struct ieee80211_ops rtw89_ops = { .sw_scan_start = rtw89_ops_sw_scan_start, .sw_scan_complete = rtw89_ops_sw_scan_complete, .reconfig_complete = rtw89_ops_reconfig_complete, + .hw_scan = rtw89_ops_hw_scan, + .cancel_hw_scan = rtw89_ops_cancel_hw_scan, .set_sar_specs = rtw89_ops_set_sar_specs, }; EXPORT_SYMBOL(rtw89_ops); |