Commit d878b3af authored by John W. Linville's avatar John W. Linville
parents 16e75453 f697267f
...@@ -20,16 +20,17 @@ config IWLWIFI ...@@ -20,16 +20,17 @@ config IWLWIFI
Intel 2000 Series Wi-Fi Adapters Intel 2000 Series Wi-Fi Adapters
Intel 7260 Wi-Fi Adapter Intel 7260 Wi-Fi Adapter
Intel 3160 Wi-Fi Adapter Intel 3160 Wi-Fi Adapter
Intel 7265 Wi-Fi Adapter
This driver uses the kernel's mac80211 subsystem. 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: 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 look in the hotplug script /etc/hotplug/firmware.agent to
determine which directory FIRMWARE_DIR is set to when the script determine which directory FIRMWARE_DIR is set to when the script
runs. runs.
...@@ -39,9 +40,10 @@ config IWLWIFI ...@@ -39,9 +40,10 @@ config IWLWIFI
say M here and read <file:Documentation/kbuild/modules.txt>. The say M here and read <file:Documentation/kbuild/modules.txt>. The
module will be called iwlwifi. module will be called iwlwifi.
if IWLWIFI
config IWLWIFI_LEDS config IWLWIFI_LEDS
bool bool
depends on IWLWIFI
depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI
select LEDS_TRIGGERS select LEDS_TRIGGERS
select MAC80211_LEDS select MAC80211_LEDS
...@@ -49,7 +51,7 @@ config IWLWIFI_LEDS ...@@ -49,7 +51,7 @@ config IWLWIFI_LEDS
config IWLDVM config IWLDVM
tristate "Intel Wireless WiFi DVM Firmware support" tristate "Intel Wireless WiFi DVM Firmware support"
depends on IWLWIFI depends on m
default IWLWIFI default IWLWIFI
help help
This is the driver that supports the DVM firmware which is This is the driver that supports the DVM firmware which is
...@@ -58,7 +60,7 @@ config IWLDVM ...@@ -58,7 +60,7 @@ config IWLDVM
config IWLMVM config IWLMVM
tristate "Intel Wireless WiFi MVM Firmware support" tristate "Intel Wireless WiFi MVM Firmware support"
depends on IWLWIFI depends on m
help help
This is the driver that supports the MVM firmware which is This is the driver that supports the MVM firmware which is
currently only available for 7260 and 3160 devices. currently only available for 7260 and 3160 devices.
...@@ -70,7 +72,7 @@ config IWLWIFI_OPMODE_MODULAR ...@@ -70,7 +72,7 @@ config IWLWIFI_OPMODE_MODULAR
default y if IWLMVM=m default y if IWLMVM=m
comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM" 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 config IWLWIFI_BCAST_FILTERING
bool "Enable broadcast filtering" bool "Enable broadcast filtering"
...@@ -86,11 +88,9 @@ config IWLWIFI_BCAST_FILTERING ...@@ -86,11 +88,9 @@ config IWLWIFI_BCAST_FILTERING
expect incoming broadcasts for their normal operations. expect incoming broadcasts for their normal operations.
menu "Debugging Options" menu "Debugging Options"
depends on IWLWIFI
config IWLWIFI_DEBUG config IWLWIFI_DEBUG
bool "Enable full debugging output in the iwlwifi driver" bool "Enable full debugging output in the iwlwifi driver"
depends on IWLWIFI
---help--- ---help---
This option will enable debug tracing output for the iwlwifi drivers This option will enable debug tracing output for the iwlwifi drivers
...@@ -115,7 +115,7 @@ config IWLWIFI_DEBUG ...@@ -115,7 +115,7 @@ config IWLWIFI_DEBUG
config IWLWIFI_DEBUGFS config IWLWIFI_DEBUGFS
bool "iwlwifi debugfs support" bool "iwlwifi debugfs support"
depends on IWLWIFI && MAC80211_DEBUGFS depends on MAC80211_DEBUGFS
---help--- ---help---
Enable creation of debugfs files for the iwlwifi drivers. This Enable creation of debugfs files for the iwlwifi drivers. This
is a low-impact option that allows getting insight into the is a low-impact option that allows getting insight into the
...@@ -123,13 +123,12 @@ config IWLWIFI_DEBUGFS ...@@ -123,13 +123,12 @@ config IWLWIFI_DEBUGFS
config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
bool "Experimental uCode support" bool "Experimental uCode support"
depends on IWLWIFI && IWLWIFI_DEBUG depends on IWLWIFI_DEBUG
---help--- ---help---
Enable use of experimental ucode for testing and debugging. Enable use of experimental ucode for testing and debugging.
config IWLWIFI_DEVICE_TRACING config IWLWIFI_DEVICE_TRACING
bool "iwlwifi device access tracing" bool "iwlwifi device access tracing"
depends on IWLWIFI
depends on EVENT_TRACING depends on EVENT_TRACING
help help
Say Y here to trace all commands, including TX frames and IO Say Y here to trace all commands, including TX frames and IO
...@@ -145,3 +144,5 @@ config IWLWIFI_DEVICE_TRACING ...@@ -145,3 +144,5 @@ config IWLWIFI_DEVICE_TRACING
If unsure, say Y so we can help you better when problems If unsure, say Y so we can help you better when problems
occur. occur.
endmenu endmenu
endif
...@@ -85,6 +85,9 @@ ...@@ -85,6 +85,9 @@
#define NVM_HW_SECTION_NUM_FAMILY_8000 10 #define NVM_HW_SECTION_NUM_FAMILY_8000 10
#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin" #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 = { static const struct iwl_base_params iwl8000_base_params = {
.eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000,
.num_of_queues = IWLAGN_NUM_QUEUES, .num_of_queues = IWLAGN_NUM_QUEUES,
...@@ -129,6 +132,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { ...@@ -129,6 +132,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.nvm_ver = IWL8000_NVM_VERSION, .nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000, .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)); MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
...@@ -240,6 +240,7 @@ struct iwl_pwr_tx_backoff { ...@@ -240,6 +240,7 @@ struct iwl_pwr_tx_backoff {
* @d0i3: device uses d0i3 instead of d3 * @d0i3: device uses d0i3 instead of d3
* @nvm_hw_section_num: the ID of the HW NVM section * @nvm_hw_section_num: the ID of the HW NVM section
* @pwr_tx_backoffs: translation table between power limits and backoffs * @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. * We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs * API differences in uCode shouldn't be handled here but through TLVs
...@@ -276,6 +277,7 @@ struct iwl_cfg { ...@@ -276,6 +277,7 @@ struct iwl_cfg {
const struct iwl_pwr_tx_backoff *pwr_tx_backoffs; const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
bool no_power_up_nic_in_init; bool no_power_up_nic_in_init;
const char *default_nvm_file; const char *default_nvm_file;
unsigned int max_rx_agg_size;
}; };
/* /*
......
...@@ -70,21 +70,24 @@ ...@@ -70,21 +70,24 @@
/** /**
* enum iwl_fw_error_dump_type - types of data in the dump file * enum iwl_fw_error_dump_type - types of data in the dump file
* @IWL_FW_ERROR_DUMP_SRAM: * @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_RXF:
* @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as
* &struct iwl_fw_error_dump_txcmd packets * &struct iwl_fw_error_dump_txcmd packets
* @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info
* info on the device / firmware. * info on the device / firmware.
* @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor * @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 { enum iwl_fw_error_dump_type {
IWL_FW_ERROR_DUMP_SRAM = 0, 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_RXF = 2,
IWL_FW_ERROR_DUMP_TXCMD = 3, IWL_FW_ERROR_DUMP_TXCMD = 3,
IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4, IWL_FW_ERROR_DUMP_DEV_FW_INFO = 4,
IWL_FW_ERROR_DUMP_FW_MONITOR = 5, IWL_FW_ERROR_DUMP_FW_MONITOR = 5,
IWL_FW_ERROR_DUMP_PRPH = 6,
IWL_FW_ERROR_DUMP_MAX, IWL_FW_ERROR_DUMP_MAX,
}; };
...@@ -162,6 +165,16 @@ struct iwl_fw_error_dump_fw_mon { ...@@ -162,6 +165,16 @@ struct iwl_fw_error_dump_fw_mon {
u8 data[]; u8 data[];
} __packed; } __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 * iwl_fw_error_next_data - advance fw error dump data pointer
* @data: previous data block * @data: previous data block
......
...@@ -99,7 +99,7 @@ enum iwl_disable_11n { ...@@ -99,7 +99,7 @@ enum iwl_disable_11n {
* @wd_disable: disable stuck queue check, default = 1 * @wd_disable: disable stuck queue check, default = 1
* @bt_coex_active: enable bt coex, default = true * @bt_coex_active: enable bt coex, default = true
* @led_mode: system default, default = 0 * @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 * @power_level: power level, default = 1
* @debug_level: levels are IWL_DL_* * @debug_level: levels are IWL_DL_*
* @ant_coupling: antenna coupling in dB, default = 0 * @ant_coupling: antenna coupling in dB, default = 0
......
...@@ -394,6 +394,11 @@ struct iwl_trans_config { ...@@ -394,6 +394,11 @@ struct iwl_trans_config {
const char *const *command_names; const char *const *command_names;
}; };
struct iwl_trans_dump_data {
u32 len;
u8 data[];
};
struct iwl_trans; struct iwl_trans;
/** /**
...@@ -461,10 +466,8 @@ struct iwl_trans; ...@@ -461,10 +466,8 @@ struct iwl_trans;
* @unref: release a reference previously taken with @ref. Note that * @unref: release a reference previously taken with @ref. Note that
* initially the reference count is 1, making an initial @unref * initially the reference count is 1, making an initial @unref
* necessary to allow low power states. * necessary to allow low power states.
* @dump_data: fill a data dump with debug data, maybe containing last * @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last
* TX'ed commands and similar. When called with a NULL buffer and * TX'ed commands and similar. The buffer will be vfree'd by the caller.
* zero buffer length, provide only the (estimated) required buffer
* length. Return the used buffer length.
* Note that the transport must fill in the proper file headers. * Note that the transport must fill in the proper file headers.
*/ */
struct iwl_trans_ops { struct iwl_trans_ops {
...@@ -518,7 +521,7 @@ struct iwl_trans_ops { ...@@ -518,7 +521,7 @@ struct iwl_trans_ops {
void (*unref)(struct iwl_trans *trans); void (*unref)(struct iwl_trans *trans);
#ifdef CONFIG_IWLWIFI_DEBUGFS #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 #endif
}; };
...@@ -685,12 +688,12 @@ static inline void iwl_trans_unref(struct iwl_trans *trans) ...@@ -685,12 +688,12 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
} }
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
static inline u32 iwl_trans_dump_data(struct iwl_trans *trans, static inline struct iwl_trans_dump_data *
void *buf, u32 buflen) iwl_trans_dump_data(struct iwl_trans *trans)
{ {
if (!trans->ops->dump_data) if (!trans->ops->dump_data)
return 0; return NULL;
return trans->ops->dump_data(trans, buf, buflen); return trans->ops->dump_data(trans);
} }
#endif #endif
......
This diff is collapsed.
...@@ -649,10 +649,6 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) ...@@ -649,10 +649,6 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
sizeof(iwl_bt_prio_boost)); sizeof(iwl_bt_prio_boost));
memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut, memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut,
sizeof(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: send_cmd:
memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); 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) ...@@ -664,12 +660,13 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
return ret; return ret;
} }
static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm)
bool reduced_tx_power)
{ {
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; 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 = { struct iwl_host_cmd cmd = {
.id = BT_CONFIG, .id = BT_CONFIG,
.data[0] = &bt_cmd, .data[0] = &bt_cmd,
...@@ -680,31 +677,15 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, ...@@ -680,31 +677,15 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
if (reduced_tx_power) { ack_kill_msk = iwl_bt_ack_kill_msk[ag][primary_lut];
/* Reduced Tx power has precedence on the type of the profile */ cts_kill_msk = iwl_bt_cts_kill_msk[ag][primary_lut];
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;
}
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 (mvm->bt_ack_kill_msk[0] == ack_kill_msk &&
if (bt_kill_msk == mvm->bt_kill_msk) mvm->bt_cts_kill_msk[0] == cts_kill_msk)
return 0; 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); bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL);
if (!bt_cmd) if (!bt_cmd)
...@@ -712,16 +693,12 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, ...@@ -712,16 +693,12 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
cmd.data[0] = bt_cmd; cmd.data[0] = bt_cmd;
bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); 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_ack_msk = cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk]);
bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_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_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_ENABLE |
BT_VALID_KILL_ACK | BT_VALID_KILL_ACK |
BT_VALID_KILL_CTS); 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); ret = iwl_mvm_send_cmd(mvm, &cmd);
kfree(bt_cmd); kfree(bt_cmd);
...@@ -777,8 +754,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, ...@@ -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_iterator_data {
struct iwl_bt_coex_profile_notif_old *notif; struct iwl_bt_coex_profile_notif_old *notif;
struct iwl_mvm *mvm; struct iwl_mvm *mvm;
u32 num_bss_ifaces;
bool reduced_tx_power;
struct ieee80211_chanctx_conf *primary; struct ieee80211_chanctx_conf *primary;
struct ieee80211_chanctx_conf *secondary; struct ieee80211_chanctx_conf *secondary;
bool primary_ll; bool primary_ll;
...@@ -814,22 +789,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -814,22 +789,12 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
switch (vif->type) { switch (vif->type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
/* Count BSSes vifs */
data->num_bss_ifaces++;
/* default smps_mode for BSS / P2P client is AUTOMATIC */ /* default smps_mode for BSS / P2P client is AUTOMATIC */
smps_mode = IEEE80211_SMPS_AUTOMATIC; smps_mode = IEEE80211_SMPS_AUTOMATIC;
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
/* default smps_mode for AP / GO is OFF */ if (!mvmvif->ap_ibss_active)
smps_mode = IEEE80211_SMPS_OFF;
if (!mvmvif->ap_ibss_active) {
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
smps_mode);
return; return;
}
/* the Ack / Cts kill mask must be default if AP / GO */
data->reduced_tx_power = false;
break; break;
default: default:
return; return;
...@@ -840,11 +805,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -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 channel context is invalid or not on 2.4GHz .. */
if ((!chanctx_conf || if ((!chanctx_conf ||
chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) { chanctx_conf->def.chan->band != IEEE80211_BAND_2GHZ)) {
if (vif->type == NL80211_IFTYPE_STATION) {
/* ... relax constraints and disable rssi events */ /* ... relax constraints and disable rssi events */
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
smps_mode); smps_mode);
data->reduced_tx_power = false;
if (vif->type == NL80211_IFTYPE_STATION) {
iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
false); false);
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); 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, ...@@ -869,7 +833,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
mvmvif->id, data->notif->bt_status, bt_activity_grading, mvmvif->id, data->notif->bt_status, bt_activity_grading,
smps_mode); 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 */ /* low latency is always primary */
if (iwl_mvm_vif_low_latency(mvmvif)) { if (iwl_mvm_vif_low_latency(mvmvif)) {
...@@ -920,7 +886,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -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 || if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc || mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc ||
!data->notif->bt_status) { !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_reduced_txp(mvm, mvmvif->ap_sta_id, false);
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
return; return;
...@@ -935,23 +900,9 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -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 (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true)) if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); 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) { } 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)) if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n"); 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 */ /* 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) ...@@ -963,7 +914,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
struct iwl_bt_iterator_data data = { struct iwl_bt_iterator_data data = {
.mvm = mvm, .mvm = mvm,
.notif = &mvm->last_bt_notif_old, .notif = &mvm->last_bt_notif_old,
.reduced_tx_power = true,
}; };
struct iwl_bt_coex_ci_cmd_old cmd = {}; struct iwl_bt_coex_ci_cmd_old cmd = {};
u8 ci_bw_idx; u8 ci_bw_idx;
...@@ -1037,14 +987,7 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) ...@@ -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)); memcpy(&mvm->last_bt_ci_cmd_old, &cmd, sizeof(cmd));
} }
/* if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm))
* 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))
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); 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, ...@@ -1115,16 +1058,6 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
return; return;
mvmsta = iwl_mvm_sta_from_mac80211(sta); 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, 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, ...@@ -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_mvm_vif *mvmvif = (void *)vif->drv_priv;
struct iwl_bt_iterator_data data = { struct iwl_bt_iterator_data data = {
.mvm = mvm, .mvm = mvm,
.reduced_tx_power = true,
}; };
int ret; int ret;
...@@ -1175,14 +1107,7 @@ void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -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, mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_bt_rssi_iterator, &data); iwl_mvm_bt_rssi_iterator, &data);
/* if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm))
* 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))
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); 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, ...@@ -146,17 +146,47 @@ static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file,
char __user *user_buf, char __user *user_buf,
size_t count, loff_t *ppos) 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, static int iwl_dbgfs_fw_error_dump_release(struct inode *inode,
struct file *file) 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; return 0;
} }
...@@ -514,9 +544,9 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, ...@@ -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, "BT Configuration CMD\n");
pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\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", 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 { } else {
struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; 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, ...@@ -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)); le64_to_cpu(cmd->bt_secondary_ci));
pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n");
pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", pos += scnprintf(buf+pos, bufsz-pos,
iwl_bt_ack_kill_msk[mvm->bt_kill_msk]); "\tPrimary: ACK Kill Mask 0x%08x\n",
pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]);
iwl_bt_cts_kill_msk[mvm->bt_kill_msk]); 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); mutex_unlock(&mvm->mutex);
...@@ -830,8 +869,14 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, ...@@ -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, static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos) 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_force_nmi(mvm->trans);
iwl_mvm_unref(mvm, IWL_MVM_REF_NMI);
return count; return count;
} }
...@@ -1116,10 +1161,10 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, ...@@ -1116,10 +1161,10 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
#endif #endif
#define PRINT_MVM_REF(ref) do { \ #define PRINT_MVM_REF(ref) do { \
if (test_bit(ref, mvm->ref_bitmap)) \ if (mvm->refs[ref]) \
pos += scnprintf(buf + pos, bufsz - pos, \ pos += scnprintf(buf + pos, bufsz - pos, \
"\t(0x%lx) %s\n", \ "\t(0x%lx): %d %s\n", \
BIT(ref), #ref); \ BIT(ref), mvm->refs[ref], #ref); \
} while (0) } while (0)
static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file, 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, ...@@ -1127,12 +1172,17 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct iwl_mvm *mvm = file->private_data; struct iwl_mvm *mvm = file->private_data;
int pos = 0; int i, pos = 0;
char buf[256]; char buf[256];
const size_t bufsz = sizeof(buf); const size_t bufsz = sizeof(buf);
u32 refs = 0;
pos += scnprintf(buf + pos, bufsz - pos, "taken mvm refs: 0x%lx\n", for (i = 0; i < IWL_MVM_REF_COUNT; i++)
mvm->ref_bitmap[0]); 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_UCODE_DOWN);
PRINT_MVM_REF(IWL_MVM_REF_SCAN); 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, ...@@ -1158,7 +1208,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_write(struct iwl_mvm *mvm, char *buf,
mutex_lock(&mvm->mutex); 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) if (value == 1 && !taken)
iwl_mvm_ref(mvm, IWL_MVM_REF_USER); iwl_mvm_ref(mvm, IWL_MVM_REF_USER);
else if (value == 0 && taken) else if (value == 0 && taken)
...@@ -1194,14 +1244,21 @@ iwl_dbgfs_prph_reg_read(struct file *file, ...@@ -1194,14 +1244,21 @@ iwl_dbgfs_prph_reg_read(struct file *file,
int pos = 0; int pos = 0;
char buf[32]; char buf[32];
const size_t bufsz = sizeof(buf); const size_t bufsz = sizeof(buf);
int ret;
if (!mvm->dbgfs_prph_reg_addr) if (!mvm->dbgfs_prph_reg_addr)
return -EINVAL; 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", pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n",
mvm->dbgfs_prph_reg_addr, mvm->dbgfs_prph_reg_addr,
iwl_read_prph(mvm->trans, 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); 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, ...@@ -1211,6 +1268,7 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
{ {
u8 args; u8 args;
u32 value; u32 value;
int ret;
args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value); args = sscanf(buf, "%i %i", &mvm->dbgfs_prph_reg_addr, &value);
/* if we only want to set the reg address - nothing more to do */ /* 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, ...@@ -1221,7 +1279,13 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf,
if (args != 2) if (args != 2)
return -EINVAL; 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_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value);
iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
out: out:
return count; return count;
} }
......
...@@ -385,6 +385,8 @@ enum iwl_bt_activity_grading { ...@@ -385,6 +385,8 @@ enum iwl_bt_activity_grading {
BT_ON_NO_CONNECTION = 1, BT_ON_NO_CONNECTION = 1,
BT_LOW_TRAFFIC = 2, BT_LOW_TRAFFIC = 2,
BT_HIGH_TRAFFIC = 3, BT_HIGH_TRAFFIC = 3,
BT_MAX_AG,
}; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */ }; /* BT_COEX_BT_ACTIVITY_GRADING_API_E_VER_1 */
enum iwl_bt_ci_compliance { enum iwl_bt_ci_compliance {
......
...@@ -133,6 +133,7 @@ enum { ...@@ -133,6 +133,7 @@ enum {
/* Scan offload */ /* Scan offload */
SCAN_OFFLOAD_REQUEST_CMD = 0x51, SCAN_OFFLOAD_REQUEST_CMD = 0x51,
SCAN_OFFLOAD_ABORT_CMD = 0x52, SCAN_OFFLOAD_ABORT_CMD = 0x52,
HOT_SPOT_CMD = 0x53,
SCAN_OFFLOAD_COMPLETE = 0x6D, SCAN_OFFLOAD_COMPLETE = 0x6D,
SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
SCAN_OFFLOAD_CONFIG_CMD = 0x6f, SCAN_OFFLOAD_CONFIG_CMD = 0x6f,
...@@ -910,6 +911,72 @@ struct iwl_phy_context_cmd { ...@@ -910,6 +911,72 @@ struct iwl_phy_context_cmd {
__le32 dsp_cfg_flags; __le32 dsp_cfg_flags;
} __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ } __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_PHY_CNT 8
#define IWL_RX_INFO_ENERGY_ANT_ABC_IDX 1 #define IWL_RX_INFO_ENERGY_ANT_ABC_IDX 1
#define IWL_RX_INFO_ENERGY_ANT_A_MSK 0x000000ff #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, ...@@ -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 */ /* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 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 */ /* Fill the data specific for ap mode */
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap, 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, ...@@ -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 */ /* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 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 */ /* Fill the data specific for GO mode */
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap, iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap,
action == FW_CTXT_ACTION_ADD); action == FW_CTXT_ACTION_ADD);
......
This diff is collapsed.
...@@ -82,6 +82,8 @@ ...@@ -82,6 +82,8 @@
/* RSSI offset for WkP */ /* RSSI offset for WkP */
#define IWL_RSSI_OFFSET 50 #define IWL_RSSI_OFFSET 50
#define IWL_MVM_MISSED_BEACONS_THRESHOLD 8 #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" * The CSA NoA is scheduled IWL_MVM_CHANNEL_SWITCH_TIME TUs before "beacon 0"
...@@ -126,6 +128,21 @@ struct iwl_mvm_mod_params { ...@@ -126,6 +128,21 @@ struct iwl_mvm_mod_params {
}; };
extern struct iwl_mvm_mod_params iwlmvm_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 { struct iwl_mvm_phy_ctxt {
u16 id; u16 id;
u16 color; u16 color;
...@@ -249,6 +266,15 @@ enum iwl_mvm_ref_type { ...@@ -249,6 +266,15 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_TX, IWL_MVM_REF_TX,
IWL_MVM_REF_TX_AGG, IWL_MVM_REF_TX_AGG,
IWL_MVM_REF_ADD_IF, 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_EXIT_WORK,
IWL_MVM_REF_COUNT, IWL_MVM_REF_COUNT,
...@@ -327,6 +353,7 @@ struct iwl_mvm_vif { ...@@ -327,6 +353,7 @@ struct iwl_mvm_vif {
*/ */
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; 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 time_event_data;
struct iwl_mvm_time_event_data hs_time_event_data;
struct iwl_mvm_int_sta bcast_sta; struct iwl_mvm_int_sta bcast_sta;
...@@ -606,14 +633,15 @@ struct iwl_mvm { ...@@ -606,14 +633,15 @@ struct iwl_mvm {
*/ */
unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
/* A bitmap of reference types taken by the driver. */ /* references taken by the driver and spinlock protecting them */
unsigned long ref_bitmap[BITS_TO_LONGS(IWL_MVM_REF_COUNT)]; spinlock_t refs_lock;
u8 refs[IWL_MVM_REF_COUNT];
u8 vif_count; u8 vif_count;
/* -1 for always, 0 for never, >0 for that many times */ /* -1 for always, 0 for never, >0 for that many times */
s8 restart_fw; s8 restart_fw;
void *fw_error_dump; struct iwl_mvm_dump_ptrs *fw_error_dump;
#ifdef CONFIG_IWLWIFI_LEDS #ifdef CONFIG_IWLWIFI_LEDS
struct led_classdev led; struct led_classdev led;
...@@ -647,7 +675,8 @@ struct iwl_mvm { ...@@ -647,7 +675,8 @@ struct iwl_mvm {
wait_queue_head_t d0i3_exit_waitq; wait_queue_head_t d0i3_exit_waitq;
/* BT-Coex */ /* 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_profile_notif_old last_bt_notif_old;
struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old; struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old;
...@@ -659,6 +688,9 @@ struct iwl_mvm { ...@@ -659,6 +688,9 @@ struct iwl_mvm {
u8 bt_tx_prio; u8 bt_tx_prio;
enum iwl_bt_force_ant_mode bt_force_ant_mode; enum iwl_bt_force_ant_mode bt_force_ant_mode;
/* Aux ROC */
struct list_head aux_roc_te_list;
/* Thermal Throttling and CTkill */ /* Thermal Throttling and CTkill */
struct iwl_mvm_tt_mgmt thermal_throttle; struct iwl_mvm_tt_mgmt thermal_throttle;
s32 temperature; /* Celsius */ s32 temperature; /* Celsius */
...@@ -697,6 +729,7 @@ enum iwl_mvm_status { ...@@ -697,6 +729,7 @@ enum iwl_mvm_status {
IWL_MVM_STATUS_ROC_RUNNING, IWL_MVM_STATUS_ROC_RUNNING,
IWL_MVM_STATUS_IN_HW_RESTART, IWL_MVM_STATUS_IN_HW_RESTART,
IWL_MVM_STATUS_IN_D0I3, IWL_MVM_STATUS_IN_D0I3,
IWL_MVM_STATUS_ROC_AUX_RUNNING,
}; };
static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) 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, ...@@ -988,6 +1021,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
/* D0i3 */ /* D0i3 */
void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type); 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); 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); void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq);
int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); 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, ...@@ -1029,12 +1063,14 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm,
enum iwl_bt_kill_msk { enum iwl_bt_kill_msk {
BT_KILL_MSK_DEFAULT, BT_KILL_MSK_DEFAULT,
BT_KILL_MSK_SCO_HID_A2DP, BT_KILL_MSK_NEVER,
BT_KILL_MSK_REDUCED_TXPOW, BT_KILL_MSK_ALWAYS,
BT_KILL_MSK_MAX, 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 */ /* beacon filtering */
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
......
...@@ -265,7 +265,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) ...@@ -265,7 +265,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
!mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].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; return NULL;
} }
} else { } else {
...@@ -273,7 +273,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) ...@@ -273,7 +273,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data || if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
!mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) { !mvm->nvm_sections[NVM_SECTION_TYPE_REGULATORY].data) {
IWL_ERR(mvm, IWL_ERR(mvm,
"Can't parse empty family 8000 NVM sections\n"); "Can't parse empty family 8000 OTP/NVM sections\n");
return NULL; return NULL;
} }
/* MAC_OVERRIDE or at least HW section must exist */ /* MAC_OVERRIDE or at least HW section must exist */
......
...@@ -289,6 +289,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { ...@@ -289,6 +289,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(MATCH_FOUND_NOTIFICATION), CMD(MATCH_FOUND_NOTIFICATION),
CMD(SCAN_OFFLOAD_REQUEST_CMD), CMD(SCAN_OFFLOAD_REQUEST_CMD),
CMD(SCAN_OFFLOAD_ABORT_CMD), CMD(SCAN_OFFLOAD_ABORT_CMD),
CMD(HOT_SPOT_CMD),
CMD(SCAN_OFFLOAD_COMPLETE), CMD(SCAN_OFFLOAD_COMPLETE),
CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
CMD(SCAN_ITERATION_COMPLETE), CMD(SCAN_ITERATION_COMPLETE),
...@@ -391,6 +392,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -391,6 +392,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (!hw) if (!hw)
return NULL; return NULL;
if (cfg->max_rx_agg_size)
hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
op_mode = hw->priv; op_mode = hw->priv;
op_mode->ops = &iwl_mvm_ops; op_mode->ops = &iwl_mvm_ops;
...@@ -416,6 +420,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -416,6 +420,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mutex_init(&mvm->d0i3_suspend_mutex); mutex_init(&mvm->d0i3_suspend_mutex);
spin_lock_init(&mvm->async_handlers_lock); spin_lock_init(&mvm->async_handlers_lock);
INIT_LIST_HEAD(&mvm->time_event_list); INIT_LIST_HEAD(&mvm->time_event_list);
INIT_LIST_HEAD(&mvm->aux_roc_te_list);
INIT_LIST_HEAD(&mvm->async_handlers_list); INIT_LIST_HEAD(&mvm->async_handlers_list);
spin_lock_init(&mvm->time_event_lock); 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, ...@@ -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); INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
spin_lock_init(&mvm->d0i3_tx_lock); spin_lock_init(&mvm->d0i3_tx_lock);
spin_lock_init(&mvm->refs_lock);
skb_queue_head_init(&mvm->d0i3_tx); skb_queue_head_init(&mvm->d0i3_tx);
init_waitqueue_head(&mvm->d0i3_exit_waitq); 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, ...@@ -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)); memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx));
/* rpm starts with a taken ref. only set the appropriate bit here. */ /* 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; return op_mode;
...@@ -567,7 +573,11 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) ...@@ -567,7 +573,11 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
ieee80211_unregister_hw(mvm->hw); ieee80211_unregister_hw(mvm->hw);
kfree(mvm->scan_cmd); 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); kfree(mvm->mcast_filter_cmd);
mvm->mcast_filter_cmd = NULL; mvm->mcast_filter_cmd = NULL;
......
...@@ -98,23 +98,21 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -98,23 +98,21 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
bool update) bool update)
{ {
struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; 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; int ret;
u32 status; u32 status;
u32 agg_size = 0, mpdu_dens = 0; 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) { if (!update) {
add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk);
memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); 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) { switch (sta->bandwidth) {
case IEEE80211_STA_RX_BW_160: case IEEE80211_STA_RX_BW_160:
...@@ -528,8 +526,12 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) ...@@ -528,8 +526,12 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
/* Add the aux station, but without any queues */ /* Map Aux queue to fifo - needs to happen before adding Aux station */
ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, 0, 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); NL80211_IFTYPE_UNSPECIFIED);
if (ret) if (ret)
return ret; return ret;
......
...@@ -72,9 +72,6 @@ ...@@ -72,9 +72,6 @@
#include "iwl-io.h" #include "iwl-io.h"
#include "iwl-prph.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 * For the high priority TE use a time event type that has similar priority to
* the FW's action scan priority. * the FW's action scan priority.
...@@ -100,6 +97,21 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, ...@@ -100,6 +97,21 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
void iwl_mvm_roc_done_wk(struct work_struct *wk) void iwl_mvm_roc_done_wk(struct work_struct *wk)
{ {
struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_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(); synchronize_net();
...@@ -113,21 +125,11 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) ...@@ -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 * issue as it will have to complete before the next command is
* executed, and a new time event means a new command. * 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) 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 * Of course, our status bit is just as racy as mac80211, so in
* addition, fire off the work struct which will drop all frames * 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, ...@@ -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 * The Rx handler for time event notifications
*/ */
...@@ -278,10 +334,15 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, ...@@ -278,10 +334,15 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
le32_to_cpu(notif->action)); le32_to_cpu(notif->action));
spin_lock_bh(&mvm->time_event_lock); 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) { list_for_each_entry_safe(te_data, tmp, &mvm->time_event_list, list) {
if (le32_to_cpu(notif->unique_id) == te_data->uid) if (le32_to_cpu(notif->unique_id) == te_data->uid)
iwl_mvm_te_handle_notif(mvm, te_data, notif); iwl_mvm_te_handle_notif(mvm, te_data, notif);
} }
unlock:
spin_unlock_bh(&mvm->time_event_lock); spin_unlock_bh(&mvm->time_event_lock);
return 0; return 0;
......
...@@ -140,9 +140,9 @@ static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) ...@@ -140,9 +140,9 @@ static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm)
/* TODO: move parsing to NVM code */ /* TODO: move parsing to NVM code */
calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data; calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data;
ptat = calib[OTP_DTS_DIODE_DEVIATION]; ptat = calib[OTP_DTS_DIODE_DEVIATION * 2];
pa1 = calib[OTP_DTS_DIODE_DEVIATION + 1]; pa1 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 1];
pa2 = calib[OTP_DTS_DIODE_DEVIATION + 2]; pa2 = calib[OTP_DTS_DIODE_DEVIATION * 2 + 2];
/* get the median: */ /* get the median: */
if (ptat > pa1) { if (ptat > pa1) {
...@@ -338,10 +338,16 @@ static void check_exit_ctkill(struct work_struct *work) ...@@ -338,10 +338,16 @@ static void check_exit_ctkill(struct work_struct *work)
duration = tt->params->ct_kill_duration; 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); iwl_trans_start_hw(mvm->trans);
temp = check_nic_temperature(mvm); temp = check_nic_temperature(mvm);
iwl_trans_stop_device(mvm->trans); iwl_trans_stop_device(mvm->trans);
iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) {
IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
goto reschedule; goto reschedule;
......
...@@ -310,6 +310,16 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) ...@@ -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))) info->hw_queue != info->control.vif->cab_queue)))
return -1; 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 * If the interface on which frame is sent is the P2P_DEVICE
* or an AP/GO interface use the broadcast station associated * or an AP/GO interface use the broadcast station associated
......
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/vmalloc.h>
#include "iwl-drv.h" #include "iwl-drv.h"
#include "iwl-trans.h" #include "iwl-trans.h"
...@@ -1773,28 +1774,207 @@ static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd) ...@@ -1773,28 +1774,207 @@ static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
return cmdlen; return cmdlen;
} }
static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, static const struct {
void *buf, u32 buflen) 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_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_fw_error_dump_data *data; struct iwl_fw_error_dump_data *data;
struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue];
struct iwl_fw_error_dump_txcmd *txcmd; struct iwl_fw_error_dump_txcmd *txcmd;
struct iwl_trans_dump_data *dump_data;
u32 len; u32 len;
int i, ptr; 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); 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) if (trans_pcie->fw_mon_page)
len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
trans_pcie->fw_mon_size; trans_pcie->fw_mon_size;
if (!buf) dump_data = vzalloc(len);
return len; if (!dump_data)
return NULL;
len = 0; len = 0;
data = buf; data = (void *)dump_data->data;
data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD); data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD);
txcmd = (void *)data->data; txcmd = (void *)data->data;
spin_lock_bh(&cmdq->lock); spin_lock_bh(&cmdq->lock);
...@@ -1820,11 +2000,15 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, ...@@ -1820,11 +2000,15 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
data->len = cpu_to_le32(len); data->len = cpu_to_le32(len);
len += sizeof(*data); 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) { if (trans_pcie->fw_mon_page) {
struct iwl_fw_error_dump_fw_mon *fw_mon_data; 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->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR);
data->len = cpu_to_le32(trans_pcie->fw_mon_size + data->len = cpu_to_le32(trans_pcie->fw_mon_size +
sizeof(*fw_mon_data)); sizeof(*fw_mon_data));
...@@ -1852,7 +2036,9 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans, ...@@ -1852,7 +2036,9 @@ static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
trans_pcie->fw_mon_size; trans_pcie->fw_mon_size;
} }
return len; dump_data->len = len;
return dump_data;
} }
#else #else
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment