Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
This commit is contained in:
commit
444474dd5b
|
@ -83,6 +83,8 @@
|
|||
#define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */
|
||||
#define IWL3160_NVM_VERSION 0x709
|
||||
#define IWL3160_TX_POWER_VERSION 0xffff /* meaningless */
|
||||
#define IWL7265_NVM_VERSION 0x0a1d
|
||||
#define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */
|
||||
|
||||
#define IWL7260_FW_PRE "iwlwifi-7260-"
|
||||
#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode"
|
||||
|
@ -90,6 +92,9 @@
|
|||
#define IWL3160_FW_PRE "iwlwifi-3160-"
|
||||
#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode"
|
||||
|
||||
#define IWL7265_FW_PRE "iwlwifi-7265-"
|
||||
#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
|
||||
|
||||
static const struct iwl_base_params iwl7000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
|
@ -182,5 +187,14 @@ const struct iwl_cfg iwl3160_n_cfg = {
|
|||
.nvm_calib_ver = IWL3160_TX_POWER_VERSION,
|
||||
};
|
||||
|
||||
const struct iwl_cfg iwl7265_2ac_cfg = {
|
||||
.name = "Intel(R) Dual Band Wireless AC 7265",
|
||||
.fw_name_pre = IWL7265_FW_PRE,
|
||||
IWL_DEVICE_7000,
|
||||
.ht_params = &iwl7000_ht_params,
|
||||
.nvm_ver = IWL7265_NVM_VERSION,
|
||||
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
|
||||
MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK));
|
||||
|
|
|
@ -292,6 +292,7 @@ extern const struct iwl_cfg iwl7260_n_cfg;
|
|||
extern const struct iwl_cfg iwl3160_2ac_cfg;
|
||||
extern const struct iwl_cfg iwl3160_2n_cfg;
|
||||
extern const struct iwl_cfg iwl3160_n_cfg;
|
||||
extern const struct iwl_cfg iwl7265_2ac_cfg;
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
#endif /* __IWL_CONFIG_H__ */
|
||||
|
|
|
@ -394,6 +394,38 @@
|
|||
#define CSR_DRAM_INT_TBL_ENABLE (1 << 31)
|
||||
#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27)
|
||||
|
||||
/* SECURE boot registers */
|
||||
#define CSR_SECURE_BOOT_CONFIG_ADDR (0x100)
|
||||
enum secure_boot_config_reg {
|
||||
CSR_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001,
|
||||
CSR_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002,
|
||||
};
|
||||
|
||||
#define CSR_SECURE_BOOT_CPU1_STATUS_ADDR (0x100)
|
||||
#define CSR_SECURE_BOOT_CPU2_STATUS_ADDR (0x100)
|
||||
enum secure_boot_status_reg {
|
||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000003,
|
||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002,
|
||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004,
|
||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008,
|
||||
CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010,
|
||||
};
|
||||
|
||||
#define CSR_UCODE_LOAD_STATUS_ADDR (0x100)
|
||||
enum secure_load_status_reg {
|
||||
CSR_CPU_STATUS_LOADING_STARTED = 0x00000001,
|
||||
CSR_CPU_STATUS_LOADING_COMPLETED = 0x00000002,
|
||||
CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8,
|
||||
CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00,
|
||||
};
|
||||
|
||||
#define CSR_SECURE_INSPECTOR_CODE_ADDR (0x100)
|
||||
#define CSR_SECURE_INSPECTOR_DATA_ADDR (0x100)
|
||||
|
||||
#define CSR_SECURE_TIME_OUT (100)
|
||||
|
||||
#define FH_TCSR_0_REG0 (0x1D00)
|
||||
|
||||
/*
|
||||
* HBUS (Host-side Bus)
|
||||
*
|
||||
|
|
|
@ -483,6 +483,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
const u8 *tlv_data;
|
||||
char buildstr[25];
|
||||
u32 build;
|
||||
int num_of_cpus;
|
||||
|
||||
if (len < sizeof(*ucode)) {
|
||||
IWL_ERR(drv, "uCode has invalid length: %zd\n", len);
|
||||
|
@ -692,6 +693,42 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
goto invalid_tlv_len;
|
||||
drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data);
|
||||
break;
|
||||
case IWL_UCODE_TLV_SECURE_SEC_RT:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.img[IWL_UCODE_REGULAR].is_secure = true;
|
||||
break;
|
||||
case IWL_UCODE_TLV_SECURE_SEC_INIT:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.img[IWL_UCODE_INIT].is_secure = true;
|
||||
break;
|
||||
case IWL_UCODE_TLV_SECURE_SEC_WOWLAN:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.img[IWL_UCODE_WOWLAN].is_secure = true;
|
||||
break;
|
||||
case IWL_UCODE_TLV_NUM_OF_CPU:
|
||||
if (tlv_len != sizeof(u32))
|
||||
goto invalid_tlv_len;
|
||||
num_of_cpus =
|
||||
le32_to_cpup((__le32 *)tlv_data);
|
||||
|
||||
if (num_of_cpus == 2) {
|
||||
drv->fw.img[IWL_UCODE_REGULAR].is_dual_cpus =
|
||||
true;
|
||||
drv->fw.img[IWL_UCODE_INIT].is_dual_cpus =
|
||||
true;
|
||||
drv->fw.img[IWL_UCODE_WOWLAN].is_dual_cpus =
|
||||
true;
|
||||
} else if ((num_of_cpus > 2) || (num_of_cpus < 1)) {
|
||||
IWL_ERR(drv, "Driver support upto 2 CPUs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
|
||||
break;
|
||||
|
|
|
@ -121,6 +121,10 @@ enum iwl_ucode_tlv_type {
|
|||
IWL_UCODE_TLV_SEC_WOWLAN = 21,
|
||||
IWL_UCODE_TLV_DEF_CALIB = 22,
|
||||
IWL_UCODE_TLV_PHY_SKU = 23,
|
||||
IWL_UCODE_TLV_SECURE_SEC_RT = 24,
|
||||
IWL_UCODE_TLV_SECURE_SEC_INIT = 25,
|
||||
IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
|
||||
IWL_UCODE_TLV_NUM_OF_CPU = 27,
|
||||
};
|
||||
|
||||
struct iwl_ucode_tlv {
|
||||
|
|
|
@ -75,11 +75,23 @@
|
|||
* @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P.
|
||||
* @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS
|
||||
* @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD
|
||||
* @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan
|
||||
* offload profile config command.
|
||||
* @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api
|
||||
* @IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API.
|
||||
* @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six
|
||||
* (rather than two) IPv6 addresses
|
||||
* @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API
|
||||
* @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element
|
||||
* from the probe request template.
|
||||
* @IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping
|
||||
* connection when going back to D0
|
||||
* @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version)
|
||||
* @IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version)
|
||||
* @IWL_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan.
|
||||
* @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
|
||||
* @IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
|
||||
* containing CAM (Continuous Active Mode) indication.
|
||||
*/
|
||||
enum iwl_ucode_tlv_flag {
|
||||
IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
|
||||
|
@ -87,11 +99,20 @@ enum iwl_ucode_tlv_flag {
|
|||
IWL_UCODE_TLV_FLAGS_MFP = BIT(2),
|
||||
IWL_UCODE_TLV_FLAGS_P2P = BIT(3),
|
||||
IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4),
|
||||
IWL_UCODE_TLV_FLAGS_NEWBT_COEX = BIT(5),
|
||||
IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6),
|
||||
IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7),
|
||||
IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8),
|
||||
IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = BIT(9),
|
||||
IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10),
|
||||
IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11),
|
||||
IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12),
|
||||
IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API = BIT(14),
|
||||
IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = BIT(15),
|
||||
IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = BIT(16),
|
||||
IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17),
|
||||
IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19),
|
||||
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD = BIT(20),
|
||||
};
|
||||
|
||||
/* The default calibrate table size if not specified by firmware file */
|
||||
|
@ -133,7 +154,8 @@ enum iwl_ucode_sec {
|
|||
* For 16.0 uCode and above, there is no differentiation between sections,
|
||||
* just an offset to the HW address.
|
||||
*/
|
||||
#define IWL_UCODE_SECTION_MAX 4
|
||||
#define IWL_UCODE_SECTION_MAX 6
|
||||
#define IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU (IWL_UCODE_SECTION_MAX/2)
|
||||
|
||||
struct iwl_ucode_capabilities {
|
||||
u32 max_probe_length;
|
||||
|
@ -150,6 +172,8 @@ struct fw_desc {
|
|||
|
||||
struct fw_img {
|
||||
struct fw_desc sec[IWL_UCODE_SECTION_MAX];
|
||||
bool is_secure;
|
||||
bool is_dual_cpus;
|
||||
};
|
||||
|
||||
/* uCode version contains 4 values: Major/Minor/API/Serial */
|
||||
|
|
|
@ -97,6 +97,8 @@
|
|||
|
||||
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
|
||||
|
||||
#define APMG_RTC_INT_STT_RFKILL (0x10000000)
|
||||
|
||||
/* Device system time */
|
||||
#define DEVICE_SYSTEM_TIME_REG 0xA0206C
|
||||
|
||||
|
|
|
@ -98,126 +98,258 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
|
|||
|
||||
#undef EVENT_PRIO_ANT
|
||||
|
||||
/* BT Antenna Coupling Threshold (dB) */
|
||||
#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
|
||||
#define IWL_BT_LOAD_FORCE_SISO_THRESHOLD (3)
|
||||
|
||||
#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62)
|
||||
#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65)
|
||||
#define BT_REDUCED_TX_POWER_BIT BIT(7)
|
||||
|
||||
static inline bool is_loose_coex(void)
|
||||
{
|
||||
return iwlwifi_mod_params.ant_coupling >
|
||||
IWL_BT_ANTENNA_COUPLING_THRESHOLD;
|
||||
}
|
||||
#define BT_ANTENNA_COUPLING_THRESHOLD (30)
|
||||
|
||||
int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
|
||||
{
|
||||
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX))
|
||||
return 0;
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC,
|
||||
sizeof(struct iwl_bt_coex_prio_tbl_cmd),
|
||||
&iwl_bt_prio_tbl);
|
||||
}
|
||||
|
||||
static int iwl_send_bt_env(struct iwl_mvm *mvm, u8 action, u8 type)
|
||||
{
|
||||
struct iwl_bt_coex_prot_env_cmd env_cmd;
|
||||
int ret;
|
||||
const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = {
|
||||
[BT_KILL_MSK_DEFAULT] = 0xffff0000,
|
||||
[BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff,
|
||||
[BT_KILL_MSK_REDUCED_TXPOW] = 0,
|
||||
};
|
||||
|
||||
const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = {
|
||||
[BT_KILL_MSK_DEFAULT] = 0xffff0000,
|
||||
[BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff,
|
||||
[BT_KILL_MSK_REDUCED_TXPOW] = 0,
|
||||
};
|
||||
|
||||
static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = {
|
||||
cpu_to_le32(0xf0f0f0f0),
|
||||
cpu_to_le32(0xc0c0c0c0),
|
||||
cpu_to_le32(0xfcfcfcfc),
|
||||
cpu_to_le32(0xff00ff00),
|
||||
};
|
||||
|
||||
static const __le32 iwl_single_shared_ant[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {
|
||||
{
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
{
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
{
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
};
|
||||
|
||||
static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = {
|
||||
{
|
||||
/* Tight */
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaeaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xcc00ff28),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xcc00aaaa),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
{
|
||||
/* Loose */
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xcc00ff28),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xcc00aaaa),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
},
|
||||
{
|
||||
/* Tx Tx disabled */
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xcc00ff28),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xcc00aaaa),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xC0004000),
|
||||
cpu_to_le32(0xC0004000),
|
||||
cpu_to_le32(0xF0005000),
|
||||
cpu_to_le32(0xF0005000),
|
||||
},
|
||||
};
|
||||
|
||||
/* 20MHz / 40MHz below / 40Mhz above*/
|
||||
static const __le64 iwl_ci_mask[][3] = {
|
||||
/* dummy entry for channel 0 */
|
||||
{cpu_to_le64(0), cpu_to_le64(0), cpu_to_le64(0)},
|
||||
{
|
||||
cpu_to_le64(0x0000001FFFULL),
|
||||
cpu_to_le64(0x0ULL),
|
||||
cpu_to_le64(0x00007FFFFFULL),
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0x000000FFFFULL),
|
||||
cpu_to_le64(0x0ULL),
|
||||
cpu_to_le64(0x0003FFFFFFULL),
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0x000003FFFCULL),
|
||||
cpu_to_le64(0x0ULL),
|
||||
cpu_to_le64(0x000FFFFFFCULL),
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0x00001FFFE0ULL),
|
||||
cpu_to_le64(0x0ULL),
|
||||
cpu_to_le64(0x007FFFFFE0ULL),
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0x00007FFF80ULL),
|
||||
cpu_to_le64(0x00007FFFFFULL),
|
||||
cpu_to_le64(0x01FFFFFF80ULL),
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0x0003FFFC00ULL),
|
||||
cpu_to_le64(0x0003FFFFFFULL),
|
||||
cpu_to_le64(0x0FFFFFFC00ULL),
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0x000FFFF000ULL),
|
||||
cpu_to_le64(0x000FFFFFFCULL),
|
||||
cpu_to_le64(0x3FFFFFF000ULL),
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0x007FFF8000ULL),
|
||||
cpu_to_le64(0x007FFFFFE0ULL),
|
||||
cpu_to_le64(0xFFFFFF8000ULL),
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0x01FFFE0000ULL),
|
||||
cpu_to_le64(0x01FFFFFF80ULL),
|
||||
cpu_to_le64(0xFFFFFE0000ULL),
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0x0FFFF00000ULL),
|
||||
cpu_to_le64(0x0FFFFFFC00ULL),
|
||||
cpu_to_le64(0x0ULL),
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0x3FFFC00000ULL),
|
||||
cpu_to_le64(0x3FFFFFF000ULL),
|
||||
cpu_to_le64(0x0)
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0xFFFE000000ULL),
|
||||
cpu_to_le64(0xFFFFFF8000ULL),
|
||||
cpu_to_le64(0x0)
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0xFFF8000000ULL),
|
||||
cpu_to_le64(0xFFFFFE0000ULL),
|
||||
cpu_to_le64(0x0)
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0xFE00000000ULL),
|
||||
cpu_to_le64(0x0ULL),
|
||||
cpu_to_le64(0x0)
|
||||
},
|
||||
};
|
||||
|
||||
static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
|
||||
cpu_to_le32(0x22002200),
|
||||
cpu_to_le32(0x33113311),
|
||||
};
|
||||
|
||||
static enum iwl_bt_coex_lut_type
|
||||
iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
enum iwl_bt_coex_lut_type ret;
|
||||
u16 phy_ctx_id;
|
||||
|
||||
/*
|
||||
* Checking that we hold mvm->mutex is a good idea, but the rate
|
||||
* control can't acquire the mutex since it runs in Tx path.
|
||||
* So this is racy in that case, but in the worst case, the AMPDU
|
||||
* size limit will be wrong for a short time which is not a big
|
||||
* issue.
|
||||
*/
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
chanctx_conf = rcu_dereference(vif->chanctx_conf);
|
||||
|
||||
if (!chanctx_conf ||
|
||||
chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) {
|
||||
rcu_read_unlock();
|
||||
return BT_COEX_LOOSE_LUT;
|
||||
}
|
||||
|
||||
ret = BT_COEX_TX_DIS_LUT;
|
||||
|
||||
if (mvm->cfg->bt_shared_single_ant) {
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
phy_ctx_id = *((u16 *)chanctx_conf->drv_priv);
|
||||
|
||||
if (mvm->last_bt_ci_cmd.primary_ch_phy_id == phy_ctx_id)
|
||||
ret = le32_to_cpu(mvm->last_bt_notif.primary_ch_lut);
|
||||
else if (mvm->last_bt_ci_cmd.secondary_ch_phy_id == phy_ctx_id)
|
||||
ret = le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut);
|
||||
/* else - default = TX TX disallowed */
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
env_cmd.action = action;
|
||||
env_cmd.type = type;
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PROT_ENV, CMD_SYNC,
|
||||
sizeof(env_cmd), &env_cmd);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to send BT env command\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum iwl_bt_kill_msk {
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_SCO_HID_A2DP,
|
||||
BT_KILL_MSK_REDUCED_TXPOW,
|
||||
BT_KILL_MSK_MAX,
|
||||
};
|
||||
|
||||
static const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = {
|
||||
[BT_KILL_MSK_DEFAULT] = 0xffff0000,
|
||||
[BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff,
|
||||
[BT_KILL_MSK_REDUCED_TXPOW] = 0,
|
||||
};
|
||||
|
||||
static const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = {
|
||||
[BT_KILL_MSK_DEFAULT] = 0xffff0000,
|
||||
[BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff,
|
||||
[BT_KILL_MSK_REDUCED_TXPOW] = 0,
|
||||
};
|
||||
|
||||
#define IWL_BT_DEFAULT_BOOST (0xf0f0f0f0)
|
||||
|
||||
/* Tight Coex */
|
||||
static const __le32 iwl_tight_lookup[BT_COEX_LUT_SIZE] = {
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaeaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xcc00ff28),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xcc00aaaa),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xc0004000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
};
|
||||
|
||||
/* Loose Coex */
|
||||
static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = {
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xcc00ff28),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xcc00aaaa),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
};
|
||||
|
||||
/* Full concurrency */
|
||||
static const __le32 iwl_concurrent_lookup[BT_COEX_LUT_SIZE] = {
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
};
|
||||
|
||||
/* single shared antenna */
|
||||
static const __le32 iwl_single_shared_ant_lookup[BT_COEX_LUT_SIZE] = {
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x40000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x44000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xC0004000),
|
||||
cpu_to_le32(0xF0005000),
|
||||
cpu_to_le32(0xC0004000),
|
||||
cpu_to_le32(0xF0005000),
|
||||
};
|
||||
|
||||
int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_bt_coex_cmd *bt_cmd;
|
||||
|
@ -228,17 +360,10 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
|
|||
.flags = CMD_SYNC,
|
||||
};
|
||||
int ret;
|
||||
u32 flags;
|
||||
|
||||
/* go to CALIB state in internal BT-Coex state machine */
|
||||
ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX))
|
||||
return 0;
|
||||
|
||||
bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
|
||||
if (!bt_cmd)
|
||||
|
@ -246,40 +371,52 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
|
|||
cmd.data[0] = bt_cmd;
|
||||
|
||||
bt_cmd->max_kill = 5;
|
||||
bt_cmd->bt3_time_t7_value = 1;
|
||||
bt_cmd->bt3_prio_sample_time = 2;
|
||||
bt_cmd->bt3_timer_t2_value = 0xc;
|
||||
bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD,
|
||||
bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling,
|
||||
bt_cmd->bt4_tx_tx_delta_freq_thr = 15,
|
||||
bt_cmd->bt4_tx_rx_max_freq0 = 15,
|
||||
|
||||
bt_cmd->flags = iwlwifi_mod_params.bt_coex_active ?
|
||||
flags = iwlwifi_mod_params.bt_coex_active ?
|
||||
BT_COEX_NW : BT_COEX_DISABLE;
|
||||
bt_cmd->flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE;
|
||||
flags |= BT_CH_PRIMARY_EN | BT_CH_SECONDARY_EN | BT_SYNC_2_BT_DISABLE;
|
||||
bt_cmd->flags = cpu_to_le32(flags);
|
||||
|
||||
bt_cmd->valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE |
|
||||
bt_cmd->valid_bit_msk = cpu_to_le32(BT_VALID_ENABLE |
|
||||
BT_VALID_BT_PRIO_BOOST |
|
||||
BT_VALID_MAX_KILL |
|
||||
BT_VALID_3W_TMRS |
|
||||
BT_VALID_KILL_ACK |
|
||||
BT_VALID_KILL_CTS |
|
||||
BT_VALID_REDUCED_TX_POWER |
|
||||
BT_VALID_LUT);
|
||||
BT_VALID_LUT |
|
||||
BT_VALID_WIFI_RX_SW_PRIO_BOOST |
|
||||
BT_VALID_WIFI_TX_SW_PRIO_BOOST |
|
||||
BT_VALID_MULTI_PRIO_LUT |
|
||||
BT_VALID_CORUN_LUT_20 |
|
||||
BT_VALID_CORUN_LUT_40 |
|
||||
BT_VALID_ANT_ISOLATION |
|
||||
BT_VALID_ANT_ISOLATION_THRS |
|
||||
BT_VALID_TXTX_DELTA_FREQ_THRS |
|
||||
BT_VALID_TXRX_MAX_FREQ_0);
|
||||
|
||||
if (mvm->cfg->bt_shared_single_ant)
|
||||
memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant_lookup,
|
||||
sizeof(iwl_single_shared_ant_lookup));
|
||||
else if (is_loose_coex())
|
||||
memcpy(&bt_cmd->decision_lut, iwl_loose_lookup,
|
||||
sizeof(iwl_tight_lookup));
|
||||
memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant,
|
||||
sizeof(iwl_single_shared_ant));
|
||||
else
|
||||
memcpy(&bt_cmd->decision_lut, iwl_tight_lookup,
|
||||
sizeof(iwl_tight_lookup));
|
||||
memcpy(&bt_cmd->decision_lut, iwl_combined_lookup,
|
||||
sizeof(iwl_combined_lookup));
|
||||
|
||||
bt_cmd->bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST);
|
||||
memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost,
|
||||
sizeof(iwl_bt_prio_boost));
|
||||
memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut,
|
||||
sizeof(iwl_bt_mprio_lut));
|
||||
bt_cmd->kill_ack_msk =
|
||||
cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]);
|
||||
bt_cmd->kill_cts_msk =
|
||||
cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]);
|
||||
|
||||
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
|
||||
memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
|
||||
|
||||
ret = iwl_mvm_send_cmd(mvm, &cmd);
|
||||
|
||||
|
@ -334,13 +471,17 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
|
|||
if (!bt_cmd)
|
||||
return -ENOMEM;
|
||||
cmd.data[0] = bt_cmd;
|
||||
bt_cmd->flags = cpu_to_le32(BT_COEX_NW);
|
||||
|
||||
bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]);
|
||||
bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]);
|
||||
bt_cmd->valid_bit_msk =
|
||||
cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS);
|
||||
bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE |
|
||||
BT_VALID_KILL_ACK |
|
||||
BT_VALID_KILL_CTS);
|
||||
|
||||
IWL_DEBUG_COEX(mvm, "bt_kill_msk = %d\n", bt_kill_msk);
|
||||
IWL_DEBUG_COEX(mvm, "ACK Kill msk = 0x%08x, CTS Kill msk = 0x%08x\n",
|
||||
iwl_bt_ack_kill_msk[bt_kill_msk],
|
||||
iwl_bt_cts_kill_msk[bt_kill_msk]);
|
||||
|
||||
ret = iwl_mvm_send_cmd(mvm, &cmd);
|
||||
|
||||
|
@ -380,8 +521,10 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
|
|||
if (!bt_cmd)
|
||||
return -ENOMEM;
|
||||
cmd.data[0] = bt_cmd;
|
||||
bt_cmd->flags = cpu_to_le32(BT_COEX_NW);
|
||||
|
||||
bt_cmd->valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER),
|
||||
bt_cmd->valid_bit_msk =
|
||||
cpu_to_le32(BT_VALID_ENABLE | BT_VALID_REDUCED_TX_POWER);
|
||||
bt_cmd->bt_reduced_tx_power = sta_id;
|
||||
|
||||
if (enable)
|
||||
|
@ -403,8 +546,25 @@ struct iwl_bt_iterator_data {
|
|||
struct iwl_mvm *mvm;
|
||||
u32 num_bss_ifaces;
|
||||
bool reduced_tx_power;
|
||||
struct ieee80211_chanctx_conf *primary;
|
||||
struct ieee80211_chanctx_conf *secondary;
|
||||
};
|
||||
|
||||
static inline
|
||||
void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
bool enable, int rssi)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
mvmvif->bf_data.last_bt_coex_event = rssi;
|
||||
mvmvif->bf_data.bt_coex_max_thold =
|
||||
enable ? BT_ENABLE_REDUCED_TXPOWER_THRESHOLD : 0;
|
||||
mvmvif->bf_data.bt_coex_min_thold =
|
||||
enable ? BT_DISABLE_REDUCED_TXPOWER_THRESHOLD : 0;
|
||||
}
|
||||
|
||||
/* must be called under rcu_read_lock */
|
||||
static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
|
@ -413,65 +573,94 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
|||
struct iwl_mvm *mvm = data->mvm;
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
enum ieee80211_band band;
|
||||
int ave_rssi;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
if (vif->type != NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(vif->chanctx_conf);
|
||||
if (chanctx_conf && chanctx_conf->def.chan)
|
||||
band = chanctx_conf->def.chan->band;
|
||||
else
|
||||
band = -1;
|
||||
rcu_read_unlock();
|
||||
if (vif->type != NL80211_IFTYPE_STATION &&
|
||||
vif->type != NL80211_IFTYPE_AP)
|
||||
return;
|
||||
|
||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||
|
||||
/* non associated BSSes aren't to be considered */
|
||||
if (!vif->bss_conf.assoc)
|
||||
return;
|
||||
chanctx_conf = rcu_dereference(vif->chanctx_conf);
|
||||
|
||||
if (band != IEEE80211_BAND_2GHZ) {
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
|
||||
smps_mode);
|
||||
/* If channel context is invalid or not on 2.4GHz .. */
|
||||
if ((!chanctx_conf ||
|
||||
chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) {
|
||||
/* ... and it is an associated STATION, relax constraints */
|
||||
if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc)
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
|
||||
smps_mode);
|
||||
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->notif->bt_status)
|
||||
/* SoftAP / GO will always be primary */
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
if (!mvmvif->ap_ibss_active)
|
||||
return;
|
||||
|
||||
/* the Ack / Cts kill mask must be default if AP / GO */
|
||||
data->reduced_tx_power = false;
|
||||
|
||||
if (chanctx_conf == data->primary)
|
||||
return;
|
||||
|
||||
/* downgrade the current primary no matter what its type is */
|
||||
data->secondary = data->primary;
|
||||
data->primary = chanctx_conf;
|
||||
return;
|
||||
}
|
||||
|
||||
data->num_bss_ifaces++;
|
||||
|
||||
/* we are now a STA / P2P Client, and take associated ones only */
|
||||
if (!vif->bss_conf.assoc)
|
||||
return;
|
||||
|
||||
/* STA / P2P Client, try to be primary if first vif */
|
||||
if (!data->primary || data->primary == chanctx_conf)
|
||||
data->primary = chanctx_conf;
|
||||
else if (!data->secondary)
|
||||
/* if secondary is not NULL, it might be a GO */
|
||||
data->secondary = chanctx_conf;
|
||||
|
||||
if (le32_to_cpu(data->notif->bt_activity_grading) >= BT_HIGH_TRAFFIC)
|
||||
smps_mode = IEEE80211_SMPS_STATIC;
|
||||
else if (le32_to_cpu(data->notif->bt_activity_grading) >=
|
||||
BT_LOW_TRAFFIC)
|
||||
smps_mode = IEEE80211_SMPS_DYNAMIC;
|
||||
|
||||
if (data->notif->bt_traffic_load >= IWL_BT_LOAD_FORCE_SISO_THRESHOLD)
|
||||
smps_mode = IEEE80211_SMPS_STATIC;
|
||||
|
||||
IWL_DEBUG_COEX(data->mvm,
|
||||
"mac %d: bt_status %d traffic_load %d smps_req %d\n",
|
||||
"mac %d: bt_status %d bt_activity_grading %d smps_req %d\n",
|
||||
mvmvif->id, data->notif->bt_status,
|
||||
data->notif->bt_traffic_load, smps_mode);
|
||||
data->notif->bt_activity_grading, smps_mode);
|
||||
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode);
|
||||
|
||||
/* don't reduce the Tx power if in loose scheme */
|
||||
if (is_loose_coex())
|
||||
if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
|
||||
mvm->cfg->bt_shared_single_ant) {
|
||||
data->reduced_tx_power = false;
|
||||
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
data->num_bss_ifaces++;
|
||||
|
||||
/* reduced Txpower only if there are open BT connections, so ...*/
|
||||
if (!BT_MBOX_MSG(data->notif, 3, OPEN_CON_2)) {
|
||||
/* reduced Txpower only if BT is on, so ...*/
|
||||
if (!data->notif->bt_status) {
|
||||
/* ... cancel reduced Tx power ... */
|
||||
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
|
||||
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
|
||||
data->reduced_tx_power = false;
|
||||
|
||||
/* ... and there is no need to get reports on RSSI any more. */
|
||||
ieee80211_disable_rssi_reports(vif);
|
||||
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
ave_rssi = ieee80211_ave_rssi(vif);
|
||||
/* try to get the avg rssi from fw */
|
||||
ave_rssi = mvmvif->bf_data.ave_beacon_signal;
|
||||
|
||||
/* if the RSSI isn't valid, fake it is very low */
|
||||
if (!ave_rssi)
|
||||
|
@ -499,8 +688,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
|||
}
|
||||
|
||||
/* Begin to monitor the RSSI: it may influence the reduced Tx power */
|
||||
ieee80211_enable_rssi_reports(vif, BT_DISABLE_REDUCED_TXPOWER_THRESHOLD,
|
||||
BT_ENABLE_REDUCED_TXPOWER_THRESHOLD);
|
||||
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi);
|
||||
}
|
||||
|
||||
static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
|
||||
|
@ -510,11 +698,72 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
|
|||
.notif = &mvm->last_bt_notif,
|
||||
.reduced_tx_power = true,
|
||||
};
|
||||
struct iwl_bt_coex_ci_cmd cmd = {};
|
||||
u8 ci_bw_idx;
|
||||
|
||||
rcu_read_lock();
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_bt_notif_iterator, &data);
|
||||
|
||||
if (data.primary) {
|
||||
struct ieee80211_chanctx_conf *chan = data.primary;
|
||||
if (WARN_ON(!chan->def.chan)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (chan->def.width < NL80211_CHAN_WIDTH_40) {
|
||||
ci_bw_idx = 0;
|
||||
cmd.co_run_bw_primary = 0;
|
||||
} else {
|
||||
cmd.co_run_bw_primary = 1;
|
||||
if (chan->def.center_freq1 >
|
||||
chan->def.chan->center_freq)
|
||||
ci_bw_idx = 2;
|
||||
else
|
||||
ci_bw_idx = 1;
|
||||
}
|
||||
|
||||
cmd.bt_primary_ci =
|
||||
iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
|
||||
cmd.primary_ch_phy_id = *((u16 *)data.primary->drv_priv);
|
||||
}
|
||||
|
||||
if (data.secondary) {
|
||||
struct ieee80211_chanctx_conf *chan = data.secondary;
|
||||
if (WARN_ON(!data.secondary->def.chan)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (chan->def.width < NL80211_CHAN_WIDTH_40) {
|
||||
ci_bw_idx = 0;
|
||||
cmd.co_run_bw_secondary = 0;
|
||||
} else {
|
||||
cmd.co_run_bw_secondary = 1;
|
||||
if (chan->def.center_freq1 >
|
||||
chan->def.chan->center_freq)
|
||||
ci_bw_idx = 2;
|
||||
else
|
||||
ci_bw_idx = 1;
|
||||
}
|
||||
|
||||
cmd.bt_secondary_ci =
|
||||
iwl_ci_mask[chan->def.chan->hw_value][ci_bw_idx];
|
||||
cmd.secondary_ch_phy_id = *((u16 *)data.primary->drv_priv);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* Don't spam the fw with the same command over and over */
|
||||
if (memcmp(&cmd, &mvm->last_bt_ci_cmd, sizeof(cmd))) {
|
||||
if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_CI, CMD_SYNC,
|
||||
sizeof(cmd), &cmd))
|
||||
IWL_ERR(mvm, "Failed to send BT_CI cmd");
|
||||
memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are no BSS / P2P client interfaces, reduced Tx Power is
|
||||
* irrelevant since it is based on the RSSI coming from the beacon.
|
||||
|
@ -536,12 +785,18 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
|
|||
|
||||
|
||||
IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
|
||||
IWL_DEBUG_COEX(mvm, "\tBT %salive\n", notif->bt_status ? "" : "not ");
|
||||
IWL_DEBUG_COEX(mvm, "\tBT status: %s\n",
|
||||
notif->bt_status ? "ON" : "OFF");
|
||||
IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn);
|
||||
IWL_DEBUG_COEX(mvm, "\tBT traffic load %d\n", notif->bt_traffic_load);
|
||||
IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
|
||||
IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n",
|
||||
le32_to_cpu(notif->primary_ch_lut));
|
||||
IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n",
|
||||
le32_to_cpu(notif->secondary_ch_lut));
|
||||
IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n",
|
||||
le32_to_cpu(notif->bt_activity_grading));
|
||||
IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n",
|
||||
notif->bt_agg_traffic_load);
|
||||
IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
|
||||
|
||||
/* remember this notification for future use: rssi fluctuations */
|
||||
memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif));
|
||||
|
@ -565,6 +820,18 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
|
|||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
|
||||
rcu_read_lock();
|
||||
chanctx_conf = rcu_dereference(vif->chanctx_conf);
|
||||
/* If channel context is invalid or not on 2.4GHz - don't count it */
|
||||
if (!chanctx_conf ||
|
||||
chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_STATION ||
|
||||
mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
|
||||
return;
|
||||
|
@ -594,15 +861,15 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
};
|
||||
int ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
/* Rssi update while not associated ?! */
|
||||
if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT))
|
||||
goto out_unlock;
|
||||
return;
|
||||
|
||||
/* No open connection - reports should be disabled */
|
||||
if (!BT_MBOX_MSG(&mvm->last_bt_notif, 3, OPEN_CON_2))
|
||||
goto out_unlock;
|
||||
/* No BT - reports should be disabled */
|
||||
if (!mvm->last_bt_notif.bt_status)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid,
|
||||
rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW");
|
||||
|
@ -611,7 +878,8 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
* Check if rssi is good enough for reduced Tx power, but not in loose
|
||||
* scheme.
|
||||
*/
|
||||
if (rssi_event == RSSI_EVENT_LOW || is_loose_coex())
|
||||
if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant ||
|
||||
iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT)
|
||||
ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
|
||||
false);
|
||||
else
|
||||
|
@ -633,12 +901,52 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
|
||||
if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
|
||||
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000)
|
||||
#define LINK_QUAL_AGG_TIME_LIMIT_BT_ACT (1200)
|
||||
|
||||
u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
|
||||
enum iwl_bt_coex_lut_type lut_type;
|
||||
|
||||
if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
|
||||
BT_LOW_TRAFFIC)
|
||||
return LINK_QUAL_AGG_TIME_LIMIT_DEF;
|
||||
|
||||
lut_type = iwl_get_coex_type(mvm, mvmsta->vif);
|
||||
|
||||
if (lut_type == BT_COEX_LOOSE_LUT)
|
||||
return LINK_QUAL_AGG_TIME_LIMIT_DEF;
|
||||
|
||||
/* tight coex, high bt traffic, reduce AGG time limit */
|
||||
return LINK_QUAL_AGG_TIME_LIMIT_BT_ACT;
|
||||
}
|
||||
|
||||
bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
|
||||
|
||||
if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) <
|
||||
BT_HIGH_TRAFFIC)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* In Tight, BT can't Rx while we Tx, so use both antennas since BT is
|
||||
* already killed.
|
||||
* In Loose, BT can Rx while we Tx, so forbid MIMO to let BT Rx while we
|
||||
* Tx.
|
||||
*/
|
||||
return iwl_get_coex_type(mvm, mvmsta->vif) == BT_COEX_TIGHT_LUT;
|
||||
}
|
||||
|
||||
void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm)
|
||||
{
|
||||
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX))
|
||||
return;
|
||||
|
||||
iwl_mvm_bt_coex_notif_handle(mvm);
|
||||
}
|
||||
|
|
|
@ -70,7 +70,9 @@
|
|||
#define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
|
||||
#define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC)
|
||||
#define IWL_MVM_PS_HEAVY_TX_THLD_PACKETS 20
|
||||
#define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 20
|
||||
#define IWL_MVM_PS_HEAVY_RX_THLD_PACKETS 8
|
||||
#define IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS 30
|
||||
#define IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS 20
|
||||
#define IWL_MVM_PS_HEAVY_TX_THLD_PERCENT 50
|
||||
#define IWL_MVM_PS_HEAVY_RX_THLD_PERCENT 50
|
||||
#define IWL_MVM_PS_SNOOZE_INTERVAL 25
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include <net/cfg80211.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/addrconf.h>
|
||||
#include "iwl-modparams.h"
|
||||
#include "fw-api.h"
|
||||
#include "mvm.h"
|
||||
|
@ -381,14 +382,74 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
|
|||
union {
|
||||
struct iwl_proto_offload_cmd_v1 v1;
|
||||
struct iwl_proto_offload_cmd_v2 v2;
|
||||
struct iwl_proto_offload_cmd_v3_small v3s;
|
||||
struct iwl_proto_offload_cmd_v3_large v3l;
|
||||
} cmd = {};
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = PROT_OFFLOAD_CONFIG_CMD,
|
||||
.flags = CMD_SYNC,
|
||||
.data[0] = &cmd,
|
||||
.dataflags[0] = IWL_HCMD_DFL_DUP,
|
||||
};
|
||||
struct iwl_proto_offload_cmd_common *common;
|
||||
u32 enabled = 0, size;
|
||||
u32 capa_flags = mvm->fw->ucode_capa.flags;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
int i;
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
|
||||
if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL ||
|
||||
capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
|
||||
struct iwl_ns_config *nsc;
|
||||
struct iwl_targ_addr *addrs;
|
||||
int n_nsc, n_addrs;
|
||||
int c;
|
||||
|
||||
if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
|
||||
nsc = cmd.v3s.ns_config;
|
||||
n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S;
|
||||
addrs = cmd.v3s.targ_addrs;
|
||||
n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S;
|
||||
} else {
|
||||
nsc = cmd.v3l.ns_config;
|
||||
n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L;
|
||||
addrs = cmd.v3l.targ_addrs;
|
||||
n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L;
|
||||
}
|
||||
|
||||
if (mvmvif->num_target_ipv6_addrs)
|
||||
enabled |= IWL_D3_PROTO_OFFLOAD_NS;
|
||||
|
||||
/*
|
||||
* For each address we have (and that will fit) fill a target
|
||||
* address struct and combine for NS offload structs with the
|
||||
* solicited node addresses.
|
||||
*/
|
||||
for (i = 0, c = 0;
|
||||
i < mvmvif->num_target_ipv6_addrs &&
|
||||
i < n_addrs && c < n_nsc; i++) {
|
||||
struct in6_addr solicited_addr;
|
||||
int j;
|
||||
|
||||
addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i],
|
||||
&solicited_addr);
|
||||
for (j = 0; j < c; j++)
|
||||
if (ipv6_addr_cmp(&nsc[j].dest_ipv6_addr,
|
||||
&solicited_addr) == 0)
|
||||
break;
|
||||
if (j == c)
|
||||
c++;
|
||||
addrs[i].addr = mvmvif->target_ipv6_addrs[i];
|
||||
addrs[i].config_num = cpu_to_le32(j);
|
||||
nsc[j].dest_ipv6_addr = solicited_addr;
|
||||
memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN);
|
||||
}
|
||||
|
||||
if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL)
|
||||
cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i);
|
||||
else
|
||||
cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i);
|
||||
} else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
|
||||
if (mvmvif->num_target_ipv6_addrs) {
|
||||
enabled |= IWL_D3_PROTO_OFFLOAD_NS;
|
||||
memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN);
|
||||
|
@ -419,7 +480,13 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
|
|||
}
|
||||
#endif
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
|
||||
if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
|
||||
common = &cmd.v3s.common;
|
||||
size = sizeof(cmd.v3s);
|
||||
} else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
|
||||
common = &cmd.v3l.common;
|
||||
size = sizeof(cmd.v3l);
|
||||
} else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
|
||||
common = &cmd.v2.common;
|
||||
size = sizeof(cmd.v2);
|
||||
} else {
|
||||
|
@ -438,8 +505,8 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
|
|||
|
||||
common->enabled = cpu_to_le32(enabled);
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, PROT_OFFLOAD_CONFIG_CMD, CMD_SYNC,
|
||||
size, &cmd);
|
||||
hcmd.len[0] = size;
|
||||
return iwl_mvm_send_cmd(mvm, &hcmd);
|
||||
}
|
||||
|
||||
enum iwl_mvm_tcp_packet_type {
|
||||
|
@ -793,6 +860,74 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_nonqos_seq_query_cmd query_cmd = {
|
||||
.get_set_flag = cpu_to_le32(IWL_NONQOS_SEQ_GET),
|
||||
.mac_id_n_color =
|
||||
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
|
||||
mvmvif->color)),
|
||||
};
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = NON_QOS_TX_COUNTER_CMD,
|
||||
.flags = CMD_SYNC | CMD_WANT_SKB,
|
||||
};
|
||||
int err;
|
||||
u32 size;
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) {
|
||||
cmd.data[0] = &query_cmd;
|
||||
cmd.len[0] = sizeof(query_cmd);
|
||||
}
|
||||
|
||||
err = iwl_mvm_send_cmd(mvm, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
size = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
size -= sizeof(cmd.resp_pkt->hdr);
|
||||
if (size < sizeof(__le16)) {
|
||||
err = -EINVAL;
|
||||
} else {
|
||||
err = le16_to_cpup((__le16 *)cmd.resp_pkt->data);
|
||||
/* new API returns next, not last-used seqno */
|
||||
if (mvm->fw->ucode_capa.flags &
|
||||
IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API)
|
||||
err -= 0x10;
|
||||
}
|
||||
|
||||
iwl_free_resp(&cmd);
|
||||
return err;
|
||||
}
|
||||
|
||||
void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_nonqos_seq_query_cmd query_cmd = {
|
||||
.get_set_flag = cpu_to_le32(IWL_NONQOS_SEQ_SET),
|
||||
.mac_id_n_color =
|
||||
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
|
||||
mvmvif->color)),
|
||||
.value = cpu_to_le16(mvmvif->seqno),
|
||||
};
|
||||
|
||||
/* return if called during restart, not resume from D3 */
|
||||
if (!mvmvif->seqno_valid)
|
||||
return;
|
||||
|
||||
mvmvif->seqno_valid = false;
|
||||
|
||||
if (!(mvm->fw->ucode_capa.flags &
|
||||
IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API))
|
||||
return;
|
||||
|
||||
if (iwl_mvm_send_cmd_pdu(mvm, NON_QOS_TX_COUNTER_CMD, CMD_SYNC,
|
||||
sizeof(query_cmd), &query_cmd))
|
||||
IWL_ERR(mvm, "failed to set non-QoS seqno\n");
|
||||
}
|
||||
|
||||
static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
||||
struct cfg80211_wowlan *wowlan,
|
||||
bool test)
|
||||
|
@ -829,7 +964,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
};
|
||||
int ret, i;
|
||||
int len __maybe_unused;
|
||||
u16 seq;
|
||||
u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
|
||||
|
||||
if (!wowlan) {
|
||||
|
@ -872,26 +1006,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
|
||||
mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
|
||||
|
||||
/*
|
||||
* The D3 firmware still hardcodes the AP station ID for the
|
||||
* BSS we're associated with as 0. Store the real STA ID here
|
||||
* and assign 0. When we leave this function, we'll restore
|
||||
* the original value for the resume code.
|
||||
*/
|
||||
old_ap_sta_id = mvm_ap_sta->sta_id;
|
||||
mvm_ap_sta->sta_id = 0;
|
||||
mvmvif->ap_sta_id = 0;
|
||||
|
||||
/* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */
|
||||
|
||||
wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported;
|
||||
|
||||
/*
|
||||
* We know the last used seqno, and the uCode expects to know that
|
||||
* one, it will increment before TX.
|
||||
*/
|
||||
seq = mvm_ap_sta->last_seq_ctl & IEEE80211_SCTL_SEQ;
|
||||
wowlan_config_cmd.non_qos_seq = cpu_to_le16(seq);
|
||||
/* Query the last used seqno and set it */
|
||||
ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
|
||||
if (ret < 0)
|
||||
goto out_noreset;
|
||||
wowlan_config_cmd.non_qos_seq = cpu_to_le16(ret);
|
||||
|
||||
/*
|
||||
* For QoS counters, we store the one to use next, so subtract 0x10
|
||||
|
@ -899,7 +1022,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
* increment after using the value (i.e. store the next value to use).
|
||||
*/
|
||||
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
|
||||
seq = mvm_ap_sta->tid_data[i].seq_number;
|
||||
u16 seq = mvm_ap_sta->tid_data[i].seq_number;
|
||||
seq -= 0x10;
|
||||
wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq);
|
||||
}
|
||||
|
@ -944,6 +1067,16 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
|
||||
iwl_trans_stop_device(mvm->trans);
|
||||
|
||||
/*
|
||||
* The D3 firmware still hardcodes the AP station ID for the
|
||||
* BSS we're associated with as 0. Store the real STA ID here
|
||||
* and assign 0. When we leave this function, we'll restore
|
||||
* the original value for the resume code.
|
||||
*/
|
||||
old_ap_sta_id = mvm_ap_sta->sta_id;
|
||||
mvm_ap_sta->sta_id = 0;
|
||||
mvmvif->ap_sta_id = 0;
|
||||
|
||||
/*
|
||||
* Set the HW restart bit -- this is mostly true as we're
|
||||
* going to load new firmware and reprogram that, though
|
||||
|
@ -1059,6 +1192,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = iwl_mvm_power_update_device_mode(mvm);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = iwl_mvm_power_update_mode(mvm, vif);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
@ -1109,16 +1246,26 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||
return __iwl_mvm_suspend(hw, wowlan, false);
|
||||
}
|
||||
|
||||
/* converted data from the different status responses */
|
||||
struct iwl_wowlan_status_data {
|
||||
u16 pattern_number;
|
||||
u16 qos_seq_ctr[8];
|
||||
u32 wakeup_reasons;
|
||||
u32 wake_packet_length;
|
||||
u32 wake_packet_bufsize;
|
||||
const u8 *wake_packet;
|
||||
};
|
||||
|
||||
static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_wowlan_status *status)
|
||||
struct iwl_wowlan_status_data *status)
|
||||
{
|
||||
struct sk_buff *pkt = NULL;
|
||||
struct cfg80211_wowlan_wakeup wakeup = {
|
||||
.pattern_idx = -1,
|
||||
};
|
||||
struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
|
||||
u32 reasons = le32_to_cpu(status->wakeup_reasons);
|
||||
u32 reasons = status->wakeup_reasons;
|
||||
|
||||
if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) {
|
||||
wakeup_report = NULL;
|
||||
|
@ -1130,7 +1277,7 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
|
||||
if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)
|
||||
wakeup.pattern_idx =
|
||||
le16_to_cpu(status->pattern_number);
|
||||
status->pattern_number;
|
||||
|
||||
if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
|
||||
IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))
|
||||
|
@ -1158,8 +1305,8 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
wakeup.tcp_match = true;
|
||||
|
||||
if (status->wake_packet_bufsize) {
|
||||
int pktsize = le32_to_cpu(status->wake_packet_bufsize);
|
||||
int pktlen = le32_to_cpu(status->wake_packet_length);
|
||||
int pktsize = status->wake_packet_bufsize;
|
||||
int pktlen = status->wake_packet_length;
|
||||
const u8 *pktdata = status->wake_packet;
|
||||
struct ieee80211_hdr *hdr = (void *)pktdata;
|
||||
int truncated = pktlen - pktsize;
|
||||
|
@ -1239,8 +1386,229 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
kfree_skb(pkt);
|
||||
}
|
||||
|
||||
static void iwl_mvm_aes_sc_to_seq(struct aes_sc *sc,
|
||||
struct ieee80211_key_seq *seq)
|
||||
{
|
||||
u64 pn;
|
||||
|
||||
pn = le64_to_cpu(sc->pn);
|
||||
seq->ccmp.pn[0] = pn >> 40;
|
||||
seq->ccmp.pn[1] = pn >> 32;
|
||||
seq->ccmp.pn[2] = pn >> 24;
|
||||
seq->ccmp.pn[3] = pn >> 16;
|
||||
seq->ccmp.pn[4] = pn >> 8;
|
||||
seq->ccmp.pn[5] = pn;
|
||||
}
|
||||
|
||||
static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc,
|
||||
struct ieee80211_key_seq *seq)
|
||||
{
|
||||
seq->tkip.iv32 = le32_to_cpu(sc->iv32);
|
||||
seq->tkip.iv16 = le16_to_cpu(sc->iv16);
|
||||
}
|
||||
|
||||
static void iwl_mvm_set_aes_rx_seq(struct aes_sc *scs,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
int tid;
|
||||
|
||||
BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS);
|
||||
|
||||
for (tid = 0; tid < IWL_NUM_RSC; tid++) {
|
||||
struct ieee80211_key_seq seq = {};
|
||||
|
||||
iwl_mvm_aes_sc_to_seq(&scs[tid], &seq);
|
||||
ieee80211_set_key_rx_seq(key, tid, &seq);
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
int tid;
|
||||
|
||||
BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS);
|
||||
|
||||
for (tid = 0; tid < IWL_NUM_RSC; tid++) {
|
||||
struct ieee80211_key_seq seq = {};
|
||||
|
||||
iwl_mvm_tkip_sc_to_seq(&scs[tid], &seq);
|
||||
ieee80211_set_key_rx_seq(key, tid, &seq);
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
|
||||
struct iwl_wowlan_status_v6 *status)
|
||||
{
|
||||
union iwl_all_tsc_rsc *rsc = &status->gtk.rsc.all_tsc_rsc;
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
iwl_mvm_set_aes_rx_seq(rsc->aes.multicast_rsc, key);
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
iwl_mvm_set_tkip_rx_seq(rsc->tkip.multicast_rsc, key);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
struct iwl_mvm_d3_gtk_iter_data {
|
||||
struct iwl_wowlan_status_v6 *status;
|
||||
void *last_gtk;
|
||||
u32 cipher;
|
||||
bool find_phase, unhandled_cipher;
|
||||
int num_keys;
|
||||
};
|
||||
|
||||
static void iwl_mvm_d3_update_gtks(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key,
|
||||
void *_data)
|
||||
{
|
||||
struct iwl_mvm_d3_gtk_iter_data *data = _data;
|
||||
|
||||
if (data->unhandled_cipher)
|
||||
return;
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
/* ignore WEP completely, nothing to do */
|
||||
return;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
/* we support these */
|
||||
break;
|
||||
default:
|
||||
/* everything else (even CMAC for MFP) - disconnect from AP */
|
||||
data->unhandled_cipher = true;
|
||||
return;
|
||||
}
|
||||
|
||||
data->num_keys++;
|
||||
|
||||
/*
|
||||
* pairwise key - update sequence counters only;
|
||||
* note that this assumes no TDLS sessions are active
|
||||
*/
|
||||
if (sta) {
|
||||
struct ieee80211_key_seq seq = {};
|
||||
union iwl_all_tsc_rsc *sc = &data->status->gtk.rsc.all_tsc_rsc;
|
||||
|
||||
if (data->find_phase)
|
||||
return;
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
iwl_mvm_aes_sc_to_seq(&sc->aes.tsc, &seq);
|
||||
iwl_mvm_set_aes_rx_seq(sc->aes.unicast_rsc, key);
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
iwl_mvm_tkip_sc_to_seq(&sc->tkip.tsc, &seq);
|
||||
iwl_mvm_set_tkip_rx_seq(sc->tkip.unicast_rsc, key);
|
||||
break;
|
||||
}
|
||||
ieee80211_set_key_tx_seq(key, &seq);
|
||||
|
||||
/* that's it for this key */
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->find_phase) {
|
||||
data->last_gtk = key;
|
||||
data->cipher = key->cipher;
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->status->num_of_gtk_rekeys)
|
||||
ieee80211_remove_key(key);
|
||||
else if (data->last_gtk == key)
|
||||
iwl_mvm_set_key_rx_seq(key, data->status);
|
||||
}
|
||||
|
||||
static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_wowlan_status_v6 *status)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm_d3_gtk_iter_data gtkdata = {
|
||||
.status = status,
|
||||
};
|
||||
|
||||
if (!status || !vif->bss_conf.bssid)
|
||||
return false;
|
||||
|
||||
/* find last GTK that we used initially, if any */
|
||||
gtkdata.find_phase = true;
|
||||
ieee80211_iter_keys(mvm->hw, vif,
|
||||
iwl_mvm_d3_update_gtks, >kdata);
|
||||
/* not trying to keep connections with MFP/unhandled ciphers */
|
||||
if (gtkdata.unhandled_cipher)
|
||||
return false;
|
||||
if (!gtkdata.num_keys)
|
||||
return true;
|
||||
if (!gtkdata.last_gtk)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* invalidate all other GTKs that might still exist and update
|
||||
* the one that we used
|
||||
*/
|
||||
gtkdata.find_phase = false;
|
||||
ieee80211_iter_keys(mvm->hw, vif,
|
||||
iwl_mvm_d3_update_gtks, >kdata);
|
||||
|
||||
if (status->num_of_gtk_rekeys) {
|
||||
struct ieee80211_key_conf *key;
|
||||
struct {
|
||||
struct ieee80211_key_conf conf;
|
||||
u8 key[32];
|
||||
} conf = {
|
||||
.conf.cipher = gtkdata.cipher,
|
||||
.conf.keyidx = status->gtk.key_index,
|
||||
};
|
||||
|
||||
switch (gtkdata.cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_CCMP;
|
||||
memcpy(conf.conf.key, status->gtk.decrypt_key,
|
||||
WLAN_KEY_LEN_CCMP);
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_TKIP;
|
||||
memcpy(conf.conf.key, status->gtk.decrypt_key, 16);
|
||||
/* leave TX MIC key zeroed, we don't use it anyway */
|
||||
memcpy(conf.conf.key +
|
||||
NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
|
||||
status->gtk.tkip_mic_key, 8);
|
||||
break;
|
||||
}
|
||||
|
||||
key = ieee80211_gtk_rekey_add(vif, &conf.conf);
|
||||
if (IS_ERR(key))
|
||||
return false;
|
||||
iwl_mvm_set_key_rx_seq(key, status);
|
||||
}
|
||||
|
||||
if (status->num_of_gtk_rekeys) {
|
||||
__be64 replay_ctr =
|
||||
cpu_to_be64(le64_to_cpu(status->replay_ctr));
|
||||
ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,
|
||||
(void *)&replay_ctr, GFP_KERNEL);
|
||||
}
|
||||
|
||||
mvmvif->seqno_valid = true;
|
||||
/* +0x10 because the set API expects next-to-use, not last-used */
|
||||
mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* releases the MVM mutex */
|
||||
static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
||||
static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
u32 base = mvm->error_event_table;
|
||||
|
@ -1253,8 +1621,12 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
.id = WOWLAN_GET_STATUSES,
|
||||
.flags = CMD_SYNC | CMD_WANT_SKB,
|
||||
};
|
||||
struct iwl_wowlan_status *status;
|
||||
int ret, len;
|
||||
struct iwl_wowlan_status_data status;
|
||||
struct iwl_wowlan_status_v6 *status_v6;
|
||||
int ret, len, status_size, i;
|
||||
bool keep;
|
||||
struct ieee80211_sta *ap_sta;
|
||||
struct iwl_mvm_sta *mvm_ap_sta;
|
||||
|
||||
iwl_trans_read_mem_bytes(mvm->trans, base,
|
||||
&err_info, sizeof(err_info));
|
||||
|
@ -1287,32 +1659,83 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
if (!cmd.resp_pkt)
|
||||
goto out_unlock;
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API)
|
||||
status_size = sizeof(struct iwl_wowlan_status_v6);
|
||||
else
|
||||
status_size = sizeof(struct iwl_wowlan_status_v4);
|
||||
|
||||
len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
|
||||
if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) {
|
||||
if (len - sizeof(struct iwl_cmd_header) < status_size) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
|
||||
goto out_free_resp;
|
||||
}
|
||||
|
||||
status = (void *)cmd.resp_pkt->data;
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_D3_CONTINUITY_API) {
|
||||
status_v6 = (void *)cmd.resp_pkt->data;
|
||||
|
||||
status.pattern_number = le16_to_cpu(status_v6->pattern_number);
|
||||
for (i = 0; i < 8; i++)
|
||||
status.qos_seq_ctr[i] =
|
||||
le16_to_cpu(status_v6->qos_seq_ctr[i]);
|
||||
status.wakeup_reasons = le32_to_cpu(status_v6->wakeup_reasons);
|
||||
status.wake_packet_length =
|
||||
le32_to_cpu(status_v6->wake_packet_length);
|
||||
status.wake_packet_bufsize =
|
||||
le32_to_cpu(status_v6->wake_packet_bufsize);
|
||||
status.wake_packet = status_v6->wake_packet;
|
||||
} else {
|
||||
struct iwl_wowlan_status_v4 *status_v4;
|
||||
status_v6 = NULL;
|
||||
status_v4 = (void *)cmd.resp_pkt->data;
|
||||
|
||||
status.pattern_number = le16_to_cpu(status_v4->pattern_number);
|
||||
for (i = 0; i < 8; i++)
|
||||
status.qos_seq_ctr[i] =
|
||||
le16_to_cpu(status_v4->qos_seq_ctr[i]);
|
||||
status.wakeup_reasons = le32_to_cpu(status_v4->wakeup_reasons);
|
||||
status.wake_packet_length =
|
||||
le32_to_cpu(status_v4->wake_packet_length);
|
||||
status.wake_packet_bufsize =
|
||||
le32_to_cpu(status_v4->wake_packet_bufsize);
|
||||
status.wake_packet = status_v4->wake_packet;
|
||||
}
|
||||
|
||||
if (len - sizeof(struct iwl_cmd_header) !=
|
||||
sizeof(*status) +
|
||||
ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {
|
||||
status_size + ALIGN(status.wake_packet_bufsize, 4)) {
|
||||
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
|
||||
goto out_free_resp;
|
||||
}
|
||||
|
||||
/* still at hard-coded place 0 for D3 image */
|
||||
ap_sta = rcu_dereference_protected(
|
||||
mvm->fw_id_to_mac_id[0],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (IS_ERR_OR_NULL(ap_sta))
|
||||
goto out_free_resp;
|
||||
|
||||
mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
|
||||
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
|
||||
u16 seq = status.qos_seq_ctr[i];
|
||||
/* firmware stores last-used value, we store next value */
|
||||
seq += 0x10;
|
||||
mvm_ap_sta->tid_data[i].seq_number = seq;
|
||||
}
|
||||
|
||||
/* now we have all the data we need, unlock to avoid mac80211 issues */
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
iwl_mvm_report_wakeup_reasons(mvm, vif, status);
|
||||
iwl_mvm_report_wakeup_reasons(mvm, vif, &status);
|
||||
|
||||
keep = iwl_mvm_setup_connection_keep(mvm, vif, status_v6);
|
||||
|
||||
iwl_free_resp(&cmd);
|
||||
return;
|
||||
return keep;
|
||||
|
||||
out_free_resp:
|
||||
iwl_free_resp(&cmd);
|
||||
out_unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
|
||||
|
@ -1335,6 +1758,17 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
/* skip the one we keep connection on */
|
||||
if (data == vif)
|
||||
return;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_resume_disconnect(vif);
|
||||
}
|
||||
|
||||
static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
||||
{
|
||||
struct iwl_d3_iter_data resume_iter_data = {
|
||||
|
@ -1343,6 +1777,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
|||
struct ieee80211_vif *vif = NULL;
|
||||
int ret;
|
||||
enum iwl_d3_status d3_status;
|
||||
bool keep = false;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
|
@ -1368,7 +1803,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
|||
/* query SRAM first in case we want event logging */
|
||||
iwl_mvm_read_d3_sram(mvm);
|
||||
|
||||
iwl_mvm_query_wakeup_reasons(mvm, vif);
|
||||
keep = iwl_mvm_query_wakeup_reasons(mvm, vif);
|
||||
/* has unlocked the mutex, so skip that */
|
||||
goto out;
|
||||
|
||||
|
@ -1376,8 +1811,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
|||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
out:
|
||||
if (!test && vif)
|
||||
ieee80211_resume_disconnect(vif);
|
||||
if (!test)
|
||||
ieee80211_iterate_active_interfaces_rtnl(mvm->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_d3_disconnect_iter, keep ? vif : NULL);
|
||||
|
||||
/* return 1 to reconfigure the device */
|
||||
set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
|
||||
|
|
|
@ -246,58 +246,56 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
|
|||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_power_down_allow_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
static ssize_t iwl_dbgfs_disable_power_off_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
char buf[8] = {};
|
||||
int allow;
|
||||
char buf[64];
|
||||
int bufsz = sizeof(buf);
|
||||
int pos = 0;
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d0=%d\n",
|
||||
mvm->disable_power_off);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off_d3=%d\n",
|
||||
mvm->disable_power_off_d3);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_disable_power_off_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
char buf[64] = {};
|
||||
int ret;
|
||||
int val;
|
||||
|
||||
if (!mvm->ucode_loaded)
|
||||
return -EIO;
|
||||
|
||||
if (copy_from_user(buf, user_buf, sizeof(buf)))
|
||||
count = min_t(size_t, count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
if (sscanf(buf, "%d", &allow) != 1)
|
||||
if (!strncmp("disable_power_off_d0=", buf, 21)) {
|
||||
if (sscanf(buf + 21, "%d", &val) != 1)
|
||||
return -EINVAL;
|
||||
mvm->disable_power_off = val;
|
||||
} else if (!strncmp("disable_power_off_d3=", buf, 21)) {
|
||||
if (sscanf(buf + 21, "%d", &val) != 1)
|
||||
return -EINVAL;
|
||||
mvm->disable_power_off_d3 = val;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
IWL_DEBUG_POWER(mvm, "%s device power down\n",
|
||||
allow ? "allow" : "prevent");
|
||||
mutex_lock(&mvm->mutex);
|
||||
ret = iwl_mvm_power_update_device_mode(mvm);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
/*
|
||||
* TODO: Send REPLY_DEBUG_CMD (0xf0) when FW support it
|
||||
*/
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
char buf[8] = {};
|
||||
int allow;
|
||||
|
||||
if (copy_from_user(buf, user_buf, sizeof(buf)))
|
||||
return -EFAULT;
|
||||
|
||||
if (sscanf(buf, "%d", &allow) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
IWL_DEBUG_POWER(mvm, "%s device power down in d3\n",
|
||||
allow ? "allow" : "prevent");
|
||||
|
||||
/*
|
||||
* TODO: When WoWLAN FW alive notification happens, driver will send
|
||||
* REPLY_DEBUG_CMD setting power_down_allow flag according to
|
||||
* mvm->prevent_power_down_d3
|
||||
*/
|
||||
mvm->prevent_power_down_d3 = !allow;
|
||||
|
||||
return count;
|
||||
return ret ?: count;
|
||||
}
|
||||
|
||||
static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
|
||||
|
@ -371,7 +369,8 @@ static ssize_t iwl_dbgfs_pm_params_write(struct file *file,
|
|||
int val;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(buf, user_buf, sizeof(buf)))
|
||||
count = min_t(size_t, count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
if (!strncmp("keep_alive=", buf, 11)) {
|
||||
|
@ -394,7 +393,9 @@ static ssize_t iwl_dbgfs_pm_params_write(struct file *file,
|
|||
if (sscanf(buf + 16, "%d", &val) != 1)
|
||||
return -EINVAL;
|
||||
param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT;
|
||||
} else if (!strncmp("disable_power_off=", buf, 18)) {
|
||||
} else if (!strncmp("disable_power_off=", buf, 18) &&
|
||||
!(mvm->fw->ucode_capa.flags &
|
||||
IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) {
|
||||
if (sscanf(buf + 18, "%d", &val) != 1)
|
||||
return -EINVAL;
|
||||
param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF;
|
||||
|
@ -581,15 +582,21 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
|
|||
BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n",
|
||||
notif->bt_status);
|
||||
notif->bt_status);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n",
|
||||
notif->bt_open_conn);
|
||||
notif->bt_open_conn);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n",
|
||||
notif->bt_traffic_load);
|
||||
notif->bt_traffic_load);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n",
|
||||
notif->bt_agg_traffic_load);
|
||||
notif->bt_agg_traffic_load);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n",
|
||||
notif->bt_ci_compliance);
|
||||
notif->bt_ci_compliance);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "primary_ch_lut = %d\n",
|
||||
le32_to_cpu(notif->primary_ch_lut));
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "secondary_ch_lut = %d\n",
|
||||
le32_to_cpu(notif->secondary_ch_lut));
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "bt_activity_grading = %d\n",
|
||||
le32_to_cpu(notif->bt_activity_grading));
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
|
@ -600,6 +607,38 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
|
|||
}
|
||||
#undef BT_MBOX_PRINT
|
||||
|
||||
static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
|
||||
char buf[256];
|
||||
int bufsz = sizeof(buf);
|
||||
int pos = 0;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "Channel inhibition CMD\n");
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tPrimary Channel Bitmap 0x%016llx Fat: %d\n",
|
||||
le64_to_cpu(cmd->bt_primary_ci),
|
||||
!!cmd->co_run_bw_primary);
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tSecondary Channel Bitmap 0x%016llx Fat: %d\n",
|
||||
le64_to_cpu(cmd->bt_secondary_ci),
|
||||
!!cmd->co_run_bw_secondary);
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n");
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n",
|
||||
iwl_bt_ack_kill_msk[mvm->bt_kill_msk]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n",
|
||||
iwl_bt_cts_kill_msk[mvm->bt_kill_msk]);
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
#define PRINT_STATS_LE32(_str, _val) \
|
||||
pos += scnprintf(buf + pos, bufsz - pos, \
|
||||
fmt_table, _str, \
|
||||
|
@ -615,9 +654,11 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
|
|||
int pos = 0;
|
||||
char *buf;
|
||||
int ret;
|
||||
int bufsz = sizeof(struct mvm_statistics_rx_phy) * 20 +
|
||||
sizeof(struct mvm_statistics_rx_non_phy) * 10 +
|
||||
sizeof(struct mvm_statistics_rx_ht_phy) * 10 + 200;
|
||||
/* 43 is the size of each data line, 33 is the size of each header */
|
||||
size_t bufsz =
|
||||
((sizeof(struct mvm_statistics_rx) / sizeof(__le32)) * 43) +
|
||||
(4 * 33) + 1;
|
||||
|
||||
struct mvm_statistics_rx_phy *ofdm;
|
||||
struct mvm_statistics_rx_phy *cck;
|
||||
struct mvm_statistics_rx_non_phy *general;
|
||||
|
@ -712,6 +753,7 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
|
|||
PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b);
|
||||
PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c);
|
||||
PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills);
|
||||
PRINT_STATS_LE32("mac_id", general->mac_id);
|
||||
PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
|
||||
|
@ -757,6 +799,59 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
iwl_dbgfs_scan_ant_rxchain_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
int pos = 0;
|
||||
char buf[32];
|
||||
const size_t bufsz = sizeof(buf);
|
||||
|
||||
/* print which antennas were set for the scan command by the user */
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "Antennas for scan: ");
|
||||
if (mvm->scan_rx_ant & ANT_A)
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "A");
|
||||
if (mvm->scan_rx_ant & ANT_B)
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "B");
|
||||
if (mvm->scan_rx_ant & ANT_C)
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "C");
|
||||
pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
iwl_dbgfs_scan_ant_rxchain_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
char buf[8];
|
||||
int buf_size;
|
||||
u8 scan_rx_ant;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf_size = min(count, sizeof(buf) - 1);
|
||||
|
||||
/* get the argument from the user and check if it is valid */
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
if (sscanf(buf, "%hhx", &scan_rx_ant) != 1)
|
||||
return -EINVAL;
|
||||
if (scan_rx_ant > ANT_ABC)
|
||||
return -EINVAL;
|
||||
if (scan_rx_ant & ~iwl_fw_valid_rx_ant(mvm->fw))
|
||||
return -EINVAL;
|
||||
|
||||
/* change the rx antennas for scan command */
|
||||
mvm->scan_rx_ant = scan_rx_ant;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif,
|
||||
enum iwl_dbgfs_bf_mask param, int value)
|
||||
{
|
||||
|
@ -968,7 +1063,8 @@ static ssize_t iwl_dbgfs_d3_sram_write(struct file *file,
|
|||
char buf[8] = {};
|
||||
int store;
|
||||
|
||||
if (copy_from_user(buf, user_buf, sizeof(buf)))
|
||||
count = min_t(size_t, count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
if (sscanf(buf, "%d", &store) != 1)
|
||||
|
@ -1063,10 +1159,12 @@ MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
|
|||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(stations);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off);
|
||||
MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats);
|
||||
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram);
|
||||
#endif
|
||||
|
@ -1087,10 +1185,14 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
|||
MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)
|
||||
MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
|
||||
S_IRUSR | S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir,
|
||||
S_IWUSR | S_IRUSR);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
|
||||
MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
|
||||
|
|
|
@ -82,6 +82,8 @@
|
|||
* @BT_USE_DEFAULTS:
|
||||
* @BT_SYNC_2_BT_DISABLE:
|
||||
* @BT_COEX_CORUNNING_TBL_EN:
|
||||
*
|
||||
* The COEX_MODE must be set for each command. Even if it is not changed.
|
||||
*/
|
||||
enum iwl_bt_coex_flags {
|
||||
BT_CH_PRIMARY_EN = BIT(0),
|
||||
|
@ -95,14 +97,16 @@ enum iwl_bt_coex_flags {
|
|||
BT_COEX_NW = 0x3 << BT_COEX_MODE_POS,
|
||||
BT_USE_DEFAULTS = BIT(6),
|
||||
BT_SYNC_2_BT_DISABLE = BIT(7),
|
||||
/*
|
||||
* For future use - when the flags will be enlarged
|
||||
* BT_COEX_CORUNNING_TBL_EN = BIT(8),
|
||||
*/
|
||||
BT_COEX_CORUNNING_TBL_EN = BIT(8),
|
||||
BT_COEX_MPLUT_TBL_EN = BIT(9),
|
||||
/* Bit 10 is reserved */
|
||||
BT_COEX_WF_PRIO_BOOST_CHECK_EN = BIT(11),
|
||||
};
|
||||
|
||||
/*
|
||||
* indicates what has changed in the BT_COEX command.
|
||||
* BT_VALID_ENABLE must be set for each command. Commands without this bit will
|
||||
* discarded by the firmware
|
||||
*/
|
||||
enum iwl_bt_coex_valid_bit_msk {
|
||||
BT_VALID_ENABLE = BIT(0),
|
||||
|
@ -121,11 +125,8 @@ enum iwl_bt_coex_valid_bit_msk {
|
|||
BT_VALID_CORUN_LUT_40 = BIT(13),
|
||||
BT_VALID_ANT_ISOLATION = BIT(14),
|
||||
BT_VALID_ANT_ISOLATION_THRS = BIT(15),
|
||||
/*
|
||||
* For future use - when the valid flags will be enlarged
|
||||
* BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16),
|
||||
* BT_VALID_TXRX_MAX_FREQ_0 = BIT(17),
|
||||
*/
|
||||
BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16),
|
||||
BT_VALID_TXRX_MAX_FREQ_0 = BIT(17),
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -142,48 +143,88 @@ enum iwl_bt_reduced_tx_power {
|
|||
BT_REDUCED_TX_POWER_DATA = BIT(1),
|
||||
};
|
||||
|
||||
enum iwl_bt_coex_lut_type {
|
||||
BT_COEX_TIGHT_LUT = 0,
|
||||
BT_COEX_LOOSE_LUT,
|
||||
BT_COEX_TX_DIS_LUT,
|
||||
|
||||
BT_COEX_MAX_LUT,
|
||||
};
|
||||
|
||||
#define BT_COEX_LUT_SIZE (12)
|
||||
#define BT_COEX_CORUN_LUT_SIZE (32)
|
||||
#define BT_COEX_MULTI_PRIO_LUT_SIZE (2)
|
||||
#define BT_COEX_BOOST_SIZE (4)
|
||||
#define BT_REDUCED_TX_POWER_BIT BIT(7)
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_cmd - bt coex configuration command
|
||||
* @flags:&enum iwl_bt_coex_flags
|
||||
* @lead_time:
|
||||
* @max_kill:
|
||||
* @bt3_time_t7_value:
|
||||
* @kill_ack_msk:
|
||||
* @kill_cts_msk:
|
||||
* @bt3_prio_sample_time:
|
||||
* @bt3_timer_t2_value:
|
||||
* @bt4_reaction_time:
|
||||
* @decision_lut[12]:
|
||||
* @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power
|
||||
* @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk
|
||||
* @bt_prio_boost: values for PTA boost register
|
||||
* @bt4_antenna_isolation:
|
||||
* @bt4_antenna_isolation_thr:
|
||||
* @bt4_tx_tx_delta_freq_thr:
|
||||
* @bt4_tx_rx_max_freq0:
|
||||
* @bt_prio_boost:
|
||||
* @wifi_tx_prio_boost: SW boost of wifi tx priority
|
||||
* @wifi_rx_prio_boost: SW boost of wifi rx priority
|
||||
* @kill_ack_msk:
|
||||
* @kill_cts_msk:
|
||||
* @decision_lut:
|
||||
* @bt4_multiprio_lut:
|
||||
* @bt4_corun_lut20:
|
||||
* @bt4_corun_lut40:
|
||||
* @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk
|
||||
*
|
||||
* The structure is used for the BT_COEX command.
|
||||
*/
|
||||
struct iwl_bt_coex_cmd {
|
||||
u8 flags;
|
||||
u8 lead_time;
|
||||
__le32 flags;
|
||||
u8 max_kill;
|
||||
u8 bt3_time_t7_value;
|
||||
u8 bt_reduced_tx_power;
|
||||
u8 reserved[2];
|
||||
|
||||
u8 bt4_antenna_isolation;
|
||||
u8 bt4_antenna_isolation_thr;
|
||||
u8 bt4_tx_tx_delta_freq_thr;
|
||||
u8 bt4_tx_rx_max_freq0;
|
||||
|
||||
__le32 bt_prio_boost[BT_COEX_BOOST_SIZE];
|
||||
__le32 wifi_tx_prio_boost;
|
||||
__le32 wifi_rx_prio_boost;
|
||||
__le32 kill_ack_msk;
|
||||
__le32 kill_cts_msk;
|
||||
u8 bt3_prio_sample_time;
|
||||
u8 bt3_timer_t2_value;
|
||||
__le16 bt4_reaction_time;
|
||||
__le32 decision_lut[BT_COEX_LUT_SIZE];
|
||||
u8 bt_reduced_tx_power;
|
||||
u8 reserved;
|
||||
__le16 valid_bit_msk;
|
||||
__le32 bt_prio_boost;
|
||||
u8 reserved2;
|
||||
u8 wifi_tx_prio_boost;
|
||||
__le16 wifi_rx_prio_boost;
|
||||
|
||||
__le32 decision_lut[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE];
|
||||
__le32 bt4_multiprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE];
|
||||
__le32 bt4_corun_lut20[BT_COEX_CORUN_LUT_SIZE];
|
||||
__le32 bt4_corun_lut40[BT_COEX_CORUN_LUT_SIZE];
|
||||
|
||||
__le32 valid_bit_msk;
|
||||
} __packed; /* BT_COEX_CMD_API_S_VER_3 */
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_ci_cmd - bt coex channel inhibition command
|
||||
* @bt_primary_ci:
|
||||
* @bt_secondary_ci:
|
||||
* @co_run_bw_primary:
|
||||
* @co_run_bw_secondary:
|
||||
* @primary_ch_phy_id:
|
||||
* @secondary_ch_phy_id:
|
||||
*
|
||||
* Used for BT_COEX_CI command
|
||||
*/
|
||||
struct iwl_bt_coex_ci_cmd {
|
||||
__le64 bt_primary_ci;
|
||||
__le64 bt_secondary_ci;
|
||||
|
||||
u8 co_run_bw_primary;
|
||||
u8 co_run_bw_secondary;
|
||||
u8 primary_ch_phy_id;
|
||||
u8 secondary_ch_phy_id;
|
||||
} __packed; /* BT_CI_MSG_API_S_VER_1 */
|
||||
|
||||
#define BT_MBOX(n_dw, _msg, _pos, _nbits) \
|
||||
BT_MBOX##n_dw##_##_msg##_POS = (_pos), \
|
||||
BT_MBOX##n_dw##_##_msg = BITS(_nbits) << BT_MBOX##n_dw##_##_msg##_POS
|
||||
|
@ -244,23 +285,39 @@ enum iwl_bt_mxbox_dw3 {
|
|||
((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
|
||||
>> BT_MBOX##_num##_##_field##_POS)
|
||||
|
||||
enum iwl_bt_activity_grading {
|
||||
BT_OFF = 0,
|
||||
BT_ON_NO_CONNECTION = 1,
|
||||
BT_LOW_TRAFFIC = 2,
|
||||
BT_HIGH_TRAFFIC = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_profile_notif - notification about BT coex
|
||||
* @mbox_msg: message from BT to WiFi
|
||||
* @:bt_status: 0 - off, 1 - on
|
||||
* @:bt_open_conn: number of BT connections open
|
||||
* @:bt_traffic_load: load of BT traffic
|
||||
* @:bt_agg_traffic_load: aggregated load of BT traffic
|
||||
* @:bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant
|
||||
* @msg_idx: the index of the message
|
||||
* @bt_status: 0 - off, 1 - on
|
||||
* @bt_open_conn: number of BT connections open
|
||||
* @bt_traffic_load: load of BT traffic
|
||||
* @bt_agg_traffic_load: aggregated load of BT traffic
|
||||
* @bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant
|
||||
* @primary_ch_lut: LUT used for primary channel
|
||||
* @secondary_ch_lut: LUT used for secondary channel
|
||||
* @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading
|
||||
*/
|
||||
struct iwl_bt_coex_profile_notif {
|
||||
__le32 mbox_msg[4];
|
||||
__le32 msg_idx;
|
||||
u8 bt_status;
|
||||
u8 bt_open_conn;
|
||||
u8 bt_traffic_load;
|
||||
u8 bt_agg_traffic_load;
|
||||
u8 bt_ci_compliance;
|
||||
u8 reserved[3];
|
||||
|
||||
__le32 primary_ch_lut;
|
||||
__le32 secondary_ch_lut;
|
||||
__le32 bt_activity_grading;
|
||||
} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_2 */
|
||||
|
||||
enum iwl_bt_coex_prio_table_event {
|
||||
|
@ -300,20 +357,4 @@ struct iwl_bt_coex_prio_tbl_cmd {
|
|||
u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
|
||||
} __packed;
|
||||
|
||||
enum iwl_bt_coex_env_action {
|
||||
BT_COEX_ENV_CLOSE = 0,
|
||||
BT_COEX_ENV_OPEN = 1,
|
||||
}; /* BT_COEX_PROT_ENV_ACTION_API_E_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_prot_env_cmd - BT Protection Envelope
|
||||
* @action: enum %iwl_bt_coex_env_action
|
||||
* @type: enum %iwl_bt_coex_prio_table_event
|
||||
*/
|
||||
struct iwl_bt_coex_prot_env_cmd {
|
||||
u8 action; /* 0 = closed, 1 = open */
|
||||
u8 type; /* 0 .. 15 */
|
||||
u8 reserved[2];
|
||||
} __packed;
|
||||
|
||||
#endif /* __fw_api_bt_coex_h__ */
|
||||
|
|
|
@ -100,7 +100,12 @@ enum iwl_proto_offloads {
|
|||
|
||||
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2
|
||||
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2 6
|
||||
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 6
|
||||
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L 12
|
||||
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S 4
|
||||
#define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX 12
|
||||
|
||||
#define IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L 4
|
||||
#define IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S 2
|
||||
|
||||
/**
|
||||
* struct iwl_proto_offload_cmd_common - ARP/NS offload common part
|
||||
|
@ -155,6 +160,43 @@ struct iwl_proto_offload_cmd_v2 {
|
|||
u8 reserved2[3];
|
||||
} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_2 */
|
||||
|
||||
struct iwl_ns_config {
|
||||
struct in6_addr source_ipv6_addr;
|
||||
struct in6_addr dest_ipv6_addr;
|
||||
u8 target_mac_addr[ETH_ALEN];
|
||||
__le16 reserved;
|
||||
} __packed; /* NS_OFFLOAD_CONFIG */
|
||||
|
||||
struct iwl_targ_addr {
|
||||
struct in6_addr addr;
|
||||
__le32 config_num;
|
||||
} __packed; /* TARGET_IPV6_ADDRESS */
|
||||
|
||||
/**
|
||||
* struct iwl_proto_offload_cmd_v3_small - ARP/NS offload configuration
|
||||
* @common: common/IPv4 configuration
|
||||
* @target_ipv6_addr: target IPv6 addresses
|
||||
* @ns_config: NS offload configurations
|
||||
*/
|
||||
struct iwl_proto_offload_cmd_v3_small {
|
||||
struct iwl_proto_offload_cmd_common common;
|
||||
__le32 num_valid_ipv6_addrs;
|
||||
struct iwl_targ_addr targ_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S];
|
||||
struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3S];
|
||||
} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */
|
||||
|
||||
/**
|
||||
* struct iwl_proto_offload_cmd_v3_large - ARP/NS offload configuration
|
||||
* @common: common/IPv4 configuration
|
||||
* @target_ipv6_addr: target IPv6 addresses
|
||||
* @ns_config: NS offload configurations
|
||||
*/
|
||||
struct iwl_proto_offload_cmd_v3_large {
|
||||
struct iwl_proto_offload_cmd_common common;
|
||||
__le32 num_valid_ipv6_addrs;
|
||||
struct iwl_targ_addr targ_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L];
|
||||
struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L];
|
||||
} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */
|
||||
|
||||
/*
|
||||
* WOWLAN_PATTERNS
|
||||
|
@ -293,7 +335,7 @@ enum iwl_wowlan_wakeup_reason {
|
|||
IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12),
|
||||
}; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */
|
||||
|
||||
struct iwl_wowlan_status {
|
||||
struct iwl_wowlan_status_v4 {
|
||||
__le64 replay_ctr;
|
||||
__le16 pattern_number;
|
||||
__le16 non_qos_seq_ctr;
|
||||
|
@ -308,6 +350,29 @@ struct iwl_wowlan_status {
|
|||
u8 wake_packet[]; /* can be truncated from _length to _bufsize */
|
||||
} __packed; /* WOWLAN_STATUSES_API_S_VER_4 */
|
||||
|
||||
struct iwl_wowlan_gtk_status {
|
||||
u8 key_index;
|
||||
u8 reserved[3];
|
||||
u8 decrypt_key[16];
|
||||
u8 tkip_mic_key[8];
|
||||
struct iwl_wowlan_rsc_tsc_params_cmd rsc;
|
||||
} __packed;
|
||||
|
||||
struct iwl_wowlan_status_v6 {
|
||||
struct iwl_wowlan_gtk_status gtk;
|
||||
__le64 replay_ctr;
|
||||
__le16 pattern_number;
|
||||
__le16 non_qos_seq_ctr;
|
||||
__le16 qos_seq_ctr[8];
|
||||
__le32 wakeup_reasons;
|
||||
__le32 num_of_gtk_rekeys;
|
||||
__le32 transmitted_ndps;
|
||||
__le32 received_beacons;
|
||||
__le32 wake_packet_length;
|
||||
__le32 wake_packet_bufsize;
|
||||
u8 wake_packet[]; /* can be truncated from _length to _bufsize */
|
||||
} __packed; /* WOWLAN_STATUSES_API_S_VER_6 */
|
||||
|
||||
#define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64
|
||||
#define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128
|
||||
#define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048
|
||||
|
|
|
@ -170,12 +170,14 @@ struct iwl_mac_data_ap {
|
|||
* @beacon_tsf: beacon transmit time in TSF
|
||||
* @bi: beacon interval in TU
|
||||
* @bi_reciprocal: 2^32 / bi
|
||||
* @beacon_template: beacon template ID
|
||||
*/
|
||||
struct iwl_mac_data_ibss {
|
||||
__le32 beacon_time;
|
||||
__le64 beacon_tsf;
|
||||
__le32 bi;
|
||||
__le32 bi_reciprocal;
|
||||
__le32 beacon_template;
|
||||
} __packed; /* IBSS_MAC_DATA_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
|
@ -372,4 +374,13 @@ static inline u32 iwl_mvm_reciprocal(u32 v)
|
|||
return 0xFFFFFFFF / v;
|
||||
}
|
||||
|
||||
#define IWL_NONQOS_SEQ_GET 0x1
|
||||
#define IWL_NONQOS_SEQ_SET 0x2
|
||||
struct iwl_nonqos_seq_query_cmd {
|
||||
__le32 get_set_flag;
|
||||
__le32 mac_id_n_color;
|
||||
__le16 value;
|
||||
__le16 reserved;
|
||||
} __packed; /* NON_QOS_TX_COUNTER_GET_SET_API_S_VER_1 */
|
||||
|
||||
#endif /* __fw_api_mac_h__ */
|
||||
|
|
|
@ -131,6 +131,33 @@ struct iwl_powertable_cmd {
|
|||
__le32 lprx_rssi_threshold;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* enum iwl_device_power_flags - masks for device power command flags
|
||||
* @DEVIC_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off
|
||||
* receiver and transmitter. '0' - does not allow. This flag should be
|
||||
* always set to '1' unless one need to disable actual power down for debug
|
||||
* purposes.
|
||||
* @DEVICE_POWER_FLAGS_CAM_MSK: '1' CAM (Continuous Active Mode) is set, meaning
|
||||
* that power management is disabled. '0' Power management is enabled, one
|
||||
* of power schemes is applied.
|
||||
*/
|
||||
enum iwl_device_power_flags {
|
||||
DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0),
|
||||
DEVICE_POWER_FLAGS_CAM_MSK = BIT(13),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_device_power_cmd - device wide power command.
|
||||
* DEVICE_POWER_CMD = 0x77 (command, has simple generic response)
|
||||
*
|
||||
* @flags: Power table command flags from DEVICE_POWER_FLAGS_*
|
||||
*/
|
||||
struct iwl_device_power_cmd {
|
||||
/* PM_POWER_TABLE_CMD_API_S_VER_6 */
|
||||
__le16 flags;
|
||||
__le16 reserved;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iwl_mac_power_cmd - New power command containing uAPSD support
|
||||
* MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response)
|
||||
|
@ -290,7 +317,7 @@ struct iwl_beacon_filter_cmd {
|
|||
#define IWL_BF_ESCAPE_TIMER_MIN 0
|
||||
|
||||
#define IWL_BA_ESCAPE_TIMER_DEFAULT 6
|
||||
#define IWL_BA_ESCAPE_TIMER_D3 6
|
||||
#define IWL_BA_ESCAPE_TIMER_D3 9
|
||||
#define IWL_BA_ESCAPE_TIMER_MAX 1024
|
||||
#define IWL_BA_ESCAPE_TIMER_MIN 0
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
/*
|
||||
* These serve as indexes into
|
||||
* struct iwl_rate_info fw_rate_idx_to_plcp[IWL_RATE_COUNT];
|
||||
* TODO: avoid overlap between legacy and HT rates
|
||||
*/
|
||||
enum {
|
||||
IWL_RATE_1M_INDEX = 0,
|
||||
|
@ -78,18 +79,31 @@ enum {
|
|||
IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
|
||||
IWL_RATE_6M_INDEX,
|
||||
IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
|
||||
IWL_RATE_MCS_0_INDEX = IWL_RATE_6M_INDEX,
|
||||
IWL_FIRST_HT_RATE = IWL_RATE_MCS_0_INDEX,
|
||||
IWL_FIRST_VHT_RATE = IWL_RATE_MCS_0_INDEX,
|
||||
IWL_RATE_9M_INDEX,
|
||||
IWL_RATE_12M_INDEX,
|
||||
IWL_RATE_MCS_1_INDEX = IWL_RATE_12M_INDEX,
|
||||
IWL_RATE_18M_INDEX,
|
||||
IWL_RATE_MCS_2_INDEX = IWL_RATE_18M_INDEX,
|
||||
IWL_RATE_24M_INDEX,
|
||||
IWL_RATE_MCS_3_INDEX = IWL_RATE_24M_INDEX,
|
||||
IWL_RATE_36M_INDEX,
|
||||
IWL_RATE_MCS_4_INDEX = IWL_RATE_36M_INDEX,
|
||||
IWL_RATE_48M_INDEX,
|
||||
IWL_RATE_MCS_5_INDEX = IWL_RATE_48M_INDEX,
|
||||
IWL_RATE_54M_INDEX,
|
||||
IWL_RATE_MCS_6_INDEX = IWL_RATE_54M_INDEX,
|
||||
IWL_LAST_NON_HT_RATE = IWL_RATE_54M_INDEX,
|
||||
IWL_RATE_60M_INDEX,
|
||||
IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
|
||||
IWL_RATE_MCS_7_INDEX = IWL_RATE_60M_INDEX,
|
||||
IWL_LAST_HT_RATE = IWL_RATE_MCS_7_INDEX,
|
||||
IWL_RATE_MCS_8_INDEX,
|
||||
IWL_RATE_MCS_9_INDEX,
|
||||
IWL_LAST_VHT_RATE = IWL_RATE_MCS_9_INDEX,
|
||||
IWL_RATE_COUNT_LEGACY = IWL_LAST_NON_HT_RATE + 1,
|
||||
IWL_RATE_COUNT,
|
||||
IWL_RATE_COUNT = IWL_LAST_VHT_RATE + 1,
|
||||
};
|
||||
|
||||
#define IWL_RATE_BIT_MSK(r) BIT(IWL_RATE_##r##M_INDEX)
|
||||
|
@ -108,6 +122,7 @@ enum {
|
|||
IWL_RATE_2M_PLCP = 20,
|
||||
IWL_RATE_5M_PLCP = 55,
|
||||
IWL_RATE_11M_PLCP = 110,
|
||||
IWL_RATE_INVM_PLCP = -1,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -164,6 +179,8 @@ enum {
|
|||
* which is the duplicate 20 MHz MCS (bit 5 set, all others zero.)
|
||||
*/
|
||||
#define RATE_HT_MCS_RATE_CODE_MSK 0x7
|
||||
#define RATE_HT_MCS_NSS_POS 3
|
||||
#define RATE_HT_MCS_NSS_MSK (3 << RATE_HT_MCS_NSS_POS)
|
||||
|
||||
/* Bit 10: (1) Use Green Field preamble */
|
||||
#define RATE_HT_MCS_GF_POS 10
|
||||
|
|
|
@ -356,6 +356,7 @@ struct iwl_scan_complete_notif {
|
|||
/* scan offload */
|
||||
#define IWL_MAX_SCAN_CHANNELS 40
|
||||
#define IWL_SCAN_MAX_BLACKLIST_LEN 64
|
||||
#define IWL_SCAN_SHORT_BLACKLIST_LEN 16
|
||||
#define IWL_SCAN_MAX_PROFILES 11
|
||||
#define SCAN_OFFLOAD_PROBE_REQ_SIZE 512
|
||||
|
||||
|
@ -368,6 +369,12 @@ struct iwl_scan_complete_notif {
|
|||
#define IWL_FULL_SCAN_MULTIPLIER 5
|
||||
#define IWL_FAST_SCHED_SCAN_ITERATIONS 3
|
||||
|
||||
enum scan_framework_client {
|
||||
SCAN_CLIENT_SCHED_SCAN = BIT(0),
|
||||
SCAN_CLIENT_NETDETECT = BIT(1),
|
||||
SCAN_CLIENT_ASSET_TRACKING = BIT(2),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6
|
||||
* @scan_flags: see enum iwl_scan_flags
|
||||
|
@ -449,11 +456,12 @@ struct iwl_scan_offload_cfg {
|
|||
* iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S
|
||||
* @ssid: MAC address to filter out
|
||||
* @reported_rssi: AP rssi reported to the host
|
||||
* @client_bitmap: clients ignore this entry - enum scan_framework_client
|
||||
*/
|
||||
struct iwl_scan_offload_blacklist {
|
||||
u8 ssid[ETH_ALEN];
|
||||
u8 reported_rssi;
|
||||
u8 reserved;
|
||||
u8 client_bitmap;
|
||||
} __packed;
|
||||
|
||||
enum iwl_scan_offload_network_type {
|
||||
|
@ -475,6 +483,7 @@ enum iwl_scan_offload_band_selection {
|
|||
* @aut_alg: authentication olgorithm to match - bitmap
|
||||
* @network_type: enum iwl_scan_offload_network_type
|
||||
* @band_selection: enum iwl_scan_offload_band_selection
|
||||
* @client_bitmap: clients waiting for match - enum scan_framework_client
|
||||
*/
|
||||
struct iwl_scan_offload_profile {
|
||||
u8 ssid_index;
|
||||
|
@ -482,7 +491,8 @@ struct iwl_scan_offload_profile {
|
|||
u8 auth_alg;
|
||||
u8 network_type;
|
||||
u8 band_selection;
|
||||
u8 reserved[3];
|
||||
u8 client_bitmap;
|
||||
u8 reserved[2];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
|
@ -491,13 +501,18 @@ struct iwl_scan_offload_profile {
|
|||
* @profiles: profiles to search for match
|
||||
* @blacklist_len: length of blacklist
|
||||
* @num_profiles: num of profiles in the list
|
||||
* @match_notify: clients waiting for match found notification
|
||||
* @pass_match: clients waiting for the results
|
||||
* @active_clients: active clients bitmap - enum scan_framework_client
|
||||
*/
|
||||
struct iwl_scan_offload_profile_cfg {
|
||||
struct iwl_scan_offload_blacklist blacklist[IWL_SCAN_MAX_BLACKLIST_LEN];
|
||||
struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES];
|
||||
u8 blacklist_len;
|
||||
u8 num_profiles;
|
||||
u8 reserved[2];
|
||||
u8 match_notify;
|
||||
u8 pass_match;
|
||||
u8 active_clients;
|
||||
u8 reserved[3];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
|
@ -560,4 +575,15 @@ struct iwl_scan_offload_complete {
|
|||
u8 reserved;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* iwl_sched_scan_results - SCAN_OFFLOAD_MATCH_FOUND_NTF_API_S_VER_1
|
||||
* @ssid_bitmap: SSIDs indexes found in this iteration
|
||||
* @client_bitmap: clients that are active and wait for this notification
|
||||
*/
|
||||
struct iwl_sched_scan_results {
|
||||
__le16 ssid_bitmap;
|
||||
u8 client_bitmap;
|
||||
u8 reserved;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -247,7 +247,7 @@ struct iwl_mvm_keyinfo {
|
|||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_add_sta_cmd - Add / modify a station in the fw's station table
|
||||
* struct iwl_mvm_add_sta_cmd_v5 - Add/modify a station in the fw's sta table.
|
||||
* ( REPLY_ADD_STA = 0x18 )
|
||||
* @add_modify: 1: modify existing, 0: add new station
|
||||
* @unicast_tx_key_id: unicast tx key id. Relevant only when unicast key sent
|
||||
|
@ -286,7 +286,7 @@ struct iwl_mvm_keyinfo {
|
|||
* ADD_STA sets up the table entry for one station, either creating a new
|
||||
* entry, or modifying a pre-existing one.
|
||||
*/
|
||||
struct iwl_mvm_add_sta_cmd {
|
||||
struct iwl_mvm_add_sta_cmd_v5 {
|
||||
u8 add_modify;
|
||||
u8 unicast_tx_key_id;
|
||||
u8 multicast_tx_key_id;
|
||||
|
@ -312,6 +312,57 @@ struct iwl_mvm_add_sta_cmd {
|
|||
__le32 tfd_queue_msk;
|
||||
} __packed; /* ADD_STA_CMD_API_S_VER_5 */
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_add_sta_cmd_v6 - Add / modify a station
|
||||
* VER_6 of this command is quite similar to VER_5 except
|
||||
* exclusion of all fields related to the security key installation.
|
||||
*/
|
||||
struct iwl_mvm_add_sta_cmd_v6 {
|
||||
u8 add_modify;
|
||||
u8 reserved1;
|
||||
__le16 tid_disable_tx;
|
||||
__le32 mac_id_n_color;
|
||||
u8 addr[ETH_ALEN]; /* _STA_ID_MODIFY_INFO_API_S_VER_1 */
|
||||
__le16 reserved2;
|
||||
u8 sta_id;
|
||||
u8 modify_mask;
|
||||
__le16 reserved3;
|
||||
__le32 station_flags;
|
||||
__le32 station_flags_msk;
|
||||
u8 add_immediate_ba_tid;
|
||||
u8 remove_immediate_ba_tid;
|
||||
__le16 add_immediate_ba_ssn;
|
||||
__le16 sleep_tx_count;
|
||||
__le16 sleep_state_flags;
|
||||
__le16 assoc_id;
|
||||
__le16 beamform_flags;
|
||||
__le32 tfd_queue_msk;
|
||||
} __packed; /* ADD_STA_CMD_API_S_VER_6 */
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_add_sta_key_cmd - add/modify sta key
|
||||
* ( REPLY_ADD_STA_KEY = 0x17 )
|
||||
* @sta_id: index of station in uCode's station table
|
||||
* @key_offset: key offset in key storage
|
||||
* @key_flags: type %iwl_sta_key_flag
|
||||
* @key: key material data
|
||||
* @key2: key material data
|
||||
* @rx_secur_seq_cnt: RX security sequence counter for the key
|
||||
* @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection
|
||||
* @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx
|
||||
*/
|
||||
struct iwl_mvm_add_sta_key_cmd {
|
||||
u8 sta_id;
|
||||
u8 key_offset;
|
||||
__le16 key_flags;
|
||||
u8 key[16];
|
||||
u8 key2[16];
|
||||
u8 rx_secur_seq_cnt[16];
|
||||
u8 tkip_rx_tsc_byte2;
|
||||
u8 reserved;
|
||||
__le16 tkip_rx_ttak[5];
|
||||
} __packed; /* ADD_MODIFY_STA_KEY_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* enum iwl_mvm_add_sta_rsp_status - status in the response to ADD_STA command
|
||||
* @ADD_STA_SUCCESS: operation was executed successfully
|
||||
|
|
|
@ -72,17 +72,17 @@
|
|||
#include "fw-api-d3.h"
|
||||
#include "fw-api-bt-coex.h"
|
||||
|
||||
/* queue and FIFO numbers by usage */
|
||||
/* maximal number of Tx queues in any platform */
|
||||
#define IWL_MVM_MAX_QUEUES 20
|
||||
|
||||
/* Tx queue numbers */
|
||||
enum {
|
||||
IWL_MVM_OFFCHANNEL_QUEUE = 8,
|
||||
IWL_MVM_CMD_QUEUE = 9,
|
||||
IWL_MVM_AUX_QUEUE = 15,
|
||||
IWL_MVM_FIRST_AGG_QUEUE = 16,
|
||||
IWL_MVM_NUM_QUEUES = 20,
|
||||
IWL_MVM_LAST_AGG_QUEUE = IWL_MVM_NUM_QUEUES - 1,
|
||||
IWL_MVM_CMD_FIFO = 7
|
||||
};
|
||||
|
||||
#define IWL_MVM_CMD_FIFO 7
|
||||
|
||||
#define IWL_MVM_STATION_COUNT 16
|
||||
|
||||
/* commands */
|
||||
|
@ -97,6 +97,7 @@ enum {
|
|||
DBG_CFG = 0x9,
|
||||
|
||||
/* station table */
|
||||
ADD_STA_KEY = 0x17,
|
||||
ADD_STA = 0x18,
|
||||
REMOVE_STA = 0x19,
|
||||
|
||||
|
@ -114,6 +115,7 @@ enum {
|
|||
TIME_EVENT_NOTIFICATION = 0x2a,
|
||||
BINDING_CONTEXT_CMD = 0x2b,
|
||||
TIME_QUOTA_CMD = 0x2c,
|
||||
NON_QOS_TX_COUNTER_CMD = 0x2d,
|
||||
|
||||
LQ_CMD = 0x4e,
|
||||
|
||||
|
@ -130,6 +132,7 @@ enum {
|
|||
SCAN_OFFLOAD_COMPLETE = 0x6D,
|
||||
SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
|
||||
SCAN_OFFLOAD_CONFIG_CMD = 0x6f,
|
||||
MATCH_FOUND_NOTIFICATION = 0xd9,
|
||||
|
||||
/* Phy */
|
||||
PHY_CONFIGURATION_CMD = 0x6a,
|
||||
|
@ -178,6 +181,7 @@ enum {
|
|||
BT_COEX_PRIO_TABLE = 0xcc,
|
||||
BT_COEX_PROT_ENV = 0xcd,
|
||||
BT_PROFILE_NOTIFICATION = 0xce,
|
||||
BT_COEX_CI = 0x5d,
|
||||
|
||||
REPLY_BEACON_FILTERING_CMD = 0xd2,
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
|
|||
*/
|
||||
|
||||
for (i = 0; i < IWL_MAX_HW_QUEUES; i++) {
|
||||
if (i < IWL_MVM_FIRST_AGG_QUEUE && i != IWL_MVM_CMD_QUEUE)
|
||||
if (i < mvm->first_agg_queue && i != IWL_MVM_CMD_QUEUE)
|
||||
mvm->queue_to_mac80211[i] = i;
|
||||
else
|
||||
mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
|
||||
|
@ -243,7 +243,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
|
|||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (mvm->init_ucode_run)
|
||||
if (mvm->init_ucode_complete)
|
||||
return 0;
|
||||
|
||||
iwl_init_notification_wait(&mvm->notif_wait,
|
||||
|
@ -264,6 +264,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
|
|||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* Read the NVM only at driver load time, no need to do this twice */
|
||||
if (read_nvm) {
|
||||
/* Read nvm */
|
||||
ret = iwl_nvm_init(mvm);
|
||||
|
@ -273,6 +274,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
|
|||
}
|
||||
}
|
||||
|
||||
/* In case we read the NVM from external file, load it to the NIC */
|
||||
if (iwlwifi_mod_params.nvm_file)
|
||||
iwl_mvm_load_nvm_to_nic(mvm);
|
||||
|
||||
ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);
|
||||
WARN_ON(ret);
|
||||
|
||||
|
@ -310,7 +315,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
|
|||
ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait,
|
||||
MVM_UCODE_CALIB_TIMEOUT);
|
||||
if (!ret)
|
||||
mvm->init_ucode_run = true;
|
||||
mvm->init_ucode_complete = true;
|
||||
goto out;
|
||||
|
||||
error:
|
||||
|
@ -353,8 +358,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* If we were in RFKILL during module loading, load init ucode now */
|
||||
if (!mvm->init_ucode_run) {
|
||||
/*
|
||||
* If we haven't completed the run of the init ucode during
|
||||
* module loading, load init ucode now
|
||||
* (for example, if we were in RFKILL)
|
||||
*/
|
||||
if (!mvm->init_ucode_complete) {
|
||||
ret = iwl_run_init_mvm_ucode(mvm, false);
|
||||
if (ret && !iwlmvm_mod_params.init_dbg) {
|
||||
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret);
|
||||
|
@ -424,6 +433,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
|||
goto error;
|
||||
}
|
||||
|
||||
ret = iwl_mvm_power_update_device_mode(mvm);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
|
||||
return 0;
|
||||
error:
|
||||
|
|
|
@ -80,7 +80,7 @@ struct iwl_mvm_mac_iface_iterator_data {
|
|||
struct ieee80211_vif *vif;
|
||||
unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)];
|
||||
unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)];
|
||||
unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_FIRST_AGG_QUEUE)];
|
||||
unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_MAX_QUEUES)];
|
||||
enum iwl_tsf_id preferred_tsf;
|
||||
bool found_vif;
|
||||
};
|
||||
|
@ -218,7 +218,7 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
|||
.preferred_tsf = NUM_TSF_IDS,
|
||||
.used_hw_queues = {
|
||||
BIT(IWL_MVM_OFFCHANNEL_QUEUE) |
|
||||
BIT(IWL_MVM_AUX_QUEUE) |
|
||||
BIT(mvm->aux_queue) |
|
||||
BIT(IWL_MVM_CMD_QUEUE)
|
||||
},
|
||||
.found_vif = false,
|
||||
|
@ -242,9 +242,17 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
|||
* that we should share it with another interface.
|
||||
*/
|
||||
|
||||
/* Currently, MAC ID 0 should be used only for the managed vif */
|
||||
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
|
||||
/* Currently, MAC ID 0 should be used only for the managed/IBSS vif */
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (!vif->p2p)
|
||||
break;
|
||||
/* fall through */
|
||||
default:
|
||||
__clear_bit(0, data.available_mac_ids);
|
||||
}
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
|
@ -302,9 +310,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
|||
/* Find available queues, and allocate them to the ACs */
|
||||
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
u8 queue = find_first_zero_bit(data.used_hw_queues,
|
||||
IWL_MVM_FIRST_AGG_QUEUE);
|
||||
mvm->first_agg_queue);
|
||||
|
||||
if (queue >= IWL_MVM_FIRST_AGG_QUEUE) {
|
||||
if (queue >= mvm->first_agg_queue) {
|
||||
IWL_ERR(mvm, "Failed to allocate queue\n");
|
||||
ret = -EIO;
|
||||
goto exit_fail;
|
||||
|
@ -317,9 +325,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
|
|||
/* Allocate the CAB queue for softAP and GO interfaces */
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
u8 queue = find_first_zero_bit(data.used_hw_queues,
|
||||
IWL_MVM_FIRST_AGG_QUEUE);
|
||||
mvm->first_agg_queue);
|
||||
|
||||
if (queue >= IWL_MVM_FIRST_AGG_QUEUE) {
|
||||
if (queue >= mvm->first_agg_queue) {
|
||||
IWL_ERR(mvm, "Failed to allocate cab queue\n");
|
||||
ret = -EIO;
|
||||
goto exit_fail;
|
||||
|
@ -559,8 +567,12 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
|
|||
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
|
||||
|
||||
/* Don't use cts to self as the fw doesn't support it currently. */
|
||||
if (vif->bss_conf.use_cts_prot)
|
||||
if (vif->bss_conf.use_cts_prot) {
|
||||
cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
|
||||
if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8)
|
||||
cmd->protection_flags |=
|
||||
cpu_to_le32(MAC_PROT_FLG_SELF_CTS_EN);
|
||||
}
|
||||
|
||||
/*
|
||||
* I think that we should enable these 2 flags regardless the HT PROT
|
||||
|
@ -712,6 +724,31 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
|
|||
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
|
||||
}
|
||||
|
||||
static int iwl_mvm_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
u32 action)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mac_ctx_cmd cmd = {};
|
||||
|
||||
WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);
|
||||
|
||||
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
|
||||
|
||||
cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_BEACON |
|
||||
MAC_FILTER_IN_PROBE_REQUEST);
|
||||
|
||||
/* cmd.ibss.beacon_time/cmd.ibss.beacon_tsf are curently ignored */
|
||||
cmd.ibss.bi = cpu_to_le32(vif->bss_conf.beacon_int);
|
||||
cmd.ibss.bi_reciprocal =
|
||||
cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int));
|
||||
|
||||
/* TODO: Assumes that the beacon id == mac context id */
|
||||
cmd.ibss.beacon_template = cpu_to_le32(mvmvif->id);
|
||||
|
||||
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
|
||||
}
|
||||
|
||||
struct iwl_mvm_go_iterator_data {
|
||||
bool go_active;
|
||||
};
|
||||
|
@ -721,7 +758,8 @@ static void iwl_mvm_go_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif)
|
|||
struct iwl_mvm_go_iterator_data *data = _data;
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP && vif->p2p && mvmvif->ap_active)
|
||||
if (vif->type == NL80211_IFTYPE_AP && vif->p2p &&
|
||||
mvmvif->ap_ibss_active)
|
||||
data->go_active = true;
|
||||
}
|
||||
|
||||
|
@ -833,9 +871,10 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
|
|||
cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate));
|
||||
|
||||
/* Set up TX beacon command fields */
|
||||
iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd,
|
||||
beacon->data,
|
||||
beacon_skb_len);
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd,
|
||||
beacon->data,
|
||||
beacon_skb_len);
|
||||
|
||||
/* Submit command */
|
||||
cmd.len[0] = sizeof(beacon_cmd);
|
||||
|
@ -848,14 +887,15 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
|
|||
return iwl_mvm_send_cmd(mvm, &cmd);
|
||||
}
|
||||
|
||||
/* The beacon template for the AP/GO context has changed and needs update */
|
||||
/* The beacon template for the AP/GO/IBSS has changed and needs update */
|
||||
int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct sk_buff *beacon;
|
||||
int ret;
|
||||
|
||||
WARN_ON(vif->type != NL80211_IFTYPE_AP);
|
||||
WARN_ON(vif->type != NL80211_IFTYPE_AP &&
|
||||
vif->type != NL80211_IFTYPE_ADHOC);
|
||||
|
||||
beacon = ieee80211_beacon_get(mvm->hw, vif);
|
||||
if (!beacon)
|
||||
|
@ -1018,6 +1058,8 @@ static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
return iwl_mvm_mac_ctxt_cmd_listener(mvm, vif, action);
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
return iwl_mvm_mac_ctxt_cmd_p2p_device(mvm, vif, action);
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
return iwl_mvm_mac_ctxt_cmd_ibss(mvm, vif, action);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1038,6 +1080,9 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* will only do anything at resume from D3 time */
|
||||
iwl_mvm_set_last_nonqos_seq(mvm, vif);
|
||||
|
||||
mvmvif->uploaded = true;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
#include "iwl-eeprom-parse.h"
|
||||
#include "fw-api-scan.h"
|
||||
#include "iwl-phy-db.h"
|
||||
#include "testmode.h"
|
||||
|
||||
static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
|
||||
{
|
||||
|
@ -138,6 +139,14 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm)
|
|||
}
|
||||
}
|
||||
|
||||
static int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm)
|
||||
{
|
||||
/* we create the 802.11 header and SSID element */
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID)
|
||||
return mvm->fw->ucode_capa.max_probe_length - 24 - 2;
|
||||
return mvm->fw->ucode_capa.max_probe_length - 24 - 34;
|
||||
}
|
||||
|
||||
int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct ieee80211_hw *hw = mvm->hw;
|
||||
|
@ -158,7 +167,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
IEEE80211_HW_SUPPORTS_STATIC_SMPS |
|
||||
IEEE80211_HW_SUPPORTS_UAPSD;
|
||||
|
||||
hw->queues = IWL_MVM_FIRST_AGG_QUEUE;
|
||||
hw->queues = mvm->first_agg_queue;
|
||||
hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
|
||||
hw->rate_control_algorithm = "iwl-mvm-rs";
|
||||
|
||||
|
@ -181,6 +190,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_P2P_DEVICE);
|
||||
|
||||
/* IBSS has bugs in older versions */
|
||||
if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 8)
|
||||
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
|
||||
|
||||
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
|
||||
WIPHY_FLAG_DISABLE_BEACON_HINTS |
|
||||
WIPHY_FLAG_IBSS_RSN;
|
||||
|
@ -212,9 +225,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
|
||||
iwl_mvm_reset_phy_ctxts(mvm);
|
||||
|
||||
/* we create the 802.11 header and a max-length SSID element */
|
||||
hw->wiphy->max_scan_ie_len =
|
||||
mvm->fw->ucode_capa.max_probe_length - 24 - 34;
|
||||
hw->wiphy->max_scan_ie_len = iwl_mvm_max_scan_ie_len(mvm);
|
||||
|
||||
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
|
||||
|
||||
if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels)
|
||||
|
@ -231,6 +243,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
else
|
||||
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) {
|
||||
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
|
||||
hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
|
||||
hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
|
||||
/* we create the 802.11 header and zero length SSID IE. */
|
||||
hw->wiphy->max_sched_scan_ie_len =
|
||||
SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
|
||||
}
|
||||
|
||||
hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
|
||||
NL80211_FEATURE_P2P_GO_OPPPS;
|
||||
|
||||
|
@ -548,7 +569,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
|
|||
* In short: there's not much we can do at this point, other than
|
||||
* allocating resources :)
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
if (vif->type == NL80211_IFTYPE_AP ||
|
||||
vif->type == NL80211_IFTYPE_ADHOC) {
|
||||
u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
|
||||
ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta,
|
||||
qmask);
|
||||
|
@ -698,7 +720,14 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
|
|||
* For AP/GO interface, the tear down of the resources allocated to the
|
||||
* interface is be handled as part of the stop_ap flow.
|
||||
*/
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
if (vif->type == NL80211_IFTYPE_AP ||
|
||||
vif->type == NL80211_IFTYPE_ADHOC) {
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
if (vif == mvm->noa_vif) {
|
||||
mvm->noa_vif = NULL;
|
||||
mvm->noa_duration = 0;
|
||||
}
|
||||
#endif
|
||||
iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
|
||||
goto out_release;
|
||||
}
|
||||
|
@ -796,6 +825,27 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|||
return;
|
||||
}
|
||||
iwl_mvm_configure_mcast_filter(mvm, vif);
|
||||
|
||||
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
|
||||
&mvm->status)) {
|
||||
/*
|
||||
* If we're restarting then the firmware will
|
||||
* obviously have lost synchronisation with
|
||||
* the AP. It will attempt to synchronise by
|
||||
* itself, but we can make it more reliable by
|
||||
* scheduling a session protection time event.
|
||||
*
|
||||
* The firmware needs to receive a beacon to
|
||||
* catch up with synchronisation, use 110% of
|
||||
* the beacon interval.
|
||||
*
|
||||
* Set a large maximum delay to allow for more
|
||||
* than a single interface.
|
||||
*/
|
||||
u32 dur = (11 * vif->bss_conf.beacon_int) / 10;
|
||||
iwl_mvm_protect_session(mvm, vif, dur, dur,
|
||||
5 * dur);
|
||||
}
|
||||
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
|
||||
/* remove AP station now that the MAC is unassoc */
|
||||
ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
|
||||
|
@ -819,7 +869,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|||
if (ret)
|
||||
IWL_ERR(mvm, "failed to update power mode\n");
|
||||
}
|
||||
iwl_mvm_bt_coex_vif_assoc(mvm, vif);
|
||||
iwl_mvm_bt_coex_vif_change(mvm);
|
||||
} else if (changes & BSS_CHANGED_BEACON_INFO) {
|
||||
/*
|
||||
* We received a beacon _after_ association so
|
||||
|
@ -848,7 +898,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|||
}
|
||||
}
|
||||
|
||||
static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
@ -871,7 +922,7 @@ static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||
if (ret)
|
||||
goto out_remove;
|
||||
|
||||
mvmvif->ap_active = true;
|
||||
mvmvif->ap_ibss_active = true;
|
||||
|
||||
/* Send the bcast station. At this stage the TBTT and DTIM time events
|
||||
* are added and applied to the scheduler */
|
||||
|
@ -883,10 +934,12 @@ static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||
if (ret)
|
||||
goto out_rm_bcast;
|
||||
|
||||
/* Need to update the P2P Device MAC */
|
||||
/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
|
||||
if (vif->p2p && mvm->p2p_device_vif)
|
||||
iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif);
|
||||
|
||||
iwl_mvm_bt_coex_vif_change(mvm);
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
return 0;
|
||||
|
||||
|
@ -901,7 +954,8 @@ out_unlock:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
@ -910,9 +964,11 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
mvmvif->ap_active = false;
|
||||
mvmvif->ap_ibss_active = false;
|
||||
|
||||
/* Need to update the P2P Device MAC */
|
||||
iwl_mvm_bt_coex_vif_change(mvm);
|
||||
|
||||
/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
|
||||
if (vif->p2p && mvm->p2p_device_vif)
|
||||
iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif);
|
||||
|
||||
|
@ -924,10 +980,11 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
static void iwl_mvm_bss_info_changed_ap(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
u32 changes)
|
||||
static void
|
||||
iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
u32 changes)
|
||||
{
|
||||
/* Need to send a new beacon template to the FW */
|
||||
if (changes & BSS_CHANGED_BEACON) {
|
||||
|
@ -950,7 +1007,8 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
|
|||
iwl_mvm_bss_info_changed_station(mvm, vif, bss_conf, changes);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
iwl_mvm_bss_info_changed_ap(mvm, vif, bss_conf, changes);
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
iwl_mvm_bss_info_changed_ap_ibss(mvm, vif, bss_conf, changes);
|
||||
break;
|
||||
default:
|
||||
/* shouldn't happen */
|
||||
|
@ -1163,7 +1221,54 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&mvm->mutex);
|
||||
/* Try really hard to protect the session and hear a beacon */
|
||||
iwl_mvm_protect_session(mvm, vif, duration, min_duration);
|
||||
iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
|
||||
IWL_DEBUG_SCAN(mvm,
|
||||
"SCHED SCAN request during internal scan - abort\n");
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mvm->scan_status = IWL_MVM_SCAN_SCHED;
|
||||
|
||||
ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = iwl_mvm_sched_scan_start(mvm, req);
|
||||
if (!ret)
|
||||
goto out;
|
||||
err:
|
||||
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
||||
out:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
iwl_mvm_sched_scan_stop(mvm);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
|
@ -1207,8 +1312,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
|||
|
||||
switch (cmd) {
|
||||
case SET_KEY:
|
||||
if (vif->type == NL80211_IFTYPE_AP && !sta) {
|
||||
/* GTK on AP interface is a TX-only key, return 0 */
|
||||
if ((vif->type == NL80211_IFTYPE_ADHOC ||
|
||||
vif->type == NL80211_IFTYPE_AP) && !sta) {
|
||||
/*
|
||||
* GTK on AP interface is a TX-only key, return 0;
|
||||
* on IBSS they're per-station and because we're lazy
|
||||
* we don't support them for RX, so do the same.
|
||||
*/
|
||||
ret = 0;
|
||||
key->hw_key_idx = STA_KEY_IDX_INVALID;
|
||||
break;
|
||||
|
@ -1252,6 +1362,9 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
|
||||
if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)
|
||||
return;
|
||||
|
||||
iwl_mvm_update_tkip_key(mvm, vif, keyconf, sta, iv32, phase1key);
|
||||
}
|
||||
|
||||
|
@ -1445,6 +1558,7 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
|
|||
iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def,
|
||||
ctx->rx_chains_static,
|
||||
ctx->rx_chains_dynamic);
|
||||
iwl_mvm_bt_coex_vif_change(mvm);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
|
@ -1464,14 +1578,14 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
/*
|
||||
* The AP binding flow is handled as part of the start_ap flow
|
||||
* (in bss_info_changed).
|
||||
* (in bss_info_changed), similarly for IBSS.
|
||||
*/
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
break;
|
||||
default:
|
||||
|
@ -1517,10 +1631,10 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
|
||||
iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
goto out_unlock;
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
goto out_unlock;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
mvmvif->monitor_active = false;
|
||||
iwl_mvm_update_quotas(mvm, NULL);
|
||||
|
@ -1550,14 +1664,72 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
|
|||
return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif);
|
||||
}
|
||||
|
||||
static void iwl_mvm_mac_rssi_callback(struct ieee80211_hw *hw,
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
static const struct nla_policy iwl_mvm_tm_policy[IWL_MVM_TM_ATTR_MAX + 1] = {
|
||||
[IWL_MVM_TM_ATTR_CMD] = { .type = NLA_U32 },
|
||||
[IWL_MVM_TM_ATTR_NOA_DURATION] = { .type = NLA_U32 },
|
||||
[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_rssi_event rssi_event)
|
||||
void *data, int len)
|
||||
{
|
||||
struct nlattr *tb[IWL_MVM_TM_ATTR_MAX + 1];
|
||||
int err;
|
||||
u32 noa_duration;
|
||||
|
||||
err = nla_parse(tb, IWL_MVM_TM_ATTR_MAX, data, len, iwl_mvm_tm_policy);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!tb[IWL_MVM_TM_ATTR_CMD])
|
||||
return -EINVAL;
|
||||
|
||||
switch (nla_get_u32(tb[IWL_MVM_TM_ATTR_CMD])) {
|
||||
case IWL_MVM_TM_CMD_SET_NOA:
|
||||
if (!vif || vif->type != NL80211_IFTYPE_AP || !vif->p2p ||
|
||||
!vif->bss_conf.enable_beacon ||
|
||||
!tb[IWL_MVM_TM_ATTR_NOA_DURATION])
|
||||
return -EINVAL;
|
||||
|
||||
noa_duration = nla_get_u32(tb[IWL_MVM_TM_ATTR_NOA_DURATION]);
|
||||
if (noa_duration >= vif->bss_conf.beacon_int)
|
||||
return -EINVAL;
|
||||
|
||||
mvm->noa_duration = noa_duration;
|
||||
mvm->noa_vif = vif;
|
||||
|
||||
return iwl_mvm_update_quotas(mvm, NULL);
|
||||
case IWL_MVM_TM_CMD_SET_BEACON_FILTER:
|
||||
/* must be associated client vif - ignore authorized */
|
||||
if (!vif || vif->type != NL80211_IFTYPE_STATION ||
|
||||
!vif->bss_conf.assoc || !vif->bss_conf.dtim_period ||
|
||||
!tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE])
|
||||
return -EINVAL;
|
||||
|
||||
if (nla_get_u32(tb[IWL_MVM_TM_ATTR_BEACON_FILTER_STATE]))
|
||||
return iwl_mvm_enable_beacon_filter(mvm, vif);
|
||||
return iwl_mvm_disable_beacon_filter(mvm, vif);
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
void *data, int len)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
int err;
|
||||
|
||||
iwl_mvm_bt_rssi_event(mvm, vif, rssi_event);
|
||||
mutex_lock(&mvm->mutex);
|
||||
err = __iwl_mvm_mac_testmode_cmd(mvm, vif, data, len);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ieee80211_ops iwl_mvm_hw_ops = {
|
||||
.tx = iwl_mvm_mac_tx,
|
||||
|
@ -1578,23 +1750,27 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
|
|||
.set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
|
||||
.conf_tx = iwl_mvm_mac_conf_tx,
|
||||
.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
|
||||
.sched_scan_start = iwl_mvm_mac_sched_scan_start,
|
||||
.sched_scan_stop = iwl_mvm_mac_sched_scan_stop,
|
||||
.set_key = iwl_mvm_mac_set_key,
|
||||
.update_tkip_key = iwl_mvm_mac_update_tkip_key,
|
||||
.remain_on_channel = iwl_mvm_roc,
|
||||
.cancel_remain_on_channel = iwl_mvm_cancel_roc,
|
||||
.rssi_callback = iwl_mvm_mac_rssi_callback,
|
||||
|
||||
.add_chanctx = iwl_mvm_add_chanctx,
|
||||
.remove_chanctx = iwl_mvm_remove_chanctx,
|
||||
.change_chanctx = iwl_mvm_change_chanctx,
|
||||
.assign_vif_chanctx = iwl_mvm_assign_vif_chanctx,
|
||||
.unassign_vif_chanctx = iwl_mvm_unassign_vif_chanctx,
|
||||
|
||||
.start_ap = iwl_mvm_start_ap,
|
||||
.stop_ap = iwl_mvm_stop_ap,
|
||||
.start_ap = iwl_mvm_start_ap_ibss,
|
||||
.stop_ap = iwl_mvm_stop_ap_ibss,
|
||||
.join_ibss = iwl_mvm_start_ap_ibss,
|
||||
.leave_ibss = iwl_mvm_stop_ap_ibss,
|
||||
|
||||
.set_tim = iwl_mvm_set_tim,
|
||||
|
||||
CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd)
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/* look at d3.c */
|
||||
.suspend = iwl_mvm_suspend,
|
||||
|
|
|
@ -162,6 +162,7 @@ enum iwl_power_scheme {
|
|||
struct iwl_mvm_power_ops {
|
||||
int (*power_update_mode)(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif);
|
||||
int (*power_update_device_mode)(struct iwl_mvm *mvm);
|
||||
int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
|
@ -241,12 +242,18 @@ enum iwl_mvm_smps_type_request {
|
|||
* @last_beacon_signal: last beacon rssi signal in dbm
|
||||
* @ave_beacon_signal: average beacon signal
|
||||
* @last_cqm_event: rssi of the last cqm event
|
||||
* @bt_coex_min_thold: minimum threshold for BT coex
|
||||
* @bt_coex_max_thold: maximum threshold for BT coex
|
||||
* @last_bt_coex_event: rssi of the last BT coex event
|
||||
*/
|
||||
struct iwl_mvm_vif_bf_data {
|
||||
bool bf_enabled;
|
||||
bool ba_enabled;
|
||||
s8 ave_beacon_signal;
|
||||
s8 last_cqm_event;
|
||||
s8 bt_coex_min_thold;
|
||||
s8 bt_coex_max_thold;
|
||||
s8 last_bt_coex_event;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -255,8 +262,8 @@ struct iwl_mvm_vif_bf_data {
|
|||
* @color: to solve races upon MAC addition and removal
|
||||
* @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA
|
||||
* @uploaded: indicates the MAC context has been added to the device
|
||||
* @ap_active: indicates that ap context is configured, and that the interface
|
||||
* should get quota etc.
|
||||
* @ap_ibss_active: indicates that AP/IBSS is configured and that the interface
|
||||
* should get quota etc.
|
||||
* @monitor_active: indicates that monitor context is configured, and that the
|
||||
* interface should get quota etc.
|
||||
* @queue_params: QoS params for this MAC
|
||||
|
@ -272,7 +279,7 @@ struct iwl_mvm_vif {
|
|||
u8 ap_sta_id;
|
||||
|
||||
bool uploaded;
|
||||
bool ap_active;
|
||||
bool ap_ibss_active;
|
||||
bool monitor_active;
|
||||
struct iwl_mvm_vif_bf_data bf_data;
|
||||
|
||||
|
@ -306,6 +313,9 @@ struct iwl_mvm_vif {
|
|||
|
||||
int tx_key_idx;
|
||||
|
||||
bool seqno_valid;
|
||||
u16 seqno;
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
/* IPv6 addresses for WoWLAN */
|
||||
struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX];
|
||||
|
@ -333,6 +343,7 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
|
|||
enum iwl_scan_status {
|
||||
IWL_MVM_SCAN_NONE,
|
||||
IWL_MVM_SCAN_OS,
|
||||
IWL_MVM_SCAN_SCHED,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -434,7 +445,7 @@ struct iwl_mvm {
|
|||
|
||||
enum iwl_ucode_type cur_ucode;
|
||||
bool ucode_loaded;
|
||||
bool init_ucode_run;
|
||||
bool init_ucode_complete;
|
||||
u32 error_event_table;
|
||||
u32 log_event_table;
|
||||
|
||||
|
@ -470,6 +481,9 @@ struct iwl_mvm {
|
|||
enum iwl_scan_status scan_status;
|
||||
struct iwl_scan_cmd *scan_cmd;
|
||||
|
||||
/* rx chain antennas set through debugfs for the scan command */
|
||||
u8 scan_rx_ant;
|
||||
|
||||
/* Internal station */
|
||||
struct iwl_mvm_int_sta aux_sta;
|
||||
|
||||
|
@ -479,7 +493,8 @@ struct iwl_mvm {
|
|||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
struct dentry *debugfs_dir;
|
||||
u32 dbgfs_sram_offset, dbgfs_sram_len;
|
||||
bool prevent_power_down_d3;
|
||||
bool disable_power_off;
|
||||
bool disable_power_off_d3;
|
||||
#endif
|
||||
|
||||
struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
|
||||
|
@ -523,12 +538,23 @@ struct iwl_mvm {
|
|||
/* BT-Coex */
|
||||
u8 bt_kill_msk;
|
||||
struct iwl_bt_coex_profile_notif last_bt_notif;
|
||||
struct iwl_bt_coex_ci_cmd last_bt_ci_cmd;
|
||||
|
||||
/* Thermal Throttling and CTkill */
|
||||
struct iwl_mvm_tt_mgmt thermal_throttle;
|
||||
s32 temperature; /* Celsius */
|
||||
|
||||
const struct iwl_mvm_power_ops *pm_ops;
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
u32 noa_duration;
|
||||
struct ieee80211_vif *noa_vif;
|
||||
#endif
|
||||
|
||||
/* Tx queues */
|
||||
u8 aux_queue;
|
||||
u8 first_agg_queue;
|
||||
u8 last_agg_queue;
|
||||
};
|
||||
|
||||
/* Extract MVM priv from op_mode and _hw */
|
||||
|
@ -570,6 +596,9 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm);
|
|||
/* Utils */
|
||||
int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
|
||||
enum ieee80211_band band);
|
||||
void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_tx_rate *r);
|
||||
u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx);
|
||||
void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_dump_sram(struct iwl_mvm *mvm);
|
||||
|
@ -608,6 +637,7 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
|
|||
|
||||
/* NVM */
|
||||
int iwl_nvm_init(struct iwl_mvm *mvm);
|
||||
int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm);
|
||||
|
||||
int iwl_mvm_up(struct iwl_mvm *mvm);
|
||||
int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm);
|
||||
|
@ -682,6 +712,23 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
|
|||
struct iwl_device_cmd *cmd);
|
||||
void iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
|
||||
|
||||
/* Scheduled scan */
|
||||
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_cmd_buffer *rxb,
|
||||
struct iwl_device_cmd *cmd);
|
||||
int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies);
|
||||
int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
|
||||
struct cfg80211_sched_scan_request *req);
|
||||
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
||||
struct cfg80211_sched_scan_request *req);
|
||||
void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm);
|
||||
int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_cmd_buffer *rxb,
|
||||
struct iwl_device_cmd *cmd);
|
||||
|
||||
/* MVM debugfs */
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir);
|
||||
|
@ -720,6 +767,13 @@ static inline int iwl_mvm_power_disable(struct iwl_mvm *mvm,
|
|||
return mvm->pm_ops->power_disable(mvm, vif);
|
||||
}
|
||||
|
||||
static inline int iwl_mvm_power_update_device_mode(struct iwl_mvm *mvm)
|
||||
{
|
||||
if (mvm->pm_ops->power_update_device_mode)
|
||||
return mvm->pm_ops->power_update_device_mode(mvm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
|
@ -745,6 +799,15 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
|
|||
void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, int idx);
|
||||
extern const struct file_operations iwl_dbgfs_d3_test_ops;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif);
|
||||
#else
|
||||
static inline void
|
||||
iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* BT Coex */
|
||||
int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
|
||||
|
@ -754,7 +817,20 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
|
|||
struct iwl_device_cmd *cmd);
|
||||
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
enum ieee80211_rssi_event rssi_event);
|
||||
void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm);
|
||||
u16 iwl_mvm_bt_coex_agg_time_limit(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta);
|
||||
bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta);
|
||||
|
||||
enum iwl_bt_kill_msk {
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_SCO_HID_A2DP,
|
||||
BT_KILL_MSK_REDUCED_TXPOW,
|
||||
BT_KILL_MSK_MAX,
|
||||
};
|
||||
extern const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX];
|
||||
extern const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX];
|
||||
|
||||
/* beacon filtering */
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
|
|
|
@ -77,7 +77,7 @@ static const int nvm_to_read[] = {
|
|||
|
||||
/* Default NVM size to read */
|
||||
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
|
||||
#define IWL_MAX_NVM_SECTION_SIZE 6000
|
||||
#define IWL_MAX_NVM_SECTION_SIZE 7000
|
||||
|
||||
#define NVM_WRITE_OPCODE 1
|
||||
#define NVM_READ_OPCODE 0
|
||||
|
@ -259,6 +259,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
|
|||
#define MAX_NVM_FILE_LEN 16384
|
||||
|
||||
/*
|
||||
* Reads external NVM from a file into mvm->nvm_sections
|
||||
*
|
||||
* HOW TO CREATE THE NVM FILE FORMAT:
|
||||
* ------------------------------
|
||||
* 1. create hex file, format:
|
||||
|
@ -277,20 +279,23 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
|
|||
*
|
||||
* 4. save as "iNVM_xxx.bin" under /lib/firmware
|
||||
*/
|
||||
static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm)
|
||||
static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
|
||||
{
|
||||
int ret, section_id, section_size;
|
||||
int ret, section_size;
|
||||
u16 section_id;
|
||||
const struct firmware *fw_entry;
|
||||
const struct {
|
||||
__le16 word1;
|
||||
__le16 word2;
|
||||
u8 data[];
|
||||
} *file_sec;
|
||||
const u8 *eof;
|
||||
const u8 *eof, *temp;
|
||||
|
||||
#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
|
||||
#define NVM_WORD2_ID(x) (x >> 12)
|
||||
|
||||
IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
|
||||
|
||||
/*
|
||||
* Obtain NVM image via request_firmware. Since we already used
|
||||
* request_firmware_nowait() for the firmware binary load and only
|
||||
|
@ -362,12 +367,18 @@ static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm)
|
|||
break;
|
||||
}
|
||||
|
||||
ret = iwl_nvm_write_section(mvm, section_id, file_sec->data,
|
||||
section_size);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret);
|
||||
temp = kmemdup(file_sec->data, section_size, GFP_KERNEL);
|
||||
if (!temp) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
if (WARN_ON(section_id >= NVM_NUM_OF_SECTIONS)) {
|
||||
IWL_ERR(mvm, "Invalid NVM section ID\n");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
mvm->nvm_sections[section_id].data = temp;
|
||||
mvm->nvm_sections[section_id].length = section_size;
|
||||
|
||||
/* advance to the next section */
|
||||
file_sec = (void *)(file_sec->data + section_size);
|
||||
|
@ -377,6 +388,28 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Loads the NVM data stored in mvm->nvm_sections into the NIC */
|
||||
int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm)
|
||||
{
|
||||
int i, ret;
|
||||
u16 section_id;
|
||||
struct iwl_nvm_section *sections = mvm->nvm_sections;
|
||||
|
||||
IWL_DEBUG_EEPROM(mvm->trans->dev, "'Write to NVM\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
|
||||
section_id = nvm_to_read[i];
|
||||
ret = iwl_nvm_write_section(mvm, section_id,
|
||||
sections[section_id].data,
|
||||
sections[section_id].length);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_nvm_init(struct iwl_mvm *mvm)
|
||||
{
|
||||
int ret, i, section;
|
||||
|
@ -385,36 +418,36 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
|
|||
/* load external NVM if configured */
|
||||
if (iwlwifi_mod_params.nvm_file) {
|
||||
/* move to External NVM flow */
|
||||
ret = iwl_mvm_load_external_nvm(mvm);
|
||||
ret = iwl_mvm_read_external_nvm(mvm);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* Read From FW NVM */
|
||||
IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
|
||||
|
||||
/* Read From FW NVM */
|
||||
IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n");
|
||||
|
||||
/* TODO: find correct NVM max size for a section */
|
||||
nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
|
||||
GFP_KERNEL);
|
||||
if (!nvm_buffer)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
|
||||
section = nvm_to_read[i];
|
||||
/* we override the constness for initial read */
|
||||
ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
|
||||
if (ret < 0)
|
||||
break;
|
||||
temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
|
||||
if (!temp) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
/* TODO: find correct NVM max size for a section */
|
||||
nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
|
||||
GFP_KERNEL);
|
||||
if (!nvm_buffer)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
|
||||
section = nvm_to_read[i];
|
||||
/* we override the constness for initial read */
|
||||
ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
|
||||
if (ret < 0)
|
||||
break;
|
||||
temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
|
||||
if (!temp) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
mvm->nvm_sections[section].data = temp;
|
||||
mvm->nvm_sections[section].length = ret;
|
||||
}
|
||||
mvm->nvm_sections[section].data = temp;
|
||||
mvm->nvm_sections[section].length = ret;
|
||||
kfree(nvm_buffer);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
kfree(nvm_buffer);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mvm->nvm_data = iwl_parse_nvm_sections(mvm);
|
||||
if (!mvm->nvm_data)
|
||||
|
|
|
@ -224,6 +224,10 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
|
|||
|
||||
RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
|
||||
RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
|
||||
RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
|
||||
iwl_mvm_rx_scan_offload_complete_notif, false),
|
||||
RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results,
|
||||
false),
|
||||
|
||||
RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
|
||||
RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
|
||||
|
@ -249,6 +253,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
|
|||
CMD(TIME_EVENT_NOTIFICATION),
|
||||
CMD(BINDING_CONTEXT_CMD),
|
||||
CMD(TIME_QUOTA_CMD),
|
||||
CMD(NON_QOS_TX_COUNTER_CMD),
|
||||
CMD(RADIO_VERSION_NOTIFICATION),
|
||||
CMD(SCAN_REQUEST_CMD),
|
||||
CMD(SCAN_ABORT_CMD),
|
||||
|
@ -260,10 +265,12 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
|
|||
CMD(CALIB_RES_NOTIF_PHY_DB),
|
||||
CMD(SET_CALIB_DEFAULT_CMD),
|
||||
CMD(CALIBRATION_COMPLETE_NOTIFICATION),
|
||||
CMD(ADD_STA_KEY),
|
||||
CMD(ADD_STA),
|
||||
CMD(REMOVE_STA),
|
||||
CMD(LQ_CMD),
|
||||
CMD(SCAN_OFFLOAD_CONFIG_CMD),
|
||||
CMD(MATCH_FOUND_NOTIFICATION),
|
||||
CMD(SCAN_OFFLOAD_REQUEST_CMD),
|
||||
CMD(SCAN_OFFLOAD_ABORT_CMD),
|
||||
CMD(SCAN_OFFLOAD_COMPLETE),
|
||||
|
@ -303,6 +310,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
|
|||
CMD(REPLY_BEACON_FILTERING_CMD),
|
||||
CMD(REPLY_THERMAL_MNG_BACKOFF),
|
||||
CMD(MAC_PM_POWER_TABLE),
|
||||
CMD(BT_COEX_CI),
|
||||
};
|
||||
#undef CMD
|
||||
|
||||
|
@ -344,6 +352,14 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
|
||||
mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0;
|
||||
|
||||
mvm->aux_queue = 15;
|
||||
mvm->first_agg_queue = 16;
|
||||
mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1;
|
||||
if (mvm->cfg->base_params->num_of_queues == 16) {
|
||||
mvm->aux_queue = 11;
|
||||
mvm->first_agg_queue = 12;
|
||||
}
|
||||
|
||||
mutex_init(&mvm->mutex);
|
||||
spin_lock_init(&mvm->async_handlers_lock);
|
||||
INIT_LIST_HEAD(&mvm->time_event_list);
|
||||
|
@ -401,24 +417,32 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
IWL_INFO(mvm, "Detected %s, REV=0x%X\n",
|
||||
mvm->cfg->name, mvm->trans->hw_rev);
|
||||
|
||||
err = iwl_trans_start_hw(mvm->trans);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
iwl_mvm_tt_initialize(mvm);
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
err = iwl_run_init_mvm_ucode(mvm, true);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
/* returns 0 if successful, 1 if success but in rfkill */
|
||||
if (err < 0 && !iwlmvm_mod_params.init_dbg) {
|
||||
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
|
||||
goto out_free;
|
||||
}
|
||||
/*
|
||||
* If the NVM exists in an external file,
|
||||
* there is no need to unnecessarily power up the NIC at driver load
|
||||
*/
|
||||
if (iwlwifi_mod_params.nvm_file) {
|
||||
iwl_nvm_init(mvm);
|
||||
} else {
|
||||
err = iwl_trans_start_hw(mvm->trans);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
/* Stop the hw after the ALIVE and NVM has been read */
|
||||
if (!iwlmvm_mod_params.init_dbg)
|
||||
iwl_trans_stop_hw(mvm->trans, false);
|
||||
mutex_lock(&mvm->mutex);
|
||||
err = iwl_run_init_mvm_ucode(mvm, true);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
/* returns 0 if successful, 1 if success but in rfkill */
|
||||
if (err < 0 && !iwlmvm_mod_params.init_dbg) {
|
||||
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Stop the hw after the ALIVE and NVM has been read */
|
||||
if (!iwlmvm_mod_params.init_dbg)
|
||||
iwl_trans_stop_hw(mvm->trans, false);
|
||||
}
|
||||
|
||||
scan_size = sizeof(struct iwl_scan_cmd) +
|
||||
mvm->fw->ucode_capa.max_probe_length +
|
||||
|
@ -449,7 +473,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
out_free:
|
||||
iwl_phy_db_free(mvm->phy_db);
|
||||
kfree(mvm->scan_cmd);
|
||||
iwl_trans_stop_hw(trans, true);
|
||||
if (!iwlwifi_mod_params.nvm_file)
|
||||
iwl_trans_stop_hw(trans, true);
|
||||
ieee80211_free_hw(mvm->hw);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -715,6 +740,9 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
|
|||
case IWL_MVM_SCAN_OS:
|
||||
ieee80211_scan_completed(mvm->hw, true);
|
||||
break;
|
||||
case IWL_MVM_SCAN_SCHED:
|
||||
ieee80211_sched_scan_stopped(mvm->hw);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mvm->restart_fw > 0)
|
||||
|
|
|
@ -297,11 +297,6 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
if (cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
|
||||
cmd->rx_data_timeout_uapsd =
|
||||
cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
|
||||
cmd->tx_data_timeout_uapsd =
|
||||
cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
|
||||
|
||||
if (cmd->uapsd_ac_flags == (BIT(IEEE80211_AC_VO) |
|
||||
BIT(IEEE80211_AC_VI) |
|
||||
BIT(IEEE80211_AC_BE) |
|
||||
|
@ -316,10 +311,31 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
cmd->uapsd_max_sp = IWL_UAPSD_MAX_SP;
|
||||
cmd->heavy_tx_thld_packets =
|
||||
IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
|
||||
cmd->heavy_rx_thld_packets =
|
||||
IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
|
||||
|
||||
if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags &
|
||||
cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
|
||||
cmd->rx_data_timeout_uapsd =
|
||||
cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
|
||||
cmd->tx_data_timeout_uapsd =
|
||||
cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
|
||||
} else {
|
||||
cmd->rx_data_timeout_uapsd =
|
||||
cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
|
||||
cmd->tx_data_timeout_uapsd =
|
||||
cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
|
||||
}
|
||||
|
||||
if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
|
||||
cmd->heavy_tx_thld_packets =
|
||||
IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
|
||||
cmd->heavy_rx_thld_packets =
|
||||
IWL_MVM_PS_SNOOZE_HEAVY_RX_THLD_PACKETS;
|
||||
} else {
|
||||
cmd->heavy_tx_thld_packets =
|
||||
IWL_MVM_PS_HEAVY_TX_THLD_PACKETS;
|
||||
cmd->heavy_rx_thld_packets =
|
||||
IWL_MVM_PS_HEAVY_RX_THLD_PACKETS;
|
||||
}
|
||||
cmd->heavy_tx_thld_percentage =
|
||||
IWL_MVM_PS_HEAVY_TX_THLD_PERCENT;
|
||||
cmd->heavy_rx_thld_percentage =
|
||||
|
@ -427,6 +443,32 @@ static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm,
|
|||
sizeof(cmd), &cmd);
|
||||
}
|
||||
|
||||
static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_device_power_cmd cmd = {
|
||||
.flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
|
||||
};
|
||||
|
||||
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
|
||||
return 0;
|
||||
|
||||
if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
|
||||
cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if ((mvm->cur_ucode == IWL_UCODE_WOWLAN) ? mvm->disable_power_off_d3 :
|
||||
mvm->disable_power_off)
|
||||
cmd.flags &=
|
||||
cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);
|
||||
#endif
|
||||
IWL_DEBUG_POWER(mvm,
|
||||
"Sending device power command with flags = 0x%X\n",
|
||||
cmd.flags);
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, sizeof(cmd),
|
||||
&cmd);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif, char *buf,
|
||||
|
@ -437,10 +479,11 @@ static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
|
|||
|
||||
iwl_mvm_power_build_cmd(mvm, vif, &cmd);
|
||||
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n",
|
||||
(cmd.flags &
|
||||
cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ?
|
||||
0 : 1);
|
||||
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n",
|
||||
(cmd.flags &
|
||||
cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ?
|
||||
0 : 1);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n",
|
||||
iwlmvm_mod_params.power_scheme);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n",
|
||||
|
@ -606,6 +649,7 @@ int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
|
|||
|
||||
const struct iwl_mvm_power_ops pm_mac_ops = {
|
||||
.power_update_mode = iwl_mvm_power_mac_update_mode,
|
||||
.power_update_device_mode = iwl_mvm_power_update_device,
|
||||
.power_disable = iwl_mvm_power_mac_disable,
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
.power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read,
|
||||
|
|
|
@ -110,7 +110,8 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
|
|||
data->n_interfaces[id]++;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
if (mvmvif->ap_active)
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (mvmvif->ap_ibss_active)
|
||||
data->n_interfaces[id]++;
|
||||
break;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
|
@ -119,16 +120,45 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
|
|||
break;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (vif->bss_conf.ibss_joined)
|
||||
data->n_interfaces[id]++;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
|
||||
struct iwl_time_quota_cmd *cmd)
|
||||
{
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
int i, phy_id = -1, beacon_int = 0;
|
||||
|
||||
if (!mvm->noa_duration || !mvm->noa_vif)
|
||||
return;
|
||||
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(mvm->noa_vif);
|
||||
if (!mvmvif->ap_ibss_active)
|
||||
return;
|
||||
|
||||
phy_id = mvmvif->phy_ctxt->id;
|
||||
beacon_int = mvm->noa_vif->bss_conf.beacon_int;
|
||||
|
||||
for (i = 0; i < MAX_BINDINGS; i++) {
|
||||
u32 id_n_c = le32_to_cpu(cmd->quotas[i].id_and_color);
|
||||
u32 id = (id_n_c & FW_CTXT_ID_MSK) >> FW_CTXT_ID_POS;
|
||||
u32 quota = le32_to_cpu(cmd->quotas[i].quota);
|
||||
|
||||
if (id != phy_id)
|
||||
continue;
|
||||
|
||||
quota *= (beacon_int - mvm->noa_duration);
|
||||
quota /= beacon_int;
|
||||
|
||||
cmd->quotas[i].quota = cpu_to_le32(quota);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
|
||||
{
|
||||
struct iwl_time_quota_cmd cmd = {};
|
||||
|
@ -196,6 +226,8 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
|
|||
/* Give the remainder of the session to the first binding */
|
||||
le32_add_cpu(&cmd.quotas[0].quota, quota_rem);
|
||||
|
||||
iwl_mvm_adjust_quota_for_noa(mvm, &cmd);
|
||||
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC,
|
||||
sizeof(cmd), &cmd);
|
||||
if (ret)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -35,9 +35,11 @@
|
|||
#include "iwl-trans.h"
|
||||
|
||||
struct iwl_rs_rate_info {
|
||||
u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
|
||||
u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
|
||||
u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
|
||||
u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
|
||||
u8 plcp_ht_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
|
||||
u8 plcp_ht_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
|
||||
u8 plcp_vht_siso;
|
||||
u8 plcp_vht_mimo2;
|
||||
u8 prev_rs; /* previous rate used in rs algo */
|
||||
u8 next_rs; /* next rate used in rs algo */
|
||||
};
|
||||
|
@ -83,35 +85,52 @@ enum {
|
|||
#define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX)
|
||||
|
||||
|
||||
/* uCode API values for OFDM high-throughput (HT) bit rates */
|
||||
/* uCode API values for HT/VHT bit rates */
|
||||
enum {
|
||||
IWL_RATE_SISO_6M_PLCP = 0,
|
||||
IWL_RATE_SISO_12M_PLCP = 1,
|
||||
IWL_RATE_SISO_18M_PLCP = 2,
|
||||
IWL_RATE_SISO_24M_PLCP = 3,
|
||||
IWL_RATE_SISO_36M_PLCP = 4,
|
||||
IWL_RATE_SISO_48M_PLCP = 5,
|
||||
IWL_RATE_SISO_54M_PLCP = 6,
|
||||
IWL_RATE_SISO_60M_PLCP = 7,
|
||||
IWL_RATE_MIMO2_6M_PLCP = 0x8,
|
||||
IWL_RATE_MIMO2_12M_PLCP = 0x9,
|
||||
IWL_RATE_MIMO2_18M_PLCP = 0xa,
|
||||
IWL_RATE_MIMO2_24M_PLCP = 0xb,
|
||||
IWL_RATE_MIMO2_36M_PLCP = 0xc,
|
||||
IWL_RATE_MIMO2_48M_PLCP = 0xd,
|
||||
IWL_RATE_MIMO2_54M_PLCP = 0xe,
|
||||
IWL_RATE_MIMO2_60M_PLCP = 0xf,
|
||||
IWL_RATE_MIMO3_6M_PLCP = 0x10,
|
||||
IWL_RATE_MIMO3_12M_PLCP = 0x11,
|
||||
IWL_RATE_MIMO3_18M_PLCP = 0x12,
|
||||
IWL_RATE_MIMO3_24M_PLCP = 0x13,
|
||||
IWL_RATE_MIMO3_36M_PLCP = 0x14,
|
||||
IWL_RATE_MIMO3_48M_PLCP = 0x15,
|
||||
IWL_RATE_MIMO3_54M_PLCP = 0x16,
|
||||
IWL_RATE_MIMO3_60M_PLCP = 0x17,
|
||||
IWL_RATE_SISO_INVM_PLCP,
|
||||
IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
|
||||
IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
|
||||
IWL_RATE_HT_SISO_MCS_0_PLCP = 0,
|
||||
IWL_RATE_HT_SISO_MCS_1_PLCP = 1,
|
||||
IWL_RATE_HT_SISO_MCS_2_PLCP = 2,
|
||||
IWL_RATE_HT_SISO_MCS_3_PLCP = 3,
|
||||
IWL_RATE_HT_SISO_MCS_4_PLCP = 4,
|
||||
IWL_RATE_HT_SISO_MCS_5_PLCP = 5,
|
||||
IWL_RATE_HT_SISO_MCS_6_PLCP = 6,
|
||||
IWL_RATE_HT_SISO_MCS_7_PLCP = 7,
|
||||
IWL_RATE_HT_MIMO2_MCS_0_PLCP = 0x8,
|
||||
IWL_RATE_HT_MIMO2_MCS_1_PLCP = 0x9,
|
||||
IWL_RATE_HT_MIMO2_MCS_2_PLCP = 0xA,
|
||||
IWL_RATE_HT_MIMO2_MCS_3_PLCP = 0xB,
|
||||
IWL_RATE_HT_MIMO2_MCS_4_PLCP = 0xC,
|
||||
IWL_RATE_HT_MIMO2_MCS_5_PLCP = 0xD,
|
||||
IWL_RATE_HT_MIMO2_MCS_6_PLCP = 0xE,
|
||||
IWL_RATE_HT_MIMO2_MCS_7_PLCP = 0xF,
|
||||
IWL_RATE_VHT_SISO_MCS_0_PLCP = 0,
|
||||
IWL_RATE_VHT_SISO_MCS_1_PLCP = 1,
|
||||
IWL_RATE_VHT_SISO_MCS_2_PLCP = 2,
|
||||
IWL_RATE_VHT_SISO_MCS_3_PLCP = 3,
|
||||
IWL_RATE_VHT_SISO_MCS_4_PLCP = 4,
|
||||
IWL_RATE_VHT_SISO_MCS_5_PLCP = 5,
|
||||
IWL_RATE_VHT_SISO_MCS_6_PLCP = 6,
|
||||
IWL_RATE_VHT_SISO_MCS_7_PLCP = 7,
|
||||
IWL_RATE_VHT_SISO_MCS_8_PLCP = 8,
|
||||
IWL_RATE_VHT_SISO_MCS_9_PLCP = 9,
|
||||
IWL_RATE_VHT_MIMO2_MCS_0_PLCP = 0x10,
|
||||
IWL_RATE_VHT_MIMO2_MCS_1_PLCP = 0x11,
|
||||
IWL_RATE_VHT_MIMO2_MCS_2_PLCP = 0x12,
|
||||
IWL_RATE_VHT_MIMO2_MCS_3_PLCP = 0x13,
|
||||
IWL_RATE_VHT_MIMO2_MCS_4_PLCP = 0x14,
|
||||
IWL_RATE_VHT_MIMO2_MCS_5_PLCP = 0x15,
|
||||
IWL_RATE_VHT_MIMO2_MCS_6_PLCP = 0x16,
|
||||
IWL_RATE_VHT_MIMO2_MCS_7_PLCP = 0x17,
|
||||
IWL_RATE_VHT_MIMO2_MCS_8_PLCP = 0x18,
|
||||
IWL_RATE_VHT_MIMO2_MCS_9_PLCP = 0x19,
|
||||
IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_HT_MIMO2_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_VHT_SISO_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_VHT_MIMO2_MCS_INV_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_HT_SISO_MCS_8_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_HT_SISO_MCS_9_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_HT_MIMO2_MCS_8_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
IWL_RATE_HT_MIMO2_MCS_9_PLCP = IWL_RATE_HT_SISO_MCS_INV_PLCP,
|
||||
};
|
||||
|
||||
#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
|
||||
|
@ -139,25 +158,33 @@ enum {
|
|||
#define IWL_RATE_DECREASE_TH 1920 /* 15% */
|
||||
|
||||
/* possible actions when in legacy mode */
|
||||
#define IWL_LEGACY_SWITCH_ANTENNA1 0
|
||||
#define IWL_LEGACY_SWITCH_ANTENNA2 1
|
||||
#define IWL_LEGACY_SWITCH_SISO 2
|
||||
#define IWL_LEGACY_SWITCH_MIMO2 3
|
||||
enum {
|
||||
IWL_LEGACY_SWITCH_ANTENNA,
|
||||
IWL_LEGACY_SWITCH_SISO,
|
||||
IWL_LEGACY_SWITCH_MIMO2,
|
||||
IWL_LEGACY_FIRST_ACTION = IWL_LEGACY_SWITCH_ANTENNA,
|
||||
IWL_LEGACY_LAST_ACTION = IWL_LEGACY_SWITCH_MIMO2,
|
||||
};
|
||||
|
||||
/* possible actions when in siso mode */
|
||||
#define IWL_SISO_SWITCH_ANTENNA1 0
|
||||
#define IWL_SISO_SWITCH_ANTENNA2 1
|
||||
#define IWL_SISO_SWITCH_MIMO2 2
|
||||
#define IWL_SISO_SWITCH_GI 3
|
||||
enum {
|
||||
IWL_SISO_SWITCH_ANTENNA,
|
||||
IWL_SISO_SWITCH_MIMO2,
|
||||
IWL_SISO_SWITCH_GI,
|
||||
IWL_SISO_FIRST_ACTION = IWL_SISO_SWITCH_ANTENNA,
|
||||
IWL_SISO_LAST_ACTION = IWL_SISO_SWITCH_GI,
|
||||
};
|
||||
|
||||
/* possible actions when in mimo mode */
|
||||
#define IWL_MIMO2_SWITCH_ANTENNA1 0
|
||||
#define IWL_MIMO2_SWITCH_ANTENNA2 1
|
||||
#define IWL_MIMO2_SWITCH_SISO_A 2
|
||||
#define IWL_MIMO2_SWITCH_SISO_B 3
|
||||
#define IWL_MIMO2_SWITCH_GI 4
|
||||
enum {
|
||||
IWL_MIMO2_SWITCH_SISO_A,
|
||||
IWL_MIMO2_SWITCH_SISO_B,
|
||||
IWL_MIMO2_SWITCH_GI,
|
||||
IWL_MIMO2_FIRST_ACTION = IWL_MIMO2_SWITCH_SISO_A,
|
||||
IWL_MIMO2_LAST_ACTION = IWL_MIMO2_SWITCH_GI,
|
||||
};
|
||||
|
||||
#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_GI
|
||||
#define IWL_MAX_SEARCH IWL_MIMO2_LAST_ACTION
|
||||
|
||||
#define IWL_ACTION_LIMIT 3 /* # possible actions */
|
||||
|
||||
|
@ -188,20 +215,31 @@ enum {
|
|||
|
||||
enum iwl_table_type {
|
||||
LQ_NONE,
|
||||
LQ_G, /* legacy types */
|
||||
LQ_A,
|
||||
LQ_SISO, /* high-throughput types */
|
||||
LQ_MIMO2,
|
||||
LQ_LEGACY_G, /* legacy types */
|
||||
LQ_LEGACY_A,
|
||||
LQ_HT_SISO, /* HT types */
|
||||
LQ_HT_MIMO2,
|
||||
LQ_VHT_SISO, /* VHT types */
|
||||
LQ_VHT_MIMO2,
|
||||
LQ_MAX,
|
||||
};
|
||||
|
||||
#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
|
||||
#define is_siso(tbl) ((tbl) == LQ_SISO)
|
||||
#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
|
||||
#define is_mimo(tbl) is_mimo2(tbl)
|
||||
#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
|
||||
#define is_a_band(tbl) ((tbl) == LQ_A)
|
||||
#define is_g_and(tbl) ((tbl) == LQ_G)
|
||||
#define is_legacy(tbl) (((tbl) == LQ_LEGACY_G) || ((tbl) == LQ_LEGACY_A))
|
||||
#define is_ht_siso(tbl) ((tbl) == LQ_HT_SISO)
|
||||
#define is_ht_mimo2(tbl) ((tbl) == LQ_HT_MIMO2)
|
||||
#define is_vht_siso(tbl) ((tbl) == LQ_VHT_SISO)
|
||||
#define is_vht_mimo2(tbl) ((tbl) == LQ_VHT_MIMO2)
|
||||
#define is_siso(tbl) (is_ht_siso(tbl) || is_vht_siso(tbl))
|
||||
#define is_mimo2(tbl) (is_ht_mimo2(tbl) || is_vht_mimo2(tbl))
|
||||
#define is_mimo(tbl) (is_mimo2(tbl))
|
||||
#define is_ht(tbl) (is_ht_siso(tbl) || is_ht_mimo2(tbl))
|
||||
#define is_vht(tbl) (is_vht_siso(tbl) || is_vht_mimo2(tbl))
|
||||
#define is_a_band(tbl) ((tbl) == LQ_LEGACY_A)
|
||||
#define is_g_band(tbl) ((tbl) == LQ_LEGACY_G)
|
||||
|
||||
#define is_ht20(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_20)
|
||||
#define is_ht40(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_40)
|
||||
#define is_ht80(tbl) (tbl->bw == RATE_MCS_CHAN_WIDTH_80)
|
||||
|
||||
#define IWL_MAX_MCS_DISPLAY_SIZE 12
|
||||
|
||||
|
@ -232,7 +270,7 @@ struct iwl_scale_tbl_info {
|
|||
enum iwl_table_type lq_type;
|
||||
u8 ant_type;
|
||||
u8 is_SGI; /* 1 = short guard interval */
|
||||
u8 is_ht40; /* 1 = 40 MHz channel width */
|
||||
u32 bw; /* channel bandwidth; RATE_MCS_CHAN_WIDTH_XX */
|
||||
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
|
||||
u8 max_search; /* maximun number of tables we can search */
|
||||
s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
|
||||
|
@ -262,7 +300,7 @@ struct iwl_lq_sta {
|
|||
u64 flush_timer; /* time staying in mode before new search */
|
||||
|
||||
u8 action_counter; /* # mode-switch actions tried */
|
||||
u8 is_green;
|
||||
bool is_vht;
|
||||
enum ieee80211_band band;
|
||||
|
||||
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
|
||||
|
|
|
@ -422,6 +422,27 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
|
|||
|
||||
mvmvif->bf_data.ave_beacon_signal = sig;
|
||||
|
||||
/* BT Coex */
|
||||
if (mvmvif->bf_data.bt_coex_min_thold !=
|
||||
mvmvif->bf_data.bt_coex_max_thold) {
|
||||
last_event = mvmvif->bf_data.last_bt_coex_event;
|
||||
if (sig > mvmvif->bf_data.bt_coex_max_thold &&
|
||||
(last_event <= mvmvif->bf_data.bt_coex_min_thold ||
|
||||
last_event == 0)) {
|
||||
mvmvif->bf_data.last_bt_coex_event = sig;
|
||||
IWL_DEBUG_RX(mvm, "cqm_iterator bt coex high %d\n",
|
||||
sig);
|
||||
iwl_mvm_bt_rssi_event(mvm, vif, RSSI_EVENT_HIGH);
|
||||
} else if (sig < mvmvif->bf_data.bt_coex_min_thold &&
|
||||
(last_event >= mvmvif->bf_data.bt_coex_max_thold ||
|
||||
last_event == 0)) {
|
||||
mvmvif->bf_data.last_bt_coex_event = sig;
|
||||
IWL_DEBUG_RX(mvm, "cqm_iterator bt coex low %d\n",
|
||||
sig);
|
||||
iwl_mvm_bt_rssi_event(mvm, vif, RSSI_EVENT_LOW);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI))
|
||||
return;
|
||||
|
||||
|
|
|
@ -74,8 +74,12 @@
|
|||
static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
|
||||
{
|
||||
u16 rx_chain;
|
||||
u8 rx_ant = iwl_fw_valid_rx_ant(mvm->fw);
|
||||
u8 rx_ant;
|
||||
|
||||
if (mvm->scan_rx_ant != ANT_NONE)
|
||||
rx_ant = mvm->scan_rx_ant;
|
||||
else
|
||||
rx_ant = iwl_fw_valid_rx_ant(mvm->fw);
|
||||
rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS;
|
||||
rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
|
||||
rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS;
|
||||
|
@ -133,11 +137,12 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
|
|||
* request.
|
||||
*/
|
||||
static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
|
||||
struct cfg80211_scan_request *req)
|
||||
struct cfg80211_scan_request *req,
|
||||
int first)
|
||||
{
|
||||
int fw_idx, req_idx;
|
||||
|
||||
for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx > 0;
|
||||
for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx >= first;
|
||||
req_idx--, fw_idx++) {
|
||||
cmd->direct_scan[fw_idx].id = WLAN_EID_SSID;
|
||||
cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len;
|
||||
|
@ -153,9 +158,9 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
|
|||
* just to notify that this scan is active and not passive.
|
||||
* In order to notify the FW of the number of SSIDs we wish to scan (including
|
||||
* the zero-length one), we need to set the corresponding bits in chan->type,
|
||||
* one for each SSID, and set the active bit (first). The first SSID is already
|
||||
* included in the probe template, so we need to set only req->n_ssids - 1 bits
|
||||
* in addition to the first bit.
|
||||
* one for each SSID, and set the active bit (first). If the first SSID is
|
||||
* already included in the probe template, so we need to set only
|
||||
* req->n_ssids - 1 bits in addition to the first bit.
|
||||
*/
|
||||
static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
|
||||
{
|
||||
|
@ -170,7 +175,8 @@ static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
|
|||
}
|
||||
|
||||
static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
|
||||
struct cfg80211_scan_request *req)
|
||||
struct cfg80211_scan_request *req,
|
||||
bool basic_ssid)
|
||||
{
|
||||
u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band);
|
||||
u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band,
|
||||
|
@ -178,10 +184,14 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
|
|||
struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
|
||||
(cmd->data + le16_to_cpu(cmd->tx_cmd.len));
|
||||
int i;
|
||||
int type = BIT(req->n_ssids) - 1;
|
||||
|
||||
if (!basic_ssid)
|
||||
type |= BIT(req->n_ssids);
|
||||
|
||||
for (i = 0; i < cmd->channel_count; i++) {
|
||||
chan->channel = cpu_to_le16(req->channels[i]->hw_value);
|
||||
chan->type = cpu_to_le32(BIT(req->n_ssids) - 1);
|
||||
chan->type = cpu_to_le32(type);
|
||||
if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
|
||||
chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
|
||||
chan->active_dwell = cpu_to_le16(active_dwell);
|
||||
|
@ -268,6 +278,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
|||
u32 status;
|
||||
int ssid_len = 0;
|
||||
u8 *ssid = NULL;
|
||||
bool basic_ssid = !(mvm->fw->ucode_capa.flags &
|
||||
IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID);
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
BUG_ON(mvm->scan_cmd == NULL);
|
||||
|
@ -302,14 +314,16 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
|||
if (req->n_ssids > 0) {
|
||||
cmd->passive2active = cpu_to_le16(1);
|
||||
cmd->scan_flags |= SCAN_FLAGS_PASSIVE2ACTIVE;
|
||||
ssid = req->ssids[0].ssid;
|
||||
ssid_len = req->ssids[0].ssid_len;
|
||||
if (basic_ssid) {
|
||||
ssid = req->ssids[0].ssid;
|
||||
ssid_len = req->ssids[0].ssid_len;
|
||||
}
|
||||
} else {
|
||||
cmd->passive2active = 0;
|
||||
cmd->scan_flags &= ~SCAN_FLAGS_PASSIVE2ACTIVE;
|
||||
}
|
||||
|
||||
iwl_mvm_scan_fill_ssids(cmd, req);
|
||||
iwl_mvm_scan_fill_ssids(cmd, req, basic_ssid ? 1 : 0);
|
||||
|
||||
cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL);
|
||||
cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id;
|
||||
|
@ -326,7 +340,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
|||
req->ie, req->ie_len,
|
||||
mvm->fw->ucode_capa.max_probe_length));
|
||||
|
||||
iwl_mvm_scan_fill_channels(cmd, req);
|
||||
iwl_mvm_scan_fill_channels(cmd, req, basic_ssid);
|
||||
|
||||
cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) +
|
||||
le16_to_cpu(cmd->tx_cmd.len) +
|
||||
|
@ -377,6 +391,21 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_cmd_buffer *rxb,
|
||||
struct iwl_device_cmd *cmd)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_sched_scan_results *notif = (void *)pkt->data;
|
||||
|
||||
if (notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN) {
|
||||
IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n");
|
||||
ieee80211_sched_scan_results(mvm->hw);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
|
||||
struct iwl_rx_packet *pkt, void *data)
|
||||
{
|
||||
|
@ -437,3 +466,406 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
|
|||
out_remove_notif:
|
||||
iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort);
|
||||
}
|
||||
|
||||
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_cmd_buffer *rxb,
|
||||
struct iwl_device_cmd *cmd)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_scan_offload_complete *scan_notif = (void *)pkt->data;
|
||||
|
||||
IWL_DEBUG_SCAN(mvm, "Scheduled scan completed, status %s\n",
|
||||
scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
|
||||
"completed" : "aborted");
|
||||
|
||||
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
||||
ieee80211_sched_scan_stopped(mvm->hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sched_scan_ies *ies,
|
||||
enum ieee80211_band band,
|
||||
struct iwl_tx_cmd *cmd,
|
||||
u8 *data)
|
||||
{
|
||||
u16 cmd_len;
|
||||
|
||||
cmd->tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL);
|
||||
cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
|
||||
cmd->sta_id = mvm->aux_sta.sta_id;
|
||||
|
||||
cmd->rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm, band, false);
|
||||
|
||||
cmd_len = iwl_mvm_fill_probe_req((struct ieee80211_mgmt *)data,
|
||||
vif->addr,
|
||||
1, NULL, 0,
|
||||
ies->ie[band], ies->len[band],
|
||||
SCAN_OFFLOAD_PROBE_REQ_SIZE);
|
||||
cmd->len = cpu_to_le16(cmd_len);
|
||||
}
|
||||
|
||||
static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct iwl_scan_offload_cmd *scan)
|
||||
{
|
||||
scan->channel_count =
|
||||
mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels +
|
||||
mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
|
||||
scan->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
|
||||
scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
|
||||
scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT;
|
||||
scan->rx_chain = iwl_mvm_scan_rx_chain(mvm);
|
||||
scan->max_out_time = cpu_to_le32(200 * 1024);
|
||||
scan->suspend_time = iwl_mvm_scan_suspend_time(vif);
|
||||
scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
|
||||
MAC_FILTER_IN_BEACON);
|
||||
scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND);
|
||||
scan->rep_count = cpu_to_le32(1);
|
||||
}
|
||||
|
||||
static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PROBE_OPTION_MAX; i++) {
|
||||
if (!ssid_list[i].len)
|
||||
break;
|
||||
if (ssid_list[i].len == ssid_len &&
|
||||
!memcmp(ssid_list->ssid, ssid, ssid_len))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
|
||||
struct iwl_scan_offload_cmd *scan,
|
||||
u32 *ssid_bitmap)
|
||||
{
|
||||
int i, j;
|
||||
int index;
|
||||
|
||||
/*
|
||||
* copy SSIDs from match list.
|
||||
* iwl_config_sched_scan_profiles() uses the order of these ssids to
|
||||
* config match list.
|
||||
*/
|
||||
for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
|
||||
scan->direct_scan[i].id = WLAN_EID_SSID;
|
||||
scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
|
||||
memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
|
||||
scan->direct_scan[i].len);
|
||||
}
|
||||
|
||||
/* add SSIDs from scan SSID list */
|
||||
*ssid_bitmap = 0;
|
||||
for (j = 0; j < req->n_ssids && i < PROBE_OPTION_MAX; j++) {
|
||||
index = iwl_ssid_exist(req->ssids[j].ssid,
|
||||
req->ssids[j].ssid_len,
|
||||
scan->direct_scan);
|
||||
if (index < 0) {
|
||||
if (!req->ssids[j].ssid_len)
|
||||
continue;
|
||||
scan->direct_scan[i].id = WLAN_EID_SSID;
|
||||
scan->direct_scan[i].len = req->ssids[j].ssid_len;
|
||||
memcpy(scan->direct_scan[i].ssid, req->ssids[j].ssid,
|
||||
scan->direct_scan[i].len);
|
||||
*ssid_bitmap |= BIT(i + 1);
|
||||
i++;
|
||||
} else {
|
||||
*ssid_bitmap |= BIT(index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct iwl_scan_channel_cfg *channels,
|
||||
enum ieee80211_band band,
|
||||
int *head, int *tail,
|
||||
u32 ssid_bitmap)
|
||||
{
|
||||
struct ieee80211_supported_band *s_band;
|
||||
int n_probes = req->n_ssids;
|
||||
int n_channels = req->n_channels;
|
||||
u8 active_dwell, passive_dwell;
|
||||
int i, j, index = 0;
|
||||
bool partial;
|
||||
|
||||
/*
|
||||
* We have to configure all supported channels, even if we don't want to
|
||||
* scan on them, but we have to send channels in the order that we want
|
||||
* to scan. So add requested channels to head of the list and others to
|
||||
* the end.
|
||||
*/
|
||||
active_dwell = iwl_mvm_get_active_dwell(band, n_probes);
|
||||
passive_dwell = iwl_mvm_get_passive_dwell(band);
|
||||
s_band = &mvm->nvm_data->bands[band];
|
||||
|
||||
for (i = 0; i < s_band->n_channels && *head <= *tail; i++) {
|
||||
partial = false;
|
||||
for (j = 0; j < n_channels; j++)
|
||||
if (s_band->channels[i].center_freq ==
|
||||
req->channels[j]->center_freq) {
|
||||
index = *head;
|
||||
(*head)++;
|
||||
/*
|
||||
* Channels that came with the request will be
|
||||
* in partial scan .
|
||||
*/
|
||||
partial = true;
|
||||
break;
|
||||
}
|
||||
if (!partial) {
|
||||
index = *tail;
|
||||
(*tail)--;
|
||||
}
|
||||
channels->channel_number[index] =
|
||||
cpu_to_le16(ieee80211_frequency_to_channel(
|
||||
s_band->channels[i].center_freq));
|
||||
channels->dwell_time[index][0] = active_dwell;
|
||||
channels->dwell_time[index][1] = passive_dwell;
|
||||
|
||||
channels->iter_count[index] = cpu_to_le16(1);
|
||||
channels->iter_interval[index] = 0;
|
||||
|
||||
if (!(s_band->channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
|
||||
channels->type[index] |=
|
||||
cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);
|
||||
|
||||
channels->type[index] |=
|
||||
cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL);
|
||||
if (partial)
|
||||
channels->type[index] |=
|
||||
cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL);
|
||||
|
||||
if (s_band->channels[i].flags & IEEE80211_CHAN_NO_HT40)
|
||||
channels->type[index] |=
|
||||
cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_NARROW);
|
||||
|
||||
/* scan for all SSIDs from req->ssids */
|
||||
channels->type[index] |= cpu_to_le32(ssid_bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_sched_scan_request *req,
|
||||
struct ieee80211_sched_scan_ies *ies)
|
||||
{
|
||||
int supported_bands = 0;
|
||||
int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;
|
||||
int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
|
||||
int head = 0;
|
||||
int tail = band_2ghz + band_5ghz;
|
||||
u32 ssid_bitmap;
|
||||
int cmd_len;
|
||||
int ret;
|
||||
|
||||
struct iwl_scan_offload_cfg *scan_cfg;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = SCAN_OFFLOAD_CONFIG_CMD,
|
||||
.flags = CMD_SYNC,
|
||||
};
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (band_2ghz)
|
||||
supported_bands++;
|
||||
if (band_5ghz)
|
||||
supported_bands++;
|
||||
|
||||
cmd_len = sizeof(struct iwl_scan_offload_cfg) +
|
||||
supported_bands * SCAN_OFFLOAD_PROBE_REQ_SIZE;
|
||||
|
||||
scan_cfg = kzalloc(cmd_len, GFP_KERNEL);
|
||||
if (!scan_cfg)
|
||||
return -ENOMEM;
|
||||
|
||||
iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd);
|
||||
scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len);
|
||||
|
||||
iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap);
|
||||
/* build tx frames for supported bands */
|
||||
if (band_2ghz) {
|
||||
iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
|
||||
IEEE80211_BAND_2GHZ,
|
||||
&scan_cfg->scan_cmd.tx_cmd[0],
|
||||
scan_cfg->data);
|
||||
iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
|
||||
IEEE80211_BAND_2GHZ, &head, &tail,
|
||||
ssid_bitmap);
|
||||
}
|
||||
if (band_5ghz) {
|
||||
iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
|
||||
IEEE80211_BAND_5GHZ,
|
||||
&scan_cfg->scan_cmd.tx_cmd[1],
|
||||
scan_cfg->data +
|
||||
SCAN_OFFLOAD_PROBE_REQ_SIZE);
|
||||
iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
|
||||
IEEE80211_BAND_5GHZ, &head, &tail,
|
||||
ssid_bitmap);
|
||||
}
|
||||
|
||||
cmd.data[0] = scan_cfg;
|
||||
cmd.len[0] = cmd_len;
|
||||
cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
|
||||
|
||||
IWL_DEBUG_SCAN(mvm, "Sending scheduled scan config\n");
|
||||
|
||||
ret = iwl_mvm_send_cmd(mvm, &cmd);
|
||||
kfree(scan_cfg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
|
||||
struct cfg80211_sched_scan_request *req)
|
||||
{
|
||||
struct iwl_scan_offload_profile *profile;
|
||||
struct iwl_scan_offload_profile_cfg *profile_cfg;
|
||||
struct iwl_scan_offload_blacklist *blacklist;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = SCAN_OFFLOAD_UPDATE_PROFILES_CMD,
|
||||
.flags = CMD_SYNC,
|
||||
.len[1] = sizeof(*profile_cfg),
|
||||
.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
|
||||
.dataflags[1] = IWL_HCMD_DFL_NOCOPY,
|
||||
};
|
||||
int blacklist_len;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(req->n_match_sets > IWL_SCAN_MAX_PROFILES))
|
||||
return -EIO;
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SHORT_BL)
|
||||
blacklist_len = IWL_SCAN_SHORT_BLACKLIST_LEN;
|
||||
else
|
||||
blacklist_len = IWL_SCAN_MAX_BLACKLIST_LEN;
|
||||
|
||||
blacklist = kzalloc(sizeof(*blacklist) * blacklist_len, GFP_KERNEL);
|
||||
if (!blacklist)
|
||||
return -ENOMEM;
|
||||
|
||||
profile_cfg = kzalloc(sizeof(*profile_cfg), GFP_KERNEL);
|
||||
if (!profile_cfg) {
|
||||
ret = -ENOMEM;
|
||||
goto free_blacklist;
|
||||
}
|
||||
|
||||
cmd.data[0] = blacklist;
|
||||
cmd.len[0] = sizeof(*blacklist) * blacklist_len;
|
||||
cmd.data[1] = profile_cfg;
|
||||
|
||||
/* No blacklist configuration */
|
||||
|
||||
profile_cfg->num_profiles = req->n_match_sets;
|
||||
profile_cfg->active_clients = SCAN_CLIENT_SCHED_SCAN;
|
||||
profile_cfg->pass_match = SCAN_CLIENT_SCHED_SCAN;
|
||||
profile_cfg->match_notify = SCAN_CLIENT_SCHED_SCAN;
|
||||
|
||||
for (i = 0; i < req->n_match_sets; i++) {
|
||||
profile = &profile_cfg->profiles[i];
|
||||
profile->ssid_index = i;
|
||||
/* Support any cipher and auth algorithm */
|
||||
profile->unicast_cipher = 0xff;
|
||||
profile->auth_alg = 0xff;
|
||||
profile->network_type = IWL_NETWORK_TYPE_ANY;
|
||||
profile->band_selection = IWL_SCAN_OFFLOAD_SELECT_ANY;
|
||||
profile->client_bitmap = SCAN_CLIENT_SCHED_SCAN;
|
||||
}
|
||||
|
||||
IWL_DEBUG_SCAN(mvm, "Sending scheduled scan profile config\n");
|
||||
|
||||
ret = iwl_mvm_send_cmd(mvm, &cmd);
|
||||
kfree(profile_cfg);
|
||||
free_blacklist:
|
||||
kfree(blacklist);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
||||
struct cfg80211_sched_scan_request *req)
|
||||
{
|
||||
struct iwl_scan_offload_req scan_req = {
|
||||
.watchdog = IWL_SCHED_SCAN_WATCHDOG,
|
||||
|
||||
.schedule_line[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS,
|
||||
.schedule_line[0].delay = req->interval / 1000,
|
||||
.schedule_line[0].full_scan_mul = 1,
|
||||
|
||||
.schedule_line[1].iterations = 0xff,
|
||||
.schedule_line[1].delay = req->interval / 1000,
|
||||
.schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER,
|
||||
};
|
||||
|
||||
if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) {
|
||||
IWL_DEBUG_SCAN(mvm,
|
||||
"Sending scheduled scan with filtering, filter len %d\n",
|
||||
req->n_match_sets);
|
||||
scan_req.flags |=
|
||||
cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID);
|
||||
} else {
|
||||
IWL_DEBUG_SCAN(mvm,
|
||||
"Sending Scheduled scan without filtering\n");
|
||||
}
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, SCAN_OFFLOAD_REQUEST_CMD, CMD_SYNC,
|
||||
sizeof(scan_req), &scan_req);
|
||||
}
|
||||
|
||||
static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm)
|
||||
{
|
||||
int ret;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = SCAN_OFFLOAD_ABORT_CMD,
|
||||
.flags = CMD_SYNC,
|
||||
};
|
||||
u32 status;
|
||||
|
||||
/* Exit instantly with error when device is not ready
|
||||
* to receive scan abort command or it does not perform
|
||||
* scheduled scan currently */
|
||||
if (mvm->scan_status != IWL_MVM_SCAN_SCHED)
|
||||
return -EIO;
|
||||
|
||||
ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (status != CAN_ABORT_STATUS) {
|
||||
/*
|
||||
* The scan abort will return 1 for success or
|
||||
* 2 for "failure". A failure condition can be
|
||||
* due to simply not being in an active scan which
|
||||
* can occur if we send the scan abort before the
|
||||
* microcode has notified us that a scan is completed.
|
||||
*/
|
||||
IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (mvm->scan_status != IWL_MVM_SCAN_SCHED) {
|
||||
IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = iwl_mvm_send_sched_scan_abort(mvm);
|
||||
if (ret)
|
||||
IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret);
|
||||
else
|
||||
IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n");
|
||||
}
|
||||
|
|
|
@ -66,6 +66,115 @@
|
|||
#include "sta.h"
|
||||
#include "rs.h"
|
||||
|
||||
static void iwl_mvm_add_sta_cmd_v6_to_v5(struct iwl_mvm_add_sta_cmd_v6 *cmd_v6,
|
||||
struct iwl_mvm_add_sta_cmd_v5 *cmd_v5)
|
||||
{
|
||||
memset(cmd_v5, 0, sizeof(*cmd_v5));
|
||||
|
||||
cmd_v5->add_modify = cmd_v6->add_modify;
|
||||
cmd_v5->tid_disable_tx = cmd_v6->tid_disable_tx;
|
||||
cmd_v5->mac_id_n_color = cmd_v6->mac_id_n_color;
|
||||
memcpy(cmd_v5->addr, cmd_v6->addr, ETH_ALEN);
|
||||
cmd_v5->sta_id = cmd_v6->sta_id;
|
||||
cmd_v5->modify_mask = cmd_v6->modify_mask;
|
||||
cmd_v5->station_flags = cmd_v6->station_flags;
|
||||
cmd_v5->station_flags_msk = cmd_v6->station_flags_msk;
|
||||
cmd_v5->add_immediate_ba_tid = cmd_v6->add_immediate_ba_tid;
|
||||
cmd_v5->remove_immediate_ba_tid = cmd_v6->remove_immediate_ba_tid;
|
||||
cmd_v5->add_immediate_ba_ssn = cmd_v6->add_immediate_ba_ssn;
|
||||
cmd_v5->sleep_tx_count = cmd_v6->sleep_tx_count;
|
||||
cmd_v5->sleep_state_flags = cmd_v6->sleep_state_flags;
|
||||
cmd_v5->assoc_id = cmd_v6->assoc_id;
|
||||
cmd_v5->beamform_flags = cmd_v6->beamform_flags;
|
||||
cmd_v5->tfd_queue_msk = cmd_v6->tfd_queue_msk;
|
||||
}
|
||||
|
||||
static void
|
||||
iwl_mvm_add_sta_key_to_add_sta_cmd_v5(struct iwl_mvm_add_sta_key_cmd *key_cmd,
|
||||
struct iwl_mvm_add_sta_cmd_v5 *sta_cmd,
|
||||
u32 mac_id_n_color)
|
||||
{
|
||||
memset(sta_cmd, 0, sizeof(*sta_cmd));
|
||||
|
||||
sta_cmd->sta_id = key_cmd->sta_id;
|
||||
sta_cmd->add_modify = STA_MODE_MODIFY;
|
||||
sta_cmd->modify_mask = STA_MODIFY_KEY;
|
||||
sta_cmd->mac_id_n_color = cpu_to_le32(mac_id_n_color);
|
||||
|
||||
sta_cmd->key.key_offset = key_cmd->key_offset;
|
||||
sta_cmd->key.key_flags = key_cmd->key_flags;
|
||||
memcpy(sta_cmd->key.key, key_cmd->key, sizeof(sta_cmd->key.key));
|
||||
sta_cmd->key.tkip_rx_tsc_byte2 = key_cmd->tkip_rx_tsc_byte2;
|
||||
memcpy(sta_cmd->key.tkip_rx_ttak, key_cmd->tkip_rx_ttak,
|
||||
sizeof(sta_cmd->key.tkip_rx_ttak));
|
||||
}
|
||||
|
||||
static int iwl_mvm_send_add_sta_cmd_status(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_add_sta_cmd_v6 *cmd,
|
||||
int *status)
|
||||
{
|
||||
struct iwl_mvm_add_sta_cmd_v5 cmd_v5;
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD)
|
||||
return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(*cmd),
|
||||
cmd, status);
|
||||
|
||||
iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5);
|
||||
|
||||
return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd_v5),
|
||||
&cmd_v5, status);
|
||||
}
|
||||
|
||||
static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags,
|
||||
struct iwl_mvm_add_sta_cmd_v6 *cmd)
|
||||
{
|
||||
struct iwl_mvm_add_sta_cmd_v5 cmd_v5;
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD)
|
||||
return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags,
|
||||
sizeof(*cmd), cmd);
|
||||
|
||||
iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5);
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5),
|
||||
&cmd_v5);
|
||||
}
|
||||
|
||||
static int
|
||||
iwl_mvm_send_add_sta_key_cmd_status(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_add_sta_key_cmd *cmd,
|
||||
u32 mac_id_n_color,
|
||||
int *status)
|
||||
{
|
||||
struct iwl_mvm_add_sta_cmd_v5 sta_cmd;
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD)
|
||||
return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY,
|
||||
sizeof(*cmd), cmd, status);
|
||||
|
||||
iwl_mvm_add_sta_key_to_add_sta_cmd_v5(cmd, &sta_cmd, mac_id_n_color);
|
||||
|
||||
return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(sta_cmd),
|
||||
&sta_cmd, status);
|
||||
}
|
||||
|
||||
static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm,
|
||||
u32 flags,
|
||||
struct iwl_mvm_add_sta_key_cmd *cmd,
|
||||
u32 mac_id_n_color)
|
||||
{
|
||||
struct iwl_mvm_add_sta_cmd_v5 sta_cmd;
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD)
|
||||
return iwl_mvm_send_cmd_pdu(mvm, ADD_STA_KEY, flags,
|
||||
sizeof(*cmd), cmd);
|
||||
|
||||
iwl_mvm_add_sta_key_to_add_sta_cmd_v5(cmd, &sta_cmd, mac_id_n_color);
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(sta_cmd),
|
||||
&sta_cmd);
|
||||
}
|
||||
|
||||
static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm)
|
||||
{
|
||||
int sta_id;
|
||||
|
@ -87,7 +196,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
bool update)
|
||||
{
|
||||
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
|
||||
struct iwl_mvm_add_sta_cmd add_sta_cmd;
|
||||
struct iwl_mvm_add_sta_cmd_v6 add_sta_cmd;
|
||||
int ret;
|
||||
u32 status;
|
||||
u32 agg_size = 0, mpdu_dens = 0;
|
||||
|
@ -175,8 +284,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT);
|
||||
|
||||
status = ADD_STA_SUCCESS;
|
||||
ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd),
|
||||
&add_sta_cmd, &status);
|
||||
ret = iwl_mvm_send_add_sta_cmd_status(mvm, &add_sta_cmd, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -229,8 +337,12 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
|
|||
if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE)
|
||||
mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]);
|
||||
|
||||
/* for HW restart - need to reset the seq_number etc... */
|
||||
memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data));
|
||||
/* for HW restart - reset everything but the sequence number */
|
||||
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
|
||||
u16 seq = mvm_sta->tid_data[i].seq_number;
|
||||
memset(&mvm_sta->tid_data[i], 0, sizeof(mvm_sta->tid_data[i]));
|
||||
mvm_sta->tid_data[i].seq_number = seq;
|
||||
}
|
||||
|
||||
ret = iwl_mvm_sta_send_to_fw(mvm, sta, false);
|
||||
if (ret)
|
||||
|
@ -256,7 +368,7 @@ int iwl_mvm_update_sta(struct iwl_mvm *mvm,
|
|||
int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
|
||||
bool drain)
|
||||
{
|
||||
struct iwl_mvm_add_sta_cmd cmd = {};
|
||||
struct iwl_mvm_add_sta_cmd_v6 cmd = {};
|
||||
int ret;
|
||||
u32 status;
|
||||
|
||||
|
@ -269,8 +381,7 @@ int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
|
|||
cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW);
|
||||
|
||||
status = ADD_STA_SUCCESS;
|
||||
ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
|
||||
&cmd, &status);
|
||||
ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -469,13 +580,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
|
|||
const u8 *addr,
|
||||
u16 mac_id, u16 color)
|
||||
{
|
||||
struct iwl_mvm_add_sta_cmd cmd;
|
||||
struct iwl_mvm_add_sta_cmd_v6 cmd;
|
||||
int ret;
|
||||
u32 status;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd));
|
||||
memset(&cmd, 0, sizeof(struct iwl_mvm_add_sta_cmd_v6));
|
||||
cmd.sta_id = sta->sta_id;
|
||||
cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id,
|
||||
color));
|
||||
|
@ -485,8 +596,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
|
|||
if (addr)
|
||||
memcpy(cmd.addr, addr, ETH_ALEN);
|
||||
|
||||
ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
|
||||
&cmd, &status);
|
||||
ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -534,10 +644,14 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
struct iwl_mvm_int_sta *bsta)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
static const u8 *baddr = _baddr;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_ADHOC)
|
||||
baddr = vif->bss_conf.bssid;
|
||||
|
||||
if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_STATION_COUNT))
|
||||
return -ENOSPC;
|
||||
|
||||
|
@ -614,7 +728,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
int tid, u16 ssn, bool start)
|
||||
{
|
||||
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
|
||||
struct iwl_mvm_add_sta_cmd cmd = {};
|
||||
struct iwl_mvm_add_sta_cmd_v6 cmd = {};
|
||||
int ret;
|
||||
u32 status;
|
||||
|
||||
|
@ -638,8 +752,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
STA_MODIFY_REMOVE_BA_TID;
|
||||
|
||||
status = ADD_STA_SUCCESS;
|
||||
ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
|
||||
&cmd, &status);
|
||||
ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -674,7 +787,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
int tid, u8 queue, bool start)
|
||||
{
|
||||
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
|
||||
struct iwl_mvm_add_sta_cmd cmd = {};
|
||||
struct iwl_mvm_add_sta_cmd_v6 cmd = {};
|
||||
int ret;
|
||||
u32 status;
|
||||
|
||||
|
@ -696,8 +809,7 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg);
|
||||
|
||||
status = ADD_STA_SUCCESS;
|
||||
ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
|
||||
&cmd, &status);
|
||||
ret = iwl_mvm_send_add_sta_cmd_status(mvm, &cmd, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -743,13 +855,13 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
for (txq_id = IWL_MVM_FIRST_AGG_QUEUE;
|
||||
txq_id <= IWL_MVM_LAST_AGG_QUEUE; txq_id++)
|
||||
for (txq_id = mvm->first_agg_queue;
|
||||
txq_id <= mvm->last_agg_queue; txq_id++)
|
||||
if (mvm->queue_to_mac80211[txq_id] ==
|
||||
IWL_INVALID_MAC80211_QUEUE)
|
||||
break;
|
||||
|
||||
if (txq_id > IWL_MVM_LAST_AGG_QUEUE) {
|
||||
if (txq_id > mvm->last_agg_queue) {
|
||||
IWL_ERR(mvm, "Failed to allocate agg queue\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -987,10 +1099,11 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
|
|||
u32 cmd_flags)
|
||||
{
|
||||
__le16 key_flags;
|
||||
struct iwl_mvm_add_sta_cmd cmd = {};
|
||||
struct iwl_mvm_add_sta_key_cmd cmd = {};
|
||||
int ret, status;
|
||||
u16 keyidx;
|
||||
int i;
|
||||
u32 mac_id_n_color = mvm_sta->mac_id_n_color;
|
||||
|
||||
keyidx = (keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
|
||||
STA_KEY_FLG_KEYID_MSK;
|
||||
|
@ -1000,14 +1113,14 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
|
|||
switch (keyconf->cipher) {
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
key_flags |= cpu_to_le16(STA_KEY_FLG_TKIP);
|
||||
cmd.key.tkip_rx_tsc_byte2 = tkip_iv32;
|
||||
cmd.tkip_rx_tsc_byte2 = tkip_iv32;
|
||||
for (i = 0; i < 5; i++)
|
||||
cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]);
|
||||
memcpy(cmd.key.key, keyconf->key, keyconf->keylen);
|
||||
cmd.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]);
|
||||
memcpy(cmd.key, keyconf->key, keyconf->keylen);
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
key_flags |= cpu_to_le16(STA_KEY_FLG_CCM);
|
||||
memcpy(cmd.key.key, keyconf->key, keyconf->keylen);
|
||||
memcpy(cmd.key, keyconf->key, keyconf->keylen);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
|
@ -1017,20 +1130,18 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
|
|||
if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
|
||||
key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
|
||||
|
||||
cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
|
||||
cmd.key.key_offset = keyconf->hw_key_idx;
|
||||
cmd.key.key_flags = key_flags;
|
||||
cmd.add_modify = STA_MODE_MODIFY;
|
||||
cmd.modify_mask = STA_MODIFY_KEY;
|
||||
cmd.key_offset = keyconf->hw_key_idx;
|
||||
cmd.key_flags = key_flags;
|
||||
cmd.sta_id = sta_id;
|
||||
|
||||
status = ADD_STA_SUCCESS;
|
||||
if (cmd_flags == CMD_SYNC)
|
||||
ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
|
||||
&cmd, &status);
|
||||
ret = iwl_mvm_send_add_sta_key_cmd_status(mvm, &cmd,
|
||||
mac_id_n_color,
|
||||
&status);
|
||||
else
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
|
||||
sizeof(cmd), &cmd);
|
||||
ret = iwl_mvm_send_add_sta_key_cmd(mvm, CMD_ASYNC, &cmd,
|
||||
mac_id_n_color);
|
||||
|
||||
switch (status) {
|
||||
case ADD_STA_SUCCESS:
|
||||
|
@ -1197,7 +1308,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
|
|||
struct ieee80211_key_conf *keyconf)
|
||||
{
|
||||
struct iwl_mvm_sta *mvm_sta;
|
||||
struct iwl_mvm_add_sta_cmd cmd = {};
|
||||
struct iwl_mvm_add_sta_key_cmd cmd = {};
|
||||
__le16 key_flags;
|
||||
int ret, status;
|
||||
u8 sta_id;
|
||||
|
@ -1252,17 +1363,14 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
|
|||
if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
|
||||
key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
|
||||
|
||||
cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
|
||||
cmd.key.key_flags = key_flags;
|
||||
cmd.key.key_offset = keyconf->hw_key_idx;
|
||||
cmd.key_flags = key_flags;
|
||||
cmd.key_offset = keyconf->hw_key_idx;
|
||||
cmd.sta_id = sta_id;
|
||||
|
||||
cmd.modify_mask = STA_MODIFY_KEY;
|
||||
cmd.add_modify = STA_MODE_MODIFY;
|
||||
|
||||
status = ADD_STA_SUCCESS;
|
||||
ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
|
||||
&cmd, &status);
|
||||
ret = iwl_mvm_send_add_sta_key_cmd_status(mvm, &cmd,
|
||||
mvm_sta->mac_id_n_color,
|
||||
&status);
|
||||
|
||||
switch (status) {
|
||||
case ADD_STA_SUCCESS:
|
||||
|
@ -1309,7 +1417,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
|
|||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
|
||||
struct iwl_mvm_add_sta_cmd cmd = {
|
||||
struct iwl_mvm_add_sta_cmd_v6 cmd = {
|
||||
.add_modify = STA_MODE_MODIFY,
|
||||
.sta_id = mvmsta->sta_id,
|
||||
.station_flags_msk = cpu_to_le32(STA_FLG_PS),
|
||||
|
@ -1317,7 +1425,7 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
|
|||
};
|
||||
int ret;
|
||||
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
|
||||
ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
|
||||
}
|
||||
|
@ -1331,7 +1439,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
|
|||
(reason == IEEE80211_FRAME_RELEASE_UAPSD) ?
|
||||
STA_SLEEP_STATE_UAPSD : STA_SLEEP_STATE_PS_POLL;
|
||||
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
|
||||
struct iwl_mvm_add_sta_cmd cmd = {
|
||||
struct iwl_mvm_add_sta_cmd_v6 cmd = {
|
||||
.add_modify = STA_MODE_MODIFY,
|
||||
.sta_id = mvmsta->sta_id,
|
||||
.modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
|
||||
|
@ -1346,7 +1454,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
|
|||
int ret;
|
||||
|
||||
/* TODO: somehow the fw doesn't seem to take PS_POLL into account */
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
|
||||
ret = iwl_mvm_send_add_sta_cmd(mvm, CMD_ASYNC, &cmd);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
|
||||
}
|
||||
|
|
|
@ -293,10 +293,6 @@ struct iwl_mvm_sta {
|
|||
struct iwl_lq_sta lq_sta;
|
||||
struct ieee80211_vif *vif;
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
u16 last_seq_ctl;
|
||||
#endif
|
||||
|
||||
/* Temporary, until the new TLC will control the Tx protection */
|
||||
s8 tx_protection;
|
||||
bool tt_tx_protection;
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2013 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||
* USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called COPYING.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Linux Wireless <ilw@linux.intel.com>
|
||||
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2013 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __IWL_MVM_TESTMODE_H__
|
||||
#define __IWL_MVM_TESTMODE_H__
|
||||
|
||||
/**
|
||||
* enum iwl_mvm_testmode_attrs - testmode attributes inside NL80211_ATTR_TESTDATA
|
||||
* @IWL_MVM_TM_ATTR_UNSPEC: (invalid attribute)
|
||||
* @IWL_MVM_TM_ATTR_CMD: sub command, see &enum iwl_mvm_testmode_commands (u32)
|
||||
* @IWL_MVM_TM_ATTR_NOA_DURATION: requested NoA duration (u32)
|
||||
* @IWL_MVM_TM_ATTR_BEACON_FILTER_STATE: beacon filter state (0 or 1, u32)
|
||||
*/
|
||||
enum iwl_mvm_testmode_attrs {
|
||||
IWL_MVM_TM_ATTR_UNSPEC,
|
||||
IWL_MVM_TM_ATTR_CMD,
|
||||
IWL_MVM_TM_ATTR_NOA_DURATION,
|
||||
IWL_MVM_TM_ATTR_BEACON_FILTER_STATE,
|
||||
|
||||
/* keep last */
|
||||
NUM_IWL_MVM_TM_ATTRS,
|
||||
IWL_MVM_TM_ATTR_MAX = NUM_IWL_MVM_TM_ATTRS - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_mvm_testmode_commands - MVM testmode commands
|
||||
* @IWL_MVM_TM_CMD_SET_NOA: set NoA on GO vif for testing
|
||||
* @IWL_MVM_TM_CMD_SET_BEACON_FILTER: turn beacon filtering off/on
|
||||
*/
|
||||
enum iwl_mvm_testmode_commands {
|
||||
IWL_MVM_TM_CMD_SET_NOA,
|
||||
IWL_MVM_TM_CMD_SET_BEACON_FILTER,
|
||||
};
|
||||
|
||||
#endif /* __IWL_MVM_TESTMODE_H__ */
|
|
@ -387,7 +387,8 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
|
|||
|
||||
void iwl_mvm_protect_session(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
u32 duration, u32 min_duration)
|
||||
u32 duration, u32 min_duration,
|
||||
u32 max_delay)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
|
||||
|
@ -426,7 +427,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
|
|||
cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG));
|
||||
|
||||
time_cmd.max_frags = TE_V2_FRAG_NONE;
|
||||
time_cmd.max_delay = cpu_to_le32(500);
|
||||
time_cmd.max_delay = cpu_to_le32(max_delay);
|
||||
/* TODO: why do we need to interval = bi if it is not periodic? */
|
||||
time_cmd.interval = cpu_to_le32(1);
|
||||
time_cmd.duration = cpu_to_le32(duration);
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
* @duration: the duration of the session in TU.
|
||||
* @min_duration: will start a new session if the current session will end
|
||||
* in less than min_duration.
|
||||
* @max_delay: maximum delay before starting the time event (in TU)
|
||||
*
|
||||
* This function can be used to start a session protection which means that the
|
||||
* fw will stay on the channel for %duration_ms milliseconds. This function
|
||||
|
@ -133,7 +134,8 @@
|
|||
*/
|
||||
void iwl_mvm_protect_session(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
u32 duration, u32 min_duration);
|
||||
u32 duration, u32 min_duration,
|
||||
u32 max_delay);
|
||||
|
||||
/**
|
||||
* iwl_mvm_stop_session_protection - cancel the session protection.
|
||||
|
|
|
@ -417,7 +417,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
|
||||
spin_unlock(&mvmsta->lock);
|
||||
|
||||
if (txq_id < IWL_MVM_FIRST_AGG_QUEUE)
|
||||
if (txq_id < mvm->first_agg_queue)
|
||||
atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
|
||||
|
||||
return 0;
|
||||
|
@ -511,16 +511,10 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status)
|
|||
}
|
||||
#endif /* CONFIG_IWLWIFI_DEBUG */
|
||||
|
||||
/**
|
||||
* translate ucode response to mac80211 tx status control values
|
||||
*/
|
||||
static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags,
|
||||
struct ieee80211_tx_info *info)
|
||||
void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
|
||||
enum ieee80211_band band,
|
||||
struct ieee80211_tx_rate *r)
|
||||
{
|
||||
struct ieee80211_tx_rate *r = &info->status.rates[0];
|
||||
|
||||
info->status.antenna =
|
||||
((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
|
||||
if (rate_n_flags & RATE_HT_MCS_GF_MSK)
|
||||
r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
|
||||
switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
|
||||
|
@ -549,10 +543,23 @@ static void iwl_mvm_hwrate_to_tx_control(u32 rate_n_flags,
|
|||
r->flags |= IEEE80211_TX_RC_VHT_MCS;
|
||||
} else {
|
||||
r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
|
||||
info->band);
|
||||
band);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* translate ucode response to mac80211 tx status control values
|
||||
*/
|
||||
static void iwl_mvm_hwrate_to_tx_status(u32 rate_n_flags,
|
||||
struct ieee80211_tx_info *info)
|
||||
{
|
||||
struct ieee80211_tx_rate *r = &info->status.rates[0];
|
||||
|
||||
info->status.antenna =
|
||||
((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
|
||||
iwl_mvm_hwrate_to_tx_rate(rate_n_flags, info->band, r);
|
||||
}
|
||||
|
||||
static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
|
@ -602,11 +609,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
info->status.rates[0].count = tx_resp->failure_frame + 1;
|
||||
iwl_mvm_hwrate_to_tx_control(le32_to_cpu(tx_resp->initial_rate),
|
||||
info);
|
||||
iwl_mvm_hwrate_to_tx_status(le32_to_cpu(tx_resp->initial_rate),
|
||||
info);
|
||||
|
||||
/* Single frame failure in an AMPDU queue => send BAR */
|
||||
if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE &&
|
||||
if (txq_id >= mvm->first_agg_queue &&
|
||||
!(info->flags & IEEE80211_TX_STAT_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
|
||||
|
||||
|
@ -619,7 +626,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
ieee80211_tx_status_ni(mvm->hw, skb);
|
||||
}
|
||||
|
||||
if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE) {
|
||||
if (txq_id >= mvm->first_agg_queue) {
|
||||
/* If this is an aggregation queue, we use the ssn since:
|
||||
* ssn = wifi seq_num % 256.
|
||||
* The seq_ctl is the sequence control of the packet to which
|
||||
|
@ -668,10 +675,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
iwl_mvm_check_ratid_empty(mvm, sta, tid);
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
mvmsta->last_seq_ctl = seq_ctl;
|
||||
#endif
|
||||
} else {
|
||||
sta = NULL;
|
||||
mvmsta = NULL;
|
||||
|
@ -681,7 +684,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
* If the txq is not an AMPDU queue, there is no chance we freed
|
||||
* several skbs. Check that out...
|
||||
*/
|
||||
if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && !WARN_ON(skb_freed > 1) &&
|
||||
if (txq_id < mvm->first_agg_queue && !WARN_ON(skb_freed > 1) &&
|
||||
atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) {
|
||||
if (mvmsta) {
|
||||
/*
|
||||
|
@ -777,7 +780,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
|
|||
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
|
||||
struct ieee80211_sta *sta;
|
||||
|
||||
if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_MVM_FIRST_AGG_QUEUE))
|
||||
if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < mvm->first_agg_queue))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS))
|
||||
|
@ -904,8 +907,8 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
|
|||
info->flags |= IEEE80211_TX_STAT_AMPDU;
|
||||
info->status.ampdu_ack_len = ba_notif->txed_2_done;
|
||||
info->status.ampdu_len = ba_notif->txed;
|
||||
iwl_mvm_hwrate_to_tx_control(tid_data->rate_n_flags,
|
||||
info);
|
||||
iwl_mvm_hwrate_to_tx_status(tid_data->rate_n_flags,
|
||||
info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -466,7 +466,7 @@ void iwl_mvm_dump_sram(struct iwl_mvm *mvm)
|
|||
ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
|
||||
len = img->sec[IWL_UCODE_SECTION_DATA].len;
|
||||
|
||||
buf = kzalloc(len, GFP_KERNEL);
|
||||
buf = kzalloc(len, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
|
|
|
@ -258,7 +258,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
|
|||
#endif /* CONFIG_IWLDVM */
|
||||
|
||||
#if IS_ENABLED(CONFIG_IWLMVM)
|
||||
/* 7000 Series */
|
||||
/* 7260 Series */
|
||||
{IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x08B1, 0x4170, iwl7260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x08B1, 0x4060, iwl7260_2n_cfg)},
|
||||
|
@ -308,6 +308,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
|
|||
{IWL_PCI_DEVICE(0x08B3, 0x8062, iwl3160_n_cfg)},
|
||||
{IWL_PCI_DEVICE(0x08B4, 0x8270, iwl3160_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x08B3, 0x8470, iwl3160_2ac_cfg)},
|
||||
|
||||
/* 7265 Series */
|
||||
{IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
{0}
|
||||
|
@ -349,7 +352,6 @@ out_free_drv:
|
|||
iwl_drv_stop(trans_pcie->drv);
|
||||
out_free_trans:
|
||||
iwl_trans_pcie_free(iwl_trans);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -360,8 +362,6 @@ static void iwl_pci_remove(struct pci_dev *pdev)
|
|||
|
||||
iwl_drv_stop(trans_pcie->drv);
|
||||
iwl_trans_pcie_free(trans);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
|
@ -220,6 +220,9 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
|
|||
iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
|
||||
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
|
||||
|
||||
/* Clear the interrupt in APMG if the NIC is in RFKILL */
|
||||
iwl_write_prph(trans, APMG_RTC_INT_STT_REG, APMG_RTC_INT_STT_RFKILL);
|
||||
|
||||
set_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
|
||||
|
||||
out:
|
||||
|
@ -443,22 +446,138 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_pcie_secure_set(struct iwl_trans *trans, int cpu)
|
||||
{
|
||||
int shift_param;
|
||||
u32 address;
|
||||
int ret = 0;
|
||||
|
||||
if (cpu == 1) {
|
||||
shift_param = 0;
|
||||
address = CSR_SECURE_BOOT_CPU1_STATUS_ADDR;
|
||||
} else {
|
||||
shift_param = 16;
|
||||
address = CSR_SECURE_BOOT_CPU2_STATUS_ADDR;
|
||||
}
|
||||
|
||||
/* set CPU to started */
|
||||
iwl_trans_set_bits_mask(trans,
|
||||
CSR_UCODE_LOAD_STATUS_ADDR,
|
||||
CSR_CPU_STATUS_LOADING_STARTED << shift_param,
|
||||
1);
|
||||
|
||||
/* set last complete descriptor number */
|
||||
iwl_trans_set_bits_mask(trans,
|
||||
CSR_UCODE_LOAD_STATUS_ADDR,
|
||||
CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED
|
||||
<< shift_param,
|
||||
1);
|
||||
|
||||
/* set last loaded block */
|
||||
iwl_trans_set_bits_mask(trans,
|
||||
CSR_UCODE_LOAD_STATUS_ADDR,
|
||||
CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK
|
||||
<< shift_param,
|
||||
1);
|
||||
|
||||
/* image loading complete */
|
||||
iwl_trans_set_bits_mask(trans,
|
||||
CSR_UCODE_LOAD_STATUS_ADDR,
|
||||
CSR_CPU_STATUS_LOADING_COMPLETED
|
||||
<< shift_param,
|
||||
1);
|
||||
|
||||
/* set FH_TCSR_0_REG */
|
||||
iwl_trans_set_bits_mask(trans, FH_TCSR_0_REG0, 0x00400000, 1);
|
||||
|
||||
/* verify image verification started */
|
||||
ret = iwl_poll_bit(trans, address,
|
||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS,
|
||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS,
|
||||
CSR_SECURE_TIME_OUT);
|
||||
if (ret < 0) {
|
||||
IWL_ERR(trans, "secure boot process didn't start\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* wait for image verification to complete */
|
||||
ret = iwl_poll_bit(trans, address,
|
||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
|
||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
|
||||
CSR_SECURE_TIME_OUT);
|
||||
|
||||
if (ret < 0) {
|
||||
IWL_ERR(trans, "Time out on secure boot process\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
|
||||
const struct fw_img *image)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) {
|
||||
IWL_DEBUG_FW(trans,
|
||||
"working with %s image\n",
|
||||
image->is_secure ? "Secured" : "Non Secured");
|
||||
IWL_DEBUG_FW(trans,
|
||||
"working with %s CPU\n",
|
||||
image->is_dual_cpus ? "Dual" : "Single");
|
||||
|
||||
/* configure the ucode to be ready to get the secured image */
|
||||
if (image->is_secure) {
|
||||
/* set secure boot inspector addresses */
|
||||
iwl_write32(trans, CSR_SECURE_INSPECTOR_CODE_ADDR, 0);
|
||||
iwl_write32(trans, CSR_SECURE_INSPECTOR_DATA_ADDR, 0);
|
||||
|
||||
/* release CPU1 reset if secure inspector image burned in OTP */
|
||||
iwl_write32(trans, CSR_RESET, 0);
|
||||
}
|
||||
|
||||
/* load to FW the binary sections of CPU1 */
|
||||
IWL_DEBUG_INFO(trans, "Loading CPU1\n");
|
||||
for (i = 0;
|
||||
i < IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU;
|
||||
i++) {
|
||||
if (!image->sec[i].data)
|
||||
break;
|
||||
|
||||
ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Remove all resets to allow NIC to operate */
|
||||
iwl_write32(trans, CSR_RESET, 0);
|
||||
/* configure the ucode to start secure process on CPU1 */
|
||||
if (image->is_secure) {
|
||||
/* config CPU1 to start secure protocol */
|
||||
ret = iwl_pcie_secure_set(trans, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* Remove all resets to allow NIC to operate */
|
||||
iwl_write32(trans, CSR_RESET, 0);
|
||||
}
|
||||
|
||||
if (image->is_dual_cpus) {
|
||||
/* load to FW the binary sections of CPU2 */
|
||||
IWL_DEBUG_INFO(trans, "working w/ DUAL CPUs - Loading CPU2\n");
|
||||
for (i = IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU;
|
||||
i < IWL_UCODE_SECTION_MAX; i++) {
|
||||
if (!image->sec[i].data)
|
||||
break;
|
||||
ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (image->is_secure) {
|
||||
/* set CPU2 for secure protocol */
|
||||
ret = iwl_pcie_secure_set(trans, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1539,6 +1539,9 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
|
|||
"Clearing HCMD_ACTIVE for command %s\n",
|
||||
get_cmd_string(trans_pcie, cmd->id));
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
iwl_op_mode_nic_error(trans->op_mode);
|
||||
|
||||
goto cancel;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue