Path: blob/master/drivers/net/wireless/realtek/rtw88/mac80211.c
25924 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/* Copyright(c) 2018-2019 Realtek Corporation2*/34#include "main.h"5#include "sec.h"6#include "tx.h"7#include "fw.h"8#include "mac.h"9#include "coex.h"10#include "ps.h"11#include "reg.h"12#include "bf.h"13#include "debug.h"14#include "wow.h"15#include "sar.h"1617static void rtw_ops_tx(struct ieee80211_hw *hw,18struct ieee80211_tx_control *control,19struct sk_buff *skb)20{21struct rtw_dev *rtwdev = hw->priv;2223if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) {24ieee80211_free_txskb(hw, skb);25return;26}2728rtw_tx(rtwdev, control, skb);29}3031static void rtw_ops_wake_tx_queue(struct ieee80211_hw *hw,32struct ieee80211_txq *txq)33{34struct rtw_dev *rtwdev = hw->priv;35struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv;3637if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags))38return;3940spin_lock_bh(&rtwdev->txq_lock);41if (list_empty(&rtwtxq->list))42list_add_tail(&rtwtxq->list, &rtwdev->txqs);43spin_unlock_bh(&rtwdev->txq_lock);4445/* ensure to dequeue EAPOL (4/4) at the right time */46if (txq->ac == IEEE80211_AC_VO)47__rtw_tx_work(rtwdev);48else49queue_work(rtwdev->tx_wq, &rtwdev->tx_work);50}5152static int rtw_ops_start(struct ieee80211_hw *hw)53{54struct rtw_dev *rtwdev = hw->priv;55int ret;5657mutex_lock(&rtwdev->mutex);58ret = rtw_core_start(rtwdev);59mutex_unlock(&rtwdev->mutex);6061return ret;62}6364static void rtw_ops_stop(struct ieee80211_hw *hw, bool suspend)65{66struct rtw_dev *rtwdev = hw->priv;6768mutex_lock(&rtwdev->mutex);69rtw_core_stop(rtwdev);70mutex_unlock(&rtwdev->mutex);71}7273static int rtw_ops_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)74{75struct rtw_dev *rtwdev = hw->priv;76int ret = 0;7778/* let previous ips work finish to ensure we don't leave ips twice */79cancel_work_sync(&rtwdev->ips_work);8081mutex_lock(&rtwdev->mutex);8283rtw_leave_lps_deep(rtwdev);8485if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&86!(hw->conf.flags & IEEE80211_CONF_IDLE)) {87ret = rtw_leave_ips(rtwdev);88if (ret) {89rtw_err(rtwdev, "failed to leave idle state\n");90goto out;91}92}9394if (changed & IEEE80211_CONF_CHANGE_CHANNEL)95rtw_set_channel(rtwdev);9697if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&98(hw->conf.flags & IEEE80211_CONF_IDLE) &&99!test_bit(RTW_FLAG_SCANNING, rtwdev->flags))100rtw_enter_ips(rtwdev);101102out:103mutex_unlock(&rtwdev->mutex);104return ret;105}106107static const struct rtw_vif_port rtw_vif_port[] = {108[0] = {109.mac_addr = {.addr = 0x0610},110.bssid = {.addr = 0x0618},111.net_type = {.addr = 0x0100, .mask = 0x30000},112.aid = {.addr = 0x06a8, .mask = 0x7ff},113.bcn_ctrl = {.addr = 0x0550, .mask = 0xff},114},115[1] = {116.mac_addr = {.addr = 0x0700},117.bssid = {.addr = 0x0708},118.net_type = {.addr = 0x0100, .mask = 0xc0000},119.aid = {.addr = 0x0710, .mask = 0x7ff},120.bcn_ctrl = {.addr = 0x0551, .mask = 0xff},121},122[2] = {123.mac_addr = {.addr = 0x1620},124.bssid = {.addr = 0x1628},125.net_type = {.addr = 0x1100, .mask = 0x3},126.aid = {.addr = 0x1600, .mask = 0x7ff},127.bcn_ctrl = {.addr = 0x0578, .mask = 0xff},128},129[3] = {130.mac_addr = {.addr = 0x1630},131.bssid = {.addr = 0x1638},132.net_type = {.addr = 0x1100, .mask = 0xc},133.aid = {.addr = 0x1604, .mask = 0x7ff},134.bcn_ctrl = {.addr = 0x0579, .mask = 0xff},135},136[4] = {137.mac_addr = {.addr = 0x1640},138.bssid = {.addr = 0x1648},139.net_type = {.addr = 0x1100, .mask = 0x30},140.aid = {.addr = 0x1608, .mask = 0x7ff},141.bcn_ctrl = {.addr = 0x057a, .mask = 0xff},142},143};144145static int rtw_ops_add_interface(struct ieee80211_hw *hw,146struct ieee80211_vif *vif)147{148struct rtw_dev *rtwdev = hw->priv;149struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;150enum rtw_net_type net_type;151u32 config = 0;152u8 port;153u8 bcn_ctrl = 0;154155if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER))156vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |157IEEE80211_VIF_SUPPORTS_CQM_RSSI;158rtwvif->stats.tx_unicast = 0;159rtwvif->stats.rx_unicast = 0;160rtwvif->stats.tx_cnt = 0;161rtwvif->stats.rx_cnt = 0;162rtwvif->scan_req = NULL;163memset(&rtwvif->bfee, 0, sizeof(struct rtw_bfee));164rtw_txq_init(rtwdev, vif->txq);165INIT_LIST_HEAD(&rtwvif->rsvd_page_list);166167mutex_lock(&rtwdev->mutex);168169rtwvif->mac_id = rtw_acquire_macid(rtwdev);170if (rtwvif->mac_id >= RTW_MAX_MAC_ID_NUM) {171mutex_unlock(&rtwdev->mutex);172return -ENOSPC;173}174175port = find_first_zero_bit(rtwdev->hw_port, RTW_PORT_NUM);176if (port >= RTW_PORT_NUM) {177mutex_unlock(&rtwdev->mutex);178return -EINVAL;179}180set_bit(port, rtwdev->hw_port);181182rtwvif->port = port;183rtwvif->conf = &rtw_vif_port[port];184rtw_leave_lps_deep(rtwdev);185186switch (vif->type) {187case NL80211_IFTYPE_AP:188case NL80211_IFTYPE_MESH_POINT:189rtw_add_rsvd_page_bcn(rtwdev, rtwvif);190net_type = RTW_NET_AP_MODE;191bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT;192break;193case NL80211_IFTYPE_ADHOC:194rtw_add_rsvd_page_bcn(rtwdev, rtwvif);195net_type = RTW_NET_AD_HOC;196bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT;197break;198case NL80211_IFTYPE_STATION:199rtw_add_rsvd_page_sta(rtwdev, rtwvif);200net_type = RTW_NET_NO_LINK;201bcn_ctrl = BIT_EN_BCN_FUNCTION;202break;203default:204WARN_ON(1);205clear_bit(rtwvif->port, rtwdev->hw_port);206mutex_unlock(&rtwdev->mutex);207return -EINVAL;208}209210ether_addr_copy(rtwvif->mac_addr, vif->addr);211config |= PORT_SET_MAC_ADDR;212rtwvif->net_type = net_type;213config |= PORT_SET_NET_TYPE;214rtwvif->bcn_ctrl = bcn_ctrl;215config |= PORT_SET_BCN_CTRL;216rtw_vif_port_config(rtwdev, rtwvif, config);217rtw_core_port_switch(rtwdev, vif);218rtw_recalc_lps(rtwdev, vif);219220mutex_unlock(&rtwdev->mutex);221222rtw_dbg(rtwdev, RTW_DBG_STATE, "start vif %pM mac_id %d on port %d\n",223vif->addr, rtwvif->mac_id, rtwvif->port);224return 0;225}226227static void rtw_ops_remove_interface(struct ieee80211_hw *hw,228struct ieee80211_vif *vif)229{230struct rtw_dev *rtwdev = hw->priv;231struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;232u32 config = 0;233234rtw_dbg(rtwdev, RTW_DBG_STATE, "stop vif %pM mac_id %d on port %d\n",235vif->addr, rtwvif->mac_id, rtwvif->port);236237mutex_lock(&rtwdev->mutex);238239rtw_leave_lps_deep(rtwdev);240241rtw_txq_cleanup(rtwdev, vif->txq);242rtw_remove_rsvd_page(rtwdev, rtwvif);243244eth_zero_addr(rtwvif->mac_addr);245config |= PORT_SET_MAC_ADDR;246rtwvif->net_type = RTW_NET_NO_LINK;247config |= PORT_SET_NET_TYPE;248rtwvif->bcn_ctrl = 0;249config |= PORT_SET_BCN_CTRL;250rtw_vif_port_config(rtwdev, rtwvif, config);251clear_bit(rtwvif->port, rtwdev->hw_port);252rtw_release_macid(rtwdev, rtwvif->mac_id);253rtw_recalc_lps(rtwdev, NULL);254255mutex_unlock(&rtwdev->mutex);256}257258static int rtw_ops_change_interface(struct ieee80211_hw *hw,259struct ieee80211_vif *vif,260enum nl80211_iftype type, bool p2p)261{262struct rtw_dev *rtwdev = hw->priv;263264rtw_dbg(rtwdev, RTW_DBG_STATE, "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n",265vif->addr, vif->type, type, vif->p2p, p2p);266267rtw_ops_remove_interface(hw, vif);268269vif->type = type;270vif->p2p = p2p;271272return rtw_ops_add_interface(hw, vif);273}274275static void rtw_ops_configure_filter(struct ieee80211_hw *hw,276unsigned int changed_flags,277unsigned int *new_flags,278u64 multicast)279{280struct rtw_dev *rtwdev = hw->priv;281282*new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL |283FIF_BCN_PRBRESP_PROMISC;284285mutex_lock(&rtwdev->mutex);286287rtw_leave_lps_deep(rtwdev);288289if (changed_flags & FIF_ALLMULTI) {290if (*new_flags & FIF_ALLMULTI)291rtwdev->hal.rcr |= BIT_AM;292else293rtwdev->hal.rcr &= ~(BIT_AM);294}295if (changed_flags & FIF_FCSFAIL) {296if (*new_flags & FIF_FCSFAIL)297rtwdev->hal.rcr |= BIT_ACRC32;298else299rtwdev->hal.rcr &= ~(BIT_ACRC32);300}301if (changed_flags & FIF_OTHER_BSS) {302if (*new_flags & FIF_OTHER_BSS)303rtwdev->hal.rcr |= BIT_AAP;304else305rtwdev->hal.rcr &= ~(BIT_AAP);306}307if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {308if (*new_flags & FIF_BCN_PRBRESP_PROMISC)309rtwdev->hal.rcr &= ~(BIT_CBSSID_BCN | BIT_CBSSID_DATA);310else311rtwdev->hal.rcr |= BIT_CBSSID_BCN;312}313314rtw_dbg(rtwdev, RTW_DBG_RX,315"config rx filter, changed=0x%08x, new=0x%08x, rcr=0x%08x\n",316changed_flags, *new_flags, rtwdev->hal.rcr);317318rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr);319320mutex_unlock(&rtwdev->mutex);321}322323/* Only have one group of EDCA parameters now */324static const u32 ac_to_edca_param[IEEE80211_NUM_ACS] = {325[IEEE80211_AC_VO] = REG_EDCA_VO_PARAM,326[IEEE80211_AC_VI] = REG_EDCA_VI_PARAM,327[IEEE80211_AC_BE] = REG_EDCA_BE_PARAM,328[IEEE80211_AC_BK] = REG_EDCA_BK_PARAM,329};330331static u8 rtw_aifsn_to_aifs(struct rtw_dev *rtwdev,332struct rtw_vif *rtwvif, u8 aifsn)333{334struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);335u8 slot_time;336u8 sifs;337338slot_time = vif->bss_conf.use_short_slot ? 9 : 20;339sifs = rtwdev->hal.current_band_type == RTW_BAND_5G ? 16 : 10;340341return aifsn * slot_time + sifs;342}343344static void __rtw_conf_tx(struct rtw_dev *rtwdev,345struct rtw_vif *rtwvif, u16 ac)346{347struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac];348u32 edca_param = ac_to_edca_param[ac];349u8 ecw_max, ecw_min;350u8 aifs;351352/* 2^ecw - 1 = cw; ecw = log2(cw + 1) */353ecw_max = ilog2(params->cw_max + 1);354ecw_min = ilog2(params->cw_min + 1);355aifs = rtw_aifsn_to_aifs(rtwdev, rtwvif, params->aifs);356rtw_write32_mask(rtwdev, edca_param, BIT_MASK_TXOP_LMT, params->txop);357rtw_write32_mask(rtwdev, edca_param, BIT_MASK_CWMAX, ecw_max);358rtw_write32_mask(rtwdev, edca_param, BIT_MASK_CWMIN, ecw_min);359rtw_write32_mask(rtwdev, edca_param, BIT_MASK_AIFS, aifs);360}361362static void rtw_conf_tx(struct rtw_dev *rtwdev,363struct rtw_vif *rtwvif)364{365u16 ac;366367for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)368__rtw_conf_tx(rtwdev, rtwvif, ac);369}370371static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,372struct ieee80211_vif *vif,373struct ieee80211_bss_conf *conf,374u64 changed)375{376struct rtw_dev *rtwdev = hw->priv;377struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;378struct rtw_coex *coex = &rtwdev->coex;379struct rtw_coex_stat *coex_stat = &coex->stat;380u32 config = 0;381382mutex_lock(&rtwdev->mutex);383384rtw_leave_lps_deep(rtwdev);385386if (changed & BSS_CHANGED_ASSOC) {387rtw_vif_assoc_changed(rtwvif, conf);388if (vif->cfg.assoc) {389rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_FINISH);390391rtw_fw_download_rsvd_page(rtwdev);392rtw_send_rsvd_page_h2c(rtwdev);393rtw_fw_default_port(rtwdev, rtwvif);394rtw_coex_media_status_notify(rtwdev, vif->cfg.assoc);395if (rtw_bf_support)396rtw_bf_assoc(rtwdev, vif, conf);397398rtw_set_ampdu_factor(rtwdev, vif, conf);399400rtw_fw_beacon_filter_config(rtwdev, true, vif);401} else {402rtw_leave_lps(rtwdev);403rtw_bf_disassoc(rtwdev, vif, conf);404/* Abort ongoing scan if cancel_scan isn't issued405* when disconnected by peer406*/407if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags))408rtw_hw_scan_abort(rtwdev);409410}411412config |= PORT_SET_NET_TYPE;413config |= PORT_SET_AID;414}415416if (changed & BSS_CHANGED_BSSID) {417ether_addr_copy(rtwvif->bssid, conf->bssid);418config |= PORT_SET_BSSID;419if (!rtw_core_check_sta_active(rtwdev))420rtw_clear_op_chan(rtwdev);421else422rtw_store_op_chan(rtwdev, true);423}424425if (changed & BSS_CHANGED_BEACON_INT) {426if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION)427coex_stat->wl_beacon_interval = conf->beacon_int;428}429430if (changed & BSS_CHANGED_BEACON) {431rtw_set_dtim_period(rtwdev, conf->dtim_period);432rtw_fw_download_rsvd_page(rtwdev);433rtw_send_rsvd_page_h2c(rtwdev);434}435436if (changed & BSS_CHANGED_BEACON_ENABLED) {437if (conf->enable_beacon)438rtw_write32_set(rtwdev, REG_FWHW_TXQ_CTRL,439BIT_EN_BCNQ_DL);440else441rtw_write32_clr(rtwdev, REG_FWHW_TXQ_CTRL,442BIT_EN_BCNQ_DL);443}444if (changed & BSS_CHANGED_CQM)445rtw_fw_beacon_filter_config(rtwdev, true, vif);446447if (changed & BSS_CHANGED_MU_GROUPS)448rtw_chip_set_gid_table(rtwdev, vif, conf);449450if (changed & BSS_CHANGED_ERP_SLOT)451rtw_conf_tx(rtwdev, rtwvif);452453if (changed & BSS_CHANGED_PS)454rtw_recalc_lps(rtwdev, NULL);455456rtw_vif_port_config(rtwdev, rtwvif, config);457458mutex_unlock(&rtwdev->mutex);459}460461static int rtw_ops_start_ap(struct ieee80211_hw *hw,462struct ieee80211_vif *vif,463struct ieee80211_bss_conf *link_conf)464{465struct rtw_dev *rtwdev = hw->priv;466const struct rtw_chip_info *chip = rtwdev->chip;467468mutex_lock(&rtwdev->mutex);469rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD);470rtwdev->ap_active = true;471rtw_store_op_chan(rtwdev, true);472chip->ops->phy_calibration(rtwdev);473mutex_unlock(&rtwdev->mutex);474475return 0;476}477478static void rtw_ops_stop_ap(struct ieee80211_hw *hw,479struct ieee80211_vif *vif,480struct ieee80211_bss_conf *link_conf)481{482struct rtw_dev *rtwdev = hw->priv;483484mutex_lock(&rtwdev->mutex);485rtw_write32_clr(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD);486rtwdev->ap_active = false;487if (!rtw_core_check_sta_active(rtwdev))488rtw_clear_op_chan(rtwdev);489mutex_unlock(&rtwdev->mutex);490}491492static int rtw_ops_conf_tx(struct ieee80211_hw *hw,493struct ieee80211_vif *vif,494unsigned int link_id, u16 ac,495const struct ieee80211_tx_queue_params *params)496{497struct rtw_dev *rtwdev = hw->priv;498struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;499500mutex_lock(&rtwdev->mutex);501502rtw_leave_lps_deep(rtwdev);503504rtwvif->tx_params[ac] = *params;505__rtw_conf_tx(rtwdev, rtwvif, ac);506507mutex_unlock(&rtwdev->mutex);508509return 0;510}511512static int rtw_ops_sta_add(struct ieee80211_hw *hw,513struct ieee80211_vif *vif,514struct ieee80211_sta *sta)515{516struct rtw_dev *rtwdev = hw->priv;517int ret = 0;518519mutex_lock(&rtwdev->mutex);520ret = rtw_sta_add(rtwdev, sta, vif);521mutex_unlock(&rtwdev->mutex);522523return ret;524}525526static int rtw_ops_sta_remove(struct ieee80211_hw *hw,527struct ieee80211_vif *vif,528struct ieee80211_sta *sta)529{530struct rtw_dev *rtwdev = hw->priv;531532mutex_lock(&rtwdev->mutex);533rtw_fw_beacon_filter_config(rtwdev, false, vif);534rtw_sta_remove(rtwdev, sta, true);535mutex_unlock(&rtwdev->mutex);536537return 0;538}539540static int rtw_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,541bool set)542{543struct rtw_dev *rtwdev = hw->priv;544545ieee80211_queue_work(hw, &rtwdev->update_beacon_work);546547return 0;548}549550static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,551struct ieee80211_vif *vif, struct ieee80211_sta *sta,552struct ieee80211_key_conf *key)553{554struct rtw_dev *rtwdev = hw->priv;555struct rtw_sec_desc *sec = &rtwdev->sec;556u8 hw_key_type;557u8 hw_key_idx;558int ret = 0;559560switch (key->cipher) {561case WLAN_CIPHER_SUITE_WEP40:562hw_key_type = RTW_CAM_WEP40;563break;564case WLAN_CIPHER_SUITE_WEP104:565hw_key_type = RTW_CAM_WEP104;566break;567case WLAN_CIPHER_SUITE_TKIP:568hw_key_type = RTW_CAM_TKIP;569key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;570break;571case WLAN_CIPHER_SUITE_CCMP:572hw_key_type = RTW_CAM_AES;573key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;574break;575case WLAN_CIPHER_SUITE_AES_CMAC:576case WLAN_CIPHER_SUITE_BIP_CMAC_256:577case WLAN_CIPHER_SUITE_BIP_GMAC_128:578case WLAN_CIPHER_SUITE_BIP_GMAC_256:579case WLAN_CIPHER_SUITE_CCMP_256:580case WLAN_CIPHER_SUITE_GCMP:581case WLAN_CIPHER_SUITE_GCMP_256:582/* suppress error messages */583return -EOPNOTSUPP;584default:585return -ENOTSUPP;586}587588mutex_lock(&rtwdev->mutex);589590rtw_leave_lps_deep(rtwdev);591592if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {593hw_key_idx = rtw_sec_get_free_cam(sec);594} else {595/* multiple interfaces? */596hw_key_idx = key->keyidx;597}598599if (hw_key_idx > sec->total_cam_num) {600ret = -ENOSPC;601goto out;602}603604switch (cmd) {605case SET_KEY:606/* need sw generated IV */607key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;608key->hw_key_idx = hw_key_idx;609rtw_sec_write_cam(rtwdev, sec, sta, key,610hw_key_type, hw_key_idx);611break;612case DISABLE_KEY:613rtw_hci_flush_all_queues(rtwdev, false);614rtw_mac_flush_all_queues(rtwdev, false);615rtw_sec_clear_cam(rtwdev, sec, key->hw_key_idx);616break;617}618619/* download new cam settings for PG to backup */620if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG)621rtw_fw_download_rsvd_page(rtwdev);622623out:624mutex_unlock(&rtwdev->mutex);625626return ret;627}628629static int rtw_ops_ampdu_action(struct ieee80211_hw *hw,630struct ieee80211_vif *vif,631struct ieee80211_ampdu_params *params)632{633struct ieee80211_sta *sta = params->sta;634u16 tid = params->tid;635struct ieee80211_txq *txq = sta->txq[tid];636struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv;637638switch (params->action) {639case IEEE80211_AMPDU_TX_START:640return IEEE80211_AMPDU_TX_START_IMMEDIATE;641case IEEE80211_AMPDU_TX_STOP_CONT:642case IEEE80211_AMPDU_TX_STOP_FLUSH:643case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:644clear_bit(RTW_TXQ_AMPDU, &rtwtxq->flags);645ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);646break;647case IEEE80211_AMPDU_TX_OPERATIONAL:648set_bit(RTW_TXQ_AMPDU, &rtwtxq->flags);649break;650case IEEE80211_AMPDU_RX_START:651case IEEE80211_AMPDU_RX_STOP:652break;653default:654WARN_ON(1);655return -ENOTSUPP;656}657658return 0;659}660661static bool rtw_ops_can_aggregate_in_amsdu(struct ieee80211_hw *hw,662struct sk_buff *head,663struct sk_buff *skb)664{665struct rtw_dev *rtwdev = hw->priv;666struct rtw_hal *hal = &rtwdev->hal;667668/* we don't want to enable TX AMSDU on 2.4G */669if (hal->current_band_type == RTW_BAND_2G)670return false;671672return true;673}674675static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw,676struct ieee80211_vif *vif,677const u8 *mac_addr)678{679struct rtw_dev *rtwdev = hw->priv;680struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;681682mutex_lock(&rtwdev->mutex);683rtw_core_scan_start(rtwdev, rtwvif, mac_addr, false);684mutex_unlock(&rtwdev->mutex);685}686687static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw,688struct ieee80211_vif *vif)689{690struct rtw_dev *rtwdev = hw->priv;691692mutex_lock(&rtwdev->mutex);693rtw_core_scan_complete(rtwdev, vif, false);694mutex_unlock(&rtwdev->mutex);695}696697static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw,698struct ieee80211_vif *vif,699struct ieee80211_prep_tx_info *info)700{701struct rtw_dev *rtwdev = hw->priv;702703mutex_lock(&rtwdev->mutex);704rtw_leave_lps_deep(rtwdev);705rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_START);706rtw_chip_prepare_tx(rtwdev);707mutex_unlock(&rtwdev->mutex);708}709710static int rtw_ops_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,711u32 value)712{713struct rtw_dev *rtwdev = hw->priv;714715mutex_lock(&rtwdev->mutex);716rtwdev->rts_threshold = value;717mutex_unlock(&rtwdev->mutex);718719return 0;720}721722static void rtw_ops_sta_statistics(struct ieee80211_hw *hw,723struct ieee80211_vif *vif,724struct ieee80211_sta *sta,725struct station_info *sinfo)726{727struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;728729sinfo->txrate = si->ra_report.txrate;730sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);731}732733static void rtw_ops_flush(struct ieee80211_hw *hw,734struct ieee80211_vif *vif,735u32 queues, bool drop)736{737struct rtw_dev *rtwdev = hw->priv;738739mutex_lock(&rtwdev->mutex);740rtw_leave_lps_deep(rtwdev);741742rtw_hci_flush_queues(rtwdev, queues, drop);743rtw_mac_flush_queues(rtwdev, queues, drop);744mutex_unlock(&rtwdev->mutex);745}746747struct rtw_iter_bitrate_mask_data {748struct rtw_dev *rtwdev;749struct ieee80211_vif *vif;750const struct cfg80211_bitrate_mask *mask;751};752753static void rtw_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta)754{755struct rtw_iter_bitrate_mask_data *br_data = data;756struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;757758if (si->vif != br_data->vif)759return;760761/* free previous mask setting */762kfree(si->mask);763si->mask = kmemdup(br_data->mask, sizeof(struct cfg80211_bitrate_mask),764GFP_ATOMIC);765if (!si->mask) {766si->use_cfg_mask = false;767return;768}769770si->use_cfg_mask = true;771rtw_update_sta_info(br_data->rtwdev, si, true);772}773774static void rtw_ra_mask_info_update(struct rtw_dev *rtwdev,775struct ieee80211_vif *vif,776const struct cfg80211_bitrate_mask *mask)777{778struct rtw_iter_bitrate_mask_data br_data;779780br_data.rtwdev = rtwdev;781br_data.vif = vif;782br_data.mask = mask;783rtw_iterate_stas(rtwdev, rtw_ra_mask_info_update_iter, &br_data);784}785786static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw,787struct ieee80211_vif *vif,788const struct cfg80211_bitrate_mask *mask)789{790struct rtw_dev *rtwdev = hw->priv;791792mutex_lock(&rtwdev->mutex);793rtw_ra_mask_info_update(rtwdev, vif, mask);794mutex_unlock(&rtwdev->mutex);795796return 0;797}798799static int rtw_ops_set_antenna(struct ieee80211_hw *hw,800int radio_idx,801u32 tx_antenna,802u32 rx_antenna)803{804struct rtw_dev *rtwdev = hw->priv;805const struct rtw_chip_info *chip = rtwdev->chip;806int ret;807808if (!chip->ops->set_antenna)809return -EOPNOTSUPP;810811mutex_lock(&rtwdev->mutex);812ret = chip->ops->set_antenna(rtwdev, -1, tx_antenna, rx_antenna);813mutex_unlock(&rtwdev->mutex);814815return ret;816}817818static int rtw_ops_get_antenna(struct ieee80211_hw *hw,819int radio_idx,820u32 *tx_antenna,821u32 *rx_antenna)822{823struct rtw_dev *rtwdev = hw->priv;824struct rtw_hal *hal = &rtwdev->hal;825826*tx_antenna = hal->antenna_tx;827*rx_antenna = hal->antenna_rx;828829return 0;830}831832#ifdef CONFIG_PM833static int rtw_ops_suspend(struct ieee80211_hw *hw,834struct cfg80211_wowlan *wowlan)835{836struct rtw_dev *rtwdev = hw->priv;837int ret;838839mutex_lock(&rtwdev->mutex);840ret = rtw_wow_suspend(rtwdev, wowlan);841if (ret)842rtw_err(rtwdev, "failed to suspend for wow %d\n", ret);843mutex_unlock(&rtwdev->mutex);844845return ret ? 1 : 0;846}847848static int rtw_ops_resume(struct ieee80211_hw *hw)849{850struct rtw_dev *rtwdev = hw->priv;851int ret;852853mutex_lock(&rtwdev->mutex);854ret = rtw_wow_resume(rtwdev);855if (ret)856rtw_err(rtwdev, "failed to resume for wow %d\n", ret);857mutex_unlock(&rtwdev->mutex);858859return ret ? 1 : 0;860}861862static void rtw_ops_set_wakeup(struct ieee80211_hw *hw, bool enabled)863{864struct rtw_dev *rtwdev = hw->priv;865866device_set_wakeup_enable(rtwdev->dev, enabled);867}868#endif869870static void rtw_reconfig_complete(struct ieee80211_hw *hw,871enum ieee80211_reconfig_type reconfig_type)872{873struct rtw_dev *rtwdev = hw->priv;874875mutex_lock(&rtwdev->mutex);876if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART)877clear_bit(RTW_FLAG_RESTARTING, rtwdev->flags);878mutex_unlock(&rtwdev->mutex);879}880881static int rtw_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,882struct ieee80211_scan_request *req)883{884struct rtw_dev *rtwdev = hw->priv;885int ret;886887if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD))888return 1;889890if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags))891return -EBUSY;892893mutex_lock(&rtwdev->mutex);894rtw_hw_scan_start(rtwdev, vif, req);895ret = rtw_hw_scan_offload(rtwdev, vif, true);896if (ret) {897rtw_hw_scan_abort(rtwdev);898rtw_err(rtwdev, "HW scan failed with status: %d\n", ret);899}900mutex_unlock(&rtwdev->mutex);901902return ret;903}904905static void rtw_ops_cancel_hw_scan(struct ieee80211_hw *hw,906struct ieee80211_vif *vif)907{908struct rtw_dev *rtwdev = hw->priv;909910if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD))911return;912913if (!test_bit(RTW_FLAG_SCANNING, rtwdev->flags))914return;915916mutex_lock(&rtwdev->mutex);917rtw_hw_scan_abort(rtwdev);918mutex_unlock(&rtwdev->mutex);919}920921static int rtw_ops_set_sar_specs(struct ieee80211_hw *hw,922const struct cfg80211_sar_specs *sar)923{924struct rtw_dev *rtwdev = hw->priv;925926mutex_lock(&rtwdev->mutex);927rtw_set_sar_specs(rtwdev, sar);928mutex_unlock(&rtwdev->mutex);929930return 0;931}932933static void rtw_ops_sta_rc_update(struct ieee80211_hw *hw,934struct ieee80211_vif *vif,935struct ieee80211_link_sta *link_sta,936u32 changed)937{938struct ieee80211_sta *sta = link_sta->sta;939struct rtw_dev *rtwdev = hw->priv;940struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv;941942if (changed & IEEE80211_RC_BW_CHANGED)943ieee80211_queue_work(rtwdev->hw, &si->rc_work);944}945946const struct ieee80211_ops rtw_ops = {947.add_chanctx = ieee80211_emulate_add_chanctx,948.remove_chanctx = ieee80211_emulate_remove_chanctx,949.change_chanctx = ieee80211_emulate_change_chanctx,950.switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,951.tx = rtw_ops_tx,952.wake_tx_queue = rtw_ops_wake_tx_queue,953.start = rtw_ops_start,954.stop = rtw_ops_stop,955.config = rtw_ops_config,956.add_interface = rtw_ops_add_interface,957.remove_interface = rtw_ops_remove_interface,958.change_interface = rtw_ops_change_interface,959.configure_filter = rtw_ops_configure_filter,960.bss_info_changed = rtw_ops_bss_info_changed,961.start_ap = rtw_ops_start_ap,962.stop_ap = rtw_ops_stop_ap,963.conf_tx = rtw_ops_conf_tx,964.sta_add = rtw_ops_sta_add,965.sta_remove = rtw_ops_sta_remove,966.set_tim = rtw_ops_set_tim,967.set_key = rtw_ops_set_key,968.ampdu_action = rtw_ops_ampdu_action,969.can_aggregate_in_amsdu = rtw_ops_can_aggregate_in_amsdu,970.sw_scan_start = rtw_ops_sw_scan_start,971.sw_scan_complete = rtw_ops_sw_scan_complete,972.mgd_prepare_tx = rtw_ops_mgd_prepare_tx,973.set_rts_threshold = rtw_ops_set_rts_threshold,974.sta_statistics = rtw_ops_sta_statistics,975.flush = rtw_ops_flush,976.set_bitrate_mask = rtw_ops_set_bitrate_mask,977.set_antenna = rtw_ops_set_antenna,978.get_antenna = rtw_ops_get_antenna,979.reconfig_complete = rtw_reconfig_complete,980.hw_scan = rtw_ops_hw_scan,981.cancel_hw_scan = rtw_ops_cancel_hw_scan,982.link_sta_rc_update = rtw_ops_sta_rc_update,983.set_sar_specs = rtw_ops_set_sar_specs,984#ifdef CONFIG_PM985.suspend = rtw_ops_suspend,986.resume = rtw_ops_resume,987.set_wakeup = rtw_ops_set_wakeup,988#endif989};990EXPORT_SYMBOL(rtw_ops);991992993