diff options
Diffstat (limited to 'drivers/net/wireless/realtek/rtw88/main.c')
| -rw-r--r-- | drivers/net/wireless/realtek/rtw88/main.c | 410 |
1 files changed, 326 insertions, 84 deletions
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 888427cf3bdf..fa0ed39cb199 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -18,6 +18,8 @@ #include "debug.h" #include "bf.h" #include "sar.h" +#include "sdio.h" +#include "led.h" bool rtw_disable_lps_deep_mode; EXPORT_SYMBOL(rtw_disable_lps_deep_mode); @@ -102,6 +104,26 @@ static struct ieee80211_rate rtw_ratetable[] = { {.bitrate = 540, .hw_value = 0x0b,}, }; +static const struct ieee80211_iface_limit rtw_iface_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + } +}; + +static const struct ieee80211_iface_combination rtw_iface_combs[] = { + { + .limits = rtw_iface_limits, + .n_limits = ARRAY_SIZE(rtw_iface_limits), + .max_interfaces = 2, + .num_different_channels = 1, + } +}; + u16 rtw_desc_to_bitrate(u8 desc_rate) { struct ieee80211_rate rate; @@ -114,7 +136,7 @@ u16 rtw_desc_to_bitrate(u8 desc_rate) return rate.bitrate; } -static struct ieee80211_supported_band rtw_band_2ghz = { +static const struct ieee80211_supported_band rtw_band_2ghz = { .band = NL80211_BAND_2GHZ, .channels = rtw_channeltable_2g, @@ -127,7 +149,7 @@ static struct ieee80211_supported_band rtw_band_2ghz = { .vht_cap = {0}, }; -static struct ieee80211_supported_band rtw_band_5ghz = { +static const struct ieee80211_supported_band rtw_band_5ghz = { .band = NL80211_BAND_5GHZ, .channels = rtw_channeltable_5g, @@ -164,8 +186,7 @@ static void rtw_dynamic_csi_rate(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) bf_info->cur_csi_rpt_rate = new_csi_rate_idx; } -static void rtw_vif_watch_dog_iter(void *data, u8 *mac, - struct ieee80211_vif *vif) +static void rtw_vif_watch_dog_iter(void *data, struct ieee80211_vif *vif) { struct rtw_watch_dog_iter_data *iter_data = data; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; @@ -182,6 +203,21 @@ static void rtw_vif_watch_dog_iter(void *data, u8 *mac, rtwvif->stats.rx_cnt = 0; } +static void rtw_sw_beacon_loss_check(struct rtw_dev *rtwdev, + struct rtw_vif *rtwvif, int received_beacons) +{ + int watchdog_delay = 2000000 / 1024; /* TU */ + int beacon_int, expected_beacons; + + if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER) || !rtwvif) + return; + + beacon_int = rtwvif_to_vif(rtwvif)->bss_conf.beacon_int; + expected_beacons = DIV_ROUND_UP(watchdog_delay, beacon_int); + + rtwdev->beacon_loss = received_beacons < expected_beacons / 2; +} + /* process TX/RX statistics periodically for hardware, * the information helps hardware to enhance performance */ @@ -192,6 +228,8 @@ static void rtw_watch_dog_work(struct work_struct *work) struct rtw_traffic_stats *stats = &rtwdev->stats; struct rtw_watch_dog_iter_data data = {}; bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); + int received_beacons = rtwdev->dm_info.cur_pkt_count.num_bcn_pkt; + u32 tx_unicast_mbps, rx_unicast_mbps; bool ps_active; mutex_lock(&rtwdev->mutex); @@ -207,9 +245,6 @@ static void rtw_watch_dog_work(struct work_struct *work) else clear_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); - rtw_coex_wl_status_check(rtwdev); - rtw_coex_query_bt_hid_list(rtwdev); - if (busy_traffic != test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags)) rtw_coex_wl_status_change_notify(rtwdev, 0); @@ -219,10 +254,11 @@ static void rtw_watch_dog_work(struct work_struct *work) else ps_active = false; - ewma_tp_add(&stats->tx_ewma_tp, - (u32)(stats->tx_unicast >> RTW_TP_SHIFT)); - ewma_tp_add(&stats->rx_ewma_tp, - (u32)(stats->rx_unicast >> RTW_TP_SHIFT)); + tx_unicast_mbps = stats->tx_unicast >> RTW_TP_SHIFT; + rx_unicast_mbps = stats->rx_unicast >> RTW_TP_SHIFT; + + ewma_tp_add(&stats->tx_ewma_tp, tx_unicast_mbps); + ewma_tp_add(&stats->rx_ewma_tp, rx_unicast_mbps); stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp); stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp); @@ -237,24 +273,34 @@ static void rtw_watch_dog_work(struct work_struct *work) /* make sure BB/RF is working for dynamic mech */ rtw_leave_lps(rtwdev); + rtw_coex_wl_status_check(rtwdev); + rtw_coex_query_bt_hid_list(rtwdev); + rtw_coex_active_query_bt_info(rtwdev); rtw_phy_dynamic_mechanism(rtwdev); + rtw_hci_dynamic_rx_agg(rtwdev, + tx_unicast_mbps >= 1 || rx_unicast_mbps >= 1); + data.rtwdev = rtwdev; - /* use atomic version to avoid taking local->iflist_mtx mutex */ - rtw_iterate_vifs_atomic(rtwdev, rtw_vif_watch_dog_iter, &data); + /* rtw_iterate_vifs internally uses an atomic iterator which is needed + * to avoid taking local->iflist_mtx mutex + */ + rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data); + + rtw_sw_beacon_loss_check(rtwdev, data.rtwvif, received_beacons); /* fw supports only one station associated to enter lps, if there are * more than two stations associated to the AP, then we can not enter * lps, because fw does not handle the overlapped beacon interval * - * mac80211 should iterate vifs and determine if driver can enter - * ps by passing IEEE80211_CONF_PS to us, all we need to do is to + * rtw_recalc_lps() iterate vifs and determine if driver can enter + * ps by vif->type and vif->cfg.ps, all we need to do here is to * get that vif and check if device is having traffic more than the * threshold. */ if (rtwdev->ps_enabled && data.rtwvif && !ps_active && - !rtwdev->beacon_loss) + !rtwdev->beacon_loss && !rtwdev->ap_active) rtw_enter_lps(rtwdev, data.rtwvif->port); rtwdev->watch_dog_cnt++; @@ -285,33 +331,40 @@ static void rtw_ips_work(struct work_struct *work) mutex_unlock(&rtwdev->mutex); } -static u8 rtw_acquire_macid(struct rtw_dev *rtwdev) +static void rtw_sta_rc_work(struct work_struct *work) { - unsigned long mac_id; + struct rtw_sta_info *si = container_of(work, struct rtw_sta_info, + rc_work); + struct rtw_dev *rtwdev = si->rtwdev; - mac_id = find_first_zero_bit(rtwdev->mac_id_map, RTW_MAX_MAC_ID_NUM); - if (mac_id < RTW_MAX_MAC_ID_NUM) - set_bit(mac_id, rtwdev->mac_id_map); - - return mac_id; + mutex_lock(&rtwdev->mutex); + rtw_update_sta_info(rtwdev, si, true); + mutex_unlock(&rtwdev->mutex); } int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; int i; - si->mac_id = rtw_acquire_macid(rtwdev); - if (si->mac_id >= RTW_MAX_MAC_ID_NUM) - return -ENOSPC; + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { + si->mac_id = rtwvif->mac_id; + } else { + si->mac_id = rtw_acquire_macid(rtwdev); + if (si->mac_id >= RTW_MAX_MAC_ID_NUM) + return -ENOSPC; + } + si->rtwdev = rtwdev; si->sta = sta; si->vif = vif; si->init_ra_lv = 1; ewma_rssi_init(&si->avg_rssi); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) rtw_txq_init(rtwdev, sta->txq[i]); + INIT_WORK(&si->rc_work, rtw_sta_rc_work); rtw_update_sta_info(rtwdev, si, true); rtw_fw_media_status_report(rtwdev, si->mac_id, true); @@ -328,9 +381,13 @@ void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, bool fw_exist) { struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + struct ieee80211_vif *vif = si->vif; int i; - rtw_release_macid(rtwdev, si->mac_id); + cancel_work_sync(&si->rc_work); + + if (vif->type != NL80211_IFTYPE_STATION || sta->tdls) + rtw_release_macid(rtwdev, si->mac_id); if (fw_exist) rtw_fw_media_status_report(rtwdev, si->mac_id, false); @@ -570,6 +627,8 @@ static void rtw_reset_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) rtw_bf_disassoc(rtwdev, vif, NULL); rtw_vif_assoc_changed(rtwvif, NULL); rtw_txq_cleanup(rtwdev, vif->txq); + + rtw_release_macid(rtwdev, rtwvif->mac_id); } void rtw_fw_recovery(struct rtw_dev *rtwdev) @@ -577,6 +636,7 @@ void rtw_fw_recovery(struct rtw_dev *rtwdev) if (!test_bit(RTW_FLAG_RESTARTING, rtwdev->flags)) ieee80211_queue_work(rtwdev->hw, &rtwdev->fw_recovery_work); } +EXPORT_SYMBOL(rtw_fw_recovery); static void __fw_recovery_work(struct rtw_dev *rtwdev) { @@ -607,6 +667,7 @@ free: rcu_read_unlock(); rtw_iterate_stas_atomic(rtwdev, rtw_reset_sta_iter, rtwdev); rtw_iterate_vifs_atomic(rtwdev, rtw_reset_vif_iter, rtwdev); + bitmap_zero(rtwdev->hw_port, RTW_PORT_NUM); rtw_enter_ips(rtwdev); } @@ -826,6 +887,9 @@ void rtw_set_channel(struct rtw_dev *rtwdev) rtw_update_channel(rtwdev, center_chan, primary_chan, band, bandwidth); + if (rtwdev->scan_info.op_chan) + rtw_store_op_chan(rtwdev, true); + chip->ops->set_channel(rtwdev, center_chan, bandwidth, hal->current_primary_channel_index); @@ -1155,7 +1219,6 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, u8 wireless_set; u8 bw_mode; u8 rate_id; - u8 rf_type = RF_1T1R; u8 stbc_en = 0; u8 ldpc_en = 0; u8 tx_num = 1; @@ -1172,7 +1235,9 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) ldpc_en = VHT_LDPC_EN; } else if (sta->deflink.ht_cap.ht_supported) { - ra_mask |= (sta->deflink.ht_cap.mcs.rx_mask[1] << 20) | + ra_mask |= ((u64)sta->deflink.ht_cap.mcs.rx_mask[3] << 36) | + ((u64)sta->deflink.ht_cap.mcs.rx_mask[2] << 28) | + (sta->deflink.ht_cap.mcs.rx_mask[1] << 20) | (sta->deflink.ht_cap.mcs.rx_mask[0] << 12); if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) stbc_en = HT_STBC_EN; @@ -1182,6 +1247,9 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, if (efuse->hw_cap.nss == 1 || rtwdev->hal.txrx_1ss) ra_mask &= RA_MASK_VHT_RATES_1SS | RA_MASK_HT_RATES_1SS; + else if (efuse->hw_cap.nss == 2) + ra_mask &= RA_MASK_VHT_RATES_2SS | RA_MASK_HT_RATES_2SS | + RA_MASK_VHT_RATES_1SS | RA_MASK_HT_RATES_1SS; if (hal->current_band_type == RTW_BAND_5G) { ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_5GHZ] << 4; @@ -1240,13 +1308,9 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, break; } - if (sta->deflink.vht_cap.vht_supported && ra_mask & 0xffc00000) { - tx_num = 2; - rf_type = RF_2T2R; - } else if (sta->deflink.ht_cap.ht_supported && ra_mask & 0xfff00000) { - tx_num = 2; - rf_type = RF_2T2R; - } + if (sta->deflink.vht_cap.vht_supported || + sta->deflink.ht_cap.ht_supported) + tx_num = efuse->hw_cap.nss; rate_id = get_rate_id(wireless_set, bw_mode, tx_num); @@ -1257,8 +1321,6 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, si->bw_mode = bw_mode; si->stbc_en = stbc_en; si->ldpc_en = ldpc_en; - si->rf_type = rf_type; - si->wireless_set = wireless_set; si->sgi_enable = is_support_sgi; si->vht_enable = is_vht_enable; si->ra_mask = ra_mask; @@ -1267,25 +1329,27 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, rtw_fw_send_ra_info(rtwdev, si, reset_ra_mask); } -static int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) +int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) { const struct rtw_chip_info *chip = rtwdev->chip; struct rtw_fw_state *fw; + int ret = 0; fw = &rtwdev->fw; wait_for_completion(&fw->completion); if (!fw->firmware) - return -EINVAL; + ret = -EINVAL; if (chip->wow_fw_name) { fw = &rtwdev->wow_fw; wait_for_completion(&fw->completion); if (!fw->firmware) - return -EINVAL; + ret = -EINVAL; } - return 0; + return ret; } +EXPORT_SYMBOL(rtw_wait_firmware_completion); static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) @@ -1307,7 +1371,7 @@ static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, return LPS_DEEP_MODE_NONE; } -static int rtw_power_on(struct rtw_dev *rtwdev) +int rtw_power_on(struct rtw_dev *rtwdev) { const struct rtw_chip_info *chip = rtwdev->chip; struct rtw_fw_state *fw = &rtwdev->fw; @@ -1348,6 +1412,12 @@ static int rtw_power_on(struct rtw_dev *rtwdev) chip->ops->phy_set_param(rtwdev); + ret = rtw_mac_postinit(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to configure mac in postinit\n"); + goto err_off; + } + ret = rtw_hci_start(rtwdev); if (ret) { rtw_err(rtwdev, "failed to start hci\n"); @@ -1370,6 +1440,7 @@ err_off: err: return ret; } +EXPORT_SYMBOL(rtw_power_on); void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start) { @@ -1442,7 +1513,7 @@ int rtw_core_start(struct rtw_dev *rtwdev) { int ret; - ret = rtw_power_on(rtwdev); + ret = rtwdev->chip->ops->power_on(rtwdev); if (ret) return ret; @@ -1462,12 +1533,13 @@ int rtw_core_start(struct rtw_dev *rtwdev) return 0; } -static void rtw_power_off(struct rtw_dev *rtwdev) +void rtw_power_off(struct rtw_dev *rtwdev) { rtw_hci_stop(rtwdev); rtw_coex_power_off_setting(rtwdev); rtw_mac_power_off(rtwdev); } +EXPORT_SYMBOL(rtw_power_off); void rtw_core_stop(struct rtw_dev *rtwdev) { @@ -1492,7 +1564,7 @@ void rtw_core_stop(struct rtw_dev *rtwdev) mutex_lock(&rtwdev->mutex); - rtw_power_off(rtwdev); + rtwdev->chip->ops->power_off(rtwdev); } static void rtw_init_ht_cap(struct rtw_dev *rtwdev, @@ -1500,6 +1572,7 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev, { const struct rtw_chip_info *chip = rtwdev->chip; struct rtw_efuse *efuse = &rtwdev->efuse; + int i; ht_cap->ht_supported = true; ht_cap->cap = 0; @@ -1519,25 +1592,20 @@ static void rtw_init_ht_cap(struct rtw_dev *rtwdev, ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; ht_cap->ampdu_density = chip->ampdu_density; ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; - if (efuse->hw_cap.nss > 1) { - ht_cap->mcs.rx_mask[0] = 0xFF; - ht_cap->mcs.rx_mask[1] = 0xFF; - ht_cap->mcs.rx_mask[4] = 0x01; - ht_cap->mcs.rx_highest = cpu_to_le16(300); - } else { - ht_cap->mcs.rx_mask[0] = 0xFF; - ht_cap->mcs.rx_mask[1] = 0x00; - ht_cap->mcs.rx_mask[4] = 0x01; - ht_cap->mcs.rx_highest = cpu_to_le16(150); - } + + for (i = 0; i < efuse->hw_cap.nss; i++) + ht_cap->mcs.rx_mask[i] = 0xFF; + ht_cap->mcs.rx_mask[4] = 0x01; + ht_cap->mcs.rx_highest = cpu_to_le16(150 * efuse->hw_cap.nss); } static void rtw_init_vht_cap(struct rtw_dev *rtwdev, struct ieee80211_sta_vht_cap *vht_cap) { struct rtw_efuse *efuse = &rtwdev->efuse; - u16 mcs_map; + u16 mcs_map = 0; __le16 highest; + int i; if (efuse->hw_cap.ptcl != EFUSE_HW_CAP_IGNORE && efuse->hw_cap.ptcl != EFUSE_HW_CAP_PTCL_VHT) @@ -1560,21 +1628,15 @@ static void rtw_init_vht_cap(struct rtw_dev *rtwdev, if (rtw_chip_has_rx_ldpc(rtwdev)) vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; - mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | - IEEE80211_VHT_MCS_NOT_SUPPORTED << 14; - if (efuse->hw_cap.nss > 1) { - highest = cpu_to_le16(780); - mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << 2; - } else { - highest = cpu_to_le16(390); - mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << 2; + for (i = 0; i < 8; i++) { + if (i < efuse->hw_cap.nss) + mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2); + else + mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2); } + highest = cpu_to_le16(390 * efuse->hw_cap.nss); + vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); vht_cap->vht_mcs.rx_highest = highest; @@ -1710,7 +1772,7 @@ static void __update_firmware_info_legacy(struct rtw_dev *rtwdev, static void update_firmware_info(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) { - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) __update_firmware_info_legacy(rtwdev, fw); else __update_firmware_info(rtwdev, fw); @@ -1783,6 +1845,10 @@ static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev) rtwdev->hci.rpwm_addr = 0x03d9; rtwdev->hci.cpwm_addr = 0x03da; break; + case RTW_HCI_TYPE_SDIO: + rtwdev->hci.rpwm_addr = REG_SDIO_HRPWM1; + rtwdev->hci.cpwm_addr = REG_SDIO_HCPWM1_V2; + break; case RTW_HCI_TYPE_USB: rtwdev->hci.rpwm_addr = 0xfe58; rtwdev->hci.cpwm_addr = 0xfe57; @@ -1870,6 +1936,9 @@ static int rtw_dump_hw_feature(struct rtw_dev *rtwdev) u8 bw; int i; + if (!rtwdev->chip->hw_feature_report) + return 0; + id = rtw_read8(rtwdev, REG_C2HEVT); if (id != C2H_HW_FEATURE_REPORT) { rtw_err(rtwdev, "failed to read hw feature report\n"); @@ -1959,7 +2028,12 @@ static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev) efuse->ext_pa_2g = efuse->pa_type_2g & BIT(4) ? 1 : 0; efuse->ext_lna_2g = efuse->lna_type_2g & BIT(3) ? 1 : 0; efuse->ext_pa_5g = efuse->pa_type_5g & BIT(0) ? 1 : 0; - efuse->ext_lna_2g = efuse->lna_type_5g & BIT(3) ? 1 : 0; + efuse->ext_lna_5g = efuse->lna_type_5g & BIT(3) ? 1 : 0; + + if (!is_valid_ether_addr(efuse->addr)) { + eth_random_addr(efuse->addr); + dev_warn(rtwdev->dev, "efuse MAC invalid, using random\n"); + } out_disable: rtw_chip_efuse_disable(rtwdev); @@ -1977,11 +2051,9 @@ static int rtw_chip_board_info_setup(struct rtw_dev *rtwdev) if (!rfe_def) return -ENODEV; - rtw_phy_setup_phy_cond(rtwdev, 0); + rtw_phy_setup_phy_cond(rtwdev, hal->pkg_type); rtw_phy_init_tx_power(rtwdev); - if (rfe_def->agc_btg_tbl) - rtw_load_table(rtwdev, rfe_def->agc_btg_tbl); rtw_load_table(rtwdev, rfe_def->phy_pg_tbl); rtw_load_table(rtwdev, rfe_def->txpwr_lmt_tbl); rtw_phy_tx_power_by_rate_config(hal); @@ -2084,7 +2156,6 @@ int rtw_core_init(struct rtw_dev *rtwdev) rtwdev->sec.total_cam_num = 32; rtwdev->hal.current_channel = 1; rtwdev->dm_info.fix_rate = U8_MAX; - set_bit(RTW_BC_MC_MACID, rtwdev->mac_id_map); rtw_stats_init(rtwdev); @@ -2134,10 +2205,12 @@ void rtw_core_deinit(struct rtw_dev *rtwdev) release_firmware(wow_fw->firmware); destroy_workqueue(rtwdev->tx_wq); + timer_delete_sync(&rtwdev->tx_report.purge_timer); spin_lock_irqsave(&rtwdev->tx_report.q_lock, flags); skb_queue_purge(&rtwdev->tx_report.queue); - skb_queue_purge(&rtwdev->coex.queue); spin_unlock_irqrestore(&rtwdev->tx_report.q_lock, flags); + skb_queue_purge(&rtwdev->coex.queue); + skb_queue_purge(&rtwdev->c2h_queue); list_for_each_entry_safe(rsvd_pkt, tmp, &rtwdev->rsvd_page_list, build_list) { @@ -2156,9 +2229,11 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) int max_tx_headroom = 0; int ret; - /* TODO: USB & SDIO may need extra room? */ max_tx_headroom = rtwdev->chip->tx_pkt_desc_sz; + if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) + max_tx_headroom += RTW_SDIO_DATA_PTR_ALIGN; + hw->extra_tx_headroom = max_tx_headroom; hw->queues = IEEE80211_NUM_ACS; hw->txq_data_size = sizeof(struct rtw_txq); @@ -2173,15 +2248,15 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); - ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); + if (rtwdev->chip->amsdu_in_ampdu) + ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, TX_AMSDU); ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_MESH_POINT); + BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->available_antennas_tx = hal->antenna_tx; hw->wiphy->available_antennas_rx = hal->antenna_rx; @@ -2192,6 +2267,11 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) hw->wiphy->max_scan_ssids = RTW_SCAN_MAX_SSIDS; hw->wiphy->max_scan_ie_len = rtw_get_max_scan_ie_len(rtwdev); + if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C) { + hw->wiphy->iface_combinations = rtw_iface_combs; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw_iface_combs); + } + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SCAN_RANDOM_SN); wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); @@ -2211,16 +2291,18 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) return ret; } + rtw_led_init(rtwdev); + ret = ieee80211_register_hw(hw); if (ret) { rtw_err(rtwdev, "failed to register hw\n"); - return ret; + goto led_deinit; } ret = rtw_regd_hint(rtwdev); if (ret) { rtw_err(rtwdev, "failed to hint regd\n"); - return ret; + goto led_deinit; } rtw_debugfs_init(rtwdev); @@ -2229,6 +2311,10 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) rtwdev->bf_info.bfer_su_cnt = 0; return 0; + +led_deinit: + rtw_led_deinit(rtwdev); + return ret; } EXPORT_SYMBOL(rtw_register_hw); @@ -2238,9 +2324,165 @@ void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) ieee80211_unregister_hw(hw); rtw_unset_supported_band(hw, chip); + rtw_debugfs_deinit(rtwdev); + rtw_led_deinit(rtwdev); } EXPORT_SYMBOL(rtw_unregister_hw); +static +void rtw_swap_reg_nbytes(struct rtw_dev *rtwdev, const struct rtw_hw_reg *reg1, + const struct rtw_hw_reg *reg2, u8 nbytes) +{ + u8 i; + + for (i = 0; i < nbytes; i++) { + u8 v1 = rtw_read8(rtwdev, reg1->addr + i); + u8 v2 = rtw_read8(rtwdev, reg2->addr + i); + + rtw_write8(rtwdev, reg1->addr + i, v2); + rtw_write8(rtwdev, reg2->addr + i, v1); + } +} + +static +void rtw_swap_reg_mask(struct rtw_dev *rtwdev, const struct rtw_hw_reg *reg1, + const struct rtw_hw_reg *reg2) +{ + u32 v1, v2; + + v1 = rtw_read32_mask(rtwdev, reg1->addr, reg1->mask); + v2 = rtw_read32_mask(rtwdev, reg2->addr, reg2->mask); + rtw_write32_mask(rtwdev, reg2->addr, reg2->mask, v1); + rtw_write32_mask(rtwdev, reg1->addr, reg1->mask, v2); +} + +struct rtw_iter_port_switch_data { + struct rtw_dev *rtwdev; + struct rtw_vif *rtwvif_ap; +}; + +static void rtw_port_switch_iter(void *data, struct ieee80211_vif *vif) +{ + struct rtw_iter_port_switch_data *iter_data = data; + struct rtw_dev *rtwdev = iter_data->rtwdev; + struct rtw_vif *rtwvif_target = (struct rtw_vif *)vif->drv_priv; + struct rtw_vif *rtwvif_ap = iter_data->rtwvif_ap; + const struct rtw_hw_reg *reg1, *reg2; + + if (rtwvif_target->port != RTW_PORT_0) + return; + + rtw_dbg(rtwdev, RTW_DBG_STATE, "AP port switch from %d -> %d\n", + rtwvif_ap->port, rtwvif_target->port); + + /* Leave LPS so the value swapped are not in PS mode */ + rtw_leave_lps(rtwdev); + + reg1 = &rtwvif_ap->conf->net_type; + reg2 = &rtwvif_target->conf->net_type; + rtw_swap_reg_mask(rtwdev, reg1, reg2); + + reg1 = &rtwvif_ap->conf->mac_addr; + reg2 = &rtwvif_target->conf->mac_addr; + rtw_swap_reg_nbytes(rtwdev, reg1, reg2, ETH_ALEN); + + reg1 = &rtwvif_ap->conf->bssid; + reg2 = &rtwvif_target->conf->bssid; + rtw_swap_reg_nbytes(rtwdev, reg1, reg2, ETH_ALEN); + + reg1 = &rtwvif_ap->conf->bcn_ctrl; + reg2 = &rtwvif_target->conf->bcn_ctrl; + rtw_swap_reg_nbytes(rtwdev, reg1, reg2, 1); + + swap(rtwvif_target->port, rtwvif_ap->port); + swap(rtwvif_target->conf, rtwvif_ap->conf); + + rtw_fw_default_port(rtwdev, rtwvif_target); +} + +void rtw_core_port_switch(struct rtw_dev *rtwdev, struct ieee80211_vif *vif) +{ + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + struct rtw_iter_port_switch_data iter_data; + + if (vif->type != NL80211_IFTYPE_AP || rtwvif->port == RTW_PORT_0) + return; + + iter_data.rtwdev = rtwdev; + iter_data.rtwvif_ap = rtwvif; + rtw_iterate_vifs(rtwdev, rtw_port_switch_iter, &iter_data); +} + +static void rtw_check_sta_active_iter(void *data, struct ieee80211_vif *vif) +{ + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + bool *active = data; + + if (*active) + return; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + if (vif->cfg.assoc || !is_zero_ether_addr(rtwvif->bssid)) + *active = true; +} + +bool rtw_core_check_sta_active(struct rtw_dev *rtwdev) +{ + bool sta_active = false; + + rtw_iterate_vifs(rtwdev, rtw_check_sta_active_iter, &sta_active); + + return rtwdev->ap_active || sta_active; +} + +void rtw_core_enable_beacon(struct rtw_dev *rtwdev, bool enable) +{ + if (!rtwdev->ap_active) + return; + + if (enable) { + rtw_write32_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); + rtw_write32_clr(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); + } else { + rtw_write32_clr(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); + rtw_write32_set(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); + } +} + +void rtw_set_ampdu_factor(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) +{ + const struct rtw_chip_ops *ops = rtwdev->chip->ops; + struct ieee80211_sta *sta; + u8 factor = 0xff; + + if (!ops->set_ampdu_factor) + return; + + rcu_read_lock(); + + sta = ieee80211_find_sta(vif, bss_conf->bssid); + if (!sta) { + rcu_read_unlock(); + rtw_warn(rtwdev, "%s: failed to find station %pM\n", + __func__, bss_conf->bssid); + return; + } + + if (sta->deflink.vht_cap.vht_supported) + factor = u32_get_bits(sta->deflink.vht_cap.cap, + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); + else if (sta->deflink.ht_cap.ht_supported) + factor = sta->deflink.ht_cap.ampdu_factor; + + rcu_read_unlock(); + + if (factor != 0xff) + ops->set_ampdu_factor(rtwdev, factor); +} + MODULE_AUTHOR("Realtek Corporation"); MODULE_DESCRIPTION("Realtek 802.11ac wireless core module"); MODULE_LICENSE("Dual BSD/GPL"); |
