project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp: Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem. sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately. sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades. sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for fastboot. Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
1020 lines
37 KiB
C
1020 lines
37 KiB
C
/*
|
|
* Copyright (c) 2021 iComm-semi Ltd.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
/**
|
|
* @file fmac_mod_params.c
|
|
* @brief Set configuration according to modules parameters
|
|
*/
|
|
|
|
|
|
/*******************************************************************************
|
|
* Include Files
|
|
******************************************************************************/
|
|
#include <linux/module.h>
|
|
|
|
#include "fmac.h"
|
|
#include "fmac_defs.h"
|
|
#include "fmac_tx.h"
|
|
#include "fmac_msg_tx.h"
|
|
#include "hal_desc.h"
|
|
#include "ssv_debug.h"
|
|
|
|
|
|
extern struct ssv6xxx_cfg ssv_cfg;
|
|
/*******************************************************************************
|
|
* Local Defines
|
|
******************************************************************************/
|
|
#define COMMON_PARAM(name, default_softmac, default_fullmac) \
|
|
.name = default_fullmac,
|
|
#define SOFTMAC_PARAM(name, default)
|
|
#define FULLMAC_PARAM(name, default) .name = default,
|
|
|
|
|
|
|
|
#define __MDM_MAJOR_VERSION(v) (((v) & 0xFF000000) >> 24)
|
|
#define __MDM_MINOR_VERSION(v) (((v) & 0x00FF0000) >> 16)
|
|
#define __MDM_VERSION(v) ((__MDM_MAJOR_VERSION(v) + 2) * 10 + __MDM_MINOR_VERSION(v))
|
|
/******************************************************************************
|
|
* CFG80211
|
|
*****************************************************************************/
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0)
|
|
#define WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT 0
|
|
|
|
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242 0x00
|
|
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484 0x40
|
|
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996 0x80
|
|
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996 0xc0
|
|
#define IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_MASK 0xc0
|
|
|
|
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US 0x00
|
|
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US 0x40
|
|
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US 0x80
|
|
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED 0xc0
|
|
#define IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK 0xc0
|
|
#endif // 5.1
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
|
|
#define cfg80211_notify_new_peer_candidate(dev, addr, ie, ie_len, sig_dbm, gfp) \
|
|
cfg80211_notify_new_peer_candidate(dev, addr, ie, ie_len, gfp)
|
|
|
|
#define WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT BIT(5)
|
|
#define WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT BIT(6)
|
|
|
|
#endif // 5.0
|
|
|
|
struct ssv_mod_params ssv_mod_params = {
|
|
/* common parameters */
|
|
COMMON_PARAM(ht_on, true, true)
|
|
COMMON_PARAM(vht_on, false, false)
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
COMMON_PARAM(mcs_map, IEEE80211_VHT_MCS_SUPPORT_0_9, IEEE80211_VHT_MCS_SUPPORT_0_7)
|
|
#else
|
|
COMMON_PARAM(mcs_map, 2, 0)
|
|
#endif
|
|
COMMON_PARAM(he_on, true, true) // overwrite by ssv_cfg
|
|
COMMON_PARAM(twt_on, false, false)
|
|
COMMON_PARAM(ldpc_on, true, true)
|
|
COMMON_PARAM(vht_stbc, false, false)
|
|
COMMON_PARAM(phy_cfg, 2, 2)
|
|
COMMON_PARAM(uapsd_timeout, 0, 0)
|
|
COMMON_PARAM(ap_uapsd_on, false, false)
|
|
COMMON_PARAM(sgi, true, true)
|
|
COMMON_PARAM(use_2040, true, true) // overwrite by ssv_cfg
|
|
COMMON_PARAM(nss, 1, 1)
|
|
COMMON_PARAM(bfmee, false, false)
|
|
COMMON_PARAM(mesh, false, false)
|
|
COMMON_PARAM(custregd, false, false)
|
|
COMMON_PARAM(roc_dur_max, 500, 500)
|
|
COMMON_PARAM(listen_itv, 0, 0)
|
|
COMMON_PARAM(listen_bcmc, true, true)
|
|
COMMON_PARAM(lp_clk_ppm, 20, 20)
|
|
COMMON_PARAM(ps_on, false, false)
|
|
COMMON_PARAM(tx_lft, SSV_TX_LIFETIME_MS, SSV_TX_LIFETIME_MS) // overwrite by ssv_cfg
|
|
// By default, only enable UAPSD for Voice queue (see IEEE80211_DEFAULT_UAPSD_QUEUE comment)
|
|
COMMON_PARAM(uapsd_queues, 0, 0)
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) || defined(IEEE80211_HE_MAC_CAP2_TRS)
|
|
COMMON_PARAM(he_mcs_map, IEEE80211_HE_MCS_SUPPORT_0_9, IEEE80211_HE_MCS_SUPPORT_0_9)
|
|
#endif
|
|
};
|
|
|
|
module_param_named(ht_on, ssv_mod_params.ht_on, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(ht_on, "Enable HT (Default: 1)");
|
|
|
|
module_param_named(vht_on, ssv_mod_params.vht_on, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(vht_on, "Enable VHT (Default: 1)");
|
|
|
|
module_param_named(mcs_map, ssv_mod_params.mcs_map, int, S_IRUGO);
|
|
MODULE_PARM_DESC(mcs_map, "VHT MCS map value 0: MCS0_7, 1: MCS0_8, 2: MCS0_9"
|
|
" (Default: 0)");
|
|
|
|
module_param_named(he_on, ssv_mod_params.vht_on, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(he_on, "Enable HE (Default: 1)");
|
|
|
|
module_param_named(ps_on, ssv_mod_params.ps_on, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(ps_on, "Enable PowerSaving (Default: 1-Enabled)");
|
|
|
|
module_param_named(tx_lft, ssv_mod_params.tx_lft, int, 0644);
|
|
MODULE_PARM_DESC(tx_lft, "Tx lifetime (ms) - setting it to 0 disables retries "
|
|
"(Default: "__stringify(SSV_TX_LIFETIME_MS)")");
|
|
|
|
module_param_named(ldpc_on, ssv_mod_params.ldpc_on, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(ldpc_on, "Enable LDPC (Default: 1)");
|
|
|
|
module_param_named(vht_stbc, ssv_mod_params.vht_stbc, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(vht_stbc, "Enable VHT STBC in RX (Default: 1)");
|
|
|
|
module_param_named(phycfg, ssv_mod_params.phy_cfg, int, S_IRUGO);
|
|
MODULE_PARM_DESC(phycfg,
|
|
"0 <= phycfg <= 5 : RF Channel Conf (Default: 2(C0-A1-B2))");
|
|
|
|
module_param_named(uapsd_timeout, ssv_mod_params.uapsd_timeout, int, S_IRUGO | S_IWUSR);
|
|
MODULE_PARM_DESC(uapsd_timeout,
|
|
"UAPSD Timer timeout, in ms (Default: 300). If 0, UAPSD is disabled");
|
|
|
|
module_param_named(uapsd_queues, ssv_mod_params.uapsd_queues, int, S_IRUGO | S_IWUSR);
|
|
MODULE_PARM_DESC(uapsd_queues, "UAPSD Queues, integer value, must be seen as a bitfield\n"
|
|
" Bit 0 = VO\n"
|
|
" Bit 1 = VI\n"
|
|
" Bit 2 = BK\n"
|
|
" Bit 3 = BE\n"
|
|
" -> uapsd_queues=7 will enable uapsd for VO, VI and BK queues");
|
|
|
|
module_param_named(ap_uapsd_on, ssv_mod_params.ap_uapsd_on, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(ap_uapsd_on, "Enable UAPSD in AP mode (Default: 1)");
|
|
|
|
module_param_named(sgi, ssv_mod_params.sgi, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(sgi, "Advertise Short Guard Interval support (Default: 1)");
|
|
|
|
module_param_named(use_2040, ssv_mod_params.use_2040, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(use_2040, "Use tweaked 20-40MHz mode (Default: 1)");
|
|
|
|
module_param_named(custregd, ssv_mod_params.custregd, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(custregd,
|
|
"Use permissive custom regulatory rules (for testing ONLY) (Default: 0)");
|
|
|
|
module_param_named(nss, ssv_mod_params.nss, int, S_IRUGO);
|
|
MODULE_PARM_DESC(nss, "1 <= nss <= 2 : Supported number of Spatial Streams (Default: 1)");
|
|
|
|
module_param_named(bfmee, ssv_mod_params.bfmee, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(bfmee, "Enable Beamformee Capability (Default: 1-Enabled)");
|
|
|
|
module_param_named(mesh, ssv_mod_params.mesh, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(mesh, "Enable Meshing Capability (Default: 0-Disabled)");
|
|
|
|
module_param_named(roc_dur_max, ssv_mod_params.roc_dur_max, int, S_IRUGO);
|
|
MODULE_PARM_DESC(roc_dur_max, "Maximum Remain on Channel duration");
|
|
|
|
module_param_named(listen_itv, ssv_mod_params.listen_itv, int, S_IRUGO);
|
|
MODULE_PARM_DESC(listen_itv, "Maximum listen interval");
|
|
|
|
module_param_named(listen_bcmc, ssv_mod_params.listen_bcmc, bool, S_IRUGO);
|
|
MODULE_PARM_DESC(listen_bcmc, "Wait for BC/MC traffic following DTIM beacon");
|
|
|
|
module_param_named(lp_clk_ppm, ssv_mod_params.lp_clk_ppm, int, S_IRUGO);
|
|
MODULE_PARM_DESC(lp_clk_ppm, "Low Power Clock accuracy of the local device");
|
|
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) || defined(IEEE80211_HE_MAC_CAP2_TRS)
|
|
module_param_named(he_mcs_map, ssv_mod_params.he_mcs_map, int, S_IRUGO | S_IWUSR);
|
|
MODULE_PARM_DESC(he_mcs_map, "HE MCS map value 0: MCS0_7, 1: MCS0_9, 2: MCS0_11"
|
|
" (Default: 2)");
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
* Local Enumerations
|
|
******************************************************************************/
|
|
|
|
|
|
/*******************************************************************************
|
|
* Local Structures
|
|
******************************************************************************/
|
|
|
|
|
|
/*******************************************************************************
|
|
* Global Variables
|
|
******************************************************************************/
|
|
|
|
|
|
/*******************************************************************************
|
|
* Local Variables
|
|
******************************************************************************/
|
|
/* Regulatory rules */
|
|
static const struct ieee80211_regdomain ssv_regdom = {
|
|
.n_reg_rules = 3,
|
|
.alpha2 = "99",
|
|
.reg_rules = {
|
|
REG_RULE(2412 - 10, 2472 + 10, 40, 0, 1000, 0),
|
|
REG_RULE(2484 - 10, 2484 + 10, 20, 0, 1000, 0),
|
|
REG_RULE(5150 - 10, 5850 + 10, 80, 0, 1000, 0),
|
|
}
|
|
};
|
|
|
|
|
|
struct channel_range
|
|
{
|
|
u32 start_ch; //start channel
|
|
u32 end_ch; //end channel
|
|
};
|
|
|
|
struct custom_channel_info
|
|
{
|
|
u32 n_ch_rules; //total n channel ranges
|
|
struct channel_range ch_list[14]; //channel list.
|
|
};
|
|
|
|
struct custom_channel_info custom_channel_info = {0};
|
|
|
|
|
|
/*******************************************************************************
|
|
* Local Functions
|
|
******************************************************************************/
|
|
/**
|
|
* Do some sanity check
|
|
*
|
|
*/
|
|
static int ssv_check_fw_hw_feature(struct ssv_softc *sc,
|
|
struct wiphy *wiphy)
|
|
{
|
|
u32_l sys_feat = sc->version_cfm.features;
|
|
u32_l phy_feat = sc->version_cfm.version_phy_1;
|
|
|
|
if (!(sys_feat & BIT(MM_FEAT_UMAC_BIT))) {
|
|
wiphy_err(wiphy,
|
|
"Loading softmac firmware with fullmac driver\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!(sys_feat & BIT(MM_FEAT_VHT_BIT))) {
|
|
sc->mod_params->vht_on = false;
|
|
}
|
|
|
|
if (!(sys_feat & BIT(MM_FEAT_HE_BIT))) {
|
|
sc->mod_params->he_on = false;
|
|
}
|
|
|
|
if (!(sys_feat & BIT(MM_FEAT_TWT_BIT))) {
|
|
sc->mod_params->twt_on = false;
|
|
}
|
|
|
|
if (!(sys_feat & BIT(MM_FEAT_PS_BIT))) {
|
|
sc->mod_params->ps_on = false;
|
|
}
|
|
|
|
if (!(sys_feat & BIT(MM_FEAT_UAPSD_BIT))) {
|
|
sc->mod_params->uapsd_timeout = 0;
|
|
}
|
|
|
|
if (sys_feat & BIT(MM_FEAT_WAPI_BIT)) {
|
|
ssv_enable_wapi(sc);
|
|
}
|
|
|
|
if (sys_feat & BIT(MM_FEAT_MFP_BIT)) {
|
|
ssv_enable_mfp(sc);
|
|
}
|
|
|
|
#ifdef CONFIG_SSV_RADAR
|
|
if (sys_feat & BIT(MM_FEAT_RADAR_BIT)) {
|
|
/* Enable combination with radar detection */
|
|
wiphy->n_iface_combinations++;
|
|
}
|
|
#endif /* CONFIG_SSV_RADAR */
|
|
|
|
{
|
|
struct ieee80211_supported_band *band_2GHz = wiphy->bands[NL80211_BAND_2GHZ];
|
|
SSV_LOG_DBG("\n\nsys_feat = 0x%08x, phy_feat = 0x%08x\n\n\n", sys_feat, phy_feat);
|
|
if (sys_feat & BIT(MM_AMSDU_MAX_SIZE_BIT1)) {
|
|
band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
|
|
#endif
|
|
}
|
|
else if (sys_feat & BIT(MM_AMSDU_MAX_SIZE_BIT0)) {
|
|
band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
|
|
#endif
|
|
}
|
|
else {
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifndef CONFIG_SSV_SDM
|
|
switch (__MDM_PHYCFG_FROM_VERS(phy_feat)) {
|
|
case MDM_PHY_CONFIG_TRIDENT:
|
|
case MDM_PHY_CONFIG_ELMA:
|
|
sc->mod_params->nss = 1;
|
|
break;
|
|
case MDM_PHY_CONFIG_KARST:
|
|
{
|
|
int nss_supp = (phy_feat & MDM_NSS_MASK) >> MDM_NSS_LSB;
|
|
if (sc->mod_params->nss > nss_supp)
|
|
sc->mod_params->nss = nss_supp;
|
|
}
|
|
break;
|
|
default:
|
|
WARN_ON(1);
|
|
break;
|
|
}
|
|
#endif /* CONFIG_SSV_SDM */
|
|
|
|
/* PHY features */
|
|
{
|
|
u8 phy_ch_bw = ((phy_feat & MDM_CHBW_MASK) >> MDM_CHBW_LSB);
|
|
|
|
sc->phy_ch_bw = phy_ch_bw;
|
|
sc->mod_params->ht_on = phy_ch_bw >= PHY_CHNL_BW_40 ? true : false;
|
|
sc->mod_params->vht_on = phy_ch_bw >= PHY_CHNL_BW_80 ? true : false;
|
|
if (!(phy_feat & MDM_LDPCDEC_BIT))
|
|
{
|
|
sc->mod_params->ldpc_on = false;
|
|
}
|
|
if (!(phy_feat & MDM_BFMEE_BIT))
|
|
{
|
|
sc->mod_params->bfmee = false;
|
|
}
|
|
}
|
|
|
|
if (sc->mod_params->nss < 1 || sc->mod_params->nss > 2)
|
|
sc->mod_params->nss = 1;
|
|
|
|
wiphy_info(wiphy, "PHY features: [NSS=%d][CHBW=%d]%s\n",
|
|
sc->mod_params->nss,
|
|
20 * (1 << ((phy_feat & MDM_CHBW_MASK) >> MDM_CHBW_LSB)),
|
|
sc->mod_params->ldpc_on ? "[LDPC]" : "");
|
|
#if (SSV_VER == 691)
|
|
#define PRINT_SSV_FEAT(feat) \
|
|
(sys_feat & BIT(MM_FEAT_##feat##_BIT) ? "["#feat"]" : "")
|
|
|
|
wiphy_info(wiphy, "FW features: %s%s%s%s%s%s%s%s%s%s\n",
|
|
PRINT_SSV_FEAT(BCN),
|
|
PRINT_SSV_FEAT(RADAR),
|
|
PRINT_SSV_FEAT(PS),
|
|
PRINT_SSV_FEAT(UAPSD),
|
|
PRINT_SSV_FEAT(AMPDU),
|
|
PRINT_SSV_FEAT(AMSDU),
|
|
PRINT_SSV_FEAT(UMAC),
|
|
PRINT_SSV_FEAT(VHT),
|
|
PRINT_SSV_FEAT(WAPI),
|
|
PRINT_SSV_FEAT(MFP));
|
|
#else
|
|
#define PRINT_SSV_FEAT(feat) \
|
|
(sys_feat & BIT(MM_FEAT_##feat##_BIT) ? "["#feat"]" : "")
|
|
|
|
wiphy_info(wiphy, "FW features: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
|
|
PRINT_SSV_FEAT(BCN),
|
|
PRINT_SSV_FEAT(AUTOBCN),
|
|
PRINT_SSV_FEAT(HWSCAN),
|
|
PRINT_SSV_FEAT(CMON),
|
|
PRINT_SSV_FEAT(MROLE),
|
|
PRINT_SSV_FEAT(RADAR),
|
|
PRINT_SSV_FEAT(PS),
|
|
PRINT_SSV_FEAT(UAPSD),
|
|
PRINT_SSV_FEAT(DPSM),
|
|
PRINT_SSV_FEAT(AMPDU),
|
|
PRINT_SSV_FEAT(AMSDU),
|
|
PRINT_SSV_FEAT(CHNL_CTXT),
|
|
PRINT_SSV_FEAT(REORD),
|
|
PRINT_SSV_FEAT(UMAC),
|
|
PRINT_SSV_FEAT(VHT),
|
|
PRINT_SSV_FEAT(WAPI),
|
|
PRINT_SSV_FEAT(MFP));
|
|
#endif
|
|
#undef PRINT_SSV_FEAT
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
* Global Functions
|
|
******************************************************************************/
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) || defined(IEEE80211_HE_MAC_CAP2_TRS)
|
|
static void ssv_set_ppe_threshold(struct ssv_softc *sc,
|
|
struct ieee80211_sta_he_cap *he_cap)
|
|
{
|
|
const u8_l PPE_THRES_INFO_OFT = 7;
|
|
const u8_l PPE_THRES_INFO_BIT_LEN = 6;
|
|
struct ppe_thres_info_tag
|
|
{
|
|
u8_l ppet16 : 3;
|
|
u8_l ppet8 : 3;
|
|
}__packed;
|
|
|
|
struct ppe_thres_field_tag
|
|
{
|
|
u8_l nsts : 3;
|
|
u8_l ru_idx_bmp : 4;
|
|
};
|
|
int nss = sc->mod_params->nss;
|
|
struct ppe_thres_field_tag* ppe_thres_field = (struct ppe_thres_field_tag*) he_cap->ppe_thres;
|
|
struct ppe_thres_info_tag ppe_thres_info = {.ppet16 = 0, //BSPK
|
|
.ppet8 = 7 //None
|
|
};
|
|
u8_l* ppe_thres_info_ptr = (u8_l*) &ppe_thres_info;
|
|
u16_l* ppe_thres_ptr = (u16_l*) he_cap->ppe_thres;
|
|
u8_l i, j, cnt, offset;
|
|
|
|
if (sc->mod_params->use_2040)
|
|
{
|
|
ppe_thres_field->ru_idx_bmp = 3;
|
|
cnt = 2;
|
|
}
|
|
else
|
|
{
|
|
ppe_thres_field->ru_idx_bmp = 1;
|
|
cnt = 1;
|
|
}
|
|
|
|
ppe_thres_field->nsts = nss - 1;
|
|
for (i = 0; i < nss ; i++)
|
|
{
|
|
for (j = 0; j < cnt; j++){
|
|
offset = (i * cnt + j) * PPE_THRES_INFO_BIT_LEN + PPE_THRES_INFO_OFT;
|
|
ppe_thres_ptr = (u16_l*)&he_cap->ppe_thres[offset / 8];
|
|
*ppe_thres_ptr |= *ppe_thres_info_ptr << (offset % 8);
|
|
}
|
|
}
|
|
}
|
|
#endif // LINUX_VERSION_CODE >= 4.20
|
|
|
|
|
|
|
|
void ssv_get_custom_channle_range(u32 channel_bitwise, struct custom_channel_info *p_channel_info)
|
|
{
|
|
int n_bit = 1;
|
|
int ch_list_idx = 0;
|
|
int start_ch = 0;
|
|
int end_ch = 0;
|
|
|
|
u32 ch = channel_bitwise;
|
|
|
|
memset(p_channel_info, 0x0, sizeof(struct custom_channel_info));
|
|
|
|
while(n_bit < 16)
|
|
{
|
|
// SSV_LOG_DBG("n_bit %d, ch %d\n", n_bit, ch);
|
|
if(ch & 1)
|
|
{
|
|
if(!start_ch)
|
|
start_ch = n_bit;
|
|
}
|
|
else
|
|
{
|
|
if(start_ch)
|
|
{
|
|
end_ch = n_bit -1;
|
|
p_channel_info->ch_list[ch_list_idx].start_ch = start_ch;
|
|
p_channel_info->ch_list[ch_list_idx].end_ch = end_ch;
|
|
ch_list_idx++;
|
|
start_ch = 0;
|
|
end_ch = 0;
|
|
}
|
|
}
|
|
ch = ch>>1;
|
|
n_bit++;
|
|
}
|
|
p_channel_info->n_ch_rules = ch_list_idx;
|
|
|
|
}
|
|
|
|
void dump_custom_channel_info(struct custom_channel_info *p_channel_info)
|
|
{
|
|
int i = 0;
|
|
SSV_LOG_DBG("n_ch_rules %d\n", p_channel_info->n_ch_rules);
|
|
for(i=0; i<p_channel_info->n_ch_rules; i++)
|
|
{
|
|
SSV_LOG_DBG("i=%d, start_ch:end_ch (%d:%d)\n",
|
|
i,
|
|
p_channel_info->ch_list[i].start_ch,
|
|
p_channel_info->ch_list[i].end_ch);
|
|
}
|
|
|
|
}
|
|
|
|
u32 channel_to_freq(u32 ch)
|
|
{
|
|
u32 freq = 0;
|
|
switch(ch)
|
|
{
|
|
case 1:
|
|
freq = 2412;
|
|
break;
|
|
case 2:
|
|
freq = 2417;
|
|
break;
|
|
case 3:
|
|
freq = 2422;
|
|
break;
|
|
case 4:
|
|
freq = 2427;
|
|
break;
|
|
case 5:
|
|
freq = 2432;
|
|
break;
|
|
case 6:
|
|
freq = 2437;
|
|
break;
|
|
case 7:
|
|
freq = 2442;
|
|
break;
|
|
case 8:
|
|
freq = 2447;
|
|
break;
|
|
case 9:
|
|
freq = 2452;
|
|
break;
|
|
case 10:
|
|
freq = 2457;
|
|
break;
|
|
case 11:
|
|
freq = 2462;
|
|
break;
|
|
case 12:
|
|
freq = 2467;
|
|
break;
|
|
case 13:
|
|
freq = 2472;
|
|
break;
|
|
case 14:
|
|
freq = 2484;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return freq;
|
|
}
|
|
|
|
|
|
|
|
void ssv_gen_custom_regulatory(struct custom_channel_info *p_channel_info, struct ieee80211_regdomain *ssv_regdom)
|
|
{
|
|
int i;
|
|
u8 alpha2[3] = "99";
|
|
u32 start_ch;
|
|
u32 end_ch;
|
|
ssv_regdom->n_reg_rules = p_channel_info->n_ch_rules;
|
|
memcpy(ssv_regdom->alpha2, alpha2, 3);
|
|
for(i=0; i<ssv_regdom->n_reg_rules; i++ )
|
|
{
|
|
start_ch = p_channel_info->ch_list[i].start_ch;
|
|
end_ch = p_channel_info->ch_list[i].end_ch;
|
|
ssv_regdom->reg_rules[i].freq_range.start_freq_khz = (channel_to_freq(start_ch) - 5)*1000;//MHZ_TO_KHZ
|
|
ssv_regdom->reg_rules[i].freq_range.end_freq_khz = (channel_to_freq(end_ch) + 5)*1000; //MHZ_TO_KHZ
|
|
ssv_regdom->reg_rules[i].freq_range.max_bandwidth_khz = 40*1000; //MHZ_TO_KHZ
|
|
ssv_regdom->reg_rules[i].power_rule.max_antenna_gain = 0; //DBI_TO_MBI
|
|
ssv_regdom->reg_rules[i].power_rule.max_eirp = 1000*100; //DBM_TO_MBM
|
|
ssv_regdom->reg_rules[i].flags = 0;
|
|
}
|
|
}
|
|
|
|
void dump_custom_regulatory(struct ieee80211_regdomain *ssv_regdom)
|
|
{
|
|
int i;
|
|
|
|
SSV_LOG_DBG("n_reg_rules %d\n", ssv_regdom->n_reg_rules);
|
|
// SSV_LOG_DBG_DUMP("aplha2", &ssv_regdom->alpha2, 3);
|
|
//SSV_LOG_DBG("alpha2 %s\n", &ssv_regdom->alpha2);
|
|
|
|
for(i=0; i<ssv_regdom->n_reg_rules; i++ )
|
|
{
|
|
SSV_LOG_DBG("i %d, freq_start %d, freq_end %d, bw %d, gain %d, eirp %d, flags %d\n",
|
|
i,
|
|
ssv_regdom->reg_rules[i].freq_range.start_freq_khz,
|
|
ssv_regdom->reg_rules[i].freq_range.end_freq_khz,
|
|
ssv_regdom->reg_rules[i].freq_range.max_bandwidth_khz,
|
|
ssv_regdom->reg_rules[i].power_rule.max_antenna_gain,
|
|
ssv_regdom->reg_rules[i].power_rule.max_eirp,
|
|
ssv_regdom->reg_rules[i].flags);
|
|
}
|
|
|
|
SSV_LOG_DBG("\n");
|
|
}
|
|
|
|
|
|
int ssv_handle_dynparams(struct ssv_softc *sc, struct wiphy *wiphy)
|
|
{
|
|
struct ieee80211_supported_band *band_2GHz = wiphy->bands[NL80211_BAND_2GHZ];
|
|
#ifndef CONFIG_SSV_SDM
|
|
u32 mdm_phy_cfg;
|
|
#endif
|
|
int i, ret;
|
|
int nss;
|
|
int mcs_map;
|
|
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) || defined(IEEE80211_HE_MAC_CAP2_TRS)
|
|
struct ieee80211_sta_he_cap *he_cap;
|
|
int mcs_map_max_2ss = IEEE80211_HE_MCS_SUPPORT_0_11;
|
|
u8 dcm_max_ru = IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242;
|
|
u32_l phy_vers = sc->version_cfm.version_phy_2;
|
|
#endif
|
|
|
|
struct ieee80211_regdomain *ssv_custom_regdom = NULL;
|
|
u32 regdom_rule_len;
|
|
u32 ssv_regdom_total_len;
|
|
|
|
ret = ssv_check_fw_hw_feature(sc, wiphy);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* FULLMAC specific parameters */
|
|
wiphy->flags |= WIPHY_FLAG_REPORTS_OBSS;
|
|
|
|
if (sc->mod_params->ap_uapsd_on)
|
|
wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
|
|
|
|
if (sc->mod_params->phy_cfg < 0 || sc->mod_params->phy_cfg > 5)
|
|
sc->mod_params->phy_cfg = 2;
|
|
|
|
if (sc->mod_params->mcs_map < 0 || sc->mod_params->mcs_map > 2)
|
|
sc->mod_params->mcs_map = 0;
|
|
|
|
#ifndef CONFIG_SSV_SDM
|
|
mdm_phy_cfg = __MDM_PHYCFG_FROM_VERS(sc->version_cfm.version_phy_1);
|
|
#if 0 //No config file.
|
|
if (mdm_phy_cfg == MDM_PHY_CONFIG_TRIDENT) {
|
|
struct ssv_phy_conf_file phy_conf;
|
|
// Retrieve the Trident configuration
|
|
ssv_parse_phy_configfile(sc, SSV_PHY_CONFIG_TRD_NAME, &phy_conf);
|
|
memcpy(&sc->phy_config, &phy_conf.trd, sizeof(phy_conf.trd));
|
|
} else if (mdm_phy_cfg == MDM_PHY_CONFIG_ELMA) {
|
|
} else if (mdm_phy_cfg == MDM_PHY_CONFIG_KARST) {
|
|
struct ssv_phy_conf_file phy_conf;
|
|
// We use the NSS parameter as is
|
|
// Retrieve the Karst configuration
|
|
ssv_parse_phy_configfile(sc, SSV_PHY_CONFIG_KARST_NAME, &phy_conf);
|
|
|
|
memcpy(&sc->phy_config, &phy_conf.karst, sizeof(phy_conf.karst));
|
|
} else {
|
|
WARN_ON(1);
|
|
}
|
|
#endif
|
|
#endif /* CONFIG_SSV_SDM */
|
|
|
|
nss = sc->mod_params->nss;
|
|
|
|
/*
|
|
* MCS map:
|
|
* This capabilities are filled according to the mcs_map module parameter.
|
|
* However currently we have some limitations due to FPGA clock constraints
|
|
* that prevent always using the range of MCS that is defined by the
|
|
* parameter:
|
|
* - in RX, 2SS, we support up to MCS7
|
|
* - in TX, 2SS, we support up to MCS8
|
|
*/
|
|
mcs_map = sc->mod_params->mcs_map;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
band_2GHz->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0);
|
|
#endif
|
|
//band_5GHz->vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(0);
|
|
for (i = 0; i < nss; i++) {
|
|
band_2GHz->ht_cap.mcs.rx_mask[i] = 0xFF;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
band_2GHz->vht_cap.vht_mcs.rx_mcs_map |= cpu_to_le16(mcs_map << (i*2));
|
|
//band_5GHz->vht_cap.vht_mcs.rx_mcs_map |= cpu_to_le16(mcs_map << (i*2));
|
|
mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_7;
|
|
#endif
|
|
}
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
for (; i < 8; i++) {
|
|
band_2GHz->vht_cap.vht_mcs.rx_mcs_map |= cpu_to_le16(
|
|
IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2));
|
|
//band_5GHz->vht_cap.vht_mcs.rx_mcs_map |= cpu_to_le16(
|
|
//IEEE80211_VHT_MCS_NOT_SUPPORTED << (i*2));
|
|
}
|
|
mcs_map = sc->mod_params->mcs_map;
|
|
//band_5GHz->vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(0);
|
|
for (i = 0; i < nss; i++) {
|
|
//band_5GHz->vht_cap.vht_mcs.tx_mcs_map |= cpu_to_le16(mcs_map << (i*2));
|
|
mcs_map = min_t(int, sc->mod_params->mcs_map,
|
|
IEEE80211_VHT_MCS_SUPPORT_0_8);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* LDPC capability:
|
|
* This capability is filled according to the ldpc_on module parameter.
|
|
* However currently we have some limitations due to FPGA clock constraints
|
|
* that prevent correctly receiving more than MCS4-2SS when using LDPC.
|
|
* We therefore disable the LDPC support if 2SS is supported.
|
|
*/
|
|
sc->mod_params->ldpc_on = nss > 1 ? false: sc->mod_params->ldpc_on;
|
|
|
|
/* HT capabilities */
|
|
band_2GHz->ht_cap.cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
|
|
if (sc->mod_params->ldpc_on)
|
|
band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
|
|
if (sc->mod_params->use_2040) {
|
|
band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
|
|
band_2GHz->ht_cap.mcs.rx_highest = cpu_to_le16(135 * nss);
|
|
} else {
|
|
band_2GHz->ht_cap.mcs.rx_highest = cpu_to_le16(65 * nss);
|
|
}
|
|
if (nss > 1)
|
|
band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
|
|
|
|
if (sc->mod_params->sgi) {
|
|
band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
|
|
if (sc->mod_params->use_2040) {
|
|
band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
|
|
band_2GHz->ht_cap.mcs.rx_highest = cpu_to_le16(150 * nss);
|
|
} else
|
|
band_2GHz->ht_cap.mcs.rx_highest = cpu_to_le16(72 * nss);
|
|
}
|
|
if (!sc->mod_params->ht_on) {
|
|
band_2GHz->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD;
|
|
}
|
|
// SSV_LOG_DBG("--->ht_on=%d\n", sc->mod_params->ht_on);
|
|
if (!sc->mod_params->ht_on)
|
|
band_2GHz->ht_cap.ht_supported = false;
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
/* VHT capabilities */
|
|
{
|
|
#define VHT_RATE(_mcs, _nss) (((u32)(vht_base_rate[(_mcs)] * vht_mult) >> 16) * (_nss))
|
|
u16 vht_base_rate[3] = {0x4100, 0x4E00, 0x56AB}; // VHT base rate per mcs 65, 78 and 86.66 in Q8 notation
|
|
u16 vht_mult = 0;
|
|
u8 vht_mcs = (u8)IEEE80211_VHT_MCS_SUPPORT_0_9; //IEEE80211_VHT_MCS_SUPPORT_0_9(2)
|
|
u8 mcs_map_tx = 0;
|
|
u8 mcs_map_rx = 0;
|
|
bool vht_on = sc->mod_params->vht_on;
|
|
|
|
if (vht_on)
|
|
vht_mult = 0x0480; // x4.5 in Q8 notation
|
|
else if (ssv_mod_params.ht_on)
|
|
vht_mult = 0x0214; // x2.07 in Q8 notation
|
|
else
|
|
vht_mult = 0x0100; // x1 in Q8 notation
|
|
|
|
if (sc->mod_params->ldpc_on)
|
|
band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC;
|
|
if (nss > 1)
|
|
band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC;
|
|
if(sc->mod_params->vht_stbc)
|
|
band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_1;
|
|
if (sc->mod_params->bfmee)
|
|
band_2GHz->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
band_2GHz->vht_cap.cap |= (nss - 1 ) << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
|
|
#else
|
|
band_2GHz->vht_cap.cap |= (nss - 1 ) << 16;
|
|
#endif
|
|
band_2GHz->vht_cap.cap |= (7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
|
|
|
|
// RX/TX MCS
|
|
if (!ssv_mod_params.ht_on)
|
|
// MCS9 not allowed in 20MHZ
|
|
vht_mcs = min(vht_mcs, (u8)IEEE80211_VHT_MCS_SUPPORT_0_8);
|
|
|
|
mcs_map_rx = vht_mcs;
|
|
mcs_map_tx = vht_mcs;
|
|
// 1 SS
|
|
band_2GHz->vht_cap.vht_mcs.rx_mcs_map = mcs_map_rx;
|
|
band_2GHz->vht_cap.vht_mcs.tx_mcs_map = mcs_map_tx;
|
|
// 2 SS and above
|
|
if (nss > 1)
|
|
{
|
|
if (vht_on)
|
|
{
|
|
// limit rate @80MHz because of FPGA platform limitation
|
|
mcs_map_rx = IEEE80211_VHT_MCS_SUPPORT_0_7;
|
|
mcs_map_tx = min(mcs_map_tx, (u8)IEEE80211_VHT_MCS_SUPPORT_0_8);
|
|
}
|
|
for (i = 1; i < nss; i++)
|
|
{
|
|
band_2GHz->vht_cap.vht_mcs.rx_mcs_map |= mcs_map_rx << (2 * i);
|
|
band_2GHz->vht_cap.vht_mcs.tx_mcs_map |= mcs_map_tx << (2 * i);
|
|
}
|
|
}
|
|
// Non supported NSS
|
|
for (i = nss; i < 8; i++)
|
|
{
|
|
band_2GHz->vht_cap.vht_mcs.rx_mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (2 * i);
|
|
band_2GHz->vht_cap.vht_mcs.tx_mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (2 * i);
|
|
}
|
|
|
|
band_2GHz->vht_cap.vht_mcs.rx_highest = VHT_RATE(mcs_map_rx, nss);
|
|
band_2GHz->vht_cap.vht_mcs.tx_highest = VHT_RATE(mcs_map_tx, nss);
|
|
|
|
if (!vht_on)
|
|
band_2GHz->vht_cap.vht_supported = false;
|
|
}/* VHT capabilities */
|
|
#endif
|
|
|
|
|
|
/* HE capabilities */
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) || defined(IEEE80211_HE_MAC_CAP2_TRS)
|
|
nss = sc->mod_params->nss;
|
|
|
|
if (!sc->mod_params->he_on) {
|
|
band_2GHz->iftype_data = NULL;
|
|
band_2GHz->n_iftype_data = 0;
|
|
//band_5GHz->iftype_data = NULL;
|
|
//band_5GHz->n_iftype_data = 0;
|
|
return 0;
|
|
}
|
|
|
|
he_cap = (struct ieee80211_sta_he_cap *) &band_2GHz->iftype_data->he_cap;
|
|
he_cap->has_he = true;
|
|
|
|
he_cap->he_cap_elem.mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_HTC_HE;
|
|
if(sc->mod_params->twt_on)
|
|
{
|
|
sc->ext_capa[9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT;
|
|
he_cap->he_cap_elem.mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ;
|
|
}
|
|
|
|
//he_cap->he_cap_elem.mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_ALL_ACK;
|
|
ssv_set_ppe_threshold(sc, he_cap);
|
|
if (sc->mod_params->use_2040) {
|
|
he_cap->he_cap_elem.phy_cap_info[0] |=
|
|
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
|
|
dcm_max_ru = IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484;
|
|
}
|
|
he_cap->he_cap_elem.phy_cap_info[0] |=
|
|
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G;
|
|
|
|
he_cap->he_cap_elem.phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A;
|
|
if (sc->mod_params->ldpc_on) {
|
|
he_cap->he_cap_elem.phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
|
|
} else {
|
|
// If no LDPC is supported, we have to limit to MCS0_9, as LDPC is mandatory
|
|
// for MCS 10 and 11
|
|
sc->mod_params->he_mcs_map = min_t(int, sc->mod_params->he_mcs_map,
|
|
IEEE80211_HE_MCS_SUPPORT_0_9);
|
|
}
|
|
he_cap->he_cap_elem.phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US |
|
|
IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS;
|
|
he_cap->he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS | /* me_config no setting */
|
|
IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
|
|
IEEE80211_HE_PHY_CAP2_DOPPLER_TX |
|
|
IEEE80211_HE_PHY_CAP2_DOPPLER_RX;
|
|
|
|
he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0) /* me_config no kernel version */
|
|
he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM;
|
|
#else
|
|
he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM |
|
|
IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA; /* me_config always setting*/
|
|
#endif
|
|
he_cap->he_cap_elem.phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1;
|
|
|
|
if (sc->mod_params->bfmee) {
|
|
he_cap->he_cap_elem.phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE;
|
|
he_cap->he_cap_elem.phy_cap_info[4] |=
|
|
IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4;
|
|
}
|
|
|
|
he_cap->he_cap_elem.phy_cap_info[5] |= IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK;
|
|
he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
|
|
IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0) /* me_config no kernel version */
|
|
IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
|
|
#endif
|
|
IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
|
|
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
|
|
he_cap->he_cap_elem.phy_cap_info[7] |= IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
|
|
IEEE80211_HE_PHY_CAP7_MAX_NC_1;
|
|
he_cap->he_cap_elem.phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI |
|
|
IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
|
|
IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
|
|
dcm_max_ru;
|
|
he_cap->he_cap_elem.phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK |
|
|
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
|
|
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
|
|
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED;
|
|
|
|
// Starting from version v31 more HE_ER_SU modulations is supported
|
|
if (__MDM_VERSION(phy_vers) > 30) {
|
|
|
|
he_cap->he_cap_elem.phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE;
|
|
he_cap->he_cap_elem.phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI |
|
|
IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI;
|
|
}
|
|
|
|
mcs_map = sc->mod_params->he_mcs_map;
|
|
memset(&he_cap->he_mcs_nss_supp, 0, sizeof(he_cap->he_mcs_nss_supp));
|
|
for (i = 0; i < nss; i++) {
|
|
__le16 unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i*2));
|
|
he_cap->he_mcs_nss_supp.rx_mcs_80 |= cpu_to_le16(mcs_map << (i*2));
|
|
he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss;
|
|
he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss;
|
|
mcs_map = min_t(int, sc->mod_params->he_mcs_map,
|
|
mcs_map_max_2ss);
|
|
}
|
|
for (; i < 8; i++) {
|
|
__le16 unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i*2));
|
|
he_cap->he_mcs_nss_supp.rx_mcs_80 |= unsup_for_ss;
|
|
he_cap->he_mcs_nss_supp.rx_mcs_160 |= unsup_for_ss;
|
|
he_cap->he_mcs_nss_supp.rx_mcs_80p80 |= unsup_for_ss;
|
|
}
|
|
mcs_map = sc->mod_params->he_mcs_map;
|
|
for (i = 0; i < nss; i++) {
|
|
__le16 unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i*2));
|
|
he_cap->he_mcs_nss_supp.tx_mcs_80 |= cpu_to_le16(mcs_map << (i*2));
|
|
he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss;
|
|
he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss;
|
|
mcs_map = min_t(int, sc->mod_params->he_mcs_map,
|
|
mcs_map_max_2ss);
|
|
}
|
|
for (; i < 8; i++) {
|
|
__le16 unsup_for_ss = cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << (i*2));
|
|
he_cap->he_mcs_nss_supp.tx_mcs_80 |= unsup_for_ss;
|
|
he_cap->he_mcs_nss_supp.tx_mcs_160 |= unsup_for_ss;
|
|
he_cap->he_mcs_nss_supp.tx_mcs_80p80 |= unsup_for_ss;
|
|
}
|
|
#endif
|
|
|
|
if (sc->mod_params->custregd) {
|
|
SSV_LOG_ERR(
|
|
"\n\n%s: CAUTION: USING PERMISSIVE CUSTOM REGULATORY RULES\n",
|
|
__func__);
|
|
|
|
if(ssv_cfg.channel_list_2p4g)
|
|
{
|
|
SSV_LOG_DBG("channel_list_2p4g 0x%X\n", ssv_cfg.channel_list_2p4g);
|
|
ssv_get_custom_channle_range(ssv_cfg.channel_list_2p4g, &custom_channel_info);
|
|
//dump_custom_channel_info(&custom_channel_info);
|
|
|
|
regdom_rule_len = (u32)(sizeof(struct ieee80211_reg_rule) * custom_channel_info.n_ch_rules);
|
|
ssv_regdom_total_len = (u32)(sizeof(struct ieee80211_regdomain) + regdom_rule_len);
|
|
// SSV_LOG_DBG("rule len %d, total_len %d\n", regdom_rule_len, ssv_regdom_total_len);
|
|
|
|
ssv_custom_regdom = kzalloc(ssv_regdom_total_len +1, GFP_KERNEL);
|
|
if (!ssv_custom_regdom) {
|
|
SSV_LOG_ERR("%s(): Fail to alloc ssv_regdom buffer.\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
ssv_gen_custom_regulatory(&custom_channel_info, ssv_custom_regdom);
|
|
dump_custom_regulatory(ssv_custom_regdom);
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
|
|
#else
|
|
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
|
#endif
|
|
wiphy_apply_custom_regulatory(wiphy, ssv_custom_regdom);
|
|
|
|
//SSV_LOG_DBG("Free ssv_custom_regdom\n");
|
|
kfree(ssv_custom_regdom);
|
|
}
|
|
else
|
|
{
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
|
|
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
|
|
#else
|
|
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
|
|
#endif
|
|
wiphy_apply_custom_regulatory(wiphy, &ssv_regdom);
|
|
}
|
|
}
|
|
|
|
|
|
wiphy->max_scan_ssids = SCAN_SSID_MAX;
|
|
wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
|
|
|
|
/**
|
|
* adjust caps with lower layers sc->version_cfm
|
|
*/
|
|
#ifndef CONFIG_SSV_SDM
|
|
switch (mdm_phy_cfg) {
|
|
case MDM_PHY_CONFIG_TRIDENT:
|
|
{
|
|
// SSV_DBG("%s: found Trident phy .. using phy bw tweaks\n", __func__);
|
|
sc->use_phy_bw_tweaks = true;
|
|
break;
|
|
}
|
|
case MDM_PHY_CONFIG_ELMA:
|
|
// SSV_DBG("%s: found ELMA phy .. disabling 2.4GHz and greenfield rx\n", __func__);
|
|
wiphy->bands[NL80211_BAND_2GHZ] = NULL;
|
|
band_2GHz->ht_cap.cap &= ~IEEE80211_HT_CAP_GRN_FLD;
|
|
break;
|
|
case MDM_PHY_CONFIG_KARST:
|
|
{
|
|
break;
|
|
}
|
|
default:
|
|
WARN_ON(1);
|
|
break;
|
|
}
|
|
#endif /* CONFIG_SSV_SDM */
|
|
|
|
return 0;
|
|
}
|