mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-23 12:49:47 +07:00
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
This commit is contained in:
commit
d878b3af67
@ -20,16 +20,17 @@ config IWLWIFI
|
||||
Intel 2000 Series Wi-Fi Adapters
|
||||
Intel 7260 Wi-Fi Adapter
|
||||
Intel 3160 Wi-Fi Adapter
|
||||
Intel 7265 Wi-Fi Adapter
|
||||
|
||||
|
||||
This driver uses the kernel's mac80211 subsystem.
|
||||
|
||||
In order to use this driver, you will need a microcode (uCode)
|
||||
In order to use this driver, you will need a firmware
|
||||
image for it. You can obtain the microcode from:
|
||||
|
||||
<http://intellinuxwireless.org/>.
|
||||
<http://wireless.kernel.org/en/users/Drivers/iwlwifi>.
|
||||
|
||||
The microcode is typically installed in /lib/firmware. You can
|
||||
The firmware is typically installed in /lib/firmware. You can
|
||||
look in the hotplug script /etc/hotplug/firmware.agent to
|
||||
determine which directory FIRMWARE_DIR is set to when the script
|
||||
runs.
|
||||
@ -39,9 +40,10 @@ config IWLWIFI
|
||||
say M here and read <file:Documentation/kbuild/modules.txt>. The
|
||||
module will be called iwlwifi.
|
||||
|
||||
if IWLWIFI
|
||||
|
||||
config IWLWIFI_LEDS
|
||||
bool
|
||||
depends on IWLWIFI
|
||||
depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI
|
||||
select LEDS_TRIGGERS
|
||||
select MAC80211_LEDS
|
||||
@ -49,7 +51,7 @@ config IWLWIFI_LEDS
|
||||
|
||||
config IWLDVM
|
||||
tristate "Intel Wireless WiFi DVM Firmware support"
|
||||
depends on IWLWIFI
|
||||
depends on m
|
||||
default IWLWIFI
|
||||
help
|
||||
This is the driver that supports the DVM firmware which is
|
||||
@ -58,7 +60,7 @@ config IWLDVM
|
||||
|
||||
config IWLMVM
|
||||
tristate "Intel Wireless WiFi MVM Firmware support"
|
||||
depends on IWLWIFI
|
||||
depends on m
|
||||
help
|
||||
This is the driver that supports the MVM firmware which is
|
||||
currently only available for 7260 and 3160 devices.
|
||||
@ -70,7 +72,7 @@ config IWLWIFI_OPMODE_MODULAR
|
||||
default y if IWLMVM=m
|
||||
|
||||
comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM"
|
||||
depends on IWLWIFI && IWLDVM=n && IWLMVM=n
|
||||
depends on IWLDVM=n && IWLMVM=n
|
||||
|
||||
config IWLWIFI_BCAST_FILTERING
|
||||
bool "Enable broadcast filtering"
|
||||
@ -86,11 +88,9 @@ config IWLWIFI_BCAST_FILTERING
|
||||
expect incoming broadcasts for their normal operations.
|
||||
|
||||
menu "Debugging Options"
|
||||
depends on IWLWIFI
|
||||
|
||||
config IWLWIFI_DEBUG
|
||||
bool "Enable full debugging output in the iwlwifi driver"
|
||||
depends on IWLWIFI
|
||||
---help---
|
||||
This option will enable debug tracing output for the iwlwifi drivers
|
||||
|
||||
@ -115,7 +115,7 @@ config IWLWIFI_DEBUG
|
||||
|
||||
config IWLWIFI_DEBUGFS
|
||||
bool "iwlwifi debugfs support"
|
||||
depends on IWLWIFI && MAC80211_DEBUGFS
|
||||
depends on MAC80211_DEBUGFS
|
||||
---help---
|
||||
Enable creation of debugfs files for the iwlwifi drivers. This
|
||||
is a low-impact option that allows getting insight into the
|
||||
@ -123,13 +123,12 @@ config IWLWIFI_DEBUGFS
|
||||
|
||||
config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
|
||||
bool "Experimental uCode support"
|
||||
depends on IWLWIFI && IWLWIFI_DEBUG
|
||||
depends on IWLWIFI_DEBUG
|
||||
---help---
|
||||
Enable use of experimental ucode for testing and debugging.
|
||||
|
||||
config IWLWIFI_DEVICE_TRACING
|
||||
bool "iwlwifi device access tracing"
|
||||
depends on IWLWIFI
|
||||
depends on EVENT_TRACING
|
||||
help
|
||||
Say Y here to trace all commands, including TX frames and IO
|
||||
@ -145,3 +144,5 @@ config IWLWIFI_DEVICE_TRACING
|
||||
If unsure, say Y so we can help you better when problems
|
||||
occur.
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
@ -85,6 +85,9 @@
|
||||
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
|
||||
#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin"
|
||||
|
||||
/* Max SDIO RX aggregation size of the ADDBA request/response */
|
||||
#define MAX_RX_AGG_SIZE_8260_SDIO 28
|
||||
|
||||
static const struct iwl_base_params iwl8000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000,
|
||||
.num_of_queues = IWLAGN_NUM_QUEUES,
|
||||
@ -129,6 +132,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
|
||||
.nvm_ver = IWL8000_NVM_VERSION,
|
||||
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
|
||||
.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
|
||||
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
|
||||
|
@ -240,6 +240,7 @@ struct iwl_pwr_tx_backoff {
|
||||
* @d0i3: device uses d0i3 instead of d3
|
||||
* @nvm_hw_section_num: the ID of the HW NVM section
|
||||
* @pwr_tx_backoffs: translation table between power limits and backoffs
|
||||
* @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
|
||||
*
|
||||
* We enable the driver to be backward compatible wrt. hardware features.
|
||||
* API differences in uCode shouldn't be handled here but through TLVs
|
||||
@ -276,6 +277,7 @@ struct iwl_cfg {
|
||||
const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
|
||||
bool no_power_up_nic_in_init;
|
||||
const char *default_nvm_file;
|
||||
unsigned int max_rx_agg_size;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -70,21 +70,24 @@
|
||||
/**
|
||||
* enum iwl_fw_error_dump_type - types of data in the dump file
|
||||
* @IWL_FW_ERROR_DUMP_SRAM:
|
||||
* @IWL_FW_ERROR_DUMP_REG:
|
||||
* @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0
|
||||
* @IWL_FW_ERROR_DUMP_RXF:
|
||||
* @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as
|
||||
* &struct iwl_fw_error_dump_txcmd packets
|
||||
* @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info
|
||||
* info on the device / firmware.
|
||||
* @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor
|
||||
* @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several
|
||||
* sections like this in a single file.
|
||||
*/
|
||||
enum iwl_fw_error_dump_type {
|
||||
IWL_FW_ERROR_DUMP_SRAM = 0,
|
||||
IWL_FW_ERROR_DUMP_REG = 1,
|
||||
IWL_FW_ERROR_DUMP_CSR = 1,
|
||||
IWL_FW_ERROR_DUMP_RXF = 2,
|
||||
IWL_FW_ERROR_DUMP_TXCMD = 3,
|
||||
IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4,
|
||||
IWL_FW_ERROR_DUMP_FW_MONITOR = 5,
|
||||
IWL_FW_ERROR_DUMP_PRPH = 6,
|
||||
|
||||
IWL_FW_ERROR_DUMP_MAX,
|
||||
};
|
||||
@ -162,6 +165,16 @@ struct iwl_fw_error_dump_fw_mon {
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iwl_fw_error_dump_prph - periphery registers data
|
||||
* @prph_start: address of the first register in this chunk
|
||||
* @data: the content of the registers
|
||||
*/
|
||||
struct iwl_fw_error_dump_prph {
|
||||
__le32 prph_start;
|
||||
__le32 data[];
|
||||
};
|
||||
|
||||
/**
|
||||
* iwl_fw_error_next_data - advance fw error dump data pointer
|
||||
* @data: previous data block
|
||||
|
@ -99,7 +99,7 @@ enum iwl_disable_11n {
|
||||
* @wd_disable: disable stuck queue check, default = 1
|
||||
* @bt_coex_active: enable bt coex, default = true
|
||||
* @led_mode: system default, default = 0
|
||||
* @power_save: disable power save, default = false
|
||||
* @power_save: enable power save, default = false
|
||||
* @power_level: power level, default = 1
|
||||
* @debug_level: levels are IWL_DL_*
|
||||
* @ant_coupling: antenna coupling in dB, default = 0
|
||||
|
@ -394,6 +394,11 @@ struct iwl_trans_config {
|
||||
const char *const *command_names;
|
||||
};
|
||||
|
||||
struct iwl_trans_dump_data {
|
||||
u32 len;
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
struct iwl_trans;
|
||||
|
||||
/**
|
||||
@ -461,10 +466,8 @@ struct iwl_trans;
|
||||
* @unref: release a reference previously taken with @ref. Note that
|
||||
* initially the reference count is 1, making an initial @unref
|
||||
* necessary to allow low power states.
|
||||
* @dump_data: fill a data dump with debug data, maybe containing last
|
||||
* TX'ed commands and similar. When called with a NULL buffer and
|
||||
* zero buffer length, provide only the (estimated) required buffer
|
||||
* length. Return the used buffer length.
|
||||
* @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last
|
||||
* TX'ed commands and similar. The buffer will be vfree'd by the caller.
|
||||
* Note that the transport must fill in the proper file headers.
|
||||
*/
|
||||
struct iwl_trans_ops {
|
||||
@ -518,7 +521,7 @@ struct iwl_trans_ops {
|
||||
void (*unref)(struct iwl_trans *trans);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
u32 (*dump_data)(struct iwl_trans *trans, void *buf, u32 buflen);
|
||||
struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans);
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -685,12 +688,12 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
static inline u32 iwl_trans_dump_data(struct iwl_trans *trans,
|
||||
void *buf, u32 buflen)
|
||||
static inline struct iwl_trans_dump_data *
|
||||
iwl_trans_dump_data(struct iwl_trans *trans)
|
||||
{
|
||||
if (!trans->ops->dump_data)
|
||||
return 0;
|
||||
return trans->ops->dump_data(trans, buf, buflen);
|
||||
return NULL;
|
||||
return trans->ops->dump_data(trans);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -72,16 +72,56 @@
|
||||
|
||||
#define BT_ANTENNA_COUPLING_THRESHOLD (30)
|
||||
|
||||
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_ctl_kill_msk[BT_KILL_MSK_MAX] = {
|
||||
[BT_KILL_MSK_DEFAULT] = 0xfffffc00,
|
||||
[BT_KILL_MSK_NEVER] = 0xffffffff,
|
||||
[BT_KILL_MSK_ALWAYS] = 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,
|
||||
const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_NEVER,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
},
|
||||
};
|
||||
|
||||
const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = {
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
},
|
||||
{
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
},
|
||||
};
|
||||
|
||||
static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = {
|
||||
@ -611,54 +651,43 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm,
|
||||
bool reduced_tx_power)
|
||||
static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm)
|
||||
{
|
||||
enum iwl_bt_kill_msk bt_kill_msk;
|
||||
struct iwl_bt_coex_sw_boost_update_cmd cmd = {};
|
||||
struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
|
||||
u32 primary_lut = le32_to_cpu(notif->primary_ch_lut);
|
||||
u32 secondary_lut = le32_to_cpu(notif->secondary_ch_lut);
|
||||
u32 ag = le32_to_cpu(notif->bt_activity_grading);
|
||||
struct iwl_bt_coex_sw_boost_update_cmd cmd = {};
|
||||
u8 ack_kill_msk[NUM_PHY_CTX] = {};
|
||||
u8 cts_kill_msk[NUM_PHY_CTX] = {};
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (reduced_tx_power) {
|
||||
/* Reduced Tx power has precedence on the type of the profile */
|
||||
bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW;
|
||||
} else {
|
||||
/* Low latency BT profile is active: give higher prio to BT */
|
||||
if (BT_MBOX_MSG(notif, 3, SCO_STATE) ||
|
||||
BT_MBOX_MSG(notif, 3, A2DP_STATE) ||
|
||||
BT_MBOX_MSG(notif, 3, SNIFF_STATE))
|
||||
bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP;
|
||||
else
|
||||
bt_kill_msk = BT_KILL_MSK_DEFAULT;
|
||||
}
|
||||
ack_kill_msk[0] = iwl_bt_ack_kill_msk[ag][primary_lut];
|
||||
cts_kill_msk[0] = iwl_bt_cts_kill_msk[ag][primary_lut];
|
||||
|
||||
IWL_DEBUG_COEX(mvm,
|
||||
"Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n",
|
||||
bt_kill_msk,
|
||||
BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
|
||||
BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
|
||||
BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in");
|
||||
ack_kill_msk[1] = iwl_bt_ack_kill_msk[ag][secondary_lut];
|
||||
cts_kill_msk[1] = iwl_bt_cts_kill_msk[ag][secondary_lut];
|
||||
|
||||
/* Don't send HCMD if there is no update */
|
||||
if (bt_kill_msk == mvm->bt_kill_msk)
|
||||
if (!memcmp(ack_kill_msk, mvm->bt_ack_kill_msk, sizeof(ack_kill_msk)) ||
|
||||
!memcmp(cts_kill_msk, mvm->bt_cts_kill_msk, sizeof(cts_kill_msk)))
|
||||
return 0;
|
||||
|
||||
mvm->bt_kill_msk = bt_kill_msk;
|
||||
memcpy(mvm->bt_ack_kill_msk, ack_kill_msk,
|
||||
sizeof(mvm->bt_ack_kill_msk));
|
||||
memcpy(mvm->bt_cts_kill_msk, cts_kill_msk,
|
||||
sizeof(mvm->bt_cts_kill_msk));
|
||||
|
||||
cmd.boost_values[0].kill_ack_msk =
|
||||
cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]);
|
||||
cmd.boost_values[0].kill_cts_msk =
|
||||
cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]);
|
||||
BUILD_BUG_ON(ARRAY_SIZE(ack_kill_msk) < ARRAY_SIZE(cmd.boost_values));
|
||||
|
||||
cmd.boost_values[1].kill_ack_msk = cmd.boost_values[0].kill_ack_msk;
|
||||
cmd.boost_values[2].kill_cts_msk = cmd.boost_values[0].kill_cts_msk;
|
||||
cmd.boost_values[1].kill_ack_msk = cmd.boost_values[0].kill_ack_msk;
|
||||
cmd.boost_values[2].kill_cts_msk = cmd.boost_values[0].kill_cts_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]);
|
||||
for (i = 0; i < ARRAY_SIZE(cmd.boost_values); i++) {
|
||||
cmd.boost_values[i].kill_ack_msk =
|
||||
cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk[i]]);
|
||||
cmd.boost_values[i].kill_cts_msk =
|
||||
cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk[i]]);
|
||||
}
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0,
|
||||
sizeof(cmd), &cmd);
|
||||
@ -700,8 +729,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
|
||||
struct iwl_bt_iterator_data {
|
||||
struct iwl_bt_coex_profile_notif *notif;
|
||||
struct iwl_mvm *mvm;
|
||||
u32 num_bss_ifaces;
|
||||
bool reduced_tx_power;
|
||||
struct ieee80211_chanctx_conf *primary;
|
||||
struct ieee80211_chanctx_conf *secondary;
|
||||
bool primary_ll;
|
||||
@ -737,22 +764,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
/* Count BSSes vifs */
|
||||
data->num_bss_ifaces++;
|
||||
/* default smps_mode for BSS / P2P client is AUTOMATIC */
|
||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
/* default smps_mode for AP / GO is OFF */
|
||||
smps_mode = IEEE80211_SMPS_OFF;
|
||||
if (!mvmvif->ap_ibss_active) {
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
|
||||
smps_mode);
|
||||
if (!mvmvif->ap_ibss_active)
|
||||
return;
|
||||
}
|
||||
|
||||
/* the Ack / Cts kill mask must be default if AP / GO */
|
||||
data->reduced_tx_power = false;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -763,11 +780,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
/* If channel context is invalid or not on 2.4GHz .. */
|
||||
if ((!chanctx_conf ||
|
||||
chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) {
|
||||
/* ... relax constraints and disable rssi events */
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
|
||||
smps_mode);
|
||||
data->reduced_tx_power = false;
|
||||
if (vif->type == NL80211_IFTYPE_STATION) {
|
||||
/* ... relax constraints and disable rssi events */
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
|
||||
smps_mode);
|
||||
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
|
||||
false);
|
||||
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
|
||||
@ -779,9 +795,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
if (bt_activity_grading >= BT_HIGH_TRAFFIC)
|
||||
smps_mode = IEEE80211_SMPS_STATIC;
|
||||
else if (bt_activity_grading >= BT_LOW_TRAFFIC)
|
||||
smps_mode = vif->type == NL80211_IFTYPE_AP ?
|
||||
IEEE80211_SMPS_OFF :
|
||||
IEEE80211_SMPS_DYNAMIC;
|
||||
smps_mode = IEEE80211_SMPS_DYNAMIC;
|
||||
|
||||
/* relax SMPS contraints for next association */
|
||||
if (!vif->bss_conf.assoc)
|
||||
@ -795,7 +809,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
"mac %d: bt_activity_grading %d smps_req %d\n",
|
||||
mvmvif->id, bt_activity_grading, smps_mode);
|
||||
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode);
|
||||
if (vif->type == NL80211_IFTYPE_STATION)
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
|
||||
smps_mode);
|
||||
|
||||
/* low latency is always primary */
|
||||
if (iwl_mvm_vif_low_latency(mvmvif)) {
|
||||
@ -846,7 +862,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
|
||||
mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc ||
|
||||
le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) {
|
||||
data->reduced_tx_power = false;
|
||||
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false);
|
||||
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
|
||||
return;
|
||||
@ -861,23 +876,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
|
||||
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
|
||||
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
|
||||
|
||||
/*
|
||||
* bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the
|
||||
* BSS / P2P clients have rssi above threshold.
|
||||
* We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before
|
||||
* the iteration, if one interface's rssi isn't good enough,
|
||||
* bt_kill_msk will be set to default values.
|
||||
*/
|
||||
} else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
|
||||
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
|
||||
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
|
||||
|
||||
/*
|
||||
* One interface hasn't rssi above threshold, bt_kill_msk must
|
||||
* be set to default values.
|
||||
*/
|
||||
data->reduced_tx_power = false;
|
||||
}
|
||||
|
||||
/* Begin to monitor the RSSI: it may influence the reduced Tx power */
|
||||
@ -889,7 +890,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
|
||||
struct iwl_bt_iterator_data data = {
|
||||
.mvm = mvm,
|
||||
.notif = &mvm->last_bt_notif,
|
||||
.reduced_tx_power = true,
|
||||
};
|
||||
struct iwl_bt_coex_ci_cmd cmd = {};
|
||||
u8 ci_bw_idx;
|
||||
@ -959,14 +959,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
|
||||
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.
|
||||
* Use BT_KILL_MSK_DEFAULT in that case.
|
||||
*/
|
||||
data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
|
||||
|
||||
if (iwl_mvm_bt_udpate_sw_boost(mvm, data.reduced_tx_power))
|
||||
if (iwl_mvm_bt_udpate_sw_boost(mvm))
|
||||
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
|
||||
}
|
||||
|
||||
@ -1035,16 +1028,6 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
|
||||
return;
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
data->num_bss_ifaces++;
|
||||
|
||||
/*
|
||||
* This interface doesn't support reduced Tx power (because of low
|
||||
* RSSI probably), then set bt_kill_msk to default values.
|
||||
*/
|
||||
if (!mvmsta->bt_reduced_txpower)
|
||||
data->reduced_tx_power = false;
|
||||
/* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */
|
||||
}
|
||||
|
||||
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
@ -1053,7 +1036,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
|
||||
struct iwl_bt_iterator_data data = {
|
||||
.mvm = mvm,
|
||||
.reduced_tx_power = true,
|
||||
};
|
||||
int ret;
|
||||
|
||||
@ -1100,14 +1082,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_bt_rssi_iterator, &data);
|
||||
|
||||
/*
|
||||
* If there are no BSS / P2P client interfaces, reduced Tx Power is
|
||||
* irrelevant since it is based on the RSSI coming from the beacon.
|
||||
* Use BT_KILL_MSK_DEFAULT in that case.
|
||||
*/
|
||||
data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
|
||||
|
||||
if (iwl_mvm_bt_udpate_sw_boost(mvm, data.reduced_tx_power))
|
||||
if (iwl_mvm_bt_udpate_sw_boost(mvm))
|
||||
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
|
||||
}
|
||||
|
||||
@ -1150,7 +1125,7 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
|
||||
enum iwl_bt_coex_lut_type lut_type;
|
||||
|
||||
if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
|
||||
return iwl_mvm_coex_agg_time_limit_old(mvm, sta);
|
||||
return iwl_mvm_bt_coex_is_mimo_allowed_old(mvm, sta);
|
||||
|
||||
if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id))
|
||||
return true;
|
||||
|
@ -649,10 +649,6 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
|
||||
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]);
|
||||
|
||||
send_cmd:
|
||||
memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
|
||||
@ -664,12 +660,13 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
|
||||
bool reduced_tx_power)
|
||||
static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm)
|
||||
{
|
||||
enum iwl_bt_kill_msk bt_kill_msk;
|
||||
struct iwl_bt_coex_cmd_old *bt_cmd;
|
||||
struct iwl_bt_coex_profile_notif_old *notif = &mvm->last_bt_notif_old;
|
||||
u32 primary_lut = le32_to_cpu(notif->primary_ch_lut);
|
||||
u32 ag = le32_to_cpu(notif->bt_activity_grading);
|
||||
struct iwl_bt_coex_cmd_old *bt_cmd;
|
||||
u8 ack_kill_msk, cts_kill_msk;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = BT_CONFIG,
|
||||
.data[0] = &bt_cmd,
|
||||
@ -680,31 +677,15 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (reduced_tx_power) {
|
||||
/* Reduced Tx power has precedence on the type of the profile */
|
||||
bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW;
|
||||
} else {
|
||||
/* Low latency BT profile is active: give higher prio to BT */
|
||||
if (BT_MBOX_MSG(notif, 3, SCO_STATE) ||
|
||||
BT_MBOX_MSG(notif, 3, A2DP_STATE) ||
|
||||
BT_MBOX_MSG(notif, 3, SNIFF_STATE))
|
||||
bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP;
|
||||
else
|
||||
bt_kill_msk = BT_KILL_MSK_DEFAULT;
|
||||
}
|
||||
ack_kill_msk = iwl_bt_ack_kill_msk[ag][primary_lut];
|
||||
cts_kill_msk = iwl_bt_cts_kill_msk[ag][primary_lut];
|
||||
|
||||
IWL_DEBUG_COEX(mvm,
|
||||
"Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n",
|
||||
bt_kill_msk,
|
||||
BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
|
||||
BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
|
||||
BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in");
|
||||
|
||||
/* Don't send HCMD if there is no update */
|
||||
if (bt_kill_msk == mvm->bt_kill_msk)
|
||||
if (mvm->bt_ack_kill_msk[0] == ack_kill_msk &&
|
||||
mvm->bt_cts_kill_msk[0] == cts_kill_msk)
|
||||
return 0;
|
||||
|
||||
mvm->bt_kill_msk = bt_kill_msk;
|
||||
mvm->bt_ack_kill_msk[0] = ack_kill_msk;
|
||||
mvm->bt_cts_kill_msk[0] = cts_kill_msk;
|
||||
|
||||
bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
|
||||
if (!bt_cmd)
|
||||
@ -712,16 +693,12 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
|
||||
cmd.data[0] = bt_cmd;
|
||||
bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD);
|
||||
|
||||
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->kill_ack_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk]);
|
||||
bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk]);
|
||||
bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE |
|
||||
BT_VALID_KILL_ACK |
|
||||
BT_VALID_KILL_CTS);
|
||||
|
||||
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);
|
||||
|
||||
kfree(bt_cmd);
|
||||
@ -777,8 +754,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
|
||||
struct iwl_bt_iterator_data {
|
||||
struct iwl_bt_coex_profile_notif_old *notif;
|
||||
struct iwl_mvm *mvm;
|
||||
u32 num_bss_ifaces;
|
||||
bool reduced_tx_power;
|
||||
struct ieee80211_chanctx_conf *primary;
|
||||
struct ieee80211_chanctx_conf *secondary;
|
||||
bool primary_ll;
|
||||
@ -814,22 +789,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
/* Count BSSes vifs */
|
||||
data->num_bss_ifaces++;
|
||||
/* default smps_mode for BSS / P2P client is AUTOMATIC */
|
||||
smps_mode = IEEE80211_SMPS_AUTOMATIC;
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
/* default smps_mode for AP / GO is OFF */
|
||||
smps_mode = IEEE80211_SMPS_OFF;
|
||||
if (!mvmvif->ap_ibss_active) {
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
|
||||
smps_mode);
|
||||
if (!mvmvif->ap_ibss_active)
|
||||
return;
|
||||
}
|
||||
|
||||
/* the Ack / Cts kill mask must be default if AP / GO */
|
||||
data->reduced_tx_power = false;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -840,11 +805,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
/* If channel context is invalid or not on 2.4GHz .. */
|
||||
if ((!chanctx_conf ||
|
||||
chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) {
|
||||
/* ... relax constraints and disable rssi events */
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
|
||||
smps_mode);
|
||||
data->reduced_tx_power = false;
|
||||
if (vif->type == NL80211_IFTYPE_STATION) {
|
||||
/* ... relax constraints and disable rssi events */
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
|
||||
smps_mode);
|
||||
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
|
||||
false);
|
||||
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
|
||||
@ -869,7 +833,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
mvmvif->id, data->notif->bt_status, bt_activity_grading,
|
||||
smps_mode);
|
||||
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode);
|
||||
if (vif->type == NL80211_IFTYPE_STATION)
|
||||
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
|
||||
smps_mode);
|
||||
|
||||
/* low latency is always primary */
|
||||
if (iwl_mvm_vif_low_latency(mvmvif)) {
|
||||
@ -920,7 +886,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
|
||||
mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc ||
|
||||
!data->notif->bt_status) {
|
||||
data->reduced_tx_power = false;
|
||||
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false);
|
||||
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
|
||||
return;
|
||||
@ -935,23 +900,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
||||
if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
|
||||
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
|
||||
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
|
||||
|
||||
/*
|
||||
* bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the
|
||||
* BSS / P2P clients have rssi above threshold.
|
||||
* We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before
|
||||
* the iteration, if one interface's rssi isn't good enough,
|
||||
* bt_kill_msk will be set to default values.
|
||||
*/
|
||||
} else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
|
||||
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
|
||||
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
|
||||
|
||||
/*
|
||||
* One interface hasn't rssi above threshold, bt_kill_msk must
|
||||
* be set to default values.
|
||||
*/
|
||||
data->reduced_tx_power = false;
|
||||
}
|
||||
|
||||
/* Begin to monitor the RSSI: it may influence the reduced Tx power */
|
||||
@ -963,7 +914,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
|
||||
struct iwl_bt_iterator_data data = {
|
||||
.mvm = mvm,
|
||||
.notif = &mvm->last_bt_notif_old,
|
||||
.reduced_tx_power = true,
|
||||
};
|
||||
struct iwl_bt_coex_ci_cmd_old cmd = {};
|
||||
u8 ci_bw_idx;
|
||||
@ -1037,14 +987,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
|
||||
memcpy(&mvm->last_bt_ci_cmd_old, &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.
|
||||
* Use BT_KILL_MSK_DEFAULT in that case.
|
||||
*/
|
||||
data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
|
||||
|
||||
if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
|
||||
if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm))
|
||||
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
|
||||
}
|
||||
|
||||
@ -1115,16 +1058,6 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
|
||||
return;
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
data->num_bss_ifaces++;
|
||||
|
||||
/*
|
||||
* This interface doesn't support reduced Tx power (because of low
|
||||
* RSSI probably), then set bt_kill_msk to default values.
|
||||
*/
|
||||
if (!mvmsta->bt_reduced_txpower)
|
||||
data->reduced_tx_power = false;
|
||||
/* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */
|
||||
}
|
||||
|
||||
void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
@ -1133,7 +1066,6 @@ void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
|
||||
struct iwl_bt_iterator_data data = {
|
||||
.mvm = mvm,
|
||||
.reduced_tx_power = true,
|
||||
};
|
||||
int ret;
|
||||
|
||||
@ -1175,14 +1107,7 @@ void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_bt_rssi_iterator, &data);
|
||||
|
||||
/*
|
||||
* If there are no BSS / P2P client interfaces, reduced Tx Power is
|
||||
* irrelevant since it is based on the RSSI coming from the beacon.
|
||||
* Use BT_KILL_MSK_DEFAULT in that case.
|
||||
*/
|
||||
data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
|
||||
|
||||
if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
|
||||
if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm))
|
||||
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
|
||||
}
|
||||
|
||||
|
@ -146,17 +146,47 @@ static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_fw_error_dump_file *dump_file = file->private_data;
|
||||
struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
|
||||
ssize_t bytes_read = 0;
|
||||
ssize_t bytes_read_trans = 0;
|
||||
|
||||
if (*ppos < dump_ptrs->op_mode_len)
|
||||
bytes_read +=
|
||||
simple_read_from_buffer(user_buf, count, ppos,
|
||||
dump_ptrs->op_mode_ptr,
|
||||
dump_ptrs->op_mode_len);
|
||||
|
||||
if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len)
|
||||
return bytes_read;
|
||||
|
||||
if (dump_ptrs->trans_ptr) {
|
||||
*ppos -= dump_ptrs->op_mode_len;
|
||||
bytes_read_trans =
|
||||
simple_read_from_buffer(user_buf + bytes_read,
|
||||
count - bytes_read, ppos,
|
||||
dump_ptrs->trans_ptr->data,
|
||||
dump_ptrs->trans_ptr->len);
|
||||
*ppos += dump_ptrs->op_mode_len;
|
||||
|
||||
if (bytes_read_trans >= 0)
|
||||
bytes_read += bytes_read_trans;
|
||||
else if (!bytes_read)
|
||||
/* propagate the failure */
|
||||
return bytes_read_trans;
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos,
|
||||
dump_file,
|
||||
le32_to_cpu(dump_file->file_len));
|
||||
}
|
||||
|
||||
static int iwl_dbgfs_fw_error_dump_release(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
vfree(file->private_data);
|
||||
struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
|
||||
|
||||
vfree(dump_ptrs->op_mode_ptr);
|
||||
vfree(dump_ptrs->trans_ptr);
|
||||
kfree(dump_ptrs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -514,9 +544,9 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
|
||||
|
||||
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]);
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n",
|
||||
iwl_bt_cts_kill_msk[mvm->bt_kill_msk]);
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]);
|
||||
|
||||
} else {
|
||||
struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd;
|
||||
@ -531,10 +561,19 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf,
|
||||
le64_to_cpu(cmd->bt_secondary_ci));
|
||||
|
||||
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]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tPrimary: ACK Kill Mask 0x%08x\n",
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tPrimary: CTS Kill Mask 0x%08x\n",
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tSecondary: ACK Kill Mask 0x%08x\n",
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[1]]);
|
||||
pos += scnprintf(buf+pos, bufsz-pos,
|
||||
"\tSecondary: CTS Kill Mask 0x%08x\n",
|
||||
iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[1]]);
|
||||
|
||||
}
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
@ -830,8 +869,14 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
|
||||
static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iwl_force_nmi(mvm->trans);
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_NMI);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1115,11 +1160,11 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
|
||||
}
|
||||
#endif
|
||||
|
||||
#define PRINT_MVM_REF(ref) do { \
|
||||
if (test_bit(ref, mvm->ref_bitmap)) \
|
||||
pos += scnprintf(buf + pos, bufsz - pos, \
|
||||
"\t(0x%lx) %s\n", \
|
||||
BIT(ref), #ref); \
|
||||
#define PRINT_MVM_REF(ref) do { \
|
||||
if (mvm->refs[ref]) \
|
||||
pos += scnprintf(buf + pos, bufsz - pos, \
|
||||
"\t(0x%lx): %d %s\n", \
|
||||
BIT(ref), mvm->refs[ref], #ref); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
|
||||
@ -1127,12 +1172,17 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct iwl_mvm *mvm = file->private_data;
|
||||
int pos = 0;
|
||||
int i, pos = 0;
|
||||
char buf[256];
|
||||
const size_t bufsz = sizeof(buf);
|
||||
u32 refs = 0;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n",
|
||||
mvm->ref_bitmap[0]);
|
||||
for (i = 0; i < IWL_MVM_REF_COUNT; i++)
|
||||
if (mvm->refs[i])
|
||||
refs |= BIT(i);
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%x\n",
|
||||
refs);
|
||||
|
||||
PRINT_MVM_REF(IWL_MVM_REF_UCODE_DOWN);
|
||||
PRINT_MVM_REF(IWL_MVM_REF_SCAN);
|
||||
@ -1158,7 +1208,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
taken = test_bit(IWL_MVM_REF_USER, mvm->ref_bitmap);
|
||||
taken = mvm->refs[IWL_MVM_REF_USER];
|
||||
if (value == 1 && !taken)
|
||||
iwl_mvm_ref(mvm, IWL_MVM_REF_USER);
|
||||
else if (value == 0 && taken)
|
||||
@ -1194,14 +1244,21 @@ iwl_dbgfs_prph_reg_read(struct file *file,
|
||||
int pos = 0;
|
||||
char buf[32];
|
||||
const size_t bufsz = sizeof(buf);
|
||||
int ret;
|
||||
|
||||
if (!mvm->dbgfs_prph_reg_addr)
|
||||
return -EINVAL;
|
||||
|
||||
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
|
||||
mvm->dbgfs_prph_reg_addr,
|
||||
iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr));
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_READ);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||
}
|
||||
|
||||
@ -1211,6 +1268,7 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
|
||||
{
|
||||
u8 args;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
|
||||
/* if we only want to set the reg address - nothing more to do */
|
||||
@ -1221,7 +1279,13 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
|
||||
if (args != 2)
|
||||
return -EINVAL;
|
||||
|
||||
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
|
||||
out:
|
||||
return count;
|
||||
}
|
||||
|
@ -385,6 +385,8 @@ enum iwl_bt_activity_grading {
|
||||
BT_ON_NO_CONNECTION = 1,
|
||||
BT_LOW_TRAFFIC = 2,
|
||||
BT_HIGH_TRAFFIC = 3,
|
||||
|
||||
BT_MAX_AG,
|
||||
}; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */
|
||||
|
||||
enum iwl_bt_ci_compliance {
|
||||
|
@ -133,6 +133,7 @@ enum {
|
||||
/* Scan offload */
|
||||
SCAN_OFFLOAD_REQUEST_CMD = 0x51,
|
||||
SCAN_OFFLOAD_ABORT_CMD = 0x52,
|
||||
HOT_SPOT_CMD = 0x53,
|
||||
SCAN_OFFLOAD_COMPLETE = 0x6D,
|
||||
SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
|
||||
SCAN_OFFLOAD_CONFIG_CMD = 0x6f,
|
||||
@ -910,6 +911,72 @@ struct iwl_phy_context_cmd {
|
||||
__le32 dsp_cfg_flags;
|
||||
} __packed; /* PHY_CONTEXT_CMD_API_VER_1 */
|
||||
|
||||
/*
|
||||
* Aux ROC command
|
||||
*
|
||||
* Command requests the firmware to create a time event for a certain duration
|
||||
* and remain on the given channel. This is done by using the Aux framework in
|
||||
* the FW.
|
||||
* The command was first used for Hot Spot issues - but can be used regardless
|
||||
* to Hot Spot.
|
||||
*
|
||||
* ( HOT_SPOT_CMD 0x53 )
|
||||
*
|
||||
* @id_and_color: ID and color of the MAC
|
||||
* @action: action to perform, one of FW_CTXT_ACTION_*
|
||||
* @event_unique_id: If the action FW_CTXT_ACTION_REMOVE then the
|
||||
* event_unique_id should be the id of the time event assigned by ucode.
|
||||
* Otherwise ignore the event_unique_id.
|
||||
* @sta_id_and_color: station id and color, resumed during "Remain On Channel"
|
||||
* activity.
|
||||
* @channel_info: channel info
|
||||
* @node_addr: Our MAC Address
|
||||
* @reserved: reserved for alignment
|
||||
* @apply_time: GP2 value to start (should always be the current GP2 value)
|
||||
* @apply_time_max_delay: Maximum apply time delay value in TU. Defines max
|
||||
* time by which start of the event is allowed to be postponed.
|
||||
* @duration: event duration in TU To calculate event duration:
|
||||
* timeEventDuration = min(duration, remainingQuota)
|
||||
*/
|
||||
struct iwl_hs20_roc_req {
|
||||
/* COMMON_INDEX_HDR_API_S_VER_1 hdr */
|
||||
__le32 id_and_color;
|
||||
__le32 action;
|
||||
__le32 event_unique_id;
|
||||
__le32 sta_id_and_color;
|
||||
struct iwl_fw_channel_info channel_info;
|
||||
u8 node_addr[ETH_ALEN];
|
||||
__le16 reserved;
|
||||
__le32 apply_time;
|
||||
__le32 apply_time_max_delay;
|
||||
__le32 duration;
|
||||
} __packed; /* HOT_SPOT_CMD_API_S_VER_1 */
|
||||
|
||||
/*
|
||||
* values for AUX ROC result values
|
||||
*/
|
||||
enum iwl_mvm_hot_spot {
|
||||
HOT_SPOT_RSP_STATUS_OK,
|
||||
HOT_SPOT_RSP_STATUS_TOO_MANY_EVENTS,
|
||||
HOT_SPOT_MAX_NUM_OF_SESSIONS,
|
||||
};
|
||||
|
||||
/*
|
||||
* Aux ROC command response
|
||||
*
|
||||
* In response to iwl_hs20_roc_req the FW sends this command to notify the
|
||||
* driver the uid of the timevent.
|
||||
*
|
||||
* ( HOT_SPOT_CMD 0x53 )
|
||||
*
|
||||
* @event_unique_id: Unique ID of time event assigned by ucode
|
||||
* @status: Return status 0 is success, all the rest used for specific errors
|
||||
*/
|
||||
struct iwl_hs20_roc_res {
|
||||
__le32 event_unique_id;
|
||||
__le32 status;
|
||||
} __packed; /* HOT_SPOT_RSP_API_S_VER_1 */
|
||||
|
||||
#define IWL_RX_INFO_PHY_CNT 8
|
||||
#define IWL_RX_INFO_ENERGY_ANT_ABC_IDX 1
|
||||
#define IWL_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff
|
||||
|
@ -1074,8 +1074,12 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
|
||||
/* Fill the common data for all mac context types */
|
||||
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
|
||||
|
||||
/* Also enable probe requests to pass */
|
||||
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
|
||||
/*
|
||||
* pass probe requests and beacons from other APs (needed
|
||||
* for ht protection)
|
||||
*/
|
||||
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST |
|
||||
MAC_FILTER_IN_BEACON);
|
||||
|
||||
/* Fill the data specific for ap mode */
|
||||
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap,
|
||||
@ -1096,6 +1100,13 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
|
||||
/* Fill the common data for all mac context types */
|
||||
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
|
||||
|
||||
/*
|
||||
* pass probe requests and beacons from other APs (needed
|
||||
* for ht protection)
|
||||
*/
|
||||
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST |
|
||||
MAC_FILTER_IN_BEACON);
|
||||
|
||||
/* Fill the data specific for GO mode */
|
||||
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap,
|
||||
action == FW_CTXT_ACTION_ADD);
|
||||
|
@ -211,7 +211,9 @@ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type);
|
||||
WARN_ON(test_and_set_bit(ref_type, mvm->ref_bitmap));
|
||||
spin_lock_bh(&mvm->refs_lock);
|
||||
mvm->refs[ref_type]++;
|
||||
spin_unlock_bh(&mvm->refs_lock);
|
||||
iwl_trans_ref(mvm->trans);
|
||||
}
|
||||
|
||||
@ -221,29 +223,35 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
|
||||
return;
|
||||
|
||||
IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type);
|
||||
WARN_ON(!test_and_clear_bit(ref_type, mvm->ref_bitmap));
|
||||
spin_lock_bh(&mvm->refs_lock);
|
||||
WARN_ON(!mvm->refs[ref_type]--);
|
||||
spin_unlock_bh(&mvm->refs_lock);
|
||||
iwl_trans_unref(mvm->trans);
|
||||
}
|
||||
|
||||
static void
|
||||
iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref)
|
||||
static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm,
|
||||
enum iwl_mvm_ref_type except_ref)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
if (!iwl_mvm_is_d0i3_supported(mvm))
|
||||
return;
|
||||
|
||||
for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) {
|
||||
if (ref == i)
|
||||
spin_lock_bh(&mvm->refs_lock);
|
||||
for (i = 0; i < IWL_MVM_REF_COUNT; i++) {
|
||||
if (except_ref == i || !mvm->refs[i])
|
||||
continue;
|
||||
|
||||
IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d\n", i);
|
||||
clear_bit(i, mvm->ref_bitmap);
|
||||
iwl_trans_unref(mvm->trans);
|
||||
IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d (%d)\n",
|
||||
i, mvm->refs[i]);
|
||||
for (j = 0; j < mvm->refs[i]; j++)
|
||||
iwl_trans_unref(mvm->trans);
|
||||
mvm->refs[i] = 0;
|
||||
}
|
||||
spin_unlock_bh(&mvm->refs_lock);
|
||||
}
|
||||
|
||||
static int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
|
||||
int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
|
||||
{
|
||||
iwl_mvm_ref(mvm, ref_type);
|
||||
|
||||
@ -321,13 +329,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
||||
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
|
||||
}
|
||||
|
||||
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT &&
|
||||
!iwlwifi_mod_params.uapsd_disable) {
|
||||
hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
|
||||
hw->uapsd_queues = IWL_UAPSD_AC_INFO;
|
||||
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
|
||||
}
|
||||
|
||||
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
|
||||
hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
|
||||
|
||||
@ -660,6 +661,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
|
||||
spin_unlock_bh(&mvm->time_event_lock);
|
||||
|
||||
mvmvif->phy_ctxt = NULL;
|
||||
memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
@ -668,11 +670,11 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
||||
struct iwl_fw_error_dump_file *dump_file;
|
||||
struct iwl_fw_error_dump_data *dump_data;
|
||||
struct iwl_fw_error_dump_info *dump_info;
|
||||
struct iwl_mvm_dump_ptrs *fw_error_dump;
|
||||
const struct fw_img *img;
|
||||
u32 sram_len, sram_ofs;
|
||||
u32 file_len, rxf_len;
|
||||
unsigned long flags;
|
||||
u32 trans_len;
|
||||
int reg_val;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
@ -680,6 +682,10 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
||||
if (mvm->fw_error_dump)
|
||||
return;
|
||||
|
||||
fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL);
|
||||
if (!fw_error_dump)
|
||||
return;
|
||||
|
||||
img = &mvm->fw->img[mvm->cur_ucode];
|
||||
sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
|
||||
sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
|
||||
@ -697,18 +703,15 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
||||
rxf_len +
|
||||
sizeof(*dump_info);
|
||||
|
||||
trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0);
|
||||
if (trans_len)
|
||||
file_len += trans_len;
|
||||
|
||||
dump_file = vzalloc(file_len);
|
||||
if (!dump_file)
|
||||
if (!dump_file) {
|
||||
kfree(fw_error_dump);
|
||||
return;
|
||||
}
|
||||
|
||||
mvm->fw_error_dump = dump_file;
|
||||
fw_error_dump->op_mode_ptr = dump_file;
|
||||
|
||||
dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
|
||||
dump_file->file_len = cpu_to_le32(file_len);
|
||||
dump_data = (void *)dump_file->data;
|
||||
|
||||
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO);
|
||||
@ -749,14 +752,12 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
||||
iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data,
|
||||
sram_len);
|
||||
|
||||
if (trans_len) {
|
||||
void *buf = iwl_fw_error_next_data(dump_data);
|
||||
u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf,
|
||||
trans_len);
|
||||
dump_data = (void *)((u8 *)buf + real_trans_len);
|
||||
dump_file->file_len =
|
||||
cpu_to_le32(file_len - trans_len + real_trans_len);
|
||||
}
|
||||
fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans);
|
||||
fw_error_dump->op_mode_len = file_len;
|
||||
if (fw_error_dump->trans_ptr)
|
||||
file_len += fw_error_dump->trans_ptr->len;
|
||||
dump_file->file_len = cpu_to_le32(file_len);
|
||||
mvm->fw_error_dump = fw_error_dump;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -788,6 +789,12 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
||||
iwl_mvm_reset_phy_ctxts(mvm);
|
||||
memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
|
||||
memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
|
||||
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
|
||||
memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
|
||||
memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
|
||||
memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old));
|
||||
memset(&mvm->bt_ack_kill_msk, 0, sizeof(mvm->bt_ack_kill_msk));
|
||||
memset(&mvm->bt_cts_kill_msk, 0, sizeof(mvm->bt_cts_kill_msk));
|
||||
|
||||
ieee80211_wake_queues(mvm->hw);
|
||||
|
||||
@ -1399,6 +1406,28 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
|
||||
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (!sta || IS_ERR(sta) || !sta->tdls)
|
||||
continue;
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
|
||||
NL80211_TDLS_TEARDOWN,
|
||||
WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *bss_conf,
|
||||
@ -1494,14 +1523,18 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
||||
*/
|
||||
iwl_mvm_remove_time_event(mvm, mvmvif,
|
||||
&mvmvif->time_event_data);
|
||||
iwl_mvm_sf_update(mvm, vif, false);
|
||||
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
|
||||
} else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |
|
||||
BSS_CHANGED_QOS)) {
|
||||
ret = iwl_mvm_power_update_mac(mvm);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to update power mode\n");
|
||||
}
|
||||
|
||||
if (changes & BSS_CHANGED_BEACON_INFO) {
|
||||
iwl_mvm_sf_update(mvm, vif, false);
|
||||
WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
|
||||
}
|
||||
|
||||
if (changes & BSS_CHANGED_TXPOWER) {
|
||||
IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n",
|
||||
bss_conf->txpower);
|
||||
@ -1533,6 +1566,14 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* iwl_mvm_mac_ctxt_add() might read directly from the device
|
||||
* (the system time), so make sure it is available.
|
||||
*/
|
||||
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_START_AP);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
/* Send the beacon template */
|
||||
@ -1581,6 +1622,10 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
||||
|
||||
iwl_mvm_bt_coex_vif_change(mvm);
|
||||
|
||||
/* we don't support TDLS during DCM */
|
||||
if (iwl_mvm_phy_ctx_count(mvm) > 1)
|
||||
iwl_mvm_teardown_tdls_peers(mvm);
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
return 0;
|
||||
|
||||
@ -1594,6 +1639,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
||||
iwl_mvm_mac_ctxt_remove(mvm, vif);
|
||||
out_unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_START_AP);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1671,6 +1717,14 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
|
||||
/*
|
||||
* iwl_mvm_bss_info_changed_station() might call
|
||||
* iwl_mvm_protect_session(), which reads directly from
|
||||
* the device (the system time), so make sure it is available.
|
||||
*/
|
||||
if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_BSS_CHANGED))
|
||||
return;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (changes & BSS_CHANGED_IDLE && !bss_conf->idle)
|
||||
@ -1690,8 +1744,50 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED);
|
||||
}
|
||||
|
||||
static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm,
|
||||
enum iwl_scan_status scan_type)
|
||||
{
|
||||
int ret;
|
||||
bool wait_for_handlers = false;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (mvm->scan_status != scan_type) {
|
||||
ret = 0;
|
||||
/* make sure there are no pending notifications */
|
||||
wait_for_handlers = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (scan_type) {
|
||||
case IWL_MVM_SCAN_SCHED:
|
||||
ret = iwl_mvm_scan_offload_stop(mvm, true);
|
||||
break;
|
||||
case IWL_MVM_SCAN_OS:
|
||||
ret = iwl_mvm_cancel_scan(mvm);
|
||||
break;
|
||||
case IWL_MVM_SCAN_NONE:
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
wait_for_handlers = true;
|
||||
out:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
/* make sure we consume the completion notification */
|
||||
if (wait_for_handlers)
|
||||
iwl_mvm_wait_for_async_handlers(mvm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_scan_request *hw_req)
|
||||
@ -1704,19 +1800,13 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
|
||||
return -EINVAL;
|
||||
|
||||
ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
switch (mvm->scan_status) {
|
||||
case IWL_MVM_SCAN_SCHED:
|
||||
ret = iwl_mvm_scan_offload_stop(mvm, true);
|
||||
if (ret) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case IWL_MVM_SCAN_NONE:
|
||||
break;
|
||||
default:
|
||||
if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
@ -1732,8 +1822,6 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
||||
out:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
/* make sure to flush the Rx handler before the next scan arrives */
|
||||
iwl_mvm_wait_for_async_handlers(mvm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1885,28 +1973,6 @@ static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm,
|
||||
iwl_mvm_power_update_mac(mvm);
|
||||
}
|
||||
|
||||
static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
|
||||
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (!sta || IS_ERR(sta) || !sta->tdls)
|
||||
continue;
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
|
||||
NL80211_TDLS_TEARDOWN,
|
||||
WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
|
||||
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
@ -2065,10 +2131,19 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
|
||||
if (WARN_ON_ONCE(vif->bss_conf.assoc))
|
||||
return;
|
||||
|
||||
/*
|
||||
* iwl_mvm_protect_session() reads directly from the device
|
||||
* (the system time), so make sure it is available.
|
||||
*/
|
||||
if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PREPARE_TX))
|
||||
return;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
/* Try really hard to protect the session and hear a beacon */
|
||||
iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX);
|
||||
}
|
||||
|
||||
static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
|
||||
@ -2077,10 +2152,19 @@ static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;
|
||||
|
||||
/*
|
||||
* iwl_mvm_protect_session() reads directly from the device
|
||||
* (the system time), so make sure it is available.
|
||||
*/
|
||||
if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS))
|
||||
return;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
/* Protect the session to hear the TDLS setup response on the channel */
|
||||
iwl_mvm_protect_session(mvm, vif, duration, duration, 100);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
|
||||
}
|
||||
|
||||
static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
|
||||
@ -2091,6 +2175,10 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
int ret;
|
||||
|
||||
ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (!iwl_mvm_is_idle(mvm)) {
|
||||
@ -2098,26 +2186,7 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (mvm->scan_status) {
|
||||
case IWL_MVM_SCAN_OS:
|
||||
IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n");
|
||||
ret = iwl_mvm_cancel_scan(mvm);
|
||||
if (ret) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* iwl_mvm_rx_scan_complete() will be called soon but will
|
||||
* not reset the scan status as it won't be IWL_MVM_SCAN_OS
|
||||
* any more since we queue the next scan immediately (below).
|
||||
* We make sure it is called before the next scan starts by
|
||||
* flushing the async-handlers work.
|
||||
*/
|
||||
break;
|
||||
case IWL_MVM_SCAN_NONE:
|
||||
break;
|
||||
default:
|
||||
if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
@ -2145,8 +2214,6 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
|
||||
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
||||
out:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
/* make sure to flush the Rx handler before the next scan arrives */
|
||||
iwl_mvm_wait_for_async_handlers(mvm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2266,6 +2333,119 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
}
|
||||
|
||||
|
||||
static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait,
|
||||
struct iwl_rx_packet *pkt, void *data)
|
||||
{
|
||||
struct iwl_mvm *mvm =
|
||||
container_of(notif_wait, struct iwl_mvm, notif_wait);
|
||||
struct iwl_hs20_roc_res *resp;
|
||||
int resp_len = iwl_rx_packet_payload_len(pkt);
|
||||
struct iwl_mvm_time_event_data *te_data = data;
|
||||
|
||||
if (WARN_ON(pkt->hdr.cmd != HOT_SPOT_CMD))
|
||||
return true;
|
||||
|
||||
if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
|
||||
IWL_ERR(mvm, "Invalid HOT_SPOT_CMD response\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
resp = (void *)pkt->data;
|
||||
|
||||
IWL_DEBUG_TE(mvm,
|
||||
"Aux ROC: Recieved response from ucode: status=%d uid=%d\n",
|
||||
resp->status, resp->event_unique_id);
|
||||
|
||||
te_data->uid = le32_to_cpu(resp->event_unique_id);
|
||||
IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",
|
||||
te_data->uid);
|
||||
|
||||
spin_lock_bh(&mvm->time_event_lock);
|
||||
list_add_tail(&te_data->list, &mvm->aux_roc_te_list);
|
||||
spin_unlock_bh(&mvm->time_event_lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define AUX_ROC_MAX_DELAY_ON_CHANNEL 5000
|
||||
static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
|
||||
struct ieee80211_channel *channel,
|
||||
struct ieee80211_vif *vif,
|
||||
int duration)
|
||||
{
|
||||
int res, time_reg = DEVICE_SYSTEM_TIME_REG;
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data;
|
||||
static const u8 time_event_response[] = { HOT_SPOT_CMD };
|
||||
struct iwl_notification_wait wait_time_event;
|
||||
struct iwl_hs20_roc_req aux_roc_req = {
|
||||
.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
|
||||
.id_and_color =
|
||||
cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)),
|
||||
.sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id),
|
||||
/* Set the channel info data */
|
||||
.channel_info.band = (channel->band == IEEE80211_BAND_2GHZ) ?
|
||||
PHY_BAND_24 : PHY_BAND_5,
|
||||
.channel_info.channel = channel->hw_value,
|
||||
.channel_info.width = PHY_VHT_CHANNEL_MODE20,
|
||||
/* Set the time and duration */
|
||||
.apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)),
|
||||
.apply_time_max_delay =
|
||||
cpu_to_le32(MSEC_TO_TU(AUX_ROC_MAX_DELAY_ON_CHANNEL)),
|
||||
.duration = cpu_to_le32(MSEC_TO_TU(duration)),
|
||||
};
|
||||
|
||||
/* Set the node address */
|
||||
memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN);
|
||||
|
||||
te_data->vif = vif;
|
||||
te_data->duration = duration;
|
||||
te_data->id = HOT_SPOT_CMD;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
spin_lock_bh(&mvm->time_event_lock);
|
||||
list_add_tail(&te_data->list, &mvm->time_event_list);
|
||||
spin_unlock_bh(&mvm->time_event_lock);
|
||||
|
||||
/*
|
||||
* Use a notification wait, which really just processes the
|
||||
* command response and doesn't wait for anything, in order
|
||||
* to be able to process the response and get the UID inside
|
||||
* the RX path. Using CMD_WANT_SKB doesn't work because it
|
||||
* stores the buffer and then wakes up this thread, by which
|
||||
* time another notification (that the time event started)
|
||||
* might already be processed unsuccessfully.
|
||||
*/
|
||||
iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
|
||||
time_event_response,
|
||||
ARRAY_SIZE(time_event_response),
|
||||
iwl_mvm_rx_aux_roc, te_data);
|
||||
|
||||
res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, sizeof(aux_roc_req),
|
||||
&aux_roc_req);
|
||||
|
||||
if (res) {
|
||||
IWL_ERR(mvm, "Couldn't send HOT_SPOT_CMD: %d\n", res);
|
||||
iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
|
||||
goto out_clear_te;
|
||||
}
|
||||
|
||||
/* No need to wait for anything, so just pass 1 (0 isn't valid) */
|
||||
res = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1);
|
||||
/* should never fail */
|
||||
WARN_ON_ONCE(res);
|
||||
|
||||
if (res) {
|
||||
out_clear_te:
|
||||
spin_lock_bh(&mvm->time_event_lock);
|
||||
iwl_mvm_te_clear_data(mvm, te_data);
|
||||
spin_unlock_bh(&mvm->time_event_lock);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int iwl_mvm_roc(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_channel *channel,
|
||||
@ -2281,8 +2461,17 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
|
||||
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
|
||||
duration, type);
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {
|
||||
IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type);
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
/* Use aux roc framework (HS20) */
|
||||
ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
|
||||
vif, duration);
|
||||
return ret;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
/* handle below */
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -2661,6 +2850,10 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw,
|
||||
goto out_remove;
|
||||
}
|
||||
|
||||
/* we don't support TDLS during DCM - can be caused by channel switch */
|
||||
if (iwl_mvm_phy_ctx_count(mvm) > 1)
|
||||
iwl_mvm_teardown_tdls_peers(mvm);
|
||||
|
||||
goto out;
|
||||
|
||||
out_remove:
|
||||
|
@ -82,6 +82,8 @@
|
||||
/* RSSI offset for WkP */
|
||||
#define IWL_RSSI_OFFSET 50
|
||||
#define IWL_MVM_MISSED_BEACONS_THRESHOLD 8
|
||||
/* A TimeUnit is 1024 microsecond */
|
||||
#define MSEC_TO_TU(_msec) (_msec*1000/1024)
|
||||
|
||||
/*
|
||||
* The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0"
|
||||
@ -126,6 +128,21 @@ struct iwl_mvm_mod_params {
|
||||
};
|
||||
extern struct iwl_mvm_mod_params iwlmvm_mod_params;
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_dump_ptrs - set of pointers needed for the fw-error-dump
|
||||
*
|
||||
* @op_mode_ptr: pointer to the buffer coming from the mvm op_mode
|
||||
* @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the
|
||||
* transport's data.
|
||||
* @trans_len: length of the valid data in trans_ptr
|
||||
* @op_mode_len: length of the valid data in op_mode_ptr
|
||||
*/
|
||||
struct iwl_mvm_dump_ptrs {
|
||||
struct iwl_trans_dump_data *trans_ptr;
|
||||
void *op_mode_ptr;
|
||||
u32 op_mode_len;
|
||||
};
|
||||
|
||||
struct iwl_mvm_phy_ctxt {
|
||||
u16 id;
|
||||
u16 color;
|
||||
@ -249,6 +266,15 @@ enum iwl_mvm_ref_type {
|
||||
IWL_MVM_REF_TX,
|
||||
IWL_MVM_REF_TX_AGG,
|
||||
IWL_MVM_REF_ADD_IF,
|
||||
IWL_MVM_REF_START_AP,
|
||||
IWL_MVM_REF_BSS_CHANGED,
|
||||
IWL_MVM_REF_PREPARE_TX,
|
||||
IWL_MVM_REF_PROTECT_TDLS,
|
||||
IWL_MVM_REF_CHECK_CTKILL,
|
||||
IWL_MVM_REF_PRPH_READ,
|
||||
IWL_MVM_REF_PRPH_WRITE,
|
||||
IWL_MVM_REF_NMI,
|
||||
IWL_MVM_REF_TM_CMD,
|
||||
IWL_MVM_REF_EXIT_WORK,
|
||||
|
||||
IWL_MVM_REF_COUNT,
|
||||
@ -327,6 +353,7 @@ struct iwl_mvm_vif {
|
||||
*/
|
||||
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
|
||||
struct iwl_mvm_time_event_data time_event_data;
|
||||
struct iwl_mvm_time_event_data hs_time_event_data;
|
||||
|
||||
struct iwl_mvm_int_sta bcast_sta;
|
||||
|
||||
@ -606,14 +633,15 @@ struct iwl_mvm {
|
||||
*/
|
||||
unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
|
||||
|
||||
/* A bitmap of reference types taken by the driver. */
|
||||
unsigned long ref_bitmap[BITS_TO_LONGS(IWL_MVM_REF_COUNT)];
|
||||
/* references taken by the driver and spinlock protecting them */
|
||||
spinlock_t refs_lock;
|
||||
u8 refs[IWL_MVM_REF_COUNT];
|
||||
|
||||
u8 vif_count;
|
||||
|
||||
/* -1 for always, 0 for never, >0 for that many times */
|
||||
s8 restart_fw;
|
||||
void *fw_error_dump;
|
||||
struct iwl_mvm_dump_ptrs *fw_error_dump;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEDS
|
||||
struct led_classdev led;
|
||||
@ -647,7 +675,8 @@ struct iwl_mvm {
|
||||
wait_queue_head_t d0i3_exit_waitq;
|
||||
|
||||
/* BT-Coex */
|
||||
u8 bt_kill_msk;
|
||||
u8 bt_ack_kill_msk[NUM_PHY_CTX];
|
||||
u8 bt_cts_kill_msk[NUM_PHY_CTX];
|
||||
|
||||
struct iwl_bt_coex_profile_notif_old last_bt_notif_old;
|
||||
struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old;
|
||||
@ -659,6 +688,9 @@ struct iwl_mvm {
|
||||
u8 bt_tx_prio;
|
||||
enum iwl_bt_force_ant_mode bt_force_ant_mode;
|
||||
|
||||
/* Aux ROC */
|
||||
struct list_head aux_roc_te_list;
|
||||
|
||||
/* Thermal Throttling and CTkill */
|
||||
struct iwl_mvm_tt_mgmt thermal_throttle;
|
||||
s32 temperature; /* Celsius */
|
||||
@ -697,6 +729,7 @@ enum iwl_mvm_status {
|
||||
IWL_MVM_STATUS_ROC_RUNNING,
|
||||
IWL_MVM_STATUS_IN_HW_RESTART,
|
||||
IWL_MVM_STATUS_IN_D0I3,
|
||||
IWL_MVM_STATUS_ROC_AUX_RUNNING,
|
||||
};
|
||||
|
||||
static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
|
||||
@ -988,6 +1021,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
|
||||
/* D0i3 */
|
||||
void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
|
||||
void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
|
||||
int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
|
||||
void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq);
|
||||
int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm);
|
||||
|
||||
@ -1029,12 +1063,14 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm,
|
||||
|
||||
enum iwl_bt_kill_msk {
|
||||
BT_KILL_MSK_DEFAULT,
|
||||
BT_KILL_MSK_SCO_HID_A2DP,
|
||||
BT_KILL_MSK_REDUCED_TXPOW,
|
||||
BT_KILL_MSK_NEVER,
|
||||
BT_KILL_MSK_ALWAYS,
|
||||
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];
|
||||
|
||||
extern const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT];
|
||||
extern const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT];
|
||||
extern const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX];
|
||||
|
||||
/* beacon filtering */
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
|
@ -265,7 +265,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
|
||||
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
|
||||
if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
|
||||
!mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
|
||||
IWL_ERR(mvm, "Can't parse empty NVM sections\n");
|
||||
IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n");
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
@ -273,7 +273,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
|
||||
if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
|
||||
!mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) {
|
||||
IWL_ERR(mvm,
|
||||
"Can't parse empty family 8000 NVM sections\n");
|
||||
"Can't parse empty family 8000 OTP/NVM sections\n");
|
||||
return NULL;
|
||||
}
|
||||
/* MAC_OVERRIDE or at least HW section must exist */
|
||||
|
@ -289,6 +289,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
|
||||
CMD(MATCH_FOUND_NOTIFICATION),
|
||||
CMD(SCAN_OFFLOAD_REQUEST_CMD),
|
||||
CMD(SCAN_OFFLOAD_ABORT_CMD),
|
||||
CMD(HOT_SPOT_CMD),
|
||||
CMD(SCAN_OFFLOAD_COMPLETE),
|
||||
CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
|
||||
CMD(SCAN_ITERATION_COMPLETE),
|
||||
@ -391,6 +392,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||
if (!hw)
|
||||
return NULL;
|
||||
|
||||
if (cfg->max_rx_agg_size)
|
||||
hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
|
||||
|
||||
op_mode = hw->priv;
|
||||
op_mode->ops = &iwl_mvm_ops;
|
||||
|
||||
@ -416,6 +420,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||
mutex_init(&mvm->d0i3_suspend_mutex);
|
||||
spin_lock_init(&mvm->async_handlers_lock);
|
||||
INIT_LIST_HEAD(&mvm->time_event_list);
|
||||
INIT_LIST_HEAD(&mvm->aux_roc_te_list);
|
||||
INIT_LIST_HEAD(&mvm->async_handlers_list);
|
||||
spin_lock_init(&mvm->time_event_lock);
|
||||
|
||||
@ -425,6 +430,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||
INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
|
||||
|
||||
spin_lock_init(&mvm->d0i3_tx_lock);
|
||||
spin_lock_init(&mvm->refs_lock);
|
||||
skb_queue_head_init(&mvm->d0i3_tx);
|
||||
init_waitqueue_head(&mvm->d0i3_exit_waitq);
|
||||
|
||||
@ -539,7 +545,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||
memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx));
|
||||
|
||||
/* rpm starts with a taken ref. only set the appropriate bit here. */
|
||||
set_bit(IWL_MVM_REF_UCODE_DOWN, mvm->ref_bitmap);
|
||||
mvm->refs[IWL_MVM_REF_UCODE_DOWN] = 1;
|
||||
|
||||
return op_mode;
|
||||
|
||||
@ -567,7 +573,11 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
|
||||
ieee80211_unregister_hw(mvm->hw);
|
||||
|
||||
kfree(mvm->scan_cmd);
|
||||
vfree(mvm->fw_error_dump);
|
||||
if (mvm->fw_error_dump) {
|
||||
vfree(mvm->fw_error_dump->op_mode_ptr);
|
||||
vfree(mvm->fw_error_dump->trans_ptr);
|
||||
kfree(mvm->fw_error_dump);
|
||||
}
|
||||
kfree(mvm->mcast_filter_cmd);
|
||||
mvm->mcast_filter_cmd = NULL;
|
||||
|
||||
|
@ -98,23 +98,21 @@ 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 add_sta_cmd = {
|
||||
.sta_id = mvm_sta->sta_id,
|
||||
.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color),
|
||||
.add_modify = update ? 1 : 0,
|
||||
.station_flags_msk = cpu_to_le32(STA_FLG_FAT_EN_MSK |
|
||||
STA_FLG_MIMO_EN_MSK),
|
||||
};
|
||||
int ret;
|
||||
u32 status;
|
||||
u32 agg_size = 0, mpdu_dens = 0;
|
||||
|
||||
memset(&add_sta_cmd, 0, sizeof(add_sta_cmd));
|
||||
|
||||
add_sta_cmd.sta_id = mvm_sta->sta_id;
|
||||
add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
|
||||
if (!update) {
|
||||
add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk);
|
||||
memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN);
|
||||
}
|
||||
add_sta_cmd.add_modify = update ? 1 : 0;
|
||||
|
||||
add_sta_cmd.station_flags_msk |= cpu_to_le32(STA_FLG_FAT_EN_MSK |
|
||||
STA_FLG_MIMO_EN_MSK);
|
||||
|
||||
switch (sta->bandwidth) {
|
||||
case IEEE80211_STA_RX_BW_160:
|
||||
@ -528,8 +526,12 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
/* Add the aux station, but without any queues */
|
||||
ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0,
|
||||
/* Map Aux queue to fifo - needs to happen before adding Aux station */
|
||||
iwl_trans_ac_txq_enable(mvm->trans, mvm->aux_queue,
|
||||
IWL_MVM_TX_FIFO_MCAST);
|
||||
|
||||
/* Allocate aux station and assign to it the aux queue */
|
||||
ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue),
|
||||
NL80211_IFTYPE_UNSPECIFIED);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -72,9 +72,6 @@
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-prph.h"
|
||||
|
||||
/* A TimeUnit is 1024 microsecond */
|
||||
#define MSEC_TO_TU(_msec) (_msec*1000/1024)
|
||||
|
||||
/*
|
||||
* For the high priority TE use a time event type that has similar priority to
|
||||
* the FW's action scan priority.
|
||||
@ -100,6 +97,21 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
|
||||
void iwl_mvm_roc_done_wk(struct work_struct *wk)
|
||||
{
|
||||
struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk);
|
||||
u32 queues = 0;
|
||||
|
||||
/*
|
||||
* Clear the ROC_RUNNING /ROC_AUX_RUNNING status bit.
|
||||
* This will cause the TX path to drop offchannel transmissions.
|
||||
* That would also be done by mac80211, but it is racy, in particular
|
||||
* in the case that the time event actually completed in the firmware
|
||||
* (which is handled in iwl_mvm_te_handle_notif).
|
||||
*/
|
||||
if (test_and_clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
|
||||
queues |= BIT(IWL_MVM_OFFCHANNEL_QUEUE);
|
||||
if (test_and_clear_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
|
||||
queues |= BIT(mvm->aux_queue);
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
|
||||
|
||||
synchronize_net();
|
||||
|
||||
@ -113,21 +125,11 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
|
||||
* issue as it will have to complete before the next command is
|
||||
* executed, and a new time event means a new command.
|
||||
*/
|
||||
iwl_mvm_flush_tx_path(mvm, BIT(IWL_MVM_OFFCHANNEL_QUEUE), false);
|
||||
iwl_mvm_flush_tx_path(mvm, queues, false);
|
||||
}
|
||||
|
||||
static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
|
||||
{
|
||||
/*
|
||||
* First, clear the ROC_RUNNING status bit. This will cause the TX
|
||||
* path to drop offchannel transmissions. That would also be done
|
||||
* by mac80211, but it is racy, in particular in the case that the
|
||||
* time event actually completed in the firmware (which is handled
|
||||
* in iwl_mvm_te_handle_notif).
|
||||
*/
|
||||
clear_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_ROC);
|
||||
|
||||
/*
|
||||
* Of course, our status bit is just as racy as mac80211, so in
|
||||
* addition, fire off the work struct which will drop all frames
|
||||
@ -262,6 +264,60 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle A Aux ROC time event
|
||||
*/
|
||||
static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
|
||||
struct iwl_time_event_notif *notif)
|
||||
{
|
||||
struct iwl_mvm_time_event_data *te_data, *tmp;
|
||||
bool aux_roc_te = false;
|
||||
|
||||
list_for_each_entry_safe(te_data, tmp, &mvm->aux_roc_te_list, list) {
|
||||
if (le32_to_cpu(notif->unique_id) == te_data->uid) {
|
||||
aux_roc_te = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!aux_roc_te) /* Not a Aux ROC time event */
|
||||
return -EINVAL;
|
||||
|
||||
if (!le32_to_cpu(notif->status)) {
|
||||
IWL_DEBUG_TE(mvm,
|
||||
"ERROR: Aux ROC Time Event %s notification failure\n",
|
||||
(le32_to_cpu(notif->action) &
|
||||
TE_V2_NOTIF_HOST_EVENT_START) ? "start" : "end");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
IWL_DEBUG_TE(mvm,
|
||||
"Aux ROC time event notification - UID = 0x%x action %d\n",
|
||||
le32_to_cpu(notif->unique_id),
|
||||
le32_to_cpu(notif->action));
|
||||
|
||||
if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_END) {
|
||||
/* End TE, notify mac80211 */
|
||||
ieee80211_remain_on_channel_expired(mvm->hw);
|
||||
iwl_mvm_roc_finished(mvm); /* flush aux queue */
|
||||
list_del(&te_data->list); /* remove from list */
|
||||
te_data->running = false;
|
||||
te_data->vif = NULL;
|
||||
te_data->uid = 0;
|
||||
} else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
|
||||
set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
|
||||
set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
|
||||
te_data->running = true;
|
||||
ieee80211_ready_on_channel(mvm->hw); /* Start TE */
|
||||
} else {
|
||||
IWL_DEBUG_TE(mvm,
|
||||
"ERROR: Unknown Aux ROC Time Event (action = %d)\n",
|
||||
le32_to_cpu(notif->action));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Rx handler for time event notifications
|
||||
*/
|
||||
@ -278,10 +334,15 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
|
||||
le32_to_cpu(notif->action));
|
||||
|
||||
spin_lock_bh(&mvm->time_event_lock);
|
||||
/* This time event is triggered for Aux ROC request */
|
||||
if (!iwl_mvm_aux_roc_te_handle_notif(mvm, notif))
|
||||
goto unlock;
|
||||
|
||||
list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) {
|
||||
if (le32_to_cpu(notif->unique_id) == te_data->uid)
|
||||
iwl_mvm_te_handle_notif(mvm, te_data, notif);
|
||||
}
|
||||
unlock:
|
||||
spin_unlock_bh(&mvm->time_event_lock);
|
||||
|
||||
return 0;
|
||||
|
@ -140,9 +140,9 @@ static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm)
|
||||
|
||||
/* TODO: move parsing to NVM code */
|
||||
calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data;
|
||||
ptat = calib[OTP_DTS_DIODE_DEVIATION];
|
||||
pa1 = calib[OTP_DTS_DIODE_DEVIATION + 1];
|
||||
pa2 = calib[OTP_DTS_DIODE_DEVIATION + 2];
|
||||
ptat = calib[OTP_DTS_DIODE_DEVIATION * 2];
|
||||
pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1];
|
||||
pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2];
|
||||
|
||||
/* get the median: */
|
||||
if (ptat > pa1) {
|
||||
@ -338,10 +338,16 @@ static void check_exit_ctkill(struct work_struct *work)
|
||||
|
||||
duration = tt->params->ct_kill_duration;
|
||||
|
||||
/* make sure the device is available for direct read/writes */
|
||||
if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_CHECK_CTKILL))
|
||||
goto reschedule;
|
||||
|
||||
iwl_trans_start_hw(mvm->trans);
|
||||
temp = check_nic_temperature(mvm);
|
||||
iwl_trans_stop_device(mvm->trans);
|
||||
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
|
||||
|
||||
if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) {
|
||||
IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
|
||||
goto reschedule;
|
||||
|
@ -310,6 +310,16 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
||||
info->hw_queue != info->control.vif->cab_queue)))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used
|
||||
* in 2 different types of vifs, P2P & STATION. P2P uses the offchannel
|
||||
* queue. STATION (HS2.0) uses the auxiliary context of the FW,
|
||||
* and hence needs to be sent on the aux queue
|
||||
*/
|
||||
if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
|
||||
info->control.vif->type == NL80211_IFTYPE_STATION)
|
||||
IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue;
|
||||
|
||||
/*
|
||||
* If the interface on which frame is sent is the P2P_DEVICE
|
||||
* or an AP/GO interface use the broadcast station associated
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "iwl-drv.h"
|
||||
#include "iwl-trans.h"
|
||||
@ -1773,28 +1774,207 @@ static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
|
||||
return cmdlen;
|
||||
}
|
||||
|
||||
static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
|
||||
void *buf, u32 buflen)
|
||||
static const struct {
|
||||
u32 start, end;
|
||||
} iwl_prph_dump_addr[] = {
|
||||
{ .start = 0x00a00000, .end = 0x00a00000 },
|
||||
{ .start = 0x00a0000c, .end = 0x00a00024 },
|
||||
{ .start = 0x00a0002c, .end = 0x00a0003c },
|
||||
{ .start = 0x00a00410, .end = 0x00a00418 },
|
||||
{ .start = 0x00a00420, .end = 0x00a00420 },
|
||||
{ .start = 0x00a00428, .end = 0x00a00428 },
|
||||
{ .start = 0x00a00430, .end = 0x00a0043c },
|
||||
{ .start = 0x00a00444, .end = 0x00a00444 },
|
||||
{ .start = 0x00a004c0, .end = 0x00a004cc },
|
||||
{ .start = 0x00a004d8, .end = 0x00a004d8 },
|
||||
{ .start = 0x00a004e0, .end = 0x00a004f0 },
|
||||
{ .start = 0x00a00840, .end = 0x00a00840 },
|
||||
{ .start = 0x00a00850, .end = 0x00a00858 },
|
||||
{ .start = 0x00a01004, .end = 0x00a01008 },
|
||||
{ .start = 0x00a01010, .end = 0x00a01010 },
|
||||
{ .start = 0x00a01018, .end = 0x00a01018 },
|
||||
{ .start = 0x00a01024, .end = 0x00a01024 },
|
||||
{ .start = 0x00a0102c, .end = 0x00a01034 },
|
||||
{ .start = 0x00a0103c, .end = 0x00a01040 },
|
||||
{ .start = 0x00a01048, .end = 0x00a01094 },
|
||||
{ .start = 0x00a01c00, .end = 0x00a01c20 },
|
||||
{ .start = 0x00a01c58, .end = 0x00a01c58 },
|
||||
{ .start = 0x00a01c7c, .end = 0x00a01c7c },
|
||||
{ .start = 0x00a01c28, .end = 0x00a01c54 },
|
||||
{ .start = 0x00a01c5c, .end = 0x00a01c5c },
|
||||
{ .start = 0x00a01c84, .end = 0x00a01c84 },
|
||||
{ .start = 0x00a01ce0, .end = 0x00a01d0c },
|
||||
{ .start = 0x00a01d18, .end = 0x00a01d20 },
|
||||
{ .start = 0x00a01d2c, .end = 0x00a01d30 },
|
||||
{ .start = 0x00a01d40, .end = 0x00a01d5c },
|
||||
{ .start = 0x00a01d80, .end = 0x00a01d80 },
|
||||
{ .start = 0x00a01d98, .end = 0x00a01d98 },
|
||||
{ .start = 0x00a01dc0, .end = 0x00a01dfc },
|
||||
{ .start = 0x00a01e00, .end = 0x00a01e2c },
|
||||
{ .start = 0x00a01e40, .end = 0x00a01e60 },
|
||||
{ .start = 0x00a01e84, .end = 0x00a01e90 },
|
||||
{ .start = 0x00a01e9c, .end = 0x00a01ec4 },
|
||||
{ .start = 0x00a01ed0, .end = 0x00a01ed0 },
|
||||
{ .start = 0x00a01f00, .end = 0x00a01f14 },
|
||||
{ .start = 0x00a01f44, .end = 0x00a01f58 },
|
||||
{ .start = 0x00a01f80, .end = 0x00a01fa8 },
|
||||
{ .start = 0x00a01fb0, .end = 0x00a01fbc },
|
||||
{ .start = 0x00a01ff8, .end = 0x00a01ffc },
|
||||
{ .start = 0x00a02000, .end = 0x00a02048 },
|
||||
{ .start = 0x00a02068, .end = 0x00a020f0 },
|
||||
{ .start = 0x00a02100, .end = 0x00a02118 },
|
||||
{ .start = 0x00a02140, .end = 0x00a0214c },
|
||||
{ .start = 0x00a02168, .end = 0x00a0218c },
|
||||
{ .start = 0x00a021c0, .end = 0x00a021c0 },
|
||||
{ .start = 0x00a02400, .end = 0x00a02410 },
|
||||
{ .start = 0x00a02418, .end = 0x00a02420 },
|
||||
{ .start = 0x00a02428, .end = 0x00a0242c },
|
||||
{ .start = 0x00a02434, .end = 0x00a02434 },
|
||||
{ .start = 0x00a02440, .end = 0x00a02460 },
|
||||
{ .start = 0x00a02468, .end = 0x00a024b0 },
|
||||
{ .start = 0x00a024c8, .end = 0x00a024cc },
|
||||
{ .start = 0x00a02500, .end = 0x00a02504 },
|
||||
{ .start = 0x00a0250c, .end = 0x00a02510 },
|
||||
{ .start = 0x00a02540, .end = 0x00a02554 },
|
||||
{ .start = 0x00a02580, .end = 0x00a025f4 },
|
||||
{ .start = 0x00a02600, .end = 0x00a0260c },
|
||||
{ .start = 0x00a02648, .end = 0x00a02650 },
|
||||
{ .start = 0x00a02680, .end = 0x00a02680 },
|
||||
{ .start = 0x00a026c0, .end = 0x00a026d0 },
|
||||
{ .start = 0x00a02700, .end = 0x00a0270c },
|
||||
{ .start = 0x00a02804, .end = 0x00a02804 },
|
||||
{ .start = 0x00a02818, .end = 0x00a0281c },
|
||||
{ .start = 0x00a02c00, .end = 0x00a02db4 },
|
||||
{ .start = 0x00a02df4, .end = 0x00a02fb0 },
|
||||
{ .start = 0x00a03000, .end = 0x00a03014 },
|
||||
{ .start = 0x00a0301c, .end = 0x00a0302c },
|
||||
{ .start = 0x00a03034, .end = 0x00a03038 },
|
||||
{ .start = 0x00a03040, .end = 0x00a03048 },
|
||||
{ .start = 0x00a03060, .end = 0x00a03068 },
|
||||
{ .start = 0x00a03070, .end = 0x00a03074 },
|
||||
{ .start = 0x00a0307c, .end = 0x00a0307c },
|
||||
{ .start = 0x00a03080, .end = 0x00a03084 },
|
||||
{ .start = 0x00a0308c, .end = 0x00a03090 },
|
||||
{ .start = 0x00a03098, .end = 0x00a03098 },
|
||||
{ .start = 0x00a030a0, .end = 0x00a030a0 },
|
||||
{ .start = 0x00a030a8, .end = 0x00a030b4 },
|
||||
{ .start = 0x00a030bc, .end = 0x00a030bc },
|
||||
{ .start = 0x00a030c0, .end = 0x00a0312c },
|
||||
{ .start = 0x00a03c00, .end = 0x00a03c5c },
|
||||
{ .start = 0x00a04400, .end = 0x00a04454 },
|
||||
{ .start = 0x00a04460, .end = 0x00a04474 },
|
||||
{ .start = 0x00a044c0, .end = 0x00a044ec },
|
||||
{ .start = 0x00a04500, .end = 0x00a04504 },
|
||||
{ .start = 0x00a04510, .end = 0x00a04538 },
|
||||
{ .start = 0x00a04540, .end = 0x00a04548 },
|
||||
{ .start = 0x00a04560, .end = 0x00a0457c },
|
||||
{ .start = 0x00a04590, .end = 0x00a04598 },
|
||||
{ .start = 0x00a045c0, .end = 0x00a045f4 },
|
||||
};
|
||||
|
||||
static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans,
|
||||
struct iwl_fw_error_dump_data **data)
|
||||
{
|
||||
struct iwl_fw_error_dump_prph *prph;
|
||||
unsigned long flags;
|
||||
u32 prph_len = 0, i;
|
||||
|
||||
if (!iwl_trans_grab_nic_access(trans, false, &flags))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
|
||||
/* The range includes both boundaries */
|
||||
int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
|
||||
iwl_prph_dump_addr[i].start + 4;
|
||||
int reg;
|
||||
__le32 *val;
|
||||
|
||||
prph_len += sizeof(*data) + sizeof(*prph) +
|
||||
num_bytes_in_chunk;
|
||||
|
||||
(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
|
||||
(*data)->len = cpu_to_le32(sizeof(*prph) +
|
||||
num_bytes_in_chunk);
|
||||
prph = (void *)(*data)->data;
|
||||
prph->prph_start = cpu_to_le32(iwl_prph_dump_addr[i].start);
|
||||
val = (void *)prph->data;
|
||||
|
||||
for (reg = iwl_prph_dump_addr[i].start;
|
||||
reg <= iwl_prph_dump_addr[i].end;
|
||||
reg += 4)
|
||||
*val++ = cpu_to_le32(iwl_trans_pcie_read_prph(trans,
|
||||
reg));
|
||||
*data = iwl_fw_error_next_data(*data);
|
||||
}
|
||||
|
||||
iwl_trans_release_nic_access(trans, &flags);
|
||||
|
||||
return prph_len;
|
||||
}
|
||||
|
||||
#define IWL_CSR_TO_DUMP (0x250)
|
||||
|
||||
static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans,
|
||||
struct iwl_fw_error_dump_data **data)
|
||||
{
|
||||
u32 csr_len = sizeof(**data) + IWL_CSR_TO_DUMP;
|
||||
__le32 *val;
|
||||
int i;
|
||||
|
||||
(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_CSR);
|
||||
(*data)->len = cpu_to_le32(IWL_CSR_TO_DUMP);
|
||||
val = (void *)(*data)->data;
|
||||
|
||||
for (i = 0; i < IWL_CSR_TO_DUMP; i += 4)
|
||||
*val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i));
|
||||
|
||||
*data = iwl_fw_error_next_data(*data);
|
||||
|
||||
return csr_len;
|
||||
}
|
||||
|
||||
static
|
||||
struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_fw_error_dump_data *data;
|
||||
struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue];
|
||||
struct iwl_fw_error_dump_txcmd *txcmd;
|
||||
struct iwl_trans_dump_data *dump_data;
|
||||
u32 len;
|
||||
int i, ptr;
|
||||
|
||||
len = sizeof(*data) +
|
||||
/* transport dump header */
|
||||
len = sizeof(*dump_data);
|
||||
|
||||
/* host commands */
|
||||
len += sizeof(*data) +
|
||||
cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE);
|
||||
|
||||
/* CSR registers */
|
||||
len += sizeof(*data) + IWL_CSR_TO_DUMP;
|
||||
|
||||
/* PRPH registers */
|
||||
for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
|
||||
/* The range includes both boundaries */
|
||||
int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
|
||||
iwl_prph_dump_addr[i].start + 4;
|
||||
|
||||
len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) +
|
||||
num_bytes_in_chunk;
|
||||
}
|
||||
|
||||
/* FW monitor */
|
||||
if (trans_pcie->fw_mon_page)
|
||||
len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
|
||||
trans_pcie->fw_mon_size;
|
||||
|
||||
if (!buf)
|
||||
return len;
|
||||
dump_data = vzalloc(len);
|
||||
if (!dump_data)
|
||||
return NULL;
|
||||
|
||||
len = 0;
|
||||
data = buf;
|
||||
data = (void *)dump_data->data;
|
||||
data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD);
|
||||
txcmd = (void *)data->data;
|
||||
spin_lock_bh(&cmdq->lock);
|
||||
@ -1820,11 +2000,15 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
|
||||
|
||||
data->len = cpu_to_le32(len);
|
||||
len += sizeof(*data);
|
||||
data = iwl_fw_error_next_data(data);
|
||||
|
||||
len += iwl_trans_pcie_dump_prph(trans, &data);
|
||||
len += iwl_trans_pcie_dump_csr(trans, &data);
|
||||
/* data is already pointing to the next section */
|
||||
|
||||
if (trans_pcie->fw_mon_page) {
|
||||
struct iwl_fw_error_dump_fw_mon *fw_mon_data;
|
||||
|
||||
data = iwl_fw_error_next_data(data);
|
||||
data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR);
|
||||
data->len = cpu_to_le32(trans_pcie->fw_mon_size +
|
||||
sizeof(*fw_mon_data));
|
||||
@ -1852,7 +2036,9 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
|
||||
trans_pcie->fw_mon_size;
|
||||
}
|
||||
|
||||
return len;
|
||||
dump_data->len = len;
|
||||
|
||||
return dump_data;
|
||||
}
|
||||
#else
|
||||
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
|
||||
|
Loading…
Reference in New Issue
Block a user