18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Atheros CARL9170 driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * mac80211 interaction code 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> 78c2ecf20Sopenharmony_ci * Copyright 2009, 2010, Christian Lamparter <chunkeey@googlemail.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 118c2ecf20Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 128c2ecf20Sopenharmony_ci * (at your option) any later version. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 158c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 168c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 178c2ecf20Sopenharmony_ci * GNU General Public License for more details. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 208c2ecf20Sopenharmony_ci * along with this program; see the file COPYING. If not, see 218c2ecf20Sopenharmony_ci * http://www.gnu.org/licenses/. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and 248c2ecf20Sopenharmony_ci * permission notice: 258c2ecf20Sopenharmony_ci * Copyright (c) 2007-2008 Atheros Communications, Inc. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 288c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 298c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 328c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 338c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 348c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 358c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 368c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 378c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <linux/slab.h> 418c2ecf20Sopenharmony_ci#include <linux/module.h> 428c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 438c2ecf20Sopenharmony_ci#include <linux/random.h> 448c2ecf20Sopenharmony_ci#include <net/mac80211.h> 458c2ecf20Sopenharmony_ci#include <net/cfg80211.h> 468c2ecf20Sopenharmony_ci#include "hw.h" 478c2ecf20Sopenharmony_ci#include "carl9170.h" 488c2ecf20Sopenharmony_ci#include "cmd.h" 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic bool modparam_nohwcrypt; 518c2ecf20Sopenharmony_cimodule_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); 528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nohwcrypt, "Disable hardware crypto offload."); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciint modparam_noht; 558c2ecf20Sopenharmony_cimodule_param_named(noht, modparam_noht, int, 0444); 568c2ecf20Sopenharmony_ciMODULE_PARM_DESC(noht, "Disable MPDU aggregation."); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ 598c2ecf20Sopenharmony_ci .bitrate = (_bitrate), \ 608c2ecf20Sopenharmony_ci .flags = (_flags), \ 618c2ecf20Sopenharmony_ci .hw_value = (_hw_rate) | (_txpidx) << 4, \ 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistruct ieee80211_rate __carl9170_ratetable[] = { 658c2ecf20Sopenharmony_ci RATE(10, 0, 0, 0), 668c2ecf20Sopenharmony_ci RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE), 678c2ecf20Sopenharmony_ci RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE), 688c2ecf20Sopenharmony_ci RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE), 698c2ecf20Sopenharmony_ci RATE(60, 0xb, 0, 0), 708c2ecf20Sopenharmony_ci RATE(90, 0xf, 0, 0), 718c2ecf20Sopenharmony_ci RATE(120, 0xa, 0, 0), 728c2ecf20Sopenharmony_ci RATE(180, 0xe, 0, 0), 738c2ecf20Sopenharmony_ci RATE(240, 0x9, 0, 0), 748c2ecf20Sopenharmony_ci RATE(360, 0xd, 1, 0), 758c2ecf20Sopenharmony_ci RATE(480, 0x8, 2, 0), 768c2ecf20Sopenharmony_ci RATE(540, 0xc, 3, 0), 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci#undef RATE 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define carl9170_g_ratetable (__carl9170_ratetable + 0) 818c2ecf20Sopenharmony_ci#define carl9170_g_ratetable_size 12 828c2ecf20Sopenharmony_ci#define carl9170_a_ratetable (__carl9170_ratetable + 4) 838c2ecf20Sopenharmony_ci#define carl9170_a_ratetable_size 8 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* 868c2ecf20Sopenharmony_ci * NB: The hw_value is used as an index into the carl9170_phy_freq_params 878c2ecf20Sopenharmony_ci * array in phy.c so that we don't have to do frequency lookups! 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci#define CHAN(_freq, _idx) { \ 908c2ecf20Sopenharmony_ci .center_freq = (_freq), \ 918c2ecf20Sopenharmony_ci .hw_value = (_idx), \ 928c2ecf20Sopenharmony_ci .max_power = 18, /* XXX */ \ 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic struct ieee80211_channel carl9170_2ghz_chantable[] = { 968c2ecf20Sopenharmony_ci CHAN(2412, 0), 978c2ecf20Sopenharmony_ci CHAN(2417, 1), 988c2ecf20Sopenharmony_ci CHAN(2422, 2), 998c2ecf20Sopenharmony_ci CHAN(2427, 3), 1008c2ecf20Sopenharmony_ci CHAN(2432, 4), 1018c2ecf20Sopenharmony_ci CHAN(2437, 5), 1028c2ecf20Sopenharmony_ci CHAN(2442, 6), 1038c2ecf20Sopenharmony_ci CHAN(2447, 7), 1048c2ecf20Sopenharmony_ci CHAN(2452, 8), 1058c2ecf20Sopenharmony_ci CHAN(2457, 9), 1068c2ecf20Sopenharmony_ci CHAN(2462, 10), 1078c2ecf20Sopenharmony_ci CHAN(2467, 11), 1088c2ecf20Sopenharmony_ci CHAN(2472, 12), 1098c2ecf20Sopenharmony_ci CHAN(2484, 13), 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic struct ieee80211_channel carl9170_5ghz_chantable[] = { 1138c2ecf20Sopenharmony_ci CHAN(4920, 14), 1148c2ecf20Sopenharmony_ci CHAN(4940, 15), 1158c2ecf20Sopenharmony_ci CHAN(4960, 16), 1168c2ecf20Sopenharmony_ci CHAN(4980, 17), 1178c2ecf20Sopenharmony_ci CHAN(5040, 18), 1188c2ecf20Sopenharmony_ci CHAN(5060, 19), 1198c2ecf20Sopenharmony_ci CHAN(5080, 20), 1208c2ecf20Sopenharmony_ci CHAN(5180, 21), 1218c2ecf20Sopenharmony_ci CHAN(5200, 22), 1228c2ecf20Sopenharmony_ci CHAN(5220, 23), 1238c2ecf20Sopenharmony_ci CHAN(5240, 24), 1248c2ecf20Sopenharmony_ci CHAN(5260, 25), 1258c2ecf20Sopenharmony_ci CHAN(5280, 26), 1268c2ecf20Sopenharmony_ci CHAN(5300, 27), 1278c2ecf20Sopenharmony_ci CHAN(5320, 28), 1288c2ecf20Sopenharmony_ci CHAN(5500, 29), 1298c2ecf20Sopenharmony_ci CHAN(5520, 30), 1308c2ecf20Sopenharmony_ci CHAN(5540, 31), 1318c2ecf20Sopenharmony_ci CHAN(5560, 32), 1328c2ecf20Sopenharmony_ci CHAN(5580, 33), 1338c2ecf20Sopenharmony_ci CHAN(5600, 34), 1348c2ecf20Sopenharmony_ci CHAN(5620, 35), 1358c2ecf20Sopenharmony_ci CHAN(5640, 36), 1368c2ecf20Sopenharmony_ci CHAN(5660, 37), 1378c2ecf20Sopenharmony_ci CHAN(5680, 38), 1388c2ecf20Sopenharmony_ci CHAN(5700, 39), 1398c2ecf20Sopenharmony_ci CHAN(5745, 40), 1408c2ecf20Sopenharmony_ci CHAN(5765, 41), 1418c2ecf20Sopenharmony_ci CHAN(5785, 42), 1428c2ecf20Sopenharmony_ci CHAN(5805, 43), 1438c2ecf20Sopenharmony_ci CHAN(5825, 44), 1448c2ecf20Sopenharmony_ci CHAN(5170, 45), 1458c2ecf20Sopenharmony_ci CHAN(5190, 46), 1468c2ecf20Sopenharmony_ci CHAN(5210, 47), 1478c2ecf20Sopenharmony_ci CHAN(5230, 48), 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci#undef CHAN 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define CARL9170_HT_CAP \ 1528c2ecf20Sopenharmony_ci{ \ 1538c2ecf20Sopenharmony_ci .ht_supported = true, \ 1548c2ecf20Sopenharmony_ci .cap = IEEE80211_HT_CAP_MAX_AMSDU | \ 1558c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ 1568c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SGI_40 | \ 1578c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_DSSSCCK40 | \ 1588c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SM_PS, \ 1598c2ecf20Sopenharmony_ci .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \ 1608c2ecf20Sopenharmony_ci .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \ 1618c2ecf20Sopenharmony_ci .mcs = { \ 1628c2ecf20Sopenharmony_ci .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \ 1638c2ecf20Sopenharmony_ci .rx_highest = cpu_to_le16(300), \ 1648c2ecf20Sopenharmony_ci .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ 1658c2ecf20Sopenharmony_ci }, \ 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic struct ieee80211_supported_band carl9170_band_2GHz = { 1698c2ecf20Sopenharmony_ci .channels = carl9170_2ghz_chantable, 1708c2ecf20Sopenharmony_ci .n_channels = ARRAY_SIZE(carl9170_2ghz_chantable), 1718c2ecf20Sopenharmony_ci .bitrates = carl9170_g_ratetable, 1728c2ecf20Sopenharmony_ci .n_bitrates = carl9170_g_ratetable_size, 1738c2ecf20Sopenharmony_ci .ht_cap = CARL9170_HT_CAP, 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic struct ieee80211_supported_band carl9170_band_5GHz = { 1778c2ecf20Sopenharmony_ci .channels = carl9170_5ghz_chantable, 1788c2ecf20Sopenharmony_ci .n_channels = ARRAY_SIZE(carl9170_5ghz_chantable), 1798c2ecf20Sopenharmony_ci .bitrates = carl9170_a_ratetable, 1808c2ecf20Sopenharmony_ci .n_bitrates = carl9170_a_ratetable_size, 1818c2ecf20Sopenharmony_ci .ht_cap = CARL9170_HT_CAP, 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void carl9170_ampdu_gc(struct ar9170 *ar) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct carl9170_sta_tid *tid_info; 1878c2ecf20Sopenharmony_ci LIST_HEAD(tid_gc); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci rcu_read_lock(); 1908c2ecf20Sopenharmony_ci list_for_each_entry_rcu(tid_info, &ar->tx_ampdu_list, list) { 1918c2ecf20Sopenharmony_ci spin_lock_bh(&ar->tx_ampdu_list_lock); 1928c2ecf20Sopenharmony_ci if (tid_info->state == CARL9170_TID_STATE_SHUTDOWN) { 1938c2ecf20Sopenharmony_ci tid_info->state = CARL9170_TID_STATE_KILLED; 1948c2ecf20Sopenharmony_ci list_del_rcu(&tid_info->list); 1958c2ecf20Sopenharmony_ci ar->tx_ampdu_list_len--; 1968c2ecf20Sopenharmony_ci list_add_tail(&tid_info->tmp_list, &tid_gc); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->tx_ampdu_list_lock); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci rcu_assign_pointer(ar->tx_ampdu_iter, tid_info); 2028c2ecf20Sopenharmony_ci rcu_read_unlock(); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci synchronize_rcu(); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci while (!list_empty(&tid_gc)) { 2078c2ecf20Sopenharmony_ci struct sk_buff *skb; 2088c2ecf20Sopenharmony_ci tid_info = list_first_entry(&tid_gc, struct carl9170_sta_tid, 2098c2ecf20Sopenharmony_ci tmp_list); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&tid_info->queue))) 2128c2ecf20Sopenharmony_ci carl9170_tx_status(ar, skb, false); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci list_del_init(&tid_info->tmp_list); 2158c2ecf20Sopenharmony_ci kfree(tid_info); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic void carl9170_flush(struct ar9170 *ar, bool drop_queued) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci if (drop_queued) { 2228c2ecf20Sopenharmony_ci int i; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* 2258c2ecf20Sopenharmony_ci * We can only drop frames which have not been uploaded 2268c2ecf20Sopenharmony_ci * to the device yet. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci for (i = 0; i < ar->hw->queues; i++) { 2308c2ecf20Sopenharmony_ci struct sk_buff *skb; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&ar->tx_pending[i]))) { 2338c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 2368c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_AMPDU) 2378c2ecf20Sopenharmony_ci atomic_dec(&ar->tx_ampdu_upload); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci carl9170_tx_status(ar, skb, false); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* Wait for all other outstanding frames to timeout. */ 2458c2ecf20Sopenharmony_ci if (atomic_read(&ar->tx_total_queued)) 2468c2ecf20Sopenharmony_ci WARN_ON(wait_for_completion_timeout(&ar->tx_flush, HZ) == 0); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void carl9170_flush_ba(struct ar9170 *ar) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct sk_buff_head free; 2528c2ecf20Sopenharmony_ci struct carl9170_sta_tid *tid_info; 2538c2ecf20Sopenharmony_ci struct sk_buff *skb; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci __skb_queue_head_init(&free); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci rcu_read_lock(); 2588c2ecf20Sopenharmony_ci spin_lock_bh(&ar->tx_ampdu_list_lock); 2598c2ecf20Sopenharmony_ci list_for_each_entry_rcu(tid_info, &ar->tx_ampdu_list, list) { 2608c2ecf20Sopenharmony_ci if (tid_info->state > CARL9170_TID_STATE_SUSPEND) { 2618c2ecf20Sopenharmony_ci tid_info->state = CARL9170_TID_STATE_SUSPEND; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci spin_lock(&tid_info->lock); 2648c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&tid_info->queue))) 2658c2ecf20Sopenharmony_ci __skb_queue_tail(&free, skb); 2668c2ecf20Sopenharmony_ci spin_unlock(&tid_info->lock); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->tx_ampdu_list_lock); 2708c2ecf20Sopenharmony_ci rcu_read_unlock(); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&free))) 2738c2ecf20Sopenharmony_ci carl9170_tx_status(ar, skb, false); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void carl9170_zap_queues(struct ar9170 *ar) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct carl9170_vif_info *cvif; 2798c2ecf20Sopenharmony_ci unsigned int i; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci carl9170_ampdu_gc(ar); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci carl9170_flush_ba(ar); 2848c2ecf20Sopenharmony_ci carl9170_flush(ar, true); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci for (i = 0; i < ar->hw->queues; i++) { 2878c2ecf20Sopenharmony_ci spin_lock_bh(&ar->tx_status[i].lock); 2888c2ecf20Sopenharmony_ci while (!skb_queue_empty(&ar->tx_status[i])) { 2898c2ecf20Sopenharmony_ci struct sk_buff *skb; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci skb = skb_peek(&ar->tx_status[i]); 2928c2ecf20Sopenharmony_ci carl9170_tx_get_skb(skb); 2938c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->tx_status[i].lock); 2948c2ecf20Sopenharmony_ci carl9170_tx_drop(ar, skb); 2958c2ecf20Sopenharmony_ci spin_lock_bh(&ar->tx_status[i].lock); 2968c2ecf20Sopenharmony_ci carl9170_tx_put_skb(skb); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->tx_status[i].lock); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci BUILD_BUG_ON(CARL9170_NUM_TX_LIMIT_SOFT < 1); 3028c2ecf20Sopenharmony_ci BUILD_BUG_ON(CARL9170_NUM_TX_LIMIT_HARD < CARL9170_NUM_TX_LIMIT_SOFT); 3038c2ecf20Sopenharmony_ci BUILD_BUG_ON(CARL9170_NUM_TX_LIMIT_HARD >= CARL9170_BAW_BITS); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* reinitialize queues statistics */ 3068c2ecf20Sopenharmony_ci memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); 3078c2ecf20Sopenharmony_ci for (i = 0; i < ar->hw->queues; i++) 3088c2ecf20Sopenharmony_ci ar->tx_stats[i].limit = CARL9170_NUM_TX_LIMIT_HARD; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci for (i = 0; i < DIV_ROUND_UP(ar->fw.mem_blocks, BITS_PER_LONG); i++) 3118c2ecf20Sopenharmony_ci ar->mem_bitmap[i] = 0; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci rcu_read_lock(); 3148c2ecf20Sopenharmony_ci list_for_each_entry_rcu(cvif, &ar->vif_list, list) { 3158c2ecf20Sopenharmony_ci spin_lock_bh(&ar->beacon_lock); 3168c2ecf20Sopenharmony_ci dev_kfree_skb_any(cvif->beacon); 3178c2ecf20Sopenharmony_ci cvif->beacon = NULL; 3188c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->beacon_lock); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci rcu_read_unlock(); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci atomic_set(&ar->tx_ampdu_upload, 0); 3238c2ecf20Sopenharmony_ci atomic_set(&ar->tx_ampdu_scheduler, 0); 3248c2ecf20Sopenharmony_ci atomic_set(&ar->tx_total_pending, 0); 3258c2ecf20Sopenharmony_ci atomic_set(&ar->tx_total_queued, 0); 3268c2ecf20Sopenharmony_ci atomic_set(&ar->mem_free_blocks, ar->fw.mem_blocks); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci#define CARL9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ 3308c2ecf20Sopenharmony_cido { \ 3318c2ecf20Sopenharmony_ci queue.aifs = ai_fs; \ 3328c2ecf20Sopenharmony_ci queue.cw_min = cwmin; \ 3338c2ecf20Sopenharmony_ci queue.cw_max = cwmax; \ 3348c2ecf20Sopenharmony_ci queue.txop = _txop; \ 3358c2ecf20Sopenharmony_ci} while (0) 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic int carl9170_op_start(struct ieee80211_hw *hw) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 3408c2ecf20Sopenharmony_ci int err, i; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci carl9170_zap_queues(ar); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* reset QoS defaults */ 3478c2ecf20Sopenharmony_ci CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_VO], 2, 3, 7, 47); 3488c2ecf20Sopenharmony_ci CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_VI], 2, 7, 15, 94); 3498c2ecf20Sopenharmony_ci CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_BE], 3, 15, 1023, 0); 3508c2ecf20Sopenharmony_ci CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_BK], 7, 15, 1023, 0); 3518c2ecf20Sopenharmony_ci CARL9170_FILL_QUEUE(ar->edcf[AR9170_TXQ_SPECIAL], 2, 3, 7, 0); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci ar->current_factor = ar->current_density = -1; 3548c2ecf20Sopenharmony_ci /* "The first key is unique." */ 3558c2ecf20Sopenharmony_ci ar->usedkeys = 1; 3568c2ecf20Sopenharmony_ci ar->filter_state = 0; 3578c2ecf20Sopenharmony_ci ar->ps.last_action = jiffies; 3588c2ecf20Sopenharmony_ci ar->ps.last_slept = jiffies; 3598c2ecf20Sopenharmony_ci ar->erp_mode = CARL9170_ERP_AUTO; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* Set "disable hw crypto offload" whenever the module parameter 3628c2ecf20Sopenharmony_ci * nohwcrypt is true or if the firmware does not support it. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci ar->disable_offload = modparam_nohwcrypt | 3658c2ecf20Sopenharmony_ci ar->fw.disable_offload_fw; 3668c2ecf20Sopenharmony_ci ar->rx_software_decryption = ar->disable_offload; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci for (i = 0; i < ar->hw->queues; i++) { 3698c2ecf20Sopenharmony_ci ar->queue_stop_timeout[i] = jiffies; 3708c2ecf20Sopenharmony_ci ar->max_queue_stop_timeout[i] = 0; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci atomic_set(&ar->mem_allocs, 0); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci err = carl9170_usb_open(ar); 3768c2ecf20Sopenharmony_ci if (err) 3778c2ecf20Sopenharmony_ci goto out; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci err = carl9170_init_mac(ar); 3808c2ecf20Sopenharmony_ci if (err) 3818c2ecf20Sopenharmony_ci goto out; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci err = carl9170_set_qos(ar); 3848c2ecf20Sopenharmony_ci if (err) 3858c2ecf20Sopenharmony_ci goto out; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (ar->fw.rx_filter) { 3888c2ecf20Sopenharmony_ci err = carl9170_rx_filter(ar, CARL9170_RX_FILTER_OTHER_RA | 3898c2ecf20Sopenharmony_ci CARL9170_RX_FILTER_CTL_OTHER | CARL9170_RX_FILTER_BAD); 3908c2ecf20Sopenharmony_ci if (err) 3918c2ecf20Sopenharmony_ci goto out; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci err = carl9170_write_reg(ar, AR9170_MAC_REG_DMA_TRIGGER, 3958c2ecf20Sopenharmony_ci AR9170_DMA_TRIGGER_RXQ); 3968c2ecf20Sopenharmony_ci if (err) 3978c2ecf20Sopenharmony_ci goto out; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Clear key-cache */ 4008c2ecf20Sopenharmony_ci for (i = 0; i < AR9170_CAM_MAX_USER + 4; i++) { 4018c2ecf20Sopenharmony_ci err = carl9170_upload_key(ar, i, NULL, AR9170_ENC_ALG_NONE, 4028c2ecf20Sopenharmony_ci 0, NULL, 0); 4038c2ecf20Sopenharmony_ci if (err) 4048c2ecf20Sopenharmony_ci goto out; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci err = carl9170_upload_key(ar, i, NULL, AR9170_ENC_ALG_NONE, 4078c2ecf20Sopenharmony_ci 1, NULL, 0); 4088c2ecf20Sopenharmony_ci if (err) 4098c2ecf20Sopenharmony_ci goto out; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (i < AR9170_CAM_MAX_USER) { 4128c2ecf20Sopenharmony_ci err = carl9170_disable_key(ar, i); 4138c2ecf20Sopenharmony_ci if (err) 4148c2ecf20Sopenharmony_ci goto out; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci carl9170_set_state_when(ar, CARL9170_IDLE, CARL9170_STARTED); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(ar->hw, &ar->stat_work, 4218c2ecf20Sopenharmony_ci round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK))); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci ieee80211_wake_queues(ar->hw); 4248c2ecf20Sopenharmony_ci err = 0; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ciout: 4278c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 4288c2ecf20Sopenharmony_ci return err; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic void carl9170_cancel_worker(struct ar9170 *ar) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&ar->stat_work); 4348c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&ar->tx_janitor); 4358c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_LEDS 4368c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&ar->led_work); 4378c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_LEDS */ 4388c2ecf20Sopenharmony_ci cancel_work_sync(&ar->ps_work); 4398c2ecf20Sopenharmony_ci cancel_work_sync(&ar->ping_work); 4408c2ecf20Sopenharmony_ci cancel_work_sync(&ar->ampdu_work); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void carl9170_op_stop(struct ieee80211_hw *hw) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci carl9170_set_state_when(ar, CARL9170_STARTED, CARL9170_IDLE); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci ieee80211_stop_queues(ar->hw); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 4528c2ecf20Sopenharmony_ci if (IS_ACCEPTING_CMD(ar)) { 4538c2ecf20Sopenharmony_ci RCU_INIT_POINTER(ar->beacon_iter, NULL); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci carl9170_led_set_state(ar, 0); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* stop DMA */ 4588c2ecf20Sopenharmony_ci carl9170_write_reg(ar, AR9170_MAC_REG_DMA_TRIGGER, 0); 4598c2ecf20Sopenharmony_ci carl9170_usb_stop(ar); 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci carl9170_zap_queues(ar); 4638c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci carl9170_cancel_worker(ar); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic void carl9170_restart_work(struct work_struct *work) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct ar9170 *ar = container_of(work, struct ar9170, 4718c2ecf20Sopenharmony_ci restart_work); 4728c2ecf20Sopenharmony_ci int err = -EIO; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci ar->usedkeys = 0; 4758c2ecf20Sopenharmony_ci ar->filter_state = 0; 4768c2ecf20Sopenharmony_ci carl9170_cancel_worker(ar); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 4798c2ecf20Sopenharmony_ci if (!ar->force_usb_reset) { 4808c2ecf20Sopenharmony_ci err = carl9170_usb_restart(ar); 4818c2ecf20Sopenharmony_ci if (net_ratelimit()) { 4828c2ecf20Sopenharmony_ci if (err) 4838c2ecf20Sopenharmony_ci dev_err(&ar->udev->dev, "Failed to restart device (%d).\n", err); 4848c2ecf20Sopenharmony_ci else 4858c2ecf20Sopenharmony_ci dev_info(&ar->udev->dev, "device restarted successfully.\n"); 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci carl9170_zap_queues(ar); 4898c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (!err && !ar->force_usb_reset) { 4928c2ecf20Sopenharmony_ci ar->restart_counter++; 4938c2ecf20Sopenharmony_ci atomic_set(&ar->pending_restarts, 0); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci ieee80211_restart_hw(ar->hw); 4968c2ecf20Sopenharmony_ci } else { 4978c2ecf20Sopenharmony_ci /* 4988c2ecf20Sopenharmony_ci * The reset was unsuccessful and the device seems to 4998c2ecf20Sopenharmony_ci * be dead. But there's still one option: a low-level 5008c2ecf20Sopenharmony_ci * usb subsystem reset... 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci carl9170_usb_reset(ar); 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_civoid carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci carl9170_set_state_when(ar, CARL9170_STARTED, CARL9170_IDLE); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* 5128c2ecf20Sopenharmony_ci * Sometimes, an error can trigger several different reset events. 5138c2ecf20Sopenharmony_ci * By ignoring these *surplus* reset events, the device won't be 5148c2ecf20Sopenharmony_ci * killed again, right after it has recovered. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ci if (atomic_inc_return(&ar->pending_restarts) > 1) { 5178c2ecf20Sopenharmony_ci dev_dbg(&ar->udev->dev, "ignoring restart (%d)\n", r); 5188c2ecf20Sopenharmony_ci return; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci ieee80211_stop_queues(ar->hw); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci dev_err(&ar->udev->dev, "restart device (%d)\n", r); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (!WARN_ON(r == CARL9170_RR_NO_REASON) || 5268c2ecf20Sopenharmony_ci !WARN_ON(r >= __CARL9170_RR_LAST)) 5278c2ecf20Sopenharmony_ci ar->last_reason = r; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (!ar->registered) 5308c2ecf20Sopenharmony_ci return; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (!IS_ACCEPTING_CMD(ar) || ar->needs_full_reset) 5338c2ecf20Sopenharmony_ci ar->force_usb_reset = true; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci ieee80211_queue_work(ar->hw, &ar->restart_work); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* 5388c2ecf20Sopenharmony_ci * At this point, the device instance might have vanished/disabled. 5398c2ecf20Sopenharmony_ci * So, don't put any code which access the ar9170 struct 5408c2ecf20Sopenharmony_ci * without proper protection. 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic void carl9170_ping_work(struct work_struct *work) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct ar9170 *ar = container_of(work, struct ar9170, ping_work); 5478c2ecf20Sopenharmony_ci int err; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (!IS_STARTED(ar)) 5508c2ecf20Sopenharmony_ci return; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 5538c2ecf20Sopenharmony_ci err = carl9170_echo_test(ar, 0xdeadbeef); 5548c2ecf20Sopenharmony_ci if (err) 5558c2ecf20Sopenharmony_ci carl9170_restart(ar, CARL9170_RR_UNRESPONSIVE_DEVICE); 5568c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic int carl9170_init_interface(struct ar9170 *ar, 5608c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct ath_common *common = &ar->common; 5638c2ecf20Sopenharmony_ci int err; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (!vif) { 5668c2ecf20Sopenharmony_ci WARN_ON_ONCE(IS_STARTED(ar)); 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci memcpy(common->macaddr, vif->addr, ETH_ALEN); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* We have to fall back to software crypto, whenever 5738c2ecf20Sopenharmony_ci * the user choose to participates in an IBSS. HW 5748c2ecf20Sopenharmony_ci * offload for IBSS RSN is not supported by this driver. 5758c2ecf20Sopenharmony_ci * 5768c2ecf20Sopenharmony_ci * NOTE: If the previous main interface has already 5778c2ecf20Sopenharmony_ci * disabled hw crypto offload, we have to keep this 5788c2ecf20Sopenharmony_ci * previous disable_offload setting as it was. 5798c2ecf20Sopenharmony_ci * Altough ideally, we should notify mac80211 and tell 5808c2ecf20Sopenharmony_ci * it to forget about any HW crypto offload for now. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci ar->disable_offload |= ((vif->type != NL80211_IFTYPE_STATION) && 5838c2ecf20Sopenharmony_ci (vif->type != NL80211_IFTYPE_AP)); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* The driver used to have P2P GO+CLIENT support, 5868c2ecf20Sopenharmony_ci * but since this was dropped and we don't know if 5878c2ecf20Sopenharmony_ci * there are any gremlins lurking in the shadows, 5888c2ecf20Sopenharmony_ci * so best we keep HW offload disabled for P2P. 5898c2ecf20Sopenharmony_ci */ 5908c2ecf20Sopenharmony_ci ar->disable_offload |= vif->p2p; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci ar->rx_software_decryption = ar->disable_offload; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci err = carl9170_set_operating_mode(ar); 5958c2ecf20Sopenharmony_ci return err; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic int carl9170_op_add_interface(struct ieee80211_hw *hw, 5998c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv; 6028c2ecf20Sopenharmony_ci struct ieee80211_vif *main_vif, *old_main = NULL; 6038c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 6048c2ecf20Sopenharmony_ci int vif_id = -1, err = 0; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 6078c2ecf20Sopenharmony_ci rcu_read_lock(); 6088c2ecf20Sopenharmony_ci if (vif_priv->active) { 6098c2ecf20Sopenharmony_ci /* 6108c2ecf20Sopenharmony_ci * Skip the interface structure initialization, 6118c2ecf20Sopenharmony_ci * if the vif survived the _restart call. 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_ci vif_id = vif_priv->id; 6148c2ecf20Sopenharmony_ci vif_priv->enable_beacon = false; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci spin_lock_bh(&ar->beacon_lock); 6178c2ecf20Sopenharmony_ci dev_kfree_skb_any(vif_priv->beacon); 6188c2ecf20Sopenharmony_ci vif_priv->beacon = NULL; 6198c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->beacon_lock); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci goto init; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Because the AR9170 HW's MAC doesn't provide full support for 6258c2ecf20Sopenharmony_ci * multiple, independent interfaces [of different operation modes]. 6268c2ecf20Sopenharmony_ci * We have to select ONE main interface [main mode of HW], but we 6278c2ecf20Sopenharmony_ci * can have multiple slaves [AKA: entry in the ACK-table]. 6288c2ecf20Sopenharmony_ci * 6298c2ecf20Sopenharmony_ci * The first (from HEAD/TOP) interface in the ar->vif_list is 6308c2ecf20Sopenharmony_ci * always the main intf. All following intfs in this list 6318c2ecf20Sopenharmony_ci * are considered to be slave intfs. 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_ci main_vif = carl9170_get_main_vif(ar); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (main_vif) { 6368c2ecf20Sopenharmony_ci switch (main_vif->type) { 6378c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 6388c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci err = -EBUSY; 6428c2ecf20Sopenharmony_ci rcu_read_unlock(); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci goto unlock; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 6478c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 6488c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION) || 6498c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_WDS) || 6508c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_AP) || 6518c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_MESH_POINT)) 6528c2ecf20Sopenharmony_ci break; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci err = -EBUSY; 6558c2ecf20Sopenharmony_ci rcu_read_unlock(); 6568c2ecf20Sopenharmony_ci goto unlock; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci default: 6598c2ecf20Sopenharmony_ci rcu_read_unlock(); 6608c2ecf20Sopenharmony_ci goto unlock; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci vif_id = bitmap_find_free_region(&ar->vif_bitmap, ar->fw.vif_num, 0); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (vif_id < 0) { 6678c2ecf20Sopenharmony_ci rcu_read_unlock(); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci err = -ENOSPC; 6708c2ecf20Sopenharmony_ci goto unlock; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci BUG_ON(ar->vif_priv[vif_id].id != vif_id); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci vif_priv->active = true; 6768c2ecf20Sopenharmony_ci vif_priv->id = vif_id; 6778c2ecf20Sopenharmony_ci vif_priv->enable_beacon = false; 6788c2ecf20Sopenharmony_ci ar->vifs++; 6798c2ecf20Sopenharmony_ci if (old_main) { 6808c2ecf20Sopenharmony_ci /* We end up in here, if the main interface is being replaced. 6818c2ecf20Sopenharmony_ci * Put the new main interface at the HEAD of the list and the 6828c2ecf20Sopenharmony_ci * previous inteface will automatically become second in line. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci list_add_rcu(&vif_priv->list, &ar->vif_list); 6858c2ecf20Sopenharmony_ci } else { 6868c2ecf20Sopenharmony_ci /* Add new inteface. If the list is empty, it will become the 6878c2ecf20Sopenharmony_ci * main inteface, otherwise it will be slave. 6888c2ecf20Sopenharmony_ci */ 6898c2ecf20Sopenharmony_ci list_add_tail_rcu(&vif_priv->list, &ar->vif_list); 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci rcu_assign_pointer(ar->vif_priv[vif_id].vif, vif); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ciinit: 6948c2ecf20Sopenharmony_ci main_vif = carl9170_get_main_vif(ar); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (main_vif == vif) { 6978c2ecf20Sopenharmony_ci rcu_assign_pointer(ar->beacon_iter, vif_priv); 6988c2ecf20Sopenharmony_ci rcu_read_unlock(); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (old_main) { 7018c2ecf20Sopenharmony_ci struct carl9170_vif_info *old_main_priv = 7028c2ecf20Sopenharmony_ci (void *) old_main->drv_priv; 7038c2ecf20Sopenharmony_ci /* downgrade old main intf to slave intf. 7048c2ecf20Sopenharmony_ci * NOTE: We are no longer under rcu_read_lock. 7058c2ecf20Sopenharmony_ci * But we are still holding ar->mutex, so the 7068c2ecf20Sopenharmony_ci * vif data [id, addr] is safe. 7078c2ecf20Sopenharmony_ci */ 7088c2ecf20Sopenharmony_ci err = carl9170_mod_virtual_mac(ar, old_main_priv->id, 7098c2ecf20Sopenharmony_ci old_main->addr); 7108c2ecf20Sopenharmony_ci if (err) 7118c2ecf20Sopenharmony_ci goto unlock; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci err = carl9170_init_interface(ar, vif); 7158c2ecf20Sopenharmony_ci if (err) 7168c2ecf20Sopenharmony_ci goto unlock; 7178c2ecf20Sopenharmony_ci } else { 7188c2ecf20Sopenharmony_ci rcu_read_unlock(); 7198c2ecf20Sopenharmony_ci err = carl9170_mod_virtual_mac(ar, vif_id, vif->addr); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (err) 7228c2ecf20Sopenharmony_ci goto unlock; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (ar->fw.tx_seq_table) { 7268c2ecf20Sopenharmony_ci err = carl9170_write_reg(ar, ar->fw.tx_seq_table + vif_id * 4, 7278c2ecf20Sopenharmony_ci 0); 7288c2ecf20Sopenharmony_ci if (err) 7298c2ecf20Sopenharmony_ci goto unlock; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ciunlock: 7338c2ecf20Sopenharmony_ci if (err && (vif_id >= 0)) { 7348c2ecf20Sopenharmony_ci vif_priv->active = false; 7358c2ecf20Sopenharmony_ci bitmap_release_region(&ar->vif_bitmap, vif_id, 0); 7368c2ecf20Sopenharmony_ci ar->vifs--; 7378c2ecf20Sopenharmony_ci RCU_INIT_POINTER(ar->vif_priv[vif_id].vif, NULL); 7388c2ecf20Sopenharmony_ci list_del_rcu(&vif_priv->list); 7398c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 7408c2ecf20Sopenharmony_ci synchronize_rcu(); 7418c2ecf20Sopenharmony_ci } else { 7428c2ecf20Sopenharmony_ci if (ar->vifs > 1) 7438c2ecf20Sopenharmony_ci ar->ps.off_override |= PS_OFF_VIF; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci return err; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic void carl9170_op_remove_interface(struct ieee80211_hw *hw, 7528c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci struct carl9170_vif_info *vif_priv = (void *) vif->drv_priv; 7558c2ecf20Sopenharmony_ci struct ieee80211_vif *main_vif; 7568c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 7578c2ecf20Sopenharmony_ci unsigned int id; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!vif_priv->active)) 7628c2ecf20Sopenharmony_ci goto unlock; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci ar->vifs--; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci rcu_read_lock(); 7678c2ecf20Sopenharmony_ci main_vif = carl9170_get_main_vif(ar); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci id = vif_priv->id; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci vif_priv->active = false; 7728c2ecf20Sopenharmony_ci WARN_ON(vif_priv->enable_beacon); 7738c2ecf20Sopenharmony_ci vif_priv->enable_beacon = false; 7748c2ecf20Sopenharmony_ci list_del_rcu(&vif_priv->list); 7758c2ecf20Sopenharmony_ci RCU_INIT_POINTER(ar->vif_priv[id].vif, NULL); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (vif == main_vif) { 7788c2ecf20Sopenharmony_ci rcu_read_unlock(); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (ar->vifs) { 7818c2ecf20Sopenharmony_ci WARN_ON(carl9170_init_interface(ar, 7828c2ecf20Sopenharmony_ci carl9170_get_main_vif(ar))); 7838c2ecf20Sopenharmony_ci } else { 7848c2ecf20Sopenharmony_ci carl9170_set_operating_mode(ar); 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci } else { 7878c2ecf20Sopenharmony_ci rcu_read_unlock(); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci WARN_ON(carl9170_mod_virtual_mac(ar, id, NULL)); 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci carl9170_update_beacon(ar, false); 7938c2ecf20Sopenharmony_ci carl9170_flush_cab(ar, id); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci spin_lock_bh(&ar->beacon_lock); 7968c2ecf20Sopenharmony_ci dev_kfree_skb_any(vif_priv->beacon); 7978c2ecf20Sopenharmony_ci vif_priv->beacon = NULL; 7988c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->beacon_lock); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci bitmap_release_region(&ar->vif_bitmap, id, 0); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci carl9170_set_beacon_timers(ar); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (ar->vifs == 1) 8058c2ecf20Sopenharmony_ci ar->ps.off_override &= ~PS_OFF_VIF; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ciunlock: 8088c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci synchronize_rcu(); 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_civoid carl9170_ps_check(struct ar9170 *ar) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci ieee80211_queue_work(ar->hw, &ar->ps_work); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci/* caller must hold ar->mutex */ 8198c2ecf20Sopenharmony_cistatic int carl9170_ps_update(struct ar9170 *ar) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci bool ps = false; 8228c2ecf20Sopenharmony_ci int err = 0; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (!ar->ps.off_override) 8258c2ecf20Sopenharmony_ci ps = (ar->hw->conf.flags & IEEE80211_CONF_PS); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (ps != ar->ps.state) { 8288c2ecf20Sopenharmony_ci err = carl9170_powersave(ar, ps); 8298c2ecf20Sopenharmony_ci if (err) 8308c2ecf20Sopenharmony_ci return err; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (ar->ps.state && !ps) { 8338c2ecf20Sopenharmony_ci ar->ps.sleep_ms = jiffies_to_msecs(jiffies - 8348c2ecf20Sopenharmony_ci ar->ps.last_action); 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (ps) 8388c2ecf20Sopenharmony_ci ar->ps.last_slept = jiffies; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci ar->ps.last_action = jiffies; 8418c2ecf20Sopenharmony_ci ar->ps.state = ps; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return 0; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic void carl9170_ps_work(struct work_struct *work) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct ar9170 *ar = container_of(work, struct ar9170, 8508c2ecf20Sopenharmony_ci ps_work); 8518c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 8528c2ecf20Sopenharmony_ci if (IS_STARTED(ar)) 8538c2ecf20Sopenharmony_ci WARN_ON_ONCE(carl9170_ps_update(ar) != 0); 8548c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int carl9170_update_survey(struct ar9170 *ar, bool flush, bool noise) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci int err; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (noise) { 8628c2ecf20Sopenharmony_ci err = carl9170_get_noisefloor(ar); 8638c2ecf20Sopenharmony_ci if (err) 8648c2ecf20Sopenharmony_ci return err; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (ar->fw.hw_counters) { 8688c2ecf20Sopenharmony_ci err = carl9170_collect_tally(ar); 8698c2ecf20Sopenharmony_ci if (err) 8708c2ecf20Sopenharmony_ci return err; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (flush) 8748c2ecf20Sopenharmony_ci memset(&ar->tally, 0, sizeof(ar->tally)); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci return 0; 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic void carl9170_stat_work(struct work_struct *work) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci struct ar9170 *ar = container_of(work, struct ar9170, stat_work.work); 8828c2ecf20Sopenharmony_ci int err; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 8858c2ecf20Sopenharmony_ci err = carl9170_update_survey(ar, false, true); 8868c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (err) 8898c2ecf20Sopenharmony_ci return; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci ieee80211_queue_delayed_work(ar->hw, &ar->stat_work, 8928c2ecf20Sopenharmony_ci round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK))); 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic int carl9170_op_config(struct ieee80211_hw *hw, u32 changed) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 8988c2ecf20Sopenharmony_ci int err = 0; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 9018c2ecf20Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { 9028c2ecf20Sopenharmony_ci /* TODO */ 9038c2ecf20Sopenharmony_ci err = 0; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_PS) { 9078c2ecf20Sopenharmony_ci err = carl9170_ps_update(ar); 9088c2ecf20Sopenharmony_ci if (err) 9098c2ecf20Sopenharmony_ci goto out; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_SMPS) { 9138c2ecf20Sopenharmony_ci /* TODO */ 9148c2ecf20Sopenharmony_ci err = 0; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 9188c2ecf20Sopenharmony_ci enum nl80211_channel_type channel_type = 9198c2ecf20Sopenharmony_ci cfg80211_get_chandef_type(&hw->conf.chandef); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci /* adjust slot time for 5 GHz */ 9228c2ecf20Sopenharmony_ci err = carl9170_set_slot_time(ar); 9238c2ecf20Sopenharmony_ci if (err) 9248c2ecf20Sopenharmony_ci goto out; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci err = carl9170_update_survey(ar, true, false); 9278c2ecf20Sopenharmony_ci if (err) 9288c2ecf20Sopenharmony_ci goto out; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci err = carl9170_set_channel(ar, hw->conf.chandef.chan, 9318c2ecf20Sopenharmony_ci channel_type); 9328c2ecf20Sopenharmony_ci if (err) 9338c2ecf20Sopenharmony_ci goto out; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci err = carl9170_update_survey(ar, false, true); 9368c2ecf20Sopenharmony_ci if (err) 9378c2ecf20Sopenharmony_ci goto out; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci err = carl9170_set_dyn_sifs_ack(ar); 9408c2ecf20Sopenharmony_ci if (err) 9418c2ecf20Sopenharmony_ci goto out; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci err = carl9170_set_rts_cts_rate(ar); 9448c2ecf20Sopenharmony_ci if (err) 9458c2ecf20Sopenharmony_ci goto out; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_POWER) { 9498c2ecf20Sopenharmony_ci err = carl9170_set_mac_tpc(ar, ar->hw->conf.chandef.chan); 9508c2ecf20Sopenharmony_ci if (err) 9518c2ecf20Sopenharmony_ci goto out; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ciout: 9558c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 9568c2ecf20Sopenharmony_ci return err; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic u64 carl9170_op_prepare_multicast(struct ieee80211_hw *hw, 9608c2ecf20Sopenharmony_ci struct netdev_hw_addr_list *mc_list) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 9638c2ecf20Sopenharmony_ci u64 mchash; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci /* always get broadcast frames */ 9668c2ecf20Sopenharmony_ci mchash = 1ULL << (0xff >> 2); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci netdev_hw_addr_list_for_each(ha, mc_list) 9698c2ecf20Sopenharmony_ci mchash |= 1ULL << (ha->addr[5] >> 2); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci return mchash; 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_cistatic void carl9170_op_configure_filter(struct ieee80211_hw *hw, 9758c2ecf20Sopenharmony_ci unsigned int changed_flags, 9768c2ecf20Sopenharmony_ci unsigned int *new_flags, 9778c2ecf20Sopenharmony_ci u64 multicast) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* mask supported flags */ 9828c2ecf20Sopenharmony_ci *new_flags &= FIF_ALLMULTI | ar->rx_filter_caps; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (!IS_ACCEPTING_CMD(ar)) 9858c2ecf20Sopenharmony_ci return; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci ar->filter_state = *new_flags; 9908c2ecf20Sopenharmony_ci /* 9918c2ecf20Sopenharmony_ci * We can support more by setting the sniffer bit and 9928c2ecf20Sopenharmony_ci * then checking the error flags, later. 9938c2ecf20Sopenharmony_ci */ 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (*new_flags & FIF_ALLMULTI) 9968c2ecf20Sopenharmony_ci multicast = ~0ULL; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (multicast != ar->cur_mc_hash) 9998c2ecf20Sopenharmony_ci WARN_ON(carl9170_update_multicast(ar, multicast)); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (changed_flags & FIF_OTHER_BSS) { 10028c2ecf20Sopenharmony_ci ar->sniffer_enabled = !!(*new_flags & FIF_OTHER_BSS); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci WARN_ON(carl9170_set_operating_mode(ar)); 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (ar->fw.rx_filter && changed_flags & ar->rx_filter_caps) { 10088c2ecf20Sopenharmony_ci u32 rx_filter = 0; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci if (!ar->fw.ba_filter) 10118c2ecf20Sopenharmony_ci rx_filter |= CARL9170_RX_FILTER_CTL_OTHER; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (!(*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))) 10148c2ecf20Sopenharmony_ci rx_filter |= CARL9170_RX_FILTER_BAD; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (!(*new_flags & FIF_CONTROL)) 10178c2ecf20Sopenharmony_ci rx_filter |= CARL9170_RX_FILTER_CTL_OTHER; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (!(*new_flags & FIF_PSPOLL)) 10208c2ecf20Sopenharmony_ci rx_filter |= CARL9170_RX_FILTER_CTL_PSPOLL; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (!(*new_flags & FIF_OTHER_BSS)) { 10238c2ecf20Sopenharmony_ci rx_filter |= CARL9170_RX_FILTER_OTHER_RA; 10248c2ecf20Sopenharmony_ci rx_filter |= CARL9170_RX_FILTER_DECRY_FAIL; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci WARN_ON(carl9170_rx_filter(ar, rx_filter)); 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_cistatic void carl9170_op_bss_info_changed(struct ieee80211_hw *hw, 10358c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 10368c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss_conf, 10378c2ecf20Sopenharmony_ci u32 changed) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 10408c2ecf20Sopenharmony_ci struct ath_common *common = &ar->common; 10418c2ecf20Sopenharmony_ci int err = 0; 10428c2ecf20Sopenharmony_ci struct carl9170_vif_info *vif_priv; 10438c2ecf20Sopenharmony_ci struct ieee80211_vif *main_vif; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 10468c2ecf20Sopenharmony_ci vif_priv = (void *) vif->drv_priv; 10478c2ecf20Sopenharmony_ci main_vif = carl9170_get_main_vif(ar); 10488c2ecf20Sopenharmony_ci if (WARN_ON(!main_vif)) 10498c2ecf20Sopenharmony_ci goto out; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_ENABLED) { 10528c2ecf20Sopenharmony_ci struct carl9170_vif_info *iter; 10538c2ecf20Sopenharmony_ci int i = 0; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci vif_priv->enable_beacon = bss_conf->enable_beacon; 10568c2ecf20Sopenharmony_ci rcu_read_lock(); 10578c2ecf20Sopenharmony_ci list_for_each_entry_rcu(iter, &ar->vif_list, list) { 10588c2ecf20Sopenharmony_ci if (iter->active && iter->enable_beacon) 10598c2ecf20Sopenharmony_ci i++; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci rcu_read_unlock(); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci ar->beacon_enabled = i; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BEACON) { 10688c2ecf20Sopenharmony_ci err = carl9170_update_beacon(ar, false); 10698c2ecf20Sopenharmony_ci if (err) 10708c2ecf20Sopenharmony_ci goto out; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON | 10748c2ecf20Sopenharmony_ci BSS_CHANGED_BEACON_INT)) { 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (main_vif != vif) { 10778c2ecf20Sopenharmony_ci bss_conf->beacon_int = main_vif->bss_conf.beacon_int; 10788c2ecf20Sopenharmony_ci bss_conf->dtim_period = main_vif->bss_conf.dtim_period; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* 10828c2ecf20Sopenharmony_ci * Therefore a hard limit for the broadcast traffic should 10838c2ecf20Sopenharmony_ci * prevent false alarms. 10848c2ecf20Sopenharmony_ci */ 10858c2ecf20Sopenharmony_ci if (vif->type != NL80211_IFTYPE_STATION && 10868c2ecf20Sopenharmony_ci (bss_conf->beacon_int * bss_conf->dtim_period >= 10878c2ecf20Sopenharmony_ci (CARL9170_QUEUE_STUCK_TIMEOUT / 2))) { 10888c2ecf20Sopenharmony_ci err = -EINVAL; 10898c2ecf20Sopenharmony_ci goto out; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci err = carl9170_set_beacon_timers(ar); 10938c2ecf20Sopenharmony_ci if (err) 10948c2ecf20Sopenharmony_ci goto out; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_HT) { 10988c2ecf20Sopenharmony_ci /* TODO */ 10998c2ecf20Sopenharmony_ci err = 0; 11008c2ecf20Sopenharmony_ci if (err) 11018c2ecf20Sopenharmony_ci goto out; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci if (main_vif != vif) 11058c2ecf20Sopenharmony_ci goto out; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* 11088c2ecf20Sopenharmony_ci * The following settings can only be changed by the 11098c2ecf20Sopenharmony_ci * master interface. 11108c2ecf20Sopenharmony_ci */ 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BSSID) { 11138c2ecf20Sopenharmony_ci memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); 11148c2ecf20Sopenharmony_ci err = carl9170_set_operating_mode(ar); 11158c2ecf20Sopenharmony_ci if (err) 11168c2ecf20Sopenharmony_ci goto out; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_ASSOC) { 11208c2ecf20Sopenharmony_ci ar->common.curaid = bss_conf->aid; 11218c2ecf20Sopenharmony_ci err = carl9170_set_beacon_timers(ar); 11228c2ecf20Sopenharmony_ci if (err) 11238c2ecf20Sopenharmony_ci goto out; 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_ERP_SLOT) { 11278c2ecf20Sopenharmony_ci err = carl9170_set_slot_time(ar); 11288c2ecf20Sopenharmony_ci if (err) 11298c2ecf20Sopenharmony_ci goto out; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_BASIC_RATES) { 11338c2ecf20Sopenharmony_ci err = carl9170_set_mac_rates(ar); 11348c2ecf20Sopenharmony_ci if (err) 11358c2ecf20Sopenharmony_ci goto out; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ciout: 11398c2ecf20Sopenharmony_ci WARN_ON_ONCE(err && IS_STARTED(ar)); 11408c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic u64 carl9170_op_get_tsf(struct ieee80211_hw *hw, 11448c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 11478c2ecf20Sopenharmony_ci struct carl9170_tsf_rsp tsf; 11488c2ecf20Sopenharmony_ci int err; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 11518c2ecf20Sopenharmony_ci err = carl9170_exec_cmd(ar, CARL9170_CMD_READ_TSF, 11528c2ecf20Sopenharmony_ci 0, NULL, sizeof(tsf), &tsf); 11538c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 11548c2ecf20Sopenharmony_ci if (WARN_ON(err)) 11558c2ecf20Sopenharmony_ci return 0; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci return le64_to_cpu(tsf.tsf_64); 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_cistatic int carl9170_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 11618c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 11628c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 11638c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 11668c2ecf20Sopenharmony_ci int err = 0, i; 11678c2ecf20Sopenharmony_ci u8 ktype; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (ar->disable_offload || !vif) 11708c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* Fall back to software encryption whenever the driver is connected 11738c2ecf20Sopenharmony_ci * to more than one network. 11748c2ecf20Sopenharmony_ci * 11758c2ecf20Sopenharmony_ci * This is very unfortunate, because some machines cannot handle 11768c2ecf20Sopenharmony_ci * the high througput speed in 802.11n networks. 11778c2ecf20Sopenharmony_ci */ 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (!is_main_vif(ar, vif)) { 11808c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 11818c2ecf20Sopenharmony_ci goto err_softw; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci /* 11858c2ecf20Sopenharmony_ci * While the hardware supports *catch-all* key, for offloading 11868c2ecf20Sopenharmony_ci * group-key en-/de-cryption. The way of how the hardware 11878c2ecf20Sopenharmony_ci * decides which keyId maps to which key, remains a mystery... 11888c2ecf20Sopenharmony_ci */ 11898c2ecf20Sopenharmony_ci if ((vif->type != NL80211_IFTYPE_STATION && 11908c2ecf20Sopenharmony_ci vif->type != NL80211_IFTYPE_ADHOC) && 11918c2ecf20Sopenharmony_ci !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 11928c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci switch (key->cipher) { 11958c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 11968c2ecf20Sopenharmony_ci ktype = AR9170_ENC_ALG_WEP64; 11978c2ecf20Sopenharmony_ci break; 11988c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 11998c2ecf20Sopenharmony_ci ktype = AR9170_ENC_ALG_WEP128; 12008c2ecf20Sopenharmony_ci break; 12018c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 12028c2ecf20Sopenharmony_ci ktype = AR9170_ENC_ALG_TKIP; 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 12058c2ecf20Sopenharmony_ci ktype = AR9170_ENC_ALG_AESCCMP; 12068c2ecf20Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; 12078c2ecf20Sopenharmony_ci break; 12088c2ecf20Sopenharmony_ci default: 12098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 12138c2ecf20Sopenharmony_ci if (cmd == SET_KEY) { 12148c2ecf20Sopenharmony_ci if (!IS_STARTED(ar)) { 12158c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 12168c2ecf20Sopenharmony_ci goto out; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { 12208c2ecf20Sopenharmony_ci sta = NULL; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci i = 64 + key->keyidx; 12238c2ecf20Sopenharmony_ci } else { 12248c2ecf20Sopenharmony_ci for (i = 0; i < 64; i++) 12258c2ecf20Sopenharmony_ci if (!(ar->usedkeys & BIT(i))) 12268c2ecf20Sopenharmony_ci break; 12278c2ecf20Sopenharmony_ci if (i == 64) 12288c2ecf20Sopenharmony_ci goto err_softw; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci key->hw_key_idx = i; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci err = carl9170_upload_key(ar, i, sta ? sta->addr : NULL, 12348c2ecf20Sopenharmony_ci ktype, 0, key->key, 12358c2ecf20Sopenharmony_ci min_t(u8, 16, key->keylen)); 12368c2ecf20Sopenharmony_ci if (err) 12378c2ecf20Sopenharmony_ci goto out; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { 12408c2ecf20Sopenharmony_ci err = carl9170_upload_key(ar, i, sta ? sta->addr : 12418c2ecf20Sopenharmony_ci NULL, ktype, 1, 12428c2ecf20Sopenharmony_ci key->key + 16, 16); 12438c2ecf20Sopenharmony_ci if (err) 12448c2ecf20Sopenharmony_ci goto out; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci /* 12478c2ecf20Sopenharmony_ci * hardware is not capable generating MMIC 12488c2ecf20Sopenharmony_ci * of fragmented frames! 12498c2ecf20Sopenharmony_ci */ 12508c2ecf20Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci if (i < 64) 12548c2ecf20Sopenharmony_ci ar->usedkeys |= BIT(i); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 12578c2ecf20Sopenharmony_ci } else { 12588c2ecf20Sopenharmony_ci if (!IS_STARTED(ar)) { 12598c2ecf20Sopenharmony_ci /* The device is gone... together with the key ;-) */ 12608c2ecf20Sopenharmony_ci err = 0; 12618c2ecf20Sopenharmony_ci goto out; 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci if (key->hw_key_idx < 64) { 12658c2ecf20Sopenharmony_ci ar->usedkeys &= ~BIT(key->hw_key_idx); 12668c2ecf20Sopenharmony_ci } else { 12678c2ecf20Sopenharmony_ci err = carl9170_upload_key(ar, key->hw_key_idx, NULL, 12688c2ecf20Sopenharmony_ci AR9170_ENC_ALG_NONE, 0, 12698c2ecf20Sopenharmony_ci NULL, 0); 12708c2ecf20Sopenharmony_ci if (err) 12718c2ecf20Sopenharmony_ci goto out; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { 12748c2ecf20Sopenharmony_ci err = carl9170_upload_key(ar, key->hw_key_idx, 12758c2ecf20Sopenharmony_ci NULL, 12768c2ecf20Sopenharmony_ci AR9170_ENC_ALG_NONE, 12778c2ecf20Sopenharmony_ci 1, NULL, 0); 12788c2ecf20Sopenharmony_ci if (err) 12798c2ecf20Sopenharmony_ci goto out; 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci err = carl9170_disable_key(ar, key->hw_key_idx); 12858c2ecf20Sopenharmony_ci if (err) 12868c2ecf20Sopenharmony_ci goto out; 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ciout: 12908c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 12918c2ecf20Sopenharmony_ci return err; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cierr_softw: 12948c2ecf20Sopenharmony_ci if (!ar->rx_software_decryption) { 12958c2ecf20Sopenharmony_ci ar->rx_software_decryption = true; 12968c2ecf20Sopenharmony_ci carl9170_set_operating_mode(ar); 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 12998c2ecf20Sopenharmony_ci return -ENOSPC; 13008c2ecf20Sopenharmony_ci} 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_cistatic int carl9170_op_sta_add(struct ieee80211_hw *hw, 13038c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 13048c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; 13078c2ecf20Sopenharmony_ci unsigned int i; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci atomic_set(&sta_info->pending_frames, 0); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported) { 13128c2ecf20Sopenharmony_ci if (sta->ht_cap.ampdu_density > 6) { 13138c2ecf20Sopenharmony_ci /* 13148c2ecf20Sopenharmony_ci * HW does support 16us AMPDU density. 13158c2ecf20Sopenharmony_ci * No HT-Xmit for station. 13168c2ecf20Sopenharmony_ci */ 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci return 0; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) 13228c2ecf20Sopenharmony_ci RCU_INIT_POINTER(sta_info->agg[i], NULL); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor); 13258c2ecf20Sopenharmony_ci sta_info->ht_sta = true; 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci return 0; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic int carl9170_op_sta_remove(struct ieee80211_hw *hw, 13328c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 13338c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 13368c2ecf20Sopenharmony_ci struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; 13378c2ecf20Sopenharmony_ci unsigned int i; 13388c2ecf20Sopenharmony_ci bool cleanup = false; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported) { 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci sta_info->ht_sta = false; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci rcu_read_lock(); 13458c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta_info->agg); i++) { 13468c2ecf20Sopenharmony_ci struct carl9170_sta_tid *tid_info; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci tid_info = rcu_dereference(sta_info->agg[i]); 13498c2ecf20Sopenharmony_ci RCU_INIT_POINTER(sta_info->agg[i], NULL); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci if (!tid_info) 13528c2ecf20Sopenharmony_ci continue; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci spin_lock_bh(&ar->tx_ampdu_list_lock); 13558c2ecf20Sopenharmony_ci if (tid_info->state > CARL9170_TID_STATE_SHUTDOWN) 13568c2ecf20Sopenharmony_ci tid_info->state = CARL9170_TID_STATE_SHUTDOWN; 13578c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->tx_ampdu_list_lock); 13588c2ecf20Sopenharmony_ci cleanup = true; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci rcu_read_unlock(); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (cleanup) 13638c2ecf20Sopenharmony_ci carl9170_ampdu_gc(ar); 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci return 0; 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic int carl9170_op_conf_tx(struct ieee80211_hw *hw, 13708c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, u16 queue, 13718c2ecf20Sopenharmony_ci const struct ieee80211_tx_queue_params *param) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 13748c2ecf20Sopenharmony_ci int ret; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 13778c2ecf20Sopenharmony_ci memcpy(&ar->edcf[ar9170_qmap(queue)], param, sizeof(*param)); 13788c2ecf20Sopenharmony_ci ret = carl9170_set_qos(ar); 13798c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 13808c2ecf20Sopenharmony_ci return ret; 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_cistatic void carl9170_ampdu_work(struct work_struct *work) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct ar9170 *ar = container_of(work, struct ar9170, 13868c2ecf20Sopenharmony_ci ampdu_work); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (!IS_STARTED(ar)) 13898c2ecf20Sopenharmony_ci return; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 13928c2ecf20Sopenharmony_ci carl9170_ampdu_gc(ar); 13938c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 13948c2ecf20Sopenharmony_ci} 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cistatic int carl9170_op_ampdu_action(struct ieee80211_hw *hw, 13978c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 13988c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params) 13998c2ecf20Sopenharmony_ci{ 14008c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = params->sta; 14018c2ecf20Sopenharmony_ci enum ieee80211_ampdu_mlme_action action = params->action; 14028c2ecf20Sopenharmony_ci u16 tid = params->tid; 14038c2ecf20Sopenharmony_ci u16 *ssn = ¶ms->ssn; 14048c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 14058c2ecf20Sopenharmony_ci struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; 14068c2ecf20Sopenharmony_ci struct carl9170_sta_tid *tid_info; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (modparam_noht) 14098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci switch (action) { 14128c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_TX_START: 14138c2ecf20Sopenharmony_ci if (!sta_info->ht_sta) 14148c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci tid_info = kzalloc(sizeof(struct carl9170_sta_tid), 14178c2ecf20Sopenharmony_ci GFP_ATOMIC); 14188c2ecf20Sopenharmony_ci if (!tid_info) 14198c2ecf20Sopenharmony_ci return -ENOMEM; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci tid_info->hsn = tid_info->bsn = tid_info->snx = (*ssn); 14228c2ecf20Sopenharmony_ci tid_info->state = CARL9170_TID_STATE_PROGRESS; 14238c2ecf20Sopenharmony_ci tid_info->tid = tid; 14248c2ecf20Sopenharmony_ci tid_info->max = sta_info->ampdu_max_len; 14258c2ecf20Sopenharmony_ci tid_info->sta = sta; 14268c2ecf20Sopenharmony_ci tid_info->vif = vif; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tid_info->list); 14298c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tid_info->tmp_list); 14308c2ecf20Sopenharmony_ci skb_queue_head_init(&tid_info->queue); 14318c2ecf20Sopenharmony_ci spin_lock_init(&tid_info->lock); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci spin_lock_bh(&ar->tx_ampdu_list_lock); 14348c2ecf20Sopenharmony_ci ar->tx_ampdu_list_len++; 14358c2ecf20Sopenharmony_ci list_add_tail_rcu(&tid_info->list, &ar->tx_ampdu_list); 14368c2ecf20Sopenharmony_ci rcu_assign_pointer(sta_info->agg[tid], tid_info); 14378c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->tx_ampdu_list_lock); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci return IEEE80211_AMPDU_TX_START_IMMEDIATE; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_CONT: 14428c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH: 14438c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 14448c2ecf20Sopenharmony_ci rcu_read_lock(); 14458c2ecf20Sopenharmony_ci tid_info = rcu_dereference(sta_info->agg[tid]); 14468c2ecf20Sopenharmony_ci if (tid_info) { 14478c2ecf20Sopenharmony_ci spin_lock_bh(&ar->tx_ampdu_list_lock); 14488c2ecf20Sopenharmony_ci if (tid_info->state > CARL9170_TID_STATE_SHUTDOWN) 14498c2ecf20Sopenharmony_ci tid_info->state = CARL9170_TID_STATE_SHUTDOWN; 14508c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->tx_ampdu_list_lock); 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci RCU_INIT_POINTER(sta_info->agg[tid], NULL); 14548c2ecf20Sopenharmony_ci rcu_read_unlock(); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 14578c2ecf20Sopenharmony_ci ieee80211_queue_work(ar->hw, &ar->ampdu_work); 14588c2ecf20Sopenharmony_ci break; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_TX_OPERATIONAL: 14618c2ecf20Sopenharmony_ci rcu_read_lock(); 14628c2ecf20Sopenharmony_ci tid_info = rcu_dereference(sta_info->agg[tid]); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci sta_info->stats[tid].clear = true; 14658c2ecf20Sopenharmony_ci sta_info->stats[tid].req = false; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (tid_info) { 14688c2ecf20Sopenharmony_ci bitmap_zero(tid_info->bitmap, CARL9170_BAW_SIZE); 14698c2ecf20Sopenharmony_ci tid_info->state = CARL9170_TID_STATE_IDLE; 14708c2ecf20Sopenharmony_ci } 14718c2ecf20Sopenharmony_ci rcu_read_unlock(); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!tid_info)) 14748c2ecf20Sopenharmony_ci return -EFAULT; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci break; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_RX_START: 14798c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_RX_STOP: 14808c2ecf20Sopenharmony_ci /* Handled by hardware */ 14818c2ecf20Sopenharmony_ci break; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci default: 14848c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci return 0; 14888c2ecf20Sopenharmony_ci} 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_WPC 14918c2ecf20Sopenharmony_cistatic int carl9170_register_wps_button(struct ar9170 *ar) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci struct input_dev *input; 14948c2ecf20Sopenharmony_ci int err; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci if (!(ar->features & CARL9170_WPS_BUTTON)) 14978c2ecf20Sopenharmony_ci return 0; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci input = input_allocate_device(); 15008c2ecf20Sopenharmony_ci if (!input) 15018c2ecf20Sopenharmony_ci return -ENOMEM; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci snprintf(ar->wps.name, sizeof(ar->wps.name), "%s WPS Button", 15048c2ecf20Sopenharmony_ci wiphy_name(ar->hw->wiphy)); 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci snprintf(ar->wps.phys, sizeof(ar->wps.phys), 15078c2ecf20Sopenharmony_ci "ieee80211/%s/input0", wiphy_name(ar->hw->wiphy)); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci input->name = ar->wps.name; 15108c2ecf20Sopenharmony_ci input->phys = ar->wps.phys; 15118c2ecf20Sopenharmony_ci input->id.bustype = BUS_USB; 15128c2ecf20Sopenharmony_ci input->dev.parent = &ar->hw->wiphy->dev; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci input_set_capability(input, EV_KEY, KEY_WPS_BUTTON); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci err = input_register_device(input); 15178c2ecf20Sopenharmony_ci if (err) { 15188c2ecf20Sopenharmony_ci input_free_device(input); 15198c2ecf20Sopenharmony_ci return err; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci ar->wps.pbc = input; 15238c2ecf20Sopenharmony_ci return 0; 15248c2ecf20Sopenharmony_ci} 15258c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_WPC */ 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_HWRNG 15288c2ecf20Sopenharmony_cistatic int carl9170_rng_get(struct ar9170 *ar) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci#define RW (CARL9170_MAX_CMD_PAYLOAD_LEN / sizeof(u32)) 15328c2ecf20Sopenharmony_ci#define RB (CARL9170_MAX_CMD_PAYLOAD_LEN) 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci static const __le32 rng_load[RW] = { 15358c2ecf20Sopenharmony_ci [0 ... (RW - 1)] = cpu_to_le32(AR9170_RAND_REG_NUM)}; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci u32 buf[RW]; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci unsigned int i, off = 0, transfer, count; 15408c2ecf20Sopenharmony_ci int err; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci BUILD_BUG_ON(RB > CARL9170_MAX_CMD_PAYLOAD_LEN); 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci if (!IS_ACCEPTING_CMD(ar) || !ar->rng.initialized) 15458c2ecf20Sopenharmony_ci return -EAGAIN; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci count = ARRAY_SIZE(ar->rng.cache); 15488c2ecf20Sopenharmony_ci while (count) { 15498c2ecf20Sopenharmony_ci err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG, 15508c2ecf20Sopenharmony_ci RB, (u8 *) rng_load, 15518c2ecf20Sopenharmony_ci RB, (u8 *) buf); 15528c2ecf20Sopenharmony_ci if (err) 15538c2ecf20Sopenharmony_ci return err; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci transfer = min_t(unsigned int, count, RW); 15568c2ecf20Sopenharmony_ci for (i = 0; i < transfer; i++) 15578c2ecf20Sopenharmony_ci ar->rng.cache[off + i] = buf[i]; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci off += transfer; 15608c2ecf20Sopenharmony_ci count -= transfer; 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci ar->rng.cache_idx = 0; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci#undef RW 15668c2ecf20Sopenharmony_ci#undef RB 15678c2ecf20Sopenharmony_ci return 0; 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_cistatic int carl9170_rng_read(struct hwrng *rng, u32 *data) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci struct ar9170 *ar = (struct ar9170 *)rng->priv; 15738c2ecf20Sopenharmony_ci int ret = -EIO; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 15768c2ecf20Sopenharmony_ci if (ar->rng.cache_idx >= ARRAY_SIZE(ar->rng.cache)) { 15778c2ecf20Sopenharmony_ci ret = carl9170_rng_get(ar); 15788c2ecf20Sopenharmony_ci if (ret) { 15798c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 15808c2ecf20Sopenharmony_ci return ret; 15818c2ecf20Sopenharmony_ci } 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci *data = ar->rng.cache[ar->rng.cache_idx++]; 15858c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci return sizeof(u16); 15888c2ecf20Sopenharmony_ci} 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_cistatic void carl9170_unregister_hwrng(struct ar9170 *ar) 15918c2ecf20Sopenharmony_ci{ 15928c2ecf20Sopenharmony_ci if (ar->rng.initialized) { 15938c2ecf20Sopenharmony_ci hwrng_unregister(&ar->rng.rng); 15948c2ecf20Sopenharmony_ci ar->rng.initialized = false; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci} 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_cistatic int carl9170_register_hwrng(struct ar9170 *ar) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci int err; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci snprintf(ar->rng.name, ARRAY_SIZE(ar->rng.name), 16038c2ecf20Sopenharmony_ci "%s_%s", KBUILD_MODNAME, wiphy_name(ar->hw->wiphy)); 16048c2ecf20Sopenharmony_ci ar->rng.rng.name = ar->rng.name; 16058c2ecf20Sopenharmony_ci ar->rng.rng.data_read = carl9170_rng_read; 16068c2ecf20Sopenharmony_ci ar->rng.rng.priv = (unsigned long)ar; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (WARN_ON(ar->rng.initialized)) 16098c2ecf20Sopenharmony_ci return -EALREADY; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci err = hwrng_register(&ar->rng.rng); 16128c2ecf20Sopenharmony_ci if (err) { 16138c2ecf20Sopenharmony_ci dev_err(&ar->udev->dev, "Failed to register the random " 16148c2ecf20Sopenharmony_ci "number generator (%d)\n", err); 16158c2ecf20Sopenharmony_ci return err; 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci ar->rng.initialized = true; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci err = carl9170_rng_get(ar); 16218c2ecf20Sopenharmony_ci if (err) { 16228c2ecf20Sopenharmony_ci carl9170_unregister_hwrng(ar); 16238c2ecf20Sopenharmony_ci return err; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci return 0; 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_HWRNG */ 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_cistatic int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx, 16318c2ecf20Sopenharmony_ci struct survey_info *survey) 16328c2ecf20Sopenharmony_ci{ 16338c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 16348c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 16358c2ecf20Sopenharmony_ci struct ieee80211_supported_band *band; 16368c2ecf20Sopenharmony_ci int err, b, i; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci chan = ar->channel; 16398c2ecf20Sopenharmony_ci if (!chan) 16408c2ecf20Sopenharmony_ci return -ENODEV; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (idx == chan->hw_value) { 16438c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 16448c2ecf20Sopenharmony_ci err = carl9170_update_survey(ar, false, true); 16458c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 16468c2ecf20Sopenharmony_ci if (err) 16478c2ecf20Sopenharmony_ci return err; 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci for (b = 0; b < NUM_NL80211_BANDS; b++) { 16518c2ecf20Sopenharmony_ci band = ar->hw->wiphy->bands[b]; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci if (!band) 16548c2ecf20Sopenharmony_ci continue; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci for (i = 0; i < band->n_channels; i++) { 16578c2ecf20Sopenharmony_ci if (band->channels[i].hw_value == idx) { 16588c2ecf20Sopenharmony_ci chan = &band->channels[i]; 16598c2ecf20Sopenharmony_ci goto found; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci return -ENOENT; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_cifound: 16668c2ecf20Sopenharmony_ci memcpy(survey, &ar->survey[idx], sizeof(*survey)); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci survey->channel = chan; 16698c2ecf20Sopenharmony_ci survey->filled = SURVEY_INFO_NOISE_DBM; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (ar->channel == chan) 16728c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_IN_USE; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci if (ar->fw.hw_counters) { 16758c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_TIME | 16768c2ecf20Sopenharmony_ci SURVEY_INFO_TIME_BUSY | 16778c2ecf20Sopenharmony_ci SURVEY_INFO_TIME_TX; 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci return 0; 16818c2ecf20Sopenharmony_ci} 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_cistatic void carl9170_op_flush(struct ieee80211_hw *hw, 16848c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 16858c2ecf20Sopenharmony_ci u32 queues, bool drop) 16868c2ecf20Sopenharmony_ci{ 16878c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 16888c2ecf20Sopenharmony_ci unsigned int vid; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci mutex_lock(&ar->mutex); 16918c2ecf20Sopenharmony_ci for_each_set_bit(vid, &ar->vif_bitmap, ar->fw.vif_num) 16928c2ecf20Sopenharmony_ci carl9170_flush_cab(ar, vid); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci carl9170_flush(ar, drop); 16958c2ecf20Sopenharmony_ci mutex_unlock(&ar->mutex); 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_cistatic int carl9170_op_get_stats(struct ieee80211_hw *hw, 16998c2ecf20Sopenharmony_ci struct ieee80211_low_level_stats *stats) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 17048c2ecf20Sopenharmony_ci stats->dot11ACKFailureCount = ar->tx_ack_failures; 17058c2ecf20Sopenharmony_ci stats->dot11FCSErrorCount = ar->tx_fcs_errors; 17068c2ecf20Sopenharmony_ci return 0; 17078c2ecf20Sopenharmony_ci} 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_cistatic void carl9170_op_sta_notify(struct ieee80211_hw *hw, 17108c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 17118c2ecf20Sopenharmony_ci enum sta_notify_cmd cmd, 17128c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci switch (cmd) { 17178c2ecf20Sopenharmony_ci case STA_NOTIFY_SLEEP: 17188c2ecf20Sopenharmony_ci sta_info->sleeping = true; 17198c2ecf20Sopenharmony_ci if (atomic_read(&sta_info->pending_frames)) 17208c2ecf20Sopenharmony_ci ieee80211_sta_block_awake(hw, sta, true); 17218c2ecf20Sopenharmony_ci break; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci case STA_NOTIFY_AWAKE: 17248c2ecf20Sopenharmony_ci sta_info->sleeping = false; 17258c2ecf20Sopenharmony_ci break; 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci} 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic bool carl9170_tx_frames_pending(struct ieee80211_hw *hw) 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci return !!atomic_read(&ar->tx_total_queued); 17348c2ecf20Sopenharmony_ci} 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_cistatic const struct ieee80211_ops carl9170_ops = { 17378c2ecf20Sopenharmony_ci .start = carl9170_op_start, 17388c2ecf20Sopenharmony_ci .stop = carl9170_op_stop, 17398c2ecf20Sopenharmony_ci .tx = carl9170_op_tx, 17408c2ecf20Sopenharmony_ci .flush = carl9170_op_flush, 17418c2ecf20Sopenharmony_ci .add_interface = carl9170_op_add_interface, 17428c2ecf20Sopenharmony_ci .remove_interface = carl9170_op_remove_interface, 17438c2ecf20Sopenharmony_ci .config = carl9170_op_config, 17448c2ecf20Sopenharmony_ci .prepare_multicast = carl9170_op_prepare_multicast, 17458c2ecf20Sopenharmony_ci .configure_filter = carl9170_op_configure_filter, 17468c2ecf20Sopenharmony_ci .conf_tx = carl9170_op_conf_tx, 17478c2ecf20Sopenharmony_ci .bss_info_changed = carl9170_op_bss_info_changed, 17488c2ecf20Sopenharmony_ci .get_tsf = carl9170_op_get_tsf, 17498c2ecf20Sopenharmony_ci .set_key = carl9170_op_set_key, 17508c2ecf20Sopenharmony_ci .sta_add = carl9170_op_sta_add, 17518c2ecf20Sopenharmony_ci .sta_remove = carl9170_op_sta_remove, 17528c2ecf20Sopenharmony_ci .sta_notify = carl9170_op_sta_notify, 17538c2ecf20Sopenharmony_ci .get_survey = carl9170_op_get_survey, 17548c2ecf20Sopenharmony_ci .get_stats = carl9170_op_get_stats, 17558c2ecf20Sopenharmony_ci .ampdu_action = carl9170_op_ampdu_action, 17568c2ecf20Sopenharmony_ci .tx_frames_pending = carl9170_tx_frames_pending, 17578c2ecf20Sopenharmony_ci}; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_civoid *carl9170_alloc(size_t priv_size) 17608c2ecf20Sopenharmony_ci{ 17618c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 17628c2ecf20Sopenharmony_ci struct ar9170 *ar; 17638c2ecf20Sopenharmony_ci struct sk_buff *skb; 17648c2ecf20Sopenharmony_ci int i; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci /* 17678c2ecf20Sopenharmony_ci * this buffer is used for rx stream reconstruction. 17688c2ecf20Sopenharmony_ci * Under heavy load this device (or the transport layer?) 17698c2ecf20Sopenharmony_ci * tends to split the streams into separate rx descriptors. 17708c2ecf20Sopenharmony_ci */ 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL); 17738c2ecf20Sopenharmony_ci if (!skb) 17748c2ecf20Sopenharmony_ci goto err_nomem; 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci hw = ieee80211_alloc_hw(priv_size, &carl9170_ops); 17778c2ecf20Sopenharmony_ci if (!hw) 17788c2ecf20Sopenharmony_ci goto err_nomem; 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci ar = hw->priv; 17818c2ecf20Sopenharmony_ci ar->hw = hw; 17828c2ecf20Sopenharmony_ci ar->rx_failover = skb; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci memset(&ar->rx_plcp, 0, sizeof(struct ar9170_rx_head)); 17858c2ecf20Sopenharmony_ci ar->rx_has_plcp = false; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci /* 17888c2ecf20Sopenharmony_ci * Here's a hidden pitfall! 17898c2ecf20Sopenharmony_ci * 17908c2ecf20Sopenharmony_ci * All 4 AC queues work perfectly well under _legacy_ operation. 17918c2ecf20Sopenharmony_ci * However as soon as aggregation is enabled, the traffic flow 17928c2ecf20Sopenharmony_ci * gets very bumpy. Therefore we have to _switch_ to a 17938c2ecf20Sopenharmony_ci * software AC with a single HW queue. 17948c2ecf20Sopenharmony_ci */ 17958c2ecf20Sopenharmony_ci hw->queues = __AR9170_NUM_TXQ; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci mutex_init(&ar->mutex); 17988c2ecf20Sopenharmony_ci spin_lock_init(&ar->beacon_lock); 17998c2ecf20Sopenharmony_ci spin_lock_init(&ar->cmd_lock); 18008c2ecf20Sopenharmony_ci spin_lock_init(&ar->tx_stats_lock); 18018c2ecf20Sopenharmony_ci spin_lock_init(&ar->tx_ampdu_list_lock); 18028c2ecf20Sopenharmony_ci spin_lock_init(&ar->mem_lock); 18038c2ecf20Sopenharmony_ci spin_lock_init(&ar->state_lock); 18048c2ecf20Sopenharmony_ci atomic_set(&ar->pending_restarts, 0); 18058c2ecf20Sopenharmony_ci ar->vifs = 0; 18068c2ecf20Sopenharmony_ci for (i = 0; i < ar->hw->queues; i++) { 18078c2ecf20Sopenharmony_ci skb_queue_head_init(&ar->tx_status[i]); 18088c2ecf20Sopenharmony_ci skb_queue_head_init(&ar->tx_pending[i]); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ar->bar_list[i]); 18118c2ecf20Sopenharmony_ci spin_lock_init(&ar->bar_list_lock[i]); 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci INIT_WORK(&ar->ps_work, carl9170_ps_work); 18148c2ecf20Sopenharmony_ci INIT_WORK(&ar->ping_work, carl9170_ping_work); 18158c2ecf20Sopenharmony_ci INIT_WORK(&ar->restart_work, carl9170_restart_work); 18168c2ecf20Sopenharmony_ci INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work); 18178c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&ar->stat_work, carl9170_stat_work); 18188c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor); 18198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ar->tx_ampdu_list); 18208c2ecf20Sopenharmony_ci rcu_assign_pointer(ar->tx_ampdu_iter, 18218c2ecf20Sopenharmony_ci (struct carl9170_sta_tid *) &ar->tx_ampdu_list); 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci bitmap_zero(&ar->vif_bitmap, ar->fw.vif_num); 18248c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ar->vif_list); 18258c2ecf20Sopenharmony_ci init_completion(&ar->tx_flush); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci /* firmware decides which modes we support */ 18288c2ecf20Sopenharmony_ci hw->wiphy->interface_modes = 0; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, RX_INCLUDES_FCS); 18318c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, MFP_CAPABLE); 18328c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 18338c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_PS); 18348c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 18358c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC); 18368c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 18378c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 18388c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (!modparam_noht) { 18418c2ecf20Sopenharmony_ci /* 18428c2ecf20Sopenharmony_ci * see the comment above, why we allow the user 18438c2ecf20Sopenharmony_ci * to disable HT by a module parameter. 18448c2ecf20Sopenharmony_ci */ 18458c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, AMPDU_AGGREGATION); 18468c2ecf20Sopenharmony_ci } 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci hw->extra_tx_headroom = sizeof(struct _carl9170_tx_superframe); 18498c2ecf20Sopenharmony_ci hw->sta_data_size = sizeof(struct carl9170_sta_info); 18508c2ecf20Sopenharmony_ci hw->vif_data_size = sizeof(struct carl9170_vif_info); 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci hw->max_rates = CARL9170_TX_MAX_RATES; 18538c2ecf20Sopenharmony_ci hw->max_rate_tries = CARL9170_TX_USER_RATE_TRIES; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ar->noise); i++) 18568c2ecf20Sopenharmony_ci ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci return ar; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_cierr_nomem: 18638c2ecf20Sopenharmony_ci kfree_skb(skb); 18648c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_cistatic int carl9170_read_eeprom(struct ar9170 *ar) 18688c2ecf20Sopenharmony_ci{ 18698c2ecf20Sopenharmony_ci#define RW 8 /* number of words to read at once */ 18708c2ecf20Sopenharmony_ci#define RB (sizeof(u32) * RW) 18718c2ecf20Sopenharmony_ci u8 *eeprom = (void *)&ar->eeprom; 18728c2ecf20Sopenharmony_ci __le32 offsets[RW]; 18738c2ecf20Sopenharmony_ci int i, j, err; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(ar->eeprom) & 3); 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci BUILD_BUG_ON(RB > CARL9170_MAX_CMD_LEN - 4); 18788c2ecf20Sopenharmony_ci#ifndef __CHECKER__ 18798c2ecf20Sopenharmony_ci /* don't want to handle trailing remains */ 18808c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(ar->eeprom) % RB); 18818c2ecf20Sopenharmony_ci#endif 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(ar->eeprom) / RB; i++) { 18848c2ecf20Sopenharmony_ci for (j = 0; j < RW; j++) 18858c2ecf20Sopenharmony_ci offsets[j] = cpu_to_le32(AR9170_EEPROM_START + 18868c2ecf20Sopenharmony_ci RB * i + 4 * j); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG, 18898c2ecf20Sopenharmony_ci RB, (u8 *) &offsets, 18908c2ecf20Sopenharmony_ci RB, eeprom + RB * i); 18918c2ecf20Sopenharmony_ci if (err) 18928c2ecf20Sopenharmony_ci return err; 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci#undef RW 18968c2ecf20Sopenharmony_ci#undef RB 18978c2ecf20Sopenharmony_ci return 0; 18988c2ecf20Sopenharmony_ci} 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_cistatic int carl9170_parse_eeprom(struct ar9170 *ar) 19018c2ecf20Sopenharmony_ci{ 19028c2ecf20Sopenharmony_ci struct ath_regulatory *regulatory = &ar->common.regulatory; 19038c2ecf20Sopenharmony_ci unsigned int rx_streams, tx_streams, tx_params = 0; 19048c2ecf20Sopenharmony_ci int bands = 0; 19058c2ecf20Sopenharmony_ci int chans = 0; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci if (ar->eeprom.length == cpu_to_le16(0xffff)) 19088c2ecf20Sopenharmony_ci return -ENODATA; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci rx_streams = hweight8(ar->eeprom.rx_mask); 19118c2ecf20Sopenharmony_ci tx_streams = hweight8(ar->eeprom.tx_mask); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci if (rx_streams != tx_streams) { 19148c2ecf20Sopenharmony_ci tx_params = IEEE80211_HT_MCS_TX_RX_DIFF; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci WARN_ON(!(tx_streams >= 1 && tx_streams <= 19178c2ecf20Sopenharmony_ci IEEE80211_HT_MCS_TX_MAX_STREAMS)); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci tx_params |= (tx_streams - 1) << 19208c2ecf20Sopenharmony_ci IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci carl9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params; 19238c2ecf20Sopenharmony_ci carl9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params; 19248c2ecf20Sopenharmony_ci } 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { 19278c2ecf20Sopenharmony_ci ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = 19288c2ecf20Sopenharmony_ci &carl9170_band_2GHz; 19298c2ecf20Sopenharmony_ci chans += carl9170_band_2GHz.n_channels; 19308c2ecf20Sopenharmony_ci bands++; 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { 19338c2ecf20Sopenharmony_ci ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = 19348c2ecf20Sopenharmony_ci &carl9170_band_5GHz; 19358c2ecf20Sopenharmony_ci chans += carl9170_band_5GHz.n_channels; 19368c2ecf20Sopenharmony_ci bands++; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (!bands) 19408c2ecf20Sopenharmony_ci return -EINVAL; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci ar->survey = kcalloc(chans, sizeof(struct survey_info), GFP_KERNEL); 19438c2ecf20Sopenharmony_ci if (!ar->survey) 19448c2ecf20Sopenharmony_ci return -ENOMEM; 19458c2ecf20Sopenharmony_ci ar->num_channels = chans; 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci /* second part of wiphy init */ 19508c2ecf20Sopenharmony_ci SET_IEEE80211_PERM_ADDR(ar->hw, ar->eeprom.mac_address); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci return 0; 19538c2ecf20Sopenharmony_ci} 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_cistatic void carl9170_reg_notifier(struct wiphy *wiphy, 19568c2ecf20Sopenharmony_ci struct regulatory_request *request) 19578c2ecf20Sopenharmony_ci{ 19588c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 19598c2ecf20Sopenharmony_ci struct ar9170 *ar = hw->priv; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory); 19628c2ecf20Sopenharmony_ci} 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ciint carl9170_register(struct ar9170 *ar) 19658c2ecf20Sopenharmony_ci{ 19668c2ecf20Sopenharmony_ci struct ath_regulatory *regulatory = &ar->common.regulatory; 19678c2ecf20Sopenharmony_ci int err = 0, i; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci if (WARN_ON(ar->mem_bitmap)) 19708c2ecf20Sopenharmony_ci return -EINVAL; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci ar->mem_bitmap = kcalloc(roundup(ar->fw.mem_blocks, BITS_PER_LONG), 19738c2ecf20Sopenharmony_ci sizeof(unsigned long), 19748c2ecf20Sopenharmony_ci GFP_KERNEL); 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci if (!ar->mem_bitmap) 19778c2ecf20Sopenharmony_ci return -ENOMEM; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci /* try to read EEPROM, init MAC addr */ 19808c2ecf20Sopenharmony_ci err = carl9170_read_eeprom(ar); 19818c2ecf20Sopenharmony_ci if (err) 19828c2ecf20Sopenharmony_ci return err; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci err = carl9170_parse_eeprom(ar); 19858c2ecf20Sopenharmony_ci if (err) 19868c2ecf20Sopenharmony_ci return err; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci err = ath_regd_init(regulatory, ar->hw->wiphy, 19898c2ecf20Sopenharmony_ci carl9170_reg_notifier); 19908c2ecf20Sopenharmony_ci if (err) 19918c2ecf20Sopenharmony_ci return err; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci if (modparam_noht) { 19948c2ecf20Sopenharmony_ci carl9170_band_2GHz.ht_cap.ht_supported = false; 19958c2ecf20Sopenharmony_ci carl9170_band_5GHz.ht_cap.ht_supported = false; 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci for (i = 0; i < ar->fw.vif_num; i++) { 19998c2ecf20Sopenharmony_ci ar->vif_priv[i].id = i; 20008c2ecf20Sopenharmony_ci ar->vif_priv[i].vif = NULL; 20018c2ecf20Sopenharmony_ci } 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci err = ieee80211_register_hw(ar->hw); 20048c2ecf20Sopenharmony_ci if (err) 20058c2ecf20Sopenharmony_ci return err; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci /* mac80211 interface is now registered */ 20088c2ecf20Sopenharmony_ci ar->registered = true; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci if (!ath_is_world_regd(regulatory)) 20118c2ecf20Sopenharmony_ci regulatory_hint(ar->hw->wiphy, regulatory->alpha2); 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_DEBUGFS 20148c2ecf20Sopenharmony_ci carl9170_debugfs_register(ar); 20158c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_DEBUGFS */ 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci err = carl9170_led_init(ar); 20188c2ecf20Sopenharmony_ci if (err) 20198c2ecf20Sopenharmony_ci goto err_unreg; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_LEDS 20228c2ecf20Sopenharmony_ci err = carl9170_led_register(ar); 20238c2ecf20Sopenharmony_ci if (err) 20248c2ecf20Sopenharmony_ci goto err_unreg; 20258c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_LEDS */ 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_WPC 20288c2ecf20Sopenharmony_ci err = carl9170_register_wps_button(ar); 20298c2ecf20Sopenharmony_ci if (err) 20308c2ecf20Sopenharmony_ci goto err_unreg; 20318c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_WPC */ 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_HWRNG 20348c2ecf20Sopenharmony_ci err = carl9170_register_hwrng(ar); 20358c2ecf20Sopenharmony_ci if (err) 20368c2ecf20Sopenharmony_ci goto err_unreg; 20378c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_HWRNG */ 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n", 20408c2ecf20Sopenharmony_ci wiphy_name(ar->hw->wiphy)); 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci return 0; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_cierr_unreg: 20458c2ecf20Sopenharmony_ci carl9170_unregister(ar); 20468c2ecf20Sopenharmony_ci return err; 20478c2ecf20Sopenharmony_ci} 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_civoid carl9170_unregister(struct ar9170 *ar) 20508c2ecf20Sopenharmony_ci{ 20518c2ecf20Sopenharmony_ci if (!ar->registered) 20528c2ecf20Sopenharmony_ci return; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci ar->registered = false; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_LEDS 20578c2ecf20Sopenharmony_ci carl9170_led_unregister(ar); 20588c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_LEDS */ 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_DEBUGFS 20618c2ecf20Sopenharmony_ci carl9170_debugfs_unregister(ar); 20628c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_DEBUGFS */ 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_WPC 20658c2ecf20Sopenharmony_ci if (ar->wps.pbc) { 20668c2ecf20Sopenharmony_ci input_unregister_device(ar->wps.pbc); 20678c2ecf20Sopenharmony_ci ar->wps.pbc = NULL; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_WPC */ 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci#ifdef CONFIG_CARL9170_HWRNG 20728c2ecf20Sopenharmony_ci carl9170_unregister_hwrng(ar); 20738c2ecf20Sopenharmony_ci#endif /* CONFIG_CARL9170_HWRNG */ 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci carl9170_cancel_worker(ar); 20768c2ecf20Sopenharmony_ci cancel_work_sync(&ar->restart_work); 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci ieee80211_unregister_hw(ar->hw); 20798c2ecf20Sopenharmony_ci} 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_civoid carl9170_free(struct ar9170 *ar) 20828c2ecf20Sopenharmony_ci{ 20838c2ecf20Sopenharmony_ci WARN_ON(ar->registered); 20848c2ecf20Sopenharmony_ci WARN_ON(IS_INITIALIZED(ar)); 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci kfree_skb(ar->rx_failover); 20878c2ecf20Sopenharmony_ci ar->rx_failover = NULL; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci kfree(ar->mem_bitmap); 20908c2ecf20Sopenharmony_ci ar->mem_bitmap = NULL; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci kfree(ar->survey); 20938c2ecf20Sopenharmony_ci ar->survey = NULL; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci mutex_destroy(&ar->mutex); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci ieee80211_free_hw(ar->hw); 20988c2ecf20Sopenharmony_ci} 2099