Introduce watchdog to monitor signal then update the rate mask accordingly. The rate mask update logic comes from the rtlwifi refresh_rate_adaptive_mask() from different chips. --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 + .../realtek/rtl8xxxu/rtl8xxxu_8723b.c | 151 ++++++++++++++++++ .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 38 +++++ 3 files changed, 197 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 771f58aa7cae..f97271951053 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1239,6 +1239,11 @@ struct rtl8xxxu_rate_adaptive { u8 rssi_level; /* INIT, HIGH, MIDDLE, LOW */ } __packed; +struct rtl8xxxu_watchdog { + struct ieee80211_vif *vif; + struct delayed_work ra_wq; +}; + struct rtl8xxxu_priv { struct ieee80211_hw *hw; struct usb_device *udev; @@ -1344,6 +1349,7 @@ struct rtl8xxxu_priv { u8 no_pape:1; u8 int_buf[USB_INTR_CONTENT_LENGTH]; struct rtl8xxxu_rate_adaptive ra_info; + struct rtl8xxxu_watchdog watchdog; }; struct rtl8xxxu_rx_urb { @@ -1380,6 +1386,8 @@ struct rtl8xxxu_fileops { bool ht40); void (*update_rate_mask) (struct rtl8xxxu_priv *priv, u32 ramask, int sgi); + void (*refresh_rate_mask) (struct rtl8xxxu_priv *priv, int signal, + struct ieee80211_sta *sta); void (*report_connect) (struct rtl8xxxu_priv *priv, u8 macid, bool connect); void (*fill_txdesc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index 26b674aca125..92c35afecae0 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -1645,6 +1645,156 @@ static void rtl8723bu_init_statistics(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_OFDM0_FA_RSTC, val32); } +static u8 rtl8723b_signal_to_rssi(int signal) +{ + if (signal < -95) + signal = -95; + return (u8)(signal + 95); +} + +static void rtl8723b_refresh_rate_mask(struct rtl8xxxu_priv *priv, + int signal, struct ieee80211_sta *sta) +{ + struct rtl8xxxu_rate_adaptive *ra; + struct ieee80211_hw *hw = priv->hw; + u16 wireless_mode; + u8 rssi_level, ratr_index; + u8 txbw_40mhz; + u8 rssi, rssi_thresh_high, rssi_thresh_low; + + ra = &priv->ra_info; + wireless_mode = ra->wireless_mode; + rssi_level = ra->rssi_level; + rssi = rtl8723b_signal_to_rssi(signal); + ratr_index = ra->ratr_index; + txbw_40mhz = (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40)? 1 : 0; + + switch (rssi_level) { + case RTL8XXXU_RATR_STA_HIGH: + rssi_thresh_high = 50; + rssi_thresh_low = 20; + break; + case RTL8XXXU_RATR_STA_MID: + rssi_thresh_high = 55; + rssi_thresh_low = 20; + break; + case RTL8XXXU_RATR_STA_LOW: + rssi_thresh_high = 60; + rssi_thresh_low = 25; + break; + default: + rssi_thresh_high = 50; + rssi_thresh_low = 20; + break; + } + + if (rssi > rssi_thresh_high) + rssi_level = RTL8XXXU_RATR_STA_HIGH; + else if (rssi > rssi_thresh_low) + rssi_level = RTL8XXXU_RATR_STA_MID; + else + rssi_level = RTL8XXXU_RATR_STA_LOW; + + if (rssi_level != ra->rssi_level) { + int sgi = 0; + u32 rate_bitmap = 0; + + rcu_read_lock(); + rate_bitmap = (sta->supp_rates[0] & 0xfff) | + sta->ht_cap.mcs.rx_mask[0] << 12 | + sta->ht_cap.mcs.rx_mask[1] << 20; + if (sta->ht_cap.cap & + (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20)) + sgi = 1; + rcu_read_unlock(); + + switch (wireless_mode) { + case WIRELESS_MODE_B: + ratr_index = RATEID_IDX_B; + if (rate_bitmap & 0x0000000c) + rate_bitmap &= 0x0000000d; + else + rate_bitmap &= 0x0000000f; + break; + case WIRELESS_MODE_A: + case WIRELESS_MODE_G: + ratr_index = RATEID_IDX_G; + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) + rate_bitmap &= 0x00000f00; + else + rate_bitmap &= 0x00000ff0; + break; + case (WIRELESS_MODE_B|WIRELESS_MODE_G): + ratr_index = RATEID_IDX_BG; + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) + rate_bitmap &= 0x00000f00; + else if (rssi_level == RTL8XXXU_RATR_STA_MID) + rate_bitmap &= 0x00000ff0; + else + rate_bitmap &= 0x00000ff5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + case (WIRELESS_MODE_G|WIRELESS_MODE_N_24G): + case (WIRELESS_MODE_A|WIRELESS_MODE_N_5G): + if (priv->tx_paths == 2 && priv->rx_paths == 2) + ratr_index = RATEID_IDX_GN_N2SS; + else + ratr_index = RATEID_IDX_GN_N1SS; + case (WIRELESS_MODE_B|WIRELESS_MODE_G|WIRELESS_MODE_N_24G): + case (WIRELESS_MODE_B|WIRELESS_MODE_N_24G): + if (txbw_40mhz) { + if (priv->tx_paths == 2 && priv->rx_paths == 2) + ratr_index = RATEID_IDX_BGN_40M_2SS; + else + ratr_index = RATEID_IDX_BGN_40M_1SS; + } + else { + if (priv->tx_paths == 2 && priv->rx_paths == 2) + ratr_index = RATEID_IDX_BGN_20M_2SS_BN; + else + ratr_index = RATEID_IDX_BGN_20M_1SS_BN; + } + + if (priv->tx_paths == 2 && priv->rx_paths == 2) { + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) + rate_bitmap &= 0x0f8f0000; + else if (rssi_level == RTL8XXXU_RATR_STA_MID) + rate_bitmap &= 0x0f8ff000; + else { + if (txbw_40mhz) + rate_bitmap &= 0x0f8ff015; + else + rate_bitmap &= 0x0f8ff005; + } + } + else { + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) + rate_bitmap &= 0x000f0000; + else if (rssi_level == RTL8XXXU_RATR_STA_MID) + rate_bitmap &= 0x000ff000; + else { + if (txbw_40mhz) + rate_bitmap &= 0x000ff015; + else + rate_bitmap &= 0x000ff005; + } + } + break; + default: + ratr_index = RATEID_IDX_BGN_40M_2SS; + rate_bitmap &= 0x0fffffff; + break; + } + + ra->ratr_index = ratr_index; + ra->rssi_level = rssi_level; + priv->fops->update_rate_mask(priv, rate_bitmap, sgi); + } + + return; +} + struct rtl8xxxu_fileops rtl8723bu_fops = { .parse_efuse = rtl8723bu_parse_efuse, .load_firmware = rtl8723bu_load_firmware, @@ -1665,6 +1815,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = { .usb_quirks = rtl8xxxu_gen2_usb_quirks, .set_tx_power = rtl8723b_set_tx_power, .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, + .refresh_rate_mask = rtl8723b_refresh_rate_mask, .report_connect = rtl8xxxu_gen2_report_connect, .fill_txdesc = rtl8xxxu_fill_txdesc_v2, .writeN_block_size = 1024, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 360e9bd837e5..8db479986e97 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4565,6 +4565,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, sgi = 1; rcu_read_unlock(); + priv->watchdog.vif = vif; ra = &priv->ra_info; ra->wireless_mode = rtl8xxxu_wireless_mode(hw, sta); ra->ratr_index = RATEID_IDX_BGN_40M_2SS; @@ -5822,6 +5823,38 @@ rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return 0; } +static void rtl8xxxu_watchdog_callback(struct work_struct *work) +{ + struct ieee80211_vif *vif; + struct rtl8xxxu_watchdog *wdog; + struct rtl8xxxu_priv *priv; + + wdog = container_of(work, struct rtl8xxxu_watchdog, ra_wq.work); + priv = container_of(wdog, struct rtl8xxxu_priv, watchdog); + vif = wdog->vif; + + if (vif) { + int signal; + struct ieee80211_sta *sta; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); + if (!sta) { + struct device *dev = &priv->udev->dev; + dev_info(dev, "%s: no sta found\n", __func__); + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + + signal = ieee80211_ave_rssi(vif); + if (priv->fops->refresh_rate_mask) + priv->fops->refresh_rate_mask(priv, signal, sta); + } + + schedule_delayed_work(&priv->watchdog.ra_wq, 2 * HZ); +} + static int rtl8xxxu_start(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; @@ -5878,6 +5911,8 @@ static int rtl8xxxu_start(struct ieee80211_hw *hw) ret = rtl8xxxu_submit_rx_urb(priv, rx_urb); } + + schedule_delayed_work(&priv->watchdog.ra_wq, 2* HZ); exit: /* * Accept all data and mgmt frames @@ -6101,6 +6136,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, INIT_LIST_HEAD(&priv->rx_urb_pending_list); spin_lock_init(&priv->rx_urb_lock); INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work); + INIT_DELAYED_WORK(&priv->watchdog.ra_wq, rtl8xxxu_watchdog_callback); usb_set_intfdata(interface, hw); @@ -6226,6 +6262,8 @@ static void rtl8xxxu_disconnect(struct usb_interface *interface) mutex_destroy(&priv->usb_buf_mutex); mutex_destroy(&priv->h2c_mutex); + cancel_delayed_work_sync(&priv->watchdog.ra_wq); + if (priv->udev->state != USB_STATE_NOTATTACHED) { dev_info(&priv->udev->dev, "Device still attached, trying to reset\n"); -- 2.21.0