summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/realtek/rtl8xxxu
diff options
context:
space:
mode:
authorBitterblue Smith <rtl8821cerfe2@gmail.com>2022-12-17 17:21:59 +0300
committerKalle Valo <kvalo@kernel.org>2022-12-21 21:51:40 +0300
commit8b9754b28f0f231736667e1751f1fc6f18c80ad4 (patch)
tree19105c86efcb6bc184966e6c2da61457a738e9fb /drivers/net/wireless/realtek/rtl8xxxu
parent3dfb8e844fa30cceb4b810613e2c35f628eb3e70 (diff)
downloadlinux-8b9754b28f0f231736667e1751f1fc6f18c80ad4.tar.xz
wifi: rtl8xxxu: Add rate control code for RTL8188EU
Copied from the newer vendor driver, v5.2.2.4. Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com> Reviewed-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Kalle Valo <kvalo@kernel.org> Link: https://lore.kernel.org/r/5acc1e5d-62d6-3a6a-0f9e-cbc8b809b1d7@gmail.com
Diffstat (limited to 'drivers/net/wireless/realtek/rtl8xxxu')
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h39
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c590
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c130
3 files changed, 729 insertions, 30 deletions
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
index 29f5dbee16b0..be9479f969b7 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
@@ -531,6 +531,7 @@ struct rtl8xxxu_txdesc40 {
#define TXDESC32_CTS_SELF_ENABLE BIT(11)
#define TXDESC32_RTS_CTS_ENABLE BIT(12)
#define TXDESC32_HW_RTS_ENABLE BIT(13)
+#define TXDESC32_PT_STAGE_MASK GENMASK(17, 15)
#define TXDESC_PRIME_CH_OFF_LOWER BIT(20)
#define TXDESC_PRIME_CH_OFF_UPPER BIT(21)
#define TXDESC32_SHORT_PREAMBLE BIT(24)
@@ -1376,6 +1377,39 @@ struct rtl8xxxu_ra_report {
u8 desc_rate;
};
+struct rtl8xxxu_ra_info {
+ u8 rate_id;
+ u32 rate_mask;
+ u32 ra_use_rate;
+ u8 rate_sgi;
+ u8 rssi_sta_ra; /* Percentage */
+ u8 pre_rssi_sta_ra;
+ u8 sgi_enable;
+ u8 decision_rate;
+ u8 pre_rate;
+ u8 highest_rate;
+ u8 lowest_rate;
+ u32 nsc_up;
+ u32 nsc_down;
+ u32 total;
+ u16 retry[5];
+ u16 drop;
+ u16 rpt_time;
+ u16 pre_min_rpt_time;
+ u8 dynamic_tx_rpt_timing_counter;
+ u8 ra_waiting_counter;
+ u8 ra_pending_counter;
+ u8 ra_drop_after_down;
+ u8 pt_try_state; /* 0 trying state, 1 for decision state */
+ u8 pt_stage; /* 0~6 */
+ u8 pt_stop_count; /* Stop PT counter */
+ u8 pt_pre_rate; /* if rate change do PT */
+ u8 pt_pre_rssi; /* if RSSI change 5% do PT */
+ u8 pt_mode_ss; /* decide which rate should do PT */
+ u8 ra_stage; /* StageRA, decide how many times RA will be done between PT */
+ u8 pt_smooth_factor;
+};
+
#define CFO_TH_XTAL_HIGH 20 /* kHz */
#define CFO_TH_XTAL_LOW 10 /* kHz */
#define CFO_TH_ATC 80 /* kHz */
@@ -1509,6 +1543,7 @@ struct rtl8xxxu_priv {
struct rtl8xxxu_btcoex bt_coex;
struct rtl8xxxu_ra_report ra_report;
struct rtl8xxxu_cfo_tracking cfo_tracking;
+ struct rtl8xxxu_ra_info ra_info;
};
struct rtl8xxxu_rx_urb {
@@ -1684,6 +1719,10 @@ void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv);
void rtl8723a_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap);
void rtl8188f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap);
s8 rtl8723a_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt);
+void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt,
+ u8 rate, u8 sgi, u8 bw);
+void rtl8188e_ra_info_init_all(struct rtl8xxxu_ra_info *ra);
+void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *skb);
extern struct rtl8xxxu_fileops rtl8188fu_fops;
extern struct rtl8xxxu_fileops rtl8188eu_fops;
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c
index 97fceec4c086..37658a090aee 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c
@@ -280,6 +280,123 @@ static const struct rtl8xxxu_rfregval rtl8188eu_radioa_init_table[] = {
{0xff, 0xffffffff}
};
+#define PERENTRY 23
+#define RETRYSIZE 5
+#define RATESIZE 28
+#define TX_RPT2_ITEM_SIZE 8
+
+static const u8 retry_penalty[PERENTRY][RETRYSIZE + 1] = {
+ {5, 4, 3, 2, 0, 3}, /* 92 , idx=0 */
+ {6, 5, 4, 3, 0, 4}, /* 86 , idx=1 */
+ {6, 5, 4, 2, 0, 4}, /* 81 , idx=2 */
+ {8, 7, 6, 4, 0, 6}, /* 75 , idx=3 */
+ {10, 9, 8, 6, 0, 8}, /* 71 , idx=4 */
+ {10, 9, 8, 4, 0, 8}, /* 66 , idx=5 */
+ {10, 9, 8, 2, 0, 8}, /* 62 , idx=6 */
+ {10, 9, 8, 0, 0, 8}, /* 59 , idx=7 */
+ {18, 17, 16, 8, 0, 16}, /* 53 , idx=8 */
+ {26, 25, 24, 16, 0, 24}, /* 50 , idx=9 */
+ {34, 33, 32, 24, 0, 32}, /* 47 , idx=0x0a */
+ {34, 31, 28, 20, 0, 32}, /* 43 , idx=0x0b */
+ {34, 31, 27, 18, 0, 32}, /* 40 , idx=0x0c */
+ {34, 31, 26, 16, 0, 32}, /* 37 , idx=0x0d */
+ {34, 30, 22, 16, 0, 32}, /* 32 , idx=0x0e */
+ {34, 30, 24, 16, 0, 32}, /* 26 , idx=0x0f */
+ {49, 46, 40, 16, 0, 48}, /* 20 , idx=0x10 */
+ {49, 45, 32, 0, 0, 48}, /* 17 , idx=0x11 */
+ {49, 45, 22, 18, 0, 48}, /* 15 , idx=0x12 */
+ {49, 40, 24, 16, 0, 48}, /* 12 , idx=0x13 */
+ {49, 32, 18, 12, 0, 48}, /* 9 , idx=0x14 */
+ {49, 22, 18, 14, 0, 48}, /* 6 , idx=0x15 */
+ {49, 16, 16, 0, 0, 48} /* 3, idx=0x16 */
+};
+
+static const u8 pt_penalty[RETRYSIZE + 1] = {34, 31, 30, 24, 0, 32};
+
+static const u8 retry_penalty_idx_normal[2][RATESIZE] = {
+ { /* RSSI>TH */
+ 4, 4, 4, 5,
+ 4, 4, 5, 7, 7, 7, 8, 0x0a,
+ 4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d,
+ 5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f
+ },
+ { /* RSSI<TH */
+ 0x0a, 0x0a, 0x0b, 0x0c,
+ 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x13,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x13, 0x13,
+ 9, 9, 9, 9, 0x0c, 0x0e, 0x11, 0x13
+ }
+};
+
+static const u8 retry_penalty_idx_cut_i[2][RATESIZE] = {
+ { /* RSSI>TH */
+ 4, 4, 4, 5,
+ 4, 4, 5, 7, 7, 7, 8, 0x0a,
+ 4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d,
+ 5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f
+ },
+ { /* RSSI<TH */
+ 0x0a, 0x0a, 0x0b, 0x0c,
+ 0x0a, 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x13,
+ 0x06, 0x07, 0x08, 0x0d, 0x0e, 0x11, 0x11, 0x11,
+ 9, 9, 9, 9, 0x0c, 0x0e, 0x11, 0x13
+ }
+};
+
+static const u8 retry_penalty_up_idx_normal[RATESIZE] = {
+ 0x0c, 0x0d, 0x0d, 0x0f,
+ 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x12, 0x13, 0x14,
+ 0x0f, 0x10, 0x10, 0x12, 0x12, 0x13, 0x14, 0x15,
+ 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15
+};
+
+static const u8 retry_penalty_up_idx_cut_i[RATESIZE] = {
+ 0x0c, 0x0d, 0x0d, 0x0f,
+ 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x12, 0x13, 0x14,
+ 0x0b, 0x0b, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12,
+ 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15
+};
+
+static const u8 rssi_threshold[RATESIZE] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x24, 0x26, 0x2a,
+ 0x18, 0x1a, 0x1d, 0x1f, 0x21, 0x27, 0x29, 0x2a,
+ 0, 0, 0, 0x1f, 0x23, 0x28, 0x2a, 0x2c
+};
+
+static const u16 n_threshold_high[RATESIZE] = {
+ 4, 4, 8, 16,
+ 24, 36, 48, 72, 96, 144, 192, 216,
+ 60, 80, 100, 160, 240, 400, 600, 800,
+ 300, 320, 480, 720, 1000, 1200, 1600, 2000
+};
+
+static const u16 n_threshold_low[RATESIZE] = {
+ 2, 2, 4, 8,
+ 12, 18, 24, 36, 48, 72, 96, 108,
+ 30, 40, 50, 80, 120, 200, 300, 400,
+ 150, 160, 240, 360, 500, 600, 800, 1000
+};
+
+static const u8 dropping_necessary[RATESIZE] = {
+ 1, 1, 1, 1,
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 5, 6, 7, 8, 9, 10, 11, 12
+};
+
+static const u8 pending_for_rate_up_fail[5] = {2, 10, 24, 40, 60};
+
+static const u16 dynamic_tx_rpt_timing[6] = {
+ 0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12, 0x927c /* 200ms-1200ms */
+};
+
+enum rtl8188e_tx_rpt_timing {
+ DEFAULT_TIMING = 0,
+ INCREASE_TIMING,
+ DECREASE_TIMING
+};
+
static int rtl8188eu_identify_chip(struct rtl8xxxu_priv *priv)
{
struct device *dev = &priv->udev->dev;
@@ -1233,6 +1350,477 @@ static s8 rtl8188e_cck_rssi(struct rtl8xxxu_priv *priv, u8 cck_agc_rpt)
return rx_pwr_all;
}
+static void rtl8188e_set_tx_rpt_timing(struct rtl8xxxu_ra_info *ra, u8 timing)
+{
+ u8 idx;
+
+ for (idx = 0; idx < 5; idx++)
+ if (dynamic_tx_rpt_timing[idx] == ra->rpt_time)
+ break;
+
+ if (timing == DEFAULT_TIMING) {
+ idx = 0; /* 200ms */
+ } else if (timing == INCREASE_TIMING) {
+ if (idx < 5)
+ idx++;
+ } else if (timing == DECREASE_TIMING) {
+ if (idx > 0)
+ idx--;
+ }
+
+ ra->rpt_time = dynamic_tx_rpt_timing[idx];
+}
+
+static void rtl8188e_rate_down(struct rtl8xxxu_ra_info *ra)
+{
+ u8 rate_id = ra->pre_rate;
+ u8 lowest_rate = ra->lowest_rate;
+ u8 highest_rate = ra->highest_rate;
+ s8 i;
+
+ if (rate_id > highest_rate) {
+ rate_id = highest_rate;
+ } else if (ra->rate_sgi) {
+ ra->rate_sgi = 0;
+ } else if (rate_id > lowest_rate) {
+ if (rate_id > 0) {
+ for (i = rate_id - 1; i >= lowest_rate; i--) {
+ if (ra->ra_use_rate & BIT(i)) {
+ rate_id = i;
+ goto rate_down_finish;
+ }
+ }
+ }
+ } else if (rate_id <= lowest_rate) {
+ rate_id = lowest_rate;
+ }
+
+rate_down_finish:
+ if (ra->ra_waiting_counter == 1) {
+ ra->ra_waiting_counter++;
+ ra->ra_pending_counter++;
+ } else if (ra->ra_waiting_counter > 1) {
+ ra->ra_waiting_counter = 0;
+ ra->ra_pending_counter = 0;
+ }
+
+ if (ra->ra_pending_counter >= 4)
+ ra->ra_pending_counter = 4;
+
+ ra->ra_drop_after_down = 1;
+
+ ra->decision_rate = rate_id;
+
+ rtl8188e_set_tx_rpt_timing(ra, DECREASE_TIMING);
+}
+
+static void rtl8188e_rate_up(struct rtl8xxxu_ra_info *ra)
+{
+ u8 rate_id = ra->pre_rate;
+ u8 highest_rate = ra->highest_rate;
+ u8 i;
+
+ if (ra->ra_waiting_counter == 1) {
+ ra->ra_waiting_counter = 0;
+ ra->ra_pending_counter = 0;
+ } else if (ra->ra_waiting_counter > 1) {
+ ra->pre_rssi_sta_ra = ra->rssi_sta_ra;
+ goto rate_up_finish;
+ }
+
+ rtl8188e_set_tx_rpt_timing(ra, DEFAULT_TIMING);
+
+ if (rate_id < highest_rate) {
+ for (i = rate_id + 1; i <= highest_rate; i++) {
+ if (ra->ra_use_rate & BIT(i)) {
+ rate_id = i;
+ goto rate_up_finish;
+ }
+ }
+ } else if (rate_id == highest_rate) {
+ if (ra->sgi_enable && !ra->rate_sgi)
+ ra->rate_sgi = 1;
+ else if (!ra->sgi_enable)
+ ra->rate_sgi = 0;
+ } else { /* rate_id > ra->highest_rate */
+ rate_id = highest_rate;
+ }
+
+rate_up_finish:
+ if (ra->ra_waiting_counter == (4 + pending_for_rate_up_fail[ra->ra_pending_counter]))
+ ra->ra_waiting_counter = 0;
+ else
+ ra->ra_waiting_counter++;
+
+ ra->decision_rate = rate_id;
+}
+
+static void rtl8188e_reset_ra_counter(struct rtl8xxxu_ra_info *ra)
+{
+ u8 rate_id = ra->decision_rate;
+
+ ra->nsc_up = (n_threshold_high[rate_id] + n_threshold_low[rate_id]) >> 1;
+ ra->nsc_down = (n_threshold_high[rate_id] + n_threshold_low[rate_id]) >> 1;
+}
+
+static void rtl8188e_rate_decision(struct rtl8xxxu_ra_info *ra)
+{
+ struct rtl8xxxu_priv *priv = container_of(ra, struct rtl8xxxu_priv, ra_info);
+ const u8 *retry_penalty_idx_0;
+ const u8 *retry_penalty_idx_1;
+ const u8 *retry_penalty_up_idx;
+ u8 rate_id, penalty_id1, penalty_id2;
+ int i;
+
+ if (ra->total == 0)
+ return;
+
+ if (ra->ra_drop_after_down) {
+ ra->ra_drop_after_down--;
+
+ rtl8188e_reset_ra_counter(ra);
+
+ return;
+ }
+
+ if (priv->chip_cut == 8) { /* cut I */
+ retry_penalty_idx_0 = retry_penalty_idx_cut_i[0];
+ retry_penalty_idx_1 = retry_penalty_idx_cut_i[1];
+ retry_penalty_up_idx = retry_penalty_up_idx_cut_i;
+ } else {
+ retry_penalty_idx_0 = retry_penalty_idx_normal[0];
+ retry_penalty_idx_1 = retry_penalty_idx_normal[1];
+ retry_penalty_up_idx = retry_penalty_up_idx_normal;
+ }
+
+ if (ra->rssi_sta_ra < (ra->pre_rssi_sta_ra - 3) ||
+ ra->rssi_sta_ra > (ra->pre_rssi_sta_ra + 3)) {
+ ra->pre_rssi_sta_ra = ra->rssi_sta_ra;
+ ra->ra_waiting_counter = 0;
+ ra->ra_pending_counter = 0;
+ }
+
+ /* Start RA decision */
+ if (ra->pre_rate > ra->highest_rate)
+ rate_id = ra->highest_rate;
+ else
+ rate_id = ra->pre_rate;
+
+ /* rate down */
+ if (ra->rssi_sta_ra > rssi_threshold[rate_id])
+ penalty_id1 = retry_penalty_idx_0[rate_id];
+ else
+ penalty_id1 = retry_penalty_idx_1[rate_id];
+
+ for (i = 0; i < 5; i++)
+ ra->nsc_down += ra->retry[i] * retry_penalty[penalty_id1][i];
+
+ if (ra->nsc_down > (ra->total * retry_penalty[penalty_id1][5]))
+ ra->nsc_down -= ra->total * retry_penalty[penalty_id1][5];
+ else
+ ra->nsc_down = 0;
+
+ /* rate up */
+ penalty_id2 = retry_penalty_up_idx[rate_id];
+
+ for (i = 0; i < 5; i++)
+ ra->nsc_up += ra->retry[i] * retry_penalty[penalty_id2][i];
+
+ if (ra->nsc_up > (ra->total * retry_penalty[penalty_id2][5]))
+ ra->nsc_up -= ra->total * retry_penalty[penalty_id2][5];
+ else
+ ra->nsc_up = 0;
+
+ if (ra->nsc_down < n_threshold_low[rate_id] ||
+ ra->drop > dropping_necessary[rate_id]) {
+ rtl8188e_rate_down(ra);
+
+ rtl8xxxu_update_ra_report(&priv->ra_report, ra->decision_rate,
+ ra->rate_sgi, priv->ra_report.txrate.bw);
+ } else if (ra->nsc_up > n_threshold_high[rate_id]) {
+ rtl8188e_rate_up(ra);
+
+ rtl8xxxu_update_ra_report(&priv->ra_report, ra->decision_rate,
+ ra->rate_sgi, priv->ra_report.txrate.bw);
+ }
+
+ if (ra->decision_rate == ra->pre_rate)
+ ra->dynamic_tx_rpt_timing_counter++;
+ else
+ ra->dynamic_tx_rpt_timing_counter = 0;
+
+ if (ra->dynamic_tx_rpt_timing_counter >= 4) {
+ /* Rate didn't change 4 times, extend RPT timing */
+ rtl8188e_set_tx_rpt_timing(ra, INCREASE_TIMING);
+ ra->dynamic_tx_rpt_timing_counter = 0;
+ }
+
+ ra->pre_rate = ra->decision_rate;
+
+ rtl8188e_reset_ra_counter(ra);
+}
+
+static void rtl8188e_power_training_try_state(struct rtl8xxxu_ra_info *ra)
+{
+ ra->pt_try_state = 0;
+ switch (ra->pt_mode_ss) {
+ case 3:
+ if (ra->decision_rate >= DESC_RATE_MCS13)
+ ra->pt_try_state = 1;
+ break;
+ case 2:
+ if (ra->decision_rate >= DESC_RATE_MCS5)
+ ra->pt_try_state = 1;
+ break;
+ case 1:
+ if (ra->decision_rate >= DESC_RATE_48M)
+ ra->pt_try_state = 1;
+ break;
+ case 0:
+ if (ra->decision_rate >= DESC_RATE_11M)
+ ra->pt_try_state = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (ra->rssi_sta_ra < 48) {
+ ra->pt_stage = 0;
+ } else if (ra->pt_try_state == 1) {
+ if ((ra->pt_stop_count >= 10) ||
+ (ra->pt_pre_rssi > ra->rssi_sta_ra + 5) ||
+ (ra->pt_pre_rssi < ra->rssi_sta_ra - 5) ||
+ (ra->decision_rate != ra->pt_pre_rate)) {
+ if (ra->pt_stage == 0)
+ ra->pt_stage = 1;
+ else if (ra->pt_stage == 1)
+ ra->pt_stage = 3;
+ else
+ ra->pt_stage = 5;
+
+ ra->pt_pre_rssi = ra->rssi_sta_ra;
+ ra->pt_stop_count = 0;
+ } else {
+ ra->ra_stage = 0;
+ ra->pt_stop_count++;
+ }
+ } else {
+ ra->pt_stage = 0;
+ ra->ra_stage = 0;
+ }
+
+ ra->pt_pre_rate = ra->decision_rate;
+
+ /* TODO: implement the "false alarm" statistics for this */
+ /* Disable power training when noisy environment */
+ /* if (p_dm_odm->is_disable_power_training) { */
+ if (1) {
+ ra->pt_stage = 0;
+ ra->ra_stage = 0;
+ ra->pt_stop_count = 0;
+ }
+}
+
+static void rtl8188e_power_training_decision(struct rtl8xxxu_ra_info *ra)
+{
+ u8 temp_stage;
+ u32 numsc;
+ u32 num_total;
+ u8 stage_id;
+ u8 j;
+
+ numsc = 0;
+ num_total = ra->total * pt_penalty[5];
+ for (j = 0; j <= 4; j++) {
+ numsc += ra->retry[j] * pt_penalty[j];
+
+ if (numsc > num_total)
+ break;
+ }
+
+ j >>= 1;
+ temp_stage = (ra->pt_stage + 1) >> 1;
+ if (temp_stage > j)
+ stage_id = temp_stage - j;
+ else
+ stage_id = 0;
+
+ ra->pt_smooth_factor = (ra->pt_smooth_factor >> 1) +
+ (ra->pt_smooth_factor >> 2) +
+ stage_id * 16 + 2;
+ if (ra->pt_smooth_factor > 192)
+ ra->pt_smooth_factor = 192;
+ stage_id = ra->pt_smooth_factor >> 6;
+ temp_stage = stage_id * 2;
+ if (temp_stage != 0)
+ temp_stage--;
+ if (ra->drop > 3)
+ temp_stage = 0;
+ ra->pt_stage = temp_stage;
+}
+
+void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
+{
+ u32 *_rx_desc = (u32 *)(skb->data - sizeof(struct rtl8xxxu_rxdesc16));
+ struct rtl8xxxu_rxdesc16 *rx_desc = (struct rtl8xxxu_rxdesc16 *)_rx_desc;
+ struct device *dev = &priv->udev->dev;
+ struct rtl8xxxu_ra_info *ra = &priv->ra_info;
+ u32 tx_rpt_len = rx_desc->pktlen & 0x3ff;
+ u32 items = tx_rpt_len / TX_RPT2_ITEM_SIZE;
+ u64 macid_valid = ((u64)_rx_desc[5] << 32) | _rx_desc[4];
+ u32 macid;
+ u8 *rpt = skb->data;
+ bool valid;
+ u16 min_rpt_time = 0x927c;
+
+ dev_dbg(dev, "%s: len: %d items: %d\n", __func__, tx_rpt_len, items);
+
+ for (macid = 0; macid < items; macid++) {
+ valid = false;
+
+ if (macid < 64)
+ valid = macid_valid & BIT(macid);
+
+ if (valid) {
+ ra->retry[0] = le16_to_cpu(*(__le16 *)rpt);
+ ra->retry[1] = rpt[2];
+ ra->retry[2] = rpt[3];
+ ra->retry[3] = rpt[4];
+ ra->retry[4] = rpt[5];
+ ra->drop = rpt[6];
+ ra->total = ra->retry[0] + ra->retry[1] + ra->retry[2] +
+ ra->retry[3] + ra->retry[4] + ra->drop;
+
+ if (ra->total > 0) {
+ if (ra->ra_stage < 5)
+ rtl8188e_rate_decision(ra);
+ else if (ra->ra_stage == 5)
+ rtl8188e_power_training_try_state(ra);
+ else /* ra->ra_stage == 6 */
+ rtl8188e_power_training_decision(ra);
+
+ if (ra->ra_stage <= 5)
+ ra->ra_stage++;
+ else
+ ra->ra_stage = 0;
+ }
+ } else if (macid == 0) {
+ dev_warn(dev, "%s: TX report item 0 not valid\n", __func__);
+ }
+
+ dev_dbg(dev, "%s: valid: %d retry: %d %d %d %d %d drop: %d\n",
+ __func__, valid,
+ ra->retry[0], ra->retry[1], ra->retry[2],
+ ra->retry[3], ra->retry[4], ra->drop);
+
+ if (min_rpt_time > ra->rpt_time)
+ min_rpt_time = ra->rpt_time;
+
+ rpt += TX_RPT2_ITEM_SIZE;
+
+ /*
+ * We only use macid 0, so only the first item is relevant.
+ * AP mode will use more of them if it's ever implemented.
+ */
+ break;
+ }
+
+ if (min_rpt_time != ra->pre_min_rpt_time) {
+ rtl8xxxu_write16(priv, REG_TX_REPORT_TIME, min_rpt_time);
+ ra->pre_min_rpt_time = min_rpt_time;
+ }
+}
+
+static void rtl8188e_arfb_refresh(struct rtl8xxxu_ra_info *ra)
+{
+ s8 i;
+
+ ra->ra_use_rate = ra->rate_mask;
+
+ /* Highest rate */
+ if (ra->ra_use_rate) {
+ for (i = RATESIZE; i >= 0; i--) {
+ if (ra->ra_use_rate & BIT(i)) {
+ ra->highest_rate = i;
+ break;
+ }
+ }
+ } else {
+ ra->highest_rate = 0;
+ }
+
+ /* Lowest rate */
+ if (ra->ra_use_rate) {
+ for (i = 0; i < RATESIZE; i++) {
+ if (ra->ra_use_rate & BIT(i)) {
+ ra->lowest_rate = i;
+ break;
+ }
+ }
+ } else {
+ ra->lowest_rate = 0;
+ }
+
+ if (ra->highest_rate > DESC_RATE_MCS7)
+ ra->pt_mode_ss = 3;
+ else if (ra->highest_rate > DESC_RATE_54M)
+ ra->pt_mode_ss = 2;
+ else if (ra->highest_rate > DESC_RATE_11M)
+ ra->pt_mode_ss = 1;
+ else
+ ra->pt_mode_ss = 0;
+}
+
+static void
+rtl8188e_update_rate_mask(struct rtl8xxxu_priv *priv,
+ u32 ramask, u8 rateid, int sgi, int txbw_40mhz)
+{
+ struct rtl8xxxu_ra_info *ra = &priv->ra_info;
+
+ ra->rate_id = rateid;
+ ra->rate_mask = ramask;
+ ra->sgi_enable = sgi;
+
+ rtl8188e_arfb_refresh(ra);
+}
+
+void rtl8188e_ra_info_init_all(struct rtl8xxxu_ra_info *ra)
+{
+ ra->decision_rate = DESC_RATE_MCS7;
+ ra->pre_rate = DESC_RATE_MCS7;
+ ra->highest_rate = DESC_RATE_MCS7;
+ ra->lowest_rate = 0;
+ ra->rate_id = 0;
+ ra->rate_mask = 0xfffff;
+ ra->rssi_sta_ra = 0;
+ ra->pre_rssi_sta_ra = 0;
+ ra->sgi_enable = 0;
+ ra->ra_use_rate = 0xfffff;
+ ra->nsc_down = (n_threshold_high[DESC_RATE_MCS7] + n_threshold_low[DESC_RATE_MCS7]) / 2;
+ ra->nsc_up = (n_threshold_high[DESC_RATE_MCS7] + n_threshold_low[DESC_RATE_MCS7]) / 2;
+ ra->rate_sgi = 0;
+ ra->rpt_time = 0x927c;
+ ra->drop = 0;
+ ra->retry[0] = 0;
+ ra->retry[1] = 0;
+ ra->retry[2] = 0;
+ ra->retry[3] = 0;
+ ra->retry[4] = 0;
+ ra->total = 0;
+ ra->ra_waiting_counter = 0;
+ ra->ra_pending_counter = 0;
+ ra->ra_drop_after_down = 0;
+
+ ra->pt_try_state = 0;
+ ra->pt_stage = 5;
+ ra->pt_smooth_factor = 192;
+ ra->pt_stop_count = 0;
+ ra->pt_pre_rate = 0;
+ ra->pt_pre_rssi = 0;
+ ra->pt_mode_ss = 0;
+ ra->ra_stage = 0;
+}
+
struct rtl8xxxu_fileops rtl8188eu_fops = {
.identify_chip = rtl8188eu_identify_chip,
.parse_efuse = rtl8188eu_parse_efuse,
@@ -1252,7 +1840,7 @@ struct rtl8xxxu_fileops rtl8188eu_fops = {
.disable_rf = rtl8188e_disable_rf,
.usb_quirks = rtl8188e_usb_quirks,
.set_tx_power = rtl8188f_set_tx_power,
- .update_rate_mask = rtl8xxxu_gen2_update_rate_mask,
+ .update_rate_mask = rtl8188e_update_rate_mask,
.report_connect = rtl8xxxu_gen2_report_connect,
.fill_txdesc = rtl8xxxu_fill_txdesc_v3,
.set_crystal_cap = rtl8188f_set_crystal_cap,
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
index e73c96ea0517..fd97c040948a 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
@@ -3981,7 +3981,25 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
* Enable TX report and TX report timer for 8723bu/8188eu/...
*/
if (fops->has_tx_report) {
+ /*
+ * The RTL8188EU has two types of TX reports:
+ * rpt_sel=1:
+ * One report for one frame. We can use this for frames
+ * with IEEE80211_TX_CTL_REQ_TX_STATUS.
+ * rpt_sel=2:
+ * One report for many frames transmitted over a period
+ * of time. (This is what REG_TX_REPORT_TIME is for.) The
+ * report includes the number of frames transmitted
+ * successfully, and the number of unsuccessful
+ * transmissions. We use this for software rate control.
+ *
+ * Bit 0 of REG_TX_REPORT_CTRL is required for both types.
+ * Bit 1 (TX_REPORT_CTRL_TIMER_ENABLE) is required for
+ * type 2.
+ */
val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL);
+ if (priv->rtl_chip == RTL8188E)
+ val8 |= BIT(0);
val8 |= TX_REPORT_CTRL_TIMER_ENABLE;
rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8);
/* Set MAX RPT MACID */
@@ -4274,6 +4292,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
priv->cfo_tracking.crystal_cap = priv->default_crystal_cap;
}
+ if (priv->rtl_chip == RTL8188E)
+ rtl8188e_ra_info_init_all(&priv->ra_info);
+
exit:
return ret;
}
@@ -4637,8 +4658,8 @@ static void rtl8xxxu_set_aifs(struct rtl8xxxu_priv *priv, u8 slot_time)
}
}
-static void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt,
- u8 rate, u8 sgi, u8 bw)
+void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt,
+ u8 rate, u8 sgi, u8 bw)
{
u8 mcs, nss;
@@ -5122,6 +5143,7 @@ rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);
struct rtl8xxxu_priv *priv = hw->priv;
struct device *dev = &priv->udev->dev;
+ struct rtl8xxxu_ra_info *ra = &priv->ra_info;
u8 *qc = ieee80211_get_qos_ctl(hdr);
u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
u32 rate;
@@ -5137,9 +5159,10 @@ rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
if (ieee80211_is_data(hdr->frame_control)) {
- rate = DESC_RATE_MCS7; /* TODO: software rate control */
+ rate = ra->decision_rate;
tx_desc->txdw5 = cpu_to_le32(rate);
tx_desc->txdw4 |= cpu_to_le32(TXDESC32_USE_DRIVER_RATE);
+ tx_desc->txdw4 |= le32_encode_bits(ra->pt_stage, TXDESC32_PT_STAGE_MASK);
/* Data/RTS rate FB limit */
tx_desc->txdw5 |= cpu_to_le32(0x0001ff00);
}
@@ -5178,7 +5201,7 @@ rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
if (short_preamble)
tx_desc->txdw4 |= cpu_to_le32(TXDESC32_SHORT_PREAMBLE);
- if (sgi)
+ if (sgi && ra->rate_sgi)
tx_desc->txdw5 |= cpu_to_le32(TXDESC32_SHORT_GI);
/*
@@ -5769,6 +5792,44 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv,
schedule_work(&priv->c2hcmd_work);
}
+static void rtl8188e_c2hcmd_callback(struct work_struct *work)
+{
+ struct rtl8xxxu_priv *priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work);
+ struct device *dev = &priv->udev->dev;
+ struct sk_buff *skb = NULL;
+ struct rtl8xxxu_rxdesc16 *rx_desc;
+
+ while (!skb_queue_empty(&priv->c2hcmd_queue)) {
+ skb = skb_dequeue(&priv->c2hcmd_queue);
+
+ rx_desc = (struct rtl8xxxu_rxdesc16 *)(skb->data - sizeof(struct rtl8xxxu_rxdesc16));
+
+ switch (rx_desc->rpt_sel) {
+ case 1:
+ dev_dbg(dev, "C2H TX report type 1\n");
+
+ break;
+ case 2:
+ dev_dbg(dev, "C2H TX report type 2\n");
+
+ rtl8188e_handle_ra_tx_report2(priv, skb);
+
+ break;
+ case 3:
+ dev_dbg(dev, "C2H USB interrupt report\n");
+
+ break;
+ default:
+ dev_warn(dev, "%s: rpt_sel should not be %d\n",
+ __func__, rx_desc->rpt_sel);
+
+ break;
+ }
+
+ dev_kfree_skb(skb);
+ }
+}
+
int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
{
struct ieee80211_hw *hw = priv->hw;
@@ -5824,38 +5885,45 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc16));
- phy_stats = (struct rtl8723au_phy_stats *)skb->data;
+ if (rx_desc->rpt_sel) {
+ skb_queue_tail(&priv->c2hcmd_queue, skb);
+ schedule_work(&priv->c2hcmd_work);
+ } else {
+ phy_stats = (struct rtl8723au_phy_stats *)skb->data;
- skb_pull(skb, drvinfo_sz + desc_shift);
+ skb_pull(skb, drvinfo_sz + desc_shift);
- skb_trim(skb, pkt_len);
+ skb_trim(skb, pkt_len);
- if (rx_desc->phy_stats)
- rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats,
- rx_desc->rxmcs, (struct ieee80211_hdr *)skb->data,
- rx_desc->crc32 || rx_desc->icverr);
+ if (rx_desc->phy_stats)
+ rtl8xxxu_rx_parse_phystats(
+ priv, rx_status, phy_stats,
+ rx_desc->rxmcs,
+ (struct ieee80211_hdr *)skb->data,
+ rx_desc->crc32 || rx_desc->icverr);
- rx_status->mactime = rx_desc->tsfl;
- rx_status->flag |= RX_FLAG_MACTIME_START;
+ rx_status->mactime = rx_desc->tsfl;
+ rx_status->flag |= RX_FLAG_MACTIME_START;
- if (!rx_desc->swdec)
- rx_status->flag |= RX_FLAG_DECRYPTED;
- if (rx_desc->crc32)
- rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
- if (rx_desc->bw)
- rx_status->bw = RATE_INFO_BW_40;
+ if (!rx_desc->swdec)
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ if (rx_desc->crc32)
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+ if (rx_desc->bw)
+ rx_status->bw = RATE_INFO_BW_40;
- if (rx_desc->rxht) {
- rx_status->encoding = RX_ENC_HT;
- rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0;
- } else {
- rx_status->rate_idx = rx_desc->rxmcs;
- }
+ if (rx_desc->rxht) {
+ rx_status->encoding = RX_ENC_HT;
+ rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0;
+ } else {
+ rx_status->rate_idx = rx_desc->rxmcs;
+ }
- rx_status->freq = hw->conf.chandef.chan->center_freq;
- rx_status->band = hw->conf.chandef.chan->band;
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
- ieee80211_rx_irqsafe(hw, skb);
+ ieee80211_rx_irqsafe(hw, skb);
+ }
skb = next_skb;
if (skb)
@@ -6942,7 +7010,6 @@ static int rtl8xxxu_probe(struct usb_interface *interface,
spin_lock_init(&priv->rx_urb_lock);
INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work);
INIT_DELAYED_WORK(&priv->ra_watchdog, rtl8xxxu_watchdog_callback);
- INIT_WORK(&priv->c2hcmd_work, rtl8xxxu_c2hcmd_callback);
skb_queue_head_init(&priv->c2hcmd_queue);
usb_set_intfdata(interface, hw);
@@ -6960,6 +7027,11 @@ static int rtl8xxxu_probe(struct usb_interface *interface,
hw->wiphy->available_antennas_tx = BIT(priv->tx_paths) - 1;
hw->wiphy->available_antennas_rx = BIT(priv->rx_paths) - 1;
+ if (priv->rtl_chip == RTL8188E)
+ INIT_WORK(&priv->c2hcmd_work, rtl8188e_c2hcmd_callback);
+ else
+ INIT_WORK(&priv->c2hcmd_work, rtl8xxxu_c2hcmd_callback);
+
ret = rtl8xxxu_read_efuse(priv);
if (ret) {
dev_err(&udev->dev, "Fatal - failed to read EFuse\n");