2 ******************************************************************************
4 * @file ecrnx_mod_params.c
6 * @brief Set configuration according to modules parameters
8 * Copyright (C) ESWIN 2015-2020
10 ******************************************************************************
12 #include <linux/module.h>
13 #include <linux/rtnetlink.h>
15 #include "ecrnx_defs.h"
18 #include "ecrnx_cfgfile.h"
19 #include "reg_access.h"
20 #include "ecrnx_compat.h"
22 #ifdef CONFIG_ECRNX_SOFTMAC
23 #define COMMON_PARAM(name, default_softmac, default_fullmac) \
24 .name = default_softmac,
25 #define SOFTMAC_PARAM(name, default) .name = default,
26 #define FULLMAC_PARAM(name, default)
28 #define COMMON_PARAM(name, default_softmac, default_fullmac) \
29 .name = default_fullmac,
30 #define SOFTMAC_PARAM(name, default)
31 #define FULLMAC_PARAM(name, default) .name = default,
32 #endif /* CONFIG_ECRNX_SOFTMAC */
34 struct ecrnx_mod_params ecrnx_mod_params = {
35 /* common parameters */
36 COMMON_PARAM(ht_on, true, true)
37 COMMON_PARAM(vht_on, false, false)
38 COMMON_PARAM(he_on, true, true)
39 #ifdef CONFIG_6600_HAL
40 COMMON_PARAM(he_mcs_map, IEEE80211_HE_MCS_SUPPORT_0_7, IEEE80211_HE_MCS_SUPPORT_0_7)
42 COMMON_PARAM(he_mcs_map, IEEE80211_HE_MCS_SUPPORT_0_9, IEEE80211_HE_MCS_SUPPORT_0_9)
44 COMMON_PARAM(he_ul_on, false, false)
45 COMMON_PARAM(ldpc_on, false, false)
46 COMMON_PARAM(stbc_on, false, false)
47 COMMON_PARAM(gf_rx_on, true, true)
48 COMMON_PARAM(phy_cfg, 0, 0)
49 COMMON_PARAM(uapsd_timeout, 300, 300)
50 COMMON_PARAM(ap_uapsd_on, true, true)
51 COMMON_PARAM(sgi, true, true)
52 COMMON_PARAM(sgi80, true, true)
53 COMMON_PARAM(use_2040, 1, 1)
54 COMMON_PARAM(nss, 1, 1)
55 COMMON_PARAM(amsdu_rx_max, 2, 2)
56 COMMON_PARAM(bfmee, true, true)
57 COMMON_PARAM(bfmer, true, true)
58 COMMON_PARAM(mesh, true, true)
59 COMMON_PARAM(murx, true, true)
60 COMMON_PARAM(mutx, true, true)
61 COMMON_PARAM(mutx_on, true, true)
62 COMMON_PARAM(use_80, false, false)
63 COMMON_PARAM(custregd, false, false)
64 COMMON_PARAM(custchan, false, false)
65 COMMON_PARAM(roc_dur_max, 500, 500)
66 COMMON_PARAM(listen_itv, 0, 0)
67 COMMON_PARAM(listen_bcmc, true, true)
68 COMMON_PARAM(lp_clk_ppm, 20, 20)
69 COMMON_PARAM(ps_on, true, true)
70 COMMON_PARAM(tx_lft, ECRNX_TX_LIFETIME_MS, ECRNX_TX_LIFETIME_MS)
71 COMMON_PARAM(amsdu_maxnb, NX_TX_PAYLOAD_MAX, NX_TX_PAYLOAD_MAX)
72 // By default, only enable UAPSD for Voice queue (see IEEE80211_DEFAULT_UAPSD_QUEUE comment)
73 COMMON_PARAM(uapsd_queues, IEEE80211_WMM_IE_STA_QOSINFO_AC_VO, IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
74 COMMON_PARAM(tdls, true, true)
75 COMMON_PARAM(uf, true, true)
76 COMMON_PARAM(ftl, "", "")
77 COMMON_PARAM(dpsm, true, true)
78 COMMON_PARAM(tx_to_bk, 0, 0)
79 COMMON_PARAM(tx_to_be, 0, 0)
80 COMMON_PARAM(tx_to_vi, 0, 0)
81 COMMON_PARAM(tx_to_vo, 0, 0)
83 /* SOFTMAC only parameters */
84 SOFTMAC_PARAM(mfp_on, false)
85 SOFTMAC_PARAM(gf_on, false)
86 SOFTMAC_PARAM(bwsig_on, true)
87 SOFTMAC_PARAM(dynbw_on, true)
88 SOFTMAC_PARAM(agg_tx, true)
89 SOFTMAC_PARAM(amsdu_force, 0)
90 SOFTMAC_PARAM(rc_probes_on, false)
91 SOFTMAC_PARAM(cmon, true)
92 SOFTMAC_PARAM(hwscan, true)
93 SOFTMAC_PARAM(autobcn, true)
95 /* FULLMAC only parameters */
96 FULLMAC_PARAM(ant_div, false)
99 #ifdef CONFIG_ECRNX_SOFTMAC
100 /* SOFTMAC specific parameters */
101 module_param_named(mfp_on, ecrnx_mod_params.mfp_on, bool, S_IRUGO);
102 MODULE_PARM_DESC(mfp_on, "Enable MFP (11w) (Default: 0)");
104 module_param_named(gf_on, ecrnx_mod_params.gf_on, bool, S_IRUGO | S_IWUSR);
105 MODULE_PARM_DESC(gf_on, "Try TXing Green Field if peer supports it (Default: 0)");
107 module_param_named(bwsig_on, ecrnx_mod_params.bwsig_on, bool, S_IRUGO | S_IWUSR);
108 MODULE_PARM_DESC(bwsig_on, "Enable bandwidth signaling (VHT tx) (Default: 1)");
110 module_param_named(dynbw_on, ecrnx_mod_params.dynbw_on, bool, S_IRUGO | S_IWUSR);
111 MODULE_PARM_DESC(dynbw_on, "Enable dynamic bandwidth (VHT tx) (Default: 1)");
113 module_param_named(agg_tx, ecrnx_mod_params.agg_tx, bool, S_IRUGO);
114 MODULE_PARM_DESC(agg_tx, "Use A-MPDU in TX (Default: 1)");
116 module_param_named(amsdu_force, ecrnx_mod_params.amsdu_force, int, S_IRUGO | S_IWUSR);
117 MODULE_PARM_DESC(amsdu_force, "Use A-MSDU in TX: 0-if advertised, 1-yes, 2-no (Default: 0)");
119 module_param_named(rc_probes_on, ecrnx_mod_params.rc_probes_on, bool, S_IRUGO | S_IWUSR);
120 MODULE_PARM_DESC(rc_probes_on, "IEEE80211_TX_CTL_RATE_CTRL_PROBE is 1st in AMPDU (Default: 0)");
122 module_param_named(cmon, ecrnx_mod_params.cmon, bool, S_IRUGO);
123 MODULE_PARM_DESC(cmon, "Connection monitoring work handled by the FW (Default: 1)");
125 module_param_named(hwscan, ecrnx_mod_params.hwscan, bool, S_IRUGO);
126 MODULE_PARM_DESC(hwscan, "Scan work handled by the FW (Default: 1)");
128 module_param_named(autobcn, ecrnx_mod_params.autobcn, bool, S_IRUGO);
129 MODULE_PARM_DESC(autobcn, "Beacon transmission done autonomously by the FW (Default: 1)");
132 /* FULLMAC specific parameters*/
133 module_param_named(ant_div, ecrnx_mod_params.ant_div, bool, S_IRUGO);
134 MODULE_PARM_DESC(ant_div, "Enable Antenna Diversity (Default: 0)");
135 #endif /* CONFIG_ECRNX_SOFTMAC */
137 module_param_named(ht_on, ecrnx_mod_params.ht_on, bool, S_IRUGO);
138 MODULE_PARM_DESC(ht_on, "Enable HT (Default: 1)");
140 module_param_named(vht_on, ecrnx_mod_params.vht_on, bool, S_IRUGO);
141 MODULE_PARM_DESC(vht_on, "Enable VHT (Default: 1)");
143 module_param_named(he_on, ecrnx_mod_params.he_on, bool, S_IRUGO);
144 MODULE_PARM_DESC(he_on, "Enable HE (Default: 1)");
146 module_param_named(mcs_map, ecrnx_mod_params.mcs_map, int, S_IRUGO);
147 MODULE_PARM_DESC(mcs_map, "VHT MCS map value 0: MCS0_7, 1: MCS0_8, 2: MCS0_9"
150 module_param_named(he_mcs_map, ecrnx_mod_params.he_mcs_map, int, S_IRUGO);
151 MODULE_PARM_DESC(he_mcs_map, "HE MCS map value 0: MCS0_7, 1: MCS0_9, 2: MCS0_11"
154 module_param_named(he_ul_on, ecrnx_mod_params.he_ul_on, bool, S_IRUGO);
155 MODULE_PARM_DESC(he_ul_on, "Enable HE OFDMA UL (Default: 0)");
157 module_param_named(amsdu_maxnb, ecrnx_mod_params.amsdu_maxnb, int, S_IRUGO | S_IWUSR);
158 MODULE_PARM_DESC(amsdu_maxnb, "Maximum number of MSDUs inside an A-MSDU in TX: (Default: NX_TX_PAYLOAD_MAX)");
160 module_param_named(ps_on, ecrnx_mod_params.ps_on, bool, S_IRUGO);
161 MODULE_PARM_DESC(ps_on, "Enable PowerSaving (Default: 1-Enabled)");
163 module_param_named(tx_lft, ecrnx_mod_params.tx_lft, int, 0644);
164 MODULE_PARM_DESC(tx_lft, "Tx lifetime (ms) - setting it to 0 disables retries "
165 "(Default: "__stringify(ECRNX_TX_LIFETIME_MS)")");
167 module_param_named(ldpc_on, ecrnx_mod_params.ldpc_on, bool, S_IRUGO);
168 MODULE_PARM_DESC(ldpc_on, "Enable LDPC (Default: 1)");
170 module_param_named(stbc_on, ecrnx_mod_params.stbc_on, bool, S_IRUGO);
171 MODULE_PARM_DESC(stbc_on, "Enable STBC in RX (Default: 1)");
173 module_param_named(gf_rx_on, ecrnx_mod_params.gf_rx_on, bool, S_IRUGO);
174 MODULE_PARM_DESC(gf_rx_on, "Enable HT greenfield in reception (Default: 1)");
176 module_param_named(phycfg, ecrnx_mod_params.phy_cfg, int, S_IRUGO);
177 MODULE_PARM_DESC(phycfg, "Main RF Path (Default: 0)");
179 module_param_named(uapsd_timeout, ecrnx_mod_params.uapsd_timeout, int, S_IRUGO | S_IWUSR);
180 MODULE_PARM_DESC(uapsd_timeout,
181 "UAPSD Timer timeout, in ms (Default: 300). If 0, UAPSD is disabled");
183 module_param_named(uapsd_queues, ecrnx_mod_params.uapsd_queues, int, S_IRUGO | S_IWUSR);
184 MODULE_PARM_DESC(uapsd_queues, "UAPSD Queues, integer value, must be seen as a bitfield\n"
189 " -> uapsd_queues=7 will enable uapsd for VO, VI and BK queues");
191 module_param_named(ap_uapsd_on, ecrnx_mod_params.ap_uapsd_on, bool, S_IRUGO);
192 MODULE_PARM_DESC(ap_uapsd_on, "Enable UAPSD in AP mode (Default: 1)");
194 module_param_named(sgi, ecrnx_mod_params.sgi, bool, S_IRUGO);
195 MODULE_PARM_DESC(sgi, "Advertise Short Guard Interval support (Default: 1)");
197 module_param_named(sgi80, ecrnx_mod_params.sgi80, bool, S_IRUGO);
198 MODULE_PARM_DESC(sgi80, "Advertise Short Guard Interval support for 80MHz (Default: 1)");
200 module_param_named(use_2040, ecrnx_mod_params.use_2040, bool, S_IRUGO);
201 MODULE_PARM_DESC(use_2040, "Enable 40MHz (Default: 1)");
203 module_param_named(use_80, ecrnx_mod_params.use_80, bool, S_IRUGO);
204 MODULE_PARM_DESC(use_80, "Enable 80MHz (Default: 1)");
206 module_param_named(custregd, ecrnx_mod_params.custregd, bool, S_IRUGO);
207 MODULE_PARM_DESC(custregd,
208 "Use permissive custom regulatory rules (for testing ONLY) (Default: 0)");
210 module_param_named(custchan, ecrnx_mod_params.custchan, bool, S_IRUGO);
211 MODULE_PARM_DESC(custchan,
212 "Extend channel set to non-standard channels (for testing ONLY) (Default: 0)");
214 module_param_named(nss, ecrnx_mod_params.nss, int, S_IRUGO);
215 MODULE_PARM_DESC(nss, "1 <= nss <= 2 : Supported number of Spatial Streams (Default: 2)");
217 module_param_named(amsdu_rx_max, ecrnx_mod_params.amsdu_rx_max, int, S_IRUGO);
218 MODULE_PARM_DESC(amsdu_rx_max, "0 <= amsdu_rx_max <= 2 : Maximum A-MSDU size supported in RX\n"
222 " This value might be reduced according to the FW capabilities.\n"
225 module_param_named(bfmee, ecrnx_mod_params.bfmee, bool, S_IRUGO);
226 MODULE_PARM_DESC(bfmee, "Enable Beamformee Capability (Default: 1-Enabled)");
228 module_param_named(bfmer, ecrnx_mod_params.bfmer, bool, S_IRUGO);
229 MODULE_PARM_DESC(bfmer, "Enable Beamformer Capability (Default: 1-Enabled)");
231 module_param_named(mesh, ecrnx_mod_params.mesh, bool, S_IRUGO);
232 MODULE_PARM_DESC(mesh, "Enable Meshing Capability (Default: 1-Enabled)");
234 module_param_named(murx, ecrnx_mod_params.murx, bool, S_IRUGO);
235 MODULE_PARM_DESC(murx, "Enable MU-MIMO RX Capability (Default: 1-Enabled)");
237 module_param_named(mutx, ecrnx_mod_params.mutx, bool, S_IRUGO);
238 MODULE_PARM_DESC(mutx, "Enable MU-MIMO TX Capability (Default: 1-Enabled)");
240 module_param_named(mutx_on, ecrnx_mod_params.mutx_on, bool, S_IRUGO | S_IWUSR);
241 MODULE_PARM_DESC(mutx_on, "Enable MU-MIMO transmissions (Default: 1-Enabled)");
243 module_param_named(roc_dur_max, ecrnx_mod_params.roc_dur_max, int, S_IRUGO);
244 MODULE_PARM_DESC(roc_dur_max, "Maximum Remain on Channel duration");
246 module_param_named(listen_itv, ecrnx_mod_params.listen_itv, int, S_IRUGO);
247 MODULE_PARM_DESC(listen_itv, "Maximum listen interval");
249 module_param_named(listen_bcmc, ecrnx_mod_params.listen_bcmc, bool, S_IRUGO);
250 MODULE_PARM_DESC(listen_bcmc, "Wait for BC/MC traffic following DTIM beacon");
252 module_param_named(lp_clk_ppm, ecrnx_mod_params.lp_clk_ppm, int, S_IRUGO);
253 MODULE_PARM_DESC(lp_clk_ppm, "Low Power Clock accuracy of the local device");
255 module_param_named(tdls, ecrnx_mod_params.tdls, bool, S_IRUGO);
256 MODULE_PARM_DESC(tdls, "Enable TDLS (Default: 1-Enabled)");
258 module_param_named(uf, ecrnx_mod_params.uf, bool, S_IRUGO | S_IWUSR);
259 MODULE_PARM_DESC(uf, "Enable Unsupported HT Frame Logging (Default: 1-Enabled)");
261 module_param_named(ftl, ecrnx_mod_params.ftl, charp, S_IRUGO);
262 MODULE_PARM_DESC(ftl, "Firmware trace level (Default: \"\")");
264 module_param_named(dpsm, ecrnx_mod_params.dpsm, bool, S_IRUGO);
265 MODULE_PARM_DESC(dpsm, "Enable Dynamic PowerSaving (Default: 1-Enabled)");
266 module_param_named(tx_to_bk, ecrnx_mod_params.tx_to_bk, int, S_IRUGO);
267 MODULE_PARM_DESC(tx_to_bk,
268 "TX timeout for BK, in ms (Default: 0, Max: 65535). If 0, default value is applied");
269 module_param_named(tx_to_be, ecrnx_mod_params.tx_to_be, int, S_IRUGO);
270 MODULE_PARM_DESC(tx_to_be,
271 "TX timeout for BE, in ms (Default: 0, Max: 65535). If 0, default value is applied");
272 module_param_named(tx_to_vi, ecrnx_mod_params.tx_to_vi, int, S_IRUGO);
273 MODULE_PARM_DESC(tx_to_vi,
274 "TX timeout for VI, in ms (Default: 0, Max: 65535). If 0, default value is applied");
275 module_param_named(tx_to_vo, ecrnx_mod_params.tx_to_vo, int, S_IRUGO);
276 MODULE_PARM_DESC(tx_to_vo,
277 "TX timeout for VO, in ms (Default: 0, Max: 65535). If 0, default value is applied");
279 /* Regulatory rules */
280 static struct ieee80211_regdomain ecrnx_regdom = {
284 REG_RULE(2390 - 10, 2510 + 10, 40, 0, 1000, 0),
285 REG_RULE(5150 - 10, 5970 + 10, 80, 0, 1000, 0),
289 static const int mcs_map_to_rate[4][3] = {
290 [PHY_CHNL_BW_20][IEEE80211_VHT_MCS_SUPPORT_0_7] = 65,
291 [PHY_CHNL_BW_20][IEEE80211_VHT_MCS_SUPPORT_0_8] = 78,
292 [PHY_CHNL_BW_20][IEEE80211_VHT_MCS_SUPPORT_0_9] = 78,
293 [PHY_CHNL_BW_40][IEEE80211_VHT_MCS_SUPPORT_0_7] = 135,
294 [PHY_CHNL_BW_40][IEEE80211_VHT_MCS_SUPPORT_0_8] = 162,
295 [PHY_CHNL_BW_40][IEEE80211_VHT_MCS_SUPPORT_0_9] = 180,
296 [PHY_CHNL_BW_80][IEEE80211_VHT_MCS_SUPPORT_0_7] = 292,
297 [PHY_CHNL_BW_80][IEEE80211_VHT_MCS_SUPPORT_0_8] = 351,
298 [PHY_CHNL_BW_80][IEEE80211_VHT_MCS_SUPPORT_0_9] = 390,
299 [PHY_CHNL_BW_160][IEEE80211_VHT_MCS_SUPPORT_0_7] = 585,
300 [PHY_CHNL_BW_160][IEEE80211_VHT_MCS_SUPPORT_0_8] = 702,
301 [PHY_CHNL_BW_160][IEEE80211_VHT_MCS_SUPPORT_0_9] = 780,
304 #define MAX_VHT_RATE(map, nss, bw) (mcs_map_to_rate[bw][map] * (nss))
306 #if defined(CONFIG_ECRNX_HE)
307 struct ieee80211_sta_he_cap ecrnx_he_cap;
311 * Do some sanity check
314 static int ecrnx_check_fw_hw_feature(struct ecrnx_hw *ecrnx_hw,
317 u32_l sys_feat = ecrnx_hw->version_cfm.features;
318 u32_l mac_feat = ecrnx_hw->version_cfm.version_machw_1;
319 u32_l phy_feat = ecrnx_hw->version_cfm.version_phy_1;
320 u32_l phy_vers = ecrnx_hw->version_cfm.version_phy_2;
321 u16_l max_sta_nb = ecrnx_hw->version_cfm.max_sta_nb;
322 u8_l max_vif_nb = ecrnx_hw->version_cfm.max_vif_nb;
326 if (!ecrnx_hw->mod_params->custregd)
327 ecrnx_hw->mod_params->custchan = false;
329 if (ecrnx_hw->mod_params->custchan) {
330 #ifdef CONFIG_ECRNX_SOFTMAC
331 ecrnx_hw->mod_params->autobcn = false;
332 ecrnx_hw->mod_params->hwscan = false;
333 sys_feat &= ~BIT(MM_FEAT_CMON_BIT);
335 ecrnx_hw->mod_params->mesh = false;
336 ecrnx_hw->mod_params->tdls = false;
339 #ifdef CONFIG_ECRNX_SOFTMAC
340 if (sys_feat & BIT(MM_FEAT_UMAC_BIT)) {
341 wiphy_err(wiphy, "Loading fullmac firmware with softmac driver\n");
345 if (sys_feat & BIT(MM_FEAT_AUTOBCN_BIT) &&
346 !ecrnx_hw->mod_params->autobcn) {
348 "Auto beacon enabled in firmware but disabled in driver\n");
352 if (!!(sys_feat & BIT(MM_FEAT_HWSCAN_BIT)) !=
353 !!ecrnx_hw->mod_params->hwscan) {
355 "hwscan %sabled in firmware but %sabled in driver\n",
356 (sys_feat & BIT(MM_FEAT_HWSCAN_BIT)) ? "en" : "dis",
357 ecrnx_hw->mod_params->hwscan ? "en" : "dis");
361 if (sys_feat & BIT(MM_FEAT_CMON_BIT)) {
362 ieee80211_hw_set(ecrnx_hw->hw, CONNECTION_MONITOR);
365 /* AMPDU (non)support implies different shared structure definition
366 so insure that fw and drv have consistent compilation option */
367 if (sys_feat & BIT(MM_FEAT_AMPDU_BIT)) {
368 #ifndef CONFIG_ECRNX_AGG_TX
370 "AMPDU enabled in firmware but support not compiled in driver\n");
372 #endif /* CONFIG_ECRNX_AGG_TX */
374 #ifdef CONFIG_ECRNX_AGG_TX
376 "AMPDU disabled in firmware but support compiled in driver\n");
379 ecrnx_hw->mod_params->agg_tx = false;
380 #endif /* CONFIG_ECRNX_AGG_TX */
383 if (!(sys_feat & BIT(MM_FEAT_DPSM_BIT))) {
384 ecrnx_hw->mod_params->dpsm = false;
387 #else /* check for FULLMAC */
389 if (!(sys_feat & BIT(MM_FEAT_UMAC_BIT))) {
391 "Loading softmac firmware with fullmac driver\n");
395 if (!(sys_feat & BIT(MM_FEAT_ANT_DIV_BIT))) {
396 ecrnx_hw->mod_params->ant_div = false;
399 #endif /* CONFIG_ECRNX_SOFTMAC */
401 if (!(sys_feat & BIT(MM_FEAT_VHT_BIT))) {
402 ecrnx_hw->mod_params->vht_on = false;
405 // Check if HE is supported
406 if (!(sys_feat & BIT(MM_FEAT_HE_BIT))) {
407 ecrnx_hw->mod_params->he_on = false;
408 ecrnx_hw->mod_params->he_ul_on = false;
411 if (!(sys_feat & BIT(MM_FEAT_PS_BIT))) {
412 ecrnx_hw->mod_params->ps_on = false;
415 /* AMSDU (non)support implies different shared structure definition
416 so insure that fw and drv have consistent compilation option */
417 if (sys_feat & BIT(MM_FEAT_AMSDU_BIT)) {
418 #ifndef CONFIG_ECRNX_SPLIT_TX_BUF
420 "AMSDU enabled in firmware but support not compiled in driver\n");
423 /* Adjust amsdu_maxnb so that it stays in allowed bounds */
424 ecrnx_adjust_amsdu_maxnb(ecrnx_hw);
425 #endif /* CONFIG_ECRNX_SPLIT_TX_BUF */
427 #ifdef CONFIG_ECRNX_SPLIT_TX_BUF
429 "AMSDU disabled in firmware but support compiled in driver\n");
431 #endif /* CONFIG_ECRNX_SPLIT_TX_BUF */
434 if (!(sys_feat & BIT(MM_FEAT_UAPSD_BIT))) {
435 ecrnx_hw->mod_params->uapsd_timeout = 0;
438 if (!(sys_feat & BIT(MM_FEAT_BFMEE_BIT))) {
439 ecrnx_hw->mod_params->bfmee = false;
442 if ((sys_feat & BIT(MM_FEAT_BFMER_BIT))) {
443 #ifndef CONFIG_ECRNX_BFMER
445 "BFMER enabled in firmware but support not compiled in driver\n");
447 #endif /* CONFIG_ECRNX_BFMER */
448 // Check PHY and MAC HW BFMER support and update parameter accordingly
449 if (!(phy_feat & MDM_BFMER_BIT) || !(mac_feat & NXMAC_BFMER_BIT)) {
450 ecrnx_hw->mod_params->bfmer = false;
451 // Disable the feature in the bitfield so that it won't be displayed
452 sys_feat &= ~BIT(MM_FEAT_BFMER_BIT);
455 #ifdef CONFIG_ECRNX_BFMER
457 "BFMER disabled in firmware but support compiled in driver\n");
460 ecrnx_hw->mod_params->bfmer = false;
461 #endif /* CONFIG_ECRNX_BFMER */
464 if (!(sys_feat & BIT(MM_FEAT_MESH_BIT))) {
465 ecrnx_hw->mod_params->mesh = false;
468 if (!(sys_feat & BIT(MM_FEAT_TDLS_BIT))) {
469 ecrnx_hw->mod_params->tdls = false;
472 if (!(sys_feat & BIT(MM_FEAT_UF_BIT))) {
473 ecrnx_hw->mod_params->uf = false;
476 #ifdef CONFIG_ECRNX_FULLMAC
477 if ((sys_feat & BIT(MM_FEAT_MON_DATA_BIT))) {
478 #ifndef CONFIG_ECRNX_MON_DATA
480 "Monitor+Data interface support (MON_DATA) is enabled in firmware but support not compiled in driver\n");
482 #endif /* CONFIG_ECRNX_MON_DATA */
484 #ifdef CONFIG_ECRNX_MON_DATA
486 "Monitor+Data interface support (MON_DATA) disabled in firmware but support compiled in driver\n");
488 #endif /* CONFIG_ECRNX_MON_DATA */
492 // Check supported AMSDU RX size
493 amsdu_rx = (sys_feat >> MM_AMSDU_MAX_SIZE_BIT0) & 0x03;
494 if (amsdu_rx < ecrnx_hw->mod_params->amsdu_rx_max) {
495 ecrnx_hw->mod_params->amsdu_rx_max = amsdu_rx;
498 // Check supported BW
499 bw = (phy_feat & MDM_CHBW_MASK) >> MDM_CHBW_LSB;
500 // Check if 80MHz BW is supported
502 ecrnx_hw->mod_params->use_80 = false;
504 // Check if 40MHz BW is supported
506 ecrnx_hw->mod_params->use_2040 = false;
508 // 80MHz BW shall be disabled if 40MHz is not enabled
509 if (!ecrnx_hw->mod_params->use_2040)
510 ecrnx_hw->mod_params->use_80 = false;
512 // Check if HT is supposed to be supported. If not, disable VHT/HE too
513 if (!ecrnx_hw->mod_params->ht_on)
515 ecrnx_hw->mod_params->vht_on = false;
516 ecrnx_hw->mod_params->he_on = false;
517 ecrnx_hw->mod_params->he_ul_on = false;
518 ecrnx_hw->mod_params->use_80 = false;
519 ecrnx_hw->mod_params->use_2040 = false;
522 // LDPC is mandatory for HE40 and above, so if LDPC is not supported, then disable
523 // HE to use HT/VHT only
524 if (ecrnx_hw->mod_params->he_on && !ecrnx_hw->mod_params->ldpc_on)
526 ecrnx_hw->mod_params->use_80 = false;
527 /* ESWIN turns off 40M automotically when it is HE mode */
528 //ecrnx_hw->mod_params->use_2040 = false;
532 // HT greenfield is not supported in modem >= 3.0
533 if (__MDM_MAJOR_VERSION(phy_vers) > 0) {
534 #ifdef CONFIG_ECRNX_SOFTMAC
535 ecrnx_hw->mod_params->gf_on = false;
537 ecrnx_hw->mod_params->gf_rx_on = false;
540 if (!(sys_feat & BIT(MM_FEAT_MU_MIMO_RX_BIT)) ||
541 !ecrnx_hw->mod_params->bfmee) {
542 ecrnx_hw->mod_params->murx = false;
545 if ((sys_feat & BIT(MM_FEAT_MU_MIMO_TX_BIT))) {
546 #ifndef CONFIG_ECRNX_MUMIMO_TX
548 "MU-MIMO TX enabled in firmware but support not compiled in driver\n");
550 #endif /* CONFIG_ECRNX_MUMIMO_TX */
551 if (!ecrnx_hw->mod_params->bfmer)
552 ecrnx_hw->mod_params->mutx = false;
553 // Check PHY and MAC HW MU-MIMO TX support and update parameter accordingly
554 else if (!(phy_feat & MDM_MUMIMOTX_BIT) || !(mac_feat & NXMAC_MU_MIMO_TX_BIT)) {
555 ecrnx_hw->mod_params->mutx = false;
556 // Disable the feature in the bitfield so that it won't be displayed
557 sys_feat &= ~BIT(MM_FEAT_MU_MIMO_TX_BIT);
560 #ifdef CONFIG_ECRNX_MUMIMO_TX
562 "MU-MIMO TX disabled in firmware but support compiled in driver\n");
565 ecrnx_hw->mod_params->mutx = false;
566 #endif /* CONFIG_ECRNX_MUMIMO_TX */
569 if (sys_feat & BIT(MM_FEAT_WAPI_BIT)) {
570 ecrnx_enable_wapi(ecrnx_hw);
573 #ifdef CONFIG_ECRNX_FULLMAC
574 if (sys_feat & BIT(MM_FEAT_MFP_BIT)) {
575 ecrnx_enable_mfp(ecrnx_hw);
577 if (mac_feat & NXMAC_GCMP_BIT) {
578 ecrnx_enable_gcmp(ecrnx_hw);
582 #ifdef CONFIG_ECRNX_SOFTMAC
583 #define QUEUE_NAME "BEACON queue "
585 #define QUEUE_NAME "Broadcast/Multicast queue "
586 #endif /* CONFIG_ECRNX_SOFTMAC */
588 if (sys_feat & BIT(MM_FEAT_BCN_BIT)) {
590 wiphy_err(wiphy, QUEUE_NAME
591 "enabled in firmware but support not compiled in driver\n");
593 #endif /* NX_TXQ_CNT == 4 */
596 wiphy_err(wiphy, QUEUE_NAME
597 "disabled in firmware but support compiled in driver\n");
599 #endif /* NX_TXQ_CNT == 5 */
603 #ifdef CONFIG_ECRNX_RADAR
604 if (sys_feat & BIT(MM_FEAT_RADAR_BIT)) {
605 /* Enable combination with radar detection */
606 wiphy->n_iface_combinations++;
608 #endif /* CONFIG_ECRNX_RADAR */
610 #ifndef CONFIG_ECRNX_SDM
611 switch (__MDM_PHYCFG_FROM_VERS(phy_feat)) {
612 case MDM_PHY_CONFIG_TRIDENT:
613 ecrnx_hw->mod_params->nss = 1;
614 if ((ecrnx_hw->mod_params->phy_cfg < 0) || (ecrnx_hw->mod_params->phy_cfg > 2))
615 ecrnx_hw->mod_params->phy_cfg = 2;
617 case MDM_PHY_CONFIG_KARST:
618 case MDM_PHY_CONFIG_CATAXIA:
620 int nss_supp = (phy_feat & MDM_NSS_MASK) >> MDM_NSS_LSB;
621 if (ecrnx_hw->mod_params->nss > nss_supp)
622 ecrnx_hw->mod_params->nss = nss_supp;
623 if ((ecrnx_hw->mod_params->phy_cfg < 0) || (ecrnx_hw->mod_params->phy_cfg > 1))
624 ecrnx_hw->mod_params->phy_cfg = 0;
631 #endif /* CONFIG_ECRNX_SDM */
633 if ((ecrnx_hw->mod_params->nss < 1) || (ecrnx_hw->mod_params->nss > 2))
634 ecrnx_hw->mod_params->nss = 1;
637 if ((ecrnx_hw->mod_params->mcs_map < 0) || (ecrnx_hw->mod_params->mcs_map > 2))
638 ecrnx_hw->mod_params->mcs_map = 0;
640 #define PRINT_ECRNX_PHY_FEAT(feat) \
641 (phy_feat & MDM_##feat##_BIT ? "["#feat"]" : "")
642 wiphy_info(wiphy, "PHY features: [NSS=%d][CHBW=%d]%s%s%s%s%s%s%s\n",
643 (phy_feat & MDM_NSS_MASK) >> MDM_NSS_LSB,
644 20 * (1 << ((phy_feat & MDM_CHBW_MASK) >> MDM_CHBW_LSB)),
645 (phy_feat & (MDM_LDPCDEC_BIT | MDM_LDPCENC_BIT)) ==
646 (MDM_LDPCDEC_BIT | MDM_LDPCENC_BIT) ? "[LDPC]" : "",
647 PRINT_ECRNX_PHY_FEAT(VHT),
648 PRINT_ECRNX_PHY_FEAT(HE),
649 PRINT_ECRNX_PHY_FEAT(BFMER),
650 PRINT_ECRNX_PHY_FEAT(BFMEE),
651 PRINT_ECRNX_PHY_FEAT(MUMIMOTX),
652 PRINT_ECRNX_PHY_FEAT(MUMIMORX)
655 #define PRINT_ECRNX_FEAT(feat) \
656 (sys_feat & BIT(MM_FEAT_##feat##_BIT) ? "["#feat"]" : "")
658 wiphy_info(wiphy, "FW features: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
659 PRINT_ECRNX_FEAT(BCN),
660 PRINT_ECRNX_FEAT(AUTOBCN),
661 PRINT_ECRNX_FEAT(HWSCAN),
662 PRINT_ECRNX_FEAT(CMON),
663 PRINT_ECRNX_FEAT(MROLE),
664 PRINT_ECRNX_FEAT(RADAR),
665 PRINT_ECRNX_FEAT(PS),
666 PRINT_ECRNX_FEAT(UAPSD),
667 PRINT_ECRNX_FEAT(DPSM),
668 PRINT_ECRNX_FEAT(AMPDU),
669 PRINT_ECRNX_FEAT(AMSDU),
670 PRINT_ECRNX_FEAT(CHNL_CTXT),
671 PRINT_ECRNX_FEAT(REORD),
672 PRINT_ECRNX_FEAT(P2P),
673 PRINT_ECRNX_FEAT(P2P_GO),
674 PRINT_ECRNX_FEAT(UMAC),
675 PRINT_ECRNX_FEAT(VHT),
676 PRINT_ECRNX_FEAT(HE),
677 PRINT_ECRNX_FEAT(BFMEE),
678 PRINT_ECRNX_FEAT(BFMER),
679 PRINT_ECRNX_FEAT(WAPI),
680 PRINT_ECRNX_FEAT(MFP),
681 PRINT_ECRNX_FEAT(MU_MIMO_RX),
682 PRINT_ECRNX_FEAT(MU_MIMO_TX),
683 PRINT_ECRNX_FEAT(MESH),
684 PRINT_ECRNX_FEAT(TDLS),
685 PRINT_ECRNX_FEAT(ANT_DIV),
686 PRINT_ECRNX_FEAT(UF),
687 PRINT_ECRNX_FEAT(TWT));
688 #undef PRINT_ECRNX_FEAT
690 if(max_sta_nb != NX_REMOTE_STA_MAX)
692 wiphy_err(wiphy, "Different number of supported stations between driver and FW (%d != %d)\n",
693 NX_REMOTE_STA_MAX, max_sta_nb);
697 if(max_vif_nb != NX_VIRT_DEV_MAX)
699 wiphy_err(wiphy, "Different number of supported virtual interfaces between driver and FW (%d != %d)\n",
700 NX_VIRT_DEV_MAX, max_vif_nb);
707 static void ecrnx_set_ppe_threshold(struct ecrnx_hw *ecrnx_hw,
708 struct ieee80211_sta_he_cap *he_cap)
710 const u8_l PPE_THRES_INFO_OFT = 7;
711 const u8_l PPE_THRES_INFO_BIT_LEN = 6;
712 struct ppe_thres_info_tag
717 struct ppe_thres_field_tag
722 int nss = ecrnx_hw->mod_params->nss;
723 struct ppe_thres_field_tag* ppe_thres_field = (struct ppe_thres_field_tag*) he_cap->ppe_thres;
724 struct ppe_thres_info_tag ppe_thres_info = {.ppet16 = 0, //BSPK
727 u8_l* ppe_thres_info_ptr = (u8_l*) &ppe_thres_info;
728 u16_l* ppe_thres_ptr = (u16_l*) he_cap->ppe_thres;
729 u8_l i, j, cnt, offset;
730 if (ecrnx_hw->mod_params->use_80)
732 ppe_thres_field->ru_idx_bmp = 7;
737 ppe_thres_field->ru_idx_bmp = 1;
740 ppe_thres_field->nsts = nss - 1;
741 for (i = 0; i < nss ; i++)
743 for (j = 0; j < cnt; j++){
744 offset = (i * cnt + j) * PPE_THRES_INFO_BIT_LEN + PPE_THRES_INFO_OFT;
745 ppe_thres_ptr = (u16_l*)&he_cap->ppe_thres[offset / 8];
746 *ppe_thres_ptr |= *ppe_thres_info_ptr << (offset % 8);
752 #ifdef CONFIG_ECRNX_SOFTMAC
753 static void ecrnx_set_softmac_flags(struct ecrnx_hw *ecrnx_hw)
755 struct ieee80211_hw *hw = ecrnx_hw->hw;
757 #ifdef CONFIG_MAC80211_AMSDUS_TX
758 ieee80211_hw_set(hw, TX_AMSDU);
759 ieee80211_hw_set(hw, TX_FRAG_LIST);
760 hw->max_tx_fragments = ecrnx_hw->mod_params->amsdu_maxnb;
763 if (!ecrnx_hw->mod_params->autobcn)
764 ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
766 if (ecrnx_hw->mod_params->agg_tx)
767 ieee80211_hw_set(hw, AMPDU_AGGREGATION);
769 if (ecrnx_hw->mod_params->cmon)
770 ieee80211_hw_set(hw, CONNECTION_MONITOR);
772 if (ecrnx_hw->mod_params->hwscan)
773 ieee80211_hw_set(hw, CHANCTX_STA_CSA);
775 if (ecrnx_hw->mod_params->ps_on) {
776 ieee80211_hw_set(hw, SUPPORTS_PS);
778 /* To disable the dynamic PS we say to the stack that we support it in
779 * HW. This will force mac80211 rely on us to handle this. */
780 ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
782 if (ecrnx_hw->mod_params->mfp_on)
783 ieee80211_hw_set(hw, MFP_CAPABLE);
785 nss = ecrnx_hw->mod_params->nss;
786 ecrnx_hw->phy.ctrlinfo_1.value = 0;
787 ecrnx_hw->phy.ctrlinfo_2.value = 0;
789 ecrnx_hw->phy.ctrlinfo_2.antennaSet = 1;
791 ecrnx_hw->phy.ctrlinfo_1.fecCoding = 0;
792 ecrnx_hw->phy.ctrlinfo_1.nTx = 1;
793 ecrnx_hw->phy.ctrlinfo_2.antennaSet = 3;
794 ecrnx_hw->phy.ctrlinfo_2.smmIndex = 1;
796 ecrnx_hw->phy.stbc_nss = nss >> 1;
800 #ifdef CONFIG_ECRNX_5G
801 static void ecrnx_set_vht_capa(struct ecrnx_hw *ecrnx_hw, struct wiphy *wiphy)
803 struct ieee80211_supported_band *band_5GHz = wiphy->bands[NL80211_BAND_5GHZ];
805 int nss = ecrnx_hw->mod_params->nss;
808 int mcs_map_max_2ss_rx = IEEE80211_VHT_MCS_SUPPORT_0_9;
809 int mcs_map_max_2ss_tx = IEEE80211_VHT_MCS_SUPPORT_0_9;
812 if (!ecrnx_hw->mod_params->vht_on)
815 band_5GHz->vht_cap.vht_supported = true;
816 if (ecrnx_hw->mod_params->sgi80)
817 band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
818 if (ecrnx_hw->mod_params->stbc_on)
819 band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_1;
820 if (ecrnx_hw->mod_params->ldpc_on)
821 band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC;
822 if (ecrnx_hw->mod_params->bfmee) {
823 band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
824 band_5GHz->vht_cap.cap |= 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
827 band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC;
829 // Update the AMSDU max RX size (not shifted as located at offset 0 of the VHT cap)
830 band_5GHz->vht_cap.cap |= ecrnx_hw->mod_params->amsdu_rx_max;
832 if (ecrnx_hw->mod_params->bfmer) {
833 band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
834 /* Set number of sounding dimensions */
835 band_5GHz->vht_cap.cap |= (nss - 1) << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
837 if (ecrnx_hw->mod_params->murx)
838 band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
839 if (ecrnx_hw->mod_params->mutx)
840 band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
844 * This capabilities are filled according to the mcs_map module parameter.
845 * However currently we have some limitations due to FPGA clock constraints
846 * that prevent always using the range of MCS that is defined by the
848 * - in RX, 2SS, we support up to MCS7
849 * - in TX, 2SS, we support up to MCS8
851 // Get max supported BW
852 if (ecrnx_hw->mod_params->use_80) {
853 bw_max = PHY_CHNL_BW_80;
854 mcs_map_max_2ss_rx = IEEE80211_VHT_MCS_SUPPORT_0_7;
855 mcs_map_max_2ss_tx = IEEE80211_VHT_MCS_SUPPORT_0_8;
856 } else if (ecrnx_hw->mod_params->use_2040)
857 bw_max = PHY_CHNL_BW_40;
859 bw_max = PHY_CHNL_BW_20;
861 // Check if MCS map should be limited to MCS0_8 due to the standard. Indeed in BW20,
862 // MCS9 is not supported in 1 and 2 SS
863 if (ecrnx_hw->mod_params->use_2040)
864 mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_9;
866 mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_8;
868 mcs_map = min_t(int, ecrnx_hw->mod_params->mcs_map, mcs_map_max);
869 band_5GHz->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0);
870 for (i = 0; i < nss; i++) {
871 band_5GHz->vht_cap.vht_mcs.rx_mcs_map |= cpu_to_le16(mcs_map << (i*2));
872 band_5GHz->vht_cap.vht_mcs.rx_highest = MAX_VHT_RATE(mcs_map, nss, bw_max);
873 mcs_map = min_t(int, mcs_map, mcs_map_max_2ss_rx);
876 band_5GHz->vht_cap.vht_mcs.rx_mcs_map |= cpu_to_le16(
877 IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2));
880 mcs_map = min_t(int, ecrnx_hw->mod_params->mcs_map, mcs_map_max);
881 band_5GHz->vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(0);
882 for (i = 0; i < nss; i++) {
883 band_5GHz->vht_cap.vht_mcs.tx_mcs_map |= cpu_to_le16(mcs_map << (i*2));
884 band_5GHz->vht_cap.vht_mcs.tx_highest = MAX_VHT_RATE(mcs_map, nss, bw_max);
885 mcs_map = min_t(int, mcs_map, mcs_map_max_2ss_tx);
888 band_5GHz->vht_cap.vht_mcs.tx_mcs_map |= cpu_to_le16(
889 IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2));
892 if (!ecrnx_hw->mod_params->use_80) {
893 #ifdef CONFIG_VENDOR_ECRNX_VHT_NO80
894 band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_NOT_SUP_WIDTH_80;
896 band_5GHz->vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_80;
900 static void ecrnx_set_vht_capa(struct ecrnx_hw *ecrnx_hw, struct wiphy *wiphy)
902 struct ieee80211_supported_band *band_2GHz = wiphy->bands[NL80211_BAND_2GHZ];
904 int nss = ecrnx_hw->mod_params->nss;
907 int mcs_map_max_2ss_rx = IEEE80211_VHT_MCS_SUPPORT_0_9;
908 int mcs_map_max_2ss_tx = IEEE80211_VHT_MCS_SUPPORT_0_9;
911 if (!ecrnx_hw->mod_params->vht_on)
914 band_2GHz->vht_cap.vht_supported = true;
915 if (ecrnx_hw->mod_params->sgi80)
916 band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
917 if (ecrnx_hw->mod_params->stbc_on)
918 band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_1;
919 if (ecrnx_hw->mod_params->ldpc_on)
920 band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC;
921 if (ecrnx_hw->mod_params->bfmee) {
922 band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
923 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
924 band_2GHz->vht_cap.cap |= 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
928 band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC;
930 // Update the AMSDU max RX size (not shifted as located at offset 0 of the VHT cap)
931 band_2GHz->vht_cap.cap |= ecrnx_hw->mod_params->amsdu_rx_max;
933 if (ecrnx_hw->mod_params->bfmer) {
934 band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
935 /* Set number of sounding dimensions */
936 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
937 band_2GHz->vht_cap.cap |= (nss - 1) << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
940 if (ecrnx_hw->mod_params->murx)
941 band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
942 if (ecrnx_hw->mod_params->mutx)
943 band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
947 * This capabilities are filled according to the mcs_map module parameter.
948 * However currently we have some limitations due to FPGA clock constraints
949 * that prevent always using the range of MCS that is defined by the
951 * - in RX, 2SS, we support up to MCS7
952 * - in TX, 2SS, we support up to MCS8
954 // Get max supported BW
955 if (ecrnx_hw->mod_params->use_80) {
956 bw_max = PHY_CHNL_BW_80;
957 mcs_map_max_2ss_rx = IEEE80211_VHT_MCS_SUPPORT_0_7;
958 mcs_map_max_2ss_tx = IEEE80211_VHT_MCS_SUPPORT_0_8;
959 } else if (ecrnx_hw->mod_params->use_2040)
960 bw_max = PHY_CHNL_BW_40;
962 bw_max = PHY_CHNL_BW_20;
964 // Check if MCS map should be limited to MCS0_8 due to the standard. Indeed in BW20,
965 // MCS9 is not supported in 1 and 2 SS
966 if (ecrnx_hw->mod_params->use_2040)
967 mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_9;
969 mcs_map_max = IEEE80211_VHT_MCS_SUPPORT_0_8;
971 mcs_map = min_t(int, ecrnx_hw->mod_params->mcs_map, mcs_map_max);
972 band_2GHz->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0);
973 for (i = 0; i < nss; i++) {
974 band_2GHz->vht_cap.vht_mcs.rx_mcs_map |= cpu_to_le16(mcs_map << (i*2));
975 band_2GHz->vht_cap.vht_mcs.rx_highest = MAX_VHT_RATE(mcs_map, nss, bw_max);
976 mcs_map = min_t(int, mcs_map, mcs_map_max_2ss_rx);
979 band_2GHz->vht_cap.vht_mcs.rx_mcs_map |= cpu_to_le16(
980 IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2));
983 mcs_map = min_t(int, ecrnx_hw->mod_params->mcs_map, mcs_map_max);
984 band_2GHz->vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(0);
985 for (i = 0; i < nss; i++) {
986 band_2GHz->vht_cap.vht_mcs.tx_mcs_map |= cpu_to_le16(mcs_map << (i*2));
987 band_2GHz->vht_cap.vht_mcs.tx_highest = MAX_VHT_RATE(mcs_map, nss, bw_max);
988 mcs_map = min_t(int, mcs_map, mcs_map_max_2ss_tx);
991 band_2GHz->vht_cap.vht_mcs.tx_mcs_map |= cpu_to_le16(
992 IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2));
995 if (!ecrnx_hw->mod_params->use_80) {
996 #ifdef CONFIG_VENDOR_ECRNX_VHT_NO80
997 band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_NOT_SUP_WIDTH_80;
999 band_2GHz->vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_80;
1005 static void ecrnx_set_ht_capa(struct ecrnx_hw *ecrnx_hw, struct wiphy *wiphy)
1007 #ifdef CONFIG_ECRNX_5G
1008 struct ieee80211_supported_band *band_5GHz = wiphy->bands[NL80211_BAND_5GHZ];
1010 struct ieee80211_supported_band *band_2GHz = wiphy->bands[NL80211_BAND_2GHZ];
1012 int nss = ecrnx_hw->mod_params->nss;
1014 if (!ecrnx_hw->mod_params->ht_on) {
1015 band_2GHz->ht_cap.ht_supported = false;
1016 #ifdef CONFIG_ECRNX_5G
1017 band_5GHz->ht_cap.ht_supported = false;
1021 //JIRA438 begin by E0000550
1022 //if (ecrnx_hw->mod_params->stbc_on)
1024 band_2GHz->ht_cap.cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
1025 if (ecrnx_hw->mod_params->ldpc_on)
1026 band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
1027 if (ecrnx_hw->mod_params->use_2040) {
1028 band_2GHz->ht_cap.mcs.rx_mask[4] = 0x1; /* MCS32 */
1029 band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
1030 band_2GHz->ht_cap.mcs.rx_highest = cpu_to_le16(135 * nss);
1032 band_2GHz->ht_cap.mcs.rx_highest = cpu_to_le16(65 * nss);
1035 band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
1037 // Update the AMSDU max RX size
1038 if (ecrnx_hw->mod_params->amsdu_rx_max)
1039 band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
1041 if (ecrnx_hw->mod_params->sgi) {
1042 band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
1043 if (ecrnx_hw->mod_params->use_2040) {
1044 band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
1045 band_2GHz->ht_cap.mcs.rx_highest = cpu_to_le16(150 * nss);
1047 band_2GHz->ht_cap.mcs.rx_highest = cpu_to_le16(72 * nss);
1049 if (ecrnx_hw->mod_params->gf_rx_on)
1050 band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD;
1052 for (i = 0; i < nss; i++) {
1053 band_2GHz->ht_cap.mcs.rx_mask[i] = 0xFF;
1056 #ifdef CONFIG_ECRNX_5G
1057 band_5GHz->ht_cap = band_2GHz->ht_cap;
1061 static void ecrnx_set_he_capa(struct ecrnx_hw *ecrnx_hw, struct wiphy *wiphy)
1063 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
1064 #ifdef CONFIG_ECRNX_5G
1065 struct ieee80211_supported_band *band_5GHz = wiphy->bands[NL80211_BAND_5GHZ];
1067 struct ieee80211_supported_band *band_2GHz = wiphy->bands[NL80211_BAND_2GHZ];
1071 int nss = ecrnx_hw->mod_params->nss;
1072 struct ieee80211_sta_he_cap *he_cap;
1073 int mcs_map, mcs_map_max_2ss = IEEE80211_HE_MCS_SUPPORT_0_11;
1074 u8 dcm_max_ru = IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242;
1075 u32_l phy_vers = ecrnx_hw->version_cfm.version_phy_2;
1077 if (!ecrnx_hw->mod_params->he_on) {
1078 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
1079 band_2GHz->iftype_data = NULL;
1080 band_2GHz->n_iftype_data = 0;
1081 #ifdef CONFIG_ECRNX_5G
1082 band_5GHz->iftype_data = NULL;
1083 band_5GHz->n_iftype_data = 0;
1088 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
1089 he_cap = (struct ieee80211_sta_he_cap *) &band_2GHz->iftype_data->he_cap;
1091 he_cap = &ecrnx_he_cap;
1093 he_cap->has_he = true;
1094 #ifdef CONFIG_ECRNX_FULLMAC
1095 if (ecrnx_hw->version_cfm.features & BIT(MM_FEAT_TWT_BIT))
1097 ecrnx_hw->ext_capa[9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT;
1098 he_cap->he_cap_elem.mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ;
1101 he_cap->he_cap_elem.mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_ALL_ACK;
1102 ecrnx_set_ppe_threshold(ecrnx_hw, he_cap);
1104 /* ESWIN turns off 40M automotically when it is HE mode */
1105 if (ecrnx_hw->mod_params->use_2040) {
1106 he_cap->he_cap_elem.phy_cap_info[0] |=
1107 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
1108 dcm_max_ru = IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484;
1111 if (ecrnx_hw->mod_params->use_80) {
1112 he_cap->he_cap_elem.phy_cap_info[0] |=
1113 IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
1114 mcs_map_max_2ss = IEEE80211_HE_MCS_SUPPORT_0_7;
1115 dcm_max_ru = IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996;
1117 if (ecrnx_hw->mod_params->ldpc_on) {
1118 he_cap->he_cap_elem.phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
1120 // If no LDPC is supported, we have to limit to MCS0_9, as LDPC is mandatory
1121 // for MCS 10 and 11
1122 ecrnx_hw->mod_params->he_mcs_map = min_t(int, ecrnx_hw->mod_params->he_mcs_map,
1123 IEEE80211_HE_MCS_SUPPORT_0_9);
1126 /* ESWIN: sync the he capa with 6600 standalone */
1127 he_cap->he_cap_elem.phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US |
1128 IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS;
1129 he_cap->he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS |
1130 IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
1131 IEEE80211_HE_PHY_CAP2_DOPPLER_RX;
1133 he_cap->he_cap_elem.phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US;
1134 he_cap->he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
1135 IEEE80211_HE_PHY_CAP2_DOPPLER_RX;
1137 if (ecrnx_hw->mod_params->stbc_on)
1138 he_cap->he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
1139 he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM |
1140 IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA;
1142 /* ESWIN: sync the he capa with 6600 standalone */
1144 he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2;
1146 he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1;
1148 if (ecrnx_hw->mod_params->bfmee) {
1149 he_cap->he_cap_elem.phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE;
1150 he_cap->he_cap_elem.phy_cap_info[4] |=
1151 IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4;
1153 he_cap->he_cap_elem.phy_cap_info[5] |= IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
1154 IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
1155 he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
1156 IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
1158 /* ESWIN: sync the he capa with 6600 standalone */
1160 IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
1161 IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB |
1163 IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT |
1164 IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
1165 he_cap->he_cap_elem.phy_cap_info[7] |= IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
1166 he_cap->he_cap_elem.phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
1168 he_cap->he_cap_elem.phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
1169 IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
1170 IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
1172 if (__MDM_VERSION(phy_vers) > 30) {
1173 he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE;
1174 he_cap->he_cap_elem.phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI |
1175 IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI;
1178 mcs_map = ecrnx_hw->mod_params->he_mcs_map;
1179 memset(&he_cap->he_mcs_nss_supp, 0, sizeof(he_cap->he_mcs_nss_supp));
1180 for (i = 0; i < nss; i++) {
1181 __le16 unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i*2));
1182 he_cap->he_mcs_nss_supp.rx_mcs_80 |= cpu_to_le16(mcs_map << (i*2));
1183 he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss;
1184 he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss;
1185 mcs_map = min_t(int, ecrnx_hw->mod_params->he_mcs_map,
1188 for (; i < 8; i++) {
1189 __le16 unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i*2));
1190 he_cap->he_mcs_nss_supp.rx_mcs_80 |= unsup_for_ss;
1191 he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss;
1192 he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss;
1194 mcs_map = ecrnx_hw->mod_params->he_mcs_map;
1195 for (i = 0; i < nss; i++) {
1196 __le16 unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i*2));
1197 he_cap->he_mcs_nss_supp.tx_mcs_80 |= cpu_to_le16(mcs_map << (i*2));
1198 he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss;
1199 he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss;
1200 mcs_map = min_t(int, ecrnx_hw->mod_params->he_mcs_map,
1203 for (; i < 8; i++) {
1204 __le16 unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i*2));
1205 he_cap->he_mcs_nss_supp.tx_mcs_80 |= unsup_for_ss;
1206 he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss;
1207 he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss;
1211 static void ecrnx_set_wiphy_params(struct ecrnx_hw *ecrnx_hw, struct wiphy *wiphy)
1213 #ifdef CONFIG_ECRNX_SOFTMAC
1214 struct ieee80211_hw *hw = ecrnx_hw->hw;
1216 /* SOFTMAC specific parameters */
1217 if (ecrnx_hw->mod_params->hwscan) {
1218 hw->wiphy->max_scan_ssids = SCAN_SSID_MAX;
1219 hw->wiphy->max_scan_ie_len = SCAN_MAX_IE_LEN;
1222 /* FULLMAC specific parameters */
1223 wiphy->flags |= WIPHY_FLAG_REPORTS_OBSS;
1224 wiphy->max_scan_ssids = SCAN_SSID_MAX;
1225 wiphy->max_scan_ie_len = SCANU_MAX_IE_LEN;
1226 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
1227 wiphy->support_mbssid = 1;
1229 #endif /* CONFIG_ECRNX_FULLMAC */
1231 if (ecrnx_hw->mod_params->tdls) {
1233 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
1234 #ifdef CONFIG_ECRNX_FULLMAC
1235 /* TDLS external setup support */
1236 wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
1240 if (ecrnx_hw->mod_params->ap_uapsd_on)
1241 wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
1243 #ifdef CONFIG_ECRNX_FULLMAC
1244 if (ecrnx_hw->mod_params->ps_on)
1245 wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
1247 wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
1250 if (ecrnx_hw->mod_params->custregd) {
1251 // Apply custom regulatory. Note that for recent kernel versions we use instead the
1252 // REGULATORY_WIPHY_SELF_MANAGED flag, along with the regulatory_set_wiphy_regd()
1253 // function, that needs to be called after wiphy registration
1254 // Check if custom channel set shall be enabled. In such case only monitor mode is
1256 if (ecrnx_hw->mod_params->custchan) {
1257 wiphy->interface_modes = BIT(NL80211_IFTYPE_MONITOR);
1259 // Enable "extra" channels
1260 wiphy->bands[NL80211_BAND_2GHZ]->n_channels += 13;
1261 #ifdef CONFIG_ECRNX_5G
1262 wiphy->bands[NL80211_BAND_5GHZ]->n_channels += 59;
1268 static void ecrnx_set_rf_params(struct ecrnx_hw *ecrnx_hw, struct wiphy *wiphy)
1270 #ifndef CONFIG_ECRNX_SDM
1271 #ifdef CONFIG_ECRNX_5G
1272 struct ieee80211_supported_band *band_5GHz = wiphy->bands[NL80211_BAND_5GHZ];
1275 u32 mdm_phy_cfg = __MDM_PHYCFG_FROM_VERS(ecrnx_hw->version_cfm.version_phy_1);
1278 * Get configuration file depending on the RF
1280 #if 0 /* baoyong: we use the custom rf, do not need this */
1281 struct ecrnx_phy_conf_file phy_conf;
1282 if (mdm_phy_cfg == MDM_PHY_CONFIG_TRIDENT) {
1283 // Retrieve the Trident configuration
1284 ecrnx_parse_phy_configfile(ecrnx_hw, ECRNX_PHY_CONFIG_TRD_NAME,
1285 &phy_conf, ecrnx_hw->mod_params->phy_cfg);
1286 memcpy(&ecrnx_hw->phy.cfg, &phy_conf.trd, sizeof(phy_conf.trd));
1287 } else if (mdm_phy_cfg == MDM_PHY_CONFIG_CATAXIA) {
1288 memset(&phy_conf.cataxia, 0, sizeof(phy_conf.cataxia));
1289 phy_conf.cataxia.path_used = ecrnx_hw->mod_params->phy_cfg;
1290 memcpy(&ecrnx_hw->phy.cfg, &phy_conf.cataxia, sizeof(phy_conf.cataxia));
1291 } else if (mdm_phy_cfg == MDM_PHY_CONFIG_KARST) {
1292 // We use the NSS parameter as is
1293 // Retrieve the Karst configuration
1294 ecrnx_parse_phy_configfile(ecrnx_hw, ECRNX_PHY_CONFIG_KARST_NAME,
1295 &phy_conf, ecrnx_hw->mod_params->phy_cfg);
1297 memcpy(&ecrnx_hw->phy.cfg, &phy_conf.karst, sizeof(phy_conf.karst));
1304 * adjust caps depending on the RF
1306 switch (mdm_phy_cfg) {
1307 case MDM_PHY_CONFIG_TRIDENT:
1309 wiphy_dbg(wiphy, "found Trident PHY .. limit BW to 40MHz\n");
1310 ecrnx_hw->phy.limit_bw = true;
1311 #ifdef CONFIG_ECRNX_5G
1312 #ifdef CONFIG_VENDOR_ECRNX_VHT_NO80
1313 band_5GHz->vht_cap.cap |= IEEE80211_VHT_CAP_NOT_SUP_WIDTH_80;
1315 band_5GHz->vht_cap.cap &= ~(IEEE80211_VHT_CAP_SHORT_GI_80 |
1316 IEEE80211_VHT_CAP_RXSTBC_MASK);
1320 case MDM_PHY_CONFIG_CATAXIA:
1322 wiphy_dbg(wiphy, "found CATAXIA PHY\n");
1325 case MDM_PHY_CONFIG_KARST:
1327 wiphy_dbg(wiphy, "found KARST PHY\n");
1334 #endif /* CONFIG_ECRNX_SDM */
1337 int ecrnx_handle_dynparams(struct ecrnx_hw *ecrnx_hw, struct wiphy *wiphy)
1341 /* Check compatibility between requested parameters and HW/SW features */
1342 ret = ecrnx_check_fw_hw_feature(ecrnx_hw, wiphy);
1345 #ifndef CONFIG_ECRNX_ESWIN
1347 /* Allocate the RX buffers according to the maximum AMSDU RX size */
1348 ret = ecrnx_ipc_rxbuf_init(ecrnx_hw,
1349 (4 * (ecrnx_hw->mod_params->amsdu_rx_max + 1) + 1) * 1024);
1351 wiphy_err(wiphy, "Cannot allocate the RX buffers\n");
1355 #ifdef CONFIG_ECRNX_SOFTMAC
1356 /* SOFTMAC specific parameters*/
1357 ecrnx_set_softmac_flags(ecrnx_hw);
1358 #endif /* CONFIG_ECRNX_SOFTMAC */
1360 /* Set wiphy parameters */
1361 ecrnx_set_wiphy_params(ecrnx_hw, wiphy);
1363 /* Set VHT capabilities */
1364 ecrnx_set_vht_capa(ecrnx_hw, wiphy);
1366 /* Set HE capabilities */
1367 ecrnx_set_he_capa(ecrnx_hw, wiphy);
1369 /* Set HT capabilities */
1370 ecrnx_set_ht_capa(ecrnx_hw, wiphy);
1372 /* Set RF specific parameters (shall be done last as it might change some
1373 capabilities previously set) */
1374 ecrnx_set_rf_params(ecrnx_hw, wiphy);
1379 void ecrnx_custregd(struct ecrnx_hw *ecrnx_hw, struct wiphy *wiphy)
1381 // For older kernel version, the custom regulatory is applied before the wiphy
1382 // registration (in ecrnx_set_wiphy_params()), so nothing has to be done here
1383 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
1384 if (!ecrnx_hw->mod_params->custregd)
1387 wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
1388 wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
1391 if (regulatory_set_wiphy_regd_sync_rtnl(wiphy, &ecrnx_regdom))
1392 wiphy_err(wiphy, "Failed to set custom regdomain\n");
1394 wiphy_err(wiphy,"\n"
1395 "*******************************************************\n"
1396 "** CAUTION: USING PERMISSIVE CUSTOM REGULATORY RULES **\n"
1397 "*******************************************************\n");
1402 void ecrnx_adjust_amsdu_maxnb(struct ecrnx_hw *ecrnx_hw)
1404 if (ecrnx_hw->mod_params->amsdu_maxnb > NX_TX_PAYLOAD_MAX)
1405 ecrnx_hw->mod_params->amsdu_maxnb = NX_TX_PAYLOAD_MAX;
1406 else if (ecrnx_hw->mod_params->amsdu_maxnb == 0)
1407 ecrnx_hw->mod_params->amsdu_maxnb = 1;