162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright(c) 2018-2019 Realtek Corporation 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/devcoredump.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "main.h" 862306a36Sopenharmony_ci#include "regd.h" 962306a36Sopenharmony_ci#include "fw.h" 1062306a36Sopenharmony_ci#include "ps.h" 1162306a36Sopenharmony_ci#include "sec.h" 1262306a36Sopenharmony_ci#include "mac.h" 1362306a36Sopenharmony_ci#include "coex.h" 1462306a36Sopenharmony_ci#include "phy.h" 1562306a36Sopenharmony_ci#include "reg.h" 1662306a36Sopenharmony_ci#include "efuse.h" 1762306a36Sopenharmony_ci#include "tx.h" 1862306a36Sopenharmony_ci#include "debug.h" 1962306a36Sopenharmony_ci#include "bf.h" 2062306a36Sopenharmony_ci#include "sar.h" 2162306a36Sopenharmony_ci#include "sdio.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cibool rtw_disable_lps_deep_mode; 2462306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_disable_lps_deep_mode); 2562306a36Sopenharmony_cibool rtw_bf_support = true; 2662306a36Sopenharmony_ciunsigned int rtw_debug_mask; 2762306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_debug_mask); 2862306a36Sopenharmony_ci/* EDCCA is enabled during normal behavior. For debugging purpose in 2962306a36Sopenharmony_ci * a noisy environment, it can be disabled via edcca debugfs. Because 3062306a36Sopenharmony_ci * all rtw88 devices will probably be affected if environment is noisy, 3162306a36Sopenharmony_ci * rtw_edcca_enabled is just declared by driver instead of by device. 3262306a36Sopenharmony_ci * So, turning it off will take effect for all rtw88 devices before 3362306a36Sopenharmony_ci * there is a tough reason to maintain rtw_edcca_enabled by device. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_cibool rtw_edcca_enabled = true; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cimodule_param_named(disable_lps_deep, rtw_disable_lps_deep_mode, bool, 0644); 3862306a36Sopenharmony_cimodule_param_named(support_bf, rtw_bf_support, bool, 0644); 3962306a36Sopenharmony_cimodule_param_named(debug_mask, rtw_debug_mask, uint, 0644); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciMODULE_PARM_DESC(disable_lps_deep, "Set Y to disable Deep PS"); 4262306a36Sopenharmony_ciMODULE_PARM_DESC(support_bf, "Set Y to enable beamformee support"); 4362306a36Sopenharmony_ciMODULE_PARM_DESC(debug_mask, "Debugging mask"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic struct ieee80211_channel rtw_channeltable_2g[] = { 4662306a36Sopenharmony_ci {.center_freq = 2412, .hw_value = 1,}, 4762306a36Sopenharmony_ci {.center_freq = 2417, .hw_value = 2,}, 4862306a36Sopenharmony_ci {.center_freq = 2422, .hw_value = 3,}, 4962306a36Sopenharmony_ci {.center_freq = 2427, .hw_value = 4,}, 5062306a36Sopenharmony_ci {.center_freq = 2432, .hw_value = 5,}, 5162306a36Sopenharmony_ci {.center_freq = 2437, .hw_value = 6,}, 5262306a36Sopenharmony_ci {.center_freq = 2442, .hw_value = 7,}, 5362306a36Sopenharmony_ci {.center_freq = 2447, .hw_value = 8,}, 5462306a36Sopenharmony_ci {.center_freq = 2452, .hw_value = 9,}, 5562306a36Sopenharmony_ci {.center_freq = 2457, .hw_value = 10,}, 5662306a36Sopenharmony_ci {.center_freq = 2462, .hw_value = 11,}, 5762306a36Sopenharmony_ci {.center_freq = 2467, .hw_value = 12,}, 5862306a36Sopenharmony_ci {.center_freq = 2472, .hw_value = 13,}, 5962306a36Sopenharmony_ci {.center_freq = 2484, .hw_value = 14,}, 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic struct ieee80211_channel rtw_channeltable_5g[] = { 6362306a36Sopenharmony_ci {.center_freq = 5180, .hw_value = 36,}, 6462306a36Sopenharmony_ci {.center_freq = 5200, .hw_value = 40,}, 6562306a36Sopenharmony_ci {.center_freq = 5220, .hw_value = 44,}, 6662306a36Sopenharmony_ci {.center_freq = 5240, .hw_value = 48,}, 6762306a36Sopenharmony_ci {.center_freq = 5260, .hw_value = 52,}, 6862306a36Sopenharmony_ci {.center_freq = 5280, .hw_value = 56,}, 6962306a36Sopenharmony_ci {.center_freq = 5300, .hw_value = 60,}, 7062306a36Sopenharmony_ci {.center_freq = 5320, .hw_value = 64,}, 7162306a36Sopenharmony_ci {.center_freq = 5500, .hw_value = 100,}, 7262306a36Sopenharmony_ci {.center_freq = 5520, .hw_value = 104,}, 7362306a36Sopenharmony_ci {.center_freq = 5540, .hw_value = 108,}, 7462306a36Sopenharmony_ci {.center_freq = 5560, .hw_value = 112,}, 7562306a36Sopenharmony_ci {.center_freq = 5580, .hw_value = 116,}, 7662306a36Sopenharmony_ci {.center_freq = 5600, .hw_value = 120,}, 7762306a36Sopenharmony_ci {.center_freq = 5620, .hw_value = 124,}, 7862306a36Sopenharmony_ci {.center_freq = 5640, .hw_value = 128,}, 7962306a36Sopenharmony_ci {.center_freq = 5660, .hw_value = 132,}, 8062306a36Sopenharmony_ci {.center_freq = 5680, .hw_value = 136,}, 8162306a36Sopenharmony_ci {.center_freq = 5700, .hw_value = 140,}, 8262306a36Sopenharmony_ci {.center_freq = 5720, .hw_value = 144,}, 8362306a36Sopenharmony_ci {.center_freq = 5745, .hw_value = 149,}, 8462306a36Sopenharmony_ci {.center_freq = 5765, .hw_value = 153,}, 8562306a36Sopenharmony_ci {.center_freq = 5785, .hw_value = 157,}, 8662306a36Sopenharmony_ci {.center_freq = 5805, .hw_value = 161,}, 8762306a36Sopenharmony_ci {.center_freq = 5825, .hw_value = 165, 8862306a36Sopenharmony_ci .flags = IEEE80211_CHAN_NO_HT40MINUS}, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic struct ieee80211_rate rtw_ratetable[] = { 9262306a36Sopenharmony_ci {.bitrate = 10, .hw_value = 0x00,}, 9362306a36Sopenharmony_ci {.bitrate = 20, .hw_value = 0x01,}, 9462306a36Sopenharmony_ci {.bitrate = 55, .hw_value = 0x02,}, 9562306a36Sopenharmony_ci {.bitrate = 110, .hw_value = 0x03,}, 9662306a36Sopenharmony_ci {.bitrate = 60, .hw_value = 0x04,}, 9762306a36Sopenharmony_ci {.bitrate = 90, .hw_value = 0x05,}, 9862306a36Sopenharmony_ci {.bitrate = 120, .hw_value = 0x06,}, 9962306a36Sopenharmony_ci {.bitrate = 180, .hw_value = 0x07,}, 10062306a36Sopenharmony_ci {.bitrate = 240, .hw_value = 0x08,}, 10162306a36Sopenharmony_ci {.bitrate = 360, .hw_value = 0x09,}, 10262306a36Sopenharmony_ci {.bitrate = 480, .hw_value = 0x0a,}, 10362306a36Sopenharmony_ci {.bitrate = 540, .hw_value = 0x0b,}, 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic const struct ieee80211_iface_limit rtw_iface_limits[] = { 10762306a36Sopenharmony_ci { 10862306a36Sopenharmony_ci .max = 1, 10962306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION), 11062306a36Sopenharmony_ci }, 11162306a36Sopenharmony_ci { 11262306a36Sopenharmony_ci .max = 1, 11362306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_AP), 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic const struct ieee80211_iface_combination rtw_iface_combs[] = { 11862306a36Sopenharmony_ci { 11962306a36Sopenharmony_ci .limits = rtw_iface_limits, 12062306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(rtw_iface_limits), 12162306a36Sopenharmony_ci .max_interfaces = 2, 12262306a36Sopenharmony_ci .num_different_channels = 1, 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ciu16 rtw_desc_to_bitrate(u8 desc_rate) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct ieee80211_rate rate; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (WARN(desc_rate >= ARRAY_SIZE(rtw_ratetable), "invalid desc rate\n")) 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci rate = rtw_ratetable[desc_rate]; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return rate.bitrate; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic struct ieee80211_supported_band rtw_band_2ghz = { 13962306a36Sopenharmony_ci .band = NL80211_BAND_2GHZ, 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci .channels = rtw_channeltable_2g, 14262306a36Sopenharmony_ci .n_channels = ARRAY_SIZE(rtw_channeltable_2g), 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci .bitrates = rtw_ratetable, 14562306a36Sopenharmony_ci .n_bitrates = ARRAY_SIZE(rtw_ratetable), 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci .ht_cap = {0}, 14862306a36Sopenharmony_ci .vht_cap = {0}, 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic struct ieee80211_supported_band rtw_band_5ghz = { 15262306a36Sopenharmony_ci .band = NL80211_BAND_5GHZ, 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci .channels = rtw_channeltable_5g, 15562306a36Sopenharmony_ci .n_channels = ARRAY_SIZE(rtw_channeltable_5g), 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* 5G has no CCK rates */ 15862306a36Sopenharmony_ci .bitrates = rtw_ratetable + 4, 15962306a36Sopenharmony_ci .n_bitrates = ARRAY_SIZE(rtw_ratetable) - 4, 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci .ht_cap = {0}, 16262306a36Sopenharmony_ci .vht_cap = {0}, 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistruct rtw_watch_dog_iter_data { 16662306a36Sopenharmony_ci struct rtw_dev *rtwdev; 16762306a36Sopenharmony_ci struct rtw_vif *rtwvif; 16862306a36Sopenharmony_ci}; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void rtw_dynamic_csi_rate(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct rtw_bf_info *bf_info = &rtwdev->bf_info; 17362306a36Sopenharmony_ci u8 fix_rate_enable = 0; 17462306a36Sopenharmony_ci u8 new_csi_rate_idx; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (rtwvif->bfee.role != RTW_BFEE_SU && 17762306a36Sopenharmony_ci rtwvif->bfee.role != RTW_BFEE_MU) 17862306a36Sopenharmony_ci return; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci rtw_chip_cfg_csi_rate(rtwdev, rtwdev->dm_info.min_rssi, 18162306a36Sopenharmony_ci bf_info->cur_csi_rpt_rate, 18262306a36Sopenharmony_ci fix_rate_enable, &new_csi_rate_idx); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (new_csi_rate_idx != bf_info->cur_csi_rpt_rate) 18562306a36Sopenharmony_ci bf_info->cur_csi_rpt_rate = new_csi_rate_idx; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void rtw_vif_watch_dog_iter(void *data, struct ieee80211_vif *vif) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct rtw_watch_dog_iter_data *iter_data = data; 19162306a36Sopenharmony_ci struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 19462306a36Sopenharmony_ci if (vif->cfg.assoc) 19562306a36Sopenharmony_ci iter_data->rtwvif = rtwvif; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci rtw_dynamic_csi_rate(iter_data->rtwdev, rtwvif); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci rtwvif->stats.tx_unicast = 0; 20062306a36Sopenharmony_ci rtwvif->stats.rx_unicast = 0; 20162306a36Sopenharmony_ci rtwvif->stats.tx_cnt = 0; 20262306a36Sopenharmony_ci rtwvif->stats.rx_cnt = 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* process TX/RX statistics periodically for hardware, 20662306a36Sopenharmony_ci * the information helps hardware to enhance performance 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistatic void rtw_watch_dog_work(struct work_struct *work) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, 21162306a36Sopenharmony_ci watch_dog_work.work); 21262306a36Sopenharmony_ci struct rtw_traffic_stats *stats = &rtwdev->stats; 21362306a36Sopenharmony_ci struct rtw_watch_dog_iter_data data = {}; 21462306a36Sopenharmony_ci bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); 21562306a36Sopenharmony_ci bool ps_active; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) 22062306a36Sopenharmony_ci goto unlock; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work, 22362306a36Sopenharmony_ci RTW_WATCH_DOG_DELAY_TIME); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (rtwdev->stats.tx_cnt > 100 || rtwdev->stats.rx_cnt > 100) 22662306a36Sopenharmony_ci set_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); 22762306a36Sopenharmony_ci else 22862306a36Sopenharmony_ci clear_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci rtw_coex_wl_status_check(rtwdev); 23162306a36Sopenharmony_ci rtw_coex_query_bt_hid_list(rtwdev); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (busy_traffic != test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags)) 23462306a36Sopenharmony_ci rtw_coex_wl_status_change_notify(rtwdev, 0); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (stats->tx_cnt > RTW_LPS_THRESHOLD || 23762306a36Sopenharmony_ci stats->rx_cnt > RTW_LPS_THRESHOLD) 23862306a36Sopenharmony_ci ps_active = true; 23962306a36Sopenharmony_ci else 24062306a36Sopenharmony_ci ps_active = false; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci ewma_tp_add(&stats->tx_ewma_tp, 24362306a36Sopenharmony_ci (u32)(stats->tx_unicast >> RTW_TP_SHIFT)); 24462306a36Sopenharmony_ci ewma_tp_add(&stats->rx_ewma_tp, 24562306a36Sopenharmony_ci (u32)(stats->rx_unicast >> RTW_TP_SHIFT)); 24662306a36Sopenharmony_ci stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp); 24762306a36Sopenharmony_ci stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* reset tx/rx statictics */ 25062306a36Sopenharmony_ci stats->tx_unicast = 0; 25162306a36Sopenharmony_ci stats->rx_unicast = 0; 25262306a36Sopenharmony_ci stats->tx_cnt = 0; 25362306a36Sopenharmony_ci stats->rx_cnt = 0; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) 25662306a36Sopenharmony_ci goto unlock; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* make sure BB/RF is working for dynamic mech */ 25962306a36Sopenharmony_ci rtw_leave_lps(rtwdev); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci rtw_phy_dynamic_mechanism(rtwdev); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci data.rtwdev = rtwdev; 26462306a36Sopenharmony_ci /* rtw_iterate_vifs internally uses an atomic iterator which is needed 26562306a36Sopenharmony_ci * to avoid taking local->iflist_mtx mutex 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_ci rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* fw supports only one station associated to enter lps, if there are 27062306a36Sopenharmony_ci * more than two stations associated to the AP, then we can not enter 27162306a36Sopenharmony_ci * lps, because fw does not handle the overlapped beacon interval 27262306a36Sopenharmony_ci * 27362306a36Sopenharmony_ci * rtw_recalc_lps() iterate vifs and determine if driver can enter 27462306a36Sopenharmony_ci * ps by vif->type and vif->cfg.ps, all we need to do here is to 27562306a36Sopenharmony_ci * get that vif and check if device is having traffic more than the 27662306a36Sopenharmony_ci * threshold. 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_ci if (rtwdev->ps_enabled && data.rtwvif && !ps_active && 27962306a36Sopenharmony_ci !rtwdev->beacon_loss && !rtwdev->ap_active) 28062306a36Sopenharmony_ci rtw_enter_lps(rtwdev, data.rtwvif->port); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci rtwdev->watch_dog_cnt++; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ciunlock: 28562306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic void rtw_c2h_work(struct work_struct *work) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, c2h_work); 29162306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci skb_queue_walk_safe(&rtwdev->c2h_queue, skb, tmp) { 29462306a36Sopenharmony_ci skb_unlink(skb, &rtwdev->c2h_queue); 29562306a36Sopenharmony_ci rtw_fw_c2h_cmd_handle(rtwdev, skb); 29662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void rtw_ips_work(struct work_struct *work) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, ips_work); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 30562306a36Sopenharmony_ci if (rtwdev->hw->conf.flags & IEEE80211_CONF_IDLE) 30662306a36Sopenharmony_ci rtw_enter_ips(rtwdev); 30762306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic u8 rtw_acquire_macid(struct rtw_dev *rtwdev) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci unsigned long mac_id; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci mac_id = find_first_zero_bit(rtwdev->mac_id_map, RTW_MAX_MAC_ID_NUM); 31562306a36Sopenharmony_ci if (mac_id < RTW_MAX_MAC_ID_NUM) 31662306a36Sopenharmony_ci set_bit(mac_id, rtwdev->mac_id_map); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return mac_id; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void rtw_sta_rc_work(struct work_struct *work) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct rtw_sta_info *si = container_of(work, struct rtw_sta_info, 32462306a36Sopenharmony_ci rc_work); 32562306a36Sopenharmony_ci struct rtw_dev *rtwdev = si->rtwdev; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 32862306a36Sopenharmony_ci rtw_update_sta_info(rtwdev, si, true); 32962306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ciint rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, 33362306a36Sopenharmony_ci struct ieee80211_vif *vif) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; 33662306a36Sopenharmony_ci struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 33762306a36Sopenharmony_ci int i; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci si->mac_id = rtw_acquire_macid(rtwdev); 34062306a36Sopenharmony_ci if (si->mac_id >= RTW_MAX_MAC_ID_NUM) 34162306a36Sopenharmony_ci return -ENOSPC; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc == 0) 34462306a36Sopenharmony_ci rtwvif->mac_id = si->mac_id; 34562306a36Sopenharmony_ci si->rtwdev = rtwdev; 34662306a36Sopenharmony_ci si->sta = sta; 34762306a36Sopenharmony_ci si->vif = vif; 34862306a36Sopenharmony_ci si->init_ra_lv = 1; 34962306a36Sopenharmony_ci ewma_rssi_init(&si->avg_rssi); 35062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->txq); i++) 35162306a36Sopenharmony_ci rtw_txq_init(rtwdev, sta->txq[i]); 35262306a36Sopenharmony_ci INIT_WORK(&si->rc_work, rtw_sta_rc_work); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci rtw_update_sta_info(rtwdev, si, true); 35562306a36Sopenharmony_ci rtw_fw_media_status_report(rtwdev, si->mac_id, true); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci rtwdev->sta_cnt++; 35862306a36Sopenharmony_ci rtwdev->beacon_loss = false; 35962306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_STATE, "sta %pM joined with macid %d\n", 36062306a36Sopenharmony_ci sta->addr, si->mac_id); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_civoid rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, 36662306a36Sopenharmony_ci bool fw_exist) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; 36962306a36Sopenharmony_ci int i; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci cancel_work_sync(&si->rc_work); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci rtw_release_macid(rtwdev, si->mac_id); 37462306a36Sopenharmony_ci if (fw_exist) 37562306a36Sopenharmony_ci rtw_fw_media_status_report(rtwdev, si->mac_id, false); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->txq); i++) 37862306a36Sopenharmony_ci rtw_txq_cleanup(rtwdev, sta->txq[i]); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci kfree(si->mask); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci rtwdev->sta_cnt--; 38362306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_STATE, "sta %pM with macid %d left\n", 38462306a36Sopenharmony_ci sta->addr, si->mac_id); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistruct rtw_fwcd_hdr { 38862306a36Sopenharmony_ci u32 item; 38962306a36Sopenharmony_ci u32 size; 39062306a36Sopenharmony_ci u32 padding1; 39162306a36Sopenharmony_ci u32 padding2; 39262306a36Sopenharmony_ci} __packed; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int rtw_fwcd_prep(struct rtw_dev *rtwdev) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 39762306a36Sopenharmony_ci struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; 39862306a36Sopenharmony_ci const struct rtw_fwcd_segs *segs = chip->fwcd_segs; 39962306a36Sopenharmony_ci u32 prep_size = chip->fw_rxff_size + sizeof(struct rtw_fwcd_hdr); 40062306a36Sopenharmony_ci u8 i; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (segs) { 40362306a36Sopenharmony_ci prep_size += segs->num * sizeof(struct rtw_fwcd_hdr); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci for (i = 0; i < segs->num; i++) 40662306a36Sopenharmony_ci prep_size += segs->segs[i]; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci desc->data = vmalloc(prep_size); 41062306a36Sopenharmony_ci if (!desc->data) 41162306a36Sopenharmony_ci return -ENOMEM; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci desc->size = prep_size; 41462306a36Sopenharmony_ci desc->next = desc->data; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic u8 *rtw_fwcd_next(struct rtw_dev *rtwdev, u32 item, u32 size) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; 42262306a36Sopenharmony_ci struct rtw_fwcd_hdr *hdr; 42362306a36Sopenharmony_ci u8 *next; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (!desc->data) { 42662306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_FW, "fwcd isn't prepared successfully\n"); 42762306a36Sopenharmony_ci return NULL; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci next = desc->next + sizeof(struct rtw_fwcd_hdr); 43162306a36Sopenharmony_ci if (next - desc->data + size > desc->size) { 43262306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_FW, "fwcd isn't prepared enough\n"); 43362306a36Sopenharmony_ci return NULL; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci hdr = (struct rtw_fwcd_hdr *)(desc->next); 43762306a36Sopenharmony_ci hdr->item = item; 43862306a36Sopenharmony_ci hdr->size = size; 43962306a36Sopenharmony_ci hdr->padding1 = 0x01234567; 44062306a36Sopenharmony_ci hdr->padding2 = 0x89abcdef; 44162306a36Sopenharmony_ci desc->next = next + size; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return next; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic void rtw_fwcd_dump(struct rtw_dev *rtwdev) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_FW, "dump fwcd\n"); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* Data will be freed after lifetime of device coredump. After calling 45362306a36Sopenharmony_ci * dev_coredump, data is supposed to be handled by the device coredump 45462306a36Sopenharmony_ci * framework. Note that a new dump will be discarded if a previous one 45562306a36Sopenharmony_ci * hasn't been released yet. 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci dev_coredumpv(rtwdev->dev, desc->data, desc->size, GFP_KERNEL); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic void rtw_fwcd_free(struct rtw_dev *rtwdev, bool free_self) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (free_self) { 46562306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_FW, "free fwcd by self\n"); 46662306a36Sopenharmony_ci vfree(desc->data); 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci desc->data = NULL; 47062306a36Sopenharmony_ci desc->next = NULL; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int rtw_fw_dump_crash_log(struct rtw_dev *rtwdev) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci u32 size = rtwdev->chip->fw_rxff_size; 47662306a36Sopenharmony_ci u32 *buf; 47762306a36Sopenharmony_ci u8 seq; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci buf = (u32 *)rtw_fwcd_next(rtwdev, RTW_FWCD_TLV, size); 48062306a36Sopenharmony_ci if (!buf) 48162306a36Sopenharmony_ci return -ENOMEM; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0, size, buf)) { 48462306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_FW, "dump fw fifo fail\n"); 48562306a36Sopenharmony_ci return -EINVAL; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (GET_FW_DUMP_LEN(buf) == 0) { 48962306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_FW, "fw crash dump's length is 0\n"); 49062306a36Sopenharmony_ci return -EINVAL; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci seq = GET_FW_DUMP_SEQ(buf); 49462306a36Sopenharmony_ci if (seq > 0) { 49562306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_FW, 49662306a36Sopenharmony_ci "fw crash dump's seq is wrong: %d\n", seq); 49762306a36Sopenharmony_ci return -EINVAL; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ciint rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, 50462306a36Sopenharmony_ci u32 fwcd_item) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci u32 rxff = rtwdev->chip->fw_rxff_size; 50762306a36Sopenharmony_ci u32 dump_size, done_size = 0; 50862306a36Sopenharmony_ci u8 *buf; 50962306a36Sopenharmony_ci int ret; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci buf = rtw_fwcd_next(rtwdev, fwcd_item, size); 51262306a36Sopenharmony_ci if (!buf) 51362306a36Sopenharmony_ci return -ENOMEM; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci while (size) { 51662306a36Sopenharmony_ci dump_size = size > rxff ? rxff : size; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci ret = rtw_ddma_to_fw_fifo(rtwdev, ocp_src + done_size, 51962306a36Sopenharmony_ci dump_size); 52062306a36Sopenharmony_ci if (ret) { 52162306a36Sopenharmony_ci rtw_err(rtwdev, 52262306a36Sopenharmony_ci "ddma fw 0x%x [+0x%x] to fw fifo fail\n", 52362306a36Sopenharmony_ci ocp_src, done_size); 52462306a36Sopenharmony_ci return ret; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci ret = rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0, 52862306a36Sopenharmony_ci dump_size, (u32 *)(buf + done_size)); 52962306a36Sopenharmony_ci if (ret) { 53062306a36Sopenharmony_ci rtw_err(rtwdev, 53162306a36Sopenharmony_ci "dump fw 0x%x [+0x%x] from fw fifo fail\n", 53262306a36Sopenharmony_ci ocp_src, done_size); 53362306a36Sopenharmony_ci return ret; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci size -= dump_size; 53762306a36Sopenharmony_ci done_size += dump_size; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_dump_fw); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ciint rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci u8 *buf; 54762306a36Sopenharmony_ci u32 i; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (addr & 0x3) { 55062306a36Sopenharmony_ci WARN(1, "should be 4-byte aligned, addr = 0x%08x\n", addr); 55162306a36Sopenharmony_ci return -EINVAL; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci buf = rtw_fwcd_next(rtwdev, RTW_FWCD_REG, size); 55562306a36Sopenharmony_ci if (!buf) 55662306a36Sopenharmony_ci return -ENOMEM; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci for (i = 0; i < size; i += 4) 55962306a36Sopenharmony_ci *(u32 *)(buf + i) = rtw_read32(rtwdev, addr + i); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return 0; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_dump_reg); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_civoid rtw_vif_assoc_changed(struct rtw_vif *rtwvif, 56662306a36Sopenharmony_ci struct ieee80211_bss_conf *conf) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct ieee80211_vif *vif = NULL; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (conf) 57162306a36Sopenharmony_ci vif = container_of(conf, struct ieee80211_vif, bss_conf); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (conf && vif->cfg.assoc) { 57462306a36Sopenharmony_ci rtwvif->aid = vif->cfg.aid; 57562306a36Sopenharmony_ci rtwvif->net_type = RTW_NET_MGD_LINKED; 57662306a36Sopenharmony_ci } else { 57762306a36Sopenharmony_ci rtwvif->aid = 0; 57862306a36Sopenharmony_ci rtwvif->net_type = RTW_NET_NO_LINK; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic void rtw_reset_key_iter(struct ieee80211_hw *hw, 58362306a36Sopenharmony_ci struct ieee80211_vif *vif, 58462306a36Sopenharmony_ci struct ieee80211_sta *sta, 58562306a36Sopenharmony_ci struct ieee80211_key_conf *key, 58662306a36Sopenharmony_ci void *data) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct rtw_dev *rtwdev = (struct rtw_dev *)data; 58962306a36Sopenharmony_ci struct rtw_sec_desc *sec = &rtwdev->sec; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci rtw_sec_clear_cam(rtwdev, sec, key->hw_key_idx); 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic void rtw_reset_sta_iter(void *data, struct ieee80211_sta *sta) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct rtw_dev *rtwdev = (struct rtw_dev *)data; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (rtwdev->sta_cnt == 0) { 59962306a36Sopenharmony_ci rtw_warn(rtwdev, "sta count before reset should not be 0\n"); 60062306a36Sopenharmony_ci return; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci rtw_sta_remove(rtwdev, sta, false); 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic void rtw_reset_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct rtw_dev *rtwdev = (struct rtw_dev *)data; 60862306a36Sopenharmony_ci struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci rtw_bf_disassoc(rtwdev, vif, NULL); 61162306a36Sopenharmony_ci rtw_vif_assoc_changed(rtwvif, NULL); 61262306a36Sopenharmony_ci rtw_txq_cleanup(rtwdev, vif->txq); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_civoid rtw_fw_recovery(struct rtw_dev *rtwdev) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci if (!test_bit(RTW_FLAG_RESTARTING, rtwdev->flags)) 61862306a36Sopenharmony_ci ieee80211_queue_work(rtwdev->hw, &rtwdev->fw_recovery_work); 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic void __fw_recovery_work(struct rtw_dev *rtwdev) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci int ret = 0; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci set_bit(RTW_FLAG_RESTARTING, rtwdev->flags); 62662306a36Sopenharmony_ci clear_bit(RTW_FLAG_RESTART_TRIGGERING, rtwdev->flags); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci ret = rtw_fwcd_prep(rtwdev); 62962306a36Sopenharmony_ci if (ret) 63062306a36Sopenharmony_ci goto free; 63162306a36Sopenharmony_ci ret = rtw_fw_dump_crash_log(rtwdev); 63262306a36Sopenharmony_ci if (ret) 63362306a36Sopenharmony_ci goto free; 63462306a36Sopenharmony_ci ret = rtw_chip_dump_fw_crash(rtwdev); 63562306a36Sopenharmony_ci if (ret) 63662306a36Sopenharmony_ci goto free; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci rtw_fwcd_dump(rtwdev); 63962306a36Sopenharmony_cifree: 64062306a36Sopenharmony_ci rtw_fwcd_free(rtwdev, !!ret); 64162306a36Sopenharmony_ci rtw_write8(rtwdev, REG_MCU_TST_CFG, 0); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci WARN(1, "firmware crash, start reset and recover\n"); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci rcu_read_lock(); 64662306a36Sopenharmony_ci rtw_iterate_keys_rcu(rtwdev, NULL, rtw_reset_key_iter, rtwdev); 64762306a36Sopenharmony_ci rcu_read_unlock(); 64862306a36Sopenharmony_ci rtw_iterate_stas_atomic(rtwdev, rtw_reset_sta_iter, rtwdev); 64962306a36Sopenharmony_ci rtw_iterate_vifs_atomic(rtwdev, rtw_reset_vif_iter, rtwdev); 65062306a36Sopenharmony_ci bitmap_zero(rtwdev->hw_port, RTW_PORT_NUM); 65162306a36Sopenharmony_ci rtw_enter_ips(rtwdev); 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic void rtw_fw_recovery_work(struct work_struct *work) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, 65762306a36Sopenharmony_ci fw_recovery_work); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 66062306a36Sopenharmony_ci __fw_recovery_work(rtwdev); 66162306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci ieee80211_restart_hw(rtwdev->hw); 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistruct rtw_txq_ba_iter_data { 66762306a36Sopenharmony_ci}; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic void rtw_txq_ba_iter(void *data, struct ieee80211_sta *sta) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; 67262306a36Sopenharmony_ci int ret; 67362306a36Sopenharmony_ci u8 tid; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci tid = find_first_bit(si->tid_ba, IEEE80211_NUM_TIDS); 67662306a36Sopenharmony_ci while (tid != IEEE80211_NUM_TIDS) { 67762306a36Sopenharmony_ci clear_bit(tid, si->tid_ba); 67862306a36Sopenharmony_ci ret = ieee80211_start_tx_ba_session(sta, tid, 0); 67962306a36Sopenharmony_ci if (ret == -EINVAL) { 68062306a36Sopenharmony_ci struct ieee80211_txq *txq; 68162306a36Sopenharmony_ci struct rtw_txq *rtwtxq; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci txq = sta->txq[tid]; 68462306a36Sopenharmony_ci rtwtxq = (struct rtw_txq *)txq->drv_priv; 68562306a36Sopenharmony_ci set_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci tid = find_first_bit(si->tid_ba, IEEE80211_NUM_TIDS); 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic void rtw_txq_ba_work(struct work_struct *work) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, ba_work); 69562306a36Sopenharmony_ci struct rtw_txq_ba_iter_data data; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci rtw_iterate_stas_atomic(rtwdev, rtw_txq_ba_iter, &data); 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_civoid rtw_set_rx_freq_band(struct rtw_rx_pkt_stat *pkt_stat, u8 channel) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci if (IS_CH_2G_BAND(channel)) 70362306a36Sopenharmony_ci pkt_stat->band = NL80211_BAND_2GHZ; 70462306a36Sopenharmony_ci else if (IS_CH_5G_BAND(channel)) 70562306a36Sopenharmony_ci pkt_stat->band = NL80211_BAND_5GHZ; 70662306a36Sopenharmony_ci else 70762306a36Sopenharmony_ci return; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci pkt_stat->freq = ieee80211_channel_to_frequency(channel, pkt_stat->band); 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_set_rx_freq_band); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_civoid rtw_set_dtim_period(struct rtw_dev *rtwdev, int dtim_period) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_TIMIE); 71662306a36Sopenharmony_ci rtw_write8(rtwdev, REG_DTIM_COUNTER_ROOT, dtim_period - 1); 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_civoid rtw_update_channel(struct rtw_dev *rtwdev, u8 center_channel, 72062306a36Sopenharmony_ci u8 primary_channel, enum rtw_supported_band band, 72162306a36Sopenharmony_ci enum rtw_bandwidth bandwidth) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci enum nl80211_band nl_band = rtw_hw_to_nl80211_band(band); 72462306a36Sopenharmony_ci struct rtw_hal *hal = &rtwdev->hal; 72562306a36Sopenharmony_ci u8 *cch_by_bw = hal->cch_by_bw; 72662306a36Sopenharmony_ci u32 center_freq, primary_freq; 72762306a36Sopenharmony_ci enum rtw_sar_bands sar_band; 72862306a36Sopenharmony_ci u8 primary_channel_idx; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci center_freq = ieee80211_channel_to_frequency(center_channel, nl_band); 73162306a36Sopenharmony_ci primary_freq = ieee80211_channel_to_frequency(primary_channel, nl_band); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* assign the center channel used while 20M bw is selected */ 73462306a36Sopenharmony_ci cch_by_bw[RTW_CHANNEL_WIDTH_20] = primary_channel; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* assign the center channel used while current bw is selected */ 73762306a36Sopenharmony_ci cch_by_bw[bandwidth] = center_channel; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci switch (bandwidth) { 74062306a36Sopenharmony_ci case RTW_CHANNEL_WIDTH_20: 74162306a36Sopenharmony_ci default: 74262306a36Sopenharmony_ci primary_channel_idx = RTW_SC_DONT_CARE; 74362306a36Sopenharmony_ci break; 74462306a36Sopenharmony_ci case RTW_CHANNEL_WIDTH_40: 74562306a36Sopenharmony_ci if (primary_freq > center_freq) 74662306a36Sopenharmony_ci primary_channel_idx = RTW_SC_20_UPPER; 74762306a36Sopenharmony_ci else 74862306a36Sopenharmony_ci primary_channel_idx = RTW_SC_20_LOWER; 74962306a36Sopenharmony_ci break; 75062306a36Sopenharmony_ci case RTW_CHANNEL_WIDTH_80: 75162306a36Sopenharmony_ci if (primary_freq > center_freq) { 75262306a36Sopenharmony_ci if (primary_freq - center_freq == 10) 75362306a36Sopenharmony_ci primary_channel_idx = RTW_SC_20_UPPER; 75462306a36Sopenharmony_ci else 75562306a36Sopenharmony_ci primary_channel_idx = RTW_SC_20_UPMOST; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* assign the center channel used 75862306a36Sopenharmony_ci * while 40M bw is selected 75962306a36Sopenharmony_ci */ 76062306a36Sopenharmony_ci cch_by_bw[RTW_CHANNEL_WIDTH_40] = center_channel + 4; 76162306a36Sopenharmony_ci } else { 76262306a36Sopenharmony_ci if (center_freq - primary_freq == 10) 76362306a36Sopenharmony_ci primary_channel_idx = RTW_SC_20_LOWER; 76462306a36Sopenharmony_ci else 76562306a36Sopenharmony_ci primary_channel_idx = RTW_SC_20_LOWEST; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci /* assign the center channel used 76862306a36Sopenharmony_ci * while 40M bw is selected 76962306a36Sopenharmony_ci */ 77062306a36Sopenharmony_ci cch_by_bw[RTW_CHANNEL_WIDTH_40] = center_channel - 4; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci break; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci switch (center_channel) { 77662306a36Sopenharmony_ci case 1 ... 14: 77762306a36Sopenharmony_ci sar_band = RTW_SAR_BAND_0; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci case 36 ... 64: 78062306a36Sopenharmony_ci sar_band = RTW_SAR_BAND_1; 78162306a36Sopenharmony_ci break; 78262306a36Sopenharmony_ci case 100 ... 144: 78362306a36Sopenharmony_ci sar_band = RTW_SAR_BAND_3; 78462306a36Sopenharmony_ci break; 78562306a36Sopenharmony_ci case 149 ... 177: 78662306a36Sopenharmony_ci sar_band = RTW_SAR_BAND_4; 78762306a36Sopenharmony_ci break; 78862306a36Sopenharmony_ci default: 78962306a36Sopenharmony_ci WARN(1, "unknown ch(%u) to SAR band\n", center_channel); 79062306a36Sopenharmony_ci sar_band = RTW_SAR_BAND_0; 79162306a36Sopenharmony_ci break; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci hal->current_primary_channel_index = primary_channel_idx; 79562306a36Sopenharmony_ci hal->current_band_width = bandwidth; 79662306a36Sopenharmony_ci hal->primary_channel = primary_channel; 79762306a36Sopenharmony_ci hal->current_channel = center_channel; 79862306a36Sopenharmony_ci hal->current_band_type = band; 79962306a36Sopenharmony_ci hal->sar_band = sar_band; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_civoid rtw_get_channel_params(struct cfg80211_chan_def *chandef, 80362306a36Sopenharmony_ci struct rtw_channel_params *chan_params) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci struct ieee80211_channel *channel = chandef->chan; 80662306a36Sopenharmony_ci enum nl80211_chan_width width = chandef->width; 80762306a36Sopenharmony_ci u32 primary_freq, center_freq; 80862306a36Sopenharmony_ci u8 center_chan; 80962306a36Sopenharmony_ci u8 bandwidth = RTW_CHANNEL_WIDTH_20; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci center_chan = channel->hw_value; 81262306a36Sopenharmony_ci primary_freq = channel->center_freq; 81362306a36Sopenharmony_ci center_freq = chandef->center_freq1; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci switch (width) { 81662306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 81762306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 81862306a36Sopenharmony_ci bandwidth = RTW_CHANNEL_WIDTH_20; 81962306a36Sopenharmony_ci break; 82062306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 82162306a36Sopenharmony_ci bandwidth = RTW_CHANNEL_WIDTH_40; 82262306a36Sopenharmony_ci if (primary_freq > center_freq) 82362306a36Sopenharmony_ci center_chan -= 2; 82462306a36Sopenharmony_ci else 82562306a36Sopenharmony_ci center_chan += 2; 82662306a36Sopenharmony_ci break; 82762306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 82862306a36Sopenharmony_ci bandwidth = RTW_CHANNEL_WIDTH_80; 82962306a36Sopenharmony_ci if (primary_freq > center_freq) { 83062306a36Sopenharmony_ci if (primary_freq - center_freq == 10) 83162306a36Sopenharmony_ci center_chan -= 2; 83262306a36Sopenharmony_ci else 83362306a36Sopenharmony_ci center_chan -= 6; 83462306a36Sopenharmony_ci } else { 83562306a36Sopenharmony_ci if (center_freq - primary_freq == 10) 83662306a36Sopenharmony_ci center_chan += 2; 83762306a36Sopenharmony_ci else 83862306a36Sopenharmony_ci center_chan += 6; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci break; 84162306a36Sopenharmony_ci default: 84262306a36Sopenharmony_ci center_chan = 0; 84362306a36Sopenharmony_ci break; 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci chan_params->center_chan = center_chan; 84762306a36Sopenharmony_ci chan_params->bandwidth = bandwidth; 84862306a36Sopenharmony_ci chan_params->primary_chan = channel->hw_value; 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_civoid rtw_set_channel(struct rtw_dev *rtwdev) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 85462306a36Sopenharmony_ci struct ieee80211_hw *hw = rtwdev->hw; 85562306a36Sopenharmony_ci struct rtw_hal *hal = &rtwdev->hal; 85662306a36Sopenharmony_ci struct rtw_channel_params ch_param; 85762306a36Sopenharmony_ci u8 center_chan, primary_chan, bandwidth, band; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci rtw_get_channel_params(&hw->conf.chandef, &ch_param); 86062306a36Sopenharmony_ci if (WARN(ch_param.center_chan == 0, "Invalid channel\n")) 86162306a36Sopenharmony_ci return; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci center_chan = ch_param.center_chan; 86462306a36Sopenharmony_ci primary_chan = ch_param.primary_chan; 86562306a36Sopenharmony_ci bandwidth = ch_param.bandwidth; 86662306a36Sopenharmony_ci band = ch_param.center_chan > 14 ? RTW_BAND_5G : RTW_BAND_2G; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci rtw_update_channel(rtwdev, center_chan, primary_chan, band, bandwidth); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (rtwdev->scan_info.op_chan) 87162306a36Sopenharmony_ci rtw_store_op_chan(rtwdev, true); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci chip->ops->set_channel(rtwdev, center_chan, bandwidth, 87462306a36Sopenharmony_ci hal->current_primary_channel_index); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (hal->current_band_type == RTW_BAND_5G) { 87762306a36Sopenharmony_ci rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_5G); 87862306a36Sopenharmony_ci } else { 87962306a36Sopenharmony_ci if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) 88062306a36Sopenharmony_ci rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_24G); 88162306a36Sopenharmony_ci else 88262306a36Sopenharmony_ci rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_24G_NOFORSCAN); 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci rtw_phy_set_tx_power_level(rtwdev, center_chan); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* if the channel isn't set for scanning, we will do RF calibration 88862306a36Sopenharmony_ci * in ieee80211_ops::mgd_prepare_tx(). Performing the calibration 88962306a36Sopenharmony_ci * during scanning on each channel takes too long. 89062306a36Sopenharmony_ci */ 89162306a36Sopenharmony_ci if (!test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) 89262306a36Sopenharmony_ci rtwdev->need_rfk = true; 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_civoid rtw_chip_prepare_tx(struct rtw_dev *rtwdev) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci if (rtwdev->need_rfk) { 90062306a36Sopenharmony_ci rtwdev->need_rfk = false; 90162306a36Sopenharmony_ci chip->ops->phy_calibration(rtwdev); 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic void rtw_vif_write_addr(struct rtw_dev *rtwdev, u32 start, u8 *addr) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci int i; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 91062306a36Sopenharmony_ci rtw_write8(rtwdev, start + i, addr[i]); 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_civoid rtw_vif_port_config(struct rtw_dev *rtwdev, 91462306a36Sopenharmony_ci struct rtw_vif *rtwvif, 91562306a36Sopenharmony_ci u32 config) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci u32 addr, mask; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci if (config & PORT_SET_MAC_ADDR) { 92062306a36Sopenharmony_ci addr = rtwvif->conf->mac_addr.addr; 92162306a36Sopenharmony_ci rtw_vif_write_addr(rtwdev, addr, rtwvif->mac_addr); 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci if (config & PORT_SET_BSSID) { 92462306a36Sopenharmony_ci addr = rtwvif->conf->bssid.addr; 92562306a36Sopenharmony_ci rtw_vif_write_addr(rtwdev, addr, rtwvif->bssid); 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci if (config & PORT_SET_NET_TYPE) { 92862306a36Sopenharmony_ci addr = rtwvif->conf->net_type.addr; 92962306a36Sopenharmony_ci mask = rtwvif->conf->net_type.mask; 93062306a36Sopenharmony_ci rtw_write32_mask(rtwdev, addr, mask, rtwvif->net_type); 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci if (config & PORT_SET_AID) { 93362306a36Sopenharmony_ci addr = rtwvif->conf->aid.addr; 93462306a36Sopenharmony_ci mask = rtwvif->conf->aid.mask; 93562306a36Sopenharmony_ci rtw_write32_mask(rtwdev, addr, mask, rtwvif->aid); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci if (config & PORT_SET_BCN_CTRL) { 93862306a36Sopenharmony_ci addr = rtwvif->conf->bcn_ctrl.addr; 93962306a36Sopenharmony_ci mask = rtwvif->conf->bcn_ctrl.mask; 94062306a36Sopenharmony_ci rtw_write8_mask(rtwdev, addr, mask, rtwvif->bcn_ctrl); 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cistatic u8 hw_bw_cap_to_bitamp(u8 bw_cap) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci u8 bw = 0; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci switch (bw_cap) { 94962306a36Sopenharmony_ci case EFUSE_HW_CAP_IGNORE: 95062306a36Sopenharmony_ci case EFUSE_HW_CAP_SUPP_BW80: 95162306a36Sopenharmony_ci bw |= BIT(RTW_CHANNEL_WIDTH_80); 95262306a36Sopenharmony_ci fallthrough; 95362306a36Sopenharmony_ci case EFUSE_HW_CAP_SUPP_BW40: 95462306a36Sopenharmony_ci bw |= BIT(RTW_CHANNEL_WIDTH_40); 95562306a36Sopenharmony_ci fallthrough; 95662306a36Sopenharmony_ci default: 95762306a36Sopenharmony_ci bw |= BIT(RTW_CHANNEL_WIDTH_20); 95862306a36Sopenharmony_ci break; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci return bw; 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_cistatic void rtw_hw_config_rf_ant_num(struct rtw_dev *rtwdev, u8 hw_ant_num) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 96762306a36Sopenharmony_ci struct rtw_hal *hal = &rtwdev->hal; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (hw_ant_num == EFUSE_HW_CAP_IGNORE || 97062306a36Sopenharmony_ci hw_ant_num >= hal->rf_path_num) 97162306a36Sopenharmony_ci return; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci switch (hw_ant_num) { 97462306a36Sopenharmony_ci case 1: 97562306a36Sopenharmony_ci hal->rf_type = RF_1T1R; 97662306a36Sopenharmony_ci hal->rf_path_num = 1; 97762306a36Sopenharmony_ci if (!chip->fix_rf_phy_num) 97862306a36Sopenharmony_ci hal->rf_phy_num = hal->rf_path_num; 97962306a36Sopenharmony_ci hal->antenna_tx = BB_PATH_A; 98062306a36Sopenharmony_ci hal->antenna_rx = BB_PATH_A; 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci default: 98362306a36Sopenharmony_ci WARN(1, "invalid hw configuration from efuse\n"); 98462306a36Sopenharmony_ci break; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_cistatic u64 get_vht_ra_mask(struct ieee80211_sta *sta) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci u64 ra_mask = 0; 99162306a36Sopenharmony_ci u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map); 99262306a36Sopenharmony_ci u8 vht_mcs_cap; 99362306a36Sopenharmony_ci int i, nss; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* 4SS, every two bits for MCS7/8/9 */ 99662306a36Sopenharmony_ci for (i = 0, nss = 12; i < 4; i++, mcs_map >>= 2, nss += 10) { 99762306a36Sopenharmony_ci vht_mcs_cap = mcs_map & 0x3; 99862306a36Sopenharmony_ci switch (vht_mcs_cap) { 99962306a36Sopenharmony_ci case 2: /* MCS9 */ 100062306a36Sopenharmony_ci ra_mask |= 0x3ffULL << nss; 100162306a36Sopenharmony_ci break; 100262306a36Sopenharmony_ci case 1: /* MCS8 */ 100362306a36Sopenharmony_ci ra_mask |= 0x1ffULL << nss; 100462306a36Sopenharmony_ci break; 100562306a36Sopenharmony_ci case 0: /* MCS7 */ 100662306a36Sopenharmony_ci ra_mask |= 0x0ffULL << nss; 100762306a36Sopenharmony_ci break; 100862306a36Sopenharmony_ci default: 100962306a36Sopenharmony_ci break; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci return ra_mask; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_cistatic u8 get_rate_id(u8 wireless_set, enum rtw_bandwidth bw_mode, u8 tx_num) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci u8 rate_id = 0; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci switch (wireless_set) { 102162306a36Sopenharmony_ci case WIRELESS_CCK: 102262306a36Sopenharmony_ci rate_id = RTW_RATEID_B_20M; 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci case WIRELESS_OFDM: 102562306a36Sopenharmony_ci rate_id = RTW_RATEID_G; 102662306a36Sopenharmony_ci break; 102762306a36Sopenharmony_ci case WIRELESS_CCK | WIRELESS_OFDM: 102862306a36Sopenharmony_ci rate_id = RTW_RATEID_BG; 102962306a36Sopenharmony_ci break; 103062306a36Sopenharmony_ci case WIRELESS_OFDM | WIRELESS_HT: 103162306a36Sopenharmony_ci if (tx_num == 1) 103262306a36Sopenharmony_ci rate_id = RTW_RATEID_GN_N1SS; 103362306a36Sopenharmony_ci else if (tx_num == 2) 103462306a36Sopenharmony_ci rate_id = RTW_RATEID_GN_N2SS; 103562306a36Sopenharmony_ci else if (tx_num == 3) 103662306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR5_N_3SS; 103762306a36Sopenharmony_ci break; 103862306a36Sopenharmony_ci case WIRELESS_CCK | WIRELESS_OFDM | WIRELESS_HT: 103962306a36Sopenharmony_ci if (bw_mode == RTW_CHANNEL_WIDTH_40) { 104062306a36Sopenharmony_ci if (tx_num == 1) 104162306a36Sopenharmony_ci rate_id = RTW_RATEID_BGN_40M_1SS; 104262306a36Sopenharmony_ci else if (tx_num == 2) 104362306a36Sopenharmony_ci rate_id = RTW_RATEID_BGN_40M_2SS; 104462306a36Sopenharmony_ci else if (tx_num == 3) 104562306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR5_N_3SS; 104662306a36Sopenharmony_ci else if (tx_num == 4) 104762306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR7_N_4SS; 104862306a36Sopenharmony_ci } else { 104962306a36Sopenharmony_ci if (tx_num == 1) 105062306a36Sopenharmony_ci rate_id = RTW_RATEID_BGN_20M_1SS; 105162306a36Sopenharmony_ci else if (tx_num == 2) 105262306a36Sopenharmony_ci rate_id = RTW_RATEID_BGN_20M_2SS; 105362306a36Sopenharmony_ci else if (tx_num == 3) 105462306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR5_N_3SS; 105562306a36Sopenharmony_ci else if (tx_num == 4) 105662306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR7_N_4SS; 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci break; 105962306a36Sopenharmony_ci case WIRELESS_OFDM | WIRELESS_VHT: 106062306a36Sopenharmony_ci if (tx_num == 1) 106162306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR1_AC_1SS; 106262306a36Sopenharmony_ci else if (tx_num == 2) 106362306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR0_AC_2SS; 106462306a36Sopenharmony_ci else if (tx_num == 3) 106562306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR4_AC_3SS; 106662306a36Sopenharmony_ci else if (tx_num == 4) 106762306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR6_AC_4SS; 106862306a36Sopenharmony_ci break; 106962306a36Sopenharmony_ci case WIRELESS_CCK | WIRELESS_OFDM | WIRELESS_VHT: 107062306a36Sopenharmony_ci if (bw_mode >= RTW_CHANNEL_WIDTH_80) { 107162306a36Sopenharmony_ci if (tx_num == 1) 107262306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR1_AC_1SS; 107362306a36Sopenharmony_ci else if (tx_num == 2) 107462306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR0_AC_2SS; 107562306a36Sopenharmony_ci else if (tx_num == 3) 107662306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR4_AC_3SS; 107762306a36Sopenharmony_ci else if (tx_num == 4) 107862306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR6_AC_4SS; 107962306a36Sopenharmony_ci } else { 108062306a36Sopenharmony_ci if (tx_num == 1) 108162306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR2_AC_2G_1SS; 108262306a36Sopenharmony_ci else if (tx_num == 2) 108362306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR3_AC_2G_2SS; 108462306a36Sopenharmony_ci else if (tx_num == 3) 108562306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR4_AC_3SS; 108662306a36Sopenharmony_ci else if (tx_num == 4) 108762306a36Sopenharmony_ci rate_id = RTW_RATEID_ARFR6_AC_4SS; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci break; 109062306a36Sopenharmony_ci default: 109162306a36Sopenharmony_ci break; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci return rate_id; 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci#define RA_MASK_CCK_RATES 0x0000f 109862306a36Sopenharmony_ci#define RA_MASK_OFDM_RATES 0x00ff0 109962306a36Sopenharmony_ci#define RA_MASK_HT_RATES_1SS (0xff000ULL << 0) 110062306a36Sopenharmony_ci#define RA_MASK_HT_RATES_2SS (0xff000ULL << 8) 110162306a36Sopenharmony_ci#define RA_MASK_HT_RATES_3SS (0xff000ULL << 16) 110262306a36Sopenharmony_ci#define RA_MASK_HT_RATES (RA_MASK_HT_RATES_1SS | \ 110362306a36Sopenharmony_ci RA_MASK_HT_RATES_2SS | \ 110462306a36Sopenharmony_ci RA_MASK_HT_RATES_3SS) 110562306a36Sopenharmony_ci#define RA_MASK_VHT_RATES_1SS (0x3ff000ULL << 0) 110662306a36Sopenharmony_ci#define RA_MASK_VHT_RATES_2SS (0x3ff000ULL << 10) 110762306a36Sopenharmony_ci#define RA_MASK_VHT_RATES_3SS (0x3ff000ULL << 20) 110862306a36Sopenharmony_ci#define RA_MASK_VHT_RATES (RA_MASK_VHT_RATES_1SS | \ 110962306a36Sopenharmony_ci RA_MASK_VHT_RATES_2SS | \ 111062306a36Sopenharmony_ci RA_MASK_VHT_RATES_3SS) 111162306a36Sopenharmony_ci#define RA_MASK_CCK_IN_BG 0x00005 111262306a36Sopenharmony_ci#define RA_MASK_CCK_IN_HT 0x00005 111362306a36Sopenharmony_ci#define RA_MASK_CCK_IN_VHT 0x00005 111462306a36Sopenharmony_ci#define RA_MASK_OFDM_IN_VHT 0x00010 111562306a36Sopenharmony_ci#define RA_MASK_OFDM_IN_HT_2G 0x00010 111662306a36Sopenharmony_ci#define RA_MASK_OFDM_IN_HT_5G 0x00030 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_cistatic u64 rtw_rate_mask_rssi(struct rtw_sta_info *si, u8 wireless_set) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci u8 rssi_level = si->rssi_level; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (wireless_set == WIRELESS_CCK) 112362306a36Sopenharmony_ci return 0xffffffffffffffffULL; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (rssi_level == 0) 112662306a36Sopenharmony_ci return 0xffffffffffffffffULL; 112762306a36Sopenharmony_ci else if (rssi_level == 1) 112862306a36Sopenharmony_ci return 0xfffffffffffffff0ULL; 112962306a36Sopenharmony_ci else if (rssi_level == 2) 113062306a36Sopenharmony_ci return 0xffffffffffffefe0ULL; 113162306a36Sopenharmony_ci else if (rssi_level == 3) 113262306a36Sopenharmony_ci return 0xffffffffffffcfc0ULL; 113362306a36Sopenharmony_ci else if (rssi_level == 4) 113462306a36Sopenharmony_ci return 0xffffffffffff8f80ULL; 113562306a36Sopenharmony_ci else 113662306a36Sopenharmony_ci return 0xffffffffffff0f00ULL; 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic u64 rtw_rate_mask_recover(u64 ra_mask, u64 ra_mask_bak) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci if ((ra_mask & ~(RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES)) == 0) 114262306a36Sopenharmony_ci ra_mask |= (ra_mask_bak & ~(RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES)); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (ra_mask == 0) 114562306a36Sopenharmony_ci ra_mask |= (ra_mask_bak & (RA_MASK_CCK_RATES | RA_MASK_OFDM_RATES)); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci return ra_mask; 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic u64 rtw_rate_mask_cfg(struct rtw_dev *rtwdev, struct rtw_sta_info *si, 115162306a36Sopenharmony_ci u64 ra_mask, bool is_vht_enable) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci struct rtw_hal *hal = &rtwdev->hal; 115462306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask = si->mask; 115562306a36Sopenharmony_ci u64 cfg_mask = GENMASK_ULL(63, 0); 115662306a36Sopenharmony_ci u8 band; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci if (!si->use_cfg_mask) 115962306a36Sopenharmony_ci return ra_mask; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci band = hal->current_band_type; 116262306a36Sopenharmony_ci if (band == RTW_BAND_2G) { 116362306a36Sopenharmony_ci band = NL80211_BAND_2GHZ; 116462306a36Sopenharmony_ci cfg_mask = mask->control[band].legacy; 116562306a36Sopenharmony_ci } else if (band == RTW_BAND_5G) { 116662306a36Sopenharmony_ci band = NL80211_BAND_5GHZ; 116762306a36Sopenharmony_ci cfg_mask = u64_encode_bits(mask->control[band].legacy, 116862306a36Sopenharmony_ci RA_MASK_OFDM_RATES); 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (!is_vht_enable) { 117262306a36Sopenharmony_ci if (ra_mask & RA_MASK_HT_RATES_1SS) 117362306a36Sopenharmony_ci cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0], 117462306a36Sopenharmony_ci RA_MASK_HT_RATES_1SS); 117562306a36Sopenharmony_ci if (ra_mask & RA_MASK_HT_RATES_2SS) 117662306a36Sopenharmony_ci cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1], 117762306a36Sopenharmony_ci RA_MASK_HT_RATES_2SS); 117862306a36Sopenharmony_ci } else { 117962306a36Sopenharmony_ci if (ra_mask & RA_MASK_VHT_RATES_1SS) 118062306a36Sopenharmony_ci cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0], 118162306a36Sopenharmony_ci RA_MASK_VHT_RATES_1SS); 118262306a36Sopenharmony_ci if (ra_mask & RA_MASK_VHT_RATES_2SS) 118362306a36Sopenharmony_ci cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1], 118462306a36Sopenharmony_ci RA_MASK_VHT_RATES_2SS); 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci ra_mask &= cfg_mask; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return ra_mask; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_civoid rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, 119362306a36Sopenharmony_ci bool reset_ra_mask) 119462306a36Sopenharmony_ci{ 119562306a36Sopenharmony_ci struct rtw_dm_info *dm_info = &rtwdev->dm_info; 119662306a36Sopenharmony_ci struct ieee80211_sta *sta = si->sta; 119762306a36Sopenharmony_ci struct rtw_efuse *efuse = &rtwdev->efuse; 119862306a36Sopenharmony_ci struct rtw_hal *hal = &rtwdev->hal; 119962306a36Sopenharmony_ci u8 wireless_set; 120062306a36Sopenharmony_ci u8 bw_mode; 120162306a36Sopenharmony_ci u8 rate_id; 120262306a36Sopenharmony_ci u8 rf_type = RF_1T1R; 120362306a36Sopenharmony_ci u8 stbc_en = 0; 120462306a36Sopenharmony_ci u8 ldpc_en = 0; 120562306a36Sopenharmony_ci u8 tx_num = 1; 120662306a36Sopenharmony_ci u64 ra_mask = 0; 120762306a36Sopenharmony_ci u64 ra_mask_bak = 0; 120862306a36Sopenharmony_ci bool is_vht_enable = false; 120962306a36Sopenharmony_ci bool is_support_sgi = false; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci if (sta->deflink.vht_cap.vht_supported) { 121262306a36Sopenharmony_ci is_vht_enable = true; 121362306a36Sopenharmony_ci ra_mask |= get_vht_ra_mask(sta); 121462306a36Sopenharmony_ci if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK) 121562306a36Sopenharmony_ci stbc_en = VHT_STBC_EN; 121662306a36Sopenharmony_ci if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) 121762306a36Sopenharmony_ci ldpc_en = VHT_LDPC_EN; 121862306a36Sopenharmony_ci } else if (sta->deflink.ht_cap.ht_supported) { 121962306a36Sopenharmony_ci ra_mask |= (sta->deflink.ht_cap.mcs.rx_mask[1] << 20) | 122062306a36Sopenharmony_ci (sta->deflink.ht_cap.mcs.rx_mask[0] << 12); 122162306a36Sopenharmony_ci if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) 122262306a36Sopenharmony_ci stbc_en = HT_STBC_EN; 122362306a36Sopenharmony_ci if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) 122462306a36Sopenharmony_ci ldpc_en = HT_LDPC_EN; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (efuse->hw_cap.nss == 1 || rtwdev->hal.txrx_1ss) 122862306a36Sopenharmony_ci ra_mask &= RA_MASK_VHT_RATES_1SS | RA_MASK_HT_RATES_1SS; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if (hal->current_band_type == RTW_BAND_5G) { 123162306a36Sopenharmony_ci ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_5GHZ] << 4; 123262306a36Sopenharmony_ci ra_mask_bak = ra_mask; 123362306a36Sopenharmony_ci if (sta->deflink.vht_cap.vht_supported) { 123462306a36Sopenharmony_ci ra_mask &= RA_MASK_VHT_RATES | RA_MASK_OFDM_IN_VHT; 123562306a36Sopenharmony_ci wireless_set = WIRELESS_OFDM | WIRELESS_VHT; 123662306a36Sopenharmony_ci } else if (sta->deflink.ht_cap.ht_supported) { 123762306a36Sopenharmony_ci ra_mask &= RA_MASK_HT_RATES | RA_MASK_OFDM_IN_HT_5G; 123862306a36Sopenharmony_ci wireless_set = WIRELESS_OFDM | WIRELESS_HT; 123962306a36Sopenharmony_ci } else { 124062306a36Sopenharmony_ci wireless_set = WIRELESS_OFDM; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci dm_info->rrsr_val_init = RRSR_INIT_5G; 124362306a36Sopenharmony_ci } else if (hal->current_band_type == RTW_BAND_2G) { 124462306a36Sopenharmony_ci ra_mask |= sta->deflink.supp_rates[NL80211_BAND_2GHZ]; 124562306a36Sopenharmony_ci ra_mask_bak = ra_mask; 124662306a36Sopenharmony_ci if (sta->deflink.vht_cap.vht_supported) { 124762306a36Sopenharmony_ci ra_mask &= RA_MASK_VHT_RATES | RA_MASK_CCK_IN_VHT | 124862306a36Sopenharmony_ci RA_MASK_OFDM_IN_VHT; 124962306a36Sopenharmony_ci wireless_set = WIRELESS_CCK | WIRELESS_OFDM | 125062306a36Sopenharmony_ci WIRELESS_HT | WIRELESS_VHT; 125162306a36Sopenharmony_ci } else if (sta->deflink.ht_cap.ht_supported) { 125262306a36Sopenharmony_ci ra_mask &= RA_MASK_HT_RATES | RA_MASK_CCK_IN_HT | 125362306a36Sopenharmony_ci RA_MASK_OFDM_IN_HT_2G; 125462306a36Sopenharmony_ci wireless_set = WIRELESS_CCK | WIRELESS_OFDM | 125562306a36Sopenharmony_ci WIRELESS_HT; 125662306a36Sopenharmony_ci } else if (sta->deflink.supp_rates[0] <= 0xf) { 125762306a36Sopenharmony_ci wireless_set = WIRELESS_CCK; 125862306a36Sopenharmony_ci } else { 125962306a36Sopenharmony_ci ra_mask &= RA_MASK_OFDM_RATES | RA_MASK_CCK_IN_BG; 126062306a36Sopenharmony_ci wireless_set = WIRELESS_CCK | WIRELESS_OFDM; 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci dm_info->rrsr_val_init = RRSR_INIT_2G; 126362306a36Sopenharmony_ci } else { 126462306a36Sopenharmony_ci rtw_err(rtwdev, "Unknown band type\n"); 126562306a36Sopenharmony_ci ra_mask_bak = ra_mask; 126662306a36Sopenharmony_ci wireless_set = 0; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci switch (sta->deflink.bandwidth) { 127062306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_80: 127162306a36Sopenharmony_ci bw_mode = RTW_CHANNEL_WIDTH_80; 127262306a36Sopenharmony_ci is_support_sgi = sta->deflink.vht_cap.vht_supported && 127362306a36Sopenharmony_ci (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); 127462306a36Sopenharmony_ci break; 127562306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_40: 127662306a36Sopenharmony_ci bw_mode = RTW_CHANNEL_WIDTH_40; 127762306a36Sopenharmony_ci is_support_sgi = sta->deflink.ht_cap.ht_supported && 127862306a36Sopenharmony_ci (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40); 127962306a36Sopenharmony_ci break; 128062306a36Sopenharmony_ci default: 128162306a36Sopenharmony_ci bw_mode = RTW_CHANNEL_WIDTH_20; 128262306a36Sopenharmony_ci is_support_sgi = sta->deflink.ht_cap.ht_supported && 128362306a36Sopenharmony_ci (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20); 128462306a36Sopenharmony_ci break; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci if (sta->deflink.vht_cap.vht_supported && ra_mask & 0xffc00000) { 128862306a36Sopenharmony_ci tx_num = 2; 128962306a36Sopenharmony_ci rf_type = RF_2T2R; 129062306a36Sopenharmony_ci } else if (sta->deflink.ht_cap.ht_supported && ra_mask & 0xfff00000) { 129162306a36Sopenharmony_ci tx_num = 2; 129262306a36Sopenharmony_ci rf_type = RF_2T2R; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci rate_id = get_rate_id(wireless_set, bw_mode, tx_num); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci ra_mask &= rtw_rate_mask_rssi(si, wireless_set); 129862306a36Sopenharmony_ci ra_mask = rtw_rate_mask_recover(ra_mask, ra_mask_bak); 129962306a36Sopenharmony_ci ra_mask = rtw_rate_mask_cfg(rtwdev, si, ra_mask, is_vht_enable); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci si->bw_mode = bw_mode; 130262306a36Sopenharmony_ci si->stbc_en = stbc_en; 130362306a36Sopenharmony_ci si->ldpc_en = ldpc_en; 130462306a36Sopenharmony_ci si->rf_type = rf_type; 130562306a36Sopenharmony_ci si->sgi_enable = is_support_sgi; 130662306a36Sopenharmony_ci si->vht_enable = is_vht_enable; 130762306a36Sopenharmony_ci si->ra_mask = ra_mask; 130862306a36Sopenharmony_ci si->rate_id = rate_id; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci rtw_fw_send_ra_info(rtwdev, si, reset_ra_mask); 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_cistatic int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 131662306a36Sopenharmony_ci struct rtw_fw_state *fw; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci fw = &rtwdev->fw; 131962306a36Sopenharmony_ci wait_for_completion(&fw->completion); 132062306a36Sopenharmony_ci if (!fw->firmware) 132162306a36Sopenharmony_ci return -EINVAL; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci if (chip->wow_fw_name) { 132462306a36Sopenharmony_ci fw = &rtwdev->wow_fw; 132562306a36Sopenharmony_ci wait_for_completion(&fw->completion); 132662306a36Sopenharmony_ci if (!fw->firmware) 132762306a36Sopenharmony_ci return -EINVAL; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci return 0; 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_cistatic enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, 133462306a36Sopenharmony_ci struct rtw_fw_state *fw) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci if (rtw_disable_lps_deep_mode || !chip->lps_deep_mode_supported || 133962306a36Sopenharmony_ci !fw->feature) 134062306a36Sopenharmony_ci return LPS_DEEP_MODE_NONE; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_PG)) && 134362306a36Sopenharmony_ci rtw_fw_feature_check(fw, FW_FEATURE_PG)) 134462306a36Sopenharmony_ci return LPS_DEEP_MODE_PG; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_LCLK)) && 134762306a36Sopenharmony_ci rtw_fw_feature_check(fw, FW_FEATURE_LCLK)) 134862306a36Sopenharmony_ci return LPS_DEEP_MODE_LCLK; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci return LPS_DEEP_MODE_NONE; 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic int rtw_power_on(struct rtw_dev *rtwdev) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 135662306a36Sopenharmony_ci struct rtw_fw_state *fw = &rtwdev->fw; 135762306a36Sopenharmony_ci bool wifi_only; 135862306a36Sopenharmony_ci int ret; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci ret = rtw_hci_setup(rtwdev); 136162306a36Sopenharmony_ci if (ret) { 136262306a36Sopenharmony_ci rtw_err(rtwdev, "failed to setup hci\n"); 136362306a36Sopenharmony_ci goto err; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci /* power on MAC before firmware downloaded */ 136762306a36Sopenharmony_ci ret = rtw_mac_power_on(rtwdev); 136862306a36Sopenharmony_ci if (ret) { 136962306a36Sopenharmony_ci rtw_err(rtwdev, "failed to power on mac\n"); 137062306a36Sopenharmony_ci goto err; 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci ret = rtw_wait_firmware_completion(rtwdev); 137462306a36Sopenharmony_ci if (ret) { 137562306a36Sopenharmony_ci rtw_err(rtwdev, "failed to wait firmware completion\n"); 137662306a36Sopenharmony_ci goto err_off; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci ret = rtw_download_firmware(rtwdev, fw); 138062306a36Sopenharmony_ci if (ret) { 138162306a36Sopenharmony_ci rtw_err(rtwdev, "failed to download firmware\n"); 138262306a36Sopenharmony_ci goto err_off; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci /* config mac after firmware downloaded */ 138662306a36Sopenharmony_ci ret = rtw_mac_init(rtwdev); 138762306a36Sopenharmony_ci if (ret) { 138862306a36Sopenharmony_ci rtw_err(rtwdev, "failed to configure mac\n"); 138962306a36Sopenharmony_ci goto err_off; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci chip->ops->phy_set_param(rtwdev); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci ret = rtw_hci_start(rtwdev); 139562306a36Sopenharmony_ci if (ret) { 139662306a36Sopenharmony_ci rtw_err(rtwdev, "failed to start hci\n"); 139762306a36Sopenharmony_ci goto err_off; 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* send H2C after HCI has started */ 140162306a36Sopenharmony_ci rtw_fw_send_general_info(rtwdev); 140262306a36Sopenharmony_ci rtw_fw_send_phydm_info(rtwdev); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci wifi_only = !rtwdev->efuse.btcoex; 140562306a36Sopenharmony_ci rtw_coex_power_on_setting(rtwdev); 140662306a36Sopenharmony_ci rtw_coex_init_hw_config(rtwdev, wifi_only); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci return 0; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_cierr_off: 141162306a36Sopenharmony_ci rtw_mac_power_off(rtwdev); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_cierr: 141462306a36Sopenharmony_ci return ret; 141562306a36Sopenharmony_ci} 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_civoid rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start) 141862306a36Sopenharmony_ci{ 141962306a36Sopenharmony_ci if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_NOTIFY_SCAN)) 142062306a36Sopenharmony_ci return; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (start) { 142362306a36Sopenharmony_ci rtw_fw_scan_notify(rtwdev, true); 142462306a36Sopenharmony_ci } else { 142562306a36Sopenharmony_ci reinit_completion(&rtwdev->fw_scan_density); 142662306a36Sopenharmony_ci rtw_fw_scan_notify(rtwdev, false); 142762306a36Sopenharmony_ci if (!wait_for_completion_timeout(&rtwdev->fw_scan_density, 142862306a36Sopenharmony_ci SCAN_NOTIFY_TIMEOUT)) 142962306a36Sopenharmony_ci rtw_warn(rtwdev, "firmware failed to report density after scan\n"); 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci} 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_civoid rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif, 143462306a36Sopenharmony_ci const u8 *mac_addr, bool hw_scan) 143562306a36Sopenharmony_ci{ 143662306a36Sopenharmony_ci u32 config = 0; 143762306a36Sopenharmony_ci int ret = 0; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci rtw_leave_lps(rtwdev); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci if (hw_scan && (rtwdev->hw->conf.flags & IEEE80211_CONF_IDLE)) { 144262306a36Sopenharmony_ci ret = rtw_leave_ips(rtwdev); 144362306a36Sopenharmony_ci if (ret) { 144462306a36Sopenharmony_ci rtw_err(rtwdev, "failed to leave idle state\n"); 144562306a36Sopenharmony_ci return; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci ether_addr_copy(rtwvif->mac_addr, mac_addr); 145062306a36Sopenharmony_ci config |= PORT_SET_MAC_ADDR; 145162306a36Sopenharmony_ci rtw_vif_port_config(rtwdev, rtwvif, config); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci rtw_coex_scan_notify(rtwdev, COEX_SCAN_START); 145462306a36Sopenharmony_ci rtw_core_fw_scan_notify(rtwdev, true); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci set_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); 145762306a36Sopenharmony_ci set_bit(RTW_FLAG_SCANNING, rtwdev->flags); 145862306a36Sopenharmony_ci} 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_civoid rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, 146162306a36Sopenharmony_ci bool hw_scan) 146262306a36Sopenharmony_ci{ 146362306a36Sopenharmony_ci struct rtw_vif *rtwvif = vif ? (struct rtw_vif *)vif->drv_priv : NULL; 146462306a36Sopenharmony_ci u32 config = 0; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (!rtwvif) 146762306a36Sopenharmony_ci return; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci clear_bit(RTW_FLAG_SCANNING, rtwdev->flags); 147062306a36Sopenharmony_ci clear_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci rtw_core_fw_scan_notify(rtwdev, false); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci ether_addr_copy(rtwvif->mac_addr, vif->addr); 147562306a36Sopenharmony_ci config |= PORT_SET_MAC_ADDR; 147662306a36Sopenharmony_ci rtw_vif_port_config(rtwdev, rtwvif, config); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci rtw_coex_scan_notify(rtwdev, COEX_SCAN_FINISH); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci if (hw_scan && (rtwdev->hw->conf.flags & IEEE80211_CONF_IDLE)) 148162306a36Sopenharmony_ci ieee80211_queue_work(rtwdev->hw, &rtwdev->ips_work); 148262306a36Sopenharmony_ci} 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ciint rtw_core_start(struct rtw_dev *rtwdev) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci int ret; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci ret = rtw_power_on(rtwdev); 148962306a36Sopenharmony_ci if (ret) 149062306a36Sopenharmony_ci return ret; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci rtw_sec_enable_sec_engine(rtwdev); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci rtwdev->lps_conf.deep_mode = rtw_update_lps_deep_mode(rtwdev, &rtwdev->fw); 149562306a36Sopenharmony_ci rtwdev->lps_conf.wow_deep_mode = rtw_update_lps_deep_mode(rtwdev, &rtwdev->wow_fw); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci /* rcr reset after powered on */ 149862306a36Sopenharmony_ci rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work, 150162306a36Sopenharmony_ci RTW_WATCH_DOG_DELAY_TIME); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci set_bit(RTW_FLAG_RUNNING, rtwdev->flags); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci return 0; 150662306a36Sopenharmony_ci} 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_cistatic void rtw_power_off(struct rtw_dev *rtwdev) 150962306a36Sopenharmony_ci{ 151062306a36Sopenharmony_ci rtw_hci_stop(rtwdev); 151162306a36Sopenharmony_ci rtw_coex_power_off_setting(rtwdev); 151262306a36Sopenharmony_ci rtw_mac_power_off(rtwdev); 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_civoid rtw_core_stop(struct rtw_dev *rtwdev) 151662306a36Sopenharmony_ci{ 151762306a36Sopenharmony_ci struct rtw_coex *coex = &rtwdev->coex; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci clear_bit(RTW_FLAG_RUNNING, rtwdev->flags); 152062306a36Sopenharmony_ci clear_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci cancel_work_sync(&rtwdev->c2h_work); 152562306a36Sopenharmony_ci cancel_work_sync(&rtwdev->update_beacon_work); 152662306a36Sopenharmony_ci cancel_delayed_work_sync(&rtwdev->watch_dog_work); 152762306a36Sopenharmony_ci cancel_delayed_work_sync(&coex->bt_relink_work); 152862306a36Sopenharmony_ci cancel_delayed_work_sync(&coex->bt_reenable_work); 152962306a36Sopenharmony_ci cancel_delayed_work_sync(&coex->defreeze_work); 153062306a36Sopenharmony_ci cancel_delayed_work_sync(&coex->wl_remain_work); 153162306a36Sopenharmony_ci cancel_delayed_work_sync(&coex->bt_remain_work); 153262306a36Sopenharmony_ci cancel_delayed_work_sync(&coex->wl_connecting_work); 153362306a36Sopenharmony_ci cancel_delayed_work_sync(&coex->bt_multi_link_remain_work); 153462306a36Sopenharmony_ci cancel_delayed_work_sync(&coex->wl_ccklock_work); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci rtw_power_off(rtwdev); 153962306a36Sopenharmony_ci} 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_cistatic void rtw_init_ht_cap(struct rtw_dev *rtwdev, 154262306a36Sopenharmony_ci struct ieee80211_sta_ht_cap *ht_cap) 154362306a36Sopenharmony_ci{ 154462306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 154562306a36Sopenharmony_ci struct rtw_efuse *efuse = &rtwdev->efuse; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci ht_cap->ht_supported = true; 154862306a36Sopenharmony_ci ht_cap->cap = 0; 154962306a36Sopenharmony_ci ht_cap->cap |= IEEE80211_HT_CAP_SGI_20 | 155062306a36Sopenharmony_ci IEEE80211_HT_CAP_MAX_AMSDU | 155162306a36Sopenharmony_ci (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci if (rtw_chip_has_rx_ldpc(rtwdev)) 155462306a36Sopenharmony_ci ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING; 155562306a36Sopenharmony_ci if (rtw_chip_has_tx_stbc(rtwdev)) 155662306a36Sopenharmony_ci ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (efuse->hw_cap.bw & BIT(RTW_CHANNEL_WIDTH_40)) 155962306a36Sopenharmony_ci ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 156062306a36Sopenharmony_ci IEEE80211_HT_CAP_DSSSCCK40 | 156162306a36Sopenharmony_ci IEEE80211_HT_CAP_SGI_40; 156262306a36Sopenharmony_ci ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 156362306a36Sopenharmony_ci ht_cap->ampdu_density = chip->ampdu_density; 156462306a36Sopenharmony_ci ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 156562306a36Sopenharmony_ci if (efuse->hw_cap.nss > 1) { 156662306a36Sopenharmony_ci ht_cap->mcs.rx_mask[0] = 0xFF; 156762306a36Sopenharmony_ci ht_cap->mcs.rx_mask[1] = 0xFF; 156862306a36Sopenharmony_ci ht_cap->mcs.rx_mask[4] = 0x01; 156962306a36Sopenharmony_ci ht_cap->mcs.rx_highest = cpu_to_le16(300); 157062306a36Sopenharmony_ci } else { 157162306a36Sopenharmony_ci ht_cap->mcs.rx_mask[0] = 0xFF; 157262306a36Sopenharmony_ci ht_cap->mcs.rx_mask[1] = 0x00; 157362306a36Sopenharmony_ci ht_cap->mcs.rx_mask[4] = 0x01; 157462306a36Sopenharmony_ci ht_cap->mcs.rx_highest = cpu_to_le16(150); 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci} 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_cistatic void rtw_init_vht_cap(struct rtw_dev *rtwdev, 157962306a36Sopenharmony_ci struct ieee80211_sta_vht_cap *vht_cap) 158062306a36Sopenharmony_ci{ 158162306a36Sopenharmony_ci struct rtw_efuse *efuse = &rtwdev->efuse; 158262306a36Sopenharmony_ci u16 mcs_map; 158362306a36Sopenharmony_ci __le16 highest; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (efuse->hw_cap.ptcl != EFUSE_HW_CAP_IGNORE && 158662306a36Sopenharmony_ci efuse->hw_cap.ptcl != EFUSE_HW_CAP_PTCL_VHT) 158762306a36Sopenharmony_ci return; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci vht_cap->vht_supported = true; 159062306a36Sopenharmony_ci vht_cap->cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | 159162306a36Sopenharmony_ci IEEE80211_VHT_CAP_SHORT_GI_80 | 159262306a36Sopenharmony_ci IEEE80211_VHT_CAP_RXSTBC_1 | 159362306a36Sopenharmony_ci IEEE80211_VHT_CAP_HTC_VHT | 159462306a36Sopenharmony_ci IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | 159562306a36Sopenharmony_ci 0; 159662306a36Sopenharmony_ci if (rtwdev->hal.rf_path_num > 1) 159762306a36Sopenharmony_ci vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 159862306a36Sopenharmony_ci vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | 159962306a36Sopenharmony_ci IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; 160062306a36Sopenharmony_ci vht_cap->cap |= (rtwdev->hal.bfee_sts_cap << 160162306a36Sopenharmony_ci IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci if (rtw_chip_has_rx_ldpc(rtwdev)) 160462306a36Sopenharmony_ci vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | 160762306a36Sopenharmony_ci IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | 160862306a36Sopenharmony_ci IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | 160962306a36Sopenharmony_ci IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | 161062306a36Sopenharmony_ci IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | 161162306a36Sopenharmony_ci IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | 161262306a36Sopenharmony_ci IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; 161362306a36Sopenharmony_ci if (efuse->hw_cap.nss > 1) { 161462306a36Sopenharmony_ci highest = cpu_to_le16(780); 161562306a36Sopenharmony_ci mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << 2; 161662306a36Sopenharmony_ci } else { 161762306a36Sopenharmony_ci highest = cpu_to_le16(390); 161862306a36Sopenharmony_ci mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << 2; 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 162262306a36Sopenharmony_ci vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 162362306a36Sopenharmony_ci vht_cap->vht_mcs.rx_highest = highest; 162462306a36Sopenharmony_ci vht_cap->vht_mcs.tx_highest = highest; 162562306a36Sopenharmony_ci} 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_cistatic u16 rtw_get_max_scan_ie_len(struct rtw_dev *rtwdev) 162862306a36Sopenharmony_ci{ 162962306a36Sopenharmony_ci u16 len; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci len = rtwdev->chip->max_scan_ie_len; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_SCAN_OFFLOAD) && 163462306a36Sopenharmony_ci rtwdev->chip->id == RTW_CHIP_TYPE_8822C) 163562306a36Sopenharmony_ci len = IEEE80211_MAX_DATA_LEN; 163662306a36Sopenharmony_ci else if (rtw_fw_feature_ext_check(&rtwdev->fw, FW_FEATURE_EXT_OLD_PAGE_NUM)) 163762306a36Sopenharmony_ci len -= RTW_OLD_PROBE_PG_CNT * TX_PAGE_SIZE; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci return len; 164062306a36Sopenharmony_ci} 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_cistatic void rtw_set_supported_band(struct ieee80211_hw *hw, 164362306a36Sopenharmony_ci const struct rtw_chip_info *chip) 164462306a36Sopenharmony_ci{ 164562306a36Sopenharmony_ci struct rtw_dev *rtwdev = hw->priv; 164662306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci if (chip->band & RTW_BAND_2G) { 164962306a36Sopenharmony_ci sband = kmemdup(&rtw_band_2ghz, sizeof(*sband), GFP_KERNEL); 165062306a36Sopenharmony_ci if (!sband) 165162306a36Sopenharmony_ci goto err_out; 165262306a36Sopenharmony_ci if (chip->ht_supported) 165362306a36Sopenharmony_ci rtw_init_ht_cap(rtwdev, &sband->ht_cap); 165462306a36Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_2GHZ] = sband; 165562306a36Sopenharmony_ci } 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci if (chip->band & RTW_BAND_5G) { 165862306a36Sopenharmony_ci sband = kmemdup(&rtw_band_5ghz, sizeof(*sband), GFP_KERNEL); 165962306a36Sopenharmony_ci if (!sband) 166062306a36Sopenharmony_ci goto err_out; 166162306a36Sopenharmony_ci if (chip->ht_supported) 166262306a36Sopenharmony_ci rtw_init_ht_cap(rtwdev, &sband->ht_cap); 166362306a36Sopenharmony_ci if (chip->vht_supported) 166462306a36Sopenharmony_ci rtw_init_vht_cap(rtwdev, &sband->vht_cap); 166562306a36Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_5GHZ] = sband; 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci return; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_cierr_out: 167162306a36Sopenharmony_ci rtw_err(rtwdev, "failed to set supported band\n"); 167262306a36Sopenharmony_ci} 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_cistatic void rtw_unset_supported_band(struct ieee80211_hw *hw, 167562306a36Sopenharmony_ci const struct rtw_chip_info *chip) 167662306a36Sopenharmony_ci{ 167762306a36Sopenharmony_ci kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]); 167862306a36Sopenharmony_ci kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]); 167962306a36Sopenharmony_ci} 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_cistatic void rtw_vif_smps_iter(void *data, u8 *mac, 168262306a36Sopenharmony_ci struct ieee80211_vif *vif) 168362306a36Sopenharmony_ci{ 168462306a36Sopenharmony_ci struct rtw_dev *rtwdev = (struct rtw_dev *)data; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) 168762306a36Sopenharmony_ci return; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci if (rtwdev->hal.txrx_1ss) 169062306a36Sopenharmony_ci ieee80211_request_smps(vif, 0, IEEE80211_SMPS_STATIC); 169162306a36Sopenharmony_ci else 169262306a36Sopenharmony_ci ieee80211_request_smps(vif, 0, IEEE80211_SMPS_OFF); 169362306a36Sopenharmony_ci} 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_civoid rtw_set_txrx_1ss(struct rtw_dev *rtwdev, bool txrx_1ss) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 169862306a36Sopenharmony_ci struct rtw_hal *hal = &rtwdev->hal; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci if (!chip->ops->config_txrx_mode || rtwdev->hal.txrx_1ss == txrx_1ss) 170162306a36Sopenharmony_ci return; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci rtwdev->hal.txrx_1ss = txrx_1ss; 170462306a36Sopenharmony_ci if (txrx_1ss) 170562306a36Sopenharmony_ci chip->ops->config_txrx_mode(rtwdev, BB_PATH_A, BB_PATH_A, false); 170662306a36Sopenharmony_ci else 170762306a36Sopenharmony_ci chip->ops->config_txrx_mode(rtwdev, hal->antenna_tx, 170862306a36Sopenharmony_ci hal->antenna_rx, false); 170962306a36Sopenharmony_ci rtw_iterate_vifs_atomic(rtwdev, rtw_vif_smps_iter, rtwdev); 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_cistatic void __update_firmware_feature(struct rtw_dev *rtwdev, 171362306a36Sopenharmony_ci struct rtw_fw_state *fw) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci u32 feature; 171662306a36Sopenharmony_ci const struct rtw_fw_hdr *fw_hdr = 171762306a36Sopenharmony_ci (const struct rtw_fw_hdr *)fw->firmware->data; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci feature = le32_to_cpu(fw_hdr->feature); 172062306a36Sopenharmony_ci fw->feature = feature & FW_FEATURE_SIG ? feature : 0; 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C && 172362306a36Sopenharmony_ci RTW_FW_SUIT_VER_CODE(rtwdev->fw) < RTW_FW_VER_CODE(9, 9, 13)) 172462306a36Sopenharmony_ci fw->feature_ext |= FW_FEATURE_EXT_OLD_PAGE_NUM; 172562306a36Sopenharmony_ci} 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_cistatic void __update_firmware_info(struct rtw_dev *rtwdev, 172862306a36Sopenharmony_ci struct rtw_fw_state *fw) 172962306a36Sopenharmony_ci{ 173062306a36Sopenharmony_ci const struct rtw_fw_hdr *fw_hdr = 173162306a36Sopenharmony_ci (const struct rtw_fw_hdr *)fw->firmware->data; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci fw->h2c_version = le16_to_cpu(fw_hdr->h2c_fmt_ver); 173462306a36Sopenharmony_ci fw->version = le16_to_cpu(fw_hdr->version); 173562306a36Sopenharmony_ci fw->sub_version = fw_hdr->subversion; 173662306a36Sopenharmony_ci fw->sub_index = fw_hdr->subindex; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci __update_firmware_feature(rtwdev, fw); 173962306a36Sopenharmony_ci} 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_cistatic void __update_firmware_info_legacy(struct rtw_dev *rtwdev, 174262306a36Sopenharmony_ci struct rtw_fw_state *fw) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci struct rtw_fw_hdr_legacy *legacy = 174562306a36Sopenharmony_ci (struct rtw_fw_hdr_legacy *)fw->firmware->data; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci fw->h2c_version = 0; 174862306a36Sopenharmony_ci fw->version = le16_to_cpu(legacy->version); 174962306a36Sopenharmony_ci fw->sub_version = legacy->subversion1; 175062306a36Sopenharmony_ci fw->sub_index = legacy->subversion2; 175162306a36Sopenharmony_ci} 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_cistatic void update_firmware_info(struct rtw_dev *rtwdev, 175462306a36Sopenharmony_ci struct rtw_fw_state *fw) 175562306a36Sopenharmony_ci{ 175662306a36Sopenharmony_ci if (rtw_chip_wcpu_11n(rtwdev)) 175762306a36Sopenharmony_ci __update_firmware_info_legacy(rtwdev, fw); 175862306a36Sopenharmony_ci else 175962306a36Sopenharmony_ci __update_firmware_info(rtwdev, fw); 176062306a36Sopenharmony_ci} 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_cistatic void rtw_load_firmware_cb(const struct firmware *firmware, void *context) 176362306a36Sopenharmony_ci{ 176462306a36Sopenharmony_ci struct rtw_fw_state *fw = context; 176562306a36Sopenharmony_ci struct rtw_dev *rtwdev = fw->rtwdev; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci if (!firmware || !firmware->data) { 176862306a36Sopenharmony_ci rtw_err(rtwdev, "failed to request firmware\n"); 176962306a36Sopenharmony_ci complete_all(&fw->completion); 177062306a36Sopenharmony_ci return; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci fw->firmware = firmware; 177462306a36Sopenharmony_ci update_firmware_info(rtwdev, fw); 177562306a36Sopenharmony_ci complete_all(&fw->completion); 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci rtw_info(rtwdev, "%sFirmware version %u.%u.%u, H2C version %u\n", 177862306a36Sopenharmony_ci fw->type == RTW_WOWLAN_FW ? "WOW " : "", 177962306a36Sopenharmony_ci fw->version, fw->sub_version, fw->sub_index, fw->h2c_version); 178062306a36Sopenharmony_ci} 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_cistatic int rtw_load_firmware(struct rtw_dev *rtwdev, enum rtw_fw_type type) 178362306a36Sopenharmony_ci{ 178462306a36Sopenharmony_ci const char *fw_name; 178562306a36Sopenharmony_ci struct rtw_fw_state *fw; 178662306a36Sopenharmony_ci int ret; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci switch (type) { 178962306a36Sopenharmony_ci case RTW_WOWLAN_FW: 179062306a36Sopenharmony_ci fw = &rtwdev->wow_fw; 179162306a36Sopenharmony_ci fw_name = rtwdev->chip->wow_fw_name; 179262306a36Sopenharmony_ci break; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci case RTW_NORMAL_FW: 179562306a36Sopenharmony_ci fw = &rtwdev->fw; 179662306a36Sopenharmony_ci fw_name = rtwdev->chip->fw_name; 179762306a36Sopenharmony_ci break; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci default: 180062306a36Sopenharmony_ci rtw_warn(rtwdev, "unsupported firmware type\n"); 180162306a36Sopenharmony_ci return -ENOENT; 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci fw->type = type; 180562306a36Sopenharmony_ci fw->rtwdev = rtwdev; 180662306a36Sopenharmony_ci init_completion(&fw->completion); 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci ret = request_firmware_nowait(THIS_MODULE, true, fw_name, rtwdev->dev, 180962306a36Sopenharmony_ci GFP_KERNEL, fw, rtw_load_firmware_cb); 181062306a36Sopenharmony_ci if (ret) { 181162306a36Sopenharmony_ci rtw_err(rtwdev, "failed to async firmware request\n"); 181262306a36Sopenharmony_ci return ret; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci return 0; 181662306a36Sopenharmony_ci} 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_cistatic int rtw_chip_parameter_setup(struct rtw_dev *rtwdev) 181962306a36Sopenharmony_ci{ 182062306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 182162306a36Sopenharmony_ci struct rtw_hal *hal = &rtwdev->hal; 182262306a36Sopenharmony_ci struct rtw_efuse *efuse = &rtwdev->efuse; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci switch (rtw_hci_type(rtwdev)) { 182562306a36Sopenharmony_ci case RTW_HCI_TYPE_PCIE: 182662306a36Sopenharmony_ci rtwdev->hci.rpwm_addr = 0x03d9; 182762306a36Sopenharmony_ci rtwdev->hci.cpwm_addr = 0x03da; 182862306a36Sopenharmony_ci break; 182962306a36Sopenharmony_ci case RTW_HCI_TYPE_SDIO: 183062306a36Sopenharmony_ci rtwdev->hci.rpwm_addr = REG_SDIO_HRPWM1; 183162306a36Sopenharmony_ci rtwdev->hci.cpwm_addr = REG_SDIO_HCPWM1_V2; 183262306a36Sopenharmony_ci break; 183362306a36Sopenharmony_ci case RTW_HCI_TYPE_USB: 183462306a36Sopenharmony_ci rtwdev->hci.rpwm_addr = 0xfe58; 183562306a36Sopenharmony_ci rtwdev->hci.cpwm_addr = 0xfe57; 183662306a36Sopenharmony_ci break; 183762306a36Sopenharmony_ci default: 183862306a36Sopenharmony_ci rtw_err(rtwdev, "unsupported hci type\n"); 183962306a36Sopenharmony_ci return -EINVAL; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci hal->chip_version = rtw_read32(rtwdev, REG_SYS_CFG1); 184362306a36Sopenharmony_ci hal->cut_version = BIT_GET_CHIP_VER(hal->chip_version); 184462306a36Sopenharmony_ci hal->mp_chip = (hal->chip_version & BIT_RTL_ID) ? 0 : 1; 184562306a36Sopenharmony_ci if (hal->chip_version & BIT_RF_TYPE_ID) { 184662306a36Sopenharmony_ci hal->rf_type = RF_2T2R; 184762306a36Sopenharmony_ci hal->rf_path_num = 2; 184862306a36Sopenharmony_ci hal->antenna_tx = BB_PATH_AB; 184962306a36Sopenharmony_ci hal->antenna_rx = BB_PATH_AB; 185062306a36Sopenharmony_ci } else { 185162306a36Sopenharmony_ci hal->rf_type = RF_1T1R; 185262306a36Sopenharmony_ci hal->rf_path_num = 1; 185362306a36Sopenharmony_ci hal->antenna_tx = BB_PATH_A; 185462306a36Sopenharmony_ci hal->antenna_rx = BB_PATH_A; 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci hal->rf_phy_num = chip->fix_rf_phy_num ? chip->fix_rf_phy_num : 185762306a36Sopenharmony_ci hal->rf_path_num; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci efuse->physical_size = chip->phy_efuse_size; 186062306a36Sopenharmony_ci efuse->logical_size = chip->log_efuse_size; 186162306a36Sopenharmony_ci efuse->protect_size = chip->ptct_efuse_size; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci /* default use ack */ 186462306a36Sopenharmony_ci rtwdev->hal.rcr |= BIT_VHT_DACK; 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci hal->bfee_sts_cap = 3; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci return 0; 186962306a36Sopenharmony_ci} 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_cistatic int rtw_chip_efuse_enable(struct rtw_dev *rtwdev) 187262306a36Sopenharmony_ci{ 187362306a36Sopenharmony_ci struct rtw_fw_state *fw = &rtwdev->fw; 187462306a36Sopenharmony_ci int ret; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci ret = rtw_hci_setup(rtwdev); 187762306a36Sopenharmony_ci if (ret) { 187862306a36Sopenharmony_ci rtw_err(rtwdev, "failed to setup hci\n"); 187962306a36Sopenharmony_ci goto err; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci ret = rtw_mac_power_on(rtwdev); 188362306a36Sopenharmony_ci if (ret) { 188462306a36Sopenharmony_ci rtw_err(rtwdev, "failed to power on mac\n"); 188562306a36Sopenharmony_ci goto err; 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci rtw_write8(rtwdev, REG_C2HEVT, C2H_HW_FEATURE_DUMP); 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci wait_for_completion(&fw->completion); 189162306a36Sopenharmony_ci if (!fw->firmware) { 189262306a36Sopenharmony_ci ret = -EINVAL; 189362306a36Sopenharmony_ci rtw_err(rtwdev, "failed to load firmware\n"); 189462306a36Sopenharmony_ci goto err; 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci ret = rtw_download_firmware(rtwdev, fw); 189862306a36Sopenharmony_ci if (ret) { 189962306a36Sopenharmony_ci rtw_err(rtwdev, "failed to download firmware\n"); 190062306a36Sopenharmony_ci goto err_off; 190162306a36Sopenharmony_ci } 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci return 0; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_cierr_off: 190662306a36Sopenharmony_ci rtw_mac_power_off(rtwdev); 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_cierr: 190962306a36Sopenharmony_ci return ret; 191062306a36Sopenharmony_ci} 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_cistatic int rtw_dump_hw_feature(struct rtw_dev *rtwdev) 191362306a36Sopenharmony_ci{ 191462306a36Sopenharmony_ci struct rtw_efuse *efuse = &rtwdev->efuse; 191562306a36Sopenharmony_ci u8 hw_feature[HW_FEATURE_LEN]; 191662306a36Sopenharmony_ci u8 id; 191762306a36Sopenharmony_ci u8 bw; 191862306a36Sopenharmony_ci int i; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci id = rtw_read8(rtwdev, REG_C2HEVT); 192162306a36Sopenharmony_ci if (id != C2H_HW_FEATURE_REPORT) { 192262306a36Sopenharmony_ci rtw_err(rtwdev, "failed to read hw feature report\n"); 192362306a36Sopenharmony_ci return -EBUSY; 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci for (i = 0; i < HW_FEATURE_LEN; i++) 192762306a36Sopenharmony_ci hw_feature[i] = rtw_read8(rtwdev, REG_C2HEVT + 2 + i); 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci rtw_write8(rtwdev, REG_C2HEVT, 0); 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci bw = GET_EFUSE_HW_CAP_BW(hw_feature); 193262306a36Sopenharmony_ci efuse->hw_cap.bw = hw_bw_cap_to_bitamp(bw); 193362306a36Sopenharmony_ci efuse->hw_cap.hci = GET_EFUSE_HW_CAP_HCI(hw_feature); 193462306a36Sopenharmony_ci efuse->hw_cap.nss = GET_EFUSE_HW_CAP_NSS(hw_feature); 193562306a36Sopenharmony_ci efuse->hw_cap.ptcl = GET_EFUSE_HW_CAP_PTCL(hw_feature); 193662306a36Sopenharmony_ci efuse->hw_cap.ant_num = GET_EFUSE_HW_CAP_ANT_NUM(hw_feature); 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci rtw_hw_config_rf_ant_num(rtwdev, efuse->hw_cap.ant_num); 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci if (efuse->hw_cap.nss == EFUSE_HW_CAP_IGNORE || 194162306a36Sopenharmony_ci efuse->hw_cap.nss > rtwdev->hal.rf_path_num) 194262306a36Sopenharmony_ci efuse->hw_cap.nss = rtwdev->hal.rf_path_num; 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_EFUSE, 194562306a36Sopenharmony_ci "hw cap: hci=0x%02x, bw=0x%02x, ptcl=0x%02x, ant_num=%d, nss=%d\n", 194662306a36Sopenharmony_ci efuse->hw_cap.hci, efuse->hw_cap.bw, efuse->hw_cap.ptcl, 194762306a36Sopenharmony_ci efuse->hw_cap.ant_num, efuse->hw_cap.nss); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci return 0; 195062306a36Sopenharmony_ci} 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_cistatic void rtw_chip_efuse_disable(struct rtw_dev *rtwdev) 195362306a36Sopenharmony_ci{ 195462306a36Sopenharmony_ci rtw_hci_stop(rtwdev); 195562306a36Sopenharmony_ci rtw_mac_power_off(rtwdev); 195662306a36Sopenharmony_ci} 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_cistatic int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev) 195962306a36Sopenharmony_ci{ 196062306a36Sopenharmony_ci struct rtw_efuse *efuse = &rtwdev->efuse; 196162306a36Sopenharmony_ci int ret; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci /* power on mac to read efuse */ 196662306a36Sopenharmony_ci ret = rtw_chip_efuse_enable(rtwdev); 196762306a36Sopenharmony_ci if (ret) 196862306a36Sopenharmony_ci goto out_unlock; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci ret = rtw_parse_efuse_map(rtwdev); 197162306a36Sopenharmony_ci if (ret) 197262306a36Sopenharmony_ci goto out_disable; 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci ret = rtw_dump_hw_feature(rtwdev); 197562306a36Sopenharmony_ci if (ret) 197662306a36Sopenharmony_ci goto out_disable; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci ret = rtw_check_supported_rfe(rtwdev); 197962306a36Sopenharmony_ci if (ret) 198062306a36Sopenharmony_ci goto out_disable; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci if (efuse->crystal_cap == 0xff) 198362306a36Sopenharmony_ci efuse->crystal_cap = 0; 198462306a36Sopenharmony_ci if (efuse->pa_type_2g == 0xff) 198562306a36Sopenharmony_ci efuse->pa_type_2g = 0; 198662306a36Sopenharmony_ci if (efuse->pa_type_5g == 0xff) 198762306a36Sopenharmony_ci efuse->pa_type_5g = 0; 198862306a36Sopenharmony_ci if (efuse->lna_type_2g == 0xff) 198962306a36Sopenharmony_ci efuse->lna_type_2g = 0; 199062306a36Sopenharmony_ci if (efuse->lna_type_5g == 0xff) 199162306a36Sopenharmony_ci efuse->lna_type_5g = 0; 199262306a36Sopenharmony_ci if (efuse->channel_plan == 0xff) 199362306a36Sopenharmony_ci efuse->channel_plan = 0x7f; 199462306a36Sopenharmony_ci if (efuse->rf_board_option == 0xff) 199562306a36Sopenharmony_ci efuse->rf_board_option = 0; 199662306a36Sopenharmony_ci if (efuse->bt_setting & BIT(0)) 199762306a36Sopenharmony_ci efuse->share_ant = true; 199862306a36Sopenharmony_ci if (efuse->regd == 0xff) 199962306a36Sopenharmony_ci efuse->regd = 0; 200062306a36Sopenharmony_ci if (efuse->tx_bb_swing_setting_2g == 0xff) 200162306a36Sopenharmony_ci efuse->tx_bb_swing_setting_2g = 0; 200262306a36Sopenharmony_ci if (efuse->tx_bb_swing_setting_5g == 0xff) 200362306a36Sopenharmony_ci efuse->tx_bb_swing_setting_5g = 0; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci efuse->btcoex = (efuse->rf_board_option & 0xe0) == 0x20; 200662306a36Sopenharmony_ci efuse->ext_pa_2g = efuse->pa_type_2g & BIT(4) ? 1 : 0; 200762306a36Sopenharmony_ci efuse->ext_lna_2g = efuse->lna_type_2g & BIT(3) ? 1 : 0; 200862306a36Sopenharmony_ci efuse->ext_pa_5g = efuse->pa_type_5g & BIT(0) ? 1 : 0; 200962306a36Sopenharmony_ci efuse->ext_lna_2g = efuse->lna_type_5g & BIT(3) ? 1 : 0; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ciout_disable: 201262306a36Sopenharmony_ci rtw_chip_efuse_disable(rtwdev); 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ciout_unlock: 201562306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 201662306a36Sopenharmony_ci return ret; 201762306a36Sopenharmony_ci} 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_cistatic int rtw_chip_board_info_setup(struct rtw_dev *rtwdev) 202062306a36Sopenharmony_ci{ 202162306a36Sopenharmony_ci struct rtw_hal *hal = &rtwdev->hal; 202262306a36Sopenharmony_ci const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev); 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci if (!rfe_def) 202562306a36Sopenharmony_ci return -ENODEV; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci rtw_phy_setup_phy_cond(rtwdev, hal->pkg_type); 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci rtw_phy_init_tx_power(rtwdev); 203062306a36Sopenharmony_ci rtw_load_table(rtwdev, rfe_def->phy_pg_tbl); 203162306a36Sopenharmony_ci rtw_load_table(rtwdev, rfe_def->txpwr_lmt_tbl); 203262306a36Sopenharmony_ci rtw_phy_tx_power_by_rate_config(hal); 203362306a36Sopenharmony_ci rtw_phy_tx_power_limit_config(hal); 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci return 0; 203662306a36Sopenharmony_ci} 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ciint rtw_chip_info_setup(struct rtw_dev *rtwdev) 203962306a36Sopenharmony_ci{ 204062306a36Sopenharmony_ci int ret; 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci ret = rtw_chip_parameter_setup(rtwdev); 204362306a36Sopenharmony_ci if (ret) { 204462306a36Sopenharmony_ci rtw_err(rtwdev, "failed to setup chip parameters\n"); 204562306a36Sopenharmony_ci goto err_out; 204662306a36Sopenharmony_ci } 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci ret = rtw_chip_efuse_info_setup(rtwdev); 204962306a36Sopenharmony_ci if (ret) { 205062306a36Sopenharmony_ci rtw_err(rtwdev, "failed to setup chip efuse info\n"); 205162306a36Sopenharmony_ci goto err_out; 205262306a36Sopenharmony_ci } 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci ret = rtw_chip_board_info_setup(rtwdev); 205562306a36Sopenharmony_ci if (ret) { 205662306a36Sopenharmony_ci rtw_err(rtwdev, "failed to setup chip board info\n"); 205762306a36Sopenharmony_ci goto err_out; 205862306a36Sopenharmony_ci } 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci return 0; 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_cierr_out: 206362306a36Sopenharmony_ci return ret; 206462306a36Sopenharmony_ci} 206562306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_chip_info_setup); 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_cistatic void rtw_stats_init(struct rtw_dev *rtwdev) 206862306a36Sopenharmony_ci{ 206962306a36Sopenharmony_ci struct rtw_traffic_stats *stats = &rtwdev->stats; 207062306a36Sopenharmony_ci struct rtw_dm_info *dm_info = &rtwdev->dm_info; 207162306a36Sopenharmony_ci int i; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci ewma_tp_init(&stats->tx_ewma_tp); 207462306a36Sopenharmony_ci ewma_tp_init(&stats->rx_ewma_tp); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci for (i = 0; i < RTW_EVM_NUM; i++) 207762306a36Sopenharmony_ci ewma_evm_init(&dm_info->ewma_evm[i]); 207862306a36Sopenharmony_ci for (i = 0; i < RTW_SNR_NUM; i++) 207962306a36Sopenharmony_ci ewma_snr_init(&dm_info->ewma_snr[i]); 208062306a36Sopenharmony_ci} 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ciint rtw_core_init(struct rtw_dev *rtwdev) 208362306a36Sopenharmony_ci{ 208462306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 208562306a36Sopenharmony_ci struct rtw_coex *coex = &rtwdev->coex; 208662306a36Sopenharmony_ci int ret; 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci INIT_LIST_HEAD(&rtwdev->rsvd_page_list); 208962306a36Sopenharmony_ci INIT_LIST_HEAD(&rtwdev->txqs); 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci timer_setup(&rtwdev->tx_report.purge_timer, 209262306a36Sopenharmony_ci rtw_tx_report_purge_timer, 0); 209362306a36Sopenharmony_ci rtwdev->tx_wq = alloc_workqueue("rtw_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); 209462306a36Sopenharmony_ci if (!rtwdev->tx_wq) { 209562306a36Sopenharmony_ci rtw_warn(rtwdev, "alloc_workqueue rtw_tx_wq failed\n"); 209662306a36Sopenharmony_ci return -ENOMEM; 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci INIT_DELAYED_WORK(&rtwdev->watch_dog_work, rtw_watch_dog_work); 210062306a36Sopenharmony_ci INIT_DELAYED_WORK(&coex->bt_relink_work, rtw_coex_bt_relink_work); 210162306a36Sopenharmony_ci INIT_DELAYED_WORK(&coex->bt_reenable_work, rtw_coex_bt_reenable_work); 210262306a36Sopenharmony_ci INIT_DELAYED_WORK(&coex->defreeze_work, rtw_coex_defreeze_work); 210362306a36Sopenharmony_ci INIT_DELAYED_WORK(&coex->wl_remain_work, rtw_coex_wl_remain_work); 210462306a36Sopenharmony_ci INIT_DELAYED_WORK(&coex->bt_remain_work, rtw_coex_bt_remain_work); 210562306a36Sopenharmony_ci INIT_DELAYED_WORK(&coex->wl_connecting_work, rtw_coex_wl_connecting_work); 210662306a36Sopenharmony_ci INIT_DELAYED_WORK(&coex->bt_multi_link_remain_work, 210762306a36Sopenharmony_ci rtw_coex_bt_multi_link_remain_work); 210862306a36Sopenharmony_ci INIT_DELAYED_WORK(&coex->wl_ccklock_work, rtw_coex_wl_ccklock_work); 210962306a36Sopenharmony_ci INIT_WORK(&rtwdev->tx_work, rtw_tx_work); 211062306a36Sopenharmony_ci INIT_WORK(&rtwdev->c2h_work, rtw_c2h_work); 211162306a36Sopenharmony_ci INIT_WORK(&rtwdev->ips_work, rtw_ips_work); 211262306a36Sopenharmony_ci INIT_WORK(&rtwdev->fw_recovery_work, rtw_fw_recovery_work); 211362306a36Sopenharmony_ci INIT_WORK(&rtwdev->update_beacon_work, rtw_fw_update_beacon_work); 211462306a36Sopenharmony_ci INIT_WORK(&rtwdev->ba_work, rtw_txq_ba_work); 211562306a36Sopenharmony_ci skb_queue_head_init(&rtwdev->c2h_queue); 211662306a36Sopenharmony_ci skb_queue_head_init(&rtwdev->coex.queue); 211762306a36Sopenharmony_ci skb_queue_head_init(&rtwdev->tx_report.queue); 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci spin_lock_init(&rtwdev->txq_lock); 212062306a36Sopenharmony_ci spin_lock_init(&rtwdev->tx_report.q_lock); 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci mutex_init(&rtwdev->mutex); 212362306a36Sopenharmony_ci mutex_init(&rtwdev->hal.tx_power_mutex); 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci init_waitqueue_head(&rtwdev->coex.wait); 212662306a36Sopenharmony_ci init_completion(&rtwdev->lps_leave_check); 212762306a36Sopenharmony_ci init_completion(&rtwdev->fw_scan_density); 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci rtwdev->sec.total_cam_num = 32; 213062306a36Sopenharmony_ci rtwdev->hal.current_channel = 1; 213162306a36Sopenharmony_ci rtwdev->dm_info.fix_rate = U8_MAX; 213262306a36Sopenharmony_ci set_bit(RTW_BC_MC_MACID, rtwdev->mac_id_map); 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci rtw_stats_init(rtwdev); 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci /* default rx filter setting */ 213762306a36Sopenharmony_ci rtwdev->hal.rcr = BIT_APP_FCS | BIT_APP_MIC | BIT_APP_ICV | 213862306a36Sopenharmony_ci BIT_PKTCTL_DLEN | BIT_HTC_LOC_CTRL | BIT_APP_PHYSTS | 213962306a36Sopenharmony_ci BIT_AB | BIT_AM | BIT_APM; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci ret = rtw_load_firmware(rtwdev, RTW_NORMAL_FW); 214262306a36Sopenharmony_ci if (ret) { 214362306a36Sopenharmony_ci rtw_warn(rtwdev, "no firmware loaded\n"); 214462306a36Sopenharmony_ci goto out; 214562306a36Sopenharmony_ci } 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci if (chip->wow_fw_name) { 214862306a36Sopenharmony_ci ret = rtw_load_firmware(rtwdev, RTW_WOWLAN_FW); 214962306a36Sopenharmony_ci if (ret) { 215062306a36Sopenharmony_ci rtw_warn(rtwdev, "no wow firmware loaded\n"); 215162306a36Sopenharmony_ci wait_for_completion(&rtwdev->fw.completion); 215262306a36Sopenharmony_ci if (rtwdev->fw.firmware) 215362306a36Sopenharmony_ci release_firmware(rtwdev->fw.firmware); 215462306a36Sopenharmony_ci goto out; 215562306a36Sopenharmony_ci } 215662306a36Sopenharmony_ci } 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci return 0; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ciout: 216162306a36Sopenharmony_ci destroy_workqueue(rtwdev->tx_wq); 216262306a36Sopenharmony_ci return ret; 216362306a36Sopenharmony_ci} 216462306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_core_init); 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_civoid rtw_core_deinit(struct rtw_dev *rtwdev) 216762306a36Sopenharmony_ci{ 216862306a36Sopenharmony_ci struct rtw_fw_state *fw = &rtwdev->fw; 216962306a36Sopenharmony_ci struct rtw_fw_state *wow_fw = &rtwdev->wow_fw; 217062306a36Sopenharmony_ci struct rtw_rsvd_page *rsvd_pkt, *tmp; 217162306a36Sopenharmony_ci unsigned long flags; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci rtw_wait_firmware_completion(rtwdev); 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci if (fw->firmware) 217662306a36Sopenharmony_ci release_firmware(fw->firmware); 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci if (wow_fw->firmware) 217962306a36Sopenharmony_ci release_firmware(wow_fw->firmware); 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci destroy_workqueue(rtwdev->tx_wq); 218262306a36Sopenharmony_ci timer_delete_sync(&rtwdev->tx_report.purge_timer); 218362306a36Sopenharmony_ci spin_lock_irqsave(&rtwdev->tx_report.q_lock, flags); 218462306a36Sopenharmony_ci skb_queue_purge(&rtwdev->tx_report.queue); 218562306a36Sopenharmony_ci spin_unlock_irqrestore(&rtwdev->tx_report.q_lock, flags); 218662306a36Sopenharmony_ci skb_queue_purge(&rtwdev->coex.queue); 218762306a36Sopenharmony_ci skb_queue_purge(&rtwdev->c2h_queue); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci list_for_each_entry_safe(rsvd_pkt, tmp, &rtwdev->rsvd_page_list, 219062306a36Sopenharmony_ci build_list) { 219162306a36Sopenharmony_ci list_del(&rsvd_pkt->build_list); 219262306a36Sopenharmony_ci kfree(rsvd_pkt); 219362306a36Sopenharmony_ci } 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci mutex_destroy(&rtwdev->mutex); 219662306a36Sopenharmony_ci mutex_destroy(&rtwdev->hal.tx_power_mutex); 219762306a36Sopenharmony_ci} 219862306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_core_deinit); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ciint rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) 220162306a36Sopenharmony_ci{ 220262306a36Sopenharmony_ci struct rtw_hal *hal = &rtwdev->hal; 220362306a36Sopenharmony_ci int max_tx_headroom = 0; 220462306a36Sopenharmony_ci int ret; 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci max_tx_headroom = rtwdev->chip->tx_pkt_desc_sz; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) 220962306a36Sopenharmony_ci max_tx_headroom += RTW_SDIO_DATA_PTR_ALIGN; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci hw->extra_tx_headroom = max_tx_headroom; 221262306a36Sopenharmony_ci hw->queues = IEEE80211_NUM_ACS; 221362306a36Sopenharmony_ci hw->txq_data_size = sizeof(struct rtw_txq); 221462306a36Sopenharmony_ci hw->sta_data_size = sizeof(struct rtw_sta_info); 221562306a36Sopenharmony_ci hw->vif_data_size = sizeof(struct rtw_vif); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 221862306a36Sopenharmony_ci ieee80211_hw_set(hw, RX_INCLUDES_FCS); 221962306a36Sopenharmony_ci ieee80211_hw_set(hw, AMPDU_AGGREGATION); 222062306a36Sopenharmony_ci ieee80211_hw_set(hw, MFP_CAPABLE); 222162306a36Sopenharmony_ci ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 222262306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_PS); 222362306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); 222462306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 222562306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 222662306a36Sopenharmony_ci ieee80211_hw_set(hw, HAS_RATE_CONTROL); 222762306a36Sopenharmony_ci ieee80211_hw_set(hw, TX_AMSDU); 222862306a36Sopenharmony_ci ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 223162306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | 223262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_ADHOC) | 223362306a36Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT); 223462306a36Sopenharmony_ci hw->wiphy->available_antennas_tx = hal->antenna_tx; 223562306a36Sopenharmony_ci hw->wiphy->available_antennas_rx = hal->antenna_rx; 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | 223862306a36Sopenharmony_ci WIPHY_FLAG_TDLS_EXTERNAL_SETUP; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; 224162306a36Sopenharmony_ci hw->wiphy->max_scan_ssids = RTW_SCAN_MAX_SSIDS; 224262306a36Sopenharmony_ci hw->wiphy->max_scan_ie_len = rtw_get_max_scan_ie_len(rtwdev); 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C) { 224562306a36Sopenharmony_ci hw->wiphy->iface_combinations = rtw_iface_combs; 224662306a36Sopenharmony_ci hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw_iface_combs); 224762306a36Sopenharmony_ci } 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); 225062306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SCAN_RANDOM_SN); 225162306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci#ifdef CONFIG_PM 225462306a36Sopenharmony_ci hw->wiphy->wowlan = rtwdev->chip->wowlan_stub; 225562306a36Sopenharmony_ci hw->wiphy->max_sched_scan_ssids = rtwdev->chip->max_sched_scan_ssids; 225662306a36Sopenharmony_ci#endif 225762306a36Sopenharmony_ci rtw_set_supported_band(hw, rtwdev->chip); 225862306a36Sopenharmony_ci SET_IEEE80211_PERM_ADDR(hw, rtwdev->efuse.addr); 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci hw->wiphy->sar_capa = &rtw_sar_capa; 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci ret = rtw_regd_init(rtwdev); 226362306a36Sopenharmony_ci if (ret) { 226462306a36Sopenharmony_ci rtw_err(rtwdev, "failed to init regd\n"); 226562306a36Sopenharmony_ci return ret; 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci ret = ieee80211_register_hw(hw); 226962306a36Sopenharmony_ci if (ret) { 227062306a36Sopenharmony_ci rtw_err(rtwdev, "failed to register hw\n"); 227162306a36Sopenharmony_ci return ret; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci ret = rtw_regd_hint(rtwdev); 227562306a36Sopenharmony_ci if (ret) { 227662306a36Sopenharmony_ci rtw_err(rtwdev, "failed to hint regd\n"); 227762306a36Sopenharmony_ci return ret; 227862306a36Sopenharmony_ci } 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci rtw_debugfs_init(rtwdev); 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci rtwdev->bf_info.bfer_mu_cnt = 0; 228362306a36Sopenharmony_ci rtwdev->bf_info.bfer_su_cnt = 0; 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci return 0; 228662306a36Sopenharmony_ci} 228762306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_register_hw); 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_civoid rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) 229062306a36Sopenharmony_ci{ 229162306a36Sopenharmony_ci const struct rtw_chip_info *chip = rtwdev->chip; 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci ieee80211_unregister_hw(hw); 229462306a36Sopenharmony_ci rtw_unset_supported_band(hw, chip); 229562306a36Sopenharmony_ci} 229662306a36Sopenharmony_ciEXPORT_SYMBOL(rtw_unregister_hw); 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_cistatic 229962306a36Sopenharmony_civoid rtw_swap_reg_nbytes(struct rtw_dev *rtwdev, const struct rtw_hw_reg *reg1, 230062306a36Sopenharmony_ci const struct rtw_hw_reg *reg2, u8 nbytes) 230162306a36Sopenharmony_ci{ 230262306a36Sopenharmony_ci u8 i; 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci for (i = 0; i < nbytes; i++) { 230562306a36Sopenharmony_ci u8 v1 = rtw_read8(rtwdev, reg1->addr + i); 230662306a36Sopenharmony_ci u8 v2 = rtw_read8(rtwdev, reg2->addr + i); 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci rtw_write8(rtwdev, reg1->addr + i, v2); 230962306a36Sopenharmony_ci rtw_write8(rtwdev, reg2->addr + i, v1); 231062306a36Sopenharmony_ci } 231162306a36Sopenharmony_ci} 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_cistatic 231462306a36Sopenharmony_civoid rtw_swap_reg_mask(struct rtw_dev *rtwdev, const struct rtw_hw_reg *reg1, 231562306a36Sopenharmony_ci const struct rtw_hw_reg *reg2) 231662306a36Sopenharmony_ci{ 231762306a36Sopenharmony_ci u32 v1, v2; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci v1 = rtw_read32_mask(rtwdev, reg1->addr, reg1->mask); 232062306a36Sopenharmony_ci v2 = rtw_read32_mask(rtwdev, reg2->addr, reg2->mask); 232162306a36Sopenharmony_ci rtw_write32_mask(rtwdev, reg2->addr, reg2->mask, v1); 232262306a36Sopenharmony_ci rtw_write32_mask(rtwdev, reg1->addr, reg1->mask, v2); 232362306a36Sopenharmony_ci} 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_cistruct rtw_iter_port_switch_data { 232662306a36Sopenharmony_ci struct rtw_dev *rtwdev; 232762306a36Sopenharmony_ci struct rtw_vif *rtwvif_ap; 232862306a36Sopenharmony_ci}; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_cistatic void rtw_port_switch_iter(void *data, struct ieee80211_vif *vif) 233162306a36Sopenharmony_ci{ 233262306a36Sopenharmony_ci struct rtw_iter_port_switch_data *iter_data = data; 233362306a36Sopenharmony_ci struct rtw_dev *rtwdev = iter_data->rtwdev; 233462306a36Sopenharmony_ci struct rtw_vif *rtwvif_target = (struct rtw_vif *)vif->drv_priv; 233562306a36Sopenharmony_ci struct rtw_vif *rtwvif_ap = iter_data->rtwvif_ap; 233662306a36Sopenharmony_ci const struct rtw_hw_reg *reg1, *reg2; 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci if (rtwvif_target->port != RTW_PORT_0) 233962306a36Sopenharmony_ci return; 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci rtw_dbg(rtwdev, RTW_DBG_STATE, "AP port switch from %d -> %d\n", 234262306a36Sopenharmony_ci rtwvif_ap->port, rtwvif_target->port); 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci /* Leave LPS so the value swapped are not in PS mode */ 234562306a36Sopenharmony_ci rtw_leave_lps(rtwdev); 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci reg1 = &rtwvif_ap->conf->net_type; 234862306a36Sopenharmony_ci reg2 = &rtwvif_target->conf->net_type; 234962306a36Sopenharmony_ci rtw_swap_reg_mask(rtwdev, reg1, reg2); 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci reg1 = &rtwvif_ap->conf->mac_addr; 235262306a36Sopenharmony_ci reg2 = &rtwvif_target->conf->mac_addr; 235362306a36Sopenharmony_ci rtw_swap_reg_nbytes(rtwdev, reg1, reg2, ETH_ALEN); 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci reg1 = &rtwvif_ap->conf->bssid; 235662306a36Sopenharmony_ci reg2 = &rtwvif_target->conf->bssid; 235762306a36Sopenharmony_ci rtw_swap_reg_nbytes(rtwdev, reg1, reg2, ETH_ALEN); 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci reg1 = &rtwvif_ap->conf->bcn_ctrl; 236062306a36Sopenharmony_ci reg2 = &rtwvif_target->conf->bcn_ctrl; 236162306a36Sopenharmony_ci rtw_swap_reg_nbytes(rtwdev, reg1, reg2, 1); 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci swap(rtwvif_target->port, rtwvif_ap->port); 236462306a36Sopenharmony_ci swap(rtwvif_target->conf, rtwvif_ap->conf); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci rtw_fw_default_port(rtwdev, rtwvif_target); 236762306a36Sopenharmony_ci} 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_civoid rtw_core_port_switch(struct rtw_dev *rtwdev, struct ieee80211_vif *vif) 237062306a36Sopenharmony_ci{ 237162306a36Sopenharmony_ci struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 237262306a36Sopenharmony_ci struct rtw_iter_port_switch_data iter_data; 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_AP || rtwvif->port == RTW_PORT_0) 237562306a36Sopenharmony_ci return; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci iter_data.rtwdev = rtwdev; 237862306a36Sopenharmony_ci iter_data.rtwvif_ap = rtwvif; 237962306a36Sopenharmony_ci rtw_iterate_vifs(rtwdev, rtw_port_switch_iter, &iter_data); 238062306a36Sopenharmony_ci} 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_cistatic void rtw_check_sta_active_iter(void *data, struct ieee80211_vif *vif) 238362306a36Sopenharmony_ci{ 238462306a36Sopenharmony_ci struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; 238562306a36Sopenharmony_ci bool *active = data; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci if (*active) 238862306a36Sopenharmony_ci return; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_STATION) 239162306a36Sopenharmony_ci return; 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci if (vif->cfg.assoc || !is_zero_ether_addr(rtwvif->bssid)) 239462306a36Sopenharmony_ci *active = true; 239562306a36Sopenharmony_ci} 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_cibool rtw_core_check_sta_active(struct rtw_dev *rtwdev) 239862306a36Sopenharmony_ci{ 239962306a36Sopenharmony_ci bool sta_active = false; 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci rtw_iterate_vifs(rtwdev, rtw_check_sta_active_iter, &sta_active); 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci return rtwdev->ap_active || sta_active; 240462306a36Sopenharmony_ci} 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_civoid rtw_core_enable_beacon(struct rtw_dev *rtwdev, bool enable) 240762306a36Sopenharmony_ci{ 240862306a36Sopenharmony_ci if (!rtwdev->ap_active) 240962306a36Sopenharmony_ci return; 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci if (enable) { 241262306a36Sopenharmony_ci rtw_write32_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); 241362306a36Sopenharmony_ci rtw_write32_clr(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); 241462306a36Sopenharmony_ci } else { 241562306a36Sopenharmony_ci rtw_write32_clr(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); 241662306a36Sopenharmony_ci rtw_write32_set(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); 241762306a36Sopenharmony_ci } 241862306a36Sopenharmony_ci} 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ciMODULE_AUTHOR("Realtek Corporation"); 242162306a36Sopenharmony_ciMODULE_DESCRIPTION("Realtek 802.11ac wireless core module"); 242262306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 2423