18e93258fSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 28e93258fSBjoern A. Zeeb /* Copyright(c) 2019-2020 Realtek Corporation 38e93258fSBjoern A. Zeeb */ 48e93258fSBjoern A. Zeeb 58e93258fSBjoern A. Zeeb #include "cam.h" 68e93258fSBjoern A. Zeeb #include "chan.h" 78e93258fSBjoern A. Zeeb #include "coex.h" 88e93258fSBjoern A. Zeeb #include "debug.h" 98e93258fSBjoern A. Zeeb #include "fw.h" 108e93258fSBjoern A. Zeeb #include "mac.h" 118e93258fSBjoern A. Zeeb #include "phy.h" 128e93258fSBjoern A. Zeeb #include "ps.h" 138e93258fSBjoern A. Zeeb #include "reg.h" 148e93258fSBjoern A. Zeeb #include "sar.h" 158e93258fSBjoern A. Zeeb #include "ser.h" 16e2340276SBjoern A. Zeeb #include "util.h" 17e2340276SBjoern A. Zeeb #include "wow.h" 188e93258fSBjoern A. Zeeb 198e93258fSBjoern A. Zeeb static void rtw89_ops_tx(struct ieee80211_hw *hw, 208e93258fSBjoern A. Zeeb struct ieee80211_tx_control *control, 218e93258fSBjoern A. Zeeb struct sk_buff *skb) 228e93258fSBjoern A. Zeeb { 238e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 248e93258fSBjoern A. Zeeb struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 258e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = info->control.vif; 26e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 278e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = control->sta; 28e2340276SBjoern A. Zeeb u32 flags = IEEE80211_SKB_CB(skb)->flags; 298e93258fSBjoern A. Zeeb int ret, qsel; 308e93258fSBjoern A. Zeeb 31e2340276SBjoern A. Zeeb if (rtwvif->offchan && !(flags & IEEE80211_TX_CTL_TX_OFFCHAN) && sta) { 32e2340276SBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 33e2340276SBjoern A. Zeeb 34e2340276SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX, "ops_tx during offchan\n"); 35e2340276SBjoern A. Zeeb skb_queue_tail(&rtwsta->roc_queue, skb); 36e2340276SBjoern A. Zeeb return; 37e2340276SBjoern A. Zeeb } 38e2340276SBjoern A. Zeeb 398e93258fSBjoern A. Zeeb ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel); 408e93258fSBjoern A. Zeeb if (ret) { 418e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to transmit skb: %d\n", ret); 428e93258fSBjoern A. Zeeb ieee80211_free_txskb(hw, skb); 438e93258fSBjoern A. Zeeb return; 448e93258fSBjoern A. Zeeb } 458e93258fSBjoern A. Zeeb rtw89_core_tx_kick_off(rtwdev, qsel); 468e93258fSBjoern A. Zeeb } 478e93258fSBjoern A. Zeeb 488e93258fSBjoern A. Zeeb static void rtw89_ops_wake_tx_queue(struct ieee80211_hw *hw, 498e93258fSBjoern A. Zeeb struct ieee80211_txq *txq) 508e93258fSBjoern A. Zeeb { 518e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 528e93258fSBjoern A. Zeeb 538e93258fSBjoern A. Zeeb ieee80211_schedule_txq(hw, txq); 548e93258fSBjoern A. Zeeb queue_work(rtwdev->txq_wq, &rtwdev->txq_work); 558e93258fSBjoern A. Zeeb } 568e93258fSBjoern A. Zeeb 578e93258fSBjoern A. Zeeb static int rtw89_ops_start(struct ieee80211_hw *hw) 588e93258fSBjoern A. Zeeb { 598e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 608e93258fSBjoern A. Zeeb int ret; 618e93258fSBjoern A. Zeeb 628e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 638e93258fSBjoern A. Zeeb ret = rtw89_core_start(rtwdev); 648e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 658e93258fSBjoern A. Zeeb 668e93258fSBjoern A. Zeeb return ret; 678e93258fSBjoern A. Zeeb } 688e93258fSBjoern A. Zeeb 69*6d67aabdSBjoern A. Zeeb static void rtw89_ops_stop(struct ieee80211_hw *hw, bool suspend) 708e93258fSBjoern A. Zeeb { 718e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 728e93258fSBjoern A. Zeeb 738e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 748e93258fSBjoern A. Zeeb rtw89_core_stop(rtwdev); 758e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 768e93258fSBjoern A. Zeeb } 778e93258fSBjoern A. Zeeb 788e93258fSBjoern A. Zeeb static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed) 798e93258fSBjoern A. Zeeb { 808e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 818e93258fSBjoern A. Zeeb 828e93258fSBjoern A. Zeeb /* let previous ips work finish to ensure we don't leave ips twice */ 838e93258fSBjoern A. Zeeb cancel_work_sync(&rtwdev->ips_work); 848e93258fSBjoern A. Zeeb 858e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 868e93258fSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 878e93258fSBjoern A. Zeeb 888e93258fSBjoern A. Zeeb if ((changed & IEEE80211_CONF_CHANGE_IDLE) && 898e93258fSBjoern A. Zeeb !(hw->conf.flags & IEEE80211_CONF_IDLE)) 908e93258fSBjoern A. Zeeb rtw89_leave_ips(rtwdev); 918e93258fSBjoern A. Zeeb 928e93258fSBjoern A. Zeeb if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 938e93258fSBjoern A. Zeeb rtw89_config_entity_chandef(rtwdev, RTW89_SUB_ENTITY_0, 948e93258fSBjoern A. Zeeb &hw->conf.chandef); 958e93258fSBjoern A. Zeeb rtw89_set_channel(rtwdev); 968e93258fSBjoern A. Zeeb } 978e93258fSBjoern A. Zeeb 988e93258fSBjoern A. Zeeb if ((changed & IEEE80211_CONF_CHANGE_IDLE) && 99e2340276SBjoern A. Zeeb (hw->conf.flags & IEEE80211_CONF_IDLE) && 100e2340276SBjoern A. Zeeb !rtwdev->scanning) 1018e93258fSBjoern A. Zeeb rtw89_enter_ips(rtwdev); 1028e93258fSBjoern A. Zeeb 1038e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1048e93258fSBjoern A. Zeeb 1058e93258fSBjoern A. Zeeb return 0; 1068e93258fSBjoern A. Zeeb } 1078e93258fSBjoern A. Zeeb 1088e93258fSBjoern A. Zeeb static int rtw89_ops_add_interface(struct ieee80211_hw *hw, 1098e93258fSBjoern A. Zeeb struct ieee80211_vif *vif) 1108e93258fSBjoern A. Zeeb { 1118e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 1128e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 1138e93258fSBjoern A. Zeeb int ret = 0; 1148e93258fSBjoern A. Zeeb 115e2340276SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_STATE, "add vif %pM type %d, p2p %d\n", 116e2340276SBjoern A. Zeeb vif->addr, vif->type, vif->p2p); 117e2340276SBjoern A. Zeeb 1188e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 119e2340276SBjoern A. Zeeb 120e2340276SBjoern A. Zeeb rtw89_leave_ips_by_hwflags(rtwdev); 121e2340276SBjoern A. Zeeb 122e2340276SBjoern A. Zeeb if (RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw)) 123e2340276SBjoern A. Zeeb vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | 124e2340276SBjoern A. Zeeb IEEE80211_VIF_SUPPORTS_CQM_RSSI; 125e2340276SBjoern A. Zeeb 1268e93258fSBjoern A. Zeeb rtwvif->rtwdev = rtwdev; 127e2340276SBjoern A. Zeeb rtwvif->roc.state = RTW89_ROC_IDLE; 128e2340276SBjoern A. Zeeb rtwvif->offchan = false; 1298e93258fSBjoern A. Zeeb list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list); 1308e93258fSBjoern A. Zeeb INIT_WORK(&rtwvif->update_beacon_work, rtw89_core_update_beacon_work); 131e2340276SBjoern A. Zeeb INIT_DELAYED_WORK(&rtwvif->roc.roc_work, rtw89_roc_work); 1328e93258fSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 1338e93258fSBjoern A. Zeeb 1348e93258fSBjoern A. Zeeb rtw89_traffic_stats_init(rtwdev, &rtwvif->stats); 1358e93258fSBjoern A. Zeeb rtw89_vif_type_mapping(vif, false); 1368e93258fSBjoern A. Zeeb rtwvif->port = rtw89_core_acquire_bit_map(rtwdev->hw_port, 1378e93258fSBjoern A. Zeeb RTW89_PORT_NUM); 1388e93258fSBjoern A. Zeeb if (rtwvif->port == RTW89_PORT_NUM) { 1398e93258fSBjoern A. Zeeb ret = -ENOSPC; 140e2340276SBjoern A. Zeeb list_del_init(&rtwvif->list); 1418e93258fSBjoern A. Zeeb goto out; 1428e93258fSBjoern A. Zeeb } 1438e93258fSBjoern A. Zeeb 1448e93258fSBjoern A. Zeeb rtwvif->bcn_hit_cond = 0; 1458e93258fSBjoern A. Zeeb rtwvif->mac_idx = RTW89_MAC_0; 1468e93258fSBjoern A. Zeeb rtwvif->phy_idx = RTW89_PHY_0; 147e2340276SBjoern A. Zeeb rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; 148*6d67aabdSBjoern A. Zeeb rtwvif->chanctx_assigned = false; 1498e93258fSBjoern A. Zeeb rtwvif->hit_rule = 0; 150e2340276SBjoern A. Zeeb rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; 1518e93258fSBjoern A. Zeeb ether_addr_copy(rtwvif->mac_addr, vif->addr); 152e2340276SBjoern A. Zeeb INIT_LIST_HEAD(&rtwvif->general_pkt_list); 1538e93258fSBjoern A. Zeeb 1548e93258fSBjoern A. Zeeb ret = rtw89_mac_add_vif(rtwdev, rtwvif); 1558e93258fSBjoern A. Zeeb if (ret) { 1568e93258fSBjoern A. Zeeb rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); 157e2340276SBjoern A. Zeeb list_del_init(&rtwvif->list); 1588e93258fSBjoern A. Zeeb goto out; 1598e93258fSBjoern A. Zeeb } 1608e93258fSBjoern A. Zeeb 1618e93258fSBjoern A. Zeeb rtw89_core_txq_init(rtwdev, vif->txq); 1628e93258fSBjoern A. Zeeb 1638e93258fSBjoern A. Zeeb rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_START); 164e2340276SBjoern A. Zeeb 165e2340276SBjoern A. Zeeb rtw89_recalc_lps(rtwdev); 1668e93258fSBjoern A. Zeeb out: 1678e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1688e93258fSBjoern A. Zeeb 1698e93258fSBjoern A. Zeeb return ret; 1708e93258fSBjoern A. Zeeb } 1718e93258fSBjoern A. Zeeb 1728e93258fSBjoern A. Zeeb static void rtw89_ops_remove_interface(struct ieee80211_hw *hw, 1738e93258fSBjoern A. Zeeb struct ieee80211_vif *vif) 1748e93258fSBjoern A. Zeeb { 1758e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 1768e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 1778e93258fSBjoern A. Zeeb 178e2340276SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_STATE, "remove vif %pM type %d p2p %d\n", 179e2340276SBjoern A. Zeeb vif->addr, vif->type, vif->p2p); 180e2340276SBjoern A. Zeeb 1818e93258fSBjoern A. Zeeb cancel_work_sync(&rtwvif->update_beacon_work); 182e2340276SBjoern A. Zeeb cancel_delayed_work_sync(&rtwvif->roc.roc_work); 1838e93258fSBjoern A. Zeeb 1848e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 1858e93258fSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 1868e93258fSBjoern A. Zeeb rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_STOP); 1878e93258fSBjoern A. Zeeb rtw89_mac_remove_vif(rtwdev, rtwvif); 1888e93258fSBjoern A. Zeeb rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); 1898e93258fSBjoern A. Zeeb list_del_init(&rtwvif->list); 190e2340276SBjoern A. Zeeb rtw89_recalc_lps(rtwdev); 191e2340276SBjoern A. Zeeb rtw89_enter_ips_by_hwflags(rtwdev); 192e2340276SBjoern A. Zeeb 1938e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1948e93258fSBjoern A. Zeeb } 1958e93258fSBjoern A. Zeeb 196e2340276SBjoern A. Zeeb static int rtw89_ops_change_interface(struct ieee80211_hw *hw, 197e2340276SBjoern A. Zeeb struct ieee80211_vif *vif, 198e2340276SBjoern A. Zeeb enum nl80211_iftype type, bool p2p) 199e2340276SBjoern A. Zeeb { 200e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 201e2340276SBjoern A. Zeeb int ret; 202e2340276SBjoern A. Zeeb 203e2340276SBjoern A. Zeeb set_bit(RTW89_FLAG_CHANGING_INTERFACE, rtwdev->flags); 204e2340276SBjoern A. Zeeb 205e2340276SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_STATE, "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n", 206e2340276SBjoern A. Zeeb vif->addr, vif->type, type, vif->p2p, p2p); 207e2340276SBjoern A. Zeeb 208e2340276SBjoern A. Zeeb rtw89_ops_remove_interface(hw, vif); 209e2340276SBjoern A. Zeeb 210e2340276SBjoern A. Zeeb vif->type = type; 211e2340276SBjoern A. Zeeb vif->p2p = p2p; 212e2340276SBjoern A. Zeeb 213e2340276SBjoern A. Zeeb ret = rtw89_ops_add_interface(hw, vif); 214e2340276SBjoern A. Zeeb if (ret) 215e2340276SBjoern A. Zeeb rtw89_warn(rtwdev, "failed to change interface %d\n", ret); 216e2340276SBjoern A. Zeeb 217e2340276SBjoern A. Zeeb clear_bit(RTW89_FLAG_CHANGING_INTERFACE, rtwdev->flags); 218e2340276SBjoern A. Zeeb 219e2340276SBjoern A. Zeeb return ret; 220e2340276SBjoern A. Zeeb } 221e2340276SBjoern A. Zeeb 2228e93258fSBjoern A. Zeeb static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, 2238e93258fSBjoern A. Zeeb unsigned int changed_flags, 2248e93258fSBjoern A. Zeeb unsigned int *new_flags, 2258e93258fSBjoern A. Zeeb u64 multicast) 2268e93258fSBjoern A. Zeeb { 2278e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 228*6d67aabdSBjoern A. Zeeb const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; 229*6d67aabdSBjoern A. Zeeb u32 rx_fltr; 2308e93258fSBjoern A. Zeeb 2318e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 2328e93258fSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 2338e93258fSBjoern A. Zeeb 2348e93258fSBjoern A. Zeeb *new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL | 2358e93258fSBjoern A. Zeeb FIF_BCN_PRBRESP_PROMISC | FIF_PROBE_REQ; 2368e93258fSBjoern A. Zeeb 2378e93258fSBjoern A. Zeeb if (changed_flags & FIF_ALLMULTI) { 2388e93258fSBjoern A. Zeeb if (*new_flags & FIF_ALLMULTI) 2398e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr &= ~B_AX_A_MC; 2408e93258fSBjoern A. Zeeb else 2418e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr |= B_AX_A_MC; 2428e93258fSBjoern A. Zeeb } 2438e93258fSBjoern A. Zeeb if (changed_flags & FIF_FCSFAIL) { 2448e93258fSBjoern A. Zeeb if (*new_flags & FIF_FCSFAIL) 2458e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr |= B_AX_A_CRC32_ERR; 2468e93258fSBjoern A. Zeeb else 2478e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr &= ~B_AX_A_CRC32_ERR; 2488e93258fSBjoern A. Zeeb } 2498e93258fSBjoern A. Zeeb if (changed_flags & FIF_OTHER_BSS) { 2508e93258fSBjoern A. Zeeb if (*new_flags & FIF_OTHER_BSS) 2518e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr &= ~B_AX_A_A1_MATCH; 2528e93258fSBjoern A. Zeeb else 2538e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr |= B_AX_A_A1_MATCH; 2548e93258fSBjoern A. Zeeb } 2558e93258fSBjoern A. Zeeb if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { 2568e93258fSBjoern A. Zeeb if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { 2578e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr &= ~B_AX_A_BCN_CHK_EN; 2588e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr &= ~B_AX_A_BC; 2598e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr &= ~B_AX_A_A1_MATCH; 2608e93258fSBjoern A. Zeeb } else { 2618e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr |= B_AX_A_BCN_CHK_EN; 2628e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr |= B_AX_A_BC; 2638e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr |= B_AX_A_A1_MATCH; 2648e93258fSBjoern A. Zeeb } 2658e93258fSBjoern A. Zeeb } 2668e93258fSBjoern A. Zeeb if (changed_flags & FIF_PROBE_REQ) { 2678e93258fSBjoern A. Zeeb if (*new_flags & FIF_PROBE_REQ) { 2688e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr &= ~B_AX_A_BC_CAM_MATCH; 2698e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr &= ~B_AX_A_UC_CAM_MATCH; 2708e93258fSBjoern A. Zeeb } else { 2718e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr |= B_AX_A_BC_CAM_MATCH; 2728e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr |= B_AX_A_UC_CAM_MATCH; 2738e93258fSBjoern A. Zeeb } 2748e93258fSBjoern A. Zeeb } 2758e93258fSBjoern A. Zeeb 276*6d67aabdSBjoern A. Zeeb rx_fltr = rtwdev->hal.rx_fltr; 277*6d67aabdSBjoern A. Zeeb 278*6d67aabdSBjoern A. Zeeb /* mac80211 doesn't configure filter when HW scan, driver need to 279*6d67aabdSBjoern A. Zeeb * set by itself. However, during P2P scan might have configure 280*6d67aabdSBjoern A. Zeeb * filter to overwrite filter that HW scan needed, so we need to 281*6d67aabdSBjoern A. Zeeb * check scan and append related filter 282*6d67aabdSBjoern A. Zeeb */ 283*6d67aabdSBjoern A. Zeeb if (rtwdev->scanning) { 284*6d67aabdSBjoern A. Zeeb rx_fltr &= ~B_AX_A_BCN_CHK_EN; 285*6d67aabdSBjoern A. Zeeb rx_fltr &= ~B_AX_A_BC; 286*6d67aabdSBjoern A. Zeeb rx_fltr &= ~B_AX_A_A1_MATCH; 287*6d67aabdSBjoern A. Zeeb } 288*6d67aabdSBjoern A. Zeeb 2898e93258fSBjoern A. Zeeb rtw89_write32_mask(rtwdev, 290*6d67aabdSBjoern A. Zeeb rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), 2918e93258fSBjoern A. Zeeb B_AX_RX_FLTR_CFG_MASK, 292*6d67aabdSBjoern A. Zeeb rx_fltr); 2938e93258fSBjoern A. Zeeb if (!rtwdev->dbcc_en) 2948e93258fSBjoern A. Zeeb goto out; 2958e93258fSBjoern A. Zeeb rtw89_write32_mask(rtwdev, 296*6d67aabdSBjoern A. Zeeb rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_1), 2978e93258fSBjoern A. Zeeb B_AX_RX_FLTR_CFG_MASK, 298*6d67aabdSBjoern A. Zeeb rx_fltr); 2998e93258fSBjoern A. Zeeb 3008e93258fSBjoern A. Zeeb out: 3018e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 3028e93258fSBjoern A. Zeeb } 3038e93258fSBjoern A. Zeeb 3048e93258fSBjoern A. Zeeb static const u8 ac_to_fw_idx[IEEE80211_NUM_ACS] = { 3058e93258fSBjoern A. Zeeb [IEEE80211_AC_VO] = 3, 3068e93258fSBjoern A. Zeeb [IEEE80211_AC_VI] = 2, 3078e93258fSBjoern A. Zeeb [IEEE80211_AC_BE] = 0, 3088e93258fSBjoern A. Zeeb [IEEE80211_AC_BK] = 1, 3098e93258fSBjoern A. Zeeb }; 3108e93258fSBjoern A. Zeeb 3118e93258fSBjoern A. Zeeb static u8 rtw89_aifsn_to_aifs(struct rtw89_dev *rtwdev, 3128e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif, u8 aifsn) 3138e93258fSBjoern A. Zeeb { 3148e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); 315*6d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, 316*6d67aabdSBjoern A. Zeeb rtwvif->sub_entity_idx); 3178e93258fSBjoern A. Zeeb u8 slot_time; 3188e93258fSBjoern A. Zeeb u8 sifs; 3198e93258fSBjoern A. Zeeb 3208e93258fSBjoern A. Zeeb slot_time = vif->bss_conf.use_short_slot ? 9 : 20; 321*6d67aabdSBjoern A. Zeeb sifs = chan->band_type == RTW89_BAND_2G ? 10 : 16; 3228e93258fSBjoern A. Zeeb 3238e93258fSBjoern A. Zeeb return aifsn * slot_time + sifs; 3248e93258fSBjoern A. Zeeb } 3258e93258fSBjoern A. Zeeb 3268e93258fSBjoern A. Zeeb static void ____rtw89_conf_tx_edca(struct rtw89_dev *rtwdev, 3278e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif, u16 ac) 3288e93258fSBjoern A. Zeeb { 3298e93258fSBjoern A. Zeeb struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; 3308e93258fSBjoern A. Zeeb u32 val; 3318e93258fSBjoern A. Zeeb u8 ecw_max, ecw_min; 3328e93258fSBjoern A. Zeeb u8 aifs; 3338e93258fSBjoern A. Zeeb 3348e93258fSBjoern A. Zeeb /* 2^ecw - 1 = cw; ecw = log2(cw + 1) */ 3358e93258fSBjoern A. Zeeb ecw_max = ilog2(params->cw_max + 1); 3368e93258fSBjoern A. Zeeb ecw_min = ilog2(params->cw_min + 1); 3378e93258fSBjoern A. Zeeb aifs = rtw89_aifsn_to_aifs(rtwdev, rtwvif, params->aifs); 3388e93258fSBjoern A. Zeeb val = FIELD_PREP(FW_EDCA_PARAM_TXOPLMT_MSK, params->txop) | 3398e93258fSBjoern A. Zeeb FIELD_PREP(FW_EDCA_PARAM_CWMAX_MSK, ecw_max) | 3408e93258fSBjoern A. Zeeb FIELD_PREP(FW_EDCA_PARAM_CWMIN_MSK, ecw_min) | 3418e93258fSBjoern A. Zeeb FIELD_PREP(FW_EDCA_PARAM_AIFS_MSK, aifs); 3428e93258fSBjoern A. Zeeb rtw89_fw_h2c_set_edca(rtwdev, rtwvif, ac_to_fw_idx[ac], val); 3438e93258fSBjoern A. Zeeb } 3448e93258fSBjoern A. Zeeb 345*6d67aabdSBjoern A. Zeeb #define R_MUEDCA_ACS_PARAM(acs) {R_AX_MUEDCA_ ## acs ## _PARAM_0, \ 346*6d67aabdSBjoern A. Zeeb R_BE_MUEDCA_ ## acs ## _PARAM_0} 347*6d67aabdSBjoern A. Zeeb 348*6d67aabdSBjoern A. Zeeb static const u32 ac_to_mu_edca_param[IEEE80211_NUM_ACS][RTW89_CHIP_GEN_NUM] = { 349*6d67aabdSBjoern A. Zeeb [IEEE80211_AC_VO] = R_MUEDCA_ACS_PARAM(VO), 350*6d67aabdSBjoern A. Zeeb [IEEE80211_AC_VI] = R_MUEDCA_ACS_PARAM(VI), 351*6d67aabdSBjoern A. Zeeb [IEEE80211_AC_BE] = R_MUEDCA_ACS_PARAM(BE), 352*6d67aabdSBjoern A. Zeeb [IEEE80211_AC_BK] = R_MUEDCA_ACS_PARAM(BK), 3538e93258fSBjoern A. Zeeb }; 3548e93258fSBjoern A. Zeeb 3558e93258fSBjoern A. Zeeb static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev, 3568e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif, u16 ac) 3578e93258fSBjoern A. Zeeb { 3588e93258fSBjoern A. Zeeb struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; 3598e93258fSBjoern A. Zeeb struct ieee80211_he_mu_edca_param_ac_rec *mu_edca; 360*6d67aabdSBjoern A. Zeeb int gen = rtwdev->chip->chip_gen; 3618e93258fSBjoern A. Zeeb u8 aifs, aifsn; 3628e93258fSBjoern A. Zeeb u16 timer_32us; 3638e93258fSBjoern A. Zeeb u32 reg; 3648e93258fSBjoern A. Zeeb u32 val; 3658e93258fSBjoern A. Zeeb 3668e93258fSBjoern A. Zeeb if (!params->mu_edca) 3678e93258fSBjoern A. Zeeb return; 3688e93258fSBjoern A. Zeeb 3698e93258fSBjoern A. Zeeb mu_edca = ¶ms->mu_edca_param_rec; 3708e93258fSBjoern A. Zeeb aifsn = FIELD_GET(GENMASK(3, 0), mu_edca->aifsn); 3718e93258fSBjoern A. Zeeb aifs = aifsn ? rtw89_aifsn_to_aifs(rtwdev, rtwvif, aifsn) : 0; 3728e93258fSBjoern A. Zeeb timer_32us = mu_edca->mu_edca_timer << 8; 3738e93258fSBjoern A. Zeeb 3748e93258fSBjoern A. Zeeb val = FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_TIMER_MASK, timer_32us) | 3758e93258fSBjoern A. Zeeb FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_CW_MASK, mu_edca->ecw_min_max) | 3768e93258fSBjoern A. Zeeb FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_AIFS_MASK, aifs); 377*6d67aabdSBjoern A. Zeeb reg = rtw89_mac_reg_by_idx(rtwdev, ac_to_mu_edca_param[ac][gen], rtwvif->mac_idx); 3788e93258fSBjoern A. Zeeb rtw89_write32(rtwdev, reg, val); 3798e93258fSBjoern A. Zeeb 3808e93258fSBjoern A. Zeeb rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif, true); 3818e93258fSBjoern A. Zeeb } 3828e93258fSBjoern A. Zeeb 3838e93258fSBjoern A. Zeeb static void __rtw89_conf_tx(struct rtw89_dev *rtwdev, 3848e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif, u16 ac) 3858e93258fSBjoern A. Zeeb { 3868e93258fSBjoern A. Zeeb ____rtw89_conf_tx_edca(rtwdev, rtwvif, ac); 3878e93258fSBjoern A. Zeeb ____rtw89_conf_tx_mu_edca(rtwdev, rtwvif, ac); 3888e93258fSBjoern A. Zeeb } 3898e93258fSBjoern A. Zeeb 3908e93258fSBjoern A. Zeeb static void rtw89_conf_tx(struct rtw89_dev *rtwdev, 3918e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif) 3928e93258fSBjoern A. Zeeb { 3938e93258fSBjoern A. Zeeb u16 ac; 3948e93258fSBjoern A. Zeeb 3958e93258fSBjoern A. Zeeb for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 3968e93258fSBjoern A. Zeeb __rtw89_conf_tx(rtwdev, rtwvif, ac); 3978e93258fSBjoern A. Zeeb } 3988e93258fSBjoern A. Zeeb 3998e93258fSBjoern A. Zeeb static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, 400*6d67aabdSBjoern A. Zeeb struct ieee80211_vif *vif) 4018e93258fSBjoern A. Zeeb { 4028e93258fSBjoern A. Zeeb struct ieee80211_sta *sta; 4038e93258fSBjoern A. Zeeb 4048e93258fSBjoern A. Zeeb if (vif->type != NL80211_IFTYPE_STATION) 4058e93258fSBjoern A. Zeeb return; 4068e93258fSBjoern A. Zeeb 407*6d67aabdSBjoern A. Zeeb sta = ieee80211_find_sta(vif, vif->cfg.ap_addr); 4088e93258fSBjoern A. Zeeb if (!sta) { 4098e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "can't find sta to set sta_assoc state\n"); 4108e93258fSBjoern A. Zeeb return; 4118e93258fSBjoern A. Zeeb } 4128e93258fSBjoern A. Zeeb 4138e93258fSBjoern A. Zeeb rtw89_vif_type_mapping(vif, true); 4148e93258fSBjoern A. Zeeb 4158e93258fSBjoern A. Zeeb rtw89_core_sta_assoc(rtwdev, vif, sta); 4168e93258fSBjoern A. Zeeb } 4178e93258fSBjoern A. Zeeb 418*6d67aabdSBjoern A. Zeeb static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw, 419*6d67aabdSBjoern A. Zeeb struct ieee80211_vif *vif, u64 changed) 420*6d67aabdSBjoern A. Zeeb { 421*6d67aabdSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 422*6d67aabdSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 423*6d67aabdSBjoern A. Zeeb 424*6d67aabdSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 425*6d67aabdSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 426*6d67aabdSBjoern A. Zeeb 427*6d67aabdSBjoern A. Zeeb if (changed & BSS_CHANGED_ASSOC) { 428*6d67aabdSBjoern A. Zeeb if (vif->cfg.assoc) { 429*6d67aabdSBjoern A. Zeeb rtw89_station_mode_sta_assoc(rtwdev, vif); 430*6d67aabdSBjoern A. Zeeb rtw89_phy_set_bss_color(rtwdev, vif); 431*6d67aabdSBjoern A. Zeeb rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif); 432*6d67aabdSBjoern A. Zeeb rtw89_mac_port_update(rtwdev, rtwvif); 433*6d67aabdSBjoern A. Zeeb rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, vif); 434*6d67aabdSBjoern A. Zeeb 435*6d67aabdSBjoern A. Zeeb rtw89_queue_chanctx_work(rtwdev); 436*6d67aabdSBjoern A. Zeeb } else { 437*6d67aabdSBjoern A. Zeeb /* Abort ongoing scan if cancel_scan isn't issued 438*6d67aabdSBjoern A. Zeeb * when disconnected by peer 439*6d67aabdSBjoern A. Zeeb */ 440*6d67aabdSBjoern A. Zeeb if (rtwdev->scanning) 441*6d67aabdSBjoern A. Zeeb rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); 442*6d67aabdSBjoern A. Zeeb } 443*6d67aabdSBjoern A. Zeeb } 444*6d67aabdSBjoern A. Zeeb 445*6d67aabdSBjoern A. Zeeb if (changed & BSS_CHANGED_PS) 446*6d67aabdSBjoern A. Zeeb rtw89_recalc_lps(rtwdev); 447*6d67aabdSBjoern A. Zeeb 448*6d67aabdSBjoern A. Zeeb if (changed & BSS_CHANGED_ARP_FILTER) 449*6d67aabdSBjoern A. Zeeb rtwvif->ip_addr = vif->cfg.arp_addr_list[0]; 450*6d67aabdSBjoern A. Zeeb 451*6d67aabdSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 452*6d67aabdSBjoern A. Zeeb } 453*6d67aabdSBjoern A. Zeeb 454*6d67aabdSBjoern A. Zeeb static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw, 4558e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 4568e93258fSBjoern A. Zeeb struct ieee80211_bss_conf *conf, 4578e93258fSBjoern A. Zeeb u64 changed) 4588e93258fSBjoern A. Zeeb { 4598e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 4608e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 4618e93258fSBjoern A. Zeeb 4628e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 4638e93258fSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 4648e93258fSBjoern A. Zeeb 4658e93258fSBjoern A. Zeeb if (changed & BSS_CHANGED_BSSID) { 4668e93258fSBjoern A. Zeeb ether_addr_copy(rtwvif->bssid, conf->bssid); 4678e93258fSBjoern A. Zeeb rtw89_cam_bssid_changed(rtwdev, rtwvif); 4688e93258fSBjoern A. Zeeb rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); 469*6d67aabdSBjoern A. Zeeb WRITE_ONCE(rtwvif->sync_bcn_tsf, 0); 4708e93258fSBjoern A. Zeeb } 4718e93258fSBjoern A. Zeeb 4728e93258fSBjoern A. Zeeb if (changed & BSS_CHANGED_BEACON) 473*6d67aabdSBjoern A. Zeeb rtw89_chip_h2c_update_beacon(rtwdev, rtwvif); 4748e93258fSBjoern A. Zeeb 4758e93258fSBjoern A. Zeeb if (changed & BSS_CHANGED_ERP_SLOT) 4768e93258fSBjoern A. Zeeb rtw89_conf_tx(rtwdev, rtwvif); 4778e93258fSBjoern A. Zeeb 4788e93258fSBjoern A. Zeeb if (changed & BSS_CHANGED_HE_BSS_COLOR) 4798e93258fSBjoern A. Zeeb rtw89_phy_set_bss_color(rtwdev, vif); 4808e93258fSBjoern A. Zeeb 4818e93258fSBjoern A. Zeeb if (changed & BSS_CHANGED_MU_GROUPS) 4828e93258fSBjoern A. Zeeb rtw89_mac_bf_set_gid_table(rtwdev, vif, conf); 4838e93258fSBjoern A. Zeeb 484e2340276SBjoern A. Zeeb if (changed & BSS_CHANGED_P2P_PS) 485*6d67aabdSBjoern A. Zeeb rtw89_core_update_p2p_ps(rtwdev, vif); 486e2340276SBjoern A. Zeeb 487e2340276SBjoern A. Zeeb if (changed & BSS_CHANGED_CQM) 488e2340276SBjoern A. Zeeb rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); 489e2340276SBjoern A. Zeeb 490*6d67aabdSBjoern A. Zeeb if (changed & BSS_CHANGED_TPE) 491*6d67aabdSBjoern A. Zeeb rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true); 492e2340276SBjoern A. Zeeb 4938e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 4948e93258fSBjoern A. Zeeb } 4958e93258fSBjoern A. Zeeb 4968e93258fSBjoern A. Zeeb static int rtw89_ops_start_ap(struct ieee80211_hw *hw, 4978e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 4988e93258fSBjoern A. Zeeb struct ieee80211_bss_conf *link_conf) 4998e93258fSBjoern A. Zeeb { 5008e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 5018e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 502e2340276SBjoern A. Zeeb const struct rtw89_chan *chan; 5038e93258fSBjoern A. Zeeb 5048e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 505e2340276SBjoern A. Zeeb 506e2340276SBjoern A. Zeeb chan = rtw89_chan_get(rtwdev, rtwvif->sub_entity_idx); 507e2340276SBjoern A. Zeeb if (chan->band_type == RTW89_BAND_6G) { 508e2340276SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 509e2340276SBjoern A. Zeeb return -EOPNOTSUPP; 510e2340276SBjoern A. Zeeb } 511e2340276SBjoern A. Zeeb 512*6d67aabdSBjoern A. Zeeb if (rtwdev->scanning) 513*6d67aabdSBjoern A. Zeeb rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); 514*6d67aabdSBjoern A. Zeeb 5158e93258fSBjoern A. Zeeb ether_addr_copy(rtwvif->bssid, vif->bss_conf.bssid); 5168e93258fSBjoern A. Zeeb rtw89_cam_bssid_changed(rtwdev, rtwvif); 5178e93258fSBjoern A. Zeeb rtw89_mac_port_update(rtwdev, rtwvif); 518*6d67aabdSBjoern A. Zeeb rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); 5198e93258fSBjoern A. Zeeb rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_TYPE_CHANGE); 5208e93258fSBjoern A. Zeeb rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); 5218e93258fSBjoern A. Zeeb rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); 5228e93258fSBjoern A. Zeeb rtw89_chip_rfk_channel(rtwdev); 523*6d67aabdSBjoern A. Zeeb 524*6d67aabdSBjoern A. Zeeb rtw89_queue_chanctx_work(rtwdev); 5258e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 5268e93258fSBjoern A. Zeeb 5278e93258fSBjoern A. Zeeb return 0; 5288e93258fSBjoern A. Zeeb } 5298e93258fSBjoern A. Zeeb 5308e93258fSBjoern A. Zeeb static 5318e93258fSBjoern A. Zeeb void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 5328e93258fSBjoern A. Zeeb struct ieee80211_bss_conf *link_conf) 5338e93258fSBjoern A. Zeeb { 5348e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 5358e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 5368e93258fSBjoern A. Zeeb 5378e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 538e2340276SBjoern A. Zeeb rtw89_mac_stop_ap(rtwdev, rtwvif); 539*6d67aabdSBjoern A. Zeeb rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); 5408e93258fSBjoern A. Zeeb rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); 5418e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 5428e93258fSBjoern A. Zeeb } 5438e93258fSBjoern A. Zeeb 5448e93258fSBjoern A. Zeeb static int rtw89_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, 5458e93258fSBjoern A. Zeeb bool set) 5468e93258fSBjoern A. Zeeb { 5478e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 5488e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 5498e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = rtwsta->rtwvif; 5508e93258fSBjoern A. Zeeb 5518e93258fSBjoern A. Zeeb ieee80211_queue_work(rtwdev->hw, &rtwvif->update_beacon_work); 5528e93258fSBjoern A. Zeeb 5538e93258fSBjoern A. Zeeb return 0; 5548e93258fSBjoern A. Zeeb } 5558e93258fSBjoern A. Zeeb 5568e93258fSBjoern A. Zeeb static int rtw89_ops_conf_tx(struct ieee80211_hw *hw, 5578e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 5588e93258fSBjoern A. Zeeb unsigned int link_id, u16 ac, 5598e93258fSBjoern A. Zeeb const struct ieee80211_tx_queue_params *params) 5608e93258fSBjoern A. Zeeb { 5618e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 5628e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 5638e93258fSBjoern A. Zeeb 5648e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 5658e93258fSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 5668e93258fSBjoern A. Zeeb rtwvif->tx_params[ac] = *params; 5678e93258fSBjoern A. Zeeb __rtw89_conf_tx(rtwdev, rtwvif, ac); 5688e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 5698e93258fSBjoern A. Zeeb 5708e93258fSBjoern A. Zeeb return 0; 5718e93258fSBjoern A. Zeeb } 5728e93258fSBjoern A. Zeeb 5738e93258fSBjoern A. Zeeb static int __rtw89_ops_sta_state(struct ieee80211_hw *hw, 5748e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 5758e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, 5768e93258fSBjoern A. Zeeb enum ieee80211_sta_state old_state, 5778e93258fSBjoern A. Zeeb enum ieee80211_sta_state new_state) 5788e93258fSBjoern A. Zeeb { 5798e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 5808e93258fSBjoern A. Zeeb 5818e93258fSBjoern A. Zeeb if (old_state == IEEE80211_STA_NOTEXIST && 5828e93258fSBjoern A. Zeeb new_state == IEEE80211_STA_NONE) 5838e93258fSBjoern A. Zeeb return rtw89_core_sta_add(rtwdev, vif, sta); 5848e93258fSBjoern A. Zeeb 5858e93258fSBjoern A. Zeeb if (old_state == IEEE80211_STA_AUTH && 5868e93258fSBjoern A. Zeeb new_state == IEEE80211_STA_ASSOC) { 5878e93258fSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) 5888e93258fSBjoern A. Zeeb return 0; /* defer to bss_info_changed to have vif info */ 5898e93258fSBjoern A. Zeeb return rtw89_core_sta_assoc(rtwdev, vif, sta); 5908e93258fSBjoern A. Zeeb } 5918e93258fSBjoern A. Zeeb 5928e93258fSBjoern A. Zeeb if (old_state == IEEE80211_STA_ASSOC && 5938e93258fSBjoern A. Zeeb new_state == IEEE80211_STA_AUTH) 5948e93258fSBjoern A. Zeeb return rtw89_core_sta_disassoc(rtwdev, vif, sta); 5958e93258fSBjoern A. Zeeb 5968e93258fSBjoern A. Zeeb if (old_state == IEEE80211_STA_AUTH && 5978e93258fSBjoern A. Zeeb new_state == IEEE80211_STA_NONE) 5988e93258fSBjoern A. Zeeb return rtw89_core_sta_disconnect(rtwdev, vif, sta); 5998e93258fSBjoern A. Zeeb 6008e93258fSBjoern A. Zeeb if (old_state == IEEE80211_STA_NONE && 6018e93258fSBjoern A. Zeeb new_state == IEEE80211_STA_NOTEXIST) 6028e93258fSBjoern A. Zeeb return rtw89_core_sta_remove(rtwdev, vif, sta); 6038e93258fSBjoern A. Zeeb 6048e93258fSBjoern A. Zeeb return 0; 6058e93258fSBjoern A. Zeeb } 6068e93258fSBjoern A. Zeeb 6078e93258fSBjoern A. Zeeb static int rtw89_ops_sta_state(struct ieee80211_hw *hw, 6088e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 6098e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, 6108e93258fSBjoern A. Zeeb enum ieee80211_sta_state old_state, 6118e93258fSBjoern A. Zeeb enum ieee80211_sta_state new_state) 6128e93258fSBjoern A. Zeeb { 6138e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 6148e93258fSBjoern A. Zeeb int ret; 6158e93258fSBjoern A. Zeeb 6168e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 6178e93258fSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 6188e93258fSBjoern A. Zeeb ret = __rtw89_ops_sta_state(hw, vif, sta, old_state, new_state); 6198e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 6208e93258fSBjoern A. Zeeb 6218e93258fSBjoern A. Zeeb return ret; 6228e93258fSBjoern A. Zeeb } 6238e93258fSBjoern A. Zeeb 6248e93258fSBjoern A. Zeeb static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 6258e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 6268e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, 6278e93258fSBjoern A. Zeeb struct ieee80211_key_conf *key) 6288e93258fSBjoern A. Zeeb { 6298e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 6308e93258fSBjoern A. Zeeb int ret = 0; 6318e93258fSBjoern A. Zeeb 6328e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 6338e93258fSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 6348e93258fSBjoern A. Zeeb 6358e93258fSBjoern A. Zeeb switch (cmd) { 6368e93258fSBjoern A. Zeeb case SET_KEY: 6378e93258fSBjoern A. Zeeb rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_EAPOL_END); 6388e93258fSBjoern A. Zeeb ret = rtw89_cam_sec_key_add(rtwdev, vif, sta, key); 6398e93258fSBjoern A. Zeeb if (ret && ret != -EOPNOTSUPP) { 6408e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to add key to sec cam\n"); 6418e93258fSBjoern A. Zeeb goto out; 6428e93258fSBjoern A. Zeeb } 6438e93258fSBjoern A. Zeeb break; 6448e93258fSBjoern A. Zeeb case DISABLE_KEY: 6458e93258fSBjoern A. Zeeb rtw89_hci_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1, 6468e93258fSBjoern A. Zeeb false); 6478e93258fSBjoern A. Zeeb rtw89_mac_flush_txq(rtwdev, BIT(rtwdev->hw->queues) - 1, false); 6488e93258fSBjoern A. Zeeb ret = rtw89_cam_sec_key_del(rtwdev, vif, sta, key, true); 6498e93258fSBjoern A. Zeeb if (ret) { 6508e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to remove key from sec cam\n"); 6518e93258fSBjoern A. Zeeb goto out; 6528e93258fSBjoern A. Zeeb } 6538e93258fSBjoern A. Zeeb break; 6548e93258fSBjoern A. Zeeb } 6558e93258fSBjoern A. Zeeb 6568e93258fSBjoern A. Zeeb out: 6578e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 6588e93258fSBjoern A. Zeeb 6598e93258fSBjoern A. Zeeb return ret; 6608e93258fSBjoern A. Zeeb } 6618e93258fSBjoern A. Zeeb 6628e93258fSBjoern A. Zeeb static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, 6638e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 6648e93258fSBjoern A. Zeeb struct ieee80211_ampdu_params *params) 6658e93258fSBjoern A. Zeeb { 6668e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 6678e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = params->sta; 6688e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 6698e93258fSBjoern A. Zeeb u16 tid = params->tid; 6708e93258fSBjoern A. Zeeb struct ieee80211_txq *txq = sta->txq[tid]; 6718e93258fSBjoern A. Zeeb struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv; 6728e93258fSBjoern A. Zeeb 6738e93258fSBjoern A. Zeeb switch (params->action) { 6748e93258fSBjoern A. Zeeb case IEEE80211_AMPDU_TX_START: 6758e93258fSBjoern A. Zeeb return IEEE80211_AMPDU_TX_START_IMMEDIATE; 6768e93258fSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_CONT: 6778e93258fSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_FLUSH: 6788e93258fSBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 6798e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 6808e93258fSBjoern A. Zeeb clear_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); 681*6d67aabdSBjoern A. Zeeb clear_bit(tid, rtwsta->ampdu_map); 682*6d67aabdSBjoern A. Zeeb rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); 6838e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 6848e93258fSBjoern A. Zeeb ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 6858e93258fSBjoern A. Zeeb break; 6868e93258fSBjoern A. Zeeb case IEEE80211_AMPDU_TX_OPERATIONAL: 6878e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 6888e93258fSBjoern A. Zeeb set_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); 6898e93258fSBjoern A. Zeeb rtwsta->ampdu_params[tid].agg_num = params->buf_size; 6908e93258fSBjoern A. Zeeb rtwsta->ampdu_params[tid].amsdu = params->amsdu; 691*6d67aabdSBjoern A. Zeeb set_bit(tid, rtwsta->ampdu_map); 6928e93258fSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 693*6d67aabdSBjoern A. Zeeb rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); 6948e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 6958e93258fSBjoern A. Zeeb break; 6968e93258fSBjoern A. Zeeb case IEEE80211_AMPDU_RX_START: 6978e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 698*6d67aabdSBjoern A. Zeeb rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, true, params); 6998e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 7008e93258fSBjoern A. Zeeb break; 7018e93258fSBjoern A. Zeeb case IEEE80211_AMPDU_RX_STOP: 7028e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 703*6d67aabdSBjoern A. Zeeb rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, false, params); 7048e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 7058e93258fSBjoern A. Zeeb break; 7068e93258fSBjoern A. Zeeb default: 7078e93258fSBjoern A. Zeeb WARN_ON(1); 7088e93258fSBjoern A. Zeeb return -ENOTSUPP; 7098e93258fSBjoern A. Zeeb } 7108e93258fSBjoern A. Zeeb 7118e93258fSBjoern A. Zeeb return 0; 7128e93258fSBjoern A. Zeeb } 7138e93258fSBjoern A. Zeeb 7148e93258fSBjoern A. Zeeb static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 7158e93258fSBjoern A. Zeeb { 7168e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 7178e93258fSBjoern A. Zeeb 7188e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 7198e93258fSBjoern A. Zeeb rtw89_leave_ps_mode(rtwdev); 7208e93258fSBjoern A. Zeeb if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) 7218e93258fSBjoern A. Zeeb rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0); 7228e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 7238e93258fSBjoern A. Zeeb 7248e93258fSBjoern A. Zeeb return 0; 7258e93258fSBjoern A. Zeeb } 7268e93258fSBjoern A. Zeeb 7278e93258fSBjoern A. Zeeb static void rtw89_ops_sta_statistics(struct ieee80211_hw *hw, 7288e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 7298e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, 7308e93258fSBjoern A. Zeeb struct station_info *sinfo) 7318e93258fSBjoern A. Zeeb { 7328e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 7338e93258fSBjoern A. Zeeb 7348e93258fSBjoern A. Zeeb sinfo->txrate = rtwsta->ra_report.txrate; 7358e93258fSBjoern A. Zeeb sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 7368e93258fSBjoern A. Zeeb } 7378e93258fSBjoern A. Zeeb 738e2340276SBjoern A. Zeeb static 739e2340276SBjoern A. Zeeb void __rtw89_drop_packets(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) 740e2340276SBjoern A. Zeeb { 741e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif; 742e2340276SBjoern A. Zeeb 743e2340276SBjoern A. Zeeb if (vif) { 744e2340276SBjoern A. Zeeb rtwvif = (struct rtw89_vif *)vif->drv_priv; 745e2340276SBjoern A. Zeeb rtw89_mac_pkt_drop_vif(rtwdev, rtwvif); 746e2340276SBjoern A. Zeeb } else { 747e2340276SBjoern A. Zeeb rtw89_for_each_rtwvif(rtwdev, rtwvif) 748e2340276SBjoern A. Zeeb rtw89_mac_pkt_drop_vif(rtwdev, rtwvif); 749e2340276SBjoern A. Zeeb } 750e2340276SBjoern A. Zeeb } 751e2340276SBjoern A. Zeeb 7528e93258fSBjoern A. Zeeb static void rtw89_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 7538e93258fSBjoern A. Zeeb u32 queues, bool drop) 7548e93258fSBjoern A. Zeeb { 7558e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 7568e93258fSBjoern A. Zeeb 7578e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 7588e93258fSBjoern A. Zeeb rtw89_leave_lps(rtwdev); 7598e93258fSBjoern A. Zeeb rtw89_hci_flush_queues(rtwdev, queues, drop); 760e2340276SBjoern A. Zeeb 761e2340276SBjoern A. Zeeb if (drop && !RTW89_CHK_FW_FEATURE(NO_PACKET_DROP, &rtwdev->fw)) 762e2340276SBjoern A. Zeeb __rtw89_drop_packets(rtwdev, vif); 763e2340276SBjoern A. Zeeb else 7648e93258fSBjoern A. Zeeb rtw89_mac_flush_txq(rtwdev, queues, drop); 765e2340276SBjoern A. Zeeb 7668e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 7678e93258fSBjoern A. Zeeb } 7688e93258fSBjoern A. Zeeb 7698e93258fSBjoern A. Zeeb struct rtw89_iter_bitrate_mask_data { 7708e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev; 7718e93258fSBjoern A. Zeeb struct ieee80211_vif *vif; 7728e93258fSBjoern A. Zeeb const struct cfg80211_bitrate_mask *mask; 7738e93258fSBjoern A. Zeeb }; 7748e93258fSBjoern A. Zeeb 7758e93258fSBjoern A. Zeeb static void rtw89_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta) 7768e93258fSBjoern A. Zeeb { 7778e93258fSBjoern A. Zeeb struct rtw89_iter_bitrate_mask_data *br_data = data; 7788e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 7798e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif); 7808e93258fSBjoern A. Zeeb 781e2340276SBjoern A. Zeeb if (vif != br_data->vif || vif->p2p) 7828e93258fSBjoern A. Zeeb return; 7838e93258fSBjoern A. Zeeb 7848e93258fSBjoern A. Zeeb rtwsta->use_cfg_mask = true; 7858e93258fSBjoern A. Zeeb rtwsta->mask = *br_data->mask; 7868e93258fSBjoern A. Zeeb rtw89_phy_ra_updata_sta(br_data->rtwdev, sta, IEEE80211_RC_SUPP_RATES_CHANGED); 7878e93258fSBjoern A. Zeeb } 7888e93258fSBjoern A. Zeeb 7898e93258fSBjoern A. Zeeb static void rtw89_ra_mask_info_update(struct rtw89_dev *rtwdev, 7908e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 7918e93258fSBjoern A. Zeeb const struct cfg80211_bitrate_mask *mask) 7928e93258fSBjoern A. Zeeb { 7938e93258fSBjoern A. Zeeb struct rtw89_iter_bitrate_mask_data br_data = { .rtwdev = rtwdev, 7948e93258fSBjoern A. Zeeb .vif = vif, 7958e93258fSBjoern A. Zeeb .mask = mask}; 7968e93258fSBjoern A. Zeeb 7978e93258fSBjoern A. Zeeb ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_ra_mask_info_update_iter, 7988e93258fSBjoern A. Zeeb &br_data); 7998e93258fSBjoern A. Zeeb } 8008e93258fSBjoern A. Zeeb 8018e93258fSBjoern A. Zeeb static int rtw89_ops_set_bitrate_mask(struct ieee80211_hw *hw, 8028e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 8038e93258fSBjoern A. Zeeb const struct cfg80211_bitrate_mask *mask) 8048e93258fSBjoern A. Zeeb { 8058e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 8068e93258fSBjoern A. Zeeb 8078e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 8088e93258fSBjoern A. Zeeb rtw89_phy_rate_pattern_vif(rtwdev, vif, mask); 8098e93258fSBjoern A. Zeeb rtw89_ra_mask_info_update(rtwdev, vif, mask); 8108e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 8118e93258fSBjoern A. Zeeb 8128e93258fSBjoern A. Zeeb return 0; 8138e93258fSBjoern A. Zeeb } 8148e93258fSBjoern A. Zeeb 8158e93258fSBjoern A. Zeeb static 8168e93258fSBjoern A. Zeeb int rtw89_ops_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 8178e93258fSBjoern A. Zeeb { 8188e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 8198e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal; 8208e93258fSBjoern A. Zeeb 821e2340276SBjoern A. Zeeb if (hal->ant_diversity) { 822e2340276SBjoern A. Zeeb if (tx_ant != rx_ant || hweight32(tx_ant) != 1) 8238e93258fSBjoern A. Zeeb return -EINVAL; 824e2340276SBjoern A. Zeeb } else if (rx_ant != hw->wiphy->available_antennas_rx && rx_ant != hal->antenna_rx) { 825e2340276SBjoern A. Zeeb return -EINVAL; 826e2340276SBjoern A. Zeeb } 8278e93258fSBjoern A. Zeeb 8288e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 8298e93258fSBjoern A. Zeeb hal->antenna_tx = tx_ant; 8308e93258fSBjoern A. Zeeb hal->antenna_rx = rx_ant; 831e2340276SBjoern A. Zeeb hal->tx_path_diversity = false; 832e2340276SBjoern A. Zeeb hal->ant_diversity_fixed = true; 8338e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 8348e93258fSBjoern A. Zeeb 8358e93258fSBjoern A. Zeeb return 0; 8368e93258fSBjoern A. Zeeb } 8378e93258fSBjoern A. Zeeb 8388e93258fSBjoern A. Zeeb static 8398e93258fSBjoern A. Zeeb int rtw89_ops_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 8408e93258fSBjoern A. Zeeb { 8418e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 8428e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal; 8438e93258fSBjoern A. Zeeb 8448e93258fSBjoern A. Zeeb *tx_ant = hal->antenna_tx; 8458e93258fSBjoern A. Zeeb *rx_ant = hal->antenna_rx; 8468e93258fSBjoern A. Zeeb 8478e93258fSBjoern A. Zeeb return 0; 8488e93258fSBjoern A. Zeeb } 8498e93258fSBjoern A. Zeeb 8508e93258fSBjoern A. Zeeb static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, 8518e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 8528e93258fSBjoern A. Zeeb const u8 *mac_addr) 8538e93258fSBjoern A. Zeeb { 8548e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 8558e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 8568e93258fSBjoern A. Zeeb 8578e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 8588e93258fSBjoern A. Zeeb rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, false); 8598e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 8608e93258fSBjoern A. Zeeb } 8618e93258fSBjoern A. Zeeb 8628e93258fSBjoern A. Zeeb static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw, 8638e93258fSBjoern A. Zeeb struct ieee80211_vif *vif) 8648e93258fSBjoern A. Zeeb { 8658e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 8668e93258fSBjoern A. Zeeb 8678e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 8688e93258fSBjoern A. Zeeb rtw89_core_scan_complete(rtwdev, vif, false); 8698e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 8708e93258fSBjoern A. Zeeb } 8718e93258fSBjoern A. Zeeb 8728e93258fSBjoern A. Zeeb static void rtw89_ops_reconfig_complete(struct ieee80211_hw *hw, 8738e93258fSBjoern A. Zeeb enum ieee80211_reconfig_type reconfig_type) 8748e93258fSBjoern A. Zeeb { 8758e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 8768e93258fSBjoern A. Zeeb 8778e93258fSBjoern A. Zeeb if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART) 8788e93258fSBjoern A. Zeeb rtw89_ser_recfg_done(rtwdev); 8798e93258fSBjoern A. Zeeb } 8808e93258fSBjoern A. Zeeb 8818e93258fSBjoern A. Zeeb static int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 8828e93258fSBjoern A. Zeeb struct ieee80211_scan_request *req) 8838e93258fSBjoern A. Zeeb { 8848e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 885e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); 8868e93258fSBjoern A. Zeeb int ret = 0; 8878e93258fSBjoern A. Zeeb 8888e93258fSBjoern A. Zeeb if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) 8898e93258fSBjoern A. Zeeb return 1; 8908e93258fSBjoern A. Zeeb 891e2340276SBjoern A. Zeeb if (rtwdev->scanning || rtwvif->offchan) 8928e93258fSBjoern A. Zeeb return -EBUSY; 8938e93258fSBjoern A. Zeeb 8948e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 8958e93258fSBjoern A. Zeeb rtw89_hw_scan_start(rtwdev, vif, req); 8968e93258fSBjoern A. Zeeb ret = rtw89_hw_scan_offload(rtwdev, vif, true); 8978e93258fSBjoern A. Zeeb if (ret) { 8988e93258fSBjoern A. Zeeb rtw89_hw_scan_abort(rtwdev, vif); 8998e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "HW scan failed with status: %d\n", ret); 9008e93258fSBjoern A. Zeeb } 9018e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 9028e93258fSBjoern A. Zeeb 9038e93258fSBjoern A. Zeeb return ret; 9048e93258fSBjoern A. Zeeb } 9058e93258fSBjoern A. Zeeb 9068e93258fSBjoern A. Zeeb static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw, 9078e93258fSBjoern A. Zeeb struct ieee80211_vif *vif) 9088e93258fSBjoern A. Zeeb { 9098e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 9108e93258fSBjoern A. Zeeb 9118e93258fSBjoern A. Zeeb if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) 9128e93258fSBjoern A. Zeeb return; 9138e93258fSBjoern A. Zeeb 9148e93258fSBjoern A. Zeeb if (!rtwdev->scanning) 9158e93258fSBjoern A. Zeeb return; 9168e93258fSBjoern A. Zeeb 9178e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 9188e93258fSBjoern A. Zeeb rtw89_hw_scan_abort(rtwdev, vif); 9198e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 9208e93258fSBjoern A. Zeeb } 9218e93258fSBjoern A. Zeeb 9228e93258fSBjoern A. Zeeb static void rtw89_ops_sta_rc_update(struct ieee80211_hw *hw, 9238e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 9248e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, u32 changed) 9258e93258fSBjoern A. Zeeb { 9268e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 9278e93258fSBjoern A. Zeeb 9288e93258fSBjoern A. Zeeb rtw89_phy_ra_updata_sta(rtwdev, sta, changed); 9298e93258fSBjoern A. Zeeb } 9308e93258fSBjoern A. Zeeb 9318e93258fSBjoern A. Zeeb static int rtw89_ops_add_chanctx(struct ieee80211_hw *hw, 9328e93258fSBjoern A. Zeeb struct ieee80211_chanctx_conf *ctx) 9338e93258fSBjoern A. Zeeb { 9348e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 9358e93258fSBjoern A. Zeeb int ret; 9368e93258fSBjoern A. Zeeb 9378e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 9388e93258fSBjoern A. Zeeb ret = rtw89_chanctx_ops_add(rtwdev, ctx); 9398e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 9408e93258fSBjoern A. Zeeb 9418e93258fSBjoern A. Zeeb return ret; 9428e93258fSBjoern A. Zeeb } 9438e93258fSBjoern A. Zeeb 9448e93258fSBjoern A. Zeeb static void rtw89_ops_remove_chanctx(struct ieee80211_hw *hw, 9458e93258fSBjoern A. Zeeb struct ieee80211_chanctx_conf *ctx) 9468e93258fSBjoern A. Zeeb { 9478e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 9488e93258fSBjoern A. Zeeb 9498e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 9508e93258fSBjoern A. Zeeb rtw89_chanctx_ops_remove(rtwdev, ctx); 9518e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 9528e93258fSBjoern A. Zeeb } 9538e93258fSBjoern A. Zeeb 9548e93258fSBjoern A. Zeeb static void rtw89_ops_change_chanctx(struct ieee80211_hw *hw, 9558e93258fSBjoern A. Zeeb struct ieee80211_chanctx_conf *ctx, 9568e93258fSBjoern A. Zeeb u32 changed) 9578e93258fSBjoern A. Zeeb { 9588e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 9598e93258fSBjoern A. Zeeb 9608e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 9618e93258fSBjoern A. Zeeb rtw89_chanctx_ops_change(rtwdev, ctx, changed); 9628e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 9638e93258fSBjoern A. Zeeb } 9648e93258fSBjoern A. Zeeb 9658e93258fSBjoern A. Zeeb static int rtw89_ops_assign_vif_chanctx(struct ieee80211_hw *hw, 9668e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 9678e93258fSBjoern A. Zeeb struct ieee80211_bss_conf *link_conf, 9688e93258fSBjoern A. Zeeb struct ieee80211_chanctx_conf *ctx) 9698e93258fSBjoern A. Zeeb { 9708e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 9718e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 9728e93258fSBjoern A. Zeeb int ret; 9738e93258fSBjoern A. Zeeb 9748e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 9758e93258fSBjoern A. Zeeb ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif, ctx); 9768e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 9778e93258fSBjoern A. Zeeb 9788e93258fSBjoern A. Zeeb return ret; 9798e93258fSBjoern A. Zeeb } 9808e93258fSBjoern A. Zeeb 9818e93258fSBjoern A. Zeeb static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw, 9828e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, 9838e93258fSBjoern A. Zeeb struct ieee80211_bss_conf *link_conf, 9848e93258fSBjoern A. Zeeb struct ieee80211_chanctx_conf *ctx) 9858e93258fSBjoern A. Zeeb { 9868e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 9878e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 9888e93258fSBjoern A. Zeeb 9898e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 9908e93258fSBjoern A. Zeeb rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif, ctx); 9918e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 9928e93258fSBjoern A. Zeeb } 9938e93258fSBjoern A. Zeeb 994e2340276SBjoern A. Zeeb static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, 995e2340276SBjoern A. Zeeb struct ieee80211_vif *vif, 996e2340276SBjoern A. Zeeb struct ieee80211_channel *chan, 997e2340276SBjoern A. Zeeb int duration, 998e2340276SBjoern A. Zeeb enum ieee80211_roc_type type) 999e2340276SBjoern A. Zeeb { 1000e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 1001e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); 1002e2340276SBjoern A. Zeeb struct rtw89_roc *roc = &rtwvif->roc; 1003e2340276SBjoern A. Zeeb 1004e2340276SBjoern A. Zeeb if (!vif) 1005e2340276SBjoern A. Zeeb return -EINVAL; 1006e2340276SBjoern A. Zeeb 1007e2340276SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 1008e2340276SBjoern A. Zeeb 1009e2340276SBjoern A. Zeeb if (roc->state != RTW89_ROC_IDLE) { 1010e2340276SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1011e2340276SBjoern A. Zeeb return -EBUSY; 1012e2340276SBjoern A. Zeeb } 1013e2340276SBjoern A. Zeeb 1014e2340276SBjoern A. Zeeb if (rtwdev->scanning) 1015*6d67aabdSBjoern A. Zeeb rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); 1016e2340276SBjoern A. Zeeb 1017e2340276SBjoern A. Zeeb if (type == IEEE80211_ROC_TYPE_MGMT_TX) 1018e2340276SBjoern A. Zeeb roc->state = RTW89_ROC_MGMT; 1019e2340276SBjoern A. Zeeb else 1020e2340276SBjoern A. Zeeb roc->state = RTW89_ROC_NORMAL; 1021e2340276SBjoern A. Zeeb 1022e2340276SBjoern A. Zeeb roc->duration = duration; 1023e2340276SBjoern A. Zeeb roc->chan = *chan; 1024e2340276SBjoern A. Zeeb roc->type = type; 1025e2340276SBjoern A. Zeeb 1026e2340276SBjoern A. Zeeb rtw89_roc_start(rtwdev, rtwvif); 1027e2340276SBjoern A. Zeeb 1028e2340276SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1029e2340276SBjoern A. Zeeb 1030e2340276SBjoern A. Zeeb return 0; 1031e2340276SBjoern A. Zeeb } 1032e2340276SBjoern A. Zeeb 1033e2340276SBjoern A. Zeeb static int rtw89_ops_cancel_remain_on_channel(struct ieee80211_hw *hw, 1034e2340276SBjoern A. Zeeb struct ieee80211_vif *vif) 1035e2340276SBjoern A. Zeeb { 1036e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 1037e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); 1038e2340276SBjoern A. Zeeb 1039e2340276SBjoern A. Zeeb if (!rtwvif) 1040e2340276SBjoern A. Zeeb return -EINVAL; 1041e2340276SBjoern A. Zeeb 1042e2340276SBjoern A. Zeeb cancel_delayed_work_sync(&rtwvif->roc.roc_work); 1043e2340276SBjoern A. Zeeb 1044e2340276SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 1045e2340276SBjoern A. Zeeb rtw89_roc_end(rtwdev, rtwvif); 1046e2340276SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1047e2340276SBjoern A. Zeeb 1048e2340276SBjoern A. Zeeb return 0; 1049e2340276SBjoern A. Zeeb } 1050e2340276SBjoern A. Zeeb 1051e2340276SBjoern A. Zeeb static void rtw89_set_tid_config_iter(void *data, struct ieee80211_sta *sta) 1052e2340276SBjoern A. Zeeb { 1053e2340276SBjoern A. Zeeb struct cfg80211_tid_config *tid_config = data; 1054e2340276SBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 1055e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = rtwsta->rtwvif->rtwdev; 1056e2340276SBjoern A. Zeeb 1057e2340276SBjoern A. Zeeb rtw89_core_set_tid_config(rtwdev, sta, tid_config); 1058e2340276SBjoern A. Zeeb } 1059e2340276SBjoern A. Zeeb 1060e2340276SBjoern A. Zeeb static int rtw89_ops_set_tid_config(struct ieee80211_hw *hw, 1061e2340276SBjoern A. Zeeb struct ieee80211_vif *vif, 1062e2340276SBjoern A. Zeeb struct ieee80211_sta *sta, 1063e2340276SBjoern A. Zeeb struct cfg80211_tid_config *tid_config) 1064e2340276SBjoern A. Zeeb { 1065e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 1066e2340276SBjoern A. Zeeb 1067e2340276SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 1068e2340276SBjoern A. Zeeb if (sta) 1069e2340276SBjoern A. Zeeb rtw89_core_set_tid_config(rtwdev, sta, tid_config); 1070e2340276SBjoern A. Zeeb else 1071e2340276SBjoern A. Zeeb ieee80211_iterate_stations_atomic(rtwdev->hw, 1072e2340276SBjoern A. Zeeb rtw89_set_tid_config_iter, 1073e2340276SBjoern A. Zeeb tid_config); 1074e2340276SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1075e2340276SBjoern A. Zeeb 1076e2340276SBjoern A. Zeeb return 0; 1077e2340276SBjoern A. Zeeb } 1078e2340276SBjoern A. Zeeb 1079e2340276SBjoern A. Zeeb #ifdef CONFIG_PM 1080e2340276SBjoern A. Zeeb static int rtw89_ops_suspend(struct ieee80211_hw *hw, 1081e2340276SBjoern A. Zeeb struct cfg80211_wowlan *wowlan) 1082e2340276SBjoern A. Zeeb { 1083e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 1084e2340276SBjoern A. Zeeb int ret; 1085e2340276SBjoern A. Zeeb 1086e2340276SBjoern A. Zeeb set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); 1087e2340276SBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->track_work); 1088e2340276SBjoern A. Zeeb 1089e2340276SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 1090e2340276SBjoern A. Zeeb ret = rtw89_wow_suspend(rtwdev, wowlan); 1091e2340276SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1092e2340276SBjoern A. Zeeb 1093e2340276SBjoern A. Zeeb if (ret) { 1094e2340276SBjoern A. Zeeb rtw89_warn(rtwdev, "failed to suspend for wow %d\n", ret); 1095e2340276SBjoern A. Zeeb clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); 1096e2340276SBjoern A. Zeeb return 1; 1097e2340276SBjoern A. Zeeb } 1098e2340276SBjoern A. Zeeb 1099e2340276SBjoern A. Zeeb return 0; 1100e2340276SBjoern A. Zeeb } 1101e2340276SBjoern A. Zeeb 1102e2340276SBjoern A. Zeeb static int rtw89_ops_resume(struct ieee80211_hw *hw) 1103e2340276SBjoern A. Zeeb { 1104e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 1105e2340276SBjoern A. Zeeb int ret; 1106e2340276SBjoern A. Zeeb 1107e2340276SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 1108e2340276SBjoern A. Zeeb ret = rtw89_wow_resume(rtwdev); 1109e2340276SBjoern A. Zeeb if (ret) 1110e2340276SBjoern A. Zeeb rtw89_warn(rtwdev, "failed to resume for wow %d\n", ret); 1111e2340276SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1112e2340276SBjoern A. Zeeb 1113e2340276SBjoern A. Zeeb clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); 1114e2340276SBjoern A. Zeeb ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work, 1115e2340276SBjoern A. Zeeb RTW89_TRACK_WORK_PERIOD); 1116e2340276SBjoern A. Zeeb 1117e2340276SBjoern A. Zeeb return ret ? 1 : 0; 1118e2340276SBjoern A. Zeeb } 1119e2340276SBjoern A. Zeeb 1120e2340276SBjoern A. Zeeb static void rtw89_ops_set_wakeup(struct ieee80211_hw *hw, bool enabled) 1121e2340276SBjoern A. Zeeb { 1122e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 1123e2340276SBjoern A. Zeeb 1124e2340276SBjoern A. Zeeb device_set_wakeup_enable(rtwdev->dev, enabled); 1125e2340276SBjoern A. Zeeb } 1126*6d67aabdSBjoern A. Zeeb 1127*6d67aabdSBjoern A. Zeeb static void rtw89_set_rekey_data(struct ieee80211_hw *hw, 1128*6d67aabdSBjoern A. Zeeb struct ieee80211_vif *vif, 1129*6d67aabdSBjoern A. Zeeb struct cfg80211_gtk_rekey_data *data) 1130*6d67aabdSBjoern A. Zeeb { 1131*6d67aabdSBjoern A. Zeeb struct rtw89_dev *rtwdev = hw->priv; 1132*6d67aabdSBjoern A. Zeeb struct rtw89_wow_param *rtw_wow = &rtwdev->wow; 1133*6d67aabdSBjoern A. Zeeb struct rtw89_wow_gtk_info *gtk_info = &rtw_wow->gtk_info; 1134*6d67aabdSBjoern A. Zeeb 1135*6d67aabdSBjoern A. Zeeb if (data->kek_len > sizeof(gtk_info->kek) || 1136*6d67aabdSBjoern A. Zeeb data->kck_len > sizeof(gtk_info->kck)) { 1137*6d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "kek or kck length over fw limit\n"); 1138*6d67aabdSBjoern A. Zeeb return; 1139*6d67aabdSBjoern A. Zeeb } 1140*6d67aabdSBjoern A. Zeeb 1141*6d67aabdSBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 1142*6d67aabdSBjoern A. Zeeb 1143*6d67aabdSBjoern A. Zeeb memcpy(gtk_info->kek, data->kek, data->kek_len); 1144*6d67aabdSBjoern A. Zeeb memcpy(gtk_info->kck, data->kck, data->kck_len); 1145*6d67aabdSBjoern A. Zeeb 1146*6d67aabdSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1147*6d67aabdSBjoern A. Zeeb } 1148e2340276SBjoern A. Zeeb #endif 1149e2340276SBjoern A. Zeeb 11508e93258fSBjoern A. Zeeb const struct ieee80211_ops rtw89_ops = { 11518e93258fSBjoern A. Zeeb .tx = rtw89_ops_tx, 11528e93258fSBjoern A. Zeeb .wake_tx_queue = rtw89_ops_wake_tx_queue, 11538e93258fSBjoern A. Zeeb .start = rtw89_ops_start, 11548e93258fSBjoern A. Zeeb .stop = rtw89_ops_stop, 11558e93258fSBjoern A. Zeeb .config = rtw89_ops_config, 11568e93258fSBjoern A. Zeeb .add_interface = rtw89_ops_add_interface, 1157e2340276SBjoern A. Zeeb .change_interface = rtw89_ops_change_interface, 11588e93258fSBjoern A. Zeeb .remove_interface = rtw89_ops_remove_interface, 11598e93258fSBjoern A. Zeeb .configure_filter = rtw89_ops_configure_filter, 1160*6d67aabdSBjoern A. Zeeb .vif_cfg_changed = rtw89_ops_vif_cfg_changed, 1161*6d67aabdSBjoern A. Zeeb .link_info_changed = rtw89_ops_link_info_changed, 11628e93258fSBjoern A. Zeeb .start_ap = rtw89_ops_start_ap, 11638e93258fSBjoern A. Zeeb .stop_ap = rtw89_ops_stop_ap, 11648e93258fSBjoern A. Zeeb .set_tim = rtw89_ops_set_tim, 11658e93258fSBjoern A. Zeeb .conf_tx = rtw89_ops_conf_tx, 11668e93258fSBjoern A. Zeeb .sta_state = rtw89_ops_sta_state, 11678e93258fSBjoern A. Zeeb .set_key = rtw89_ops_set_key, 11688e93258fSBjoern A. Zeeb .ampdu_action = rtw89_ops_ampdu_action, 11698e93258fSBjoern A. Zeeb .set_rts_threshold = rtw89_ops_set_rts_threshold, 11708e93258fSBjoern A. Zeeb .sta_statistics = rtw89_ops_sta_statistics, 11718e93258fSBjoern A. Zeeb .flush = rtw89_ops_flush, 11728e93258fSBjoern A. Zeeb .set_bitrate_mask = rtw89_ops_set_bitrate_mask, 11738e93258fSBjoern A. Zeeb .set_antenna = rtw89_ops_set_antenna, 11748e93258fSBjoern A. Zeeb .get_antenna = rtw89_ops_get_antenna, 11758e93258fSBjoern A. Zeeb .sw_scan_start = rtw89_ops_sw_scan_start, 11768e93258fSBjoern A. Zeeb .sw_scan_complete = rtw89_ops_sw_scan_complete, 11778e93258fSBjoern A. Zeeb .reconfig_complete = rtw89_ops_reconfig_complete, 11788e93258fSBjoern A. Zeeb .hw_scan = rtw89_ops_hw_scan, 11798e93258fSBjoern A. Zeeb .cancel_hw_scan = rtw89_ops_cancel_hw_scan, 11808e93258fSBjoern A. Zeeb .add_chanctx = rtw89_ops_add_chanctx, 11818e93258fSBjoern A. Zeeb .remove_chanctx = rtw89_ops_remove_chanctx, 11828e93258fSBjoern A. Zeeb .change_chanctx = rtw89_ops_change_chanctx, 11838e93258fSBjoern A. Zeeb .assign_vif_chanctx = rtw89_ops_assign_vif_chanctx, 11848e93258fSBjoern A. Zeeb .unassign_vif_chanctx = rtw89_ops_unassign_vif_chanctx, 1185e2340276SBjoern A. Zeeb .remain_on_channel = rtw89_ops_remain_on_channel, 1186e2340276SBjoern A. Zeeb .cancel_remain_on_channel = rtw89_ops_cancel_remain_on_channel, 11878e93258fSBjoern A. Zeeb .set_sar_specs = rtw89_ops_set_sar_specs, 11888e93258fSBjoern A. Zeeb .sta_rc_update = rtw89_ops_sta_rc_update, 1189e2340276SBjoern A. Zeeb .set_tid_config = rtw89_ops_set_tid_config, 1190e2340276SBjoern A. Zeeb #ifdef CONFIG_PM 1191e2340276SBjoern A. Zeeb .suspend = rtw89_ops_suspend, 1192e2340276SBjoern A. Zeeb .resume = rtw89_ops_resume, 1193e2340276SBjoern A. Zeeb .set_wakeup = rtw89_ops_set_wakeup, 1194*6d67aabdSBjoern A. Zeeb .set_rekey_data = rtw89_set_rekey_data, 1195e2340276SBjoern A. Zeeb #endif 11968e93258fSBjoern A. Zeeb }; 11978e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_ops); 1198