12774f206SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 22774f206SBjoern A. Zeeb /* Copyright(c) 2018-2019 Realtek Corporation 32774f206SBjoern A. Zeeb */ 42774f206SBjoern A. Zeeb 52774f206SBjoern A. Zeeb #include "main.h" 62774f206SBjoern A. Zeeb #include "sec.h" 72774f206SBjoern A. Zeeb #include "tx.h" 82774f206SBjoern A. Zeeb #include "fw.h" 92774f206SBjoern A. Zeeb #include "mac.h" 102774f206SBjoern A. Zeeb #include "coex.h" 112774f206SBjoern A. Zeeb #include "ps.h" 122774f206SBjoern A. Zeeb #include "reg.h" 132774f206SBjoern A. Zeeb #include "bf.h" 142774f206SBjoern A. Zeeb #include "debug.h" 152774f206SBjoern A. Zeeb #include "wow.h" 162774f206SBjoern A. Zeeb #include "sar.h" 172774f206SBjoern A. Zeeb 182774f206SBjoern A. Zeeb static void rtw_ops_tx(struct ieee80211_hw *hw, 192774f206SBjoern A. Zeeb struct ieee80211_tx_control *control, 202774f206SBjoern A. Zeeb struct sk_buff *skb) 212774f206SBjoern A. Zeeb { 222774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 232774f206SBjoern A. Zeeb 242774f206SBjoern A. Zeeb if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) { 252774f206SBjoern A. Zeeb ieee80211_free_txskb(hw, skb); 262774f206SBjoern A. Zeeb return; 272774f206SBjoern A. Zeeb } 282774f206SBjoern A. Zeeb 292774f206SBjoern A. Zeeb rtw_tx(rtwdev, control, skb); 302774f206SBjoern A. Zeeb } 312774f206SBjoern A. Zeeb 322774f206SBjoern A. Zeeb static void rtw_ops_wake_tx_queue(struct ieee80211_hw *hw, 332774f206SBjoern A. Zeeb struct ieee80211_txq *txq) 342774f206SBjoern A. Zeeb { 352774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 362774f206SBjoern A. Zeeb struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv; 372774f206SBjoern A. Zeeb 382774f206SBjoern A. Zeeb if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) 392774f206SBjoern A. Zeeb return; 402774f206SBjoern A. Zeeb 412774f206SBjoern A. Zeeb spin_lock_bh(&rtwdev->txq_lock); 422774f206SBjoern A. Zeeb if (list_empty(&rtwtxq->list)) 432774f206SBjoern A. Zeeb list_add_tail(&rtwtxq->list, &rtwdev->txqs); 442774f206SBjoern A. Zeeb spin_unlock_bh(&rtwdev->txq_lock); 452774f206SBjoern A. Zeeb 4690aac0d8SBjoern A. Zeeb /* ensure to dequeue EAPOL (4/4) at the right time */ 4790aac0d8SBjoern A. Zeeb if (txq->ac == IEEE80211_AC_VO) 4890aac0d8SBjoern A. Zeeb __rtw_tx_work(rtwdev); 4990aac0d8SBjoern A. Zeeb else 502774f206SBjoern A. Zeeb queue_work(rtwdev->tx_wq, &rtwdev->tx_work); 512774f206SBjoern A. Zeeb } 522774f206SBjoern A. Zeeb 532774f206SBjoern A. Zeeb static int rtw_ops_start(struct ieee80211_hw *hw) 542774f206SBjoern A. Zeeb { 552774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 562774f206SBjoern A. Zeeb int ret; 572774f206SBjoern A. Zeeb 582774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 592774f206SBjoern A. Zeeb ret = rtw_core_start(rtwdev); 602774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 612774f206SBjoern A. Zeeb 622774f206SBjoern A. Zeeb return ret; 632774f206SBjoern A. Zeeb } 642774f206SBjoern A. Zeeb 65*11c53278SBjoern A. Zeeb static void rtw_ops_stop(struct ieee80211_hw *hw, bool suspend) 662774f206SBjoern A. Zeeb { 672774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 682774f206SBjoern A. Zeeb 692774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 702774f206SBjoern A. Zeeb rtw_core_stop(rtwdev); 712774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 722774f206SBjoern A. Zeeb } 732774f206SBjoern A. Zeeb 742774f206SBjoern A. Zeeb static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed) 752774f206SBjoern A. Zeeb { 762774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 772774f206SBjoern A. Zeeb int ret = 0; 782774f206SBjoern A. Zeeb 799c951734SBjoern A. Zeeb /* let previous ips work finish to ensure we don't leave ips twice */ 809c951734SBjoern A. Zeeb cancel_work_sync(&rtwdev->ips_work); 819c951734SBjoern A. Zeeb 822774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 832774f206SBjoern A. Zeeb 842774f206SBjoern A. Zeeb rtw_leave_lps_deep(rtwdev); 852774f206SBjoern A. Zeeb 862774f206SBjoern A. Zeeb if ((changed & IEEE80211_CONF_CHANGE_IDLE) && 872774f206SBjoern A. Zeeb !(hw->conf.flags & IEEE80211_CONF_IDLE)) { 882774f206SBjoern A. Zeeb ret = rtw_leave_ips(rtwdev); 892774f206SBjoern A. Zeeb if (ret) { 902774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to leave idle state\n"); 912774f206SBjoern A. Zeeb goto out; 922774f206SBjoern A. Zeeb } 932774f206SBjoern A. Zeeb } 942774f206SBjoern A. Zeeb 952774f206SBjoern A. Zeeb if (changed & IEEE80211_CONF_CHANGE_CHANNEL) 962774f206SBjoern A. Zeeb rtw_set_channel(rtwdev); 972774f206SBjoern A. Zeeb 982774f206SBjoern A. Zeeb if ((changed & IEEE80211_CONF_CHANGE_IDLE) && 9990aac0d8SBjoern A. Zeeb (hw->conf.flags & IEEE80211_CONF_IDLE) && 10090aac0d8SBjoern A. Zeeb !test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) 1012774f206SBjoern A. Zeeb rtw_enter_ips(rtwdev); 1022774f206SBjoern A. Zeeb 1032774f206SBjoern A. Zeeb out: 1042774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 1052774f206SBjoern A. Zeeb return ret; 1062774f206SBjoern A. Zeeb } 1072774f206SBjoern A. Zeeb 1082774f206SBjoern A. Zeeb static const struct rtw_vif_port rtw_vif_port[] = { 1092774f206SBjoern A. Zeeb [0] = { 1102774f206SBjoern A. Zeeb .mac_addr = {.addr = 0x0610}, 1112774f206SBjoern A. Zeeb .bssid = {.addr = 0x0618}, 1122774f206SBjoern A. Zeeb .net_type = {.addr = 0x0100, .mask = 0x30000}, 1132774f206SBjoern A. Zeeb .aid = {.addr = 0x06a8, .mask = 0x7ff}, 1142774f206SBjoern A. Zeeb .bcn_ctrl = {.addr = 0x0550, .mask = 0xff}, 1152774f206SBjoern A. Zeeb }, 1162774f206SBjoern A. Zeeb [1] = { 1172774f206SBjoern A. Zeeb .mac_addr = {.addr = 0x0700}, 1182774f206SBjoern A. Zeeb .bssid = {.addr = 0x0708}, 1192774f206SBjoern A. Zeeb .net_type = {.addr = 0x0100, .mask = 0xc0000}, 1202774f206SBjoern A. Zeeb .aid = {.addr = 0x0710, .mask = 0x7ff}, 1212774f206SBjoern A. Zeeb .bcn_ctrl = {.addr = 0x0551, .mask = 0xff}, 1222774f206SBjoern A. Zeeb }, 1232774f206SBjoern A. Zeeb [2] = { 1242774f206SBjoern A. Zeeb .mac_addr = {.addr = 0x1620}, 1252774f206SBjoern A. Zeeb .bssid = {.addr = 0x1628}, 1262774f206SBjoern A. Zeeb .net_type = {.addr = 0x1100, .mask = 0x3}, 1272774f206SBjoern A. Zeeb .aid = {.addr = 0x1600, .mask = 0x7ff}, 1282774f206SBjoern A. Zeeb .bcn_ctrl = {.addr = 0x0578, .mask = 0xff}, 1292774f206SBjoern A. Zeeb }, 1302774f206SBjoern A. Zeeb [3] = { 1312774f206SBjoern A. Zeeb .mac_addr = {.addr = 0x1630}, 1322774f206SBjoern A. Zeeb .bssid = {.addr = 0x1638}, 1332774f206SBjoern A. Zeeb .net_type = {.addr = 0x1100, .mask = 0xc}, 1342774f206SBjoern A. Zeeb .aid = {.addr = 0x1604, .mask = 0x7ff}, 1352774f206SBjoern A. Zeeb .bcn_ctrl = {.addr = 0x0579, .mask = 0xff}, 1362774f206SBjoern A. Zeeb }, 1372774f206SBjoern A. Zeeb [4] = { 1382774f206SBjoern A. Zeeb .mac_addr = {.addr = 0x1640}, 1392774f206SBjoern A. Zeeb .bssid = {.addr = 0x1648}, 1402774f206SBjoern A. Zeeb .net_type = {.addr = 0x1100, .mask = 0x30}, 1412774f206SBjoern A. Zeeb .aid = {.addr = 0x1608, .mask = 0x7ff}, 1422774f206SBjoern A. Zeeb .bcn_ctrl = {.addr = 0x057a, .mask = 0xff}, 1432774f206SBjoern A. Zeeb }, 1442774f206SBjoern A. Zeeb }; 1452774f206SBjoern A. Zeeb 1462774f206SBjoern A. Zeeb static int rtw_ops_add_interface(struct ieee80211_hw *hw, 1472774f206SBjoern A. Zeeb struct ieee80211_vif *vif) 1482774f206SBjoern A. Zeeb { 1492774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 1502774f206SBjoern A. Zeeb struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 1512774f206SBjoern A. Zeeb enum rtw_net_type net_type; 1522774f206SBjoern A. Zeeb u32 config = 0; 15390aac0d8SBjoern A. Zeeb u8 port; 1542774f206SBjoern A. Zeeb u8 bcn_ctrl = 0; 1552774f206SBjoern A. Zeeb 1562774f206SBjoern A. Zeeb if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER)) 1572774f206SBjoern A. Zeeb vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | 1582774f206SBjoern A. Zeeb IEEE80211_VIF_SUPPORTS_CQM_RSSI; 1592774f206SBjoern A. Zeeb rtwvif->stats.tx_unicast = 0; 1602774f206SBjoern A. Zeeb rtwvif->stats.rx_unicast = 0; 1612774f206SBjoern A. Zeeb rtwvif->stats.tx_cnt = 0; 1622774f206SBjoern A. Zeeb rtwvif->stats.rx_cnt = 0; 1632774f206SBjoern A. Zeeb rtwvif->scan_req = NULL; 1642774f206SBjoern A. Zeeb memset(&rtwvif->bfee, 0, sizeof(struct rtw_bfee)); 1652774f206SBjoern A. Zeeb rtw_txq_init(rtwdev, vif->txq); 1662774f206SBjoern A. Zeeb INIT_LIST_HEAD(&rtwvif->rsvd_page_list); 1672774f206SBjoern A. Zeeb 1682774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 1692774f206SBjoern A. Zeeb 17090aac0d8SBjoern A. Zeeb port = find_first_zero_bit(rtwdev->hw_port, RTW_PORT_NUM); 17190aac0d8SBjoern A. Zeeb if (port >= RTW_PORT_NUM) { 17290aac0d8SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 17390aac0d8SBjoern A. Zeeb return -EINVAL; 17490aac0d8SBjoern A. Zeeb } 17590aac0d8SBjoern A. Zeeb set_bit(port, rtwdev->hw_port); 17690aac0d8SBjoern A. Zeeb 17790aac0d8SBjoern A. Zeeb rtwvif->port = port; 17890aac0d8SBjoern A. Zeeb rtwvif->conf = &rtw_vif_port[port]; 1792774f206SBjoern A. Zeeb rtw_leave_lps_deep(rtwdev); 1802774f206SBjoern A. Zeeb 1812774f206SBjoern A. Zeeb switch (vif->type) { 1822774f206SBjoern A. Zeeb case NL80211_IFTYPE_AP: 1832774f206SBjoern A. Zeeb case NL80211_IFTYPE_MESH_POINT: 1842774f206SBjoern A. Zeeb rtw_add_rsvd_page_bcn(rtwdev, rtwvif); 1852774f206SBjoern A. Zeeb net_type = RTW_NET_AP_MODE; 1862774f206SBjoern A. Zeeb bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT; 1872774f206SBjoern A. Zeeb break; 1882774f206SBjoern A. Zeeb case NL80211_IFTYPE_ADHOC: 1892774f206SBjoern A. Zeeb rtw_add_rsvd_page_bcn(rtwdev, rtwvif); 1902774f206SBjoern A. Zeeb net_type = RTW_NET_AD_HOC; 1912774f206SBjoern A. Zeeb bcn_ctrl = BIT_EN_BCN_FUNCTION | BIT_DIS_TSF_UDT; 1922774f206SBjoern A. Zeeb break; 1932774f206SBjoern A. Zeeb case NL80211_IFTYPE_STATION: 1942774f206SBjoern A. Zeeb rtw_add_rsvd_page_sta(rtwdev, rtwvif); 1952774f206SBjoern A. Zeeb net_type = RTW_NET_NO_LINK; 1962774f206SBjoern A. Zeeb bcn_ctrl = BIT_EN_BCN_FUNCTION; 1972774f206SBjoern A. Zeeb break; 1982774f206SBjoern A. Zeeb default: 1992774f206SBjoern A. Zeeb WARN_ON(1); 20090aac0d8SBjoern A. Zeeb clear_bit(rtwvif->port, rtwdev->hw_port); 2012774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 2022774f206SBjoern A. Zeeb return -EINVAL; 2032774f206SBjoern A. Zeeb } 2042774f206SBjoern A. Zeeb 2052774f206SBjoern A. Zeeb ether_addr_copy(rtwvif->mac_addr, vif->addr); 2062774f206SBjoern A. Zeeb config |= PORT_SET_MAC_ADDR; 2072774f206SBjoern A. Zeeb rtwvif->net_type = net_type; 2082774f206SBjoern A. Zeeb config |= PORT_SET_NET_TYPE; 2092774f206SBjoern A. Zeeb rtwvif->bcn_ctrl = bcn_ctrl; 2102774f206SBjoern A. Zeeb config |= PORT_SET_BCN_CTRL; 2112774f206SBjoern A. Zeeb rtw_vif_port_config(rtwdev, rtwvif, config); 21290aac0d8SBjoern A. Zeeb rtw_core_port_switch(rtwdev, vif); 21390aac0d8SBjoern A. Zeeb rtw_recalc_lps(rtwdev, vif); 2142774f206SBjoern A. Zeeb 2152774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 2162774f206SBjoern A. Zeeb 2172774f206SBjoern A. Zeeb #if defined(__linux__) 2189c951734SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "start vif %pM on port %d\n", vif->addr, rtwvif->port); 2192774f206SBjoern A. Zeeb #elif defined(__FreeBSD__) 2209c951734SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "start vif %6D on port %d\n", vif->addr, ":", rtwvif->port); 2212774f206SBjoern A. Zeeb #endif 2222774f206SBjoern A. Zeeb return 0; 2232774f206SBjoern A. Zeeb } 2242774f206SBjoern A. Zeeb 2252774f206SBjoern A. Zeeb static void rtw_ops_remove_interface(struct ieee80211_hw *hw, 2262774f206SBjoern A. Zeeb struct ieee80211_vif *vif) 2272774f206SBjoern A. Zeeb { 2282774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 2292774f206SBjoern A. Zeeb struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 2302774f206SBjoern A. Zeeb u32 config = 0; 2312774f206SBjoern A. Zeeb 2322774f206SBjoern A. Zeeb #if defined(__linux__) 2339c951734SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "stop vif %pM on port %d\n", vif->addr, rtwvif->port); 2342774f206SBjoern A. Zeeb #elif defined(__FreeBSD__) 2359c951734SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "stop vif %6D on port %d\n", vif->addr, ":", rtwvif->port); 2362774f206SBjoern A. Zeeb #endif 2372774f206SBjoern A. Zeeb 2382774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 2392774f206SBjoern A. Zeeb 2402774f206SBjoern A. Zeeb rtw_leave_lps_deep(rtwdev); 2412774f206SBjoern A. Zeeb 2422774f206SBjoern A. Zeeb rtw_txq_cleanup(rtwdev, vif->txq); 2432774f206SBjoern A. Zeeb rtw_remove_rsvd_page(rtwdev, rtwvif); 2442774f206SBjoern A. Zeeb 2452774f206SBjoern A. Zeeb eth_zero_addr(rtwvif->mac_addr); 2462774f206SBjoern A. Zeeb config |= PORT_SET_MAC_ADDR; 2472774f206SBjoern A. Zeeb rtwvif->net_type = RTW_NET_NO_LINK; 2482774f206SBjoern A. Zeeb config |= PORT_SET_NET_TYPE; 2492774f206SBjoern A. Zeeb rtwvif->bcn_ctrl = 0; 2502774f206SBjoern A. Zeeb config |= PORT_SET_BCN_CTRL; 2512774f206SBjoern A. Zeeb rtw_vif_port_config(rtwdev, rtwvif, config); 25290aac0d8SBjoern A. Zeeb clear_bit(rtwvif->port, rtwdev->hw_port); 25390aac0d8SBjoern A. Zeeb rtw_recalc_lps(rtwdev, NULL); 2542774f206SBjoern A. Zeeb 2552774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 2562774f206SBjoern A. Zeeb } 2572774f206SBjoern A. Zeeb 2582774f206SBjoern A. Zeeb static int rtw_ops_change_interface(struct ieee80211_hw *hw, 2592774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 2602774f206SBjoern A. Zeeb enum nl80211_iftype type, bool p2p) 2612774f206SBjoern A. Zeeb { 2622774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 2632774f206SBjoern A. Zeeb 2642774f206SBjoern A. Zeeb #if defined(__linux__) 2659c951734SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n", 2662774f206SBjoern A. Zeeb vif->addr, vif->type, type, vif->p2p, p2p); 2672774f206SBjoern A. Zeeb #elif defined(__FreeBSD__) 2689c951734SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "change vif %6D (%d)->(%d), p2p (%d)->(%d)\n", 2692774f206SBjoern A. Zeeb vif->addr, ":", vif->type, type, vif->p2p, p2p); 2702774f206SBjoern A. Zeeb #endif 2712774f206SBjoern A. Zeeb 2722774f206SBjoern A. Zeeb rtw_ops_remove_interface(hw, vif); 2732774f206SBjoern A. Zeeb 2742774f206SBjoern A. Zeeb vif->type = type; 2752774f206SBjoern A. Zeeb vif->p2p = p2p; 2762774f206SBjoern A. Zeeb 2772774f206SBjoern A. Zeeb return rtw_ops_add_interface(hw, vif); 2782774f206SBjoern A. Zeeb } 2792774f206SBjoern A. Zeeb 2802774f206SBjoern A. Zeeb static void rtw_ops_configure_filter(struct ieee80211_hw *hw, 2812774f206SBjoern A. Zeeb unsigned int changed_flags, 2822774f206SBjoern A. Zeeb unsigned int *new_flags, 2832774f206SBjoern A. Zeeb u64 multicast) 2842774f206SBjoern A. Zeeb { 2852774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 2862774f206SBjoern A. Zeeb 2872774f206SBjoern A. Zeeb *new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL | 2882774f206SBjoern A. Zeeb FIF_BCN_PRBRESP_PROMISC; 2892774f206SBjoern A. Zeeb 2902774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 2912774f206SBjoern A. Zeeb 2922774f206SBjoern A. Zeeb rtw_leave_lps_deep(rtwdev); 2932774f206SBjoern A. Zeeb 2942774f206SBjoern A. Zeeb if (changed_flags & FIF_ALLMULTI) { 2952774f206SBjoern A. Zeeb if (*new_flags & FIF_ALLMULTI) 296*11c53278SBjoern A. Zeeb rtwdev->hal.rcr |= BIT_AM; 2972774f206SBjoern A. Zeeb else 298*11c53278SBjoern A. Zeeb rtwdev->hal.rcr &= ~(BIT_AM); 2992774f206SBjoern A. Zeeb } 3002774f206SBjoern A. Zeeb if (changed_flags & FIF_FCSFAIL) { 3012774f206SBjoern A. Zeeb if (*new_flags & FIF_FCSFAIL) 3022774f206SBjoern A. Zeeb rtwdev->hal.rcr |= BIT_ACRC32; 3032774f206SBjoern A. Zeeb else 3042774f206SBjoern A. Zeeb rtwdev->hal.rcr &= ~(BIT_ACRC32); 3052774f206SBjoern A. Zeeb } 3062774f206SBjoern A. Zeeb if (changed_flags & FIF_OTHER_BSS) { 3072774f206SBjoern A. Zeeb if (*new_flags & FIF_OTHER_BSS) 3082774f206SBjoern A. Zeeb rtwdev->hal.rcr |= BIT_AAP; 3092774f206SBjoern A. Zeeb else 3102774f206SBjoern A. Zeeb rtwdev->hal.rcr &= ~(BIT_AAP); 3112774f206SBjoern A. Zeeb } 3122774f206SBjoern A. Zeeb if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { 3132774f206SBjoern A. Zeeb if (*new_flags & FIF_BCN_PRBRESP_PROMISC) 3142774f206SBjoern A. Zeeb rtwdev->hal.rcr &= ~(BIT_CBSSID_BCN | BIT_CBSSID_DATA); 3152774f206SBjoern A. Zeeb else 3162774f206SBjoern A. Zeeb rtwdev->hal.rcr |= BIT_CBSSID_BCN; 3172774f206SBjoern A. Zeeb } 3182774f206SBjoern A. Zeeb 3192774f206SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_RX, 3202774f206SBjoern A. Zeeb "config rx filter, changed=0x%08x, new=0x%08x, rcr=0x%08x\n", 3212774f206SBjoern A. Zeeb changed_flags, *new_flags, rtwdev->hal.rcr); 3222774f206SBjoern A. Zeeb 3232774f206SBjoern A. Zeeb rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr); 3242774f206SBjoern A. Zeeb 3252774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 3262774f206SBjoern A. Zeeb } 3272774f206SBjoern A. Zeeb 3282774f206SBjoern A. Zeeb /* Only have one group of EDCA parameters now */ 3292774f206SBjoern A. Zeeb static const u32 ac_to_edca_param[IEEE80211_NUM_ACS] = { 3302774f206SBjoern A. Zeeb [IEEE80211_AC_VO] = REG_EDCA_VO_PARAM, 3312774f206SBjoern A. Zeeb [IEEE80211_AC_VI] = REG_EDCA_VI_PARAM, 3322774f206SBjoern A. Zeeb [IEEE80211_AC_BE] = REG_EDCA_BE_PARAM, 3332774f206SBjoern A. Zeeb [IEEE80211_AC_BK] = REG_EDCA_BK_PARAM, 3342774f206SBjoern A. Zeeb }; 3352774f206SBjoern A. Zeeb 3362774f206SBjoern A. Zeeb static u8 rtw_aifsn_to_aifs(struct rtw_dev *rtwdev, 3372774f206SBjoern A. Zeeb struct rtw_vif *rtwvif, u8 aifsn) 3382774f206SBjoern A. Zeeb { 3392774f206SBjoern A. Zeeb struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); 3402774f206SBjoern A. Zeeb u8 slot_time; 3412774f206SBjoern A. Zeeb u8 sifs; 3422774f206SBjoern A. Zeeb 3432774f206SBjoern A. Zeeb slot_time = vif->bss_conf.use_short_slot ? 9 : 20; 3442774f206SBjoern A. Zeeb sifs = rtwdev->hal.current_band_type == RTW_BAND_5G ? 16 : 10; 3452774f206SBjoern A. Zeeb 3462774f206SBjoern A. Zeeb return aifsn * slot_time + sifs; 3472774f206SBjoern A. Zeeb } 3482774f206SBjoern A. Zeeb 3492774f206SBjoern A. Zeeb static void __rtw_conf_tx(struct rtw_dev *rtwdev, 3502774f206SBjoern A. Zeeb struct rtw_vif *rtwvif, u16 ac) 3512774f206SBjoern A. Zeeb { 3522774f206SBjoern A. Zeeb struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; 3532774f206SBjoern A. Zeeb u32 edca_param = ac_to_edca_param[ac]; 3542774f206SBjoern A. Zeeb u8 ecw_max, ecw_min; 3552774f206SBjoern A. Zeeb u8 aifs; 3562774f206SBjoern A. Zeeb 3572774f206SBjoern A. Zeeb /* 2^ecw - 1 = cw; ecw = log2(cw + 1) */ 3582774f206SBjoern A. Zeeb ecw_max = ilog2(params->cw_max + 1); 3592774f206SBjoern A. Zeeb ecw_min = ilog2(params->cw_min + 1); 3602774f206SBjoern A. Zeeb aifs = rtw_aifsn_to_aifs(rtwdev, rtwvif, params->aifs); 3612774f206SBjoern A. Zeeb rtw_write32_mask(rtwdev, edca_param, BIT_MASK_TXOP_LMT, params->txop); 3622774f206SBjoern A. Zeeb rtw_write32_mask(rtwdev, edca_param, BIT_MASK_CWMAX, ecw_max); 3632774f206SBjoern A. Zeeb rtw_write32_mask(rtwdev, edca_param, BIT_MASK_CWMIN, ecw_min); 3642774f206SBjoern A. Zeeb rtw_write32_mask(rtwdev, edca_param, BIT_MASK_AIFS, aifs); 3652774f206SBjoern A. Zeeb } 3662774f206SBjoern A. Zeeb 3672774f206SBjoern A. Zeeb static void rtw_conf_tx(struct rtw_dev *rtwdev, 3682774f206SBjoern A. Zeeb struct rtw_vif *rtwvif) 3692774f206SBjoern A. Zeeb { 3702774f206SBjoern A. Zeeb u16 ac; 3712774f206SBjoern A. Zeeb 3722774f206SBjoern A. Zeeb for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 3732774f206SBjoern A. Zeeb __rtw_conf_tx(rtwdev, rtwvif, ac); 3742774f206SBjoern A. Zeeb } 3752774f206SBjoern A. Zeeb 3762774f206SBjoern A. Zeeb static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, 3772774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 3782774f206SBjoern A. Zeeb struct ieee80211_bss_conf *conf, 379467d3e2eSBjoern A. Zeeb u64 changed) 3802774f206SBjoern A. Zeeb { 3812774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 3822774f206SBjoern A. Zeeb struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 3832774f206SBjoern A. Zeeb struct rtw_coex *coex = &rtwdev->coex; 3842774f206SBjoern A. Zeeb struct rtw_coex_stat *coex_stat = &coex->stat; 3852774f206SBjoern A. Zeeb u32 config = 0; 3862774f206SBjoern A. Zeeb 3872774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 3882774f206SBjoern A. Zeeb 3892774f206SBjoern A. Zeeb rtw_leave_lps_deep(rtwdev); 3902774f206SBjoern A. Zeeb 3912774f206SBjoern A. Zeeb if (changed & BSS_CHANGED_ASSOC) { 3922774f206SBjoern A. Zeeb rtw_vif_assoc_changed(rtwvif, conf); 39390aac0d8SBjoern A. Zeeb if (vif->cfg.assoc) { 3942774f206SBjoern A. Zeeb rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_FINISH); 3952774f206SBjoern A. Zeeb 3962774f206SBjoern A. Zeeb rtw_fw_download_rsvd_page(rtwdev); 3972774f206SBjoern A. Zeeb rtw_send_rsvd_page_h2c(rtwdev); 39890aac0d8SBjoern A. Zeeb rtw_fw_default_port(rtwdev, rtwvif); 39990aac0d8SBjoern A. Zeeb rtw_coex_media_status_notify(rtwdev, vif->cfg.assoc); 4002774f206SBjoern A. Zeeb if (rtw_bf_support) 4012774f206SBjoern A. Zeeb rtw_bf_assoc(rtwdev, vif, conf); 402*11c53278SBjoern A. Zeeb 403*11c53278SBjoern A. Zeeb rtw_fw_beacon_filter_config(rtwdev, true, vif); 4042774f206SBjoern A. Zeeb } else { 4052774f206SBjoern A. Zeeb rtw_leave_lps(rtwdev); 4062774f206SBjoern A. Zeeb rtw_bf_disassoc(rtwdev, vif, conf); 4072774f206SBjoern A. Zeeb /* Abort ongoing scan if cancel_scan isn't issued 4082774f206SBjoern A. Zeeb * when disconnected by peer 4092774f206SBjoern A. Zeeb */ 4102774f206SBjoern A. Zeeb if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) 41190aac0d8SBjoern A. Zeeb rtw_hw_scan_abort(rtwdev); 41290aac0d8SBjoern A. Zeeb 4132774f206SBjoern A. Zeeb } 4142774f206SBjoern A. Zeeb 4152774f206SBjoern A. Zeeb config |= PORT_SET_NET_TYPE; 4162774f206SBjoern A. Zeeb config |= PORT_SET_AID; 4172774f206SBjoern A. Zeeb } 4182774f206SBjoern A. Zeeb 4192774f206SBjoern A. Zeeb if (changed & BSS_CHANGED_BSSID) { 4202774f206SBjoern A. Zeeb ether_addr_copy(rtwvif->bssid, conf->bssid); 4212774f206SBjoern A. Zeeb config |= PORT_SET_BSSID; 42290aac0d8SBjoern A. Zeeb if (!rtw_core_check_sta_active(rtwdev)) 42390aac0d8SBjoern A. Zeeb rtw_clear_op_chan(rtwdev); 42490aac0d8SBjoern A. Zeeb else 42590aac0d8SBjoern A. Zeeb rtw_store_op_chan(rtwdev, true); 4262774f206SBjoern A. Zeeb } 4272774f206SBjoern A. Zeeb 4282774f206SBjoern A. Zeeb if (changed & BSS_CHANGED_BEACON_INT) { 4292774f206SBjoern A. Zeeb if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION) 4302774f206SBjoern A. Zeeb coex_stat->wl_beacon_interval = conf->beacon_int; 4312774f206SBjoern A. Zeeb } 4322774f206SBjoern A. Zeeb 4339c951734SBjoern A. Zeeb if (changed & BSS_CHANGED_BEACON) { 4349c951734SBjoern A. Zeeb rtw_set_dtim_period(rtwdev, conf->dtim_period); 4352774f206SBjoern A. Zeeb rtw_fw_download_rsvd_page(rtwdev); 43690aac0d8SBjoern A. Zeeb rtw_send_rsvd_page_h2c(rtwdev); 4379c951734SBjoern A. Zeeb } 4382774f206SBjoern A. Zeeb 4392774f206SBjoern A. Zeeb if (changed & BSS_CHANGED_BEACON_ENABLED) { 4402774f206SBjoern A. Zeeb if (conf->enable_beacon) 4412774f206SBjoern A. Zeeb rtw_write32_set(rtwdev, REG_FWHW_TXQ_CTRL, 4422774f206SBjoern A. Zeeb BIT_EN_BCNQ_DL); 4432774f206SBjoern A. Zeeb else 4442774f206SBjoern A. Zeeb rtw_write32_clr(rtwdev, REG_FWHW_TXQ_CTRL, 4452774f206SBjoern A. Zeeb BIT_EN_BCNQ_DL); 4462774f206SBjoern A. Zeeb } 4472774f206SBjoern A. Zeeb if (changed & BSS_CHANGED_CQM) 4482774f206SBjoern A. Zeeb rtw_fw_beacon_filter_config(rtwdev, true, vif); 4492774f206SBjoern A. Zeeb 4502774f206SBjoern A. Zeeb if (changed & BSS_CHANGED_MU_GROUPS) 4512774f206SBjoern A. Zeeb rtw_chip_set_gid_table(rtwdev, vif, conf); 4522774f206SBjoern A. Zeeb 4532774f206SBjoern A. Zeeb if (changed & BSS_CHANGED_ERP_SLOT) 4542774f206SBjoern A. Zeeb rtw_conf_tx(rtwdev, rtwvif); 4552774f206SBjoern A. Zeeb 45690aac0d8SBjoern A. Zeeb if (changed & BSS_CHANGED_PS) 45790aac0d8SBjoern A. Zeeb rtw_recalc_lps(rtwdev, NULL); 45890aac0d8SBjoern A. Zeeb 4592774f206SBjoern A. Zeeb rtw_vif_port_config(rtwdev, rtwvif, config); 4602774f206SBjoern A. Zeeb 4612774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 4622774f206SBjoern A. Zeeb } 4632774f206SBjoern A. Zeeb 464549198b1SBjoern A. Zeeb static int rtw_ops_start_ap(struct ieee80211_hw *hw, 465549198b1SBjoern A. Zeeb struct ieee80211_vif *vif, 466549198b1SBjoern A. Zeeb struct ieee80211_bss_conf *link_conf) 4679c951734SBjoern A. Zeeb { 4689c951734SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 46990aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 4709c951734SBjoern A. Zeeb 4719c951734SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 47290aac0d8SBjoern A. Zeeb rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD); 47390aac0d8SBjoern A. Zeeb rtwdev->ap_active = true; 47490aac0d8SBjoern A. Zeeb rtw_store_op_chan(rtwdev, true); 4759c951734SBjoern A. Zeeb chip->ops->phy_calibration(rtwdev); 4769c951734SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 4779c951734SBjoern A. Zeeb 4789c951734SBjoern A. Zeeb return 0; 4799c951734SBjoern A. Zeeb } 4809c951734SBjoern A. Zeeb 48190aac0d8SBjoern A. Zeeb static void rtw_ops_stop_ap(struct ieee80211_hw *hw, 48290aac0d8SBjoern A. Zeeb struct ieee80211_vif *vif, 48390aac0d8SBjoern A. Zeeb struct ieee80211_bss_conf *link_conf) 48490aac0d8SBjoern A. Zeeb { 48590aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 48690aac0d8SBjoern A. Zeeb 48790aac0d8SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 48890aac0d8SBjoern A. Zeeb rtw_write32_clr(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD); 48990aac0d8SBjoern A. Zeeb rtwdev->ap_active = false; 49090aac0d8SBjoern A. Zeeb if (!rtw_core_check_sta_active(rtwdev)) 49190aac0d8SBjoern A. Zeeb rtw_clear_op_chan(rtwdev); 49290aac0d8SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 49390aac0d8SBjoern A. Zeeb } 49490aac0d8SBjoern A. Zeeb 4952774f206SBjoern A. Zeeb static int rtw_ops_conf_tx(struct ieee80211_hw *hw, 496549198b1SBjoern A. Zeeb struct ieee80211_vif *vif, 497549198b1SBjoern A. Zeeb unsigned int link_id, u16 ac, 4982774f206SBjoern A. Zeeb const struct ieee80211_tx_queue_params *params) 4992774f206SBjoern A. Zeeb { 5002774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 5012774f206SBjoern A. Zeeb struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 5022774f206SBjoern A. Zeeb 5032774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 5042774f206SBjoern A. Zeeb 5052774f206SBjoern A. Zeeb rtw_leave_lps_deep(rtwdev); 5062774f206SBjoern A. Zeeb 5072774f206SBjoern A. Zeeb rtwvif->tx_params[ac] = *params; 5082774f206SBjoern A. Zeeb __rtw_conf_tx(rtwdev, rtwvif, ac); 5092774f206SBjoern A. Zeeb 5102774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 5112774f206SBjoern A. Zeeb 5122774f206SBjoern A. Zeeb return 0; 5132774f206SBjoern A. Zeeb } 5142774f206SBjoern A. Zeeb 5152774f206SBjoern A. Zeeb static int rtw_ops_sta_add(struct ieee80211_hw *hw, 5162774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 5172774f206SBjoern A. Zeeb struct ieee80211_sta *sta) 5182774f206SBjoern A. Zeeb { 5192774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 5202774f206SBjoern A. Zeeb int ret = 0; 5212774f206SBjoern A. Zeeb 5222774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 5232774f206SBjoern A. Zeeb ret = rtw_sta_add(rtwdev, sta, vif); 5242774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 5252774f206SBjoern A. Zeeb 5262774f206SBjoern A. Zeeb return ret; 5272774f206SBjoern A. Zeeb } 5282774f206SBjoern A. Zeeb 5292774f206SBjoern A. Zeeb static int rtw_ops_sta_remove(struct ieee80211_hw *hw, 5302774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 5312774f206SBjoern A. Zeeb struct ieee80211_sta *sta) 5322774f206SBjoern A. Zeeb { 5332774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 5342774f206SBjoern A. Zeeb 5352774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 53690aac0d8SBjoern A. Zeeb rtw_fw_beacon_filter_config(rtwdev, false, vif); 5372774f206SBjoern A. Zeeb rtw_sta_remove(rtwdev, sta, true); 5382774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 5392774f206SBjoern A. Zeeb 5402774f206SBjoern A. Zeeb return 0; 5412774f206SBjoern A. Zeeb } 5422774f206SBjoern A. Zeeb 5439c951734SBjoern A. Zeeb static int rtw_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, 5449c951734SBjoern A. Zeeb bool set) 5459c951734SBjoern A. Zeeb { 5469c951734SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 5479c951734SBjoern A. Zeeb 5489c951734SBjoern A. Zeeb ieee80211_queue_work(hw, &rtwdev->update_beacon_work); 5499c951734SBjoern A. Zeeb 5509c951734SBjoern A. Zeeb return 0; 5519c951734SBjoern A. Zeeb } 5529c951734SBjoern A. Zeeb 5532774f206SBjoern A. Zeeb static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 5542774f206SBjoern A. Zeeb struct ieee80211_vif *vif, struct ieee80211_sta *sta, 5552774f206SBjoern A. Zeeb struct ieee80211_key_conf *key) 5562774f206SBjoern A. Zeeb { 5572774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 5582774f206SBjoern A. Zeeb struct rtw_sec_desc *sec = &rtwdev->sec; 5592774f206SBjoern A. Zeeb u8 hw_key_type; 5602774f206SBjoern A. Zeeb u8 hw_key_idx; 5612774f206SBjoern A. Zeeb int ret = 0; 5622774f206SBjoern A. Zeeb 5632774f206SBjoern A. Zeeb switch (key->cipher) { 5642774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP40: 5652774f206SBjoern A. Zeeb hw_key_type = RTW_CAM_WEP40; 5662774f206SBjoern A. Zeeb break; 5672774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP104: 5682774f206SBjoern A. Zeeb hw_key_type = RTW_CAM_WEP104; 5692774f206SBjoern A. Zeeb break; 5702774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_TKIP: 5712774f206SBjoern A. Zeeb hw_key_type = RTW_CAM_TKIP; 5722774f206SBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; 5732774f206SBjoern A. Zeeb break; 5742774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP: 5752774f206SBjoern A. Zeeb hw_key_type = RTW_CAM_AES; 5762774f206SBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; 5772774f206SBjoern A. Zeeb break; 5782774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_AES_CMAC: 5792774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_BIP_CMAC_256: 5802774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_BIP_GMAC_128: 5812774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_BIP_GMAC_256: 5822774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP_256: 5832774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_GCMP: 5842774f206SBjoern A. Zeeb case WLAN_CIPHER_SUITE_GCMP_256: 5852774f206SBjoern A. Zeeb /* suppress error messages */ 5862774f206SBjoern A. Zeeb return -EOPNOTSUPP; 5872774f206SBjoern A. Zeeb default: 5882774f206SBjoern A. Zeeb return -ENOTSUPP; 5892774f206SBjoern A. Zeeb } 5902774f206SBjoern A. Zeeb 5912774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 5922774f206SBjoern A. Zeeb 5932774f206SBjoern A. Zeeb rtw_leave_lps_deep(rtwdev); 5942774f206SBjoern A. Zeeb 5952774f206SBjoern A. Zeeb if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { 5962774f206SBjoern A. Zeeb hw_key_idx = rtw_sec_get_free_cam(sec); 5972774f206SBjoern A. Zeeb } else { 5982774f206SBjoern A. Zeeb /* multiple interfaces? */ 5992774f206SBjoern A. Zeeb hw_key_idx = key->keyidx; 6002774f206SBjoern A. Zeeb } 6012774f206SBjoern A. Zeeb 6022774f206SBjoern A. Zeeb if (hw_key_idx > sec->total_cam_num) { 6032774f206SBjoern A. Zeeb ret = -ENOSPC; 6042774f206SBjoern A. Zeeb goto out; 6052774f206SBjoern A. Zeeb } 6062774f206SBjoern A. Zeeb 6072774f206SBjoern A. Zeeb switch (cmd) { 6082774f206SBjoern A. Zeeb case SET_KEY: 6092774f206SBjoern A. Zeeb /* need sw generated IV */ 6102774f206SBjoern A. Zeeb key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 6112774f206SBjoern A. Zeeb key->hw_key_idx = hw_key_idx; 6122774f206SBjoern A. Zeeb rtw_sec_write_cam(rtwdev, sec, sta, key, 6132774f206SBjoern A. Zeeb hw_key_type, hw_key_idx); 6142774f206SBjoern A. Zeeb break; 6152774f206SBjoern A. Zeeb case DISABLE_KEY: 6162774f206SBjoern A. Zeeb rtw_hci_flush_all_queues(rtwdev, false); 6172774f206SBjoern A. Zeeb rtw_mac_flush_all_queues(rtwdev, false); 6182774f206SBjoern A. Zeeb rtw_sec_clear_cam(rtwdev, sec, key->hw_key_idx); 6192774f206SBjoern A. Zeeb break; 6202774f206SBjoern A. Zeeb } 6212774f206SBjoern A. Zeeb 6222774f206SBjoern A. Zeeb /* download new cam settings for PG to backup */ 6232774f206SBjoern A. Zeeb if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG) 6242774f206SBjoern A. Zeeb rtw_fw_download_rsvd_page(rtwdev); 6252774f206SBjoern A. Zeeb 6262774f206SBjoern A. Zeeb out: 6272774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 6282774f206SBjoern A. Zeeb 6292774f206SBjoern A. Zeeb return ret; 6302774f206SBjoern A. Zeeb } 6312774f206SBjoern A. Zeeb 6322774f206SBjoern A. Zeeb static int rtw_ops_ampdu_action(struct ieee80211_hw *hw, 6332774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 6342774f206SBjoern A. Zeeb struct ieee80211_ampdu_params *params) 6352774f206SBjoern A. Zeeb { 6362774f206SBjoern A. Zeeb struct ieee80211_sta *sta = params->sta; 6372774f206SBjoern A. Zeeb u16 tid = params->tid; 6382774f206SBjoern A. Zeeb struct ieee80211_txq *txq = sta->txq[tid]; 6392774f206SBjoern A. Zeeb struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv; 6402774f206SBjoern A. Zeeb 6412774f206SBjoern A. Zeeb switch (params->action) { 6422774f206SBjoern A. Zeeb case IEEE80211_AMPDU_TX_START: 6432774f206SBjoern A. Zeeb return IEEE80211_AMPDU_TX_START_IMMEDIATE; 6442774f206SBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_CONT: 6452774f206SBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_FLUSH: 6462774f206SBjoern A. Zeeb case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 6472774f206SBjoern A. Zeeb clear_bit(RTW_TXQ_AMPDU, &rtwtxq->flags); 6482774f206SBjoern A. Zeeb ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 6492774f206SBjoern A. Zeeb break; 6502774f206SBjoern A. Zeeb case IEEE80211_AMPDU_TX_OPERATIONAL: 6512774f206SBjoern A. Zeeb set_bit(RTW_TXQ_AMPDU, &rtwtxq->flags); 6522774f206SBjoern A. Zeeb break; 6532774f206SBjoern A. Zeeb case IEEE80211_AMPDU_RX_START: 6542774f206SBjoern A. Zeeb case IEEE80211_AMPDU_RX_STOP: 6552774f206SBjoern A. Zeeb break; 6562774f206SBjoern A. Zeeb default: 6572774f206SBjoern A. Zeeb WARN_ON(1); 6582774f206SBjoern A. Zeeb return -ENOTSUPP; 6592774f206SBjoern A. Zeeb } 6602774f206SBjoern A. Zeeb 6612774f206SBjoern A. Zeeb return 0; 6622774f206SBjoern A. Zeeb } 6632774f206SBjoern A. Zeeb 6642774f206SBjoern A. Zeeb static bool rtw_ops_can_aggregate_in_amsdu(struct ieee80211_hw *hw, 6652774f206SBjoern A. Zeeb struct sk_buff *head, 6662774f206SBjoern A. Zeeb struct sk_buff *skb) 6672774f206SBjoern A. Zeeb { 6682774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 6692774f206SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 6702774f206SBjoern A. Zeeb 6712774f206SBjoern A. Zeeb /* we don't want to enable TX AMSDU on 2.4G */ 6722774f206SBjoern A. Zeeb if (hal->current_band_type == RTW_BAND_2G) 6732774f206SBjoern A. Zeeb return false; 6742774f206SBjoern A. Zeeb 6752774f206SBjoern A. Zeeb return true; 6762774f206SBjoern A. Zeeb } 6772774f206SBjoern A. Zeeb 6782774f206SBjoern A. Zeeb static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw, 6792774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 6802774f206SBjoern A. Zeeb const u8 *mac_addr) 6812774f206SBjoern A. Zeeb { 6822774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 6832774f206SBjoern A. Zeeb struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 6842774f206SBjoern A. Zeeb 6852774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 6862774f206SBjoern A. Zeeb rtw_core_scan_start(rtwdev, rtwvif, mac_addr, false); 6872774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 6882774f206SBjoern A. Zeeb } 6892774f206SBjoern A. Zeeb 6902774f206SBjoern A. Zeeb static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw, 6912774f206SBjoern A. Zeeb struct ieee80211_vif *vif) 6922774f206SBjoern A. Zeeb { 6932774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 6942774f206SBjoern A. Zeeb 6952774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 6969c951734SBjoern A. Zeeb rtw_core_scan_complete(rtwdev, vif, false); 6972774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 6982774f206SBjoern A. Zeeb } 6992774f206SBjoern A. Zeeb 7002774f206SBjoern A. Zeeb static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw, 7012774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 7022774f206SBjoern A. Zeeb struct ieee80211_prep_tx_info *info) 7032774f206SBjoern A. Zeeb { 7042774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 7052774f206SBjoern A. Zeeb 7062774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 7072774f206SBjoern A. Zeeb rtw_leave_lps_deep(rtwdev); 7082774f206SBjoern A. Zeeb rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_START); 7092774f206SBjoern A. Zeeb rtw_chip_prepare_tx(rtwdev); 7102774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 7112774f206SBjoern A. Zeeb } 7122774f206SBjoern A. Zeeb 7132774f206SBjoern A. Zeeb static int rtw_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 7142774f206SBjoern A. Zeeb { 7152774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 7162774f206SBjoern A. Zeeb 7172774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 7182774f206SBjoern A. Zeeb rtwdev->rts_threshold = value; 7192774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 7202774f206SBjoern A. Zeeb 7212774f206SBjoern A. Zeeb return 0; 7222774f206SBjoern A. Zeeb } 7232774f206SBjoern A. Zeeb 7242774f206SBjoern A. Zeeb static void rtw_ops_sta_statistics(struct ieee80211_hw *hw, 7252774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 7262774f206SBjoern A. Zeeb struct ieee80211_sta *sta, 7272774f206SBjoern A. Zeeb struct station_info *sinfo) 7282774f206SBjoern A. Zeeb { 7292774f206SBjoern A. Zeeb struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; 7302774f206SBjoern A. Zeeb 7312774f206SBjoern A. Zeeb sinfo->txrate = si->ra_report.txrate; 7322774f206SBjoern A. Zeeb sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 7332774f206SBjoern A. Zeeb } 7342774f206SBjoern A. Zeeb 7352774f206SBjoern A. Zeeb static void rtw_ops_flush(struct ieee80211_hw *hw, 7362774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 7372774f206SBjoern A. Zeeb u32 queues, bool drop) 7382774f206SBjoern A. Zeeb { 7392774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 7402774f206SBjoern A. Zeeb 7412774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 7422774f206SBjoern A. Zeeb rtw_leave_lps_deep(rtwdev); 7432774f206SBjoern A. Zeeb 7442774f206SBjoern A. Zeeb rtw_hci_flush_queues(rtwdev, queues, drop); 7452774f206SBjoern A. Zeeb rtw_mac_flush_queues(rtwdev, queues, drop); 7462774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 7472774f206SBjoern A. Zeeb } 7482774f206SBjoern A. Zeeb 7492774f206SBjoern A. Zeeb struct rtw_iter_bitrate_mask_data { 7502774f206SBjoern A. Zeeb struct rtw_dev *rtwdev; 7512774f206SBjoern A. Zeeb struct ieee80211_vif *vif; 7522774f206SBjoern A. Zeeb const struct cfg80211_bitrate_mask *mask; 7532774f206SBjoern A. Zeeb }; 7542774f206SBjoern A. Zeeb 7552774f206SBjoern A. Zeeb static void rtw_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta) 7562774f206SBjoern A. Zeeb { 7572774f206SBjoern A. Zeeb struct rtw_iter_bitrate_mask_data *br_data = data; 7582774f206SBjoern A. Zeeb struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; 7592774f206SBjoern A. Zeeb 7602774f206SBjoern A. Zeeb if (si->vif != br_data->vif) 7612774f206SBjoern A. Zeeb return; 7622774f206SBjoern A. Zeeb 7632774f206SBjoern A. Zeeb /* free previous mask setting */ 7642774f206SBjoern A. Zeeb kfree(si->mask); 7652774f206SBjoern A. Zeeb si->mask = kmemdup(br_data->mask, sizeof(struct cfg80211_bitrate_mask), 7662774f206SBjoern A. Zeeb GFP_ATOMIC); 7672774f206SBjoern A. Zeeb if (!si->mask) { 7682774f206SBjoern A. Zeeb si->use_cfg_mask = false; 7692774f206SBjoern A. Zeeb return; 7702774f206SBjoern A. Zeeb } 7712774f206SBjoern A. Zeeb 7722774f206SBjoern A. Zeeb si->use_cfg_mask = true; 7739c951734SBjoern A. Zeeb rtw_update_sta_info(br_data->rtwdev, si, true); 7742774f206SBjoern A. Zeeb } 7752774f206SBjoern A. Zeeb 7762774f206SBjoern A. Zeeb static void rtw_ra_mask_info_update(struct rtw_dev *rtwdev, 7772774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 7782774f206SBjoern A. Zeeb const struct cfg80211_bitrate_mask *mask) 7792774f206SBjoern A. Zeeb { 7802774f206SBjoern A. Zeeb struct rtw_iter_bitrate_mask_data br_data; 7812774f206SBjoern A. Zeeb 7822774f206SBjoern A. Zeeb br_data.rtwdev = rtwdev; 7832774f206SBjoern A. Zeeb br_data.vif = vif; 7842774f206SBjoern A. Zeeb br_data.mask = mask; 78590aac0d8SBjoern A. Zeeb rtw_iterate_stas(rtwdev, rtw_ra_mask_info_update_iter, &br_data); 7862774f206SBjoern A. Zeeb } 7872774f206SBjoern A. Zeeb 7882774f206SBjoern A. Zeeb static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw, 7892774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 7902774f206SBjoern A. Zeeb const struct cfg80211_bitrate_mask *mask) 7912774f206SBjoern A. Zeeb { 7922774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 7932774f206SBjoern A. Zeeb 79490aac0d8SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 7952774f206SBjoern A. Zeeb rtw_ra_mask_info_update(rtwdev, vif, mask); 79690aac0d8SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 7972774f206SBjoern A. Zeeb 7982774f206SBjoern A. Zeeb return 0; 7992774f206SBjoern A. Zeeb } 8002774f206SBjoern A. Zeeb 8012774f206SBjoern A. Zeeb static int rtw_ops_set_antenna(struct ieee80211_hw *hw, 8022774f206SBjoern A. Zeeb u32 tx_antenna, 8032774f206SBjoern A. Zeeb u32 rx_antenna) 8042774f206SBjoern A. Zeeb { 8052774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 80690aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 8072774f206SBjoern A. Zeeb int ret; 8082774f206SBjoern A. Zeeb 8092774f206SBjoern A. Zeeb if (!chip->ops->set_antenna) 8102774f206SBjoern A. Zeeb return -EOPNOTSUPP; 8112774f206SBjoern A. Zeeb 8122774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 8132774f206SBjoern A. Zeeb ret = chip->ops->set_antenna(rtwdev, tx_antenna, rx_antenna); 8142774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 8152774f206SBjoern A. Zeeb 8162774f206SBjoern A. Zeeb return ret; 8172774f206SBjoern A. Zeeb } 8182774f206SBjoern A. Zeeb 8192774f206SBjoern A. Zeeb static int rtw_ops_get_antenna(struct ieee80211_hw *hw, 8202774f206SBjoern A. Zeeb u32 *tx_antenna, 8212774f206SBjoern A. Zeeb u32 *rx_antenna) 8222774f206SBjoern A. Zeeb { 8232774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 8242774f206SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 8252774f206SBjoern A. Zeeb 8262774f206SBjoern A. Zeeb *tx_antenna = hal->antenna_tx; 8272774f206SBjoern A. Zeeb *rx_antenna = hal->antenna_rx; 8282774f206SBjoern A. Zeeb 8292774f206SBjoern A. Zeeb return 0; 8302774f206SBjoern A. Zeeb } 8312774f206SBjoern A. Zeeb 8322774f206SBjoern A. Zeeb #ifdef CONFIG_PM 8332774f206SBjoern A. Zeeb static int rtw_ops_suspend(struct ieee80211_hw *hw, 8342774f206SBjoern A. Zeeb struct cfg80211_wowlan *wowlan) 8352774f206SBjoern A. Zeeb { 8362774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 8372774f206SBjoern A. Zeeb int ret; 8382774f206SBjoern A. Zeeb 8392774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 8402774f206SBjoern A. Zeeb ret = rtw_wow_suspend(rtwdev, wowlan); 8412774f206SBjoern A. Zeeb if (ret) 8422774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to suspend for wow %d\n", ret); 8432774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 8442774f206SBjoern A. Zeeb 8452774f206SBjoern A. Zeeb return ret ? 1 : 0; 8462774f206SBjoern A. Zeeb } 8472774f206SBjoern A. Zeeb 8482774f206SBjoern A. Zeeb static int rtw_ops_resume(struct ieee80211_hw *hw) 8492774f206SBjoern A. Zeeb { 8502774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 8512774f206SBjoern A. Zeeb int ret; 8522774f206SBjoern A. Zeeb 8532774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 8542774f206SBjoern A. Zeeb ret = rtw_wow_resume(rtwdev); 8552774f206SBjoern A. Zeeb if (ret) 8562774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to resume for wow %d\n", ret); 8572774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 8582774f206SBjoern A. Zeeb 8592774f206SBjoern A. Zeeb return ret ? 1 : 0; 8602774f206SBjoern A. Zeeb } 8612774f206SBjoern A. Zeeb 8622774f206SBjoern A. Zeeb static void rtw_ops_set_wakeup(struct ieee80211_hw *hw, bool enabled) 8632774f206SBjoern A. Zeeb { 8642774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 8652774f206SBjoern A. Zeeb 8662774f206SBjoern A. Zeeb device_set_wakeup_enable(rtwdev->dev, enabled); 8672774f206SBjoern A. Zeeb } 8682774f206SBjoern A. Zeeb #endif 8692774f206SBjoern A. Zeeb 8702774f206SBjoern A. Zeeb static void rtw_reconfig_complete(struct ieee80211_hw *hw, 8712774f206SBjoern A. Zeeb enum ieee80211_reconfig_type reconfig_type) 8722774f206SBjoern A. Zeeb { 8732774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 8742774f206SBjoern A. Zeeb 8752774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 8762774f206SBjoern A. Zeeb if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART) 8772774f206SBjoern A. Zeeb clear_bit(RTW_FLAG_RESTARTING, rtwdev->flags); 8782774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 8792774f206SBjoern A. Zeeb } 8802774f206SBjoern A. Zeeb 8812774f206SBjoern A. Zeeb static int rtw_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 8822774f206SBjoern A. Zeeb struct ieee80211_scan_request *req) 8832774f206SBjoern A. Zeeb { 8842774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 8852774f206SBjoern A. Zeeb int ret; 8862774f206SBjoern A. Zeeb 8872774f206SBjoern A. Zeeb if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD)) 8882774f206SBjoern A. Zeeb return 1; 8892774f206SBjoern A. Zeeb 8902774f206SBjoern A. Zeeb if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) 8912774f206SBjoern A. Zeeb return -EBUSY; 8922774f206SBjoern A. Zeeb 8932774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 8942774f206SBjoern A. Zeeb rtw_hw_scan_start(rtwdev, vif, req); 8952774f206SBjoern A. Zeeb ret = rtw_hw_scan_offload(rtwdev, vif, true); 8962774f206SBjoern A. Zeeb if (ret) { 89790aac0d8SBjoern A. Zeeb rtw_hw_scan_abort(rtwdev); 8982774f206SBjoern A. Zeeb rtw_err(rtwdev, "HW scan failed with status: %d\n", ret); 8992774f206SBjoern A. Zeeb } 9002774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 9012774f206SBjoern A. Zeeb 9022774f206SBjoern A. Zeeb return ret; 9032774f206SBjoern A. Zeeb } 9042774f206SBjoern A. Zeeb 9052774f206SBjoern A. Zeeb static void rtw_ops_cancel_hw_scan(struct ieee80211_hw *hw, 9062774f206SBjoern A. Zeeb struct ieee80211_vif *vif) 9072774f206SBjoern A. Zeeb { 9082774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 9092774f206SBjoern A. Zeeb 9102774f206SBjoern A. Zeeb if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD)) 9112774f206SBjoern A. Zeeb return; 9122774f206SBjoern A. Zeeb 9132774f206SBjoern A. Zeeb if (!test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) 9142774f206SBjoern A. Zeeb return; 9152774f206SBjoern A. Zeeb 9162774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 91790aac0d8SBjoern A. Zeeb rtw_hw_scan_abort(rtwdev); 9182774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 9192774f206SBjoern A. Zeeb } 9202774f206SBjoern A. Zeeb 9212774f206SBjoern A. Zeeb static int rtw_ops_set_sar_specs(struct ieee80211_hw *hw, 9222774f206SBjoern A. Zeeb const struct cfg80211_sar_specs *sar) 9232774f206SBjoern A. Zeeb { 9242774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 9252774f206SBjoern A. Zeeb 92690aac0d8SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 9272774f206SBjoern A. Zeeb rtw_set_sar_specs(rtwdev, sar); 92890aac0d8SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 9292774f206SBjoern A. Zeeb 9302774f206SBjoern A. Zeeb return 0; 9312774f206SBjoern A. Zeeb } 9322774f206SBjoern A. Zeeb 9339c951734SBjoern A. Zeeb static void rtw_ops_sta_rc_update(struct ieee80211_hw *hw, 9349c951734SBjoern A. Zeeb struct ieee80211_vif *vif, 9359c951734SBjoern A. Zeeb struct ieee80211_sta *sta, u32 changed) 9369c951734SBjoern A. Zeeb { 9379c951734SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 9389c951734SBjoern A. Zeeb struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; 9399c951734SBjoern A. Zeeb 9409c951734SBjoern A. Zeeb if (changed & IEEE80211_RC_BW_CHANGED) 94190aac0d8SBjoern A. Zeeb ieee80211_queue_work(rtwdev->hw, &si->rc_work); 9429c951734SBjoern A. Zeeb } 9439c951734SBjoern A. Zeeb 9442774f206SBjoern A. Zeeb const struct ieee80211_ops rtw_ops = { 945*11c53278SBjoern A. Zeeb .add_chanctx = ieee80211_emulate_add_chanctx, 946*11c53278SBjoern A. Zeeb .remove_chanctx = ieee80211_emulate_remove_chanctx, 947*11c53278SBjoern A. Zeeb .change_chanctx = ieee80211_emulate_change_chanctx, 948*11c53278SBjoern A. Zeeb .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, 9492774f206SBjoern A. Zeeb .tx = rtw_ops_tx, 9502774f206SBjoern A. Zeeb .wake_tx_queue = rtw_ops_wake_tx_queue, 9512774f206SBjoern A. Zeeb .start = rtw_ops_start, 9522774f206SBjoern A. Zeeb .stop = rtw_ops_stop, 9532774f206SBjoern A. Zeeb .config = rtw_ops_config, 9542774f206SBjoern A. Zeeb .add_interface = rtw_ops_add_interface, 9552774f206SBjoern A. Zeeb .remove_interface = rtw_ops_remove_interface, 9562774f206SBjoern A. Zeeb .change_interface = rtw_ops_change_interface, 9572774f206SBjoern A. Zeeb .configure_filter = rtw_ops_configure_filter, 9582774f206SBjoern A. Zeeb .bss_info_changed = rtw_ops_bss_info_changed, 9599c951734SBjoern A. Zeeb .start_ap = rtw_ops_start_ap, 96090aac0d8SBjoern A. Zeeb .stop_ap = rtw_ops_stop_ap, 9612774f206SBjoern A. Zeeb .conf_tx = rtw_ops_conf_tx, 9622774f206SBjoern A. Zeeb .sta_add = rtw_ops_sta_add, 9632774f206SBjoern A. Zeeb .sta_remove = rtw_ops_sta_remove, 9649c951734SBjoern A. Zeeb .set_tim = rtw_ops_set_tim, 9652774f206SBjoern A. Zeeb .set_key = rtw_ops_set_key, 9662774f206SBjoern A. Zeeb .ampdu_action = rtw_ops_ampdu_action, 9672774f206SBjoern A. Zeeb .can_aggregate_in_amsdu = rtw_ops_can_aggregate_in_amsdu, 9682774f206SBjoern A. Zeeb .sw_scan_start = rtw_ops_sw_scan_start, 9692774f206SBjoern A. Zeeb .sw_scan_complete = rtw_ops_sw_scan_complete, 9702774f206SBjoern A. Zeeb .mgd_prepare_tx = rtw_ops_mgd_prepare_tx, 9712774f206SBjoern A. Zeeb .set_rts_threshold = rtw_ops_set_rts_threshold, 9722774f206SBjoern A. Zeeb .sta_statistics = rtw_ops_sta_statistics, 9732774f206SBjoern A. Zeeb .flush = rtw_ops_flush, 9742774f206SBjoern A. Zeeb .set_bitrate_mask = rtw_ops_set_bitrate_mask, 9752774f206SBjoern A. Zeeb .set_antenna = rtw_ops_set_antenna, 9762774f206SBjoern A. Zeeb .get_antenna = rtw_ops_get_antenna, 9772774f206SBjoern A. Zeeb .reconfig_complete = rtw_reconfig_complete, 9782774f206SBjoern A. Zeeb .hw_scan = rtw_ops_hw_scan, 9792774f206SBjoern A. Zeeb .cancel_hw_scan = rtw_ops_cancel_hw_scan, 9809c951734SBjoern A. Zeeb .sta_rc_update = rtw_ops_sta_rc_update, 9812774f206SBjoern A. Zeeb .set_sar_specs = rtw_ops_set_sar_specs, 9822774f206SBjoern A. Zeeb #ifdef CONFIG_PM 9832774f206SBjoern A. Zeeb .suspend = rtw_ops_suspend, 9842774f206SBjoern A. Zeeb .resume = rtw_ops_resume, 9852774f206SBjoern A. Zeeb .set_wakeup = rtw_ops_set_wakeup, 9862774f206SBjoern A. Zeeb #endif 9872774f206SBjoern A. Zeeb }; 9882774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_ops); 989