1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright(c) 2009-2012 Realtek Corporation.*/
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include "wifi.h"
5*4882a593Smuzhiyun #include "rc.h"
6*4882a593Smuzhiyun #include "base.h"
7*4882a593Smuzhiyun #include "efuse.h"
8*4882a593Smuzhiyun #include "cam.h"
9*4882a593Smuzhiyun #include "ps.h"
10*4882a593Smuzhiyun #include "regd.h"
11*4882a593Smuzhiyun #include "pci.h"
12*4882a593Smuzhiyun #include <linux/ip.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/udp.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun /*
17*4882a593Smuzhiyun *NOTICE!!!: This file will be very big, we should
18*4882a593Smuzhiyun *keep it clear under following roles:
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun *This file include following parts, so, if you add new
21*4882a593Smuzhiyun *functions into this file, please check which part it
22*4882a593Smuzhiyun *should includes. or check if you should add new part
23*4882a593Smuzhiyun *for this file:
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun *1) mac80211 init functions
26*4882a593Smuzhiyun *2) tx information functions
27*4882a593Smuzhiyun *3) functions called by core.c
28*4882a593Smuzhiyun *4) wq & timer callback functions
29*4882a593Smuzhiyun *5) frame process functions
30*4882a593Smuzhiyun *6) IOT functions
31*4882a593Smuzhiyun *7) sysfs functions
32*4882a593Smuzhiyun *8) vif functions
33*4882a593Smuzhiyun *9) ...
34*4882a593Smuzhiyun */
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /*********************************************************
37*4882a593Smuzhiyun *
38*4882a593Smuzhiyun * mac80211 init functions
39*4882a593Smuzhiyun *
40*4882a593Smuzhiyun *********************************************************/
41*4882a593Smuzhiyun static struct ieee80211_channel rtl_channeltable_2g[] = {
42*4882a593Smuzhiyun {.center_freq = 2412, .hw_value = 1,},
43*4882a593Smuzhiyun {.center_freq = 2417, .hw_value = 2,},
44*4882a593Smuzhiyun {.center_freq = 2422, .hw_value = 3,},
45*4882a593Smuzhiyun {.center_freq = 2427, .hw_value = 4,},
46*4882a593Smuzhiyun {.center_freq = 2432, .hw_value = 5,},
47*4882a593Smuzhiyun {.center_freq = 2437, .hw_value = 6,},
48*4882a593Smuzhiyun {.center_freq = 2442, .hw_value = 7,},
49*4882a593Smuzhiyun {.center_freq = 2447, .hw_value = 8,},
50*4882a593Smuzhiyun {.center_freq = 2452, .hw_value = 9,},
51*4882a593Smuzhiyun {.center_freq = 2457, .hw_value = 10,},
52*4882a593Smuzhiyun {.center_freq = 2462, .hw_value = 11,},
53*4882a593Smuzhiyun {.center_freq = 2467, .hw_value = 12,},
54*4882a593Smuzhiyun {.center_freq = 2472, .hw_value = 13,},
55*4882a593Smuzhiyun {.center_freq = 2484, .hw_value = 14,},
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun static struct ieee80211_channel rtl_channeltable_5g[] = {
59*4882a593Smuzhiyun {.center_freq = 5180, .hw_value = 36,},
60*4882a593Smuzhiyun {.center_freq = 5200, .hw_value = 40,},
61*4882a593Smuzhiyun {.center_freq = 5220, .hw_value = 44,},
62*4882a593Smuzhiyun {.center_freq = 5240, .hw_value = 48,},
63*4882a593Smuzhiyun {.center_freq = 5260, .hw_value = 52,},
64*4882a593Smuzhiyun {.center_freq = 5280, .hw_value = 56,},
65*4882a593Smuzhiyun {.center_freq = 5300, .hw_value = 60,},
66*4882a593Smuzhiyun {.center_freq = 5320, .hw_value = 64,},
67*4882a593Smuzhiyun {.center_freq = 5500, .hw_value = 100,},
68*4882a593Smuzhiyun {.center_freq = 5520, .hw_value = 104,},
69*4882a593Smuzhiyun {.center_freq = 5540, .hw_value = 108,},
70*4882a593Smuzhiyun {.center_freq = 5560, .hw_value = 112,},
71*4882a593Smuzhiyun {.center_freq = 5580, .hw_value = 116,},
72*4882a593Smuzhiyun {.center_freq = 5600, .hw_value = 120,},
73*4882a593Smuzhiyun {.center_freq = 5620, .hw_value = 124,},
74*4882a593Smuzhiyun {.center_freq = 5640, .hw_value = 128,},
75*4882a593Smuzhiyun {.center_freq = 5660, .hw_value = 132,},
76*4882a593Smuzhiyun {.center_freq = 5680, .hw_value = 136,},
77*4882a593Smuzhiyun {.center_freq = 5700, .hw_value = 140,},
78*4882a593Smuzhiyun {.center_freq = 5745, .hw_value = 149,},
79*4882a593Smuzhiyun {.center_freq = 5765, .hw_value = 153,},
80*4882a593Smuzhiyun {.center_freq = 5785, .hw_value = 157,},
81*4882a593Smuzhiyun {.center_freq = 5805, .hw_value = 161,},
82*4882a593Smuzhiyun {.center_freq = 5825, .hw_value = 165,},
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun static struct ieee80211_rate rtl_ratetable_2g[] = {
86*4882a593Smuzhiyun {.bitrate = 10, .hw_value = 0x00,},
87*4882a593Smuzhiyun {.bitrate = 20, .hw_value = 0x01,},
88*4882a593Smuzhiyun {.bitrate = 55, .hw_value = 0x02,},
89*4882a593Smuzhiyun {.bitrate = 110, .hw_value = 0x03,},
90*4882a593Smuzhiyun {.bitrate = 60, .hw_value = 0x04,},
91*4882a593Smuzhiyun {.bitrate = 90, .hw_value = 0x05,},
92*4882a593Smuzhiyun {.bitrate = 120, .hw_value = 0x06,},
93*4882a593Smuzhiyun {.bitrate = 180, .hw_value = 0x07,},
94*4882a593Smuzhiyun {.bitrate = 240, .hw_value = 0x08,},
95*4882a593Smuzhiyun {.bitrate = 360, .hw_value = 0x09,},
96*4882a593Smuzhiyun {.bitrate = 480, .hw_value = 0x0a,},
97*4882a593Smuzhiyun {.bitrate = 540, .hw_value = 0x0b,},
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun static struct ieee80211_rate rtl_ratetable_5g[] = {
101*4882a593Smuzhiyun {.bitrate = 60, .hw_value = 0x04,},
102*4882a593Smuzhiyun {.bitrate = 90, .hw_value = 0x05,},
103*4882a593Smuzhiyun {.bitrate = 120, .hw_value = 0x06,},
104*4882a593Smuzhiyun {.bitrate = 180, .hw_value = 0x07,},
105*4882a593Smuzhiyun {.bitrate = 240, .hw_value = 0x08,},
106*4882a593Smuzhiyun {.bitrate = 360, .hw_value = 0x09,},
107*4882a593Smuzhiyun {.bitrate = 480, .hw_value = 0x0a,},
108*4882a593Smuzhiyun {.bitrate = 540, .hw_value = 0x0b,},
109*4882a593Smuzhiyun };
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun static const struct ieee80211_supported_band rtl_band_2ghz = {
112*4882a593Smuzhiyun .band = NL80211_BAND_2GHZ,
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun .channels = rtl_channeltable_2g,
115*4882a593Smuzhiyun .n_channels = ARRAY_SIZE(rtl_channeltable_2g),
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun .bitrates = rtl_ratetable_2g,
118*4882a593Smuzhiyun .n_bitrates = ARRAY_SIZE(rtl_ratetable_2g),
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun .ht_cap = {0},
121*4882a593Smuzhiyun };
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun static struct ieee80211_supported_band rtl_band_5ghz = {
124*4882a593Smuzhiyun .band = NL80211_BAND_5GHZ,
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun .channels = rtl_channeltable_5g,
127*4882a593Smuzhiyun .n_channels = ARRAY_SIZE(rtl_channeltable_5g),
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun .bitrates = rtl_ratetable_5g,
130*4882a593Smuzhiyun .n_bitrates = ARRAY_SIZE(rtl_ratetable_5g),
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun .ht_cap = {0},
133*4882a593Smuzhiyun };
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun static const u8 tid_to_ac[] = {
136*4882a593Smuzhiyun 2, /* IEEE80211_AC_BE */
137*4882a593Smuzhiyun 3, /* IEEE80211_AC_BK */
138*4882a593Smuzhiyun 3, /* IEEE80211_AC_BK */
139*4882a593Smuzhiyun 2, /* IEEE80211_AC_BE */
140*4882a593Smuzhiyun 1, /* IEEE80211_AC_VI */
141*4882a593Smuzhiyun 1, /* IEEE80211_AC_VI */
142*4882a593Smuzhiyun 0, /* IEEE80211_AC_VO */
143*4882a593Smuzhiyun 0, /* IEEE80211_AC_VO */
144*4882a593Smuzhiyun };
145*4882a593Smuzhiyun
rtl_tid_to_ac(u8 tid)146*4882a593Smuzhiyun u8 rtl_tid_to_ac(u8 tid)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun return tid_to_ac[tid];
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_tid_to_ac);
151*4882a593Smuzhiyun
_rtl_init_hw_ht_capab(struct ieee80211_hw * hw,struct ieee80211_sta_ht_cap * ht_cap)152*4882a593Smuzhiyun static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
153*4882a593Smuzhiyun struct ieee80211_sta_ht_cap *ht_cap)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
156*4882a593Smuzhiyun struct rtl_phy *rtlphy = &(rtlpriv->phy);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun ht_cap->ht_supported = true;
159*4882a593Smuzhiyun ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
160*4882a593Smuzhiyun IEEE80211_HT_CAP_SGI_40 |
161*4882a593Smuzhiyun IEEE80211_HT_CAP_SGI_20 |
162*4882a593Smuzhiyun IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (rtlpriv->rtlhal.disable_amsdu_8k)
165*4882a593Smuzhiyun ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun *Maximum length of AMPDU that the STA can receive.
169*4882a593Smuzhiyun *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
170*4882a593Smuzhiyun */
171*4882a593Smuzhiyun ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /*Minimum MPDU start spacing , */
174*4882a593Smuzhiyun ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /*hw->wiphy->bands[NL80211_BAND_2GHZ]
179*4882a593Smuzhiyun *base on ant_num
180*4882a593Smuzhiyun *rx_mask: RX mask
181*4882a593Smuzhiyun *if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7
182*4882a593Smuzhiyun *if rx_ant = 2 rx_mask[1]= 0xff;==>MCS8-MCS15
183*4882a593Smuzhiyun *if rx_ant >= 3 rx_mask[2]= 0xff;
184*4882a593Smuzhiyun *if BW_40 rx_mask[4]= 0x01;
185*4882a593Smuzhiyun *highest supported RX rate
186*4882a593Smuzhiyun */
187*4882a593Smuzhiyun if (rtlpriv->dm.supp_phymode_switch) {
188*4882a593Smuzhiyun pr_info("Support phy mode switch\n");
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun ht_cap->mcs.rx_mask[0] = 0xFF;
191*4882a593Smuzhiyun ht_cap->mcs.rx_mask[1] = 0xFF;
192*4882a593Smuzhiyun ht_cap->mcs.rx_mask[4] = 0x01;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15);
195*4882a593Smuzhiyun } else {
196*4882a593Smuzhiyun if (get_rf_type(rtlphy) == RF_1T2R ||
197*4882a593Smuzhiyun get_rf_type(rtlphy) == RF_2T2R) {
198*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG,
199*4882a593Smuzhiyun "1T2R or 2T2R\n");
200*4882a593Smuzhiyun ht_cap->mcs.rx_mask[0] = 0xFF;
201*4882a593Smuzhiyun ht_cap->mcs.rx_mask[1] = 0xFF;
202*4882a593Smuzhiyun ht_cap->mcs.rx_mask[4] = 0x01;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun ht_cap->mcs.rx_highest =
205*4882a593Smuzhiyun cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15);
206*4882a593Smuzhiyun } else if (get_rf_type(rtlphy) == RF_1T1R) {
207*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG, "1T1R\n");
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun ht_cap->mcs.rx_mask[0] = 0xFF;
210*4882a593Smuzhiyun ht_cap->mcs.rx_mask[1] = 0x00;
211*4882a593Smuzhiyun ht_cap->mcs.rx_mask[4] = 0x01;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun ht_cap->mcs.rx_highest =
214*4882a593Smuzhiyun cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
_rtl_init_hw_vht_capab(struct ieee80211_hw * hw,struct ieee80211_sta_vht_cap * vht_cap)219*4882a593Smuzhiyun static void _rtl_init_hw_vht_capab(struct ieee80211_hw *hw,
220*4882a593Smuzhiyun struct ieee80211_sta_vht_cap *vht_cap)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
223*4882a593Smuzhiyun struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun if (!(rtlpriv->cfg->spec_ver & RTL_SPEC_SUPPORT_VHT))
226*4882a593Smuzhiyun return;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE ||
229*4882a593Smuzhiyun rtlhal->hw_type == HARDWARE_TYPE_RTL8822BE) {
230*4882a593Smuzhiyun u16 mcs_map;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun vht_cap->vht_supported = true;
233*4882a593Smuzhiyun vht_cap->cap =
234*4882a593Smuzhiyun IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
235*4882a593Smuzhiyun IEEE80211_VHT_CAP_SHORT_GI_80 |
236*4882a593Smuzhiyun IEEE80211_VHT_CAP_TXSTBC |
237*4882a593Smuzhiyun IEEE80211_VHT_CAP_RXSTBC_1 |
238*4882a593Smuzhiyun IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
239*4882a593Smuzhiyun IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
240*4882a593Smuzhiyun IEEE80211_VHT_CAP_HTC_VHT |
241*4882a593Smuzhiyun IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
242*4882a593Smuzhiyun IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
243*4882a593Smuzhiyun IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
244*4882a593Smuzhiyun 0;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
247*4882a593Smuzhiyun IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
248*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
249*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
250*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
251*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
252*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
253*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 14;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
256*4882a593Smuzhiyun vht_cap->vht_mcs.rx_highest =
257*4882a593Smuzhiyun cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9);
258*4882a593Smuzhiyun vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
259*4882a593Smuzhiyun vht_cap->vht_mcs.tx_highest =
260*4882a593Smuzhiyun cpu_to_le16(MAX_BIT_RATE_SHORT_GI_2NSS_80MHZ_MCS9);
261*4882a593Smuzhiyun } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) {
262*4882a593Smuzhiyun u16 mcs_map;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun vht_cap->vht_supported = true;
265*4882a593Smuzhiyun vht_cap->cap =
266*4882a593Smuzhiyun IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
267*4882a593Smuzhiyun IEEE80211_VHT_CAP_SHORT_GI_80 |
268*4882a593Smuzhiyun IEEE80211_VHT_CAP_TXSTBC |
269*4882a593Smuzhiyun IEEE80211_VHT_CAP_RXSTBC_1 |
270*4882a593Smuzhiyun IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
271*4882a593Smuzhiyun IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
272*4882a593Smuzhiyun IEEE80211_VHT_CAP_HTC_VHT |
273*4882a593Smuzhiyun IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
274*4882a593Smuzhiyun IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
275*4882a593Smuzhiyun IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
276*4882a593Smuzhiyun 0;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
279*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 |
280*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
281*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
282*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
283*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
284*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
285*4882a593Smuzhiyun IEEE80211_VHT_MCS_NOT_SUPPORTED << 14;
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
288*4882a593Smuzhiyun vht_cap->vht_mcs.rx_highest =
289*4882a593Smuzhiyun cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9);
290*4882a593Smuzhiyun vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
291*4882a593Smuzhiyun vht_cap->vht_mcs.tx_highest =
292*4882a593Smuzhiyun cpu_to_le16(MAX_BIT_RATE_SHORT_GI_1NSS_80MHZ_MCS9);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
_rtl_init_mac80211(struct ieee80211_hw * hw)296*4882a593Smuzhiyun static void _rtl_init_mac80211(struct ieee80211_hw *hw)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
299*4882a593Smuzhiyun struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
300*4882a593Smuzhiyun struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
301*4882a593Smuzhiyun struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
302*4882a593Smuzhiyun struct ieee80211_supported_band *sband;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY &&
305*4882a593Smuzhiyun rtlhal->bandset == BAND_ON_BOTH) {
306*4882a593Smuzhiyun /* 1: 2.4 G bands */
307*4882a593Smuzhiyun /* <1> use mac->bands as mem for hw->wiphy->bands */
308*4882a593Smuzhiyun sband = &(rtlmac->bands[NL80211_BAND_2GHZ]);
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun /* <2> set hw->wiphy->bands[NL80211_BAND_2GHZ]
311*4882a593Smuzhiyun * to default value(1T1R) */
312*4882a593Smuzhiyun memcpy(&(rtlmac->bands[NL80211_BAND_2GHZ]), &rtl_band_2ghz,
313*4882a593Smuzhiyun sizeof(struct ieee80211_supported_band));
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun /* <3> init ht cap base on ant_num */
316*4882a593Smuzhiyun _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun /* <4> set mac->sband to wiphy->sband */
319*4882a593Smuzhiyun hw->wiphy->bands[NL80211_BAND_2GHZ] = sband;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun /* 2: 5 G bands */
322*4882a593Smuzhiyun /* <1> use mac->bands as mem for hw->wiphy->bands */
323*4882a593Smuzhiyun sband = &(rtlmac->bands[NL80211_BAND_5GHZ]);
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun /* <2> set hw->wiphy->bands[NL80211_BAND_5GHZ]
326*4882a593Smuzhiyun * to default value(1T1R) */
327*4882a593Smuzhiyun memcpy(&(rtlmac->bands[NL80211_BAND_5GHZ]), &rtl_band_5ghz,
328*4882a593Smuzhiyun sizeof(struct ieee80211_supported_band));
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun /* <3> init ht cap base on ant_num */
331*4882a593Smuzhiyun _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun _rtl_init_hw_vht_capab(hw, &sband->vht_cap);
334*4882a593Smuzhiyun /* <4> set mac->sband to wiphy->sband */
335*4882a593Smuzhiyun hw->wiphy->bands[NL80211_BAND_5GHZ] = sband;
336*4882a593Smuzhiyun } else {
337*4882a593Smuzhiyun if (rtlhal->current_bandtype == BAND_ON_2_4G) {
338*4882a593Smuzhiyun /* <1> use mac->bands as mem for hw->wiphy->bands */
339*4882a593Smuzhiyun sband = &(rtlmac->bands[NL80211_BAND_2GHZ]);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun /* <2> set hw->wiphy->bands[NL80211_BAND_2GHZ]
342*4882a593Smuzhiyun * to default value(1T1R) */
343*4882a593Smuzhiyun memcpy(&(rtlmac->bands[NL80211_BAND_2GHZ]),
344*4882a593Smuzhiyun &rtl_band_2ghz,
345*4882a593Smuzhiyun sizeof(struct ieee80211_supported_band));
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /* <3> init ht cap base on ant_num */
348*4882a593Smuzhiyun _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun /* <4> set mac->sband to wiphy->sband */
351*4882a593Smuzhiyun hw->wiphy->bands[NL80211_BAND_2GHZ] = sband;
352*4882a593Smuzhiyun } else if (rtlhal->current_bandtype == BAND_ON_5G) {
353*4882a593Smuzhiyun /* <1> use mac->bands as mem for hw->wiphy->bands */
354*4882a593Smuzhiyun sband = &(rtlmac->bands[NL80211_BAND_5GHZ]);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* <2> set hw->wiphy->bands[NL80211_BAND_5GHZ]
357*4882a593Smuzhiyun * to default value(1T1R) */
358*4882a593Smuzhiyun memcpy(&(rtlmac->bands[NL80211_BAND_5GHZ]),
359*4882a593Smuzhiyun &rtl_band_5ghz,
360*4882a593Smuzhiyun sizeof(struct ieee80211_supported_band));
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun /* <3> init ht cap base on ant_num */
363*4882a593Smuzhiyun _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun _rtl_init_hw_vht_capab(hw, &sband->vht_cap);
366*4882a593Smuzhiyun /* <4> set mac->sband to wiphy->sband */
367*4882a593Smuzhiyun hw->wiphy->bands[NL80211_BAND_5GHZ] = sband;
368*4882a593Smuzhiyun } else {
369*4882a593Smuzhiyun pr_err("Err BAND %d\n",
370*4882a593Smuzhiyun rtlhal->current_bandtype);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun /* <5> set hw caps */
374*4882a593Smuzhiyun ieee80211_hw_set(hw, SIGNAL_DBM);
375*4882a593Smuzhiyun ieee80211_hw_set(hw, RX_INCLUDES_FCS);
376*4882a593Smuzhiyun ieee80211_hw_set(hw, AMPDU_AGGREGATION);
377*4882a593Smuzhiyun ieee80211_hw_set(hw, MFP_CAPABLE);
378*4882a593Smuzhiyun ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
379*4882a593Smuzhiyun ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
380*4882a593Smuzhiyun ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun /* swlps or hwlps has been set in diff chip in init_sw_vars */
383*4882a593Smuzhiyun if (rtlpriv->psc.swctrl_lps) {
384*4882a593Smuzhiyun ieee80211_hw_set(hw, SUPPORTS_PS);
385*4882a593Smuzhiyun ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun if (rtlpriv->psc.fwctrl_lps) {
388*4882a593Smuzhiyun ieee80211_hw_set(hw, SUPPORTS_PS);
389*4882a593Smuzhiyun ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun hw->wiphy->interface_modes =
392*4882a593Smuzhiyun BIT(NL80211_IFTYPE_AP) |
393*4882a593Smuzhiyun BIT(NL80211_IFTYPE_STATION) |
394*4882a593Smuzhiyun BIT(NL80211_IFTYPE_ADHOC) |
395*4882a593Smuzhiyun BIT(NL80211_IFTYPE_MESH_POINT) |
396*4882a593Smuzhiyun BIT(NL80211_IFTYPE_P2P_CLIENT) |
397*4882a593Smuzhiyun BIT(NL80211_IFTYPE_P2P_GO);
398*4882a593Smuzhiyun hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun hw->wiphy->rts_threshold = 2347;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun hw->queues = AC_MAX;
405*4882a593Smuzhiyun hw->extra_tx_headroom = RTL_TX_HEADER_SIZE;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /* TODO: Correct this value for our hw */
408*4882a593Smuzhiyun hw->max_listen_interval = MAX_LISTEN_INTERVAL;
409*4882a593Smuzhiyun hw->max_rate_tries = MAX_RATE_TRIES;
410*4882a593Smuzhiyun /* hw->max_rates = 1; */
411*4882a593Smuzhiyun hw->sta_data_size = sizeof(struct rtl_sta_info);
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun /* wowlan is not supported by kernel if CONFIG_PM is not defined */
414*4882a593Smuzhiyun #ifdef CONFIG_PM
415*4882a593Smuzhiyun if (rtlpriv->psc.wo_wlan_mode) {
416*4882a593Smuzhiyun if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_MAGIC_PACKET)
417*4882a593Smuzhiyun rtlpriv->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT;
418*4882a593Smuzhiyun if (rtlpriv->psc.wo_wlan_mode & WAKE_ON_PATTERN_MATCH) {
419*4882a593Smuzhiyun rtlpriv->wowlan.n_patterns =
420*4882a593Smuzhiyun MAX_SUPPORT_WOL_PATTERN_NUM;
421*4882a593Smuzhiyun rtlpriv->wowlan.pattern_min_len = MIN_WOL_PATTERN_SIZE;
422*4882a593Smuzhiyun rtlpriv->wowlan.pattern_max_len = MAX_WOL_PATTERN_SIZE;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun hw->wiphy->wowlan = &rtlpriv->wowlan;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun #endif
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun /* <6> mac address */
429*4882a593Smuzhiyun if (is_valid_ether_addr(rtlefuse->dev_addr)) {
430*4882a593Smuzhiyun SET_IEEE80211_PERM_ADDR(hw, rtlefuse->dev_addr);
431*4882a593Smuzhiyun } else {
432*4882a593Smuzhiyun u8 rtlmac1[] = { 0x00, 0xe0, 0x4c, 0x81, 0x92, 0x00 };
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun get_random_bytes((rtlmac1 + (ETH_ALEN - 1)), 1);
435*4882a593Smuzhiyun SET_IEEE80211_PERM_ADDR(hw, rtlmac1);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun static void rtl_watchdog_wq_callback(struct work_struct *work);
440*4882a593Smuzhiyun static void rtl_fwevt_wq_callback(struct work_struct *work);
441*4882a593Smuzhiyun static void rtl_c2hcmd_wq_callback(struct work_struct *work);
442*4882a593Smuzhiyun
_rtl_init_deferred_work(struct ieee80211_hw * hw)443*4882a593Smuzhiyun static int _rtl_init_deferred_work(struct ieee80211_hw *hw)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
446*4882a593Smuzhiyun struct workqueue_struct *wq;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun wq = alloc_workqueue("%s", 0, 0, rtlpriv->cfg->name);
449*4882a593Smuzhiyun if (!wq)
450*4882a593Smuzhiyun return -ENOMEM;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /* <1> timer */
453*4882a593Smuzhiyun timer_setup(&rtlpriv->works.watchdog_timer,
454*4882a593Smuzhiyun rtl_watch_dog_timer_callback, 0);
455*4882a593Smuzhiyun timer_setup(&rtlpriv->works.dualmac_easyconcurrent_retrytimer,
456*4882a593Smuzhiyun rtl_easy_concurrent_retrytimer_callback, 0);
457*4882a593Smuzhiyun /* <2> work queue */
458*4882a593Smuzhiyun rtlpriv->works.hw = hw;
459*4882a593Smuzhiyun rtlpriv->works.rtl_wq = wq;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq,
462*4882a593Smuzhiyun rtl_watchdog_wq_callback);
463*4882a593Smuzhiyun INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
464*4882a593Smuzhiyun rtl_ips_nic_off_wq_callback);
465*4882a593Smuzhiyun INIT_DELAYED_WORK(&rtlpriv->works.ps_work, rtl_swlps_wq_callback);
466*4882a593Smuzhiyun INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq,
467*4882a593Smuzhiyun rtl_swlps_rfon_wq_callback);
468*4882a593Smuzhiyun INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq, rtl_fwevt_wq_callback);
469*4882a593Smuzhiyun INIT_DELAYED_WORK(&rtlpriv->works.c2hcmd_wq, rtl_c2hcmd_wq_callback);
470*4882a593Smuzhiyun return 0;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
rtl_deinit_deferred_work(struct ieee80211_hw * hw,bool ips_wq)473*4882a593Smuzhiyun void rtl_deinit_deferred_work(struct ieee80211_hw *hw, bool ips_wq)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun del_timer_sync(&rtlpriv->works.watchdog_timer);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun cancel_delayed_work_sync(&rtlpriv->works.watchdog_wq);
480*4882a593Smuzhiyun if (ips_wq)
481*4882a593Smuzhiyun cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
482*4882a593Smuzhiyun else
483*4882a593Smuzhiyun cancel_delayed_work_sync(&rtlpriv->works.ips_nic_off_wq);
484*4882a593Smuzhiyun cancel_delayed_work_sync(&rtlpriv->works.ps_work);
485*4882a593Smuzhiyun cancel_delayed_work_sync(&rtlpriv->works.ps_rfon_wq);
486*4882a593Smuzhiyun cancel_delayed_work_sync(&rtlpriv->works.fwevt_wq);
487*4882a593Smuzhiyun cancel_delayed_work_sync(&rtlpriv->works.c2hcmd_wq);
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work);
490*4882a593Smuzhiyun
rtl_init_rfkill(struct ieee80211_hw * hw)491*4882a593Smuzhiyun void rtl_init_rfkill(struct ieee80211_hw *hw)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun bool radio_state;
496*4882a593Smuzhiyun bool blocked;
497*4882a593Smuzhiyun u8 valid = 0;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun /*set init state to on */
500*4882a593Smuzhiyun rtlpriv->rfkill.rfkill_state = true;
501*4882a593Smuzhiyun wiphy_rfkill_set_hw_state(hw->wiphy, 0);
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun if (valid) {
506*4882a593Smuzhiyun pr_info("rtlwifi: wireless switch is %s\n",
507*4882a593Smuzhiyun rtlpriv->rfkill.rfkill_state ? "on" : "off");
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun rtlpriv->rfkill.rfkill_state = radio_state;
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun blocked = rtlpriv->rfkill.rfkill_state != 1;
512*4882a593Smuzhiyun wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun wiphy_rfkill_start_polling(hw->wiphy);
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun EXPORT_SYMBOL(rtl_init_rfkill);
518*4882a593Smuzhiyun
rtl_deinit_rfkill(struct ieee80211_hw * hw)519*4882a593Smuzhiyun void rtl_deinit_rfkill(struct ieee80211_hw *hw)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun wiphy_rfkill_stop_polling(hw->wiphy);
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_deinit_rfkill);
524*4882a593Smuzhiyun
rtl_init_core(struct ieee80211_hw * hw)525*4882a593Smuzhiyun int rtl_init_core(struct ieee80211_hw *hw)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
528*4882a593Smuzhiyun struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /* <1> init mac80211 */
531*4882a593Smuzhiyun _rtl_init_mac80211(hw);
532*4882a593Smuzhiyun rtlmac->hw = hw;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun /* <2> rate control register */
535*4882a593Smuzhiyun hw->rate_control_algorithm = "rtl_rc";
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun /*
538*4882a593Smuzhiyun * <3> init CRDA must come after init
539*4882a593Smuzhiyun * mac80211 hw in _rtl_init_mac80211.
540*4882a593Smuzhiyun */
541*4882a593Smuzhiyun if (rtl_regd_init(hw, rtl_reg_notifier)) {
542*4882a593Smuzhiyun pr_err("REGD init failed\n");
543*4882a593Smuzhiyun return 1;
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun /* <4> locks */
547*4882a593Smuzhiyun mutex_init(&rtlpriv->locks.conf_mutex);
548*4882a593Smuzhiyun mutex_init(&rtlpriv->locks.ips_mutex);
549*4882a593Smuzhiyun mutex_init(&rtlpriv->locks.lps_mutex);
550*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.irq_th_lock);
551*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.h2c_lock);
552*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.rf_ps_lock);
553*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.rf_lock);
554*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.waitq_lock);
555*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.entry_list_lock);
556*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.c2hcmd_lock);
557*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.scan_list_lock);
558*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
559*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.fw_ps_lock);
560*4882a593Smuzhiyun spin_lock_init(&rtlpriv->locks.iqk_lock);
561*4882a593Smuzhiyun /* <5> init list */
562*4882a593Smuzhiyun INIT_LIST_HEAD(&rtlpriv->entry_list);
563*4882a593Smuzhiyun INIT_LIST_HEAD(&rtlpriv->scan_list.list);
564*4882a593Smuzhiyun skb_queue_head_init(&rtlpriv->tx_report.queue);
565*4882a593Smuzhiyun skb_queue_head_init(&rtlpriv->c2hcmd_queue);
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun rtlmac->link_state = MAC80211_NOLINK;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun /* <6> init deferred work */
570*4882a593Smuzhiyun return _rtl_init_deferred_work(hw);
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_init_core);
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun static void rtl_free_entries_from_scan_list(struct ieee80211_hw *hw);
575*4882a593Smuzhiyun static void rtl_free_entries_from_ack_queue(struct ieee80211_hw *hw,
576*4882a593Smuzhiyun bool timeout);
577*4882a593Smuzhiyun
rtl_deinit_core(struct ieee80211_hw * hw)578*4882a593Smuzhiyun void rtl_deinit_core(struct ieee80211_hw *hw)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun rtl_c2hcmd_launcher(hw, 0);
581*4882a593Smuzhiyun rtl_free_entries_from_scan_list(hw);
582*4882a593Smuzhiyun rtl_free_entries_from_ack_queue(hw, false);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_deinit_core);
585*4882a593Smuzhiyun
rtl_init_rx_config(struct ieee80211_hw * hw)586*4882a593Smuzhiyun void rtl_init_rx_config(struct ieee80211_hw *hw)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
589*4882a593Smuzhiyun struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_init_rx_config);
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun /*********************************************************
596*4882a593Smuzhiyun *
597*4882a593Smuzhiyun * tx information functions
598*4882a593Smuzhiyun *
599*4882a593Smuzhiyun *********************************************************/
_rtl_qurey_shortpreamble_mode(struct ieee80211_hw * hw,struct rtl_tcb_desc * tcb_desc,struct ieee80211_tx_info * info)600*4882a593Smuzhiyun static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw,
601*4882a593Smuzhiyun struct rtl_tcb_desc *tcb_desc,
602*4882a593Smuzhiyun struct ieee80211_tx_info *info)
603*4882a593Smuzhiyun {
604*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
605*4882a593Smuzhiyun u8 rate_flag = info->control.rates[0].flags;
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun tcb_desc->use_shortpreamble = false;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun /* 1M can only use Long Preamble. 11B spec */
610*4882a593Smuzhiyun if (tcb_desc->hw_rate == rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M])
611*4882a593Smuzhiyun return;
612*4882a593Smuzhiyun else if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
613*4882a593Smuzhiyun tcb_desc->use_shortpreamble = true;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun return;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
_rtl_query_shortgi(struct ieee80211_hw * hw,struct ieee80211_sta * sta,struct rtl_tcb_desc * tcb_desc,struct ieee80211_tx_info * info)618*4882a593Smuzhiyun static void _rtl_query_shortgi(struct ieee80211_hw *hw,
619*4882a593Smuzhiyun struct ieee80211_sta *sta,
620*4882a593Smuzhiyun struct rtl_tcb_desc *tcb_desc,
621*4882a593Smuzhiyun struct ieee80211_tx_info *info)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
624*4882a593Smuzhiyun u8 rate_flag = info->control.rates[0].flags;
625*4882a593Smuzhiyun u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0;
626*4882a593Smuzhiyun u8 sgi_80 = 0, bw_80 = 0;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun tcb_desc->use_shortgi = false;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun if (sta == NULL)
631*4882a593Smuzhiyun return;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
634*4882a593Smuzhiyun sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
635*4882a593Smuzhiyun sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80;
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun if ((!sta->ht_cap.ht_supported) && (!sta->vht_cap.vht_supported))
638*4882a593Smuzhiyun return;
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun if (!sgi_40 && !sgi_20)
641*4882a593Smuzhiyun return;
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun if (mac->opmode == NL80211_IFTYPE_STATION) {
644*4882a593Smuzhiyun bw_40 = mac->bw_40;
645*4882a593Smuzhiyun bw_80 = mac->bw_80;
646*4882a593Smuzhiyun } else if (mac->opmode == NL80211_IFTYPE_AP ||
647*4882a593Smuzhiyun mac->opmode == NL80211_IFTYPE_ADHOC ||
648*4882a593Smuzhiyun mac->opmode == NL80211_IFTYPE_MESH_POINT) {
649*4882a593Smuzhiyun bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
650*4882a593Smuzhiyun bw_80 = sta->vht_cap.vht_supported;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun if (bw_80) {
654*4882a593Smuzhiyun if (sgi_80)
655*4882a593Smuzhiyun tcb_desc->use_shortgi = true;
656*4882a593Smuzhiyun else
657*4882a593Smuzhiyun tcb_desc->use_shortgi = false;
658*4882a593Smuzhiyun } else {
659*4882a593Smuzhiyun if (bw_40 && sgi_40)
660*4882a593Smuzhiyun tcb_desc->use_shortgi = true;
661*4882a593Smuzhiyun else if (!bw_40 && sgi_20)
662*4882a593Smuzhiyun tcb_desc->use_shortgi = true;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI))
666*4882a593Smuzhiyun tcb_desc->use_shortgi = false;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun
_rtl_query_protection_mode(struct ieee80211_hw * hw,struct rtl_tcb_desc * tcb_desc,struct ieee80211_tx_info * info)669*4882a593Smuzhiyun static void _rtl_query_protection_mode(struct ieee80211_hw *hw,
670*4882a593Smuzhiyun struct rtl_tcb_desc *tcb_desc,
671*4882a593Smuzhiyun struct ieee80211_tx_info *info)
672*4882a593Smuzhiyun {
673*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
674*4882a593Smuzhiyun u8 rate_flag = info->control.rates[0].flags;
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun /* Common Settings */
677*4882a593Smuzhiyun tcb_desc->rts_stbc = false;
678*4882a593Smuzhiyun tcb_desc->cts_enable = false;
679*4882a593Smuzhiyun tcb_desc->rts_sc = 0;
680*4882a593Smuzhiyun tcb_desc->rts_bw = false;
681*4882a593Smuzhiyun tcb_desc->rts_use_shortpreamble = false;
682*4882a593Smuzhiyun tcb_desc->rts_use_shortgi = false;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) {
685*4882a593Smuzhiyun /* Use CTS-to-SELF in protection mode. */
686*4882a593Smuzhiyun tcb_desc->rts_enable = true;
687*4882a593Smuzhiyun tcb_desc->cts_enable = true;
688*4882a593Smuzhiyun tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M];
689*4882a593Smuzhiyun } else if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) {
690*4882a593Smuzhiyun /* Use RTS-CTS in protection mode. */
691*4882a593Smuzhiyun tcb_desc->rts_enable = true;
692*4882a593Smuzhiyun tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M];
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun
rtl_mrate_idx_to_arfr_id(struct ieee80211_hw * hw,u8 rate_index,enum wireless_mode wirelessmode)696*4882a593Smuzhiyun u8 rtl_mrate_idx_to_arfr_id(struct ieee80211_hw *hw, u8 rate_index,
697*4882a593Smuzhiyun enum wireless_mode wirelessmode)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
700*4882a593Smuzhiyun struct rtl_phy *rtlphy = &rtlpriv->phy;
701*4882a593Smuzhiyun u8 ret = 0;
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun switch (rate_index) {
704*4882a593Smuzhiyun case RATR_INX_WIRELESS_NGB:
705*4882a593Smuzhiyun if (rtlphy->rf_type == RF_1T1R)
706*4882a593Smuzhiyun ret = RATEID_IDX_BGN_40M_1SS;
707*4882a593Smuzhiyun else
708*4882a593Smuzhiyun ret = RATEID_IDX_BGN_40M_2SS;
709*4882a593Smuzhiyun ; break;
710*4882a593Smuzhiyun case RATR_INX_WIRELESS_N:
711*4882a593Smuzhiyun case RATR_INX_WIRELESS_NG:
712*4882a593Smuzhiyun if (rtlphy->rf_type == RF_1T1R)
713*4882a593Smuzhiyun ret = RATEID_IDX_GN_N1SS;
714*4882a593Smuzhiyun else
715*4882a593Smuzhiyun ret = RATEID_IDX_GN_N2SS;
716*4882a593Smuzhiyun ; break;
717*4882a593Smuzhiyun case RATR_INX_WIRELESS_NB:
718*4882a593Smuzhiyun if (rtlphy->rf_type == RF_1T1R)
719*4882a593Smuzhiyun ret = RATEID_IDX_BGN_20M_1SS_BN;
720*4882a593Smuzhiyun else
721*4882a593Smuzhiyun ret = RATEID_IDX_BGN_20M_2SS_BN;
722*4882a593Smuzhiyun ; break;
723*4882a593Smuzhiyun case RATR_INX_WIRELESS_GB:
724*4882a593Smuzhiyun ret = RATEID_IDX_BG;
725*4882a593Smuzhiyun break;
726*4882a593Smuzhiyun case RATR_INX_WIRELESS_G:
727*4882a593Smuzhiyun ret = RATEID_IDX_G;
728*4882a593Smuzhiyun break;
729*4882a593Smuzhiyun case RATR_INX_WIRELESS_B:
730*4882a593Smuzhiyun ret = RATEID_IDX_B;
731*4882a593Smuzhiyun break;
732*4882a593Smuzhiyun case RATR_INX_WIRELESS_MC:
733*4882a593Smuzhiyun if (wirelessmode == WIRELESS_MODE_B ||
734*4882a593Smuzhiyun wirelessmode == WIRELESS_MODE_G ||
735*4882a593Smuzhiyun wirelessmode == WIRELESS_MODE_N_24G ||
736*4882a593Smuzhiyun wirelessmode == WIRELESS_MODE_AC_24G)
737*4882a593Smuzhiyun ret = RATEID_IDX_BG;
738*4882a593Smuzhiyun else
739*4882a593Smuzhiyun ret = RATEID_IDX_G;
740*4882a593Smuzhiyun break;
741*4882a593Smuzhiyun case RATR_INX_WIRELESS_AC_5N:
742*4882a593Smuzhiyun if (rtlphy->rf_type == RF_1T1R)
743*4882a593Smuzhiyun ret = RATEID_IDX_VHT_1SS;
744*4882a593Smuzhiyun else
745*4882a593Smuzhiyun ret = RATEID_IDX_VHT_2SS;
746*4882a593Smuzhiyun break;
747*4882a593Smuzhiyun case RATR_INX_WIRELESS_AC_24N:
748*4882a593Smuzhiyun if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_80) {
749*4882a593Smuzhiyun if (rtlphy->rf_type == RF_1T1R)
750*4882a593Smuzhiyun ret = RATEID_IDX_VHT_1SS;
751*4882a593Smuzhiyun else
752*4882a593Smuzhiyun ret = RATEID_IDX_VHT_2SS;
753*4882a593Smuzhiyun } else {
754*4882a593Smuzhiyun if (rtlphy->rf_type == RF_1T1R)
755*4882a593Smuzhiyun ret = RATEID_IDX_MIX1;
756*4882a593Smuzhiyun else
757*4882a593Smuzhiyun ret = RATEID_IDX_MIX2;
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun break;
760*4882a593Smuzhiyun default:
761*4882a593Smuzhiyun ret = RATEID_IDX_BGN_40M_2SS;
762*4882a593Smuzhiyun break;
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun return ret;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun EXPORT_SYMBOL(rtl_mrate_idx_to_arfr_id);
767*4882a593Smuzhiyun
_rtl_txrate_selectmode(struct ieee80211_hw * hw,struct ieee80211_sta * sta,struct rtl_tcb_desc * tcb_desc)768*4882a593Smuzhiyun static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
769*4882a593Smuzhiyun struct ieee80211_sta *sta,
770*4882a593Smuzhiyun struct rtl_tcb_desc *tcb_desc)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun #define SET_RATE_ID(rate_id) \
773*4882a593Smuzhiyun ({typeof(rate_id) _id = rate_id; \
774*4882a593Smuzhiyun ((rtlpriv->cfg->spec_ver & RTL_SPEC_NEW_RATEID) ? \
775*4882a593Smuzhiyun rtl_mrate_idx_to_arfr_id(hw, _id, \
776*4882a593Smuzhiyun (sta_entry ? sta_entry->wireless_mode : \
777*4882a593Smuzhiyun WIRELESS_MODE_G)) : \
778*4882a593Smuzhiyun _id); })
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
781*4882a593Smuzhiyun struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
782*4882a593Smuzhiyun struct rtl_sta_info *sta_entry = NULL;
783*4882a593Smuzhiyun u8 ratr_index = SET_RATE_ID(RATR_INX_WIRELESS_MC);
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun if (sta) {
786*4882a593Smuzhiyun sta_entry = (struct rtl_sta_info *) sta->drv_priv;
787*4882a593Smuzhiyun ratr_index = sta_entry->ratr_index;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) {
790*4882a593Smuzhiyun if (mac->opmode == NL80211_IFTYPE_STATION) {
791*4882a593Smuzhiyun tcb_desc->ratr_index = 0;
792*4882a593Smuzhiyun } else if (mac->opmode == NL80211_IFTYPE_ADHOC ||
793*4882a593Smuzhiyun mac->opmode == NL80211_IFTYPE_MESH_POINT) {
794*4882a593Smuzhiyun if (tcb_desc->multicast || tcb_desc->broadcast) {
795*4882a593Smuzhiyun tcb_desc->hw_rate =
796*4882a593Smuzhiyun rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
797*4882a593Smuzhiyun tcb_desc->use_driver_rate = 1;
798*4882a593Smuzhiyun tcb_desc->ratr_index =
799*4882a593Smuzhiyun SET_RATE_ID(RATR_INX_WIRELESS_MC);
800*4882a593Smuzhiyun } else {
801*4882a593Smuzhiyun tcb_desc->ratr_index = ratr_index;
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun } else if (mac->opmode == NL80211_IFTYPE_AP) {
804*4882a593Smuzhiyun tcb_desc->ratr_index = ratr_index;
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun if (rtlpriv->dm.useramask) {
809*4882a593Smuzhiyun tcb_desc->ratr_index = ratr_index;
810*4882a593Smuzhiyun /* TODO we will differentiate adhoc and station future */
811*4882a593Smuzhiyun if (mac->opmode == NL80211_IFTYPE_STATION ||
812*4882a593Smuzhiyun mac->opmode == NL80211_IFTYPE_MESH_POINT) {
813*4882a593Smuzhiyun tcb_desc->mac_id = 0;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun if (sta &&
816*4882a593Smuzhiyun (rtlpriv->cfg->spec_ver & RTL_SPEC_NEW_RATEID))
817*4882a593Smuzhiyun ; /* use sta_entry->ratr_index */
818*4882a593Smuzhiyun else if (mac->mode == WIRELESS_MODE_AC_5G)
819*4882a593Smuzhiyun tcb_desc->ratr_index =
820*4882a593Smuzhiyun SET_RATE_ID(RATR_INX_WIRELESS_AC_5N);
821*4882a593Smuzhiyun else if (mac->mode == WIRELESS_MODE_AC_24G)
822*4882a593Smuzhiyun tcb_desc->ratr_index =
823*4882a593Smuzhiyun SET_RATE_ID(RATR_INX_WIRELESS_AC_24N);
824*4882a593Smuzhiyun else if (mac->mode == WIRELESS_MODE_N_24G)
825*4882a593Smuzhiyun tcb_desc->ratr_index =
826*4882a593Smuzhiyun SET_RATE_ID(RATR_INX_WIRELESS_NGB);
827*4882a593Smuzhiyun else if (mac->mode == WIRELESS_MODE_N_5G)
828*4882a593Smuzhiyun tcb_desc->ratr_index =
829*4882a593Smuzhiyun SET_RATE_ID(RATR_INX_WIRELESS_NG);
830*4882a593Smuzhiyun else if (mac->mode & WIRELESS_MODE_G)
831*4882a593Smuzhiyun tcb_desc->ratr_index =
832*4882a593Smuzhiyun SET_RATE_ID(RATR_INX_WIRELESS_GB);
833*4882a593Smuzhiyun else if (mac->mode & WIRELESS_MODE_B)
834*4882a593Smuzhiyun tcb_desc->ratr_index =
835*4882a593Smuzhiyun SET_RATE_ID(RATR_INX_WIRELESS_B);
836*4882a593Smuzhiyun else if (mac->mode & WIRELESS_MODE_A)
837*4882a593Smuzhiyun tcb_desc->ratr_index =
838*4882a593Smuzhiyun SET_RATE_ID(RATR_INX_WIRELESS_G);
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun } else if (mac->opmode == NL80211_IFTYPE_AP ||
841*4882a593Smuzhiyun mac->opmode == NL80211_IFTYPE_ADHOC) {
842*4882a593Smuzhiyun if (NULL != sta) {
843*4882a593Smuzhiyun if (sta->aid > 0)
844*4882a593Smuzhiyun tcb_desc->mac_id = sta->aid + 1;
845*4882a593Smuzhiyun else
846*4882a593Smuzhiyun tcb_desc->mac_id = 1;
847*4882a593Smuzhiyun } else {
848*4882a593Smuzhiyun tcb_desc->mac_id = 0;
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun #undef SET_RATE_ID
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun
_rtl_query_bandwidth_mode(struct ieee80211_hw * hw,struct ieee80211_sta * sta,struct rtl_tcb_desc * tcb_desc)855*4882a593Smuzhiyun static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
856*4882a593Smuzhiyun struct ieee80211_sta *sta,
857*4882a593Smuzhiyun struct rtl_tcb_desc *tcb_desc)
858*4882a593Smuzhiyun {
859*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
860*4882a593Smuzhiyun struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun tcb_desc->packet_bw = false;
863*4882a593Smuzhiyun if (!sta)
864*4882a593Smuzhiyun return;
865*4882a593Smuzhiyun if (mac->opmode == NL80211_IFTYPE_AP ||
866*4882a593Smuzhiyun mac->opmode == NL80211_IFTYPE_ADHOC ||
867*4882a593Smuzhiyun mac->opmode == NL80211_IFTYPE_MESH_POINT) {
868*4882a593Smuzhiyun if (!(sta->ht_cap.ht_supported) ||
869*4882a593Smuzhiyun !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
870*4882a593Smuzhiyun return;
871*4882a593Smuzhiyun } else if (mac->opmode == NL80211_IFTYPE_STATION) {
872*4882a593Smuzhiyun if (!mac->bw_40 || !(sta->ht_cap.ht_supported))
873*4882a593Smuzhiyun return;
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun if (tcb_desc->multicast || tcb_desc->broadcast)
876*4882a593Smuzhiyun return;
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun /*use legency rate, shall use 20MHz */
879*4882a593Smuzhiyun if (tcb_desc->hw_rate <= rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M])
880*4882a593Smuzhiyun return;
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun tcb_desc->packet_bw = HT_CHANNEL_WIDTH_20_40;
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun if (rtlpriv->cfg->spec_ver & RTL_SPEC_SUPPORT_VHT) {
885*4882a593Smuzhiyun if (mac->opmode == NL80211_IFTYPE_AP ||
886*4882a593Smuzhiyun mac->opmode == NL80211_IFTYPE_ADHOC ||
887*4882a593Smuzhiyun mac->opmode == NL80211_IFTYPE_MESH_POINT) {
888*4882a593Smuzhiyun if (!(sta->vht_cap.vht_supported))
889*4882a593Smuzhiyun return;
890*4882a593Smuzhiyun } else if (mac->opmode == NL80211_IFTYPE_STATION) {
891*4882a593Smuzhiyun if (!mac->bw_80 ||
892*4882a593Smuzhiyun !(sta->vht_cap.vht_supported))
893*4882a593Smuzhiyun return;
894*4882a593Smuzhiyun }
895*4882a593Smuzhiyun if (tcb_desc->hw_rate <=
896*4882a593Smuzhiyun rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15])
897*4882a593Smuzhiyun return;
898*4882a593Smuzhiyun tcb_desc->packet_bw = HT_CHANNEL_WIDTH_80;
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun
_rtl_get_vht_highest_n_rate(struct ieee80211_hw * hw,struct ieee80211_sta * sta)902*4882a593Smuzhiyun static u8 _rtl_get_vht_highest_n_rate(struct ieee80211_hw *hw,
903*4882a593Smuzhiyun struct ieee80211_sta *sta)
904*4882a593Smuzhiyun {
905*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
906*4882a593Smuzhiyun struct rtl_phy *rtlphy = &(rtlpriv->phy);
907*4882a593Smuzhiyun u8 hw_rate;
908*4882a593Smuzhiyun u16 tx_mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.tx_mcs_map);
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun if ((get_rf_type(rtlphy) == RF_2T2R) &&
911*4882a593Smuzhiyun (tx_mcs_map & 0x000c) != 0x000c) {
912*4882a593Smuzhiyun if ((tx_mcs_map & 0x000c) >> 2 ==
913*4882a593Smuzhiyun IEEE80211_VHT_MCS_SUPPORT_0_7)
914*4882a593Smuzhiyun hw_rate =
915*4882a593Smuzhiyun rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS7];
916*4882a593Smuzhiyun else if ((tx_mcs_map & 0x000c) >> 2 ==
917*4882a593Smuzhiyun IEEE80211_VHT_MCS_SUPPORT_0_8)
918*4882a593Smuzhiyun hw_rate =
919*4882a593Smuzhiyun rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS8];
920*4882a593Smuzhiyun else
921*4882a593Smuzhiyun hw_rate =
922*4882a593Smuzhiyun rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9];
923*4882a593Smuzhiyun } else {
924*4882a593Smuzhiyun if ((tx_mcs_map & 0x0003) ==
925*4882a593Smuzhiyun IEEE80211_VHT_MCS_SUPPORT_0_7)
926*4882a593Smuzhiyun hw_rate =
927*4882a593Smuzhiyun rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS7];
928*4882a593Smuzhiyun else if ((tx_mcs_map & 0x0003) ==
929*4882a593Smuzhiyun IEEE80211_VHT_MCS_SUPPORT_0_8)
930*4882a593Smuzhiyun hw_rate =
931*4882a593Smuzhiyun rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS8];
932*4882a593Smuzhiyun else
933*4882a593Smuzhiyun hw_rate =
934*4882a593Smuzhiyun rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9];
935*4882a593Smuzhiyun }
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun return hw_rate;
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun
_rtl_get_highest_n_rate(struct ieee80211_hw * hw,struct ieee80211_sta * sta)940*4882a593Smuzhiyun static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw,
941*4882a593Smuzhiyun struct ieee80211_sta *sta)
942*4882a593Smuzhiyun {
943*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
944*4882a593Smuzhiyun struct rtl_phy *rtlphy = &rtlpriv->phy;
945*4882a593Smuzhiyun u8 hw_rate;
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun if (get_rf_type(rtlphy) == RF_2T2R &&
948*4882a593Smuzhiyun sta->ht_cap.mcs.rx_mask[1] != 0)
949*4882a593Smuzhiyun hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15];
950*4882a593Smuzhiyun else
951*4882a593Smuzhiyun hw_rate = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS7];
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun return hw_rate;
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun /* mac80211's rate_idx is like this:
957*4882a593Smuzhiyun *
958*4882a593Smuzhiyun * 2.4G band:rx_status->band == NL80211_BAND_2GHZ
959*4882a593Smuzhiyun *
960*4882a593Smuzhiyun * B/G rate:
961*4882a593Smuzhiyun * (rx_status->flag & RX_FLAG_HT) = 0,
962*4882a593Smuzhiyun * DESC_RATE1M-->DESC_RATE54M ==> idx is 0-->11,
963*4882a593Smuzhiyun *
964*4882a593Smuzhiyun * N rate:
965*4882a593Smuzhiyun * (rx_status->flag & RX_FLAG_HT) = 1,
966*4882a593Smuzhiyun * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15
967*4882a593Smuzhiyun *
968*4882a593Smuzhiyun * 5G band:rx_status->band == NL80211_BAND_5GHZ
969*4882a593Smuzhiyun * A rate:
970*4882a593Smuzhiyun * (rx_status->flag & RX_FLAG_HT) = 0,
971*4882a593Smuzhiyun * DESC_RATE6M-->DESC_RATE54M ==> idx is 0-->7,
972*4882a593Smuzhiyun *
973*4882a593Smuzhiyun * N rate:
974*4882a593Smuzhiyun * (rx_status->flag & RX_FLAG_HT) = 1,
975*4882a593Smuzhiyun * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15
976*4882a593Smuzhiyun *
977*4882a593Smuzhiyun * VHT rates:
978*4882a593Smuzhiyun * DESC_RATEVHT1SS_MCS0-->DESC_RATEVHT1SS_MCS9 ==> idx is 0-->9
979*4882a593Smuzhiyun * DESC_RATEVHT2SS_MCS0-->DESC_RATEVHT2SS_MCS9 ==> idx is 0-->9
980*4882a593Smuzhiyun */
rtlwifi_rate_mapping(struct ieee80211_hw * hw,bool isht,bool isvht,u8 desc_rate)981*4882a593Smuzhiyun int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, bool isvht,
982*4882a593Smuzhiyun u8 desc_rate)
983*4882a593Smuzhiyun {
984*4882a593Smuzhiyun int rate_idx;
985*4882a593Smuzhiyun
986*4882a593Smuzhiyun if (isvht) {
987*4882a593Smuzhiyun switch (desc_rate) {
988*4882a593Smuzhiyun case DESC_RATEVHT1SS_MCS0:
989*4882a593Smuzhiyun rate_idx = 0;
990*4882a593Smuzhiyun break;
991*4882a593Smuzhiyun case DESC_RATEVHT1SS_MCS1:
992*4882a593Smuzhiyun rate_idx = 1;
993*4882a593Smuzhiyun break;
994*4882a593Smuzhiyun case DESC_RATEVHT1SS_MCS2:
995*4882a593Smuzhiyun rate_idx = 2;
996*4882a593Smuzhiyun break;
997*4882a593Smuzhiyun case DESC_RATEVHT1SS_MCS3:
998*4882a593Smuzhiyun rate_idx = 3;
999*4882a593Smuzhiyun break;
1000*4882a593Smuzhiyun case DESC_RATEVHT1SS_MCS4:
1001*4882a593Smuzhiyun rate_idx = 4;
1002*4882a593Smuzhiyun break;
1003*4882a593Smuzhiyun case DESC_RATEVHT1SS_MCS5:
1004*4882a593Smuzhiyun rate_idx = 5;
1005*4882a593Smuzhiyun break;
1006*4882a593Smuzhiyun case DESC_RATEVHT1SS_MCS6:
1007*4882a593Smuzhiyun rate_idx = 6;
1008*4882a593Smuzhiyun break;
1009*4882a593Smuzhiyun case DESC_RATEVHT1SS_MCS7:
1010*4882a593Smuzhiyun rate_idx = 7;
1011*4882a593Smuzhiyun break;
1012*4882a593Smuzhiyun case DESC_RATEVHT1SS_MCS8:
1013*4882a593Smuzhiyun rate_idx = 8;
1014*4882a593Smuzhiyun break;
1015*4882a593Smuzhiyun case DESC_RATEVHT1SS_MCS9:
1016*4882a593Smuzhiyun rate_idx = 9;
1017*4882a593Smuzhiyun break;
1018*4882a593Smuzhiyun case DESC_RATEVHT2SS_MCS0:
1019*4882a593Smuzhiyun rate_idx = 0;
1020*4882a593Smuzhiyun break;
1021*4882a593Smuzhiyun case DESC_RATEVHT2SS_MCS1:
1022*4882a593Smuzhiyun rate_idx = 1;
1023*4882a593Smuzhiyun break;
1024*4882a593Smuzhiyun case DESC_RATEVHT2SS_MCS2:
1025*4882a593Smuzhiyun rate_idx = 2;
1026*4882a593Smuzhiyun break;
1027*4882a593Smuzhiyun case DESC_RATEVHT2SS_MCS3:
1028*4882a593Smuzhiyun rate_idx = 3;
1029*4882a593Smuzhiyun break;
1030*4882a593Smuzhiyun case DESC_RATEVHT2SS_MCS4:
1031*4882a593Smuzhiyun rate_idx = 4;
1032*4882a593Smuzhiyun break;
1033*4882a593Smuzhiyun case DESC_RATEVHT2SS_MCS5:
1034*4882a593Smuzhiyun rate_idx = 5;
1035*4882a593Smuzhiyun break;
1036*4882a593Smuzhiyun case DESC_RATEVHT2SS_MCS6:
1037*4882a593Smuzhiyun rate_idx = 6;
1038*4882a593Smuzhiyun break;
1039*4882a593Smuzhiyun case DESC_RATEVHT2SS_MCS7:
1040*4882a593Smuzhiyun rate_idx = 7;
1041*4882a593Smuzhiyun break;
1042*4882a593Smuzhiyun case DESC_RATEVHT2SS_MCS8:
1043*4882a593Smuzhiyun rate_idx = 8;
1044*4882a593Smuzhiyun break;
1045*4882a593Smuzhiyun case DESC_RATEVHT2SS_MCS9:
1046*4882a593Smuzhiyun rate_idx = 9;
1047*4882a593Smuzhiyun break;
1048*4882a593Smuzhiyun default:
1049*4882a593Smuzhiyun rate_idx = 0;
1050*4882a593Smuzhiyun break;
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun return rate_idx;
1053*4882a593Smuzhiyun }
1054*4882a593Smuzhiyun if (false == isht) {
1055*4882a593Smuzhiyun if (NL80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
1056*4882a593Smuzhiyun switch (desc_rate) {
1057*4882a593Smuzhiyun case DESC_RATE1M:
1058*4882a593Smuzhiyun rate_idx = 0;
1059*4882a593Smuzhiyun break;
1060*4882a593Smuzhiyun case DESC_RATE2M:
1061*4882a593Smuzhiyun rate_idx = 1;
1062*4882a593Smuzhiyun break;
1063*4882a593Smuzhiyun case DESC_RATE5_5M:
1064*4882a593Smuzhiyun rate_idx = 2;
1065*4882a593Smuzhiyun break;
1066*4882a593Smuzhiyun case DESC_RATE11M:
1067*4882a593Smuzhiyun rate_idx = 3;
1068*4882a593Smuzhiyun break;
1069*4882a593Smuzhiyun case DESC_RATE6M:
1070*4882a593Smuzhiyun rate_idx = 4;
1071*4882a593Smuzhiyun break;
1072*4882a593Smuzhiyun case DESC_RATE9M:
1073*4882a593Smuzhiyun rate_idx = 5;
1074*4882a593Smuzhiyun break;
1075*4882a593Smuzhiyun case DESC_RATE12M:
1076*4882a593Smuzhiyun rate_idx = 6;
1077*4882a593Smuzhiyun break;
1078*4882a593Smuzhiyun case DESC_RATE18M:
1079*4882a593Smuzhiyun rate_idx = 7;
1080*4882a593Smuzhiyun break;
1081*4882a593Smuzhiyun case DESC_RATE24M:
1082*4882a593Smuzhiyun rate_idx = 8;
1083*4882a593Smuzhiyun break;
1084*4882a593Smuzhiyun case DESC_RATE36M:
1085*4882a593Smuzhiyun rate_idx = 9;
1086*4882a593Smuzhiyun break;
1087*4882a593Smuzhiyun case DESC_RATE48M:
1088*4882a593Smuzhiyun rate_idx = 10;
1089*4882a593Smuzhiyun break;
1090*4882a593Smuzhiyun case DESC_RATE54M:
1091*4882a593Smuzhiyun rate_idx = 11;
1092*4882a593Smuzhiyun break;
1093*4882a593Smuzhiyun default:
1094*4882a593Smuzhiyun rate_idx = 0;
1095*4882a593Smuzhiyun break;
1096*4882a593Smuzhiyun }
1097*4882a593Smuzhiyun } else {
1098*4882a593Smuzhiyun switch (desc_rate) {
1099*4882a593Smuzhiyun case DESC_RATE6M:
1100*4882a593Smuzhiyun rate_idx = 0;
1101*4882a593Smuzhiyun break;
1102*4882a593Smuzhiyun case DESC_RATE9M:
1103*4882a593Smuzhiyun rate_idx = 1;
1104*4882a593Smuzhiyun break;
1105*4882a593Smuzhiyun case DESC_RATE12M:
1106*4882a593Smuzhiyun rate_idx = 2;
1107*4882a593Smuzhiyun break;
1108*4882a593Smuzhiyun case DESC_RATE18M:
1109*4882a593Smuzhiyun rate_idx = 3;
1110*4882a593Smuzhiyun break;
1111*4882a593Smuzhiyun case DESC_RATE24M:
1112*4882a593Smuzhiyun rate_idx = 4;
1113*4882a593Smuzhiyun break;
1114*4882a593Smuzhiyun case DESC_RATE36M:
1115*4882a593Smuzhiyun rate_idx = 5;
1116*4882a593Smuzhiyun break;
1117*4882a593Smuzhiyun case DESC_RATE48M:
1118*4882a593Smuzhiyun rate_idx = 6;
1119*4882a593Smuzhiyun break;
1120*4882a593Smuzhiyun case DESC_RATE54M:
1121*4882a593Smuzhiyun rate_idx = 7;
1122*4882a593Smuzhiyun break;
1123*4882a593Smuzhiyun default:
1124*4882a593Smuzhiyun rate_idx = 0;
1125*4882a593Smuzhiyun break;
1126*4882a593Smuzhiyun }
1127*4882a593Smuzhiyun }
1128*4882a593Smuzhiyun } else {
1129*4882a593Smuzhiyun switch (desc_rate) {
1130*4882a593Smuzhiyun case DESC_RATEMCS0:
1131*4882a593Smuzhiyun rate_idx = 0;
1132*4882a593Smuzhiyun break;
1133*4882a593Smuzhiyun case DESC_RATEMCS1:
1134*4882a593Smuzhiyun rate_idx = 1;
1135*4882a593Smuzhiyun break;
1136*4882a593Smuzhiyun case DESC_RATEMCS2:
1137*4882a593Smuzhiyun rate_idx = 2;
1138*4882a593Smuzhiyun break;
1139*4882a593Smuzhiyun case DESC_RATEMCS3:
1140*4882a593Smuzhiyun rate_idx = 3;
1141*4882a593Smuzhiyun break;
1142*4882a593Smuzhiyun case DESC_RATEMCS4:
1143*4882a593Smuzhiyun rate_idx = 4;
1144*4882a593Smuzhiyun break;
1145*4882a593Smuzhiyun case DESC_RATEMCS5:
1146*4882a593Smuzhiyun rate_idx = 5;
1147*4882a593Smuzhiyun break;
1148*4882a593Smuzhiyun case DESC_RATEMCS6:
1149*4882a593Smuzhiyun rate_idx = 6;
1150*4882a593Smuzhiyun break;
1151*4882a593Smuzhiyun case DESC_RATEMCS7:
1152*4882a593Smuzhiyun rate_idx = 7;
1153*4882a593Smuzhiyun break;
1154*4882a593Smuzhiyun case DESC_RATEMCS8:
1155*4882a593Smuzhiyun rate_idx = 8;
1156*4882a593Smuzhiyun break;
1157*4882a593Smuzhiyun case DESC_RATEMCS9:
1158*4882a593Smuzhiyun rate_idx = 9;
1159*4882a593Smuzhiyun break;
1160*4882a593Smuzhiyun case DESC_RATEMCS10:
1161*4882a593Smuzhiyun rate_idx = 10;
1162*4882a593Smuzhiyun break;
1163*4882a593Smuzhiyun case DESC_RATEMCS11:
1164*4882a593Smuzhiyun rate_idx = 11;
1165*4882a593Smuzhiyun break;
1166*4882a593Smuzhiyun case DESC_RATEMCS12:
1167*4882a593Smuzhiyun rate_idx = 12;
1168*4882a593Smuzhiyun break;
1169*4882a593Smuzhiyun case DESC_RATEMCS13:
1170*4882a593Smuzhiyun rate_idx = 13;
1171*4882a593Smuzhiyun break;
1172*4882a593Smuzhiyun case DESC_RATEMCS14:
1173*4882a593Smuzhiyun rate_idx = 14;
1174*4882a593Smuzhiyun break;
1175*4882a593Smuzhiyun case DESC_RATEMCS15:
1176*4882a593Smuzhiyun rate_idx = 15;
1177*4882a593Smuzhiyun break;
1178*4882a593Smuzhiyun default:
1179*4882a593Smuzhiyun rate_idx = 0;
1180*4882a593Smuzhiyun break;
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun }
1183*4882a593Smuzhiyun return rate_idx;
1184*4882a593Smuzhiyun }
1185*4882a593Smuzhiyun EXPORT_SYMBOL(rtlwifi_rate_mapping);
1186*4882a593Smuzhiyun
_rtl_get_tx_hw_rate(struct ieee80211_hw * hw,struct ieee80211_tx_info * info)1187*4882a593Smuzhiyun static u8 _rtl_get_tx_hw_rate(struct ieee80211_hw *hw,
1188*4882a593Smuzhiyun struct ieee80211_tx_info *info)
1189*4882a593Smuzhiyun {
1190*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1191*4882a593Smuzhiyun struct ieee80211_tx_rate *r = &info->status.rates[0];
1192*4882a593Smuzhiyun struct ieee80211_rate *txrate;
1193*4882a593Smuzhiyun u8 hw_value = 0x0;
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun if (r->flags & IEEE80211_TX_RC_MCS) {
1196*4882a593Smuzhiyun /* HT MCS0-15 */
1197*4882a593Smuzhiyun hw_value = rtlpriv->cfg->maps[RTL_RC_HT_RATEMCS15] - 15 +
1198*4882a593Smuzhiyun r->idx;
1199*4882a593Smuzhiyun } else if (r->flags & IEEE80211_TX_RC_VHT_MCS) {
1200*4882a593Smuzhiyun /* VHT MCS0-9, NSS */
1201*4882a593Smuzhiyun if (ieee80211_rate_get_vht_nss(r) == 2)
1202*4882a593Smuzhiyun hw_value = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_2SS_MCS9];
1203*4882a593Smuzhiyun else
1204*4882a593Smuzhiyun hw_value = rtlpriv->cfg->maps[RTL_RC_VHT_RATE_1SS_MCS9];
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun hw_value = hw_value - 9 + ieee80211_rate_get_vht_mcs(r);
1207*4882a593Smuzhiyun } else {
1208*4882a593Smuzhiyun /* legacy */
1209*4882a593Smuzhiyun txrate = ieee80211_get_tx_rate(hw, info);
1210*4882a593Smuzhiyun
1211*4882a593Smuzhiyun if (txrate)
1212*4882a593Smuzhiyun hw_value = txrate->hw_value;
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun /* check 5G band */
1216*4882a593Smuzhiyun if (rtlpriv->rtlhal.current_bandtype == BAND_ON_5G &&
1217*4882a593Smuzhiyun hw_value < rtlpriv->cfg->maps[RTL_RC_OFDM_RATE6M])
1218*4882a593Smuzhiyun hw_value = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE6M];
1219*4882a593Smuzhiyun
1220*4882a593Smuzhiyun return hw_value;
1221*4882a593Smuzhiyun }
1222*4882a593Smuzhiyun
rtl_get_tcb_desc(struct ieee80211_hw * hw,struct ieee80211_tx_info * info,struct ieee80211_sta * sta,struct sk_buff * skb,struct rtl_tcb_desc * tcb_desc)1223*4882a593Smuzhiyun void rtl_get_tcb_desc(struct ieee80211_hw *hw,
1224*4882a593Smuzhiyun struct ieee80211_tx_info *info,
1225*4882a593Smuzhiyun struct ieee80211_sta *sta,
1226*4882a593Smuzhiyun struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc)
1227*4882a593Smuzhiyun {
1228*4882a593Smuzhiyun #define SET_RATE_ID(rate_id) \
1229*4882a593Smuzhiyun ({typeof(rate_id) _id = rate_id; \
1230*4882a593Smuzhiyun ((rtlpriv->cfg->spec_ver & RTL_SPEC_NEW_RATEID) ? \
1231*4882a593Smuzhiyun rtl_mrate_idx_to_arfr_id(hw, _id, \
1232*4882a593Smuzhiyun (sta_entry ? sta_entry->wireless_mode : \
1233*4882a593Smuzhiyun WIRELESS_MODE_G)) : \
1234*4882a593Smuzhiyun _id); })
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1237*4882a593Smuzhiyun struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
1238*4882a593Smuzhiyun struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
1239*4882a593Smuzhiyun struct rtl_sta_info *sta_entry =
1240*4882a593Smuzhiyun (sta ? (struct rtl_sta_info *)sta->drv_priv : NULL);
1241*4882a593Smuzhiyun
1242*4882a593Smuzhiyun __le16 fc = rtl_get_fc(skb);
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun tcb_desc->hw_rate = _rtl_get_tx_hw_rate(hw, info);
1245*4882a593Smuzhiyun
1246*4882a593Smuzhiyun if (rtl_is_tx_report_skb(hw, skb))
1247*4882a593Smuzhiyun tcb_desc->use_spe_rpt = 1;
1248*4882a593Smuzhiyun
1249*4882a593Smuzhiyun if (ieee80211_is_data(fc)) {
1250*4882a593Smuzhiyun /*
1251*4882a593Smuzhiyun *we set data rate INX 0
1252*4882a593Smuzhiyun *in rtl_rc.c if skb is special data or
1253*4882a593Smuzhiyun *mgt which need low data rate.
1254*4882a593Smuzhiyun */
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun /*
1257*4882a593Smuzhiyun *So tcb_desc->hw_rate is just used for
1258*4882a593Smuzhiyun *special data and mgt frames
1259*4882a593Smuzhiyun */
1260*4882a593Smuzhiyun if (info->control.rates[0].idx == 0 ||
1261*4882a593Smuzhiyun ieee80211_is_nullfunc(fc)) {
1262*4882a593Smuzhiyun tcb_desc->use_driver_rate = true;
1263*4882a593Smuzhiyun tcb_desc->ratr_index =
1264*4882a593Smuzhiyun SET_RATE_ID(RATR_INX_WIRELESS_MC);
1265*4882a593Smuzhiyun
1266*4882a593Smuzhiyun tcb_desc->disable_ratefallback = 1;
1267*4882a593Smuzhiyun } else {
1268*4882a593Smuzhiyun /*
1269*4882a593Smuzhiyun *because hw will nerver use hw_rate
1270*4882a593Smuzhiyun *when tcb_desc->use_driver_rate = false
1271*4882a593Smuzhiyun *so we never set highest N rate here,
1272*4882a593Smuzhiyun *and N rate will all be controlled by FW
1273*4882a593Smuzhiyun *when tcb_desc->use_driver_rate = false
1274*4882a593Smuzhiyun */
1275*4882a593Smuzhiyun if (sta && sta->vht_cap.vht_supported) {
1276*4882a593Smuzhiyun tcb_desc->hw_rate =
1277*4882a593Smuzhiyun _rtl_get_vht_highest_n_rate(hw, sta);
1278*4882a593Smuzhiyun } else {
1279*4882a593Smuzhiyun if (sta && sta->ht_cap.ht_supported) {
1280*4882a593Smuzhiyun tcb_desc->hw_rate =
1281*4882a593Smuzhiyun _rtl_get_highest_n_rate(hw, sta);
1282*4882a593Smuzhiyun } else {
1283*4882a593Smuzhiyun if (rtlmac->mode == WIRELESS_MODE_B) {
1284*4882a593Smuzhiyun tcb_desc->hw_rate =
1285*4882a593Smuzhiyun rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M];
1286*4882a593Smuzhiyun } else {
1287*4882a593Smuzhiyun tcb_desc->hw_rate =
1288*4882a593Smuzhiyun rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M];
1289*4882a593Smuzhiyun }
1290*4882a593Smuzhiyun }
1291*4882a593Smuzhiyun }
1292*4882a593Smuzhiyun }
1293*4882a593Smuzhiyun
1294*4882a593Smuzhiyun if (is_multicast_ether_addr(hdr->addr1))
1295*4882a593Smuzhiyun tcb_desc->multicast = 1;
1296*4882a593Smuzhiyun else if (is_broadcast_ether_addr(hdr->addr1))
1297*4882a593Smuzhiyun tcb_desc->broadcast = 1;
1298*4882a593Smuzhiyun
1299*4882a593Smuzhiyun _rtl_txrate_selectmode(hw, sta, tcb_desc);
1300*4882a593Smuzhiyun _rtl_query_bandwidth_mode(hw, sta, tcb_desc);
1301*4882a593Smuzhiyun _rtl_qurey_shortpreamble_mode(hw, tcb_desc, info);
1302*4882a593Smuzhiyun _rtl_query_shortgi(hw, sta, tcb_desc, info);
1303*4882a593Smuzhiyun _rtl_query_protection_mode(hw, tcb_desc, info);
1304*4882a593Smuzhiyun } else {
1305*4882a593Smuzhiyun tcb_desc->use_driver_rate = true;
1306*4882a593Smuzhiyun tcb_desc->ratr_index = SET_RATE_ID(RATR_INX_WIRELESS_MC);
1307*4882a593Smuzhiyun tcb_desc->disable_ratefallback = 1;
1308*4882a593Smuzhiyun tcb_desc->mac_id = 0;
1309*4882a593Smuzhiyun tcb_desc->packet_bw = false;
1310*4882a593Smuzhiyun }
1311*4882a593Smuzhiyun #undef SET_RATE_ID
1312*4882a593Smuzhiyun }
1313*4882a593Smuzhiyun EXPORT_SYMBOL(rtl_get_tcb_desc);
1314*4882a593Smuzhiyun
rtl_tx_mgmt_proc(struct ieee80211_hw * hw,struct sk_buff * skb)1315*4882a593Smuzhiyun bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
1316*4882a593Smuzhiyun {
1317*4882a593Smuzhiyun struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
1318*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1319*4882a593Smuzhiyun __le16 fc = rtl_get_fc(skb);
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun if (rtlpriv->dm.supp_phymode_switch &&
1322*4882a593Smuzhiyun mac->link_state < MAC80211_LINKED &&
1323*4882a593Smuzhiyun (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) {
1324*4882a593Smuzhiyun if (rtlpriv->cfg->ops->chk_switch_dmdp)
1325*4882a593Smuzhiyun rtlpriv->cfg->ops->chk_switch_dmdp(hw);
1326*4882a593Smuzhiyun }
1327*4882a593Smuzhiyun if (ieee80211_is_auth(fc)) {
1328*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n");
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun mac->link_state = MAC80211_LINKING;
1331*4882a593Smuzhiyun /* Dul mac */
1332*4882a593Smuzhiyun rtlpriv->phy.need_iqk = true;
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun return true;
1337*4882a593Smuzhiyun }
1338*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc);
1339*4882a593Smuzhiyun
1340*4882a593Smuzhiyun struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw, u8 *sa,
1341*4882a593Smuzhiyun u8 *bssid, u16 tid);
1342*4882a593Smuzhiyun
process_agg_start(struct ieee80211_hw * hw,struct ieee80211_hdr * hdr,u16 tid)1343*4882a593Smuzhiyun static void process_agg_start(struct ieee80211_hw *hw,
1344*4882a593Smuzhiyun struct ieee80211_hdr *hdr, u16 tid)
1345*4882a593Smuzhiyun {
1346*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1347*4882a593Smuzhiyun struct ieee80211_rx_status rx_status = { 0 };
1348*4882a593Smuzhiyun struct sk_buff *skb_delba = NULL;
1349*4882a593Smuzhiyun
1350*4882a593Smuzhiyun skb_delba = rtl_make_del_ba(hw, hdr->addr2, hdr->addr3, tid);
1351*4882a593Smuzhiyun if (skb_delba) {
1352*4882a593Smuzhiyun rx_status.freq = hw->conf.chandef.chan->center_freq;
1353*4882a593Smuzhiyun rx_status.band = hw->conf.chandef.chan->band;
1354*4882a593Smuzhiyun rx_status.flag |= RX_FLAG_DECRYPTED;
1355*4882a593Smuzhiyun rx_status.flag |= RX_FLAG_MACTIME_START;
1356*4882a593Smuzhiyun rx_status.rate_idx = 0;
1357*4882a593Smuzhiyun rx_status.signal = 50 + 10;
1358*4882a593Smuzhiyun memcpy(IEEE80211_SKB_RXCB(skb_delba),
1359*4882a593Smuzhiyun &rx_status, sizeof(rx_status));
1360*4882a593Smuzhiyun RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG,
1361*4882a593Smuzhiyun "fake del\n",
1362*4882a593Smuzhiyun skb_delba->data,
1363*4882a593Smuzhiyun skb_delba->len);
1364*4882a593Smuzhiyun ieee80211_rx_irqsafe(hw, skb_delba);
1365*4882a593Smuzhiyun }
1366*4882a593Smuzhiyun }
1367*4882a593Smuzhiyun
rtl_action_proc(struct ieee80211_hw * hw,struct sk_buff * skb,u8 is_tx)1368*4882a593Smuzhiyun bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
1369*4882a593Smuzhiyun {
1370*4882a593Smuzhiyun struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
1371*4882a593Smuzhiyun struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
1372*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1373*4882a593Smuzhiyun __le16 fc = rtl_get_fc(skb);
1374*4882a593Smuzhiyun u8 *act = (u8 *)(((u8 *)skb->data + MAC80211_3ADDR_LEN));
1375*4882a593Smuzhiyun u8 category;
1376*4882a593Smuzhiyun
1377*4882a593Smuzhiyun if (!ieee80211_is_action(fc))
1378*4882a593Smuzhiyun return true;
1379*4882a593Smuzhiyun
1380*4882a593Smuzhiyun category = *act;
1381*4882a593Smuzhiyun act++;
1382*4882a593Smuzhiyun switch (category) {
1383*4882a593Smuzhiyun case ACT_CAT_BA:
1384*4882a593Smuzhiyun switch (*act) {
1385*4882a593Smuzhiyun case ACT_ADDBAREQ:
1386*4882a593Smuzhiyun if (mac->act_scanning)
1387*4882a593Smuzhiyun return false;
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun rtl_dbg(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
1390*4882a593Smuzhiyun "%s ACT_ADDBAREQ From :%pM\n",
1391*4882a593Smuzhiyun is_tx ? "Tx" : "Rx", hdr->addr2);
1392*4882a593Smuzhiyun RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "req\n",
1393*4882a593Smuzhiyun skb->data, skb->len);
1394*4882a593Smuzhiyun if (!is_tx) {
1395*4882a593Smuzhiyun struct ieee80211_sta *sta = NULL;
1396*4882a593Smuzhiyun struct rtl_sta_info *sta_entry = NULL;
1397*4882a593Smuzhiyun struct rtl_tid_data *tid_data;
1398*4882a593Smuzhiyun struct ieee80211_mgmt *mgmt = (void *)skb->data;
1399*4882a593Smuzhiyun u16 capab = 0, tid = 0;
1400*4882a593Smuzhiyun
1401*4882a593Smuzhiyun rcu_read_lock();
1402*4882a593Smuzhiyun sta = rtl_find_sta(hw, hdr->addr3);
1403*4882a593Smuzhiyun if (sta == NULL) {
1404*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_SEND | COMP_RECV,
1405*4882a593Smuzhiyun DBG_DMESG, "sta is NULL\n");
1406*4882a593Smuzhiyun rcu_read_unlock();
1407*4882a593Smuzhiyun return true;
1408*4882a593Smuzhiyun }
1409*4882a593Smuzhiyun
1410*4882a593Smuzhiyun sta_entry =
1411*4882a593Smuzhiyun (struct rtl_sta_info *)sta->drv_priv;
1412*4882a593Smuzhiyun if (!sta_entry) {
1413*4882a593Smuzhiyun rcu_read_unlock();
1414*4882a593Smuzhiyun return true;
1415*4882a593Smuzhiyun }
1416*4882a593Smuzhiyun capab =
1417*4882a593Smuzhiyun le16_to_cpu(mgmt->u.action.u.addba_req.capab);
1418*4882a593Smuzhiyun tid = (capab &
1419*4882a593Smuzhiyun IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
1420*4882a593Smuzhiyun if (tid >= MAX_TID_COUNT) {
1421*4882a593Smuzhiyun rcu_read_unlock();
1422*4882a593Smuzhiyun return true;
1423*4882a593Smuzhiyun }
1424*4882a593Smuzhiyun tid_data = &sta_entry->tids[tid];
1425*4882a593Smuzhiyun if (tid_data->agg.rx_agg_state ==
1426*4882a593Smuzhiyun RTL_RX_AGG_START)
1427*4882a593Smuzhiyun process_agg_start(hw, hdr, tid);
1428*4882a593Smuzhiyun rcu_read_unlock();
1429*4882a593Smuzhiyun }
1430*4882a593Smuzhiyun break;
1431*4882a593Smuzhiyun case ACT_ADDBARSP:
1432*4882a593Smuzhiyun rtl_dbg(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
1433*4882a593Smuzhiyun "%s ACT_ADDBARSP From :%pM\n",
1434*4882a593Smuzhiyun is_tx ? "Tx" : "Rx", hdr->addr2);
1435*4882a593Smuzhiyun break;
1436*4882a593Smuzhiyun case ACT_DELBA:
1437*4882a593Smuzhiyun rtl_dbg(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
1438*4882a593Smuzhiyun "ACT_ADDBADEL From :%pM\n", hdr->addr2);
1439*4882a593Smuzhiyun break;
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun break;
1442*4882a593Smuzhiyun default:
1443*4882a593Smuzhiyun break;
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun return true;
1447*4882a593Smuzhiyun }
1448*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_action_proc);
1449*4882a593Smuzhiyun
setup_special_tx(struct rtl_priv * rtlpriv,struct rtl_ps_ctl * ppsc,int type)1450*4882a593Smuzhiyun static void setup_special_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc,
1451*4882a593Smuzhiyun int type)
1452*4882a593Smuzhiyun {
1453*4882a593Smuzhiyun struct ieee80211_hw *hw = rtlpriv->hw;
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun rtlpriv->ra.is_special_data = true;
1456*4882a593Smuzhiyun if (rtlpriv->cfg->ops->get_btc_status())
1457*4882a593Smuzhiyun rtlpriv->btcoexist.btc_ops->btc_special_packet_notify(
1458*4882a593Smuzhiyun rtlpriv, type);
1459*4882a593Smuzhiyun rtl_lps_leave(hw, false);
1460*4882a593Smuzhiyun ppsc->last_delaylps_stamp_jiffies = jiffies;
1461*4882a593Smuzhiyun }
1462*4882a593Smuzhiyun
rtl_skb_ether_type_ptr(struct ieee80211_hw * hw,struct sk_buff * skb,bool is_enc)1463*4882a593Smuzhiyun static const u8 *rtl_skb_ether_type_ptr(struct ieee80211_hw *hw,
1464*4882a593Smuzhiyun struct sk_buff *skb, bool is_enc)
1465*4882a593Smuzhiyun {
1466*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1467*4882a593Smuzhiyun u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1468*4882a593Smuzhiyun u8 encrypt_header_len = 0;
1469*4882a593Smuzhiyun u8 offset;
1470*4882a593Smuzhiyun
1471*4882a593Smuzhiyun switch (rtlpriv->sec.pairwise_enc_algorithm) {
1472*4882a593Smuzhiyun case WEP40_ENCRYPTION:
1473*4882a593Smuzhiyun case WEP104_ENCRYPTION:
1474*4882a593Smuzhiyun encrypt_header_len = 4;/*WEP_IV_LEN*/
1475*4882a593Smuzhiyun break;
1476*4882a593Smuzhiyun case TKIP_ENCRYPTION:
1477*4882a593Smuzhiyun encrypt_header_len = 8;/*TKIP_IV_LEN*/
1478*4882a593Smuzhiyun break;
1479*4882a593Smuzhiyun case AESCCMP_ENCRYPTION:
1480*4882a593Smuzhiyun encrypt_header_len = 8;/*CCMP_HDR_LEN;*/
1481*4882a593Smuzhiyun break;
1482*4882a593Smuzhiyun default:
1483*4882a593Smuzhiyun break;
1484*4882a593Smuzhiyun }
1485*4882a593Smuzhiyun
1486*4882a593Smuzhiyun offset = mac_hdr_len + SNAP_SIZE;
1487*4882a593Smuzhiyun if (is_enc)
1488*4882a593Smuzhiyun offset += encrypt_header_len;
1489*4882a593Smuzhiyun
1490*4882a593Smuzhiyun return skb->data + offset;
1491*4882a593Smuzhiyun }
1492*4882a593Smuzhiyun
1493*4882a593Smuzhiyun /*should call before software enc*/
rtl_is_special_data(struct ieee80211_hw * hw,struct sk_buff * skb,u8 is_tx,bool is_enc)1494*4882a593Smuzhiyun u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx,
1495*4882a593Smuzhiyun bool is_enc)
1496*4882a593Smuzhiyun {
1497*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1498*4882a593Smuzhiyun struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
1499*4882a593Smuzhiyun __le16 fc = rtl_get_fc(skb);
1500*4882a593Smuzhiyun u16 ether_type;
1501*4882a593Smuzhiyun const u8 *ether_type_ptr;
1502*4882a593Smuzhiyun const struct iphdr *ip;
1503*4882a593Smuzhiyun
1504*4882a593Smuzhiyun if (!ieee80211_is_data(fc))
1505*4882a593Smuzhiyun goto end;
1506*4882a593Smuzhiyun
1507*4882a593Smuzhiyun ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, is_enc);
1508*4882a593Smuzhiyun ether_type = be16_to_cpup((__be16 *)ether_type_ptr);
1509*4882a593Smuzhiyun
1510*4882a593Smuzhiyun if (ETH_P_IP == ether_type) {
1511*4882a593Smuzhiyun ip = (struct iphdr *)((u8 *)ether_type_ptr +
1512*4882a593Smuzhiyun PROTOC_TYPE_SIZE);
1513*4882a593Smuzhiyun if (IPPROTO_UDP == ip->protocol) {
1514*4882a593Smuzhiyun struct udphdr *udp = (struct udphdr *)((u8 *)ip +
1515*4882a593Smuzhiyun (ip->ihl << 2));
1516*4882a593Smuzhiyun if (((((u8 *)udp)[1] == 68) &&
1517*4882a593Smuzhiyun (((u8 *)udp)[3] == 67)) ||
1518*4882a593Smuzhiyun ((((u8 *)udp)[1] == 67) &&
1519*4882a593Smuzhiyun (((u8 *)udp)[3] == 68))) {
1520*4882a593Smuzhiyun /* 68 : UDP BOOTP client
1521*4882a593Smuzhiyun * 67 : UDP BOOTP server
1522*4882a593Smuzhiyun */
1523*4882a593Smuzhiyun rtl_dbg(rtlpriv, (COMP_SEND | COMP_RECV),
1524*4882a593Smuzhiyun DBG_DMESG, "dhcp %s !!\n",
1525*4882a593Smuzhiyun (is_tx) ? "Tx" : "Rx");
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun if (is_tx)
1528*4882a593Smuzhiyun setup_special_tx(rtlpriv, ppsc,
1529*4882a593Smuzhiyun PACKET_DHCP);
1530*4882a593Smuzhiyun
1531*4882a593Smuzhiyun return true;
1532*4882a593Smuzhiyun }
1533*4882a593Smuzhiyun }
1534*4882a593Smuzhiyun } else if (ETH_P_ARP == ether_type) {
1535*4882a593Smuzhiyun if (is_tx)
1536*4882a593Smuzhiyun setup_special_tx(rtlpriv, ppsc, PACKET_ARP);
1537*4882a593Smuzhiyun
1538*4882a593Smuzhiyun return true;
1539*4882a593Smuzhiyun } else if (ETH_P_PAE == ether_type) {
1540*4882a593Smuzhiyun /* EAPOL is seens as in-4way */
1541*4882a593Smuzhiyun rtlpriv->btcoexist.btc_info.in_4way = true;
1542*4882a593Smuzhiyun rtlpriv->btcoexist.btc_info.in_4way_ts = jiffies;
1543*4882a593Smuzhiyun
1544*4882a593Smuzhiyun rtl_dbg(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
1545*4882a593Smuzhiyun "802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx");
1546*4882a593Smuzhiyun
1547*4882a593Smuzhiyun if (is_tx) {
1548*4882a593Smuzhiyun rtlpriv->ra.is_special_data = true;
1549*4882a593Smuzhiyun rtl_lps_leave(hw, false);
1550*4882a593Smuzhiyun ppsc->last_delaylps_stamp_jiffies = jiffies;
1551*4882a593Smuzhiyun
1552*4882a593Smuzhiyun setup_special_tx(rtlpriv, ppsc, PACKET_EAPOL);
1553*4882a593Smuzhiyun }
1554*4882a593Smuzhiyun
1555*4882a593Smuzhiyun return true;
1556*4882a593Smuzhiyun } else if (ETH_P_IPV6 == ether_type) {
1557*4882a593Smuzhiyun /* TODO: Handle any IPv6 cases that need special handling.
1558*4882a593Smuzhiyun * For now, always return false
1559*4882a593Smuzhiyun */
1560*4882a593Smuzhiyun goto end;
1561*4882a593Smuzhiyun }
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun end:
1564*4882a593Smuzhiyun rtlpriv->ra.is_special_data = false;
1565*4882a593Smuzhiyun return false;
1566*4882a593Smuzhiyun }
1567*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_is_special_data);
1568*4882a593Smuzhiyun
rtl_tx_ackqueue(struct ieee80211_hw * hw,struct sk_buff * skb)1569*4882a593Smuzhiyun void rtl_tx_ackqueue(struct ieee80211_hw *hw, struct sk_buff *skb)
1570*4882a593Smuzhiyun {
1571*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1572*4882a593Smuzhiyun struct rtl_tx_report *tx_report = &rtlpriv->tx_report;
1573*4882a593Smuzhiyun
1574*4882a593Smuzhiyun __skb_queue_tail(&tx_report->queue, skb);
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_tx_ackqueue);
1577*4882a593Smuzhiyun
rtl_tx_status(struct ieee80211_hw * hw,struct sk_buff * skb,bool ack)1578*4882a593Smuzhiyun static void rtl_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
1579*4882a593Smuzhiyun bool ack)
1580*4882a593Smuzhiyun {
1581*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1582*4882a593Smuzhiyun struct ieee80211_tx_info *info;
1583*4882a593Smuzhiyun
1584*4882a593Smuzhiyun info = IEEE80211_SKB_CB(skb);
1585*4882a593Smuzhiyun ieee80211_tx_info_clear_status(info);
1586*4882a593Smuzhiyun if (ack) {
1587*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_TX_REPORT, DBG_LOUD,
1588*4882a593Smuzhiyun "tx report: ack\n");
1589*4882a593Smuzhiyun info->flags |= IEEE80211_TX_STAT_ACK;
1590*4882a593Smuzhiyun } else {
1591*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_TX_REPORT, DBG_LOUD,
1592*4882a593Smuzhiyun "tx report: not ack\n");
1593*4882a593Smuzhiyun info->flags &= ~IEEE80211_TX_STAT_ACK;
1594*4882a593Smuzhiyun }
1595*4882a593Smuzhiyun ieee80211_tx_status_irqsafe(hw, skb);
1596*4882a593Smuzhiyun }
1597*4882a593Smuzhiyun
rtl_is_tx_report_skb(struct ieee80211_hw * hw,struct sk_buff * skb)1598*4882a593Smuzhiyun bool rtl_is_tx_report_skb(struct ieee80211_hw *hw, struct sk_buff *skb)
1599*4882a593Smuzhiyun {
1600*4882a593Smuzhiyun u16 ether_type;
1601*4882a593Smuzhiyun const u8 *ether_type_ptr;
1602*4882a593Smuzhiyun __le16 fc = rtl_get_fc(skb);
1603*4882a593Smuzhiyun
1604*4882a593Smuzhiyun ether_type_ptr = rtl_skb_ether_type_ptr(hw, skb, true);
1605*4882a593Smuzhiyun ether_type = be16_to_cpup((__be16 *)ether_type_ptr);
1606*4882a593Smuzhiyun
1607*4882a593Smuzhiyun if (ether_type == ETH_P_PAE || ieee80211_is_nullfunc(fc))
1608*4882a593Smuzhiyun return true;
1609*4882a593Smuzhiyun
1610*4882a593Smuzhiyun return false;
1611*4882a593Smuzhiyun }
1612*4882a593Smuzhiyun
rtl_get_tx_report_sn(struct ieee80211_hw * hw,struct rtlwifi_tx_info * tx_info)1613*4882a593Smuzhiyun static u16 rtl_get_tx_report_sn(struct ieee80211_hw *hw,
1614*4882a593Smuzhiyun struct rtlwifi_tx_info *tx_info)
1615*4882a593Smuzhiyun {
1616*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1617*4882a593Smuzhiyun struct rtl_tx_report *tx_report = &rtlpriv->tx_report;
1618*4882a593Smuzhiyun u16 sn;
1619*4882a593Smuzhiyun
1620*4882a593Smuzhiyun /* SW_DEFINE[11:8] are reserved (driver fills zeros)
1621*4882a593Smuzhiyun * SW_DEFINE[7:2] are used by driver
1622*4882a593Smuzhiyun * SW_DEFINE[1:0] are reserved for firmware (driver fills zeros)
1623*4882a593Smuzhiyun */
1624*4882a593Smuzhiyun sn = (atomic_inc_return(&tx_report->sn) & 0x003F) << 2;
1625*4882a593Smuzhiyun
1626*4882a593Smuzhiyun tx_report->last_sent_sn = sn;
1627*4882a593Smuzhiyun tx_report->last_sent_time = jiffies;
1628*4882a593Smuzhiyun tx_info->sn = sn;
1629*4882a593Smuzhiyun tx_info->send_time = tx_report->last_sent_time;
1630*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_TX_REPORT, DBG_DMESG,
1631*4882a593Smuzhiyun "Send TX-Report sn=0x%X\n", sn);
1632*4882a593Smuzhiyun
1633*4882a593Smuzhiyun return sn;
1634*4882a593Smuzhiyun }
1635*4882a593Smuzhiyun
rtl_set_tx_report(struct rtl_tcb_desc * ptcb_desc,u8 * pdesc,struct ieee80211_hw * hw,struct rtlwifi_tx_info * tx_info)1636*4882a593Smuzhiyun void rtl_set_tx_report(struct rtl_tcb_desc *ptcb_desc, u8 *pdesc,
1637*4882a593Smuzhiyun struct ieee80211_hw *hw, struct rtlwifi_tx_info *tx_info)
1638*4882a593Smuzhiyun {
1639*4882a593Smuzhiyun if (ptcb_desc->use_spe_rpt) {
1640*4882a593Smuzhiyun u16 sn = rtl_get_tx_report_sn(hw, tx_info);
1641*4882a593Smuzhiyun
1642*4882a593Smuzhiyun SET_TX_DESC_SPE_RPT(pdesc, 1);
1643*4882a593Smuzhiyun SET_TX_DESC_SW_DEFINE(pdesc, sn);
1644*4882a593Smuzhiyun }
1645*4882a593Smuzhiyun }
1646*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_set_tx_report);
1647*4882a593Smuzhiyun
rtl_tx_report_handler(struct ieee80211_hw * hw,u8 * tmp_buf,u8 c2h_cmd_len)1648*4882a593Smuzhiyun void rtl_tx_report_handler(struct ieee80211_hw *hw, u8 *tmp_buf, u8 c2h_cmd_len)
1649*4882a593Smuzhiyun {
1650*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1651*4882a593Smuzhiyun struct rtl_tx_report *tx_report = &rtlpriv->tx_report;
1652*4882a593Smuzhiyun struct rtlwifi_tx_info *tx_info;
1653*4882a593Smuzhiyun struct sk_buff_head *queue = &tx_report->queue;
1654*4882a593Smuzhiyun struct sk_buff *skb;
1655*4882a593Smuzhiyun u16 sn;
1656*4882a593Smuzhiyun u8 st, retry;
1657*4882a593Smuzhiyun
1658*4882a593Smuzhiyun if (rtlpriv->cfg->spec_ver & RTL_SPEC_EXT_C2H) {
1659*4882a593Smuzhiyun sn = GET_TX_REPORT_SN_V2(tmp_buf);
1660*4882a593Smuzhiyun st = GET_TX_REPORT_ST_V2(tmp_buf);
1661*4882a593Smuzhiyun retry = GET_TX_REPORT_RETRY_V2(tmp_buf);
1662*4882a593Smuzhiyun } else {
1663*4882a593Smuzhiyun sn = GET_TX_REPORT_SN_V1(tmp_buf);
1664*4882a593Smuzhiyun st = GET_TX_REPORT_ST_V1(tmp_buf);
1665*4882a593Smuzhiyun retry = GET_TX_REPORT_RETRY_V1(tmp_buf);
1666*4882a593Smuzhiyun }
1667*4882a593Smuzhiyun
1668*4882a593Smuzhiyun tx_report->last_recv_sn = sn;
1669*4882a593Smuzhiyun
1670*4882a593Smuzhiyun skb_queue_walk(queue, skb) {
1671*4882a593Smuzhiyun tx_info = rtl_tx_skb_cb_info(skb);
1672*4882a593Smuzhiyun if (tx_info->sn == sn) {
1673*4882a593Smuzhiyun skb_unlink(skb, queue);
1674*4882a593Smuzhiyun rtl_tx_status(hw, skb, st == 0);
1675*4882a593Smuzhiyun break;
1676*4882a593Smuzhiyun }
1677*4882a593Smuzhiyun }
1678*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_TX_REPORT, DBG_DMESG,
1679*4882a593Smuzhiyun "Recv TX-Report st=0x%02X sn=0x%X retry=0x%X\n",
1680*4882a593Smuzhiyun st, sn, retry);
1681*4882a593Smuzhiyun }
1682*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_tx_report_handler);
1683*4882a593Smuzhiyun
rtl_check_tx_report_acked(struct ieee80211_hw * hw)1684*4882a593Smuzhiyun bool rtl_check_tx_report_acked(struct ieee80211_hw *hw)
1685*4882a593Smuzhiyun {
1686*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1687*4882a593Smuzhiyun struct rtl_tx_report *tx_report = &rtlpriv->tx_report;
1688*4882a593Smuzhiyun
1689*4882a593Smuzhiyun if (tx_report->last_sent_sn == tx_report->last_recv_sn)
1690*4882a593Smuzhiyun return true;
1691*4882a593Smuzhiyun
1692*4882a593Smuzhiyun if (time_before(tx_report->last_sent_time + 3 * HZ, jiffies)) {
1693*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_TX_REPORT, DBG_WARNING,
1694*4882a593Smuzhiyun "Check TX-Report timeout!! s_sn=0x%X r_sn=0x%X\n",
1695*4882a593Smuzhiyun tx_report->last_sent_sn, tx_report->last_recv_sn);
1696*4882a593Smuzhiyun return true; /* 3 sec. (timeout) seen as acked */
1697*4882a593Smuzhiyun }
1698*4882a593Smuzhiyun
1699*4882a593Smuzhiyun return false;
1700*4882a593Smuzhiyun }
1701*4882a593Smuzhiyun
rtl_wait_tx_report_acked(struct ieee80211_hw * hw,u32 wait_ms)1702*4882a593Smuzhiyun void rtl_wait_tx_report_acked(struct ieee80211_hw *hw, u32 wait_ms)
1703*4882a593Smuzhiyun {
1704*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1705*4882a593Smuzhiyun int i;
1706*4882a593Smuzhiyun
1707*4882a593Smuzhiyun for (i = 0; i < wait_ms; i++) {
1708*4882a593Smuzhiyun if (rtl_check_tx_report_acked(hw))
1709*4882a593Smuzhiyun break;
1710*4882a593Smuzhiyun usleep_range(1000, 2000);
1711*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_SEC, DBG_DMESG,
1712*4882a593Smuzhiyun "Wait 1ms (%d/%d) to disable key.\n", i, wait_ms);
1713*4882a593Smuzhiyun }
1714*4882a593Smuzhiyun }
1715*4882a593Smuzhiyun
rtl_get_hal_edca_param(struct ieee80211_hw * hw,struct ieee80211_vif * vif,enum wireless_mode wirelessmode,struct ieee80211_tx_queue_params * param)1716*4882a593Smuzhiyun u32 rtl_get_hal_edca_param(struct ieee80211_hw *hw,
1717*4882a593Smuzhiyun struct ieee80211_vif *vif,
1718*4882a593Smuzhiyun enum wireless_mode wirelessmode,
1719*4882a593Smuzhiyun struct ieee80211_tx_queue_params *param)
1720*4882a593Smuzhiyun {
1721*4882a593Smuzhiyun u32 reg = 0;
1722*4882a593Smuzhiyun u8 sifstime = 10;
1723*4882a593Smuzhiyun u8 slottime = 20;
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun /* AIFS = AIFSN * slot time + SIFS */
1726*4882a593Smuzhiyun switch (wirelessmode) {
1727*4882a593Smuzhiyun case WIRELESS_MODE_A:
1728*4882a593Smuzhiyun case WIRELESS_MODE_N_24G:
1729*4882a593Smuzhiyun case WIRELESS_MODE_N_5G:
1730*4882a593Smuzhiyun case WIRELESS_MODE_AC_5G:
1731*4882a593Smuzhiyun case WIRELESS_MODE_AC_24G:
1732*4882a593Smuzhiyun sifstime = 16;
1733*4882a593Smuzhiyun slottime = 9;
1734*4882a593Smuzhiyun break;
1735*4882a593Smuzhiyun case WIRELESS_MODE_G:
1736*4882a593Smuzhiyun slottime = (vif->bss_conf.use_short_slot ? 9 : 20);
1737*4882a593Smuzhiyun break;
1738*4882a593Smuzhiyun default:
1739*4882a593Smuzhiyun break;
1740*4882a593Smuzhiyun }
1741*4882a593Smuzhiyun
1742*4882a593Smuzhiyun reg |= (param->txop & 0x7FF) << 16;
1743*4882a593Smuzhiyun reg |= (fls(param->cw_max) & 0xF) << 12;
1744*4882a593Smuzhiyun reg |= (fls(param->cw_min) & 0xF) << 8;
1745*4882a593Smuzhiyun reg |= (param->aifs & 0x0F) * slottime + sifstime;
1746*4882a593Smuzhiyun
1747*4882a593Smuzhiyun return reg;
1748*4882a593Smuzhiyun }
1749*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_get_hal_edca_param);
1750*4882a593Smuzhiyun
1751*4882a593Smuzhiyun /*********************************************************
1752*4882a593Smuzhiyun *
1753*4882a593Smuzhiyun * functions called by core.c
1754*4882a593Smuzhiyun *
1755*4882a593Smuzhiyun *********************************************************/
rtl_tx_agg_start(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,u16 tid,u16 * ssn)1756*4882a593Smuzhiyun int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1757*4882a593Smuzhiyun struct ieee80211_sta *sta, u16 tid, u16 *ssn)
1758*4882a593Smuzhiyun {
1759*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1760*4882a593Smuzhiyun struct rtl_tid_data *tid_data;
1761*4882a593Smuzhiyun struct rtl_sta_info *sta_entry = NULL;
1762*4882a593Smuzhiyun
1763*4882a593Smuzhiyun if (sta == NULL)
1764*4882a593Smuzhiyun return -EINVAL;
1765*4882a593Smuzhiyun
1766*4882a593Smuzhiyun if (unlikely(tid >= MAX_TID_COUNT))
1767*4882a593Smuzhiyun return -EINVAL;
1768*4882a593Smuzhiyun
1769*4882a593Smuzhiyun sta_entry = (struct rtl_sta_info *)sta->drv_priv;
1770*4882a593Smuzhiyun if (!sta_entry)
1771*4882a593Smuzhiyun return -ENXIO;
1772*4882a593Smuzhiyun tid_data = &sta_entry->tids[tid];
1773*4882a593Smuzhiyun
1774*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_SEND, DBG_DMESG,
1775*4882a593Smuzhiyun "on ra = %pM tid = %d seq:%d\n", sta->addr, tid,
1776*4882a593Smuzhiyun *ssn);
1777*4882a593Smuzhiyun
1778*4882a593Smuzhiyun tid_data->agg.agg_state = RTL_AGG_START;
1779*4882a593Smuzhiyun
1780*4882a593Smuzhiyun return IEEE80211_AMPDU_TX_START_IMMEDIATE;
1781*4882a593Smuzhiyun }
1782*4882a593Smuzhiyun
rtl_tx_agg_stop(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,u16 tid)1783*4882a593Smuzhiyun int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1784*4882a593Smuzhiyun struct ieee80211_sta *sta, u16 tid)
1785*4882a593Smuzhiyun {
1786*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1787*4882a593Smuzhiyun struct rtl_sta_info *sta_entry = NULL;
1788*4882a593Smuzhiyun
1789*4882a593Smuzhiyun if (sta == NULL)
1790*4882a593Smuzhiyun return -EINVAL;
1791*4882a593Smuzhiyun
1792*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_SEND, DBG_DMESG,
1793*4882a593Smuzhiyun "on ra = %pM tid = %d\n", sta->addr, tid);
1794*4882a593Smuzhiyun
1795*4882a593Smuzhiyun if (unlikely(tid >= MAX_TID_COUNT))
1796*4882a593Smuzhiyun return -EINVAL;
1797*4882a593Smuzhiyun
1798*4882a593Smuzhiyun sta_entry = (struct rtl_sta_info *)sta->drv_priv;
1799*4882a593Smuzhiyun sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP;
1800*4882a593Smuzhiyun
1801*4882a593Smuzhiyun ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1802*4882a593Smuzhiyun return 0;
1803*4882a593Smuzhiyun }
1804*4882a593Smuzhiyun
rtl_rx_agg_start(struct ieee80211_hw * hw,struct ieee80211_sta * sta,u16 tid)1805*4882a593Smuzhiyun int rtl_rx_agg_start(struct ieee80211_hw *hw,
1806*4882a593Smuzhiyun struct ieee80211_sta *sta, u16 tid)
1807*4882a593Smuzhiyun {
1808*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1809*4882a593Smuzhiyun struct rtl_tid_data *tid_data;
1810*4882a593Smuzhiyun struct rtl_sta_info *sta_entry = NULL;
1811*4882a593Smuzhiyun u8 reject_agg;
1812*4882a593Smuzhiyun
1813*4882a593Smuzhiyun if (sta == NULL)
1814*4882a593Smuzhiyun return -EINVAL;
1815*4882a593Smuzhiyun
1816*4882a593Smuzhiyun if (unlikely(tid >= MAX_TID_COUNT))
1817*4882a593Smuzhiyun return -EINVAL;
1818*4882a593Smuzhiyun
1819*4882a593Smuzhiyun if (rtlpriv->cfg->ops->get_btc_status()) {
1820*4882a593Smuzhiyun rtlpriv->btcoexist.btc_ops->btc_get_ampdu_cfg(rtlpriv,
1821*4882a593Smuzhiyun &reject_agg,
1822*4882a593Smuzhiyun NULL, NULL);
1823*4882a593Smuzhiyun if (reject_agg)
1824*4882a593Smuzhiyun return -EINVAL;
1825*4882a593Smuzhiyun }
1826*4882a593Smuzhiyun
1827*4882a593Smuzhiyun sta_entry = (struct rtl_sta_info *)sta->drv_priv;
1828*4882a593Smuzhiyun if (!sta_entry)
1829*4882a593Smuzhiyun return -ENXIO;
1830*4882a593Smuzhiyun tid_data = &sta_entry->tids[tid];
1831*4882a593Smuzhiyun
1832*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_RECV, DBG_DMESG,
1833*4882a593Smuzhiyun "on ra = %pM tid = %d\n", sta->addr, tid);
1834*4882a593Smuzhiyun
1835*4882a593Smuzhiyun tid_data->agg.rx_agg_state = RTL_RX_AGG_START;
1836*4882a593Smuzhiyun return 0;
1837*4882a593Smuzhiyun }
1838*4882a593Smuzhiyun
rtl_rx_agg_stop(struct ieee80211_hw * hw,struct ieee80211_sta * sta,u16 tid)1839*4882a593Smuzhiyun int rtl_rx_agg_stop(struct ieee80211_hw *hw,
1840*4882a593Smuzhiyun struct ieee80211_sta *sta, u16 tid)
1841*4882a593Smuzhiyun {
1842*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1843*4882a593Smuzhiyun struct rtl_sta_info *sta_entry = NULL;
1844*4882a593Smuzhiyun
1845*4882a593Smuzhiyun if (sta == NULL)
1846*4882a593Smuzhiyun return -EINVAL;
1847*4882a593Smuzhiyun
1848*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_SEND, DBG_DMESG,
1849*4882a593Smuzhiyun "on ra = %pM tid = %d\n", sta->addr, tid);
1850*4882a593Smuzhiyun
1851*4882a593Smuzhiyun if (unlikely(tid >= MAX_TID_COUNT))
1852*4882a593Smuzhiyun return -EINVAL;
1853*4882a593Smuzhiyun
1854*4882a593Smuzhiyun sta_entry = (struct rtl_sta_info *)sta->drv_priv;
1855*4882a593Smuzhiyun sta_entry->tids[tid].agg.rx_agg_state = RTL_RX_AGG_STOP;
1856*4882a593Smuzhiyun
1857*4882a593Smuzhiyun return 0;
1858*4882a593Smuzhiyun }
1859*4882a593Smuzhiyun
rtl_tx_agg_oper(struct ieee80211_hw * hw,struct ieee80211_sta * sta,u16 tid)1860*4882a593Smuzhiyun int rtl_tx_agg_oper(struct ieee80211_hw *hw,
1861*4882a593Smuzhiyun struct ieee80211_sta *sta, u16 tid)
1862*4882a593Smuzhiyun {
1863*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1864*4882a593Smuzhiyun struct rtl_sta_info *sta_entry = NULL;
1865*4882a593Smuzhiyun
1866*4882a593Smuzhiyun if (sta == NULL)
1867*4882a593Smuzhiyun return -EINVAL;
1868*4882a593Smuzhiyun
1869*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_SEND, DBG_DMESG,
1870*4882a593Smuzhiyun "on ra = %pM tid = %d\n", sta->addr, tid);
1871*4882a593Smuzhiyun
1872*4882a593Smuzhiyun if (unlikely(tid >= MAX_TID_COUNT))
1873*4882a593Smuzhiyun return -EINVAL;
1874*4882a593Smuzhiyun
1875*4882a593Smuzhiyun sta_entry = (struct rtl_sta_info *)sta->drv_priv;
1876*4882a593Smuzhiyun sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL;
1877*4882a593Smuzhiyun
1878*4882a593Smuzhiyun return 0;
1879*4882a593Smuzhiyun }
1880*4882a593Smuzhiyun
rtl_rx_ampdu_apply(struct rtl_priv * rtlpriv)1881*4882a593Smuzhiyun void rtl_rx_ampdu_apply(struct rtl_priv *rtlpriv)
1882*4882a593Smuzhiyun {
1883*4882a593Smuzhiyun struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops;
1884*4882a593Smuzhiyun u8 reject_agg = 0, ctrl_agg_size = 0, agg_size = 0;
1885*4882a593Smuzhiyun
1886*4882a593Smuzhiyun if (rtlpriv->cfg->ops->get_btc_status())
1887*4882a593Smuzhiyun btc_ops->btc_get_ampdu_cfg(rtlpriv, &reject_agg,
1888*4882a593Smuzhiyun &ctrl_agg_size, &agg_size);
1889*4882a593Smuzhiyun
1890*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
1891*4882a593Smuzhiyun "Set RX AMPDU: coex - reject=%d, ctrl_agg_size=%d, size=%d",
1892*4882a593Smuzhiyun reject_agg, ctrl_agg_size, agg_size);
1893*4882a593Smuzhiyun
1894*4882a593Smuzhiyun rtlpriv->hw->max_rx_aggregation_subframes =
1895*4882a593Smuzhiyun (ctrl_agg_size ? agg_size : IEEE80211_MAX_AMPDU_BUF_HT);
1896*4882a593Smuzhiyun }
1897*4882a593Smuzhiyun EXPORT_SYMBOL(rtl_rx_ampdu_apply);
1898*4882a593Smuzhiyun
1899*4882a593Smuzhiyun /*********************************************************
1900*4882a593Smuzhiyun *
1901*4882a593Smuzhiyun * wq & timer callback functions
1902*4882a593Smuzhiyun *
1903*4882a593Smuzhiyun *********************************************************/
1904*4882a593Smuzhiyun /* this function is used for roaming */
rtl_beacon_statistic(struct ieee80211_hw * hw,struct sk_buff * skb)1905*4882a593Smuzhiyun void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
1906*4882a593Smuzhiyun {
1907*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1908*4882a593Smuzhiyun struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1909*4882a593Smuzhiyun
1910*4882a593Smuzhiyun if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION)
1911*4882a593Smuzhiyun return;
1912*4882a593Smuzhiyun
1913*4882a593Smuzhiyun if (rtlpriv->mac80211.link_state < MAC80211_LINKED)
1914*4882a593Smuzhiyun return;
1915*4882a593Smuzhiyun
1916*4882a593Smuzhiyun /* check if this really is a beacon */
1917*4882a593Smuzhiyun if (!ieee80211_is_beacon(hdr->frame_control) &&
1918*4882a593Smuzhiyun !ieee80211_is_probe_resp(hdr->frame_control))
1919*4882a593Smuzhiyun return;
1920*4882a593Smuzhiyun
1921*4882a593Smuzhiyun /* min. beacon length + FCS_LEN */
1922*4882a593Smuzhiyun if (skb->len <= 40 + FCS_LEN)
1923*4882a593Smuzhiyun return;
1924*4882a593Smuzhiyun
1925*4882a593Smuzhiyun /* and only beacons from the associated BSSID, please */
1926*4882a593Smuzhiyun if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
1927*4882a593Smuzhiyun return;
1928*4882a593Smuzhiyun
1929*4882a593Smuzhiyun rtlpriv->link_info.bcn_rx_inperiod++;
1930*4882a593Smuzhiyun }
1931*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_beacon_statistic);
1932*4882a593Smuzhiyun
rtl_free_entries_from_scan_list(struct ieee80211_hw * hw)1933*4882a593Smuzhiyun static void rtl_free_entries_from_scan_list(struct ieee80211_hw *hw)
1934*4882a593Smuzhiyun {
1935*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1936*4882a593Smuzhiyun struct rtl_bssid_entry *entry, *next;
1937*4882a593Smuzhiyun
1938*4882a593Smuzhiyun list_for_each_entry_safe(entry, next, &rtlpriv->scan_list.list, list) {
1939*4882a593Smuzhiyun list_del(&entry->list);
1940*4882a593Smuzhiyun kfree(entry);
1941*4882a593Smuzhiyun rtlpriv->scan_list.num--;
1942*4882a593Smuzhiyun }
1943*4882a593Smuzhiyun }
1944*4882a593Smuzhiyun
rtl_free_entries_from_ack_queue(struct ieee80211_hw * hw,bool chk_timeout)1945*4882a593Smuzhiyun static void rtl_free_entries_from_ack_queue(struct ieee80211_hw *hw,
1946*4882a593Smuzhiyun bool chk_timeout)
1947*4882a593Smuzhiyun {
1948*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1949*4882a593Smuzhiyun struct rtl_tx_report *tx_report = &rtlpriv->tx_report;
1950*4882a593Smuzhiyun struct sk_buff_head *queue = &tx_report->queue;
1951*4882a593Smuzhiyun struct sk_buff *skb, *tmp;
1952*4882a593Smuzhiyun struct rtlwifi_tx_info *tx_info;
1953*4882a593Smuzhiyun
1954*4882a593Smuzhiyun skb_queue_walk_safe(queue, skb, tmp) {
1955*4882a593Smuzhiyun tx_info = rtl_tx_skb_cb_info(skb);
1956*4882a593Smuzhiyun if (chk_timeout &&
1957*4882a593Smuzhiyun time_after(tx_info->send_time + HZ, jiffies))
1958*4882a593Smuzhiyun continue;
1959*4882a593Smuzhiyun skb_unlink(skb, queue);
1960*4882a593Smuzhiyun rtl_tx_status(hw, skb, false);
1961*4882a593Smuzhiyun }
1962*4882a593Smuzhiyun }
1963*4882a593Smuzhiyun
rtl_scan_list_expire(struct ieee80211_hw * hw)1964*4882a593Smuzhiyun void rtl_scan_list_expire(struct ieee80211_hw *hw)
1965*4882a593Smuzhiyun {
1966*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1967*4882a593Smuzhiyun struct rtl_bssid_entry *entry, *next;
1968*4882a593Smuzhiyun unsigned long flags;
1969*4882a593Smuzhiyun
1970*4882a593Smuzhiyun spin_lock_irqsave(&rtlpriv->locks.scan_list_lock, flags);
1971*4882a593Smuzhiyun
1972*4882a593Smuzhiyun list_for_each_entry_safe(entry, next, &rtlpriv->scan_list.list, list) {
1973*4882a593Smuzhiyun /* 180 seconds */
1974*4882a593Smuzhiyun if (jiffies_to_msecs(jiffies - entry->age) < 180000)
1975*4882a593Smuzhiyun continue;
1976*4882a593Smuzhiyun
1977*4882a593Smuzhiyun list_del(&entry->list);
1978*4882a593Smuzhiyun rtlpriv->scan_list.num--;
1979*4882a593Smuzhiyun
1980*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_SCAN, DBG_LOUD,
1981*4882a593Smuzhiyun "BSSID=%pM is expire in scan list (total=%d)\n",
1982*4882a593Smuzhiyun entry->bssid, rtlpriv->scan_list.num);
1983*4882a593Smuzhiyun kfree(entry);
1984*4882a593Smuzhiyun }
1985*4882a593Smuzhiyun
1986*4882a593Smuzhiyun spin_unlock_irqrestore(&rtlpriv->locks.scan_list_lock, flags);
1987*4882a593Smuzhiyun
1988*4882a593Smuzhiyun rtlpriv->btcoexist.btc_info.ap_num = rtlpriv->scan_list.num;
1989*4882a593Smuzhiyun }
1990*4882a593Smuzhiyun
rtl_collect_scan_list(struct ieee80211_hw * hw,struct sk_buff * skb)1991*4882a593Smuzhiyun void rtl_collect_scan_list(struct ieee80211_hw *hw, struct sk_buff *skb)
1992*4882a593Smuzhiyun {
1993*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
1994*4882a593Smuzhiyun struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1995*4882a593Smuzhiyun struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
1996*4882a593Smuzhiyun unsigned long flags;
1997*4882a593Smuzhiyun
1998*4882a593Smuzhiyun struct rtl_bssid_entry *entry;
1999*4882a593Smuzhiyun bool entry_found = false;
2000*4882a593Smuzhiyun
2001*4882a593Smuzhiyun /* check if it is scanning */
2002*4882a593Smuzhiyun if (!mac->act_scanning)
2003*4882a593Smuzhiyun return;
2004*4882a593Smuzhiyun
2005*4882a593Smuzhiyun /* check if this really is a beacon */
2006*4882a593Smuzhiyun if (!ieee80211_is_beacon(hdr->frame_control) &&
2007*4882a593Smuzhiyun !ieee80211_is_probe_resp(hdr->frame_control))
2008*4882a593Smuzhiyun return;
2009*4882a593Smuzhiyun
2010*4882a593Smuzhiyun spin_lock_irqsave(&rtlpriv->locks.scan_list_lock, flags);
2011*4882a593Smuzhiyun
2012*4882a593Smuzhiyun list_for_each_entry(entry, &rtlpriv->scan_list.list, list) {
2013*4882a593Smuzhiyun if (memcmp(entry->bssid, hdr->addr3, ETH_ALEN) == 0) {
2014*4882a593Smuzhiyun list_del_init(&entry->list);
2015*4882a593Smuzhiyun entry_found = true;
2016*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_SCAN, DBG_LOUD,
2017*4882a593Smuzhiyun "Update BSSID=%pM to scan list (total=%d)\n",
2018*4882a593Smuzhiyun hdr->addr3, rtlpriv->scan_list.num);
2019*4882a593Smuzhiyun break;
2020*4882a593Smuzhiyun }
2021*4882a593Smuzhiyun }
2022*4882a593Smuzhiyun
2023*4882a593Smuzhiyun if (!entry_found) {
2024*4882a593Smuzhiyun entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
2025*4882a593Smuzhiyun
2026*4882a593Smuzhiyun if (!entry)
2027*4882a593Smuzhiyun goto label_err;
2028*4882a593Smuzhiyun
2029*4882a593Smuzhiyun memcpy(entry->bssid, hdr->addr3, ETH_ALEN);
2030*4882a593Smuzhiyun rtlpriv->scan_list.num++;
2031*4882a593Smuzhiyun
2032*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_SCAN, DBG_LOUD,
2033*4882a593Smuzhiyun "Add BSSID=%pM to scan list (total=%d)\n",
2034*4882a593Smuzhiyun hdr->addr3, rtlpriv->scan_list.num);
2035*4882a593Smuzhiyun }
2036*4882a593Smuzhiyun
2037*4882a593Smuzhiyun entry->age = jiffies;
2038*4882a593Smuzhiyun
2039*4882a593Smuzhiyun list_add_tail(&entry->list, &rtlpriv->scan_list.list);
2040*4882a593Smuzhiyun
2041*4882a593Smuzhiyun label_err:
2042*4882a593Smuzhiyun spin_unlock_irqrestore(&rtlpriv->locks.scan_list_lock, flags);
2043*4882a593Smuzhiyun }
2044*4882a593Smuzhiyun EXPORT_SYMBOL(rtl_collect_scan_list);
2045*4882a593Smuzhiyun
rtl_watchdog_wq_callback(struct work_struct * work)2046*4882a593Smuzhiyun static void rtl_watchdog_wq_callback(struct work_struct *work)
2047*4882a593Smuzhiyun {
2048*4882a593Smuzhiyun struct rtl_works *rtlworks = container_of(work, struct rtl_works,
2049*4882a593Smuzhiyun watchdog_wq.work);
2050*4882a593Smuzhiyun struct ieee80211_hw *hw = rtlworks->hw;
2051*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
2052*4882a593Smuzhiyun struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
2053*4882a593Smuzhiyun struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
2054*4882a593Smuzhiyun bool busytraffic = false;
2055*4882a593Smuzhiyun bool tx_busy_traffic = false;
2056*4882a593Smuzhiyun bool rx_busy_traffic = false;
2057*4882a593Smuzhiyun bool higher_busytraffic = false;
2058*4882a593Smuzhiyun bool higher_busyrxtraffic = false;
2059*4882a593Smuzhiyun u8 idx, tid;
2060*4882a593Smuzhiyun u32 rx_cnt_inp4eriod = 0;
2061*4882a593Smuzhiyun u32 tx_cnt_inp4eriod = 0;
2062*4882a593Smuzhiyun u32 aver_rx_cnt_inperiod = 0;
2063*4882a593Smuzhiyun u32 aver_tx_cnt_inperiod = 0;
2064*4882a593Smuzhiyun u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0};
2065*4882a593Smuzhiyun u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0};
2066*4882a593Smuzhiyun
2067*4882a593Smuzhiyun if (is_hal_stop(rtlhal))
2068*4882a593Smuzhiyun return;
2069*4882a593Smuzhiyun
2070*4882a593Smuzhiyun /* <1> Determine if action frame is allowed */
2071*4882a593Smuzhiyun if (mac->link_state > MAC80211_NOLINK) {
2072*4882a593Smuzhiyun if (mac->cnt_after_linked < 20)
2073*4882a593Smuzhiyun mac->cnt_after_linked++;
2074*4882a593Smuzhiyun } else {
2075*4882a593Smuzhiyun mac->cnt_after_linked = 0;
2076*4882a593Smuzhiyun }
2077*4882a593Smuzhiyun
2078*4882a593Smuzhiyun /* <2> to check if traffic busy, if
2079*4882a593Smuzhiyun * busytraffic we don't change channel
2080*4882a593Smuzhiyun */
2081*4882a593Smuzhiyun if (mac->link_state >= MAC80211_LINKED) {
2082*4882a593Smuzhiyun /* (1) get aver_rx_cnt_inperiod & aver_tx_cnt_inperiod */
2083*4882a593Smuzhiyun for (idx = 0; idx <= 2; idx++) {
2084*4882a593Smuzhiyun rtlpriv->link_info.num_rx_in4period[idx] =
2085*4882a593Smuzhiyun rtlpriv->link_info.num_rx_in4period[idx + 1];
2086*4882a593Smuzhiyun rtlpriv->link_info.num_tx_in4period[idx] =
2087*4882a593Smuzhiyun rtlpriv->link_info.num_tx_in4period[idx + 1];
2088*4882a593Smuzhiyun }
2089*4882a593Smuzhiyun rtlpriv->link_info.num_rx_in4period[3] =
2090*4882a593Smuzhiyun rtlpriv->link_info.num_rx_inperiod;
2091*4882a593Smuzhiyun rtlpriv->link_info.num_tx_in4period[3] =
2092*4882a593Smuzhiyun rtlpriv->link_info.num_tx_inperiod;
2093*4882a593Smuzhiyun for (idx = 0; idx <= 3; idx++) {
2094*4882a593Smuzhiyun rx_cnt_inp4eriod +=
2095*4882a593Smuzhiyun rtlpriv->link_info.num_rx_in4period[idx];
2096*4882a593Smuzhiyun tx_cnt_inp4eriod +=
2097*4882a593Smuzhiyun rtlpriv->link_info.num_tx_in4period[idx];
2098*4882a593Smuzhiyun }
2099*4882a593Smuzhiyun aver_rx_cnt_inperiod = rx_cnt_inp4eriod / 4;
2100*4882a593Smuzhiyun aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4;
2101*4882a593Smuzhiyun
2102*4882a593Smuzhiyun /* (2) check traffic busy */
2103*4882a593Smuzhiyun if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100) {
2104*4882a593Smuzhiyun busytraffic = true;
2105*4882a593Smuzhiyun if (aver_rx_cnt_inperiod > aver_tx_cnt_inperiod)
2106*4882a593Smuzhiyun rx_busy_traffic = true;
2107*4882a593Smuzhiyun else
2108*4882a593Smuzhiyun tx_busy_traffic = false;
2109*4882a593Smuzhiyun }
2110*4882a593Smuzhiyun
2111*4882a593Smuzhiyun /* Higher Tx/Rx data. */
2112*4882a593Smuzhiyun if (aver_rx_cnt_inperiod > 4000 ||
2113*4882a593Smuzhiyun aver_tx_cnt_inperiod > 4000) {
2114*4882a593Smuzhiyun higher_busytraffic = true;
2115*4882a593Smuzhiyun
2116*4882a593Smuzhiyun /* Extremely high Rx data. */
2117*4882a593Smuzhiyun if (aver_rx_cnt_inperiod > 5000)
2118*4882a593Smuzhiyun higher_busyrxtraffic = true;
2119*4882a593Smuzhiyun }
2120*4882a593Smuzhiyun
2121*4882a593Smuzhiyun /* check every tid's tx traffic */
2122*4882a593Smuzhiyun for (tid = 0; tid <= 7; tid++) {
2123*4882a593Smuzhiyun for (idx = 0; idx <= 2; idx++)
2124*4882a593Smuzhiyun rtlpriv->link_info.tidtx_in4period[tid][idx] =
2125*4882a593Smuzhiyun rtlpriv->link_info.tidtx_in4period[tid]
2126*4882a593Smuzhiyun [idx + 1];
2127*4882a593Smuzhiyun rtlpriv->link_info.tidtx_in4period[tid][3] =
2128*4882a593Smuzhiyun rtlpriv->link_info.tidtx_inperiod[tid];
2129*4882a593Smuzhiyun
2130*4882a593Smuzhiyun for (idx = 0; idx <= 3; idx++)
2131*4882a593Smuzhiyun tidtx_inp4eriod[tid] +=
2132*4882a593Smuzhiyun rtlpriv->link_info.tidtx_in4period[tid][idx];
2133*4882a593Smuzhiyun aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4;
2134*4882a593Smuzhiyun if (aver_tidtx_inperiod[tid] > 5000)
2135*4882a593Smuzhiyun rtlpriv->link_info.higher_busytxtraffic[tid] =
2136*4882a593Smuzhiyun true;
2137*4882a593Smuzhiyun else
2138*4882a593Smuzhiyun rtlpriv->link_info.higher_busytxtraffic[tid] =
2139*4882a593Smuzhiyun false;
2140*4882a593Smuzhiyun }
2141*4882a593Smuzhiyun
2142*4882a593Smuzhiyun /* PS is controlled by coex. */
2143*4882a593Smuzhiyun if (rtlpriv->cfg->ops->get_btc_status() &&
2144*4882a593Smuzhiyun rtlpriv->btcoexist.btc_ops->btc_is_bt_ctrl_lps(rtlpriv))
2145*4882a593Smuzhiyun goto label_lps_done;
2146*4882a593Smuzhiyun
2147*4882a593Smuzhiyun if (rtlpriv->link_info.num_rx_inperiod +
2148*4882a593Smuzhiyun rtlpriv->link_info.num_tx_inperiod > 8 ||
2149*4882a593Smuzhiyun rtlpriv->link_info.num_rx_inperiod > 2)
2150*4882a593Smuzhiyun rtl_lps_leave(hw, true);
2151*4882a593Smuzhiyun else
2152*4882a593Smuzhiyun rtl_lps_enter(hw, true);
2153*4882a593Smuzhiyun
2154*4882a593Smuzhiyun label_lps_done:
2155*4882a593Smuzhiyun ;
2156*4882a593Smuzhiyun }
2157*4882a593Smuzhiyun
2158*4882a593Smuzhiyun for (tid = 0; tid <= 7; tid++)
2159*4882a593Smuzhiyun rtlpriv->link_info.tidtx_inperiod[tid] = 0;
2160*4882a593Smuzhiyun
2161*4882a593Smuzhiyun rtlpriv->link_info.busytraffic = busytraffic;
2162*4882a593Smuzhiyun rtlpriv->link_info.higher_busytraffic = higher_busytraffic;
2163*4882a593Smuzhiyun rtlpriv->link_info.rx_busy_traffic = rx_busy_traffic;
2164*4882a593Smuzhiyun rtlpriv->link_info.tx_busy_traffic = tx_busy_traffic;
2165*4882a593Smuzhiyun rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic;
2166*4882a593Smuzhiyun
2167*4882a593Smuzhiyun rtlpriv->stats.txbytesunicast_inperiod =
2168*4882a593Smuzhiyun rtlpriv->stats.txbytesunicast -
2169*4882a593Smuzhiyun rtlpriv->stats.txbytesunicast_last;
2170*4882a593Smuzhiyun rtlpriv->stats.rxbytesunicast_inperiod =
2171*4882a593Smuzhiyun rtlpriv->stats.rxbytesunicast -
2172*4882a593Smuzhiyun rtlpriv->stats.rxbytesunicast_last;
2173*4882a593Smuzhiyun rtlpriv->stats.txbytesunicast_last = rtlpriv->stats.txbytesunicast;
2174*4882a593Smuzhiyun rtlpriv->stats.rxbytesunicast_last = rtlpriv->stats.rxbytesunicast;
2175*4882a593Smuzhiyun
2176*4882a593Smuzhiyun rtlpriv->stats.txbytesunicast_inperiod_tp =
2177*4882a593Smuzhiyun (u32)(rtlpriv->stats.txbytesunicast_inperiod * 8 / 2 /
2178*4882a593Smuzhiyun 1024 / 1024);
2179*4882a593Smuzhiyun rtlpriv->stats.rxbytesunicast_inperiod_tp =
2180*4882a593Smuzhiyun (u32)(rtlpriv->stats.rxbytesunicast_inperiod * 8 / 2 /
2181*4882a593Smuzhiyun 1024 / 1024);
2182*4882a593Smuzhiyun
2183*4882a593Smuzhiyun /* <3> DM */
2184*4882a593Smuzhiyun if (!rtlpriv->cfg->mod_params->disable_watchdog)
2185*4882a593Smuzhiyun rtlpriv->cfg->ops->dm_watchdog(hw);
2186*4882a593Smuzhiyun
2187*4882a593Smuzhiyun /* <4> roaming */
2188*4882a593Smuzhiyun if (mac->link_state == MAC80211_LINKED &&
2189*4882a593Smuzhiyun mac->opmode == NL80211_IFTYPE_STATION) {
2190*4882a593Smuzhiyun if ((rtlpriv->link_info.bcn_rx_inperiod +
2191*4882a593Smuzhiyun rtlpriv->link_info.num_rx_inperiod) == 0) {
2192*4882a593Smuzhiyun rtlpriv->link_info.roam_times++;
2193*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_ERR, DBG_DMESG,
2194*4882a593Smuzhiyun "AP off for %d s\n",
2195*4882a593Smuzhiyun (rtlpriv->link_info.roam_times * 2));
2196*4882a593Smuzhiyun
2197*4882a593Smuzhiyun /* if we can't recv beacon for 10s,
2198*4882a593Smuzhiyun * we should reconnect this AP
2199*4882a593Smuzhiyun */
2200*4882a593Smuzhiyun if (rtlpriv->link_info.roam_times >= 5) {
2201*4882a593Smuzhiyun pr_err("AP off, try to reconnect now\n");
2202*4882a593Smuzhiyun rtlpriv->link_info.roam_times = 0;
2203*4882a593Smuzhiyun ieee80211_connection_loss(
2204*4882a593Smuzhiyun rtlpriv->mac80211.vif);
2205*4882a593Smuzhiyun }
2206*4882a593Smuzhiyun } else {
2207*4882a593Smuzhiyun rtlpriv->link_info.roam_times = 0;
2208*4882a593Smuzhiyun }
2209*4882a593Smuzhiyun }
2210*4882a593Smuzhiyun
2211*4882a593Smuzhiyun if (rtlpriv->cfg->ops->get_btc_status())
2212*4882a593Smuzhiyun rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv);
2213*4882a593Smuzhiyun
2214*4882a593Smuzhiyun if (rtlpriv->btcoexist.btc_info.in_4way) {
2215*4882a593Smuzhiyun if (time_after(jiffies, rtlpriv->btcoexist.btc_info.in_4way_ts +
2216*4882a593Smuzhiyun msecs_to_jiffies(IN_4WAY_TIMEOUT_TIME)))
2217*4882a593Smuzhiyun rtlpriv->btcoexist.btc_info.in_4way = false;
2218*4882a593Smuzhiyun }
2219*4882a593Smuzhiyun
2220*4882a593Smuzhiyun rtlpriv->link_info.num_rx_inperiod = 0;
2221*4882a593Smuzhiyun rtlpriv->link_info.num_tx_inperiod = 0;
2222*4882a593Smuzhiyun rtlpriv->link_info.bcn_rx_inperiod = 0;
2223*4882a593Smuzhiyun
2224*4882a593Smuzhiyun /* <6> scan list */
2225*4882a593Smuzhiyun rtl_scan_list_expire(hw);
2226*4882a593Smuzhiyun
2227*4882a593Smuzhiyun /* <7> check ack queue */
2228*4882a593Smuzhiyun rtl_free_entries_from_ack_queue(hw, true);
2229*4882a593Smuzhiyun }
2230*4882a593Smuzhiyun
rtl_watch_dog_timer_callback(struct timer_list * t)2231*4882a593Smuzhiyun void rtl_watch_dog_timer_callback(struct timer_list *t)
2232*4882a593Smuzhiyun {
2233*4882a593Smuzhiyun struct rtl_priv *rtlpriv = from_timer(rtlpriv, t, works.watchdog_timer);
2234*4882a593Smuzhiyun
2235*4882a593Smuzhiyun queue_delayed_work(rtlpriv->works.rtl_wq,
2236*4882a593Smuzhiyun &rtlpriv->works.watchdog_wq, 0);
2237*4882a593Smuzhiyun
2238*4882a593Smuzhiyun mod_timer(&rtlpriv->works.watchdog_timer,
2239*4882a593Smuzhiyun jiffies + MSECS(RTL_WATCH_DOG_TIME));
2240*4882a593Smuzhiyun }
2241*4882a593Smuzhiyun
rtl_fwevt_wq_callback(struct work_struct * work)2242*4882a593Smuzhiyun static void rtl_fwevt_wq_callback(struct work_struct *work)
2243*4882a593Smuzhiyun {
2244*4882a593Smuzhiyun struct rtl_works *rtlworks = container_of(work, struct rtl_works,
2245*4882a593Smuzhiyun fwevt_wq.work);
2246*4882a593Smuzhiyun struct ieee80211_hw *hw = rtlworks->hw;
2247*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
2248*4882a593Smuzhiyun
2249*4882a593Smuzhiyun rtlpriv->cfg->ops->c2h_command_handle(hw);
2250*4882a593Smuzhiyun }
2251*4882a593Smuzhiyun
2252*4882a593Smuzhiyun static void rtl_c2h_content_parsing(struct ieee80211_hw *hw,
2253*4882a593Smuzhiyun struct sk_buff *skb);
2254*4882a593Smuzhiyun
rtl_c2h_fast_cmd(struct ieee80211_hw * hw,struct sk_buff * skb)2255*4882a593Smuzhiyun static bool rtl_c2h_fast_cmd(struct ieee80211_hw *hw, struct sk_buff *skb)
2256*4882a593Smuzhiyun {
2257*4882a593Smuzhiyun u8 cmd_id = GET_C2H_CMD_ID(skb->data);
2258*4882a593Smuzhiyun
2259*4882a593Smuzhiyun switch (cmd_id) {
2260*4882a593Smuzhiyun case C2H_BT_MP:
2261*4882a593Smuzhiyun return true;
2262*4882a593Smuzhiyun default:
2263*4882a593Smuzhiyun break;
2264*4882a593Smuzhiyun }
2265*4882a593Smuzhiyun
2266*4882a593Smuzhiyun return false;
2267*4882a593Smuzhiyun }
2268*4882a593Smuzhiyun
rtl_c2hcmd_enqueue(struct ieee80211_hw * hw,struct sk_buff * skb)2269*4882a593Smuzhiyun void rtl_c2hcmd_enqueue(struct ieee80211_hw *hw, struct sk_buff *skb)
2270*4882a593Smuzhiyun {
2271*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
2272*4882a593Smuzhiyun unsigned long flags;
2273*4882a593Smuzhiyun
2274*4882a593Smuzhiyun if (rtl_c2h_fast_cmd(hw, skb)) {
2275*4882a593Smuzhiyun rtl_c2h_content_parsing(hw, skb);
2276*4882a593Smuzhiyun kfree_skb(skb);
2277*4882a593Smuzhiyun return;
2278*4882a593Smuzhiyun }
2279*4882a593Smuzhiyun
2280*4882a593Smuzhiyun /* enqueue */
2281*4882a593Smuzhiyun spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags);
2282*4882a593Smuzhiyun
2283*4882a593Smuzhiyun __skb_queue_tail(&rtlpriv->c2hcmd_queue, skb);
2284*4882a593Smuzhiyun
2285*4882a593Smuzhiyun spin_unlock_irqrestore(&rtlpriv->locks.c2hcmd_lock, flags);
2286*4882a593Smuzhiyun
2287*4882a593Smuzhiyun /* wake up wq */
2288*4882a593Smuzhiyun queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.c2hcmd_wq, 0);
2289*4882a593Smuzhiyun }
2290*4882a593Smuzhiyun EXPORT_SYMBOL(rtl_c2hcmd_enqueue);
2291*4882a593Smuzhiyun
rtl_c2h_content_parsing(struct ieee80211_hw * hw,struct sk_buff * skb)2292*4882a593Smuzhiyun static void rtl_c2h_content_parsing(struct ieee80211_hw *hw,
2293*4882a593Smuzhiyun struct sk_buff *skb)
2294*4882a593Smuzhiyun {
2295*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
2296*4882a593Smuzhiyun struct rtl_hal_ops *hal_ops = rtlpriv->cfg->ops;
2297*4882a593Smuzhiyun const struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops;
2298*4882a593Smuzhiyun u8 cmd_id, cmd_len;
2299*4882a593Smuzhiyun u8 *cmd_buf = NULL;
2300*4882a593Smuzhiyun
2301*4882a593Smuzhiyun cmd_id = GET_C2H_CMD_ID(skb->data);
2302*4882a593Smuzhiyun cmd_len = skb->len - C2H_DATA_OFFSET;
2303*4882a593Smuzhiyun cmd_buf = GET_C2H_DATA_PTR(skb->data);
2304*4882a593Smuzhiyun
2305*4882a593Smuzhiyun switch (cmd_id) {
2306*4882a593Smuzhiyun case C2H_DBG:
2307*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD, "[C2H], C2H_DBG!!\n");
2308*4882a593Smuzhiyun break;
2309*4882a593Smuzhiyun case C2H_TXBF:
2310*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE,
2311*4882a593Smuzhiyun "[C2H], C2H_TXBF!!\n");
2312*4882a593Smuzhiyun break;
2313*4882a593Smuzhiyun case C2H_TX_REPORT:
2314*4882a593Smuzhiyun rtl_tx_report_handler(hw, cmd_buf, cmd_len);
2315*4882a593Smuzhiyun break;
2316*4882a593Smuzhiyun case C2H_RA_RPT:
2317*4882a593Smuzhiyun if (hal_ops->c2h_ra_report_handler)
2318*4882a593Smuzhiyun hal_ops->c2h_ra_report_handler(hw, cmd_buf, cmd_len);
2319*4882a593Smuzhiyun break;
2320*4882a593Smuzhiyun case C2H_BT_INFO:
2321*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE,
2322*4882a593Smuzhiyun "[C2H], C2H_BT_INFO!!\n");
2323*4882a593Smuzhiyun if (rtlpriv->cfg->ops->get_btc_status())
2324*4882a593Smuzhiyun btc_ops->btc_btinfo_notify(rtlpriv, cmd_buf, cmd_len);
2325*4882a593Smuzhiyun break;
2326*4882a593Smuzhiyun case C2H_BT_MP:
2327*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE,
2328*4882a593Smuzhiyun "[C2H], C2H_BT_MP!!\n");
2329*4882a593Smuzhiyun if (rtlpriv->cfg->ops->get_btc_status())
2330*4882a593Smuzhiyun btc_ops->btc_btmpinfo_notify(rtlpriv, cmd_buf, cmd_len);
2331*4882a593Smuzhiyun break;
2332*4882a593Smuzhiyun default:
2333*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_FW, DBG_TRACE,
2334*4882a593Smuzhiyun "[C2H], Unknown packet!! cmd_id(%#X)!\n", cmd_id);
2335*4882a593Smuzhiyun break;
2336*4882a593Smuzhiyun }
2337*4882a593Smuzhiyun }
2338*4882a593Smuzhiyun
rtl_c2hcmd_launcher(struct ieee80211_hw * hw,int exec)2339*4882a593Smuzhiyun void rtl_c2hcmd_launcher(struct ieee80211_hw *hw, int exec)
2340*4882a593Smuzhiyun {
2341*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
2342*4882a593Smuzhiyun struct sk_buff *skb;
2343*4882a593Smuzhiyun unsigned long flags;
2344*4882a593Smuzhiyun int i;
2345*4882a593Smuzhiyun
2346*4882a593Smuzhiyun for (i = 0; i < 200; i++) {
2347*4882a593Smuzhiyun /* dequeue a task */
2348*4882a593Smuzhiyun spin_lock_irqsave(&rtlpriv->locks.c2hcmd_lock, flags);
2349*4882a593Smuzhiyun
2350*4882a593Smuzhiyun skb = __skb_dequeue(&rtlpriv->c2hcmd_queue);
2351*4882a593Smuzhiyun
2352*4882a593Smuzhiyun spin_unlock_irqrestore(&rtlpriv->locks.c2hcmd_lock, flags);
2353*4882a593Smuzhiyun
2354*4882a593Smuzhiyun /* do it */
2355*4882a593Smuzhiyun if (!skb)
2356*4882a593Smuzhiyun break;
2357*4882a593Smuzhiyun
2358*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG, "C2H rx_desc_shift=%d\n",
2359*4882a593Smuzhiyun *((u8 *)skb->cb));
2360*4882a593Smuzhiyun RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_DMESG,
2361*4882a593Smuzhiyun "C2H data: ", skb->data, skb->len);
2362*4882a593Smuzhiyun
2363*4882a593Smuzhiyun if (exec)
2364*4882a593Smuzhiyun rtl_c2h_content_parsing(hw, skb);
2365*4882a593Smuzhiyun
2366*4882a593Smuzhiyun /* free */
2367*4882a593Smuzhiyun dev_kfree_skb_any(skb);
2368*4882a593Smuzhiyun }
2369*4882a593Smuzhiyun }
2370*4882a593Smuzhiyun
rtl_c2hcmd_wq_callback(struct work_struct * work)2371*4882a593Smuzhiyun static void rtl_c2hcmd_wq_callback(struct work_struct *work)
2372*4882a593Smuzhiyun {
2373*4882a593Smuzhiyun struct rtl_works *rtlworks = container_of(work, struct rtl_works,
2374*4882a593Smuzhiyun c2hcmd_wq.work);
2375*4882a593Smuzhiyun struct ieee80211_hw *hw = rtlworks->hw;
2376*4882a593Smuzhiyun
2377*4882a593Smuzhiyun rtl_c2hcmd_launcher(hw, 1);
2378*4882a593Smuzhiyun }
2379*4882a593Smuzhiyun
rtl_easy_concurrent_retrytimer_callback(struct timer_list * t)2380*4882a593Smuzhiyun void rtl_easy_concurrent_retrytimer_callback(struct timer_list *t)
2381*4882a593Smuzhiyun {
2382*4882a593Smuzhiyun struct rtl_priv *rtlpriv =
2383*4882a593Smuzhiyun from_timer(rtlpriv, t, works.dualmac_easyconcurrent_retrytimer);
2384*4882a593Smuzhiyun struct ieee80211_hw *hw = rtlpriv->hw;
2385*4882a593Smuzhiyun struct rtl_priv *buddy_priv = rtlpriv->buddy_priv;
2386*4882a593Smuzhiyun
2387*4882a593Smuzhiyun if (buddy_priv == NULL)
2388*4882a593Smuzhiyun return;
2389*4882a593Smuzhiyun
2390*4882a593Smuzhiyun rtlpriv->cfg->ops->dualmac_easy_concurrent(hw);
2391*4882a593Smuzhiyun }
2392*4882a593Smuzhiyun
2393*4882a593Smuzhiyun /*********************************************************
2394*4882a593Smuzhiyun *
2395*4882a593Smuzhiyun * frame process functions
2396*4882a593Smuzhiyun *
2397*4882a593Smuzhiyun *********************************************************/
rtl_find_ie(u8 * data,unsigned int len,u8 ie)2398*4882a593Smuzhiyun u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie)
2399*4882a593Smuzhiyun {
2400*4882a593Smuzhiyun struct ieee80211_mgmt *mgmt = (void *)data;
2401*4882a593Smuzhiyun u8 *pos, *end;
2402*4882a593Smuzhiyun
2403*4882a593Smuzhiyun pos = (u8 *)mgmt->u.beacon.variable;
2404*4882a593Smuzhiyun end = data + len;
2405*4882a593Smuzhiyun while (pos < end) {
2406*4882a593Smuzhiyun if (pos + 2 + pos[1] > end)
2407*4882a593Smuzhiyun return NULL;
2408*4882a593Smuzhiyun
2409*4882a593Smuzhiyun if (pos[0] == ie)
2410*4882a593Smuzhiyun return pos;
2411*4882a593Smuzhiyun
2412*4882a593Smuzhiyun pos += 2 + pos[1];
2413*4882a593Smuzhiyun }
2414*4882a593Smuzhiyun return NULL;
2415*4882a593Smuzhiyun }
2416*4882a593Smuzhiyun
2417*4882a593Smuzhiyun /* when we use 2 rx ants we send IEEE80211_SMPS_OFF */
2418*4882a593Smuzhiyun /* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */
rtl_make_smps_action(struct ieee80211_hw * hw,enum ieee80211_smps_mode smps,u8 * da,u8 * bssid)2419*4882a593Smuzhiyun static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw,
2420*4882a593Smuzhiyun enum ieee80211_smps_mode smps,
2421*4882a593Smuzhiyun u8 *da, u8 *bssid)
2422*4882a593Smuzhiyun {
2423*4882a593Smuzhiyun struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
2424*4882a593Smuzhiyun struct sk_buff *skb;
2425*4882a593Smuzhiyun struct ieee80211_mgmt *action_frame;
2426*4882a593Smuzhiyun
2427*4882a593Smuzhiyun /* 27 = header + category + action + smps mode */
2428*4882a593Smuzhiyun skb = dev_alloc_skb(27 + hw->extra_tx_headroom);
2429*4882a593Smuzhiyun if (!skb)
2430*4882a593Smuzhiyun return NULL;
2431*4882a593Smuzhiyun
2432*4882a593Smuzhiyun skb_reserve(skb, hw->extra_tx_headroom);
2433*4882a593Smuzhiyun action_frame = skb_put_zero(skb, 27);
2434*4882a593Smuzhiyun memcpy(action_frame->da, da, ETH_ALEN);
2435*4882a593Smuzhiyun memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN);
2436*4882a593Smuzhiyun memcpy(action_frame->bssid, bssid, ETH_ALEN);
2437*4882a593Smuzhiyun action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2438*4882a593Smuzhiyun IEEE80211_STYPE_ACTION);
2439*4882a593Smuzhiyun action_frame->u.action.category = WLAN_CATEGORY_HT;
2440*4882a593Smuzhiyun action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
2441*4882a593Smuzhiyun switch (smps) {
2442*4882a593Smuzhiyun case IEEE80211_SMPS_AUTOMATIC:/* 0 */
2443*4882a593Smuzhiyun case IEEE80211_SMPS_NUM_MODES:/* 4 */
2444*4882a593Smuzhiyun WARN_ON(1);
2445*4882a593Smuzhiyun fallthrough;
2446*4882a593Smuzhiyun case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/
2447*4882a593Smuzhiyun action_frame->u.action.u.ht_smps.smps_control =
2448*4882a593Smuzhiyun WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */
2449*4882a593Smuzhiyun break;
2450*4882a593Smuzhiyun case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/
2451*4882a593Smuzhiyun action_frame->u.action.u.ht_smps.smps_control =
2452*4882a593Smuzhiyun WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */
2453*4882a593Smuzhiyun break;
2454*4882a593Smuzhiyun case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/
2455*4882a593Smuzhiyun action_frame->u.action.u.ht_smps.smps_control =
2456*4882a593Smuzhiyun WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */
2457*4882a593Smuzhiyun break;
2458*4882a593Smuzhiyun }
2459*4882a593Smuzhiyun
2460*4882a593Smuzhiyun return skb;
2461*4882a593Smuzhiyun }
2462*4882a593Smuzhiyun
rtl_send_smps_action(struct ieee80211_hw * hw,struct ieee80211_sta * sta,enum ieee80211_smps_mode smps)2463*4882a593Smuzhiyun int rtl_send_smps_action(struct ieee80211_hw *hw,
2464*4882a593Smuzhiyun struct ieee80211_sta *sta,
2465*4882a593Smuzhiyun enum ieee80211_smps_mode smps)
2466*4882a593Smuzhiyun {
2467*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
2468*4882a593Smuzhiyun struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
2469*4882a593Smuzhiyun struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
2470*4882a593Smuzhiyun struct sk_buff *skb = NULL;
2471*4882a593Smuzhiyun struct rtl_tcb_desc tcb_desc;
2472*4882a593Smuzhiyun u8 bssid[ETH_ALEN] = {0};
2473*4882a593Smuzhiyun
2474*4882a593Smuzhiyun memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
2475*4882a593Smuzhiyun
2476*4882a593Smuzhiyun if (rtlpriv->mac80211.act_scanning)
2477*4882a593Smuzhiyun goto err_free;
2478*4882a593Smuzhiyun
2479*4882a593Smuzhiyun if (!sta)
2480*4882a593Smuzhiyun goto err_free;
2481*4882a593Smuzhiyun
2482*4882a593Smuzhiyun if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
2483*4882a593Smuzhiyun goto err_free;
2484*4882a593Smuzhiyun
2485*4882a593Smuzhiyun if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
2486*4882a593Smuzhiyun goto err_free;
2487*4882a593Smuzhiyun
2488*4882a593Smuzhiyun if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP)
2489*4882a593Smuzhiyun memcpy(bssid, rtlpriv->efuse.dev_addr, ETH_ALEN);
2490*4882a593Smuzhiyun else
2491*4882a593Smuzhiyun memcpy(bssid, rtlpriv->mac80211.bssid, ETH_ALEN);
2492*4882a593Smuzhiyun
2493*4882a593Smuzhiyun skb = rtl_make_smps_action(hw, smps, sta->addr, bssid);
2494*4882a593Smuzhiyun /* this is a type = mgmt * stype = action frame */
2495*4882a593Smuzhiyun if (skb) {
2496*4882a593Smuzhiyun struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
2497*4882a593Smuzhiyun struct rtl_sta_info *sta_entry =
2498*4882a593Smuzhiyun (struct rtl_sta_info *) sta->drv_priv;
2499*4882a593Smuzhiyun sta_entry->mimo_ps = smps;
2500*4882a593Smuzhiyun /* rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0, true); */
2501*4882a593Smuzhiyun
2502*4882a593Smuzhiyun info->control.rates[0].idx = 0;
2503*4882a593Smuzhiyun info->band = hw->conf.chandef.chan->band;
2504*4882a593Smuzhiyun rtlpriv->intf_ops->adapter_tx(hw, sta, skb, &tcb_desc);
2505*4882a593Smuzhiyun }
2506*4882a593Smuzhiyun return 1;
2507*4882a593Smuzhiyun
2508*4882a593Smuzhiyun err_free:
2509*4882a593Smuzhiyun return 0;
2510*4882a593Smuzhiyun }
2511*4882a593Smuzhiyun EXPORT_SYMBOL(rtl_send_smps_action);
2512*4882a593Smuzhiyun
rtl_phy_scan_operation_backup(struct ieee80211_hw * hw,u8 operation)2513*4882a593Smuzhiyun void rtl_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
2514*4882a593Smuzhiyun {
2515*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
2516*4882a593Smuzhiyun struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
2517*4882a593Smuzhiyun enum io_type iotype;
2518*4882a593Smuzhiyun
2519*4882a593Smuzhiyun if (!is_hal_stop(rtlhal)) {
2520*4882a593Smuzhiyun switch (operation) {
2521*4882a593Smuzhiyun case SCAN_OPT_BACKUP:
2522*4882a593Smuzhiyun iotype = IO_CMD_PAUSE_DM_BY_SCAN;
2523*4882a593Smuzhiyun rtlpriv->cfg->ops->set_hw_reg(hw,
2524*4882a593Smuzhiyun HW_VAR_IO_CMD,
2525*4882a593Smuzhiyun (u8 *)&iotype);
2526*4882a593Smuzhiyun break;
2527*4882a593Smuzhiyun case SCAN_OPT_RESTORE:
2528*4882a593Smuzhiyun iotype = IO_CMD_RESUME_DM_BY_SCAN;
2529*4882a593Smuzhiyun rtlpriv->cfg->ops->set_hw_reg(hw,
2530*4882a593Smuzhiyun HW_VAR_IO_CMD,
2531*4882a593Smuzhiyun (u8 *)&iotype);
2532*4882a593Smuzhiyun break;
2533*4882a593Smuzhiyun default:
2534*4882a593Smuzhiyun pr_err("Unknown Scan Backup operation.\n");
2535*4882a593Smuzhiyun break;
2536*4882a593Smuzhiyun }
2537*4882a593Smuzhiyun }
2538*4882a593Smuzhiyun }
2539*4882a593Smuzhiyun EXPORT_SYMBOL(rtl_phy_scan_operation_backup);
2540*4882a593Smuzhiyun
2541*4882a593Smuzhiyun /* because mac80211 have issues when can receive del ba
2542*4882a593Smuzhiyun * so here we just make a fake del_ba if we receive a ba_req
2543*4882a593Smuzhiyun * but rx_agg was opened to let mac80211 release some ba
2544*4882a593Smuzhiyun * related resources, so please this del_ba for tx
2545*4882a593Smuzhiyun */
rtl_make_del_ba(struct ieee80211_hw * hw,u8 * sa,u8 * bssid,u16 tid)2546*4882a593Smuzhiyun struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
2547*4882a593Smuzhiyun u8 *sa, u8 *bssid, u16 tid)
2548*4882a593Smuzhiyun {
2549*4882a593Smuzhiyun struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
2550*4882a593Smuzhiyun struct sk_buff *skb;
2551*4882a593Smuzhiyun struct ieee80211_mgmt *action_frame;
2552*4882a593Smuzhiyun u16 params;
2553*4882a593Smuzhiyun
2554*4882a593Smuzhiyun /* 27 = header + category + action + smps mode */
2555*4882a593Smuzhiyun skb = dev_alloc_skb(34 + hw->extra_tx_headroom);
2556*4882a593Smuzhiyun if (!skb)
2557*4882a593Smuzhiyun return NULL;
2558*4882a593Smuzhiyun
2559*4882a593Smuzhiyun skb_reserve(skb, hw->extra_tx_headroom);
2560*4882a593Smuzhiyun action_frame = skb_put_zero(skb, 34);
2561*4882a593Smuzhiyun memcpy(action_frame->sa, sa, ETH_ALEN);
2562*4882a593Smuzhiyun memcpy(action_frame->da, rtlefuse->dev_addr, ETH_ALEN);
2563*4882a593Smuzhiyun memcpy(action_frame->bssid, bssid, ETH_ALEN);
2564*4882a593Smuzhiyun action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2565*4882a593Smuzhiyun IEEE80211_STYPE_ACTION);
2566*4882a593Smuzhiyun action_frame->u.action.category = WLAN_CATEGORY_BACK;
2567*4882a593Smuzhiyun action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
2568*4882a593Smuzhiyun params = (u16)(1 << 11); /* bit 11 initiator */
2569*4882a593Smuzhiyun params |= (u16)(tid << 12); /* bit 15:12 TID number */
2570*4882a593Smuzhiyun
2571*4882a593Smuzhiyun action_frame->u.action.u.delba.params = cpu_to_le16(params);
2572*4882a593Smuzhiyun action_frame->u.action.u.delba.reason_code =
2573*4882a593Smuzhiyun cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
2574*4882a593Smuzhiyun
2575*4882a593Smuzhiyun return skb;
2576*4882a593Smuzhiyun }
2577*4882a593Smuzhiyun
2578*4882a593Smuzhiyun /*********************************************************
2579*4882a593Smuzhiyun *
2580*4882a593Smuzhiyun * IOT functions
2581*4882a593Smuzhiyun *
2582*4882a593Smuzhiyun *********************************************************/
rtl_chk_vendor_ouisub(struct ieee80211_hw * hw,struct octet_string vendor_ie)2583*4882a593Smuzhiyun static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw,
2584*4882a593Smuzhiyun struct octet_string vendor_ie)
2585*4882a593Smuzhiyun {
2586*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
2587*4882a593Smuzhiyun bool matched = false;
2588*4882a593Smuzhiyun static u8 athcap_1[] = { 0x00, 0x03, 0x7F };
2589*4882a593Smuzhiyun static u8 athcap_2[] = { 0x00, 0x13, 0x74 };
2590*4882a593Smuzhiyun static u8 broadcap_1[] = { 0x00, 0x10, 0x18 };
2591*4882a593Smuzhiyun static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 };
2592*4882a593Smuzhiyun static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 };
2593*4882a593Smuzhiyun static u8 racap[] = { 0x00, 0x0c, 0x43 };
2594*4882a593Smuzhiyun static u8 ciscocap[] = { 0x00, 0x40, 0x96 };
2595*4882a593Smuzhiyun static u8 marvcap[] = { 0x00, 0x50, 0x43 };
2596*4882a593Smuzhiyun
2597*4882a593Smuzhiyun if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 ||
2598*4882a593Smuzhiyun memcmp(vendor_ie.octet, athcap_2, 3) == 0) {
2599*4882a593Smuzhiyun rtlpriv->mac80211.vendor = PEER_ATH;
2600*4882a593Smuzhiyun matched = true;
2601*4882a593Smuzhiyun } else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 ||
2602*4882a593Smuzhiyun memcmp(vendor_ie.octet, broadcap_2, 3) == 0 ||
2603*4882a593Smuzhiyun memcmp(vendor_ie.octet, broadcap_3, 3) == 0) {
2604*4882a593Smuzhiyun rtlpriv->mac80211.vendor = PEER_BROAD;
2605*4882a593Smuzhiyun matched = true;
2606*4882a593Smuzhiyun } else if (memcmp(vendor_ie.octet, racap, 3) == 0) {
2607*4882a593Smuzhiyun rtlpriv->mac80211.vendor = PEER_RAL;
2608*4882a593Smuzhiyun matched = true;
2609*4882a593Smuzhiyun } else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) {
2610*4882a593Smuzhiyun rtlpriv->mac80211.vendor = PEER_CISCO;
2611*4882a593Smuzhiyun matched = true;
2612*4882a593Smuzhiyun } else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) {
2613*4882a593Smuzhiyun rtlpriv->mac80211.vendor = PEER_MARV;
2614*4882a593Smuzhiyun matched = true;
2615*4882a593Smuzhiyun }
2616*4882a593Smuzhiyun
2617*4882a593Smuzhiyun return matched;
2618*4882a593Smuzhiyun }
2619*4882a593Smuzhiyun
rtl_find_221_ie(struct ieee80211_hw * hw,u8 * data,unsigned int len)2620*4882a593Smuzhiyun static bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data,
2621*4882a593Smuzhiyun unsigned int len)
2622*4882a593Smuzhiyun {
2623*4882a593Smuzhiyun struct ieee80211_mgmt *mgmt = (void *)data;
2624*4882a593Smuzhiyun struct octet_string vendor_ie;
2625*4882a593Smuzhiyun u8 *pos, *end;
2626*4882a593Smuzhiyun
2627*4882a593Smuzhiyun pos = (u8 *)mgmt->u.beacon.variable;
2628*4882a593Smuzhiyun end = data + len;
2629*4882a593Smuzhiyun while (pos < end) {
2630*4882a593Smuzhiyun if (pos[0] == 221) {
2631*4882a593Smuzhiyun vendor_ie.length = pos[1];
2632*4882a593Smuzhiyun vendor_ie.octet = &pos[2];
2633*4882a593Smuzhiyun if (rtl_chk_vendor_ouisub(hw, vendor_ie))
2634*4882a593Smuzhiyun return true;
2635*4882a593Smuzhiyun }
2636*4882a593Smuzhiyun
2637*4882a593Smuzhiyun if (pos + 2 + pos[1] > end)
2638*4882a593Smuzhiyun return false;
2639*4882a593Smuzhiyun
2640*4882a593Smuzhiyun pos += 2 + pos[1];
2641*4882a593Smuzhiyun }
2642*4882a593Smuzhiyun return false;
2643*4882a593Smuzhiyun }
2644*4882a593Smuzhiyun
rtl_recognize_peer(struct ieee80211_hw * hw,u8 * data,unsigned int len)2645*4882a593Smuzhiyun void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
2646*4882a593Smuzhiyun {
2647*4882a593Smuzhiyun struct rtl_priv *rtlpriv = rtl_priv(hw);
2648*4882a593Smuzhiyun struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
2649*4882a593Smuzhiyun struct ieee80211_hdr *hdr = (void *)data;
2650*4882a593Smuzhiyun u32 vendor = PEER_UNKNOWN;
2651*4882a593Smuzhiyun
2652*4882a593Smuzhiyun static u8 ap3_1[3] = { 0x00, 0x14, 0xbf };
2653*4882a593Smuzhiyun static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 };
2654*4882a593Smuzhiyun static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e };
2655*4882a593Smuzhiyun static u8 ap4_1[3] = { 0x00, 0x90, 0xcc };
2656*4882a593Smuzhiyun static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e };
2657*4882a593Smuzhiyun static u8 ap4_3[3] = { 0x00, 0x18, 0x02 };
2658*4882a593Smuzhiyun static u8 ap4_4[3] = { 0x00, 0x17, 0x3f };
2659*4882a593Smuzhiyun static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf };
2660*4882a593Smuzhiyun static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 };
2661*4882a593Smuzhiyun static u8 ap5_2[3] = { 0x00, 0x21, 0x91 };
2662*4882a593Smuzhiyun static u8 ap5_3[3] = { 0x00, 0x24, 0x01 };
2663*4882a593Smuzhiyun static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 };
2664*4882a593Smuzhiyun static u8 ap5_5[3] = { 0x00, 0x17, 0x9A };
2665*4882a593Smuzhiyun static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 };
2666*4882a593Smuzhiyun static u8 ap6_1[3] = { 0x00, 0x17, 0x94 };
2667*4882a593Smuzhiyun static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 };
2668*4882a593Smuzhiyun
2669*4882a593Smuzhiyun if (mac->opmode != NL80211_IFTYPE_STATION)
2670*4882a593Smuzhiyun return;
2671*4882a593Smuzhiyun
2672*4882a593Smuzhiyun if (mac->link_state == MAC80211_NOLINK) {
2673*4882a593Smuzhiyun mac->vendor = PEER_UNKNOWN;
2674*4882a593Smuzhiyun return;
2675*4882a593Smuzhiyun }
2676*4882a593Smuzhiyun
2677*4882a593Smuzhiyun if (mac->cnt_after_linked > 2)
2678*4882a593Smuzhiyun return;
2679*4882a593Smuzhiyun
2680*4882a593Smuzhiyun /* check if this really is a beacon */
2681*4882a593Smuzhiyun if (!ieee80211_is_beacon(hdr->frame_control))
2682*4882a593Smuzhiyun return;
2683*4882a593Smuzhiyun
2684*4882a593Smuzhiyun /* min. beacon length + FCS_LEN */
2685*4882a593Smuzhiyun if (len <= 40 + FCS_LEN)
2686*4882a593Smuzhiyun return;
2687*4882a593Smuzhiyun
2688*4882a593Smuzhiyun /* and only beacons from the associated BSSID, please */
2689*4882a593Smuzhiyun if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
2690*4882a593Smuzhiyun return;
2691*4882a593Smuzhiyun
2692*4882a593Smuzhiyun if (rtl_find_221_ie(hw, data, len))
2693*4882a593Smuzhiyun vendor = mac->vendor;
2694*4882a593Smuzhiyun
2695*4882a593Smuzhiyun if ((memcmp(mac->bssid, ap5_1, 3) == 0) ||
2696*4882a593Smuzhiyun (memcmp(mac->bssid, ap5_2, 3) == 0) ||
2697*4882a593Smuzhiyun (memcmp(mac->bssid, ap5_3, 3) == 0) ||
2698*4882a593Smuzhiyun (memcmp(mac->bssid, ap5_4, 3) == 0) ||
2699*4882a593Smuzhiyun (memcmp(mac->bssid, ap5_5, 3) == 0) ||
2700*4882a593Smuzhiyun (memcmp(mac->bssid, ap5_6, 3) == 0) ||
2701*4882a593Smuzhiyun vendor == PEER_ATH) {
2702*4882a593Smuzhiyun vendor = PEER_ATH;
2703*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>ath find\n");
2704*4882a593Smuzhiyun } else if ((memcmp(mac->bssid, ap4_4, 3) == 0) ||
2705*4882a593Smuzhiyun (memcmp(mac->bssid, ap4_5, 3) == 0) ||
2706*4882a593Smuzhiyun (memcmp(mac->bssid, ap4_1, 3) == 0) ||
2707*4882a593Smuzhiyun (memcmp(mac->bssid, ap4_2, 3) == 0) ||
2708*4882a593Smuzhiyun (memcmp(mac->bssid, ap4_3, 3) == 0) ||
2709*4882a593Smuzhiyun vendor == PEER_RAL) {
2710*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>ral find\n");
2711*4882a593Smuzhiyun vendor = PEER_RAL;
2712*4882a593Smuzhiyun } else if (memcmp(mac->bssid, ap6_1, 3) == 0 ||
2713*4882a593Smuzhiyun vendor == PEER_CISCO) {
2714*4882a593Smuzhiyun vendor = PEER_CISCO;
2715*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>cisco find\n");
2716*4882a593Smuzhiyun } else if ((memcmp(mac->bssid, ap3_1, 3) == 0) ||
2717*4882a593Smuzhiyun (memcmp(mac->bssid, ap3_2, 3) == 0) ||
2718*4882a593Smuzhiyun (memcmp(mac->bssid, ap3_3, 3) == 0) ||
2719*4882a593Smuzhiyun vendor == PEER_BROAD) {
2720*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>broad find\n");
2721*4882a593Smuzhiyun vendor = PEER_BROAD;
2722*4882a593Smuzhiyun } else if (memcmp(mac->bssid, ap7_1, 3) == 0 ||
2723*4882a593Smuzhiyun vendor == PEER_MARV) {
2724*4882a593Smuzhiyun vendor = PEER_MARV;
2725*4882a593Smuzhiyun rtl_dbg(rtlpriv, COMP_MAC80211, DBG_LOUD, "=>marv find\n");
2726*4882a593Smuzhiyun }
2727*4882a593Smuzhiyun
2728*4882a593Smuzhiyun mac->vendor = vendor;
2729*4882a593Smuzhiyun }
2730*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_recognize_peer);
2731*4882a593Smuzhiyun
2732*4882a593Smuzhiyun MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
2733*4882a593Smuzhiyun MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
2734*4882a593Smuzhiyun MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
2735*4882a593Smuzhiyun MODULE_LICENSE("GPL");
2736*4882a593Smuzhiyun MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
2737*4882a593Smuzhiyun
2738*4882a593Smuzhiyun struct rtl_global_var rtl_global_var = {};
2739*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl_global_var);
2740*4882a593Smuzhiyun
rtl_core_module_init(void)2741*4882a593Smuzhiyun static int __init rtl_core_module_init(void)
2742*4882a593Smuzhiyun {
2743*4882a593Smuzhiyun BUILD_BUG_ON(TX_PWR_BY_RATE_NUM_RATE < TX_PWR_BY_RATE_NUM_SECTION);
2744*4882a593Smuzhiyun BUILD_BUG_ON(MAX_RATE_SECTION_NUM != MAX_RATE_SECTION);
2745*4882a593Smuzhiyun BUILD_BUG_ON(MAX_BASE_NUM_IN_PHY_REG_PG_24G != MAX_RATE_SECTION);
2746*4882a593Smuzhiyun BUILD_BUG_ON(MAX_BASE_NUM_IN_PHY_REG_PG_5G != (MAX_RATE_SECTION - 1));
2747*4882a593Smuzhiyun
2748*4882a593Smuzhiyun if (rtl_rate_control_register())
2749*4882a593Smuzhiyun pr_err("rtl: Unable to register rtl_rc, use default RC !!\n");
2750*4882a593Smuzhiyun
2751*4882a593Smuzhiyun /* add debugfs */
2752*4882a593Smuzhiyun rtl_debugfs_add_topdir();
2753*4882a593Smuzhiyun
2754*4882a593Smuzhiyun /* init some global vars */
2755*4882a593Smuzhiyun INIT_LIST_HEAD(&rtl_global_var.glb_priv_list);
2756*4882a593Smuzhiyun spin_lock_init(&rtl_global_var.glb_list_lock);
2757*4882a593Smuzhiyun
2758*4882a593Smuzhiyun return 0;
2759*4882a593Smuzhiyun }
2760*4882a593Smuzhiyun
rtl_core_module_exit(void)2761*4882a593Smuzhiyun static void __exit rtl_core_module_exit(void)
2762*4882a593Smuzhiyun {
2763*4882a593Smuzhiyun /*RC*/
2764*4882a593Smuzhiyun rtl_rate_control_unregister();
2765*4882a593Smuzhiyun
2766*4882a593Smuzhiyun /* remove debugfs */
2767*4882a593Smuzhiyun rtl_debugfs_remove_topdir();
2768*4882a593Smuzhiyun }
2769*4882a593Smuzhiyun
2770*4882a593Smuzhiyun module_init(rtl_core_module_init);
2771*4882a593Smuzhiyun module_exit(rtl_core_module_exit);
2772