12774f206SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 22774f206SBjoern A. Zeeb /* Copyright(c) 2018-2019 Realtek Corporation 32774f206SBjoern A. Zeeb */ 42774f206SBjoern A. Zeeb 52774f206SBjoern A. Zeeb #if defined(__FreeBSD__) 62774f206SBjoern A. Zeeb #define LINUXKPI_PARAM_PREFIX rtw88_ 72774f206SBjoern A. Zeeb #endif 82774f206SBjoern A. Zeeb 92774f206SBjoern A. Zeeb #include <linux/devcoredump.h> 102774f206SBjoern A. Zeeb 112774f206SBjoern A. Zeeb #include "main.h" 122774f206SBjoern A. Zeeb #include "regd.h" 132774f206SBjoern A. Zeeb #include "fw.h" 142774f206SBjoern A. Zeeb #include "ps.h" 152774f206SBjoern A. Zeeb #include "sec.h" 162774f206SBjoern A. Zeeb #include "mac.h" 172774f206SBjoern A. Zeeb #include "coex.h" 182774f206SBjoern A. Zeeb #include "phy.h" 192774f206SBjoern A. Zeeb #include "reg.h" 202774f206SBjoern A. Zeeb #include "efuse.h" 212774f206SBjoern A. Zeeb #include "tx.h" 222774f206SBjoern A. Zeeb #include "debug.h" 232774f206SBjoern A. Zeeb #include "bf.h" 242774f206SBjoern A. Zeeb #include "sar.h" 2590aac0d8SBjoern A. Zeeb #include "sdio.h" 262774f206SBjoern A. Zeeb 272774f206SBjoern A. Zeeb bool rtw_disable_lps_deep_mode; 282774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_disable_lps_deep_mode); 292774f206SBjoern A. Zeeb bool rtw_bf_support = true; 302774f206SBjoern A. Zeeb unsigned int rtw_debug_mask; 312774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_debug_mask); 322774f206SBjoern A. Zeeb /* EDCCA is enabled during normal behavior. For debugging purpose in 332774f206SBjoern A. Zeeb * a noisy environment, it can be disabled via edcca debugfs. Because 342774f206SBjoern A. Zeeb * all rtw88 devices will probably be affected if environment is noisy, 352774f206SBjoern A. Zeeb * rtw_edcca_enabled is just declared by driver instead of by device. 362774f206SBjoern A. Zeeb * So, turning it off will take effect for all rtw88 devices before 372774f206SBjoern A. Zeeb * there is a tough reason to maintain rtw_edcca_enabled by device. 382774f206SBjoern A. Zeeb */ 392774f206SBjoern A. Zeeb bool rtw_edcca_enabled = true; 402774f206SBjoern A. Zeeb 412774f206SBjoern A. Zeeb module_param_named(disable_lps_deep, rtw_disable_lps_deep_mode, bool, 0644); 422774f206SBjoern A. Zeeb module_param_named(support_bf, rtw_bf_support, bool, 0644); 432774f206SBjoern A. Zeeb module_param_named(debug_mask, rtw_debug_mask, uint, 0644); 442774f206SBjoern A. Zeeb 452774f206SBjoern A. Zeeb MODULE_PARM_DESC(disable_lps_deep, "Set Y to disable Deep PS"); 462774f206SBjoern A. Zeeb MODULE_PARM_DESC(support_bf, "Set Y to enable beamformee support"); 472774f206SBjoern A. Zeeb MODULE_PARM_DESC(debug_mask, "Debugging mask"); 482774f206SBjoern A. Zeeb 492774f206SBjoern A. Zeeb static struct ieee80211_channel rtw_channeltable_2g[] = { 502774f206SBjoern A. Zeeb {.center_freq = 2412, .hw_value = 1,}, 512774f206SBjoern A. Zeeb {.center_freq = 2417, .hw_value = 2,}, 522774f206SBjoern A. Zeeb {.center_freq = 2422, .hw_value = 3,}, 532774f206SBjoern A. Zeeb {.center_freq = 2427, .hw_value = 4,}, 542774f206SBjoern A. Zeeb {.center_freq = 2432, .hw_value = 5,}, 552774f206SBjoern A. Zeeb {.center_freq = 2437, .hw_value = 6,}, 562774f206SBjoern A. Zeeb {.center_freq = 2442, .hw_value = 7,}, 572774f206SBjoern A. Zeeb {.center_freq = 2447, .hw_value = 8,}, 582774f206SBjoern A. Zeeb {.center_freq = 2452, .hw_value = 9,}, 592774f206SBjoern A. Zeeb {.center_freq = 2457, .hw_value = 10,}, 602774f206SBjoern A. Zeeb {.center_freq = 2462, .hw_value = 11,}, 612774f206SBjoern A. Zeeb {.center_freq = 2467, .hw_value = 12,}, 622774f206SBjoern A. Zeeb {.center_freq = 2472, .hw_value = 13,}, 632774f206SBjoern A. Zeeb {.center_freq = 2484, .hw_value = 14,}, 642774f206SBjoern A. Zeeb }; 652774f206SBjoern A. Zeeb 662774f206SBjoern A. Zeeb static struct ieee80211_channel rtw_channeltable_5g[] = { 672774f206SBjoern A. Zeeb {.center_freq = 5180, .hw_value = 36,}, 682774f206SBjoern A. Zeeb {.center_freq = 5200, .hw_value = 40,}, 692774f206SBjoern A. Zeeb {.center_freq = 5220, .hw_value = 44,}, 702774f206SBjoern A. Zeeb {.center_freq = 5240, .hw_value = 48,}, 712774f206SBjoern A. Zeeb {.center_freq = 5260, .hw_value = 52,}, 722774f206SBjoern A. Zeeb {.center_freq = 5280, .hw_value = 56,}, 732774f206SBjoern A. Zeeb {.center_freq = 5300, .hw_value = 60,}, 742774f206SBjoern A. Zeeb {.center_freq = 5320, .hw_value = 64,}, 752774f206SBjoern A. Zeeb {.center_freq = 5500, .hw_value = 100,}, 762774f206SBjoern A. Zeeb {.center_freq = 5520, .hw_value = 104,}, 772774f206SBjoern A. Zeeb {.center_freq = 5540, .hw_value = 108,}, 782774f206SBjoern A. Zeeb {.center_freq = 5560, .hw_value = 112,}, 792774f206SBjoern A. Zeeb {.center_freq = 5580, .hw_value = 116,}, 802774f206SBjoern A. Zeeb {.center_freq = 5600, .hw_value = 120,}, 812774f206SBjoern A. Zeeb {.center_freq = 5620, .hw_value = 124,}, 822774f206SBjoern A. Zeeb {.center_freq = 5640, .hw_value = 128,}, 832774f206SBjoern A. Zeeb {.center_freq = 5660, .hw_value = 132,}, 842774f206SBjoern A. Zeeb {.center_freq = 5680, .hw_value = 136,}, 852774f206SBjoern A. Zeeb {.center_freq = 5700, .hw_value = 140,}, 862774f206SBjoern A. Zeeb {.center_freq = 5720, .hw_value = 144,}, 872774f206SBjoern A. Zeeb {.center_freq = 5745, .hw_value = 149,}, 882774f206SBjoern A. Zeeb {.center_freq = 5765, .hw_value = 153,}, 892774f206SBjoern A. Zeeb {.center_freq = 5785, .hw_value = 157,}, 902774f206SBjoern A. Zeeb {.center_freq = 5805, .hw_value = 161,}, 912774f206SBjoern A. Zeeb {.center_freq = 5825, .hw_value = 165, 922774f206SBjoern A. Zeeb .flags = IEEE80211_CHAN_NO_HT40MINUS}, 932774f206SBjoern A. Zeeb }; 942774f206SBjoern A. Zeeb 952774f206SBjoern A. Zeeb static struct ieee80211_rate rtw_ratetable[] = { 962774f206SBjoern A. Zeeb {.bitrate = 10, .hw_value = 0x00,}, 972774f206SBjoern A. Zeeb {.bitrate = 20, .hw_value = 0x01,}, 982774f206SBjoern A. Zeeb {.bitrate = 55, .hw_value = 0x02,}, 992774f206SBjoern A. Zeeb {.bitrate = 110, .hw_value = 0x03,}, 1002774f206SBjoern A. Zeeb {.bitrate = 60, .hw_value = 0x04,}, 1012774f206SBjoern A. Zeeb {.bitrate = 90, .hw_value = 0x05,}, 1022774f206SBjoern A. Zeeb {.bitrate = 120, .hw_value = 0x06,}, 1032774f206SBjoern A. Zeeb {.bitrate = 180, .hw_value = 0x07,}, 1042774f206SBjoern A. Zeeb {.bitrate = 240, .hw_value = 0x08,}, 1052774f206SBjoern A. Zeeb {.bitrate = 360, .hw_value = 0x09,}, 1062774f206SBjoern A. Zeeb {.bitrate = 480, .hw_value = 0x0a,}, 1072774f206SBjoern A. Zeeb {.bitrate = 540, .hw_value = 0x0b,}, 1082774f206SBjoern A. Zeeb }; 1092774f206SBjoern A. Zeeb 11090aac0d8SBjoern A. Zeeb static const struct ieee80211_iface_limit rtw_iface_limits[] = { 11190aac0d8SBjoern A. Zeeb { 11290aac0d8SBjoern A. Zeeb .max = 1, 11390aac0d8SBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_STATION), 11490aac0d8SBjoern A. Zeeb }, 11590aac0d8SBjoern A. Zeeb { 11690aac0d8SBjoern A. Zeeb .max = 1, 11790aac0d8SBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_AP), 11890aac0d8SBjoern A. Zeeb } 11990aac0d8SBjoern A. Zeeb }; 12090aac0d8SBjoern A. Zeeb 12190aac0d8SBjoern A. Zeeb static const struct ieee80211_iface_combination rtw_iface_combs[] = { 12290aac0d8SBjoern A. Zeeb { 12390aac0d8SBjoern A. Zeeb .limits = rtw_iface_limits, 12490aac0d8SBjoern A. Zeeb .n_limits = ARRAY_SIZE(rtw_iface_limits), 12590aac0d8SBjoern A. Zeeb .max_interfaces = 2, 12690aac0d8SBjoern A. Zeeb .num_different_channels = 1, 12790aac0d8SBjoern A. Zeeb } 12890aac0d8SBjoern A. Zeeb }; 12990aac0d8SBjoern A. Zeeb 1302774f206SBjoern A. Zeeb u16 rtw_desc_to_bitrate(u8 desc_rate) 1312774f206SBjoern A. Zeeb { 1322774f206SBjoern A. Zeeb struct ieee80211_rate rate; 1332774f206SBjoern A. Zeeb 1342774f206SBjoern A. Zeeb if (WARN(desc_rate >= ARRAY_SIZE(rtw_ratetable), "invalid desc rate\n")) 1352774f206SBjoern A. Zeeb return 0; 1362774f206SBjoern A. Zeeb 1372774f206SBjoern A. Zeeb rate = rtw_ratetable[desc_rate]; 1382774f206SBjoern A. Zeeb 1392774f206SBjoern A. Zeeb return rate.bitrate; 1402774f206SBjoern A. Zeeb } 1412774f206SBjoern A. Zeeb 1422774f206SBjoern A. Zeeb static struct ieee80211_supported_band rtw_band_2ghz = { 1432774f206SBjoern A. Zeeb .band = NL80211_BAND_2GHZ, 1442774f206SBjoern A. Zeeb 1452774f206SBjoern A. Zeeb .channels = rtw_channeltable_2g, 1462774f206SBjoern A. Zeeb .n_channels = ARRAY_SIZE(rtw_channeltable_2g), 1472774f206SBjoern A. Zeeb 1482774f206SBjoern A. Zeeb .bitrates = rtw_ratetable, 1492774f206SBjoern A. Zeeb .n_bitrates = ARRAY_SIZE(rtw_ratetable), 1502774f206SBjoern A. Zeeb 1512774f206SBjoern A. Zeeb .ht_cap = {0}, 1522774f206SBjoern A. Zeeb .vht_cap = {0}, 1532774f206SBjoern A. Zeeb }; 1542774f206SBjoern A. Zeeb 1552774f206SBjoern A. Zeeb static struct ieee80211_supported_band rtw_band_5ghz = { 1562774f206SBjoern A. Zeeb .band = NL80211_BAND_5GHZ, 1572774f206SBjoern A. Zeeb 1582774f206SBjoern A. Zeeb .channels = rtw_channeltable_5g, 1592774f206SBjoern A. Zeeb .n_channels = ARRAY_SIZE(rtw_channeltable_5g), 1602774f206SBjoern A. Zeeb 1612774f206SBjoern A. Zeeb /* 5G has no CCK rates */ 1622774f206SBjoern A. Zeeb .bitrates = rtw_ratetable + 4, 1632774f206SBjoern A. Zeeb .n_bitrates = ARRAY_SIZE(rtw_ratetable) - 4, 1642774f206SBjoern A. Zeeb 1652774f206SBjoern A. Zeeb .ht_cap = {0}, 1662774f206SBjoern A. Zeeb .vht_cap = {0}, 1672774f206SBjoern A. Zeeb }; 1682774f206SBjoern A. Zeeb 1692774f206SBjoern A. Zeeb struct rtw_watch_dog_iter_data { 1702774f206SBjoern A. Zeeb struct rtw_dev *rtwdev; 1712774f206SBjoern A. Zeeb struct rtw_vif *rtwvif; 1722774f206SBjoern A. Zeeb }; 1732774f206SBjoern A. Zeeb 1742774f206SBjoern A. Zeeb static void rtw_dynamic_csi_rate(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) 1752774f206SBjoern A. Zeeb { 1762774f206SBjoern A. Zeeb struct rtw_bf_info *bf_info = &rtwdev->bf_info; 1772774f206SBjoern A. Zeeb u8 fix_rate_enable = 0; 1782774f206SBjoern A. Zeeb u8 new_csi_rate_idx; 1792774f206SBjoern A. Zeeb 1802774f206SBjoern A. Zeeb if (rtwvif->bfee.role != RTW_BFEE_SU && 1812774f206SBjoern A. Zeeb rtwvif->bfee.role != RTW_BFEE_MU) 1822774f206SBjoern A. Zeeb return; 1832774f206SBjoern A. Zeeb 1842774f206SBjoern A. Zeeb rtw_chip_cfg_csi_rate(rtwdev, rtwdev->dm_info.min_rssi, 1852774f206SBjoern A. Zeeb bf_info->cur_csi_rpt_rate, 1862774f206SBjoern A. Zeeb fix_rate_enable, &new_csi_rate_idx); 1872774f206SBjoern A. Zeeb 1882774f206SBjoern A. Zeeb if (new_csi_rate_idx != bf_info->cur_csi_rpt_rate) 1892774f206SBjoern A. Zeeb bf_info->cur_csi_rpt_rate = new_csi_rate_idx; 1902774f206SBjoern A. Zeeb } 1912774f206SBjoern A. Zeeb 19290aac0d8SBjoern A. Zeeb static void rtw_vif_watch_dog_iter(void *data, struct ieee80211_vif *vif) 1932774f206SBjoern A. Zeeb { 1942774f206SBjoern A. Zeeb struct rtw_watch_dog_iter_data *iter_data = data; 1952774f206SBjoern A. Zeeb struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 1962774f206SBjoern A. Zeeb 1972774f206SBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION) 19890aac0d8SBjoern A. Zeeb if (vif->cfg.assoc) 1992774f206SBjoern A. Zeeb iter_data->rtwvif = rtwvif; 2002774f206SBjoern A. Zeeb 2012774f206SBjoern A. Zeeb rtw_dynamic_csi_rate(iter_data->rtwdev, rtwvif); 2022774f206SBjoern A. Zeeb 2032774f206SBjoern A. Zeeb rtwvif->stats.tx_unicast = 0; 2042774f206SBjoern A. Zeeb rtwvif->stats.rx_unicast = 0; 2052774f206SBjoern A. Zeeb rtwvif->stats.tx_cnt = 0; 2062774f206SBjoern A. Zeeb rtwvif->stats.rx_cnt = 0; 2072774f206SBjoern A. Zeeb } 2082774f206SBjoern A. Zeeb 2092774f206SBjoern A. Zeeb /* process TX/RX statistics periodically for hardware, 2102774f206SBjoern A. Zeeb * the information helps hardware to enhance performance 2112774f206SBjoern A. Zeeb */ 2122774f206SBjoern A. Zeeb static void rtw_watch_dog_work(struct work_struct *work) 2132774f206SBjoern A. Zeeb { 2142774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, 2152774f206SBjoern A. Zeeb watch_dog_work.work); 2162774f206SBjoern A. Zeeb struct rtw_traffic_stats *stats = &rtwdev->stats; 2172774f206SBjoern A. Zeeb struct rtw_watch_dog_iter_data data = {}; 2182774f206SBjoern A. Zeeb bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); 2192774f206SBjoern A. Zeeb bool ps_active; 2202774f206SBjoern A. Zeeb 2212774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 2222774f206SBjoern A. Zeeb 2232774f206SBjoern A. Zeeb if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) 2242774f206SBjoern A. Zeeb goto unlock; 2252774f206SBjoern A. Zeeb 2262774f206SBjoern A. Zeeb ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work, 2272774f206SBjoern A. Zeeb RTW_WATCH_DOG_DELAY_TIME); 2282774f206SBjoern A. Zeeb 2292774f206SBjoern A. Zeeb if (rtwdev->stats.tx_cnt > 100 || rtwdev->stats.rx_cnt > 100) 2302774f206SBjoern A. Zeeb set_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); 2312774f206SBjoern A. Zeeb else 2322774f206SBjoern A. Zeeb clear_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); 2332774f206SBjoern A. Zeeb 2342774f206SBjoern A. Zeeb if (busy_traffic != test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags)) 2352774f206SBjoern A. Zeeb rtw_coex_wl_status_change_notify(rtwdev, 0); 2362774f206SBjoern A. Zeeb 2372774f206SBjoern A. Zeeb if (stats->tx_cnt > RTW_LPS_THRESHOLD || 2382774f206SBjoern A. Zeeb stats->rx_cnt > RTW_LPS_THRESHOLD) 2392774f206SBjoern A. Zeeb ps_active = true; 2402774f206SBjoern A. Zeeb else 2412774f206SBjoern A. Zeeb ps_active = false; 2422774f206SBjoern A. Zeeb 2432774f206SBjoern A. Zeeb ewma_tp_add(&stats->tx_ewma_tp, 2442774f206SBjoern A. Zeeb (u32)(stats->tx_unicast >> RTW_TP_SHIFT)); 2452774f206SBjoern A. Zeeb ewma_tp_add(&stats->rx_ewma_tp, 2462774f206SBjoern A. Zeeb (u32)(stats->rx_unicast >> RTW_TP_SHIFT)); 2472774f206SBjoern A. Zeeb stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp); 2482774f206SBjoern A. Zeeb stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp); 2492774f206SBjoern A. Zeeb 2502774f206SBjoern A. Zeeb /* reset tx/rx statictics */ 2512774f206SBjoern A. Zeeb stats->tx_unicast = 0; 2522774f206SBjoern A. Zeeb stats->rx_unicast = 0; 2532774f206SBjoern A. Zeeb stats->tx_cnt = 0; 2542774f206SBjoern A. Zeeb stats->rx_cnt = 0; 2552774f206SBjoern A. Zeeb 2562774f206SBjoern A. Zeeb if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) 2572774f206SBjoern A. Zeeb goto unlock; 2582774f206SBjoern A. Zeeb 2592774f206SBjoern A. Zeeb /* make sure BB/RF is working for dynamic mech */ 2602774f206SBjoern A. Zeeb rtw_leave_lps(rtwdev); 261*11c53278SBjoern A. Zeeb rtw_coex_wl_status_check(rtwdev); 262*11c53278SBjoern A. Zeeb rtw_coex_query_bt_hid_list(rtwdev); 2632774f206SBjoern A. Zeeb 2642774f206SBjoern A. Zeeb rtw_phy_dynamic_mechanism(rtwdev); 2652774f206SBjoern A. Zeeb 2662774f206SBjoern A. Zeeb data.rtwdev = rtwdev; 26790aac0d8SBjoern A. Zeeb /* rtw_iterate_vifs internally uses an atomic iterator which is needed 26890aac0d8SBjoern A. Zeeb * to avoid taking local->iflist_mtx mutex 26990aac0d8SBjoern A. Zeeb */ 27090aac0d8SBjoern A. Zeeb rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data); 2712774f206SBjoern A. Zeeb 2722774f206SBjoern A. Zeeb /* fw supports only one station associated to enter lps, if there are 2732774f206SBjoern A. Zeeb * more than two stations associated to the AP, then we can not enter 2742774f206SBjoern A. Zeeb * lps, because fw does not handle the overlapped beacon interval 2752774f206SBjoern A. Zeeb * 27690aac0d8SBjoern A. Zeeb * rtw_recalc_lps() iterate vifs and determine if driver can enter 27790aac0d8SBjoern A. Zeeb * ps by vif->type and vif->cfg.ps, all we need to do here is to 2782774f206SBjoern A. Zeeb * get that vif and check if device is having traffic more than the 2792774f206SBjoern A. Zeeb * threshold. 2802774f206SBjoern A. Zeeb */ 2812774f206SBjoern A. Zeeb if (rtwdev->ps_enabled && data.rtwvif && !ps_active && 28290aac0d8SBjoern A. Zeeb !rtwdev->beacon_loss && !rtwdev->ap_active) 2832774f206SBjoern A. Zeeb rtw_enter_lps(rtwdev, data.rtwvif->port); 2842774f206SBjoern A. Zeeb 2852774f206SBjoern A. Zeeb rtwdev->watch_dog_cnt++; 2862774f206SBjoern A. Zeeb 2872774f206SBjoern A. Zeeb unlock: 2882774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 2892774f206SBjoern A. Zeeb } 2902774f206SBjoern A. Zeeb 2912774f206SBjoern A. Zeeb static void rtw_c2h_work(struct work_struct *work) 2922774f206SBjoern A. Zeeb { 2932774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, c2h_work); 2942774f206SBjoern A. Zeeb struct sk_buff *skb, *tmp; 2952774f206SBjoern A. Zeeb 2962774f206SBjoern A. Zeeb skb_queue_walk_safe(&rtwdev->c2h_queue, skb, tmp) { 2972774f206SBjoern A. Zeeb skb_unlink(skb, &rtwdev->c2h_queue); 2982774f206SBjoern A. Zeeb rtw_fw_c2h_cmd_handle(rtwdev, skb); 2992774f206SBjoern A. Zeeb dev_kfree_skb_any(skb); 3002774f206SBjoern A. Zeeb } 3012774f206SBjoern A. Zeeb } 3022774f206SBjoern A. Zeeb 3039c951734SBjoern A. Zeeb static void rtw_ips_work(struct work_struct *work) 3049c951734SBjoern A. Zeeb { 3059c951734SBjoern A. Zeeb struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, ips_work); 3069c951734SBjoern A. Zeeb 3079c951734SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 3089c951734SBjoern A. Zeeb if (rtwdev->hw->conf.flags & IEEE80211_CONF_IDLE) 3099c951734SBjoern A. Zeeb rtw_enter_ips(rtwdev); 3109c951734SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 3119c951734SBjoern A. Zeeb } 3129c951734SBjoern A. Zeeb 3132774f206SBjoern A. Zeeb static u8 rtw_acquire_macid(struct rtw_dev *rtwdev) 3142774f206SBjoern A. Zeeb { 3152774f206SBjoern A. Zeeb unsigned long mac_id; 3162774f206SBjoern A. Zeeb 3172774f206SBjoern A. Zeeb mac_id = find_first_zero_bit(rtwdev->mac_id_map, RTW_MAX_MAC_ID_NUM); 3182774f206SBjoern A. Zeeb if (mac_id < RTW_MAX_MAC_ID_NUM) 3192774f206SBjoern A. Zeeb set_bit(mac_id, rtwdev->mac_id_map); 3202774f206SBjoern A. Zeeb 3212774f206SBjoern A. Zeeb return mac_id; 3222774f206SBjoern A. Zeeb } 3232774f206SBjoern A. Zeeb 32490aac0d8SBjoern A. Zeeb static void rtw_sta_rc_work(struct work_struct *work) 32590aac0d8SBjoern A. Zeeb { 32690aac0d8SBjoern A. Zeeb struct rtw_sta_info *si = container_of(work, struct rtw_sta_info, 32790aac0d8SBjoern A. Zeeb rc_work); 32890aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = si->rtwdev; 32990aac0d8SBjoern A. Zeeb 33090aac0d8SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 33190aac0d8SBjoern A. Zeeb rtw_update_sta_info(rtwdev, si, true); 33290aac0d8SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 33390aac0d8SBjoern A. Zeeb } 33490aac0d8SBjoern A. Zeeb 3352774f206SBjoern A. Zeeb int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, 3362774f206SBjoern A. Zeeb struct ieee80211_vif *vif) 3372774f206SBjoern A. Zeeb { 3382774f206SBjoern A. Zeeb struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; 33990aac0d8SBjoern A. Zeeb struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 3402774f206SBjoern A. Zeeb int i; 3412774f206SBjoern A. Zeeb 3422774f206SBjoern A. Zeeb si->mac_id = rtw_acquire_macid(rtwdev); 3432774f206SBjoern A. Zeeb if (si->mac_id >= RTW_MAX_MAC_ID_NUM) 3442774f206SBjoern A. Zeeb return -ENOSPC; 3452774f206SBjoern A. Zeeb 34690aac0d8SBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc == 0) 34790aac0d8SBjoern A. Zeeb rtwvif->mac_id = si->mac_id; 34890aac0d8SBjoern A. Zeeb si->rtwdev = rtwdev; 3492774f206SBjoern A. Zeeb si->sta = sta; 3502774f206SBjoern A. Zeeb si->vif = vif; 3512774f206SBjoern A. Zeeb si->init_ra_lv = 1; 3522774f206SBjoern A. Zeeb ewma_rssi_init(&si->avg_rssi); 3532774f206SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(sta->txq); i++) 3542774f206SBjoern A. Zeeb rtw_txq_init(rtwdev, sta->txq[i]); 35590aac0d8SBjoern A. Zeeb INIT_WORK(&si->rc_work, rtw_sta_rc_work); 3562774f206SBjoern A. Zeeb 3579c951734SBjoern A. Zeeb rtw_update_sta_info(rtwdev, si, true); 3582774f206SBjoern A. Zeeb rtw_fw_media_status_report(rtwdev, si->mac_id, true); 3592774f206SBjoern A. Zeeb 3602774f206SBjoern A. Zeeb rtwdev->sta_cnt++; 3612774f206SBjoern A. Zeeb rtwdev->beacon_loss = false; 3622774f206SBjoern A. Zeeb #if defined(__linux__) 3639c951734SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "sta %pM joined with macid %d\n", 3642774f206SBjoern A. Zeeb sta->addr, si->mac_id); 3652774f206SBjoern A. Zeeb #elif defined(__FreeBSD__) 3669c951734SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "sta %6D joined with macid %d\n", 3672774f206SBjoern A. Zeeb sta->addr, ":", si->mac_id); 3682774f206SBjoern A. Zeeb #endif 3692774f206SBjoern A. Zeeb 3702774f206SBjoern A. Zeeb return 0; 3712774f206SBjoern A. Zeeb } 3722774f206SBjoern A. Zeeb 3732774f206SBjoern A. Zeeb void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, 3742774f206SBjoern A. Zeeb bool fw_exist) 3752774f206SBjoern A. Zeeb { 3762774f206SBjoern A. Zeeb struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; 3772774f206SBjoern A. Zeeb int i; 3782774f206SBjoern A. Zeeb 37990aac0d8SBjoern A. Zeeb cancel_work_sync(&si->rc_work); 38090aac0d8SBjoern A. Zeeb 3812774f206SBjoern A. Zeeb rtw_release_macid(rtwdev, si->mac_id); 3822774f206SBjoern A. Zeeb if (fw_exist) 3832774f206SBjoern A. Zeeb rtw_fw_media_status_report(rtwdev, si->mac_id, false); 3842774f206SBjoern A. Zeeb 3852774f206SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(sta->txq); i++) 3862774f206SBjoern A. Zeeb rtw_txq_cleanup(rtwdev, sta->txq[i]); 3872774f206SBjoern A. Zeeb 3882774f206SBjoern A. Zeeb kfree(si->mask); 3892774f206SBjoern A. Zeeb 3902774f206SBjoern A. Zeeb rtwdev->sta_cnt--; 3912774f206SBjoern A. Zeeb #if defined(__linux__) 3929c951734SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "sta %pM with macid %d left\n", 3932774f206SBjoern A. Zeeb sta->addr, si->mac_id); 3942774f206SBjoern A. Zeeb #elif defined(__FreeBSD__) 3959c951734SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "sta %6D with macid %d left\n", 3962774f206SBjoern A. Zeeb sta->addr, ":", si->mac_id); 3972774f206SBjoern A. Zeeb #endif 3982774f206SBjoern A. Zeeb } 3992774f206SBjoern A. Zeeb 4002774f206SBjoern A. Zeeb struct rtw_fwcd_hdr { 4012774f206SBjoern A. Zeeb u32 item; 4022774f206SBjoern A. Zeeb u32 size; 4032774f206SBjoern A. Zeeb u32 padding1; 4042774f206SBjoern A. Zeeb u32 padding2; 4052774f206SBjoern A. Zeeb } __packed; 4062774f206SBjoern A. Zeeb 4072774f206SBjoern A. Zeeb static int rtw_fwcd_prep(struct rtw_dev *rtwdev) 4082774f206SBjoern A. Zeeb { 40990aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 4102774f206SBjoern A. Zeeb struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; 4112774f206SBjoern A. Zeeb const struct rtw_fwcd_segs *segs = chip->fwcd_segs; 4122774f206SBjoern A. Zeeb u32 prep_size = chip->fw_rxff_size + sizeof(struct rtw_fwcd_hdr); 4132774f206SBjoern A. Zeeb u8 i; 4142774f206SBjoern A. Zeeb 4152774f206SBjoern A. Zeeb if (segs) { 4162774f206SBjoern A. Zeeb prep_size += segs->num * sizeof(struct rtw_fwcd_hdr); 4172774f206SBjoern A. Zeeb 4182774f206SBjoern A. Zeeb for (i = 0; i < segs->num; i++) 4192774f206SBjoern A. Zeeb prep_size += segs->segs[i]; 4202774f206SBjoern A. Zeeb } 4212774f206SBjoern A. Zeeb 4222774f206SBjoern A. Zeeb desc->data = vmalloc(prep_size); 4232774f206SBjoern A. Zeeb if (!desc->data) 4242774f206SBjoern A. Zeeb return -ENOMEM; 4252774f206SBjoern A. Zeeb 4262774f206SBjoern A. Zeeb desc->size = prep_size; 4272774f206SBjoern A. Zeeb desc->next = desc->data; 4282774f206SBjoern A. Zeeb 4292774f206SBjoern A. Zeeb return 0; 4302774f206SBjoern A. Zeeb } 4312774f206SBjoern A. Zeeb 4322774f206SBjoern A. Zeeb static u8 *rtw_fwcd_next(struct rtw_dev *rtwdev, u32 item, u32 size) 4332774f206SBjoern A. Zeeb { 4342774f206SBjoern A. Zeeb struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; 4352774f206SBjoern A. Zeeb struct rtw_fwcd_hdr *hdr; 4362774f206SBjoern A. Zeeb u8 *next; 4372774f206SBjoern A. Zeeb 4382774f206SBjoern A. Zeeb if (!desc->data) { 4392774f206SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_FW, "fwcd isn't prepared successfully\n"); 4402774f206SBjoern A. Zeeb return NULL; 4412774f206SBjoern A. Zeeb } 4422774f206SBjoern A. Zeeb 4432774f206SBjoern A. Zeeb next = desc->next + sizeof(struct rtw_fwcd_hdr); 4442774f206SBjoern A. Zeeb if (next - desc->data + size > desc->size) { 4452774f206SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_FW, "fwcd isn't prepared enough\n"); 4462774f206SBjoern A. Zeeb return NULL; 4472774f206SBjoern A. Zeeb } 4482774f206SBjoern A. Zeeb 4492774f206SBjoern A. Zeeb hdr = (struct rtw_fwcd_hdr *)(desc->next); 4502774f206SBjoern A. Zeeb hdr->item = item; 4512774f206SBjoern A. Zeeb hdr->size = size; 4522774f206SBjoern A. Zeeb hdr->padding1 = 0x01234567; 4532774f206SBjoern A. Zeeb hdr->padding2 = 0x89abcdef; 4542774f206SBjoern A. Zeeb desc->next = next + size; 4552774f206SBjoern A. Zeeb 4562774f206SBjoern A. Zeeb return next; 4572774f206SBjoern A. Zeeb } 4582774f206SBjoern A. Zeeb 4592774f206SBjoern A. Zeeb static void rtw_fwcd_dump(struct rtw_dev *rtwdev) 4602774f206SBjoern A. Zeeb { 4612774f206SBjoern A. Zeeb struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; 4622774f206SBjoern A. Zeeb 4632774f206SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_FW, "dump fwcd\n"); 4642774f206SBjoern A. Zeeb 4652774f206SBjoern A. Zeeb /* Data will be freed after lifetime of device coredump. After calling 4662774f206SBjoern A. Zeeb * dev_coredump, data is supposed to be handled by the device coredump 4672774f206SBjoern A. Zeeb * framework. Note that a new dump will be discarded if a previous one 4682774f206SBjoern A. Zeeb * hasn't been released yet. 4692774f206SBjoern A. Zeeb */ 4702774f206SBjoern A. Zeeb dev_coredumpv(rtwdev->dev, desc->data, desc->size, GFP_KERNEL); 4712774f206SBjoern A. Zeeb } 4722774f206SBjoern A. Zeeb 4732774f206SBjoern A. Zeeb static void rtw_fwcd_free(struct rtw_dev *rtwdev, bool free_self) 4742774f206SBjoern A. Zeeb { 4752774f206SBjoern A. Zeeb struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; 4762774f206SBjoern A. Zeeb 4772774f206SBjoern A. Zeeb if (free_self) { 4782774f206SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_FW, "free fwcd by self\n"); 4792774f206SBjoern A. Zeeb vfree(desc->data); 4802774f206SBjoern A. Zeeb } 4812774f206SBjoern A. Zeeb 4822774f206SBjoern A. Zeeb desc->data = NULL; 4832774f206SBjoern A. Zeeb desc->next = NULL; 4842774f206SBjoern A. Zeeb } 4852774f206SBjoern A. Zeeb 4862774f206SBjoern A. Zeeb static int rtw_fw_dump_crash_log(struct rtw_dev *rtwdev) 4872774f206SBjoern A. Zeeb { 4882774f206SBjoern A. Zeeb u32 size = rtwdev->chip->fw_rxff_size; 4892774f206SBjoern A. Zeeb u32 *buf; 4902774f206SBjoern A. Zeeb u8 seq; 4912774f206SBjoern A. Zeeb 4922774f206SBjoern A. Zeeb buf = (u32 *)rtw_fwcd_next(rtwdev, RTW_FWCD_TLV, size); 4932774f206SBjoern A. Zeeb if (!buf) 4942774f206SBjoern A. Zeeb return -ENOMEM; 4952774f206SBjoern A. Zeeb 4962774f206SBjoern A. Zeeb if (rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0, size, buf)) { 4972774f206SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_FW, "dump fw fifo fail\n"); 4982774f206SBjoern A. Zeeb return -EINVAL; 4992774f206SBjoern A. Zeeb } 5002774f206SBjoern A. Zeeb 5012774f206SBjoern A. Zeeb if (GET_FW_DUMP_LEN(buf) == 0) { 5022774f206SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_FW, "fw crash dump's length is 0\n"); 5032774f206SBjoern A. Zeeb return -EINVAL; 5042774f206SBjoern A. Zeeb } 5052774f206SBjoern A. Zeeb 5062774f206SBjoern A. Zeeb seq = GET_FW_DUMP_SEQ(buf); 5072774f206SBjoern A. Zeeb if (seq > 0) { 5082774f206SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_FW, 5092774f206SBjoern A. Zeeb "fw crash dump's seq is wrong: %d\n", seq); 5102774f206SBjoern A. Zeeb return -EINVAL; 5112774f206SBjoern A. Zeeb } 5122774f206SBjoern A. Zeeb 5132774f206SBjoern A. Zeeb return 0; 5142774f206SBjoern A. Zeeb } 5152774f206SBjoern A. Zeeb 5162774f206SBjoern A. Zeeb int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, 5172774f206SBjoern A. Zeeb u32 fwcd_item) 5182774f206SBjoern A. Zeeb { 5192774f206SBjoern A. Zeeb u32 rxff = rtwdev->chip->fw_rxff_size; 5202774f206SBjoern A. Zeeb u32 dump_size, done_size = 0; 5212774f206SBjoern A. Zeeb u8 *buf; 5222774f206SBjoern A. Zeeb int ret; 5232774f206SBjoern A. Zeeb 5242774f206SBjoern A. Zeeb buf = rtw_fwcd_next(rtwdev, fwcd_item, size); 5252774f206SBjoern A. Zeeb if (!buf) 5262774f206SBjoern A. Zeeb return -ENOMEM; 5272774f206SBjoern A. Zeeb 5282774f206SBjoern A. Zeeb while (size) { 5292774f206SBjoern A. Zeeb dump_size = size > rxff ? rxff : size; 5302774f206SBjoern A. Zeeb 5312774f206SBjoern A. Zeeb ret = rtw_ddma_to_fw_fifo(rtwdev, ocp_src + done_size, 5322774f206SBjoern A. Zeeb dump_size); 5332774f206SBjoern A. Zeeb if (ret) { 5342774f206SBjoern A. Zeeb rtw_err(rtwdev, 5352774f206SBjoern A. Zeeb "ddma fw 0x%x [+0x%x] to fw fifo fail\n", 5362774f206SBjoern A. Zeeb ocp_src, done_size); 5372774f206SBjoern A. Zeeb return ret; 5382774f206SBjoern A. Zeeb } 5392774f206SBjoern A. Zeeb 5402774f206SBjoern A. Zeeb ret = rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0, 5412774f206SBjoern A. Zeeb dump_size, (u32 *)(buf + done_size)); 5422774f206SBjoern A. Zeeb if (ret) { 5432774f206SBjoern A. Zeeb rtw_err(rtwdev, 5442774f206SBjoern A. Zeeb "dump fw 0x%x [+0x%x] from fw fifo fail\n", 5452774f206SBjoern A. Zeeb ocp_src, done_size); 5462774f206SBjoern A. Zeeb return ret; 5472774f206SBjoern A. Zeeb } 5482774f206SBjoern A. Zeeb 5492774f206SBjoern A. Zeeb size -= dump_size; 5502774f206SBjoern A. Zeeb done_size += dump_size; 5512774f206SBjoern A. Zeeb } 5522774f206SBjoern A. Zeeb 5532774f206SBjoern A. Zeeb return 0; 5542774f206SBjoern A. Zeeb } 5552774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_dump_fw); 5562774f206SBjoern A. Zeeb 5572774f206SBjoern A. Zeeb int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size) 5582774f206SBjoern A. Zeeb { 5592774f206SBjoern A. Zeeb u8 *buf; 5602774f206SBjoern A. Zeeb u32 i; 5612774f206SBjoern A. Zeeb 5622774f206SBjoern A. Zeeb if (addr & 0x3) { 5632774f206SBjoern A. Zeeb WARN(1, "should be 4-byte aligned, addr = 0x%08x\n", addr); 5642774f206SBjoern A. Zeeb return -EINVAL; 5652774f206SBjoern A. Zeeb } 5662774f206SBjoern A. Zeeb 5672774f206SBjoern A. Zeeb buf = rtw_fwcd_next(rtwdev, RTW_FWCD_REG, size); 5682774f206SBjoern A. Zeeb if (!buf) 5692774f206SBjoern A. Zeeb return -ENOMEM; 5702774f206SBjoern A. Zeeb 5712774f206SBjoern A. Zeeb for (i = 0; i < size; i += 4) 5722774f206SBjoern A. Zeeb *(u32 *)(buf + i) = rtw_read32(rtwdev, addr + i); 5732774f206SBjoern A. Zeeb 5742774f206SBjoern A. Zeeb return 0; 5752774f206SBjoern A. Zeeb } 5762774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_dump_reg); 5772774f206SBjoern A. Zeeb 5782774f206SBjoern A. Zeeb void rtw_vif_assoc_changed(struct rtw_vif *rtwvif, 5792774f206SBjoern A. Zeeb struct ieee80211_bss_conf *conf) 5802774f206SBjoern A. Zeeb { 58190aac0d8SBjoern A. Zeeb struct ieee80211_vif *vif = NULL; 58290aac0d8SBjoern A. Zeeb 58390aac0d8SBjoern A. Zeeb if (conf) 58490aac0d8SBjoern A. Zeeb vif = container_of(conf, struct ieee80211_vif, bss_conf); 58590aac0d8SBjoern A. Zeeb 58690aac0d8SBjoern A. Zeeb if (conf && vif->cfg.assoc) { 58790aac0d8SBjoern A. Zeeb rtwvif->aid = vif->cfg.aid; 5882774f206SBjoern A. Zeeb rtwvif->net_type = RTW_NET_MGD_LINKED; 5892774f206SBjoern A. Zeeb } else { 5902774f206SBjoern A. Zeeb rtwvif->aid = 0; 5912774f206SBjoern A. Zeeb rtwvif->net_type = RTW_NET_NO_LINK; 5922774f206SBjoern A. Zeeb } 5932774f206SBjoern A. Zeeb } 5942774f206SBjoern A. Zeeb 5952774f206SBjoern A. Zeeb static void rtw_reset_key_iter(struct ieee80211_hw *hw, 5962774f206SBjoern A. Zeeb struct ieee80211_vif *vif, 5972774f206SBjoern A. Zeeb struct ieee80211_sta *sta, 5982774f206SBjoern A. Zeeb struct ieee80211_key_conf *key, 5992774f206SBjoern A. Zeeb void *data) 6002774f206SBjoern A. Zeeb { 6012774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = (struct rtw_dev *)data; 6022774f206SBjoern A. Zeeb struct rtw_sec_desc *sec = &rtwdev->sec; 6032774f206SBjoern A. Zeeb 6042774f206SBjoern A. Zeeb rtw_sec_clear_cam(rtwdev, sec, key->hw_key_idx); 6052774f206SBjoern A. Zeeb } 6062774f206SBjoern A. Zeeb 6072774f206SBjoern A. Zeeb static void rtw_reset_sta_iter(void *data, struct ieee80211_sta *sta) 6082774f206SBjoern A. Zeeb { 6092774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = (struct rtw_dev *)data; 6102774f206SBjoern A. Zeeb 6112774f206SBjoern A. Zeeb if (rtwdev->sta_cnt == 0) { 6122774f206SBjoern A. Zeeb rtw_warn(rtwdev, "sta count before reset should not be 0\n"); 6132774f206SBjoern A. Zeeb return; 6142774f206SBjoern A. Zeeb } 6152774f206SBjoern A. Zeeb rtw_sta_remove(rtwdev, sta, false); 6162774f206SBjoern A. Zeeb } 6172774f206SBjoern A. Zeeb 6182774f206SBjoern A. Zeeb static void rtw_reset_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) 6192774f206SBjoern A. Zeeb { 6202774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = (struct rtw_dev *)data; 6212774f206SBjoern A. Zeeb struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 6222774f206SBjoern A. Zeeb 6232774f206SBjoern A. Zeeb rtw_bf_disassoc(rtwdev, vif, NULL); 6242774f206SBjoern A. Zeeb rtw_vif_assoc_changed(rtwvif, NULL); 6252774f206SBjoern A. Zeeb rtw_txq_cleanup(rtwdev, vif->txq); 6262774f206SBjoern A. Zeeb } 6272774f206SBjoern A. Zeeb 6282774f206SBjoern A. Zeeb void rtw_fw_recovery(struct rtw_dev *rtwdev) 6292774f206SBjoern A. Zeeb { 6302774f206SBjoern A. Zeeb if (!test_bit(RTW_FLAG_RESTARTING, rtwdev->flags)) 6312774f206SBjoern A. Zeeb ieee80211_queue_work(rtwdev->hw, &rtwdev->fw_recovery_work); 6322774f206SBjoern A. Zeeb } 6332774f206SBjoern A. Zeeb 6342774f206SBjoern A. Zeeb static void __fw_recovery_work(struct rtw_dev *rtwdev) 6352774f206SBjoern A. Zeeb { 6362774f206SBjoern A. Zeeb int ret = 0; 6372774f206SBjoern A. Zeeb 6382774f206SBjoern A. Zeeb set_bit(RTW_FLAG_RESTARTING, rtwdev->flags); 6392774f206SBjoern A. Zeeb clear_bit(RTW_FLAG_RESTART_TRIGGERING, rtwdev->flags); 6402774f206SBjoern A. Zeeb 6412774f206SBjoern A. Zeeb ret = rtw_fwcd_prep(rtwdev); 6422774f206SBjoern A. Zeeb if (ret) 6432774f206SBjoern A. Zeeb goto free; 6442774f206SBjoern A. Zeeb ret = rtw_fw_dump_crash_log(rtwdev); 6452774f206SBjoern A. Zeeb if (ret) 6462774f206SBjoern A. Zeeb goto free; 6472774f206SBjoern A. Zeeb ret = rtw_chip_dump_fw_crash(rtwdev); 6482774f206SBjoern A. Zeeb if (ret) 6492774f206SBjoern A. Zeeb goto free; 6502774f206SBjoern A. Zeeb 6512774f206SBjoern A. Zeeb rtw_fwcd_dump(rtwdev); 6522774f206SBjoern A. Zeeb free: 6532774f206SBjoern A. Zeeb rtw_fwcd_free(rtwdev, !!ret); 6542774f206SBjoern A. Zeeb rtw_write8(rtwdev, REG_MCU_TST_CFG, 0); 6552774f206SBjoern A. Zeeb 6562774f206SBjoern A. Zeeb WARN(1, "firmware crash, start reset and recover\n"); 6572774f206SBjoern A. Zeeb 6582774f206SBjoern A. Zeeb rcu_read_lock(); 6592774f206SBjoern A. Zeeb rtw_iterate_keys_rcu(rtwdev, NULL, rtw_reset_key_iter, rtwdev); 6602774f206SBjoern A. Zeeb rcu_read_unlock(); 6612774f206SBjoern A. Zeeb rtw_iterate_stas_atomic(rtwdev, rtw_reset_sta_iter, rtwdev); 6622774f206SBjoern A. Zeeb rtw_iterate_vifs_atomic(rtwdev, rtw_reset_vif_iter, rtwdev); 66390aac0d8SBjoern A. Zeeb bitmap_zero(rtwdev->hw_port, RTW_PORT_NUM); 6642774f206SBjoern A. Zeeb rtw_enter_ips(rtwdev); 6652774f206SBjoern A. Zeeb } 6662774f206SBjoern A. Zeeb 6672774f206SBjoern A. Zeeb static void rtw_fw_recovery_work(struct work_struct *work) 6682774f206SBjoern A. Zeeb { 6692774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, 6702774f206SBjoern A. Zeeb fw_recovery_work); 6712774f206SBjoern A. Zeeb 6722774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 6732774f206SBjoern A. Zeeb __fw_recovery_work(rtwdev); 6742774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 6752774f206SBjoern A. Zeeb 6762774f206SBjoern A. Zeeb ieee80211_restart_hw(rtwdev->hw); 6772774f206SBjoern A. Zeeb } 6782774f206SBjoern A. Zeeb 6792774f206SBjoern A. Zeeb struct rtw_txq_ba_iter_data { 6802774f206SBjoern A. Zeeb }; 6812774f206SBjoern A. Zeeb 6822774f206SBjoern A. Zeeb static void rtw_txq_ba_iter(void *data, struct ieee80211_sta *sta) 6832774f206SBjoern A. Zeeb { 6842774f206SBjoern A. Zeeb struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; 6852774f206SBjoern A. Zeeb int ret; 6862774f206SBjoern A. Zeeb u8 tid; 6872774f206SBjoern A. Zeeb 6882774f206SBjoern A. Zeeb tid = find_first_bit(si->tid_ba, IEEE80211_NUM_TIDS); 6892774f206SBjoern A. Zeeb while (tid != IEEE80211_NUM_TIDS) { 6902774f206SBjoern A. Zeeb clear_bit(tid, si->tid_ba); 6912774f206SBjoern A. Zeeb ret = ieee80211_start_tx_ba_session(sta, tid, 0); 6922774f206SBjoern A. Zeeb if (ret == -EINVAL) { 6932774f206SBjoern A. Zeeb struct ieee80211_txq *txq; 6942774f206SBjoern A. Zeeb struct rtw_txq *rtwtxq; 6952774f206SBjoern A. Zeeb 6962774f206SBjoern A. Zeeb txq = sta->txq[tid]; 6972774f206SBjoern A. Zeeb rtwtxq = (struct rtw_txq *)txq->drv_priv; 6982774f206SBjoern A. Zeeb set_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags); 6992774f206SBjoern A. Zeeb } 7002774f206SBjoern A. Zeeb 7012774f206SBjoern A. Zeeb tid = find_first_bit(si->tid_ba, IEEE80211_NUM_TIDS); 7022774f206SBjoern A. Zeeb } 7032774f206SBjoern A. Zeeb } 7042774f206SBjoern A. Zeeb 7052774f206SBjoern A. Zeeb static void rtw_txq_ba_work(struct work_struct *work) 7062774f206SBjoern A. Zeeb { 7072774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, ba_work); 7082774f206SBjoern A. Zeeb struct rtw_txq_ba_iter_data data; 7092774f206SBjoern A. Zeeb 7102774f206SBjoern A. Zeeb rtw_iterate_stas_atomic(rtwdev, rtw_txq_ba_iter, &data); 7112774f206SBjoern A. Zeeb } 7122774f206SBjoern A. Zeeb 7132774f206SBjoern A. Zeeb void rtw_set_rx_freq_band(struct rtw_rx_pkt_stat *pkt_stat, u8 channel) 7142774f206SBjoern A. Zeeb { 7152774f206SBjoern A. Zeeb if (IS_CH_2G_BAND(channel)) 7162774f206SBjoern A. Zeeb pkt_stat->band = NL80211_BAND_2GHZ; 7172774f206SBjoern A. Zeeb else if (IS_CH_5G_BAND(channel)) 7182774f206SBjoern A. Zeeb pkt_stat->band = NL80211_BAND_5GHZ; 7192774f206SBjoern A. Zeeb else 7202774f206SBjoern A. Zeeb return; 7212774f206SBjoern A. Zeeb 7222774f206SBjoern A. Zeeb pkt_stat->freq = ieee80211_channel_to_frequency(channel, pkt_stat->band); 7232774f206SBjoern A. Zeeb } 7242774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_set_rx_freq_band); 7252774f206SBjoern A. Zeeb 7269c951734SBjoern A. Zeeb void rtw_set_dtim_period(struct rtw_dev *rtwdev, int dtim_period) 7279c951734SBjoern A. Zeeb { 7289c951734SBjoern A. Zeeb rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_TIMIE); 7299c951734SBjoern A. Zeeb rtw_write8(rtwdev, REG_DTIM_COUNTER_ROOT, dtim_period - 1); 7309c951734SBjoern A. Zeeb } 7319c951734SBjoern A. Zeeb 73290aac0d8SBjoern A. Zeeb void rtw_update_channel(struct rtw_dev *rtwdev, u8 center_channel, 73390aac0d8SBjoern A. Zeeb u8 primary_channel, enum rtw_supported_band band, 73490aac0d8SBjoern A. Zeeb enum rtw_bandwidth bandwidth) 73590aac0d8SBjoern A. Zeeb { 73690aac0d8SBjoern A. Zeeb enum nl80211_band nl_band = rtw_hw_to_nl80211_band(band); 73790aac0d8SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 73890aac0d8SBjoern A. Zeeb u8 *cch_by_bw = hal->cch_by_bw; 73990aac0d8SBjoern A. Zeeb u32 center_freq, primary_freq; 74090aac0d8SBjoern A. Zeeb enum rtw_sar_bands sar_band; 74190aac0d8SBjoern A. Zeeb u8 primary_channel_idx; 74290aac0d8SBjoern A. Zeeb 74390aac0d8SBjoern A. Zeeb center_freq = ieee80211_channel_to_frequency(center_channel, nl_band); 74490aac0d8SBjoern A. Zeeb primary_freq = ieee80211_channel_to_frequency(primary_channel, nl_band); 74590aac0d8SBjoern A. Zeeb 74690aac0d8SBjoern A. Zeeb /* assign the center channel used while 20M bw is selected */ 74790aac0d8SBjoern A. Zeeb cch_by_bw[RTW_CHANNEL_WIDTH_20] = primary_channel; 74890aac0d8SBjoern A. Zeeb 74990aac0d8SBjoern A. Zeeb /* assign the center channel used while current bw is selected */ 75090aac0d8SBjoern A. Zeeb cch_by_bw[bandwidth] = center_channel; 75190aac0d8SBjoern A. Zeeb 75290aac0d8SBjoern A. Zeeb switch (bandwidth) { 75390aac0d8SBjoern A. Zeeb case RTW_CHANNEL_WIDTH_20: 75490aac0d8SBjoern A. Zeeb default: 75590aac0d8SBjoern A. Zeeb primary_channel_idx = RTW_SC_DONT_CARE; 75690aac0d8SBjoern A. Zeeb break; 75790aac0d8SBjoern A. Zeeb case RTW_CHANNEL_WIDTH_40: 75890aac0d8SBjoern A. Zeeb if (primary_freq > center_freq) 75990aac0d8SBjoern A. Zeeb primary_channel_idx = RTW_SC_20_UPPER; 76090aac0d8SBjoern A. Zeeb else 76190aac0d8SBjoern A. Zeeb primary_channel_idx = RTW_SC_20_LOWER; 76290aac0d8SBjoern A. Zeeb break; 76390aac0d8SBjoern A. Zeeb case RTW_CHANNEL_WIDTH_80: 76490aac0d8SBjoern A. Zeeb if (primary_freq > center_freq) { 76590aac0d8SBjoern A. Zeeb if (primary_freq - center_freq == 10) 76690aac0d8SBjoern A. Zeeb primary_channel_idx = RTW_SC_20_UPPER; 76790aac0d8SBjoern A. Zeeb else 76890aac0d8SBjoern A. Zeeb primary_channel_idx = RTW_SC_20_UPMOST; 76990aac0d8SBjoern A. Zeeb 77090aac0d8SBjoern A. Zeeb /* assign the center channel used 77190aac0d8SBjoern A. Zeeb * while 40M bw is selected 77290aac0d8SBjoern A. Zeeb */ 77390aac0d8SBjoern A. Zeeb cch_by_bw[RTW_CHANNEL_WIDTH_40] = center_channel + 4; 77490aac0d8SBjoern A. Zeeb } else { 77590aac0d8SBjoern A. Zeeb if (center_freq - primary_freq == 10) 77690aac0d8SBjoern A. Zeeb primary_channel_idx = RTW_SC_20_LOWER; 77790aac0d8SBjoern A. Zeeb else 77890aac0d8SBjoern A. Zeeb primary_channel_idx = RTW_SC_20_LOWEST; 77990aac0d8SBjoern A. Zeeb 78090aac0d8SBjoern A. Zeeb /* assign the center channel used 78190aac0d8SBjoern A. Zeeb * while 40M bw is selected 78290aac0d8SBjoern A. Zeeb */ 78390aac0d8SBjoern A. Zeeb cch_by_bw[RTW_CHANNEL_WIDTH_40] = center_channel - 4; 78490aac0d8SBjoern A. Zeeb } 78590aac0d8SBjoern A. Zeeb break; 78690aac0d8SBjoern A. Zeeb } 78790aac0d8SBjoern A. Zeeb 78890aac0d8SBjoern A. Zeeb switch (center_channel) { 78990aac0d8SBjoern A. Zeeb case 1 ... 14: 79090aac0d8SBjoern A. Zeeb sar_band = RTW_SAR_BAND_0; 79190aac0d8SBjoern A. Zeeb break; 79290aac0d8SBjoern A. Zeeb case 36 ... 64: 79390aac0d8SBjoern A. Zeeb sar_band = RTW_SAR_BAND_1; 79490aac0d8SBjoern A. Zeeb break; 79590aac0d8SBjoern A. Zeeb case 100 ... 144: 79690aac0d8SBjoern A. Zeeb sar_band = RTW_SAR_BAND_3; 79790aac0d8SBjoern A. Zeeb break; 79890aac0d8SBjoern A. Zeeb case 149 ... 177: 79990aac0d8SBjoern A. Zeeb sar_band = RTW_SAR_BAND_4; 80090aac0d8SBjoern A. Zeeb break; 80190aac0d8SBjoern A. Zeeb default: 80290aac0d8SBjoern A. Zeeb WARN(1, "unknown ch(%u) to SAR band\n", center_channel); 80390aac0d8SBjoern A. Zeeb sar_band = RTW_SAR_BAND_0; 80490aac0d8SBjoern A. Zeeb break; 80590aac0d8SBjoern A. Zeeb } 80690aac0d8SBjoern A. Zeeb 80790aac0d8SBjoern A. Zeeb hal->current_primary_channel_index = primary_channel_idx; 80890aac0d8SBjoern A. Zeeb hal->current_band_width = bandwidth; 80990aac0d8SBjoern A. Zeeb hal->primary_channel = primary_channel; 81090aac0d8SBjoern A. Zeeb hal->current_channel = center_channel; 81190aac0d8SBjoern A. Zeeb hal->current_band_type = band; 81290aac0d8SBjoern A. Zeeb hal->sar_band = sar_band; 81390aac0d8SBjoern A. Zeeb } 81490aac0d8SBjoern A. Zeeb 8152774f206SBjoern A. Zeeb void rtw_get_channel_params(struct cfg80211_chan_def *chandef, 8162774f206SBjoern A. Zeeb struct rtw_channel_params *chan_params) 8172774f206SBjoern A. Zeeb { 8182774f206SBjoern A. Zeeb struct ieee80211_channel *channel = chandef->chan; 8192774f206SBjoern A. Zeeb enum nl80211_chan_width width = chandef->width; 8202774f206SBjoern A. Zeeb u32 primary_freq, center_freq; 8212774f206SBjoern A. Zeeb u8 center_chan; 8222774f206SBjoern A. Zeeb u8 bandwidth = RTW_CHANNEL_WIDTH_20; 8232774f206SBjoern A. Zeeb 8242774f206SBjoern A. Zeeb center_chan = channel->hw_value; 8252774f206SBjoern A. Zeeb primary_freq = channel->center_freq; 8262774f206SBjoern A. Zeeb center_freq = chandef->center_freq1; 8272774f206SBjoern A. Zeeb 8282774f206SBjoern A. Zeeb switch (width) { 8292774f206SBjoern A. Zeeb case NL80211_CHAN_WIDTH_20_NOHT: 8302774f206SBjoern A. Zeeb case NL80211_CHAN_WIDTH_20: 8312774f206SBjoern A. Zeeb bandwidth = RTW_CHANNEL_WIDTH_20; 8322774f206SBjoern A. Zeeb break; 8332774f206SBjoern A. Zeeb case NL80211_CHAN_WIDTH_40: 8342774f206SBjoern A. Zeeb bandwidth = RTW_CHANNEL_WIDTH_40; 83590aac0d8SBjoern A. Zeeb if (primary_freq > center_freq) 8362774f206SBjoern A. Zeeb center_chan -= 2; 83790aac0d8SBjoern A. Zeeb else 8382774f206SBjoern A. Zeeb center_chan += 2; 8392774f206SBjoern A. Zeeb break; 8402774f206SBjoern A. Zeeb case NL80211_CHAN_WIDTH_80: 8412774f206SBjoern A. Zeeb bandwidth = RTW_CHANNEL_WIDTH_80; 8422774f206SBjoern A. Zeeb if (primary_freq > center_freq) { 84390aac0d8SBjoern A. Zeeb if (primary_freq - center_freq == 10) 8442774f206SBjoern A. Zeeb center_chan -= 2; 84590aac0d8SBjoern A. Zeeb else 8462774f206SBjoern A. Zeeb center_chan -= 6; 8472774f206SBjoern A. Zeeb } else { 84890aac0d8SBjoern A. Zeeb if (center_freq - primary_freq == 10) 8492774f206SBjoern A. Zeeb center_chan += 2; 85090aac0d8SBjoern A. Zeeb else 8512774f206SBjoern A. Zeeb center_chan += 6; 8522774f206SBjoern A. Zeeb } 8532774f206SBjoern A. Zeeb break; 8542774f206SBjoern A. Zeeb default: 8552774f206SBjoern A. Zeeb center_chan = 0; 8562774f206SBjoern A. Zeeb break; 8572774f206SBjoern A. Zeeb } 8582774f206SBjoern A. Zeeb 8592774f206SBjoern A. Zeeb chan_params->center_chan = center_chan; 8602774f206SBjoern A. Zeeb chan_params->bandwidth = bandwidth; 86190aac0d8SBjoern A. Zeeb chan_params->primary_chan = channel->hw_value; 8622774f206SBjoern A. Zeeb } 8632774f206SBjoern A. Zeeb 8642774f206SBjoern A. Zeeb void rtw_set_channel(struct rtw_dev *rtwdev) 8652774f206SBjoern A. Zeeb { 86690aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 8672774f206SBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw; 8682774f206SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 8692774f206SBjoern A. Zeeb struct rtw_channel_params ch_param; 87090aac0d8SBjoern A. Zeeb u8 center_chan, primary_chan, bandwidth, band; 8712774f206SBjoern A. Zeeb 8722774f206SBjoern A. Zeeb rtw_get_channel_params(&hw->conf.chandef, &ch_param); 8732774f206SBjoern A. Zeeb if (WARN(ch_param.center_chan == 0, "Invalid channel\n")) 8742774f206SBjoern A. Zeeb return; 8752774f206SBjoern A. Zeeb 8762774f206SBjoern A. Zeeb center_chan = ch_param.center_chan; 87790aac0d8SBjoern A. Zeeb primary_chan = ch_param.primary_chan; 8782774f206SBjoern A. Zeeb bandwidth = ch_param.bandwidth; 87990aac0d8SBjoern A. Zeeb band = ch_param.center_chan > 14 ? RTW_BAND_5G : RTW_BAND_2G; 8802774f206SBjoern A. Zeeb 88190aac0d8SBjoern A. Zeeb rtw_update_channel(rtwdev, center_chan, primary_chan, band, bandwidth); 8822774f206SBjoern A. Zeeb 88390aac0d8SBjoern A. Zeeb if (rtwdev->scan_info.op_chan) 88490aac0d8SBjoern A. Zeeb rtw_store_op_chan(rtwdev, true); 8852774f206SBjoern A. Zeeb 88690aac0d8SBjoern A. Zeeb chip->ops->set_channel(rtwdev, center_chan, bandwidth, 88790aac0d8SBjoern A. Zeeb hal->current_primary_channel_index); 8882774f206SBjoern A. Zeeb 8892774f206SBjoern A. Zeeb if (hal->current_band_type == RTW_BAND_5G) { 8902774f206SBjoern A. Zeeb rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_5G); 8912774f206SBjoern A. Zeeb } else { 8922774f206SBjoern A. Zeeb if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) 8932774f206SBjoern A. Zeeb rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_24G); 8942774f206SBjoern A. Zeeb else 8952774f206SBjoern A. Zeeb rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_24G_NOFORSCAN); 8962774f206SBjoern A. Zeeb } 8972774f206SBjoern A. Zeeb 8982774f206SBjoern A. Zeeb rtw_phy_set_tx_power_level(rtwdev, center_chan); 8992774f206SBjoern A. Zeeb 9002774f206SBjoern A. Zeeb /* if the channel isn't set for scanning, we will do RF calibration 9012774f206SBjoern A. Zeeb * in ieee80211_ops::mgd_prepare_tx(). Performing the calibration 9022774f206SBjoern A. Zeeb * during scanning on each channel takes too long. 9032774f206SBjoern A. Zeeb */ 9042774f206SBjoern A. Zeeb if (!test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) 9052774f206SBjoern A. Zeeb rtwdev->need_rfk = true; 9062774f206SBjoern A. Zeeb } 9072774f206SBjoern A. Zeeb 9082774f206SBjoern A. Zeeb void rtw_chip_prepare_tx(struct rtw_dev *rtwdev) 9092774f206SBjoern A. Zeeb { 91090aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 9112774f206SBjoern A. Zeeb 9122774f206SBjoern A. Zeeb if (rtwdev->need_rfk) { 9132774f206SBjoern A. Zeeb rtwdev->need_rfk = false; 9142774f206SBjoern A. Zeeb chip->ops->phy_calibration(rtwdev); 9152774f206SBjoern A. Zeeb } 9162774f206SBjoern A. Zeeb } 9172774f206SBjoern A. Zeeb 9182774f206SBjoern A. Zeeb static void rtw_vif_write_addr(struct rtw_dev *rtwdev, u32 start, u8 *addr) 9192774f206SBjoern A. Zeeb { 9202774f206SBjoern A. Zeeb int i; 9212774f206SBjoern A. Zeeb 9222774f206SBjoern A. Zeeb for (i = 0; i < ETH_ALEN; i++) 9232774f206SBjoern A. Zeeb rtw_write8(rtwdev, start + i, addr[i]); 9242774f206SBjoern A. Zeeb } 9252774f206SBjoern A. Zeeb 9262774f206SBjoern A. Zeeb void rtw_vif_port_config(struct rtw_dev *rtwdev, 9272774f206SBjoern A. Zeeb struct rtw_vif *rtwvif, 9282774f206SBjoern A. Zeeb u32 config) 9292774f206SBjoern A. Zeeb { 9302774f206SBjoern A. Zeeb u32 addr, mask; 9312774f206SBjoern A. Zeeb 9322774f206SBjoern A. Zeeb if (config & PORT_SET_MAC_ADDR) { 9332774f206SBjoern A. Zeeb addr = rtwvif->conf->mac_addr.addr; 9342774f206SBjoern A. Zeeb rtw_vif_write_addr(rtwdev, addr, rtwvif->mac_addr); 9352774f206SBjoern A. Zeeb } 9362774f206SBjoern A. Zeeb if (config & PORT_SET_BSSID) { 9372774f206SBjoern A. Zeeb addr = rtwvif->conf->bssid.addr; 9382774f206SBjoern A. Zeeb rtw_vif_write_addr(rtwdev, addr, rtwvif->bssid); 9392774f206SBjoern A. Zeeb } 9402774f206SBjoern A. Zeeb if (config & PORT_SET_NET_TYPE) { 9412774f206SBjoern A. Zeeb addr = rtwvif->conf->net_type.addr; 9422774f206SBjoern A. Zeeb mask = rtwvif->conf->net_type.mask; 9432774f206SBjoern A. Zeeb rtw_write32_mask(rtwdev, addr, mask, rtwvif->net_type); 9442774f206SBjoern A. Zeeb } 9452774f206SBjoern A. Zeeb if (config & PORT_SET_AID) { 9462774f206SBjoern A. Zeeb addr = rtwvif->conf->aid.addr; 9472774f206SBjoern A. Zeeb mask = rtwvif->conf->aid.mask; 9482774f206SBjoern A. Zeeb rtw_write32_mask(rtwdev, addr, mask, rtwvif->aid); 9492774f206SBjoern A. Zeeb } 9502774f206SBjoern A. Zeeb if (config & PORT_SET_BCN_CTRL) { 9512774f206SBjoern A. Zeeb addr = rtwvif->conf->bcn_ctrl.addr; 9522774f206SBjoern A. Zeeb mask = rtwvif->conf->bcn_ctrl.mask; 9532774f206SBjoern A. Zeeb rtw_write8_mask(rtwdev, addr, mask, rtwvif->bcn_ctrl); 9542774f206SBjoern A. Zeeb } 9552774f206SBjoern A. Zeeb } 9562774f206SBjoern A. Zeeb 9572774f206SBjoern A. Zeeb static u8 hw_bw_cap_to_bitamp(u8 bw_cap) 9582774f206SBjoern A. Zeeb { 9592774f206SBjoern A. Zeeb u8 bw = 0; 9602774f206SBjoern A. Zeeb 9612774f206SBjoern A. Zeeb switch (bw_cap) { 9622774f206SBjoern A. Zeeb case EFUSE_HW_CAP_IGNORE: 9632774f206SBjoern A. Zeeb case EFUSE_HW_CAP_SUPP_BW80: 9642774f206SBjoern A. Zeeb bw |= BIT(RTW_CHANNEL_WIDTH_80); 9652774f206SBjoern A. Zeeb fallthrough; 9662774f206SBjoern A. Zeeb case EFUSE_HW_CAP_SUPP_BW40: 9672774f206SBjoern A. Zeeb bw |= BIT(RTW_CHANNEL_WIDTH_40); 9682774f206SBjoern A. Zeeb fallthrough; 9692774f206SBjoern A. Zeeb default: 9702774f206SBjoern A. Zeeb bw |= BIT(RTW_CHANNEL_WIDTH_20); 9712774f206SBjoern A. Zeeb break; 9722774f206SBjoern A. Zeeb } 9732774f206SBjoern A. Zeeb 9742774f206SBjoern A. Zeeb return bw; 9752774f206SBjoern A. Zeeb } 9762774f206SBjoern A. Zeeb 9772774f206SBjoern A. Zeeb static void rtw_hw_config_rf_ant_num(struct rtw_dev *rtwdev, u8 hw_ant_num) 9782774f206SBjoern A. Zeeb { 97990aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 9802774f206SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 9812774f206SBjoern A. Zeeb 9822774f206SBjoern A. Zeeb if (hw_ant_num == EFUSE_HW_CAP_IGNORE || 9832774f206SBjoern A. Zeeb hw_ant_num >= hal->rf_path_num) 9842774f206SBjoern A. Zeeb return; 9852774f206SBjoern A. Zeeb 9862774f206SBjoern A. Zeeb switch (hw_ant_num) { 9872774f206SBjoern A. Zeeb case 1: 9882774f206SBjoern A. Zeeb hal->rf_type = RF_1T1R; 9892774f206SBjoern A. Zeeb hal->rf_path_num = 1; 9902774f206SBjoern A. Zeeb if (!chip->fix_rf_phy_num) 9912774f206SBjoern A. Zeeb hal->rf_phy_num = hal->rf_path_num; 9922774f206SBjoern A. Zeeb hal->antenna_tx = BB_PATH_A; 9932774f206SBjoern A. Zeeb hal->antenna_rx = BB_PATH_A; 9942774f206SBjoern A. Zeeb break; 9952774f206SBjoern A. Zeeb default: 9962774f206SBjoern A. Zeeb WARN(1, "invalid hw configuration from efuse\n"); 9972774f206SBjoern A. Zeeb break; 9982774f206SBjoern A. Zeeb } 9992774f206SBjoern A. Zeeb } 10002774f206SBjoern A. Zeeb 10012774f206SBjoern A. Zeeb static u64 get_vht_ra_mask(struct ieee80211_sta *sta) 10022774f206SBjoern A. Zeeb { 10032774f206SBjoern A. Zeeb u64 ra_mask = 0; 10046cf748adSBjoern A. Zeeb u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map); 10052774f206SBjoern A. Zeeb u8 vht_mcs_cap; 10062774f206SBjoern A. Zeeb int i, nss; 10072774f206SBjoern A. Zeeb 10082774f206SBjoern A. Zeeb /* 4SS, every two bits for MCS7/8/9 */ 10092774f206SBjoern A. Zeeb for (i = 0, nss = 12; i < 4; i++, mcs_map >>= 2, nss += 10) { 10102774f206SBjoern A. Zeeb vht_mcs_cap = mcs_map & 0x3; 10112774f206SBjoern A. Zeeb switch (vht_mcs_cap) { 10122774f206SBjoern A. Zeeb case 2: /* MCS9 */ 10132774f206SBjoern A. Zeeb ra_mask |= 0x3ffULL << nss; 10142774f206SBjoern A. Zeeb break; 10152774f206SBjoern A. Zeeb case 1: /* MCS8 */ 10162774f206SBjoern A. Zeeb ra_mask |= 0x1ffULL << nss; 10172774f206SBjoern A. Zeeb break; 10182774f206SBjoern A. Zeeb case 0: /* MCS7 */ 10192774f206SBjoern A. Zeeb ra_mask |= 0x0ffULL << nss; 10202774f206SBjoern A. Zeeb break; 10212774f206SBjoern A. Zeeb default: 10222774f206SBjoern A. Zeeb break; 10232774f206SBjoern A. Zeeb } 10242774f206SBjoern A. Zeeb } 10252774f206SBjoern A. Zeeb 10262774f206SBjoern A. Zeeb return ra_mask; 10272774f206SBjoern A. Zeeb } 10282774f206SBjoern A. Zeeb 10292774f206SBjoern A. Zeeb static u8 get_rate_id(u8 wireless_set, enum rtw_bandwidth bw_mode, u8 tx_num) 10302774f206SBjoern A. Zeeb { 10312774f206SBjoern A. Zeeb u8 rate_id = 0; 10322774f206SBjoern A. Zeeb 10332774f206SBjoern A. Zeeb switch (wireless_set) { 10342774f206SBjoern A. Zeeb case WIRELESS_CCK: 10352774f206SBjoern A. Zeeb rate_id = RTW_RATEID_B_20M; 10362774f206SBjoern A. Zeeb break; 10372774f206SBjoern A. Zeeb case WIRELESS_OFDM: 10382774f206SBjoern A. Zeeb rate_id = RTW_RATEID_G; 10392774f206SBjoern A. Zeeb break; 10402774f206SBjoern A. Zeeb case WIRELESS_CCK | WIRELESS_OFDM: 10412774f206SBjoern A. Zeeb rate_id = RTW_RATEID_BG; 10422774f206SBjoern A. Zeeb break; 10432774f206SBjoern A. Zeeb case WIRELESS_OFDM | WIRELESS_HT: 10442774f206SBjoern A. Zeeb if (tx_num == 1) 10452774f206SBjoern A. Zeeb rate_id = RTW_RATEID_GN_N1SS; 10462774f206SBjoern A. Zeeb else if (tx_num == 2) 10472774f206SBjoern A. Zeeb rate_id = RTW_RATEID_GN_N2SS; 10482774f206SBjoern A. Zeeb else if (tx_num == 3) 10492774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR5_N_3SS; 10502774f206SBjoern A. Zeeb break; 10512774f206SBjoern A. Zeeb case WIRELESS_CCK | WIRELESS_OFDM | WIRELESS_HT: 10522774f206SBjoern A. Zeeb if (bw_mode == RTW_CHANNEL_WIDTH_40) { 10532774f206SBjoern A. Zeeb if (tx_num == 1) 10542774f206SBjoern A. Zeeb rate_id = RTW_RATEID_BGN_40M_1SS; 10552774f206SBjoern A. Zeeb else if (tx_num == 2) 10562774f206SBjoern A. Zeeb rate_id = RTW_RATEID_BGN_40M_2SS; 10572774f206SBjoern A. Zeeb else if (tx_num == 3) 10582774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR5_N_3SS; 10592774f206SBjoern A. Zeeb else if (tx_num == 4) 10602774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR7_N_4SS; 10612774f206SBjoern A. Zeeb } else { 10622774f206SBjoern A. Zeeb if (tx_num == 1) 10632774f206SBjoern A. Zeeb rate_id = RTW_RATEID_BGN_20M_1SS; 10642774f206SBjoern A. Zeeb else if (tx_num == 2) 10652774f206SBjoern A. Zeeb rate_id = RTW_RATEID_BGN_20M_2SS; 10662774f206SBjoern A. Zeeb else if (tx_num == 3) 10672774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR5_N_3SS; 10682774f206SBjoern A. Zeeb else if (tx_num == 4) 10692774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR7_N_4SS; 10702774f206SBjoern A. Zeeb } 10712774f206SBjoern A. Zeeb break; 10722774f206SBjoern A. Zeeb case WIRELESS_OFDM | WIRELESS_VHT: 10732774f206SBjoern A. Zeeb if (tx_num == 1) 10742774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR1_AC_1SS; 10752774f206SBjoern A. Zeeb else if (tx_num == 2) 10762774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR0_AC_2SS; 10772774f206SBjoern A. Zeeb else if (tx_num == 3) 10782774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR4_AC_3SS; 10792774f206SBjoern A. Zeeb else if (tx_num == 4) 10802774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR6_AC_4SS; 10812774f206SBjoern A. Zeeb break; 10822774f206SBjoern A. Zeeb case WIRELESS_CCK | WIRELESS_OFDM | WIRELESS_VHT: 10832774f206SBjoern A. Zeeb if (bw_mode >= RTW_CHANNEL_WIDTH_80) { 10842774f206SBjoern A. Zeeb if (tx_num == 1) 10852774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR1_AC_1SS; 10862774f206SBjoern A. Zeeb else if (tx_num == 2) 10872774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR0_AC_2SS; 10882774f206SBjoern A. Zeeb else if (tx_num == 3) 10892774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR4_AC_3SS; 10902774f206SBjoern A. Zeeb else if (tx_num == 4) 10912774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR6_AC_4SS; 10922774f206SBjoern A. Zeeb } else { 10932774f206SBjoern A. Zeeb if (tx_num == 1) 10942774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR2_AC_2G_1SS; 10952774f206SBjoern A. Zeeb else if (tx_num == 2) 10962774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR3_AC_2G_2SS; 10972774f206SBjoern A. Zeeb else if (tx_num == 3) 10982774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR4_AC_3SS; 10992774f206SBjoern A. Zeeb else if (tx_num == 4) 11002774f206SBjoern A. Zeeb rate_id = RTW_RATEID_ARFR6_AC_4SS; 11012774f206SBjoern A. Zeeb } 11022774f206SBjoern A. Zeeb break; 11032774f206SBjoern A. Zeeb default: 11042774f206SBjoern A. Zeeb break; 11052774f206SBjoern A. Zeeb } 11062774f206SBjoern A. Zeeb 11072774f206SBjoern A. Zeeb return rate_id; 11082774f206SBjoern A. Zeeb } 11092774f206SBjoern A. Zeeb 11102774f206SBjoern A. Zeeb #define RA_MASK_CCK_RATES 0x0000f 11112774f206SBjoern A. Zeeb #define RA_MASK_OFDM_RATES 0x00ff0 11122774f206SBjoern A. Zeeb #define RA_MASK_HT_RATES_1SS (0xff000ULL << 0) 11132774f206SBjoern A. Zeeb #define RA_MASK_HT_RATES_2SS (0xff000ULL << 8) 11142774f206SBjoern A. Zeeb #define RA_MASK_HT_RATES_3SS (0xff000ULL << 16) 11152774f206SBjoern A. Zeeb #define RA_MASK_HT_RATES (RA_MASK_HT_RATES_1SS | \ 11162774f206SBjoern A. Zeeb RA_MASK_HT_RATES_2SS | \ 11172774f206SBjoern A. Zeeb RA_MASK_HT_RATES_3SS) 11182774f206SBjoern A. Zeeb #define RA_MASK_VHT_RATES_1SS (0x3ff000ULL << 0) 11192774f206SBjoern A. Zeeb #define RA_MASK_VHT_RATES_2SS (0x3ff000ULL << 10) 11202774f206SBjoern A. Zeeb #define RA_MASK_VHT_RATES_3SS (0x3ff000ULL << 20) 11212774f206SBjoern A. Zeeb #define RA_MASK_VHT_RATES (RA_MASK_VHT_RATES_1SS | \ 11222774f206SBjoern A. Zeeb RA_MASK_VHT_RATES_2SS | \ 11232774f206SBjoern A. Zeeb RA_MASK_VHT_RATES_3SS) 11249c951734SBjoern A. Zeeb #define RA_MASK_CCK_IN_BG 0x00005 11252774f206SBjoern A. Zeeb #define RA_MASK_CCK_IN_HT 0x00005 11262774f206SBjoern A. Zeeb #define RA_MASK_CCK_IN_VHT 0x00005 11272774f206SBjoern A. Zeeb #define RA_MASK_OFDM_IN_VHT 0x00010 11282774f206SBjoern A. Zeeb #define RA_MASK_OFDM_IN_HT_2G 0x00010 11292774f206SBjoern A. Zeeb #define RA_MASK_OFDM_IN_HT_5G 0x00030 11302774f206SBjoern A. Zeeb 11319c951734SBjoern A. Zeeb static u64 rtw_rate_mask_rssi(struct rtw_sta_info *si, u8 wireless_set) 11329c951734SBjoern A. Zeeb { 11339c951734SBjoern A. Zeeb u8 rssi_level = si->rssi_level; 11349c951734SBjoern A. Zeeb 11359c951734SBjoern A. Zeeb if (wireless_set == WIRELESS_CCK) 11369c951734SBjoern A. Zeeb return 0xffffffffffffffffULL; 11379c951734SBjoern A. Zeeb 11389c951734SBjoern A. Zeeb if (rssi_level == 0) 11399c951734SBjoern A. Zeeb return 0xffffffffffffffffULL; 11409c951734SBjoern A. Zeeb else if (rssi_level == 1) 11419c951734SBjoern A. Zeeb return 0xfffffffffffffff0ULL; 11429c951734SBjoern A. Zeeb else if (rssi_level == 2) 11439c951734SBjoern A. Zeeb return 0xffffffffffffefe0ULL; 11449c951734SBjoern A. Zeeb else if (rssi_level == 3) 11459c951734SBjoern A. Zeeb return 0xffffffffffffcfc0ULL; 11469c951734SBjoern A. Zeeb else if (rssi_level == 4) 11479c951734SBjoern A. Zeeb return 0xffffffffffff8f80ULL; 11489c951734SBjoern A. Zeeb else 11499c951734SBjoern A. Zeeb return 0xffffffffffff0f00ULL; 11509c951734SBjoern A. Zeeb } 11519c951734SBjoern A. Zeeb 11529c951734SBjoern A. Zeeb static u64 rtw_rate_mask_recover(u64 ra_mask, u64 ra_mask_bak) 11539c951734SBjoern A. Zeeb { 11549c951734SBjoern A. Zeeb if ((ra_mask & ~(RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES)) == 0) 11559c951734SBjoern A. Zeeb ra_mask |= (ra_mask_bak & ~(RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES)); 11569c951734SBjoern A. Zeeb 11579c951734SBjoern A. Zeeb if (ra_mask == 0) 11589c951734SBjoern A. Zeeb ra_mask |= (ra_mask_bak & (RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES)); 11599c951734SBjoern A. Zeeb 11609c951734SBjoern A. Zeeb return ra_mask; 11619c951734SBjoern A. Zeeb } 11629c951734SBjoern A. Zeeb 11639c951734SBjoern A. Zeeb static u64 rtw_rate_mask_cfg(struct rtw_dev *rtwdev, struct rtw_sta_info *si, 11649c951734SBjoern A. Zeeb u64 ra_mask, bool is_vht_enable) 11652774f206SBjoern A. Zeeb { 11662774f206SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 11672774f206SBjoern A. Zeeb const struct cfg80211_bitrate_mask *mask = si->mask; 11682774f206SBjoern A. Zeeb u64 cfg_mask = GENMASK_ULL(63, 0); 11699c951734SBjoern A. Zeeb u8 band; 11702774f206SBjoern A. Zeeb 11712774f206SBjoern A. Zeeb if (!si->use_cfg_mask) 11722774f206SBjoern A. Zeeb return ra_mask; 11732774f206SBjoern A. Zeeb 11742774f206SBjoern A. Zeeb band = hal->current_band_type; 11752774f206SBjoern A. Zeeb if (band == RTW_BAND_2G) { 11762774f206SBjoern A. Zeeb band = NL80211_BAND_2GHZ; 11772774f206SBjoern A. Zeeb cfg_mask = mask->control[band].legacy; 11782774f206SBjoern A. Zeeb } else if (band == RTW_BAND_5G) { 11792774f206SBjoern A. Zeeb band = NL80211_BAND_5GHZ; 11802774f206SBjoern A. Zeeb cfg_mask = u64_encode_bits(mask->control[band].legacy, 11812774f206SBjoern A. Zeeb RA_MASK_OFDM_RATES); 11822774f206SBjoern A. Zeeb } 11832774f206SBjoern A. Zeeb 11842774f206SBjoern A. Zeeb if (!is_vht_enable) { 11852774f206SBjoern A. Zeeb if (ra_mask & RA_MASK_HT_RATES_1SS) 11862774f206SBjoern A. Zeeb cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0], 11872774f206SBjoern A. Zeeb RA_MASK_HT_RATES_1SS); 11882774f206SBjoern A. Zeeb if (ra_mask & RA_MASK_HT_RATES_2SS) 11892774f206SBjoern A. Zeeb cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1], 11902774f206SBjoern A. Zeeb RA_MASK_HT_RATES_2SS); 11912774f206SBjoern A. Zeeb } else { 11922774f206SBjoern A. Zeeb if (ra_mask & RA_MASK_VHT_RATES_1SS) 11932774f206SBjoern A. Zeeb cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0], 11942774f206SBjoern A. Zeeb RA_MASK_VHT_RATES_1SS); 11952774f206SBjoern A. Zeeb if (ra_mask & RA_MASK_VHT_RATES_2SS) 11962774f206SBjoern A. Zeeb cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1], 11972774f206SBjoern A. Zeeb RA_MASK_VHT_RATES_2SS); 11982774f206SBjoern A. Zeeb } 11992774f206SBjoern A. Zeeb 12002774f206SBjoern A. Zeeb ra_mask &= cfg_mask; 12012774f206SBjoern A. Zeeb 12022774f206SBjoern A. Zeeb return ra_mask; 12032774f206SBjoern A. Zeeb } 12042774f206SBjoern A. Zeeb 12059c951734SBjoern A. Zeeb void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, 12069c951734SBjoern A. Zeeb bool reset_ra_mask) 12072774f206SBjoern A. Zeeb { 12082774f206SBjoern A. Zeeb struct rtw_dm_info *dm_info = &rtwdev->dm_info; 12092774f206SBjoern A. Zeeb struct ieee80211_sta *sta = si->sta; 12102774f206SBjoern A. Zeeb struct rtw_efuse *efuse = &rtwdev->efuse; 12112774f206SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 12122774f206SBjoern A. Zeeb u8 wireless_set; 12132774f206SBjoern A. Zeeb u8 bw_mode; 12142774f206SBjoern A. Zeeb u8 rate_id; 12152774f206SBjoern A. Zeeb u8 rf_type = RF_1T1R; 12162774f206SBjoern A. Zeeb u8 stbc_en = 0; 12172774f206SBjoern A. Zeeb u8 ldpc_en = 0; 12182774f206SBjoern A. Zeeb u8 tx_num = 1; 12192774f206SBjoern A. Zeeb u64 ra_mask = 0; 12209c951734SBjoern A. Zeeb u64 ra_mask_bak = 0; 12212774f206SBjoern A. Zeeb bool is_vht_enable = false; 12222774f206SBjoern A. Zeeb bool is_support_sgi = false; 12232774f206SBjoern A. Zeeb 12246cf748adSBjoern A. Zeeb if (sta->deflink.vht_cap.vht_supported) { 12252774f206SBjoern A. Zeeb is_vht_enable = true; 12262774f206SBjoern A. Zeeb ra_mask |= get_vht_ra_mask(sta); 12276cf748adSBjoern A. Zeeb if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK) 12282774f206SBjoern A. Zeeb stbc_en = VHT_STBC_EN; 12296cf748adSBjoern A. Zeeb if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) 12302774f206SBjoern A. Zeeb ldpc_en = VHT_LDPC_EN; 12316cf748adSBjoern A. Zeeb } else if (sta->deflink.ht_cap.ht_supported) { 12326cf748adSBjoern A. Zeeb ra_mask |= (sta->deflink.ht_cap.mcs.rx_mask[1] << 20) | 12336cf748adSBjoern A. Zeeb (sta->deflink.ht_cap.mcs.rx_mask[0] << 12); 12346cf748adSBjoern A. Zeeb if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) 12352774f206SBjoern A. Zeeb stbc_en = HT_STBC_EN; 12366cf748adSBjoern A. Zeeb if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) 12372774f206SBjoern A. Zeeb ldpc_en = HT_LDPC_EN; 12382774f206SBjoern A. Zeeb } 12392774f206SBjoern A. Zeeb 12409c951734SBjoern A. Zeeb if (efuse->hw_cap.nss == 1 || rtwdev->hal.txrx_1ss) 12412774f206SBjoern A. Zeeb ra_mask &= RA_MASK_VHT_RATES_1SS | RA_MASK_HT_RATES_1SS; 12422774f206SBjoern A. Zeeb 12432774f206SBjoern A. Zeeb if (hal->current_band_type == RTW_BAND_5G) { 12446cf748adSBjoern A. Zeeb ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_5GHZ] << 4; 12459c951734SBjoern A. Zeeb ra_mask_bak = ra_mask; 12466cf748adSBjoern A. Zeeb if (sta->deflink.vht_cap.vht_supported) { 12472774f206SBjoern A. Zeeb ra_mask &= RA_MASK_VHT_RATES | RA_MASK_OFDM_IN_VHT; 12482774f206SBjoern A. Zeeb wireless_set = WIRELESS_OFDM | WIRELESS_VHT; 12496cf748adSBjoern A. Zeeb } else if (sta->deflink.ht_cap.ht_supported) { 12502774f206SBjoern A. Zeeb ra_mask &= RA_MASK_HT_RATES | RA_MASK_OFDM_IN_HT_5G; 12512774f206SBjoern A. Zeeb wireless_set = WIRELESS_OFDM | WIRELESS_HT; 12522774f206SBjoern A. Zeeb } else { 12532774f206SBjoern A. Zeeb wireless_set = WIRELESS_OFDM; 12542774f206SBjoern A. Zeeb } 12552774f206SBjoern A. Zeeb dm_info->rrsr_val_init = RRSR_INIT_5G; 12562774f206SBjoern A. Zeeb } else if (hal->current_band_type == RTW_BAND_2G) { 12576cf748adSBjoern A. Zeeb ra_mask |= sta->deflink.supp_rates[NL80211_BAND_2GHZ]; 12589c951734SBjoern A. Zeeb ra_mask_bak = ra_mask; 12596cf748adSBjoern A. Zeeb if (sta->deflink.vht_cap.vht_supported) { 12602774f206SBjoern A. Zeeb ra_mask &= RA_MASK_VHT_RATES | RA_MASK_CCK_IN_VHT | 12612774f206SBjoern A. Zeeb RA_MASK_OFDM_IN_VHT; 12622774f206SBjoern A. Zeeb wireless_set = WIRELESS_CCK | WIRELESS_OFDM | 12632774f206SBjoern A. Zeeb WIRELESS_HT | WIRELESS_VHT; 12646cf748adSBjoern A. Zeeb } else if (sta->deflink.ht_cap.ht_supported) { 12652774f206SBjoern A. Zeeb ra_mask &= RA_MASK_HT_RATES | RA_MASK_CCK_IN_HT | 12662774f206SBjoern A. Zeeb RA_MASK_OFDM_IN_HT_2G; 12672774f206SBjoern A. Zeeb wireless_set = WIRELESS_CCK | WIRELESS_OFDM | 12682774f206SBjoern A. Zeeb WIRELESS_HT; 12698aaefd05SBjoern A. Zeeb #if defined(__linux__) 12706cf748adSBjoern A. Zeeb } else if (sta->deflink.supp_rates[0] <= 0xf) { 12718aaefd05SBjoern A. Zeeb #elif defined(__FreeBSD__) 12728aaefd05SBjoern A. Zeeb } else if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] <= 0xf) { 12738aaefd05SBjoern A. Zeeb #endif 12742774f206SBjoern A. Zeeb wireless_set = WIRELESS_CCK; 12752774f206SBjoern A. Zeeb } else { 12769c951734SBjoern A. Zeeb ra_mask &= RA_MASK_OFDM_RATES | RA_MASK_CCK_IN_BG; 12772774f206SBjoern A. Zeeb wireless_set = WIRELESS_CCK | WIRELESS_OFDM; 12782774f206SBjoern A. Zeeb } 12792774f206SBjoern A. Zeeb dm_info->rrsr_val_init = RRSR_INIT_2G; 12802774f206SBjoern A. Zeeb } else { 12812774f206SBjoern A. Zeeb rtw_err(rtwdev, "Unknown band type\n"); 12829c951734SBjoern A. Zeeb ra_mask_bak = ra_mask; 12832774f206SBjoern A. Zeeb wireless_set = 0; 12842774f206SBjoern A. Zeeb } 12852774f206SBjoern A. Zeeb 12866cf748adSBjoern A. Zeeb switch (sta->deflink.bandwidth) { 12872774f206SBjoern A. Zeeb case IEEE80211_STA_RX_BW_80: 12882774f206SBjoern A. Zeeb bw_mode = RTW_CHANNEL_WIDTH_80; 12896cf748adSBjoern A. Zeeb is_support_sgi = sta->deflink.vht_cap.vht_supported && 12906cf748adSBjoern A. Zeeb (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); 12912774f206SBjoern A. Zeeb break; 12922774f206SBjoern A. Zeeb case IEEE80211_STA_RX_BW_40: 12932774f206SBjoern A. Zeeb bw_mode = RTW_CHANNEL_WIDTH_40; 12946cf748adSBjoern A. Zeeb is_support_sgi = sta->deflink.ht_cap.ht_supported && 12956cf748adSBjoern A. Zeeb (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40); 12962774f206SBjoern A. Zeeb break; 12972774f206SBjoern A. Zeeb default: 12982774f206SBjoern A. Zeeb bw_mode = RTW_CHANNEL_WIDTH_20; 12996cf748adSBjoern A. Zeeb is_support_sgi = sta->deflink.ht_cap.ht_supported && 13006cf748adSBjoern A. Zeeb (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20); 13012774f206SBjoern A. Zeeb break; 13022774f206SBjoern A. Zeeb } 13032774f206SBjoern A. Zeeb 13046cf748adSBjoern A. Zeeb if (sta->deflink.vht_cap.vht_supported && ra_mask & 0xffc00000) { 13052774f206SBjoern A. Zeeb tx_num = 2; 13062774f206SBjoern A. Zeeb rf_type = RF_2T2R; 13076cf748adSBjoern A. Zeeb } else if (sta->deflink.ht_cap.ht_supported && ra_mask & 0xfff00000) { 13082774f206SBjoern A. Zeeb tx_num = 2; 13092774f206SBjoern A. Zeeb rf_type = RF_2T2R; 13102774f206SBjoern A. Zeeb } 13112774f206SBjoern A. Zeeb 13122774f206SBjoern A. Zeeb rate_id = get_rate_id(wireless_set, bw_mode, tx_num); 13132774f206SBjoern A. Zeeb 13149c951734SBjoern A. Zeeb ra_mask &= rtw_rate_mask_rssi(si, wireless_set); 13159c951734SBjoern A. Zeeb ra_mask = rtw_rate_mask_recover(ra_mask, ra_mask_bak); 13169c951734SBjoern A. Zeeb ra_mask = rtw_rate_mask_cfg(rtwdev, si, ra_mask, is_vht_enable); 13172774f206SBjoern A. Zeeb 13182774f206SBjoern A. Zeeb si->bw_mode = bw_mode; 13192774f206SBjoern A. Zeeb si->stbc_en = stbc_en; 13202774f206SBjoern A. Zeeb si->ldpc_en = ldpc_en; 13212774f206SBjoern A. Zeeb si->rf_type = rf_type; 13222774f206SBjoern A. Zeeb si->sgi_enable = is_support_sgi; 13232774f206SBjoern A. Zeeb si->vht_enable = is_vht_enable; 13242774f206SBjoern A. Zeeb si->ra_mask = ra_mask; 13252774f206SBjoern A. Zeeb si->rate_id = rate_id; 13262774f206SBjoern A. Zeeb 13279c951734SBjoern A. Zeeb rtw_fw_send_ra_info(rtwdev, si, reset_ra_mask); 13282774f206SBjoern A. Zeeb } 13292774f206SBjoern A. Zeeb 13302774f206SBjoern A. Zeeb static int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) 13312774f206SBjoern A. Zeeb { 133290aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 13332774f206SBjoern A. Zeeb struct rtw_fw_state *fw; 13342774f206SBjoern A. Zeeb 13352774f206SBjoern A. Zeeb fw = &rtwdev->fw; 13362774f206SBjoern A. Zeeb wait_for_completion(&fw->completion); 13372774f206SBjoern A. Zeeb if (!fw->firmware) 13382774f206SBjoern A. Zeeb return -EINVAL; 13392774f206SBjoern A. Zeeb 13402774f206SBjoern A. Zeeb if (chip->wow_fw_name) { 13412774f206SBjoern A. Zeeb fw = &rtwdev->wow_fw; 13422774f206SBjoern A. Zeeb wait_for_completion(&fw->completion); 13432774f206SBjoern A. Zeeb if (!fw->firmware) 13442774f206SBjoern A. Zeeb return -EINVAL; 13452774f206SBjoern A. Zeeb } 13462774f206SBjoern A. Zeeb 13472774f206SBjoern A. Zeeb return 0; 13482774f206SBjoern A. Zeeb } 13492774f206SBjoern A. Zeeb 13502774f206SBjoern A. Zeeb static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, 13512774f206SBjoern A. Zeeb struct rtw_fw_state *fw) 13522774f206SBjoern A. Zeeb { 135390aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 13542774f206SBjoern A. Zeeb 13552774f206SBjoern A. Zeeb if (rtw_disable_lps_deep_mode || !chip->lps_deep_mode_supported || 13562774f206SBjoern A. Zeeb !fw->feature) 13572774f206SBjoern A. Zeeb return LPS_DEEP_MODE_NONE; 13582774f206SBjoern A. Zeeb 13592774f206SBjoern A. Zeeb if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_PG)) && 13602774f206SBjoern A. Zeeb rtw_fw_feature_check(fw, FW_FEATURE_PG)) 13612774f206SBjoern A. Zeeb return LPS_DEEP_MODE_PG; 13622774f206SBjoern A. Zeeb 13632774f206SBjoern A. Zeeb if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_LCLK)) && 13642774f206SBjoern A. Zeeb rtw_fw_feature_check(fw, FW_FEATURE_LCLK)) 13652774f206SBjoern A. Zeeb return LPS_DEEP_MODE_LCLK; 13662774f206SBjoern A. Zeeb 13672774f206SBjoern A. Zeeb return LPS_DEEP_MODE_NONE; 13682774f206SBjoern A. Zeeb } 13692774f206SBjoern A. Zeeb 13702774f206SBjoern A. Zeeb static int rtw_power_on(struct rtw_dev *rtwdev) 13712774f206SBjoern A. Zeeb { 137290aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 13732774f206SBjoern A. Zeeb struct rtw_fw_state *fw = &rtwdev->fw; 13742774f206SBjoern A. Zeeb bool wifi_only; 13752774f206SBjoern A. Zeeb int ret; 13762774f206SBjoern A. Zeeb 13772774f206SBjoern A. Zeeb ret = rtw_hci_setup(rtwdev); 13782774f206SBjoern A. Zeeb if (ret) { 13792774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to setup hci\n"); 13802774f206SBjoern A. Zeeb goto err; 13812774f206SBjoern A. Zeeb } 13822774f206SBjoern A. Zeeb 13832774f206SBjoern A. Zeeb /* power on MAC before firmware downloaded */ 13842774f206SBjoern A. Zeeb ret = rtw_mac_power_on(rtwdev); 13852774f206SBjoern A. Zeeb if (ret) { 13862774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to power on mac\n"); 13872774f206SBjoern A. Zeeb goto err; 13882774f206SBjoern A. Zeeb } 13892774f206SBjoern A. Zeeb 13902774f206SBjoern A. Zeeb ret = rtw_wait_firmware_completion(rtwdev); 13912774f206SBjoern A. Zeeb if (ret) { 13922774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to wait firmware completion\n"); 13932774f206SBjoern A. Zeeb goto err_off; 13942774f206SBjoern A. Zeeb } 13952774f206SBjoern A. Zeeb 13962774f206SBjoern A. Zeeb ret = rtw_download_firmware(rtwdev, fw); 13972774f206SBjoern A. Zeeb if (ret) { 13982774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to download firmware\n"); 13992774f206SBjoern A. Zeeb goto err_off; 14002774f206SBjoern A. Zeeb } 14012774f206SBjoern A. Zeeb 14022774f206SBjoern A. Zeeb /* config mac after firmware downloaded */ 14032774f206SBjoern A. Zeeb ret = rtw_mac_init(rtwdev); 14042774f206SBjoern A. Zeeb if (ret) { 14052774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to configure mac\n"); 14062774f206SBjoern A. Zeeb goto err_off; 14072774f206SBjoern A. Zeeb } 14082774f206SBjoern A. Zeeb 14092774f206SBjoern A. Zeeb chip->ops->phy_set_param(rtwdev); 14102774f206SBjoern A. Zeeb 14112774f206SBjoern A. Zeeb ret = rtw_hci_start(rtwdev); 14122774f206SBjoern A. Zeeb if (ret) { 14132774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to start hci\n"); 14142774f206SBjoern A. Zeeb goto err_off; 14152774f206SBjoern A. Zeeb } 14162774f206SBjoern A. Zeeb 14172774f206SBjoern A. Zeeb /* send H2C after HCI has started */ 14182774f206SBjoern A. Zeeb rtw_fw_send_general_info(rtwdev); 14192774f206SBjoern A. Zeeb rtw_fw_send_phydm_info(rtwdev); 14202774f206SBjoern A. Zeeb 14212774f206SBjoern A. Zeeb wifi_only = !rtwdev->efuse.btcoex; 14222774f206SBjoern A. Zeeb rtw_coex_power_on_setting(rtwdev); 14232774f206SBjoern A. Zeeb rtw_coex_init_hw_config(rtwdev, wifi_only); 14242774f206SBjoern A. Zeeb 14252774f206SBjoern A. Zeeb return 0; 14262774f206SBjoern A. Zeeb 14272774f206SBjoern A. Zeeb err_off: 14282774f206SBjoern A. Zeeb rtw_mac_power_off(rtwdev); 14292774f206SBjoern A. Zeeb 14302774f206SBjoern A. Zeeb err: 14312774f206SBjoern A. Zeeb return ret; 14322774f206SBjoern A. Zeeb } 14332774f206SBjoern A. Zeeb 14342774f206SBjoern A. Zeeb void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start) 14352774f206SBjoern A. Zeeb { 14362774f206SBjoern A. Zeeb if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_NOTIFY_SCAN)) 14372774f206SBjoern A. Zeeb return; 14382774f206SBjoern A. Zeeb 14392774f206SBjoern A. Zeeb if (start) { 14402774f206SBjoern A. Zeeb rtw_fw_scan_notify(rtwdev, true); 14412774f206SBjoern A. Zeeb } else { 14422774f206SBjoern A. Zeeb reinit_completion(&rtwdev->fw_scan_density); 14432774f206SBjoern A. Zeeb rtw_fw_scan_notify(rtwdev, false); 14442774f206SBjoern A. Zeeb if (!wait_for_completion_timeout(&rtwdev->fw_scan_density, 14452774f206SBjoern A. Zeeb SCAN_NOTIFY_TIMEOUT)) 14462774f206SBjoern A. Zeeb rtw_warn(rtwdev, "firmware failed to report density after scan\n"); 14472774f206SBjoern A. Zeeb } 14482774f206SBjoern A. Zeeb } 14492774f206SBjoern A. Zeeb 14502774f206SBjoern A. Zeeb void rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif, 14512774f206SBjoern A. Zeeb const u8 *mac_addr, bool hw_scan) 14522774f206SBjoern A. Zeeb { 14532774f206SBjoern A. Zeeb u32 config = 0; 14542774f206SBjoern A. Zeeb int ret = 0; 14552774f206SBjoern A. Zeeb 14562774f206SBjoern A. Zeeb rtw_leave_lps(rtwdev); 14572774f206SBjoern A. Zeeb 14589c951734SBjoern A. Zeeb if (hw_scan && (rtwdev->hw->conf.flags & IEEE80211_CONF_IDLE)) { 14592774f206SBjoern A. Zeeb ret = rtw_leave_ips(rtwdev); 14602774f206SBjoern A. Zeeb if (ret) { 14612774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to leave idle state\n"); 14622774f206SBjoern A. Zeeb return; 14632774f206SBjoern A. Zeeb } 14642774f206SBjoern A. Zeeb } 14652774f206SBjoern A. Zeeb 14662774f206SBjoern A. Zeeb ether_addr_copy(rtwvif->mac_addr, mac_addr); 14672774f206SBjoern A. Zeeb config |= PORT_SET_MAC_ADDR; 14682774f206SBjoern A. Zeeb rtw_vif_port_config(rtwdev, rtwvif, config); 14692774f206SBjoern A. Zeeb 14702774f206SBjoern A. Zeeb rtw_coex_scan_notify(rtwdev, COEX_SCAN_START); 14712774f206SBjoern A. Zeeb rtw_core_fw_scan_notify(rtwdev, true); 14722774f206SBjoern A. Zeeb 14732774f206SBjoern A. Zeeb set_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); 14742774f206SBjoern A. Zeeb set_bit(RTW_FLAG_SCANNING, rtwdev->flags); 14752774f206SBjoern A. Zeeb } 14762774f206SBjoern A. Zeeb 14779c951734SBjoern A. Zeeb void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, 14789c951734SBjoern A. Zeeb bool hw_scan) 14792774f206SBjoern A. Zeeb { 14809c951734SBjoern A. Zeeb struct rtw_vif *rtwvif = vif ? (struct rtw_vif *)vif->drv_priv : NULL; 14812774f206SBjoern A. Zeeb u32 config = 0; 14822774f206SBjoern A. Zeeb 14839c951734SBjoern A. Zeeb if (!rtwvif) 14849c951734SBjoern A. Zeeb return; 14859c951734SBjoern A. Zeeb 14862774f206SBjoern A. Zeeb clear_bit(RTW_FLAG_SCANNING, rtwdev->flags); 14872774f206SBjoern A. Zeeb clear_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); 14882774f206SBjoern A. Zeeb 14892774f206SBjoern A. Zeeb rtw_core_fw_scan_notify(rtwdev, false); 14902774f206SBjoern A. Zeeb 14912774f206SBjoern A. Zeeb ether_addr_copy(rtwvif->mac_addr, vif->addr); 14922774f206SBjoern A. Zeeb config |= PORT_SET_MAC_ADDR; 14932774f206SBjoern A. Zeeb rtw_vif_port_config(rtwdev, rtwvif, config); 14942774f206SBjoern A. Zeeb 14952774f206SBjoern A. Zeeb rtw_coex_scan_notify(rtwdev, COEX_SCAN_FINISH); 14969c951734SBjoern A. Zeeb 14979c951734SBjoern A. Zeeb if (hw_scan && (rtwdev->hw->conf.flags & IEEE80211_CONF_IDLE)) 14989c951734SBjoern A. Zeeb ieee80211_queue_work(rtwdev->hw, &rtwdev->ips_work); 14992774f206SBjoern A. Zeeb } 15002774f206SBjoern A. Zeeb 15012774f206SBjoern A. Zeeb int rtw_core_start(struct rtw_dev *rtwdev) 15022774f206SBjoern A. Zeeb { 15032774f206SBjoern A. Zeeb int ret; 15042774f206SBjoern A. Zeeb 15052774f206SBjoern A. Zeeb ret = rtw_power_on(rtwdev); 15062774f206SBjoern A. Zeeb if (ret) 15072774f206SBjoern A. Zeeb return ret; 15082774f206SBjoern A. Zeeb 15092774f206SBjoern A. Zeeb rtw_sec_enable_sec_engine(rtwdev); 15102774f206SBjoern A. Zeeb 15112774f206SBjoern A. Zeeb rtwdev->lps_conf.deep_mode = rtw_update_lps_deep_mode(rtwdev, &rtwdev->fw); 15122774f206SBjoern A. Zeeb rtwdev->lps_conf.wow_deep_mode = rtw_update_lps_deep_mode(rtwdev, &rtwdev->wow_fw); 15132774f206SBjoern A. Zeeb 15142774f206SBjoern A. Zeeb /* rcr reset after powered on */ 15152774f206SBjoern A. Zeeb rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr); 15162774f206SBjoern A. Zeeb 15172774f206SBjoern A. Zeeb ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work, 15182774f206SBjoern A. Zeeb RTW_WATCH_DOG_DELAY_TIME); 15192774f206SBjoern A. Zeeb 15202774f206SBjoern A. Zeeb set_bit(RTW_FLAG_RUNNING, rtwdev->flags); 15212774f206SBjoern A. Zeeb 15222774f206SBjoern A. Zeeb return 0; 15232774f206SBjoern A. Zeeb } 15242774f206SBjoern A. Zeeb 15252774f206SBjoern A. Zeeb static void rtw_power_off(struct rtw_dev *rtwdev) 15262774f206SBjoern A. Zeeb { 15272774f206SBjoern A. Zeeb rtw_hci_stop(rtwdev); 15282774f206SBjoern A. Zeeb rtw_coex_power_off_setting(rtwdev); 15292774f206SBjoern A. Zeeb rtw_mac_power_off(rtwdev); 15302774f206SBjoern A. Zeeb } 15312774f206SBjoern A. Zeeb 15322774f206SBjoern A. Zeeb void rtw_core_stop(struct rtw_dev *rtwdev) 15332774f206SBjoern A. Zeeb { 15342774f206SBjoern A. Zeeb struct rtw_coex *coex = &rtwdev->coex; 15352774f206SBjoern A. Zeeb 15362774f206SBjoern A. Zeeb clear_bit(RTW_FLAG_RUNNING, rtwdev->flags); 15372774f206SBjoern A. Zeeb clear_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); 15382774f206SBjoern A. Zeeb 15392774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 15402774f206SBjoern A. Zeeb 15412774f206SBjoern A. Zeeb cancel_work_sync(&rtwdev->c2h_work); 15429c951734SBjoern A. Zeeb cancel_work_sync(&rtwdev->update_beacon_work); 15432774f206SBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->watch_dog_work); 15442774f206SBjoern A. Zeeb cancel_delayed_work_sync(&coex->bt_relink_work); 15452774f206SBjoern A. Zeeb cancel_delayed_work_sync(&coex->bt_reenable_work); 15462774f206SBjoern A. Zeeb cancel_delayed_work_sync(&coex->defreeze_work); 15472774f206SBjoern A. Zeeb cancel_delayed_work_sync(&coex->wl_remain_work); 15482774f206SBjoern A. Zeeb cancel_delayed_work_sync(&coex->bt_remain_work); 15492774f206SBjoern A. Zeeb cancel_delayed_work_sync(&coex->wl_connecting_work); 15502774f206SBjoern A. Zeeb cancel_delayed_work_sync(&coex->bt_multi_link_remain_work); 15512774f206SBjoern A. Zeeb cancel_delayed_work_sync(&coex->wl_ccklock_work); 15522774f206SBjoern A. Zeeb 15532774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 15542774f206SBjoern A. Zeeb 15552774f206SBjoern A. Zeeb rtw_power_off(rtwdev); 15562774f206SBjoern A. Zeeb } 15572774f206SBjoern A. Zeeb 15582774f206SBjoern A. Zeeb static void rtw_init_ht_cap(struct rtw_dev *rtwdev, 15592774f206SBjoern A. Zeeb struct ieee80211_sta_ht_cap *ht_cap) 15602774f206SBjoern A. Zeeb { 156190aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 15622774f206SBjoern A. Zeeb struct rtw_efuse *efuse = &rtwdev->efuse; 15632774f206SBjoern A. Zeeb 15642774f206SBjoern A. Zeeb ht_cap->ht_supported = true; 15652774f206SBjoern A. Zeeb ht_cap->cap = 0; 15662774f206SBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_SGI_20 | 15672774f206SBjoern A. Zeeb IEEE80211_HT_CAP_MAX_AMSDU | 15682774f206SBjoern A. Zeeb (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 15692774f206SBjoern A. Zeeb 15702774f206SBjoern A. Zeeb if (rtw_chip_has_rx_ldpc(rtwdev)) 15712774f206SBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING; 15722774f206SBjoern A. Zeeb if (rtw_chip_has_tx_stbc(rtwdev)) 15732774f206SBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 15742774f206SBjoern A. Zeeb 15752774f206SBjoern A. Zeeb if (efuse->hw_cap.bw & BIT(RTW_CHANNEL_WIDTH_40)) 15762774f206SBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 15772774f206SBjoern A. Zeeb IEEE80211_HT_CAP_DSSSCCK40 | 15782774f206SBjoern A. Zeeb IEEE80211_HT_CAP_SGI_40; 15792774f206SBjoern A. Zeeb ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 15809c951734SBjoern A. Zeeb ht_cap->ampdu_density = chip->ampdu_density; 15812774f206SBjoern A. Zeeb ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 15822774f206SBjoern A. Zeeb if (efuse->hw_cap.nss > 1) { 15832774f206SBjoern A. Zeeb ht_cap->mcs.rx_mask[0] = 0xFF; 15842774f206SBjoern A. Zeeb ht_cap->mcs.rx_mask[1] = 0xFF; 15852774f206SBjoern A. Zeeb ht_cap->mcs.rx_mask[4] = 0x01; 15862774f206SBjoern A. Zeeb ht_cap->mcs.rx_highest = cpu_to_le16(300); 15872774f206SBjoern A. Zeeb } else { 15882774f206SBjoern A. Zeeb ht_cap->mcs.rx_mask[0] = 0xFF; 15892774f206SBjoern A. Zeeb ht_cap->mcs.rx_mask[1] = 0x00; 15902774f206SBjoern A. Zeeb ht_cap->mcs.rx_mask[4] = 0x01; 15912774f206SBjoern A. Zeeb ht_cap->mcs.rx_highest = cpu_to_le16(150); 15922774f206SBjoern A. Zeeb } 15932774f206SBjoern A. Zeeb } 15942774f206SBjoern A. Zeeb 15952774f206SBjoern A. Zeeb static void rtw_init_vht_cap(struct rtw_dev *rtwdev, 15962774f206SBjoern A. Zeeb struct ieee80211_sta_vht_cap *vht_cap) 15972774f206SBjoern A. Zeeb { 15982774f206SBjoern A. Zeeb struct rtw_efuse *efuse = &rtwdev->efuse; 15992774f206SBjoern A. Zeeb u16 mcs_map; 16002774f206SBjoern A. Zeeb __le16 highest; 16012774f206SBjoern A. Zeeb 16022774f206SBjoern A. Zeeb if (efuse->hw_cap.ptcl != EFUSE_HW_CAP_IGNORE && 16032774f206SBjoern A. Zeeb efuse->hw_cap.ptcl != EFUSE_HW_CAP_PTCL_VHT) 16042774f206SBjoern A. Zeeb return; 16052774f206SBjoern A. Zeeb 16062774f206SBjoern A. Zeeb vht_cap->vht_supported = true; 16072774f206SBjoern A. Zeeb vht_cap->cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | 16082774f206SBjoern A. Zeeb IEEE80211_VHT_CAP_SHORT_GI_80 | 16092774f206SBjoern A. Zeeb IEEE80211_VHT_CAP_RXSTBC_1 | 16102774f206SBjoern A. Zeeb IEEE80211_VHT_CAP_HTC_VHT | 16112774f206SBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | 16122774f206SBjoern A. Zeeb 0; 16132774f206SBjoern A. Zeeb if (rtwdev->hal.rf_path_num > 1) 16142774f206SBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 16152774f206SBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | 16162774f206SBjoern A. Zeeb IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; 16172774f206SBjoern A. Zeeb vht_cap->cap |= (rtwdev->hal.bfee_sts_cap << 16182774f206SBjoern A. Zeeb IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); 16192774f206SBjoern A. Zeeb 16202774f206SBjoern A. Zeeb if (rtw_chip_has_rx_ldpc(rtwdev)) 16212774f206SBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; 16222774f206SBjoern A. Zeeb 16232774f206SBjoern A. Zeeb mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | 16242774f206SBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | 16252774f206SBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | 16262774f206SBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | 16272774f206SBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | 16282774f206SBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | 16292774f206SBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; 16302774f206SBjoern A. Zeeb if (efuse->hw_cap.nss > 1) { 16312774f206SBjoern A. Zeeb highest = cpu_to_le16(780); 16322774f206SBjoern A. Zeeb mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << 2; 16332774f206SBjoern A. Zeeb } else { 16342774f206SBjoern A. Zeeb highest = cpu_to_le16(390); 16352774f206SBjoern A. Zeeb mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << 2; 16362774f206SBjoern A. Zeeb } 16372774f206SBjoern A. Zeeb 16382774f206SBjoern A. Zeeb vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 16392774f206SBjoern A. Zeeb vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 16402774f206SBjoern A. Zeeb vht_cap->vht_mcs.rx_highest = highest; 16412774f206SBjoern A. Zeeb vht_cap->vht_mcs.tx_highest = highest; 16422774f206SBjoern A. Zeeb } 16432774f206SBjoern A. Zeeb 164490aac0d8SBjoern A. Zeeb static u16 rtw_get_max_scan_ie_len(struct rtw_dev *rtwdev) 164590aac0d8SBjoern A. Zeeb { 164690aac0d8SBjoern A. Zeeb u16 len; 164790aac0d8SBjoern A. Zeeb 164890aac0d8SBjoern A. Zeeb len = rtwdev->chip->max_scan_ie_len; 164990aac0d8SBjoern A. Zeeb 165090aac0d8SBjoern A. Zeeb if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD) && 165190aac0d8SBjoern A. Zeeb rtwdev->chip->id == RTW_CHIP_TYPE_8822C) 165290aac0d8SBjoern A. Zeeb len = IEEE80211_MAX_DATA_LEN; 165390aac0d8SBjoern A. Zeeb else if (rtw_fw_feature_ext_check(&rtwdev->fw, FW_FEATURE_EXT_OLD_PAGE_NUM)) 165490aac0d8SBjoern A. Zeeb len -= RTW_OLD_PROBE_PG_CNT * TX_PAGE_SIZE; 165590aac0d8SBjoern A. Zeeb 165690aac0d8SBjoern A. Zeeb return len; 165790aac0d8SBjoern A. Zeeb } 165890aac0d8SBjoern A. Zeeb 16592774f206SBjoern A. Zeeb static void rtw_set_supported_band(struct ieee80211_hw *hw, 166090aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip) 16612774f206SBjoern A. Zeeb { 16622774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = hw->priv; 16632774f206SBjoern A. Zeeb struct ieee80211_supported_band *sband; 16642774f206SBjoern A. Zeeb 16652774f206SBjoern A. Zeeb if (chip->band & RTW_BAND_2G) { 16662774f206SBjoern A. Zeeb sband = kmemdup(&rtw_band_2ghz, sizeof(*sband), GFP_KERNEL); 16672774f206SBjoern A. Zeeb if (!sband) 16682774f206SBjoern A. Zeeb goto err_out; 16692774f206SBjoern A. Zeeb if (chip->ht_supported) 16702774f206SBjoern A. Zeeb rtw_init_ht_cap(rtwdev, &sband->ht_cap); 16712774f206SBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_2GHZ] = sband; 16722774f206SBjoern A. Zeeb } 16732774f206SBjoern A. Zeeb 16742774f206SBjoern A. Zeeb if (chip->band & RTW_BAND_5G) { 16752774f206SBjoern A. Zeeb sband = kmemdup(&rtw_band_5ghz, sizeof(*sband), GFP_KERNEL); 16762774f206SBjoern A. Zeeb if (!sband) 16772774f206SBjoern A. Zeeb goto err_out; 16782774f206SBjoern A. Zeeb if (chip->ht_supported) 16792774f206SBjoern A. Zeeb rtw_init_ht_cap(rtwdev, &sband->ht_cap); 16802774f206SBjoern A. Zeeb if (chip->vht_supported) 16812774f206SBjoern A. Zeeb rtw_init_vht_cap(rtwdev, &sband->vht_cap); 16822774f206SBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_5GHZ] = sband; 16832774f206SBjoern A. Zeeb } 16842774f206SBjoern A. Zeeb 16852774f206SBjoern A. Zeeb return; 16862774f206SBjoern A. Zeeb 16872774f206SBjoern A. Zeeb err_out: 16882774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to set supported band\n"); 16892774f206SBjoern A. Zeeb } 16902774f206SBjoern A. Zeeb 16912774f206SBjoern A. Zeeb static void rtw_unset_supported_band(struct ieee80211_hw *hw, 169290aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip) 16932774f206SBjoern A. Zeeb { 16942774f206SBjoern A. Zeeb kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]); 16952774f206SBjoern A. Zeeb kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]); 16962774f206SBjoern A. Zeeb } 16972774f206SBjoern A. Zeeb 16989c951734SBjoern A. Zeeb static void rtw_vif_smps_iter(void *data, u8 *mac, 16999c951734SBjoern A. Zeeb struct ieee80211_vif *vif) 17009c951734SBjoern A. Zeeb { 17019c951734SBjoern A. Zeeb struct rtw_dev *rtwdev = (struct rtw_dev *)data; 17029c951734SBjoern A. Zeeb 170390aac0d8SBjoern A. Zeeb if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) 17049c951734SBjoern A. Zeeb return; 17059c951734SBjoern A. Zeeb 17069c951734SBjoern A. Zeeb if (rtwdev->hal.txrx_1ss) 170790aac0d8SBjoern A. Zeeb ieee80211_request_smps(vif, 0, IEEE80211_SMPS_STATIC); 17089c951734SBjoern A. Zeeb else 170990aac0d8SBjoern A. Zeeb ieee80211_request_smps(vif, 0, IEEE80211_SMPS_OFF); 17109c951734SBjoern A. Zeeb } 17119c951734SBjoern A. Zeeb 17129c951734SBjoern A. Zeeb void rtw_set_txrx_1ss(struct rtw_dev *rtwdev, bool txrx_1ss) 17139c951734SBjoern A. Zeeb { 171490aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 17159c951734SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 17169c951734SBjoern A. Zeeb 17179c951734SBjoern A. Zeeb if (!chip->ops->config_txrx_mode || rtwdev->hal.txrx_1ss == txrx_1ss) 17189c951734SBjoern A. Zeeb return; 17199c951734SBjoern A. Zeeb 17209c951734SBjoern A. Zeeb rtwdev->hal.txrx_1ss = txrx_1ss; 17219c951734SBjoern A. Zeeb if (txrx_1ss) 17229c951734SBjoern A. Zeeb chip->ops->config_txrx_mode(rtwdev, BB_PATH_A, BB_PATH_A, false); 17239c951734SBjoern A. Zeeb else 17249c951734SBjoern A. Zeeb chip->ops->config_txrx_mode(rtwdev, hal->antenna_tx, 17259c951734SBjoern A. Zeeb hal->antenna_rx, false); 17269c951734SBjoern A. Zeeb rtw_iterate_vifs_atomic(rtwdev, rtw_vif_smps_iter, rtwdev); 17279c951734SBjoern A. Zeeb } 17289c951734SBjoern A. Zeeb 17292774f206SBjoern A. Zeeb static void __update_firmware_feature(struct rtw_dev *rtwdev, 17302774f206SBjoern A. Zeeb struct rtw_fw_state *fw) 17312774f206SBjoern A. Zeeb { 17322774f206SBjoern A. Zeeb u32 feature; 17332774f206SBjoern A. Zeeb const struct rtw_fw_hdr *fw_hdr = 17342774f206SBjoern A. Zeeb (const struct rtw_fw_hdr *)fw->firmware->data; 17352774f206SBjoern A. Zeeb 17362774f206SBjoern A. Zeeb feature = le32_to_cpu(fw_hdr->feature); 17372774f206SBjoern A. Zeeb fw->feature = feature & FW_FEATURE_SIG ? feature : 0; 173890aac0d8SBjoern A. Zeeb 173990aac0d8SBjoern A. Zeeb if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C && 174090aac0d8SBjoern A. Zeeb RTW_FW_SUIT_VER_CODE(rtwdev->fw) < RTW_FW_VER_CODE(9, 9, 13)) 174190aac0d8SBjoern A. Zeeb fw->feature_ext |= FW_FEATURE_EXT_OLD_PAGE_NUM; 17422774f206SBjoern A. Zeeb } 17432774f206SBjoern A. Zeeb 17442774f206SBjoern A. Zeeb static void __update_firmware_info(struct rtw_dev *rtwdev, 17452774f206SBjoern A. Zeeb struct rtw_fw_state *fw) 17462774f206SBjoern A. Zeeb { 17472774f206SBjoern A. Zeeb const struct rtw_fw_hdr *fw_hdr = 17482774f206SBjoern A. Zeeb (const struct rtw_fw_hdr *)fw->firmware->data; 17492774f206SBjoern A. Zeeb 17502774f206SBjoern A. Zeeb fw->h2c_version = le16_to_cpu(fw_hdr->h2c_fmt_ver); 17512774f206SBjoern A. Zeeb fw->version = le16_to_cpu(fw_hdr->version); 17522774f206SBjoern A. Zeeb fw->sub_version = fw_hdr->subversion; 17532774f206SBjoern A. Zeeb fw->sub_index = fw_hdr->subindex; 17542774f206SBjoern A. Zeeb 17552774f206SBjoern A. Zeeb __update_firmware_feature(rtwdev, fw); 17562774f206SBjoern A. Zeeb } 17572774f206SBjoern A. Zeeb 17582774f206SBjoern A. Zeeb static void __update_firmware_info_legacy(struct rtw_dev *rtwdev, 17592774f206SBjoern A. Zeeb struct rtw_fw_state *fw) 17602774f206SBjoern A. Zeeb { 17612774f206SBjoern A. Zeeb struct rtw_fw_hdr_legacy *legacy = 17622774f206SBjoern A. Zeeb #if defined(__linux__) 17632774f206SBjoern A. Zeeb (struct rtw_fw_hdr_legacy *)fw->firmware->data; 17642774f206SBjoern A. Zeeb #elif defined(__FreeBSD__) 17652774f206SBjoern A. Zeeb __DECONST(struct rtw_fw_hdr_legacy *, fw->firmware->data); 17662774f206SBjoern A. Zeeb #endif 17672774f206SBjoern A. Zeeb 17682774f206SBjoern A. Zeeb fw->h2c_version = 0; 17692774f206SBjoern A. Zeeb fw->version = le16_to_cpu(legacy->version); 17702774f206SBjoern A. Zeeb fw->sub_version = legacy->subversion1; 17712774f206SBjoern A. Zeeb fw->sub_index = legacy->subversion2; 17722774f206SBjoern A. Zeeb } 17732774f206SBjoern A. Zeeb 17742774f206SBjoern A. Zeeb static void update_firmware_info(struct rtw_dev *rtwdev, 17752774f206SBjoern A. Zeeb struct rtw_fw_state *fw) 17762774f206SBjoern A. Zeeb { 17772774f206SBjoern A. Zeeb if (rtw_chip_wcpu_11n(rtwdev)) 17782774f206SBjoern A. Zeeb __update_firmware_info_legacy(rtwdev, fw); 17792774f206SBjoern A. Zeeb else 17802774f206SBjoern A. Zeeb __update_firmware_info(rtwdev, fw); 17812774f206SBjoern A. Zeeb } 17822774f206SBjoern A. Zeeb 17832774f206SBjoern A. Zeeb static void rtw_load_firmware_cb(const struct firmware *firmware, void *context) 17842774f206SBjoern A. Zeeb { 17852774f206SBjoern A. Zeeb struct rtw_fw_state *fw = context; 17862774f206SBjoern A. Zeeb struct rtw_dev *rtwdev = fw->rtwdev; 17872774f206SBjoern A. Zeeb 17882774f206SBjoern A. Zeeb if (!firmware || !firmware->data) { 17892774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to request firmware\n"); 17902774f206SBjoern A. Zeeb complete_all(&fw->completion); 17912774f206SBjoern A. Zeeb return; 17922774f206SBjoern A. Zeeb } 17932774f206SBjoern A. Zeeb 17942774f206SBjoern A. Zeeb fw->firmware = firmware; 17952774f206SBjoern A. Zeeb update_firmware_info(rtwdev, fw); 17962774f206SBjoern A. Zeeb complete_all(&fw->completion); 17972774f206SBjoern A. Zeeb 179890aac0d8SBjoern A. Zeeb rtw_info(rtwdev, "%sFirmware version %u.%u.%u, H2C version %u\n", 179990aac0d8SBjoern A. Zeeb fw->type == RTW_WOWLAN_FW ? "WOW " : "", 18002774f206SBjoern A. Zeeb fw->version, fw->sub_version, fw->sub_index, fw->h2c_version); 18012774f206SBjoern A. Zeeb } 18022774f206SBjoern A. Zeeb 18032774f206SBjoern A. Zeeb static int rtw_load_firmware(struct rtw_dev *rtwdev, enum rtw_fw_type type) 18042774f206SBjoern A. Zeeb { 18052774f206SBjoern A. Zeeb const char *fw_name; 18062774f206SBjoern A. Zeeb struct rtw_fw_state *fw; 18072774f206SBjoern A. Zeeb int ret; 18082774f206SBjoern A. Zeeb 18092774f206SBjoern A. Zeeb switch (type) { 18102774f206SBjoern A. Zeeb case RTW_WOWLAN_FW: 18112774f206SBjoern A. Zeeb fw = &rtwdev->wow_fw; 18122774f206SBjoern A. Zeeb fw_name = rtwdev->chip->wow_fw_name; 18132774f206SBjoern A. Zeeb break; 18142774f206SBjoern A. Zeeb 18152774f206SBjoern A. Zeeb case RTW_NORMAL_FW: 18162774f206SBjoern A. Zeeb fw = &rtwdev->fw; 18172774f206SBjoern A. Zeeb fw_name = rtwdev->chip->fw_name; 18182774f206SBjoern A. Zeeb break; 18192774f206SBjoern A. Zeeb 18202774f206SBjoern A. Zeeb default: 18212774f206SBjoern A. Zeeb rtw_warn(rtwdev, "unsupported firmware type\n"); 18222774f206SBjoern A. Zeeb return -ENOENT; 18232774f206SBjoern A. Zeeb } 18242774f206SBjoern A. Zeeb 182590aac0d8SBjoern A. Zeeb fw->type = type; 18262774f206SBjoern A. Zeeb fw->rtwdev = rtwdev; 18272774f206SBjoern A. Zeeb init_completion(&fw->completion); 18282774f206SBjoern A. Zeeb 18292774f206SBjoern A. Zeeb ret = request_firmware_nowait(THIS_MODULE, true, fw_name, rtwdev->dev, 18302774f206SBjoern A. Zeeb GFP_KERNEL, fw, rtw_load_firmware_cb); 18312774f206SBjoern A. Zeeb if (ret) { 18322774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to async firmware request\n"); 18332774f206SBjoern A. Zeeb return ret; 18342774f206SBjoern A. Zeeb } 18352774f206SBjoern A. Zeeb 18362774f206SBjoern A. Zeeb return 0; 18372774f206SBjoern A. Zeeb } 18382774f206SBjoern A. Zeeb 18392774f206SBjoern A. Zeeb static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev) 18402774f206SBjoern A. Zeeb { 184190aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 18422774f206SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 18432774f206SBjoern A. Zeeb struct rtw_efuse *efuse = &rtwdev->efuse; 18442774f206SBjoern A. Zeeb 18452774f206SBjoern A. Zeeb switch (rtw_hci_type(rtwdev)) { 18462774f206SBjoern A. Zeeb case RTW_HCI_TYPE_PCIE: 18472774f206SBjoern A. Zeeb rtwdev->hci.rpwm_addr = 0x03d9; 18482774f206SBjoern A. Zeeb rtwdev->hci.cpwm_addr = 0x03da; 18492774f206SBjoern A. Zeeb break; 185090aac0d8SBjoern A. Zeeb case RTW_HCI_TYPE_SDIO: 185190aac0d8SBjoern A. Zeeb rtwdev->hci.rpwm_addr = REG_SDIO_HRPWM1; 185290aac0d8SBjoern A. Zeeb rtwdev->hci.cpwm_addr = REG_SDIO_HCPWM1_V2; 185390aac0d8SBjoern A. Zeeb break; 185490aac0d8SBjoern A. Zeeb case RTW_HCI_TYPE_USB: 185590aac0d8SBjoern A. Zeeb rtwdev->hci.rpwm_addr = 0xfe58; 185690aac0d8SBjoern A. Zeeb rtwdev->hci.cpwm_addr = 0xfe57; 185790aac0d8SBjoern A. Zeeb break; 18582774f206SBjoern A. Zeeb default: 18592774f206SBjoern A. Zeeb rtw_err(rtwdev, "unsupported hci type\n"); 18602774f206SBjoern A. Zeeb return -EINVAL; 18612774f206SBjoern A. Zeeb } 18622774f206SBjoern A. Zeeb 18632774f206SBjoern A. Zeeb hal->chip_version = rtw_read32(rtwdev, REG_SYS_CFG1); 18642774f206SBjoern A. Zeeb hal->cut_version = BIT_GET_CHIP_VER(hal->chip_version); 18652774f206SBjoern A. Zeeb hal->mp_chip = (hal->chip_version & BIT_RTL_ID) ? 0 : 1; 18662774f206SBjoern A. Zeeb if (hal->chip_version & BIT_RF_TYPE_ID) { 18672774f206SBjoern A. Zeeb hal->rf_type = RF_2T2R; 18682774f206SBjoern A. Zeeb hal->rf_path_num = 2; 18692774f206SBjoern A. Zeeb hal->antenna_tx = BB_PATH_AB; 18702774f206SBjoern A. Zeeb hal->antenna_rx = BB_PATH_AB; 18712774f206SBjoern A. Zeeb } else { 18722774f206SBjoern A. Zeeb hal->rf_type = RF_1T1R; 18732774f206SBjoern A. Zeeb hal->rf_path_num = 1; 18742774f206SBjoern A. Zeeb hal->antenna_tx = BB_PATH_A; 18752774f206SBjoern A. Zeeb hal->antenna_rx = BB_PATH_A; 18762774f206SBjoern A. Zeeb } 18772774f206SBjoern A. Zeeb hal->rf_phy_num = chip->fix_rf_phy_num ? chip->fix_rf_phy_num : 18782774f206SBjoern A. Zeeb hal->rf_path_num; 18792774f206SBjoern A. Zeeb 18802774f206SBjoern A. Zeeb efuse->physical_size = chip->phy_efuse_size; 18812774f206SBjoern A. Zeeb efuse->logical_size = chip->log_efuse_size; 18822774f206SBjoern A. Zeeb efuse->protect_size = chip->ptct_efuse_size; 18832774f206SBjoern A. Zeeb 18842774f206SBjoern A. Zeeb /* default use ack */ 18852774f206SBjoern A. Zeeb rtwdev->hal.rcr |= BIT_VHT_DACK; 18862774f206SBjoern A. Zeeb 18872774f206SBjoern A. Zeeb hal->bfee_sts_cap = 3; 18882774f206SBjoern A. Zeeb 18892774f206SBjoern A. Zeeb return 0; 18902774f206SBjoern A. Zeeb } 18912774f206SBjoern A. Zeeb 18922774f206SBjoern A. Zeeb static int rtw_chip_efuse_enable(struct rtw_dev *rtwdev) 18932774f206SBjoern A. Zeeb { 18942774f206SBjoern A. Zeeb struct rtw_fw_state *fw = &rtwdev->fw; 18952774f206SBjoern A. Zeeb int ret; 18962774f206SBjoern A. Zeeb 18972774f206SBjoern A. Zeeb ret = rtw_hci_setup(rtwdev); 18982774f206SBjoern A. Zeeb if (ret) { 18992774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to setup hci\n"); 19002774f206SBjoern A. Zeeb goto err; 19012774f206SBjoern A. Zeeb } 19022774f206SBjoern A. Zeeb 19032774f206SBjoern A. Zeeb ret = rtw_mac_power_on(rtwdev); 19042774f206SBjoern A. Zeeb if (ret) { 19052774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to power on mac\n"); 19062774f206SBjoern A. Zeeb goto err; 19072774f206SBjoern A. Zeeb } 19082774f206SBjoern A. Zeeb 19092774f206SBjoern A. Zeeb rtw_write8(rtwdev, REG_C2HEVT, C2H_HW_FEATURE_DUMP); 19102774f206SBjoern A. Zeeb 19112774f206SBjoern A. Zeeb wait_for_completion(&fw->completion); 19122774f206SBjoern A. Zeeb if (!fw->firmware) { 19132774f206SBjoern A. Zeeb ret = -EINVAL; 19142774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to load firmware\n"); 19152774f206SBjoern A. Zeeb goto err; 19162774f206SBjoern A. Zeeb } 19172774f206SBjoern A. Zeeb 19182774f206SBjoern A. Zeeb ret = rtw_download_firmware(rtwdev, fw); 19192774f206SBjoern A. Zeeb if (ret) { 19202774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to download firmware\n"); 19212774f206SBjoern A. Zeeb goto err_off; 19222774f206SBjoern A. Zeeb } 19232774f206SBjoern A. Zeeb 19242774f206SBjoern A. Zeeb return 0; 19252774f206SBjoern A. Zeeb 19262774f206SBjoern A. Zeeb err_off: 19272774f206SBjoern A. Zeeb rtw_mac_power_off(rtwdev); 19282774f206SBjoern A. Zeeb 19292774f206SBjoern A. Zeeb err: 19302774f206SBjoern A. Zeeb return ret; 19312774f206SBjoern A. Zeeb } 19322774f206SBjoern A. Zeeb 19332774f206SBjoern A. Zeeb static int rtw_dump_hw_feature(struct rtw_dev *rtwdev) 19342774f206SBjoern A. Zeeb { 19352774f206SBjoern A. Zeeb struct rtw_efuse *efuse = &rtwdev->efuse; 19362774f206SBjoern A. Zeeb u8 hw_feature[HW_FEATURE_LEN]; 19372774f206SBjoern A. Zeeb u8 id; 19382774f206SBjoern A. Zeeb u8 bw; 19392774f206SBjoern A. Zeeb int i; 19402774f206SBjoern A. Zeeb 19412774f206SBjoern A. Zeeb id = rtw_read8(rtwdev, REG_C2HEVT); 19422774f206SBjoern A. Zeeb if (id != C2H_HW_FEATURE_REPORT) { 19432774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to read hw feature report\n"); 19442774f206SBjoern A. Zeeb return -EBUSY; 19452774f206SBjoern A. Zeeb } 19462774f206SBjoern A. Zeeb 19472774f206SBjoern A. Zeeb for (i = 0; i < HW_FEATURE_LEN; i++) 19482774f206SBjoern A. Zeeb hw_feature[i] = rtw_read8(rtwdev, REG_C2HEVT + 2 + i); 19492774f206SBjoern A. Zeeb 19502774f206SBjoern A. Zeeb rtw_write8(rtwdev, REG_C2HEVT, 0); 19512774f206SBjoern A. Zeeb 19522774f206SBjoern A. Zeeb bw = GET_EFUSE_HW_CAP_BW(hw_feature); 19532774f206SBjoern A. Zeeb efuse->hw_cap.bw = hw_bw_cap_to_bitamp(bw); 19542774f206SBjoern A. Zeeb efuse->hw_cap.hci = GET_EFUSE_HW_CAP_HCI(hw_feature); 19552774f206SBjoern A. Zeeb efuse->hw_cap.nss = GET_EFUSE_HW_CAP_NSS(hw_feature); 19562774f206SBjoern A. Zeeb efuse->hw_cap.ptcl = GET_EFUSE_HW_CAP_PTCL(hw_feature); 19572774f206SBjoern A. Zeeb efuse->hw_cap.ant_num = GET_EFUSE_HW_CAP_ANT_NUM(hw_feature); 19582774f206SBjoern A. Zeeb 19592774f206SBjoern A. Zeeb rtw_hw_config_rf_ant_num(rtwdev, efuse->hw_cap.ant_num); 19602774f206SBjoern A. Zeeb 19612774f206SBjoern A. Zeeb if (efuse->hw_cap.nss == EFUSE_HW_CAP_IGNORE || 19622774f206SBjoern A. Zeeb efuse->hw_cap.nss > rtwdev->hal.rf_path_num) 19632774f206SBjoern A. Zeeb efuse->hw_cap.nss = rtwdev->hal.rf_path_num; 19642774f206SBjoern A. Zeeb 19652774f206SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_EFUSE, 19662774f206SBjoern A. Zeeb "hw cap: hci=0x%02x, bw=0x%02x, ptcl=0x%02x, ant_num=%d, nss=%d\n", 19672774f206SBjoern A. Zeeb efuse->hw_cap.hci, efuse->hw_cap.bw, efuse->hw_cap.ptcl, 19682774f206SBjoern A. Zeeb efuse->hw_cap.ant_num, efuse->hw_cap.nss); 19692774f206SBjoern A. Zeeb 19702774f206SBjoern A. Zeeb return 0; 19712774f206SBjoern A. Zeeb } 19722774f206SBjoern A. Zeeb 19732774f206SBjoern A. Zeeb static void rtw_chip_efuse_disable(struct rtw_dev *rtwdev) 19742774f206SBjoern A. Zeeb { 19752774f206SBjoern A. Zeeb rtw_hci_stop(rtwdev); 19762774f206SBjoern A. Zeeb rtw_mac_power_off(rtwdev); 19772774f206SBjoern A. Zeeb } 19782774f206SBjoern A. Zeeb 19792774f206SBjoern A. Zeeb static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev) 19802774f206SBjoern A. Zeeb { 19812774f206SBjoern A. Zeeb struct rtw_efuse *efuse = &rtwdev->efuse; 19822774f206SBjoern A. Zeeb int ret; 19832774f206SBjoern A. Zeeb 19842774f206SBjoern A. Zeeb mutex_lock(&rtwdev->mutex); 19852774f206SBjoern A. Zeeb 19862774f206SBjoern A. Zeeb /* power on mac to read efuse */ 19872774f206SBjoern A. Zeeb ret = rtw_chip_efuse_enable(rtwdev); 19882774f206SBjoern A. Zeeb if (ret) 19892774f206SBjoern A. Zeeb goto out_unlock; 19902774f206SBjoern A. Zeeb 19912774f206SBjoern A. Zeeb ret = rtw_parse_efuse_map(rtwdev); 19922774f206SBjoern A. Zeeb if (ret) 19932774f206SBjoern A. Zeeb goto out_disable; 19942774f206SBjoern A. Zeeb 19952774f206SBjoern A. Zeeb ret = rtw_dump_hw_feature(rtwdev); 19962774f206SBjoern A. Zeeb if (ret) 19972774f206SBjoern A. Zeeb goto out_disable; 19982774f206SBjoern A. Zeeb 19992774f206SBjoern A. Zeeb ret = rtw_check_supported_rfe(rtwdev); 20002774f206SBjoern A. Zeeb if (ret) 20012774f206SBjoern A. Zeeb goto out_disable; 20022774f206SBjoern A. Zeeb 20032774f206SBjoern A. Zeeb if (efuse->crystal_cap == 0xff) 20042774f206SBjoern A. Zeeb efuse->crystal_cap = 0; 20052774f206SBjoern A. Zeeb if (efuse->pa_type_2g == 0xff) 20062774f206SBjoern A. Zeeb efuse->pa_type_2g = 0; 20072774f206SBjoern A. Zeeb if (efuse->pa_type_5g == 0xff) 20082774f206SBjoern A. Zeeb efuse->pa_type_5g = 0; 20092774f206SBjoern A. Zeeb if (efuse->lna_type_2g == 0xff) 20102774f206SBjoern A. Zeeb efuse->lna_type_2g = 0; 20112774f206SBjoern A. Zeeb if (efuse->lna_type_5g == 0xff) 20122774f206SBjoern A. Zeeb efuse->lna_type_5g = 0; 20132774f206SBjoern A. Zeeb if (efuse->channel_plan == 0xff) 20142774f206SBjoern A. Zeeb efuse->channel_plan = 0x7f; 20152774f206SBjoern A. Zeeb if (efuse->rf_board_option == 0xff) 20162774f206SBjoern A. Zeeb efuse->rf_board_option = 0; 20172774f206SBjoern A. Zeeb if (efuse->bt_setting & BIT(0)) 20182774f206SBjoern A. Zeeb efuse->share_ant = true; 20192774f206SBjoern A. Zeeb if (efuse->regd == 0xff) 20202774f206SBjoern A. Zeeb efuse->regd = 0; 20212774f206SBjoern A. Zeeb if (efuse->tx_bb_swing_setting_2g == 0xff) 20222774f206SBjoern A. Zeeb efuse->tx_bb_swing_setting_2g = 0; 20232774f206SBjoern A. Zeeb if (efuse->tx_bb_swing_setting_5g == 0xff) 20242774f206SBjoern A. Zeeb efuse->tx_bb_swing_setting_5g = 0; 20252774f206SBjoern A. Zeeb 20262774f206SBjoern A. Zeeb efuse->btcoex = (efuse->rf_board_option & 0xe0) == 0x20; 20272774f206SBjoern A. Zeeb efuse->ext_pa_2g = efuse->pa_type_2g & BIT(4) ? 1 : 0; 20282774f206SBjoern A. Zeeb efuse->ext_lna_2g = efuse->lna_type_2g & BIT(3) ? 1 : 0; 20292774f206SBjoern A. Zeeb efuse->ext_pa_5g = efuse->pa_type_5g & BIT(0) ? 1 : 0; 20302774f206SBjoern A. Zeeb efuse->ext_lna_2g = efuse->lna_type_5g & BIT(3) ? 1 : 0; 20312774f206SBjoern A. Zeeb 2032*11c53278SBjoern A. Zeeb if (!is_valid_ether_addr(efuse->addr)) { 2033*11c53278SBjoern A. Zeeb eth_random_addr(efuse->addr); 2034*11c53278SBjoern A. Zeeb dev_warn(rtwdev->dev, "efuse MAC invalid, using random\n"); 2035*11c53278SBjoern A. Zeeb } 2036*11c53278SBjoern A. Zeeb 20372774f206SBjoern A. Zeeb out_disable: 20382774f206SBjoern A. Zeeb rtw_chip_efuse_disable(rtwdev); 20392774f206SBjoern A. Zeeb 20402774f206SBjoern A. Zeeb out_unlock: 20412774f206SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex); 20422774f206SBjoern A. Zeeb return ret; 20432774f206SBjoern A. Zeeb } 20442774f206SBjoern A. Zeeb 20452774f206SBjoern A. Zeeb static int rtw_chip_board_info_setup(struct rtw_dev *rtwdev) 20462774f206SBjoern A. Zeeb { 20472774f206SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 20482774f206SBjoern A. Zeeb const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev); 20492774f206SBjoern A. Zeeb 20502774f206SBjoern A. Zeeb if (!rfe_def) 20512774f206SBjoern A. Zeeb return -ENODEV; 20522774f206SBjoern A. Zeeb 205390aac0d8SBjoern A. Zeeb rtw_phy_setup_phy_cond(rtwdev, hal->pkg_type); 20542774f206SBjoern A. Zeeb 20552774f206SBjoern A. Zeeb rtw_phy_init_tx_power(rtwdev); 20562774f206SBjoern A. Zeeb rtw_load_table(rtwdev, rfe_def->phy_pg_tbl); 20572774f206SBjoern A. Zeeb rtw_load_table(rtwdev, rfe_def->txpwr_lmt_tbl); 20582774f206SBjoern A. Zeeb rtw_phy_tx_power_by_rate_config(hal); 20592774f206SBjoern A. Zeeb rtw_phy_tx_power_limit_config(hal); 20602774f206SBjoern A. Zeeb 20612774f206SBjoern A. Zeeb return 0; 20622774f206SBjoern A. Zeeb } 20632774f206SBjoern A. Zeeb 20642774f206SBjoern A. Zeeb int rtw_chip_info_setup(struct rtw_dev *rtwdev) 20652774f206SBjoern A. Zeeb { 20662774f206SBjoern A. Zeeb int ret; 20672774f206SBjoern A. Zeeb 20682774f206SBjoern A. Zeeb ret = rtw_chip_parameter_setup(rtwdev); 20692774f206SBjoern A. Zeeb if (ret) { 20702774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to setup chip parameters\n"); 20712774f206SBjoern A. Zeeb goto err_out; 20722774f206SBjoern A. Zeeb } 20732774f206SBjoern A. Zeeb 20742774f206SBjoern A. Zeeb ret = rtw_chip_efuse_info_setup(rtwdev); 20752774f206SBjoern A. Zeeb if (ret) { 20762774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to setup chip efuse info\n"); 20772774f206SBjoern A. Zeeb goto err_out; 20782774f206SBjoern A. Zeeb } 20792774f206SBjoern A. Zeeb 20802774f206SBjoern A. Zeeb ret = rtw_chip_board_info_setup(rtwdev); 20812774f206SBjoern A. Zeeb if (ret) { 20822774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to setup chip board info\n"); 20832774f206SBjoern A. Zeeb goto err_out; 20842774f206SBjoern A. Zeeb } 20852774f206SBjoern A. Zeeb 20862774f206SBjoern A. Zeeb return 0; 20872774f206SBjoern A. Zeeb 20882774f206SBjoern A. Zeeb err_out: 20892774f206SBjoern A. Zeeb return ret; 20902774f206SBjoern A. Zeeb } 20912774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_chip_info_setup); 20922774f206SBjoern A. Zeeb 20932774f206SBjoern A. Zeeb static void rtw_stats_init(struct rtw_dev *rtwdev) 20942774f206SBjoern A. Zeeb { 20952774f206SBjoern A. Zeeb struct rtw_traffic_stats *stats = &rtwdev->stats; 20962774f206SBjoern A. Zeeb struct rtw_dm_info *dm_info = &rtwdev->dm_info; 20972774f206SBjoern A. Zeeb int i; 20982774f206SBjoern A. Zeeb 20992774f206SBjoern A. Zeeb ewma_tp_init(&stats->tx_ewma_tp); 21002774f206SBjoern A. Zeeb ewma_tp_init(&stats->rx_ewma_tp); 21012774f206SBjoern A. Zeeb 21022774f206SBjoern A. Zeeb for (i = 0; i < RTW_EVM_NUM; i++) 21032774f206SBjoern A. Zeeb ewma_evm_init(&dm_info->ewma_evm[i]); 21042774f206SBjoern A. Zeeb for (i = 0; i < RTW_SNR_NUM; i++) 21052774f206SBjoern A. Zeeb ewma_snr_init(&dm_info->ewma_snr[i]); 21062774f206SBjoern A. Zeeb } 21072774f206SBjoern A. Zeeb 21082774f206SBjoern A. Zeeb int rtw_core_init(struct rtw_dev *rtwdev) 21092774f206SBjoern A. Zeeb { 211090aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 21112774f206SBjoern A. Zeeb struct rtw_coex *coex = &rtwdev->coex; 21122774f206SBjoern A. Zeeb int ret; 21132774f206SBjoern A. Zeeb 21142774f206SBjoern A. Zeeb INIT_LIST_HEAD(&rtwdev->rsvd_page_list); 21152774f206SBjoern A. Zeeb INIT_LIST_HEAD(&rtwdev->txqs); 21162774f206SBjoern A. Zeeb 21172774f206SBjoern A. Zeeb timer_setup(&rtwdev->tx_report.purge_timer, 21182774f206SBjoern A. Zeeb rtw_tx_report_purge_timer, 0); 21192774f206SBjoern A. Zeeb rtwdev->tx_wq = alloc_workqueue("rtw_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); 212090aac0d8SBjoern A. Zeeb if (!rtwdev->tx_wq) { 212190aac0d8SBjoern A. Zeeb rtw_warn(rtwdev, "alloc_workqueue rtw_tx_wq failed\n"); 212290aac0d8SBjoern A. Zeeb return -ENOMEM; 212390aac0d8SBjoern A. Zeeb } 21242774f206SBjoern A. Zeeb 21252774f206SBjoern A. Zeeb INIT_DELAYED_WORK(&rtwdev->watch_dog_work, rtw_watch_dog_work); 21262774f206SBjoern A. Zeeb INIT_DELAYED_WORK(&coex->bt_relink_work, rtw_coex_bt_relink_work); 21272774f206SBjoern A. Zeeb INIT_DELAYED_WORK(&coex->bt_reenable_work, rtw_coex_bt_reenable_work); 21282774f206SBjoern A. Zeeb INIT_DELAYED_WORK(&coex->defreeze_work, rtw_coex_defreeze_work); 21292774f206SBjoern A. Zeeb INIT_DELAYED_WORK(&coex->wl_remain_work, rtw_coex_wl_remain_work); 21302774f206SBjoern A. Zeeb INIT_DELAYED_WORK(&coex->bt_remain_work, rtw_coex_bt_remain_work); 21312774f206SBjoern A. Zeeb INIT_DELAYED_WORK(&coex->wl_connecting_work, rtw_coex_wl_connecting_work); 21322774f206SBjoern A. Zeeb INIT_DELAYED_WORK(&coex->bt_multi_link_remain_work, 21332774f206SBjoern A. Zeeb rtw_coex_bt_multi_link_remain_work); 21342774f206SBjoern A. Zeeb INIT_DELAYED_WORK(&coex->wl_ccklock_work, rtw_coex_wl_ccklock_work); 21352774f206SBjoern A. Zeeb INIT_WORK(&rtwdev->tx_work, rtw_tx_work); 21362774f206SBjoern A. Zeeb INIT_WORK(&rtwdev->c2h_work, rtw_c2h_work); 21379c951734SBjoern A. Zeeb INIT_WORK(&rtwdev->ips_work, rtw_ips_work); 21382774f206SBjoern A. Zeeb INIT_WORK(&rtwdev->fw_recovery_work, rtw_fw_recovery_work); 21399c951734SBjoern A. Zeeb INIT_WORK(&rtwdev->update_beacon_work, rtw_fw_update_beacon_work); 21402774f206SBjoern A. Zeeb INIT_WORK(&rtwdev->ba_work, rtw_txq_ba_work); 21412774f206SBjoern A. Zeeb skb_queue_head_init(&rtwdev->c2h_queue); 21422774f206SBjoern A. Zeeb skb_queue_head_init(&rtwdev->coex.queue); 21432774f206SBjoern A. Zeeb skb_queue_head_init(&rtwdev->tx_report.queue); 21442774f206SBjoern A. Zeeb 21452774f206SBjoern A. Zeeb spin_lock_init(&rtwdev->txq_lock); 21462774f206SBjoern A. Zeeb spin_lock_init(&rtwdev->tx_report.q_lock); 21472774f206SBjoern A. Zeeb 21482774f206SBjoern A. Zeeb mutex_init(&rtwdev->mutex); 21492774f206SBjoern A. Zeeb mutex_init(&rtwdev->hal.tx_power_mutex); 21502774f206SBjoern A. Zeeb 21512774f206SBjoern A. Zeeb init_waitqueue_head(&rtwdev->coex.wait); 21522774f206SBjoern A. Zeeb init_completion(&rtwdev->lps_leave_check); 21532774f206SBjoern A. Zeeb init_completion(&rtwdev->fw_scan_density); 21542774f206SBjoern A. Zeeb 21552774f206SBjoern A. Zeeb rtwdev->sec.total_cam_num = 32; 21562774f206SBjoern A. Zeeb rtwdev->hal.current_channel = 1; 21572774f206SBjoern A. Zeeb rtwdev->dm_info.fix_rate = U8_MAX; 21582774f206SBjoern A. Zeeb set_bit(RTW_BC_MC_MACID, rtwdev->mac_id_map); 21592774f206SBjoern A. Zeeb 21602774f206SBjoern A. Zeeb rtw_stats_init(rtwdev); 21612774f206SBjoern A. Zeeb 21622774f206SBjoern A. Zeeb /* default rx filter setting */ 21632774f206SBjoern A. Zeeb rtwdev->hal.rcr = BIT_APP_FCS | BIT_APP_MIC | BIT_APP_ICV | 21642774f206SBjoern A. Zeeb BIT_PKTCTL_DLEN | BIT_HTC_LOC_CTRL | BIT_APP_PHYSTS | 21652774f206SBjoern A. Zeeb BIT_AB | BIT_AM | BIT_APM; 21662774f206SBjoern A. Zeeb 21672774f206SBjoern A. Zeeb ret = rtw_load_firmware(rtwdev, RTW_NORMAL_FW); 21682774f206SBjoern A. Zeeb if (ret) { 21692774f206SBjoern A. Zeeb rtw_warn(rtwdev, "no firmware loaded\n"); 217090aac0d8SBjoern A. Zeeb goto out; 21712774f206SBjoern A. Zeeb } 21722774f206SBjoern A. Zeeb 21732774f206SBjoern A. Zeeb if (chip->wow_fw_name) { 21742774f206SBjoern A. Zeeb ret = rtw_load_firmware(rtwdev, RTW_WOWLAN_FW); 21752774f206SBjoern A. Zeeb if (ret) { 21762774f206SBjoern A. Zeeb rtw_warn(rtwdev, "no wow firmware loaded\n"); 21772774f206SBjoern A. Zeeb wait_for_completion(&rtwdev->fw.completion); 21782774f206SBjoern A. Zeeb if (rtwdev->fw.firmware) 21792774f206SBjoern A. Zeeb release_firmware(rtwdev->fw.firmware); 218090aac0d8SBjoern A. Zeeb goto out; 21812774f206SBjoern A. Zeeb } 21822774f206SBjoern A. Zeeb } 21832774f206SBjoern A. Zeeb 21842774f206SBjoern A. Zeeb #if defined(__FreeBSD__) 21852774f206SBjoern A. Zeeb rtw_wait_firmware_completion(rtwdev); 21862774f206SBjoern A. Zeeb #endif 21872774f206SBjoern A. Zeeb 21882774f206SBjoern A. Zeeb return 0; 218990aac0d8SBjoern A. Zeeb 219090aac0d8SBjoern A. Zeeb out: 219190aac0d8SBjoern A. Zeeb destroy_workqueue(rtwdev->tx_wq); 219290aac0d8SBjoern A. Zeeb return ret; 21932774f206SBjoern A. Zeeb } 21942774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_core_init); 21952774f206SBjoern A. Zeeb 21962774f206SBjoern A. Zeeb void rtw_core_deinit(struct rtw_dev *rtwdev) 21972774f206SBjoern A. Zeeb { 21982774f206SBjoern A. Zeeb struct rtw_fw_state *fw = &rtwdev->fw; 21992774f206SBjoern A. Zeeb struct rtw_fw_state *wow_fw = &rtwdev->wow_fw; 22002774f206SBjoern A. Zeeb struct rtw_rsvd_page *rsvd_pkt, *tmp; 22012774f206SBjoern A. Zeeb unsigned long flags; 22022774f206SBjoern A. Zeeb 22032774f206SBjoern A. Zeeb rtw_wait_firmware_completion(rtwdev); 22042774f206SBjoern A. Zeeb 22052774f206SBjoern A. Zeeb if (fw->firmware) 22062774f206SBjoern A. Zeeb release_firmware(fw->firmware); 22072774f206SBjoern A. Zeeb 22082774f206SBjoern A. Zeeb if (wow_fw->firmware) 22092774f206SBjoern A. Zeeb release_firmware(wow_fw->firmware); 22102774f206SBjoern A. Zeeb 22112774f206SBjoern A. Zeeb destroy_workqueue(rtwdev->tx_wq); 221290aac0d8SBjoern A. Zeeb timer_delete_sync(&rtwdev->tx_report.purge_timer); 22132774f206SBjoern A. Zeeb spin_lock_irqsave(&rtwdev->tx_report.q_lock, flags); 22142774f206SBjoern A. Zeeb skb_queue_purge(&rtwdev->tx_report.queue); 22152774f206SBjoern A. Zeeb spin_unlock_irqrestore(&rtwdev->tx_report.q_lock, flags); 221690aac0d8SBjoern A. Zeeb skb_queue_purge(&rtwdev->coex.queue); 221790aac0d8SBjoern A. Zeeb skb_queue_purge(&rtwdev->c2h_queue); 22182774f206SBjoern A. Zeeb 22192774f206SBjoern A. Zeeb list_for_each_entry_safe(rsvd_pkt, tmp, &rtwdev->rsvd_page_list, 22202774f206SBjoern A. Zeeb build_list) { 22212774f206SBjoern A. Zeeb list_del(&rsvd_pkt->build_list); 22222774f206SBjoern A. Zeeb kfree(rsvd_pkt); 22232774f206SBjoern A. Zeeb } 22242774f206SBjoern A. Zeeb 22252774f206SBjoern A. Zeeb mutex_destroy(&rtwdev->mutex); 22262774f206SBjoern A. Zeeb mutex_destroy(&rtwdev->hal.tx_power_mutex); 22272774f206SBjoern A. Zeeb } 22282774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_core_deinit); 22292774f206SBjoern A. Zeeb 22302774f206SBjoern A. Zeeb int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) 22312774f206SBjoern A. Zeeb { 2232*11c53278SBjoern A. Zeeb bool sta_mode_only = rtwdev->hci.type == RTW_HCI_TYPE_SDIO; 22332774f206SBjoern A. Zeeb struct rtw_hal *hal = &rtwdev->hal; 22342774f206SBjoern A. Zeeb int max_tx_headroom = 0; 22352774f206SBjoern A. Zeeb int ret; 22362774f206SBjoern A. Zeeb 22372774f206SBjoern A. Zeeb max_tx_headroom = rtwdev->chip->tx_pkt_desc_sz; 22382774f206SBjoern A. Zeeb 223990aac0d8SBjoern A. Zeeb if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) 224090aac0d8SBjoern A. Zeeb max_tx_headroom += RTW_SDIO_DATA_PTR_ALIGN; 224190aac0d8SBjoern A. Zeeb 22422774f206SBjoern A. Zeeb hw->extra_tx_headroom = max_tx_headroom; 22432774f206SBjoern A. Zeeb hw->queues = IEEE80211_NUM_ACS; 22442774f206SBjoern A. Zeeb hw->txq_data_size = sizeof(struct rtw_txq); 22452774f206SBjoern A. Zeeb hw->sta_data_size = sizeof(struct rtw_sta_info); 22462774f206SBjoern A. Zeeb hw->vif_data_size = sizeof(struct rtw_vif); 22472774f206SBjoern A. Zeeb 22482774f206SBjoern A. Zeeb ieee80211_hw_set(hw, SIGNAL_DBM); 22492774f206SBjoern A. Zeeb ieee80211_hw_set(hw, RX_INCLUDES_FCS); 22502774f206SBjoern A. Zeeb ieee80211_hw_set(hw, AMPDU_AGGREGATION); 22512774f206SBjoern A. Zeeb ieee80211_hw_set(hw, MFP_CAPABLE); 22522774f206SBjoern A. Zeeb ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 22532774f206SBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_PS); 22542774f206SBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); 22552774f206SBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 22562774f206SBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 22572774f206SBjoern A. Zeeb ieee80211_hw_set(hw, HAS_RATE_CONTROL); 22582774f206SBjoern A. Zeeb ieee80211_hw_set(hw, TX_AMSDU); 22592774f206SBjoern A. Zeeb ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); 22602774f206SBjoern A. Zeeb 2261*11c53278SBjoern A. Zeeb if (sta_mode_only) 2262*11c53278SBjoern A. Zeeb hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 2263*11c53278SBjoern A. Zeeb else 22642774f206SBjoern A. Zeeb hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 22652774f206SBjoern A. Zeeb BIT(NL80211_IFTYPE_AP) | 2266*11c53278SBjoern A. Zeeb BIT(NL80211_IFTYPE_ADHOC); 22672774f206SBjoern A. Zeeb hw->wiphy->available_antennas_tx = hal->antenna_tx; 22682774f206SBjoern A. Zeeb hw->wiphy->available_antennas_rx = hal->antenna_rx; 22692774f206SBjoern A. Zeeb 22702774f206SBjoern A. Zeeb hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | 22712774f206SBjoern A. Zeeb WIPHY_FLAG_TDLS_EXTERNAL_SETUP; 22722774f206SBjoern A. Zeeb 22732774f206SBjoern A. Zeeb hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; 22742774f206SBjoern A. Zeeb hw->wiphy->max_scan_ssids = RTW_SCAN_MAX_SSIDS; 227590aac0d8SBjoern A. Zeeb hw->wiphy->max_scan_ie_len = rtw_get_max_scan_ie_len(rtwdev); 227690aac0d8SBjoern A. Zeeb 2277*11c53278SBjoern A. Zeeb if (!sta_mode_only && rtwdev->chip->id == RTW_CHIP_TYPE_8822C) { 227890aac0d8SBjoern A. Zeeb hw->wiphy->iface_combinations = rtw_iface_combs; 227990aac0d8SBjoern A. Zeeb hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw_iface_combs); 228090aac0d8SBjoern A. Zeeb } 22812774f206SBjoern A. Zeeb 22822774f206SBjoern A. Zeeb wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); 22832774f206SBjoern A. Zeeb wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SCAN_RANDOM_SN); 22842774f206SBjoern A. Zeeb wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); 22852774f206SBjoern A. Zeeb 22862774f206SBjoern A. Zeeb #ifdef CONFIG_PM 22872774f206SBjoern A. Zeeb hw->wiphy->wowlan = rtwdev->chip->wowlan_stub; 22882774f206SBjoern A. Zeeb hw->wiphy->max_sched_scan_ssids = rtwdev->chip->max_sched_scan_ssids; 22892774f206SBjoern A. Zeeb #endif 22902774f206SBjoern A. Zeeb rtw_set_supported_band(hw, rtwdev->chip); 22912774f206SBjoern A. Zeeb SET_IEEE80211_PERM_ADDR(hw, rtwdev->efuse.addr); 22922774f206SBjoern A. Zeeb 22932774f206SBjoern A. Zeeb hw->wiphy->sar_capa = &rtw_sar_capa; 22942774f206SBjoern A. Zeeb 22952774f206SBjoern A. Zeeb ret = rtw_regd_init(rtwdev); 22962774f206SBjoern A. Zeeb if (ret) { 22972774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to init regd\n"); 22982774f206SBjoern A. Zeeb return ret; 22992774f206SBjoern A. Zeeb } 23002774f206SBjoern A. Zeeb 23012774f206SBjoern A. Zeeb ret = ieee80211_register_hw(hw); 23022774f206SBjoern A. Zeeb if (ret) { 23032774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to register hw\n"); 23042774f206SBjoern A. Zeeb return ret; 23052774f206SBjoern A. Zeeb } 23062774f206SBjoern A. Zeeb 23072774f206SBjoern A. Zeeb ret = rtw_regd_hint(rtwdev); 23082774f206SBjoern A. Zeeb if (ret) { 23092774f206SBjoern A. Zeeb rtw_err(rtwdev, "failed to hint regd\n"); 23102774f206SBjoern A. Zeeb return ret; 23112774f206SBjoern A. Zeeb } 23122774f206SBjoern A. Zeeb 23132774f206SBjoern A. Zeeb rtw_debugfs_init(rtwdev); 23142774f206SBjoern A. Zeeb 23152774f206SBjoern A. Zeeb rtwdev->bf_info.bfer_mu_cnt = 0; 23162774f206SBjoern A. Zeeb rtwdev->bf_info.bfer_su_cnt = 0; 23172774f206SBjoern A. Zeeb 23182774f206SBjoern A. Zeeb return 0; 23192774f206SBjoern A. Zeeb } 23202774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_register_hw); 23212774f206SBjoern A. Zeeb 23222774f206SBjoern A. Zeeb void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) 23232774f206SBjoern A. Zeeb { 232490aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 23252774f206SBjoern A. Zeeb 23262774f206SBjoern A. Zeeb ieee80211_unregister_hw(hw); 23272774f206SBjoern A. Zeeb rtw_unset_supported_band(hw, chip); 23282774f206SBjoern A. Zeeb } 23292774f206SBjoern A. Zeeb EXPORT_SYMBOL(rtw_unregister_hw); 23302774f206SBjoern A. Zeeb 233190aac0d8SBjoern A. Zeeb static 233290aac0d8SBjoern A. Zeeb void rtw_swap_reg_nbytes(struct rtw_dev *rtwdev, const struct rtw_hw_reg *reg1, 233390aac0d8SBjoern A. Zeeb const struct rtw_hw_reg *reg2, u8 nbytes) 233490aac0d8SBjoern A. Zeeb { 233590aac0d8SBjoern A. Zeeb u8 i; 233690aac0d8SBjoern A. Zeeb 233790aac0d8SBjoern A. Zeeb for (i = 0; i < nbytes; i++) { 233890aac0d8SBjoern A. Zeeb u8 v1 = rtw_read8(rtwdev, reg1->addr + i); 233990aac0d8SBjoern A. Zeeb u8 v2 = rtw_read8(rtwdev, reg2->addr + i); 234090aac0d8SBjoern A. Zeeb 234190aac0d8SBjoern A. Zeeb rtw_write8(rtwdev, reg1->addr + i, v2); 234290aac0d8SBjoern A. Zeeb rtw_write8(rtwdev, reg2->addr + i, v1); 234390aac0d8SBjoern A. Zeeb } 234490aac0d8SBjoern A. Zeeb } 234590aac0d8SBjoern A. Zeeb 234690aac0d8SBjoern A. Zeeb static 234790aac0d8SBjoern A. Zeeb void rtw_swap_reg_mask(struct rtw_dev *rtwdev, const struct rtw_hw_reg *reg1, 234890aac0d8SBjoern A. Zeeb const struct rtw_hw_reg *reg2) 234990aac0d8SBjoern A. Zeeb { 235090aac0d8SBjoern A. Zeeb u32 v1, v2; 235190aac0d8SBjoern A. Zeeb 235290aac0d8SBjoern A. Zeeb v1 = rtw_read32_mask(rtwdev, reg1->addr, reg1->mask); 235390aac0d8SBjoern A. Zeeb v2 = rtw_read32_mask(rtwdev, reg2->addr, reg2->mask); 235490aac0d8SBjoern A. Zeeb rtw_write32_mask(rtwdev, reg2->addr, reg2->mask, v1); 235590aac0d8SBjoern A. Zeeb rtw_write32_mask(rtwdev, reg1->addr, reg1->mask, v2); 235690aac0d8SBjoern A. Zeeb } 235790aac0d8SBjoern A. Zeeb 235890aac0d8SBjoern A. Zeeb struct rtw_iter_port_switch_data { 235990aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 236090aac0d8SBjoern A. Zeeb struct rtw_vif *rtwvif_ap; 236190aac0d8SBjoern A. Zeeb }; 236290aac0d8SBjoern A. Zeeb 236390aac0d8SBjoern A. Zeeb static void rtw_port_switch_iter(void *data, struct ieee80211_vif *vif) 236490aac0d8SBjoern A. Zeeb { 236590aac0d8SBjoern A. Zeeb struct rtw_iter_port_switch_data *iter_data = data; 236690aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = iter_data->rtwdev; 236790aac0d8SBjoern A. Zeeb struct rtw_vif *rtwvif_target = (struct rtw_vif *)vif->drv_priv; 236890aac0d8SBjoern A. Zeeb struct rtw_vif *rtwvif_ap = iter_data->rtwvif_ap; 236990aac0d8SBjoern A. Zeeb const struct rtw_hw_reg *reg1, *reg2; 237090aac0d8SBjoern A. Zeeb 237190aac0d8SBjoern A. Zeeb if (rtwvif_target->port != RTW_PORT_0) 237290aac0d8SBjoern A. Zeeb return; 237390aac0d8SBjoern A. Zeeb 237490aac0d8SBjoern A. Zeeb rtw_dbg(rtwdev, RTW_DBG_STATE, "AP port switch from %d -> %d\n", 237590aac0d8SBjoern A. Zeeb rtwvif_ap->port, rtwvif_target->port); 237690aac0d8SBjoern A. Zeeb 237790aac0d8SBjoern A. Zeeb /* Leave LPS so the value swapped are not in PS mode */ 237890aac0d8SBjoern A. Zeeb rtw_leave_lps(rtwdev); 237990aac0d8SBjoern A. Zeeb 238090aac0d8SBjoern A. Zeeb reg1 = &rtwvif_ap->conf->net_type; 238190aac0d8SBjoern A. Zeeb reg2 = &rtwvif_target->conf->net_type; 238290aac0d8SBjoern A. Zeeb rtw_swap_reg_mask(rtwdev, reg1, reg2); 238390aac0d8SBjoern A. Zeeb 238490aac0d8SBjoern A. Zeeb reg1 = &rtwvif_ap->conf->mac_addr; 238590aac0d8SBjoern A. Zeeb reg2 = &rtwvif_target->conf->mac_addr; 238690aac0d8SBjoern A. Zeeb rtw_swap_reg_nbytes(rtwdev, reg1, reg2, ETH_ALEN); 238790aac0d8SBjoern A. Zeeb 238890aac0d8SBjoern A. Zeeb reg1 = &rtwvif_ap->conf->bssid; 238990aac0d8SBjoern A. Zeeb reg2 = &rtwvif_target->conf->bssid; 239090aac0d8SBjoern A. Zeeb rtw_swap_reg_nbytes(rtwdev, reg1, reg2, ETH_ALEN); 239190aac0d8SBjoern A. Zeeb 239290aac0d8SBjoern A. Zeeb reg1 = &rtwvif_ap->conf->bcn_ctrl; 239390aac0d8SBjoern A. Zeeb reg2 = &rtwvif_target->conf->bcn_ctrl; 239490aac0d8SBjoern A. Zeeb rtw_swap_reg_nbytes(rtwdev, reg1, reg2, 1); 239590aac0d8SBjoern A. Zeeb 239690aac0d8SBjoern A. Zeeb swap(rtwvif_target->port, rtwvif_ap->port); 239790aac0d8SBjoern A. Zeeb swap(rtwvif_target->conf, rtwvif_ap->conf); 239890aac0d8SBjoern A. Zeeb 239990aac0d8SBjoern A. Zeeb rtw_fw_default_port(rtwdev, rtwvif_target); 240090aac0d8SBjoern A. Zeeb } 240190aac0d8SBjoern A. Zeeb 240290aac0d8SBjoern A. Zeeb void rtw_core_port_switch(struct rtw_dev *rtwdev, struct ieee80211_vif *vif) 240390aac0d8SBjoern A. Zeeb { 240490aac0d8SBjoern A. Zeeb struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 240590aac0d8SBjoern A. Zeeb struct rtw_iter_port_switch_data iter_data; 240690aac0d8SBjoern A. Zeeb 240790aac0d8SBjoern A. Zeeb if (vif->type != NL80211_IFTYPE_AP || rtwvif->port == RTW_PORT_0) 240890aac0d8SBjoern A. Zeeb return; 240990aac0d8SBjoern A. Zeeb 241090aac0d8SBjoern A. Zeeb iter_data.rtwdev = rtwdev; 241190aac0d8SBjoern A. Zeeb iter_data.rtwvif_ap = rtwvif; 241290aac0d8SBjoern A. Zeeb rtw_iterate_vifs(rtwdev, rtw_port_switch_iter, &iter_data); 241390aac0d8SBjoern A. Zeeb } 241490aac0d8SBjoern A. Zeeb 241590aac0d8SBjoern A. Zeeb static void rtw_check_sta_active_iter(void *data, struct ieee80211_vif *vif) 241690aac0d8SBjoern A. Zeeb { 241790aac0d8SBjoern A. Zeeb struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 241890aac0d8SBjoern A. Zeeb bool *active = data; 241990aac0d8SBjoern A. Zeeb 242090aac0d8SBjoern A. Zeeb if (*active) 242190aac0d8SBjoern A. Zeeb return; 242290aac0d8SBjoern A. Zeeb 242390aac0d8SBjoern A. Zeeb if (vif->type != NL80211_IFTYPE_STATION) 242490aac0d8SBjoern A. Zeeb return; 242590aac0d8SBjoern A. Zeeb 242690aac0d8SBjoern A. Zeeb if (vif->cfg.assoc || !is_zero_ether_addr(rtwvif->bssid)) 242790aac0d8SBjoern A. Zeeb *active = true; 242890aac0d8SBjoern A. Zeeb } 242990aac0d8SBjoern A. Zeeb 243090aac0d8SBjoern A. Zeeb bool rtw_core_check_sta_active(struct rtw_dev *rtwdev) 243190aac0d8SBjoern A. Zeeb { 243290aac0d8SBjoern A. Zeeb bool sta_active = false; 243390aac0d8SBjoern A. Zeeb 243490aac0d8SBjoern A. Zeeb rtw_iterate_vifs(rtwdev, rtw_check_sta_active_iter, &sta_active); 243590aac0d8SBjoern A. Zeeb 243690aac0d8SBjoern A. Zeeb return rtwdev->ap_active || sta_active; 243790aac0d8SBjoern A. Zeeb } 243890aac0d8SBjoern A. Zeeb 243990aac0d8SBjoern A. Zeeb void rtw_core_enable_beacon(struct rtw_dev *rtwdev, bool enable) 244090aac0d8SBjoern A. Zeeb { 244190aac0d8SBjoern A. Zeeb if (!rtwdev->ap_active) 244290aac0d8SBjoern A. Zeeb return; 244390aac0d8SBjoern A. Zeeb 244490aac0d8SBjoern A. Zeeb if (enable) { 244590aac0d8SBjoern A. Zeeb rtw_write32_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); 244690aac0d8SBjoern A. Zeeb rtw_write32_clr(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); 244790aac0d8SBjoern A. Zeeb } else { 244890aac0d8SBjoern A. Zeeb rtw_write32_clr(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); 244990aac0d8SBjoern A. Zeeb rtw_write32_set(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); 245090aac0d8SBjoern A. Zeeb } 245190aac0d8SBjoern A. Zeeb } 245290aac0d8SBjoern A. Zeeb 24532774f206SBjoern A. Zeeb MODULE_AUTHOR("Realtek Corporation"); 24542774f206SBjoern A. Zeeb MODULE_DESCRIPTION("Realtek 802.11ac wireless core module"); 24552774f206SBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL"); 2456