diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2015-02-06 01:57:37 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-02-06 01:57:37 -0500 |
commit | 8cd4cbf249483822c6d52109b3d6ec6fd189a32b (patch) | |
tree | 2fb0e2e4f54bd2eca28cc22ce00c74268d32f45c | |
parent | 297540f69fa9c7292c9866e71cb22a7bc4c5003b (diff) | |
parent | b9a641d9cb768177a7c867e382a2fdb6023b06ad (diff) |
Merge tag 'iwlwifi-next-for-kalle-2015-02-03' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
* Add support for beamforming
* Enable stuck queue detection for iwlmvm
* A few fixes for EBS scan
* Fixes for various failure paths
* Improvements for TDLS Offchannel
26 files changed, 503 insertions, 176 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index de43dd7e170a..c4d6dd7402d9 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c | |||
@@ -1228,11 +1228,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | |||
1228 | trans_cfg.no_reclaim_cmds = no_reclaim_cmds; | 1228 | trans_cfg.no_reclaim_cmds = no_reclaim_cmds; |
1229 | trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); | 1229 | trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); |
1230 | trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; | 1230 | trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; |
1231 | if (!iwlwifi_mod_params.wd_disable) | 1231 | trans_cfg.cmd_q_wdg_timeout = IWL_WATCHDOG_DISABLED; |
1232 | trans_cfg.queue_watchdog_timeout = | 1232 | |
1233 | priv->cfg->base_params->wd_timeout; | ||
1234 | else | ||
1235 | trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; | ||
1236 | trans_cfg.command_names = iwl_dvm_cmd_strings; | 1233 | trans_cfg.command_names = iwl_dvm_cmd_strings; |
1237 | trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM; | 1234 | trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM; |
1238 | 1235 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index d1ce3ce13591..1e40a12de077 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -715,7 +715,7 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
715 | fifo = ctx->ac_to_fifo[tid_to_ac[tid]]; | 715 | fifo = ctx->ac_to_fifo[tid_to_ac[tid]]; |
716 | 716 | ||
717 | iwl_trans_txq_enable(priv->trans, q, fifo, sta_priv->sta_id, tid, | 717 | iwl_trans_txq_enable(priv->trans, q, fifo, sta_priv->sta_id, tid, |
718 | buf_size, ssn); | 718 | buf_size, ssn, 0); |
719 | 719 | ||
720 | /* | 720 | /* |
721 | * If the limit is 0, then it wasn't initialised yet, | 721 | * If the limit is 0, then it wasn't initialised yet, |
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index d5cee1530597..4dbef7e58c2e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c | |||
@@ -267,7 +267,7 @@ static int iwl_alive_notify(struct iwl_priv *priv) | |||
267 | for (i = 0; i < n_queues; i++) | 267 | for (i = 0; i < n_queues; i++) |
268 | if (queue_to_txf[i] != IWL_TX_FIFO_UNUSED) | 268 | if (queue_to_txf[i] != IWL_TX_FIFO_UNUSED) |
269 | iwl_trans_ac_txq_enable(priv->trans, i, | 269 | iwl_trans_ac_txq_enable(priv->trans, i, |
270 | queue_to_txf[i]); | 270 | queue_to_txf[i], 0); |
271 | 271 | ||
272 | priv->passive_no_rx = false; | 272 | priv->passive_no_rx = false; |
273 | priv->transport_queue_stop = 0; | 273 | priv->transport_queue_stop = 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 445bff690a63..4b190d98a1ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h | |||
@@ -126,7 +126,7 @@ enum iwl_led_mode { | |||
126 | 126 | ||
127 | /* TX queue watchdog timeouts in mSecs */ | 127 | /* TX queue watchdog timeouts in mSecs */ |
128 | #define IWL_WATCHDOG_DISABLED 0 | 128 | #define IWL_WATCHDOG_DISABLED 0 |
129 | #define IWL_DEF_WD_TIMEOUT 2000 | 129 | #define IWL_DEF_WD_TIMEOUT 2500 |
130 | #define IWL_LONG_WD_TIMEOUT 10000 | 130 | #define IWL_LONG_WD_TIMEOUT 10000 |
131 | #define IWL_MAX_WD_TIMEOUT 120000 | 131 | #define IWL_MAX_WD_TIMEOUT 120000 |
132 | 132 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index e7c0df6db6ee..996e7f16adf9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -1367,7 +1367,6 @@ struct iwl_mod_params iwlwifi_mod_params = { | |||
1367 | .restart_fw = true, | 1367 | .restart_fw = true, |
1368 | .bt_coex_active = true, | 1368 | .bt_coex_active = true, |
1369 | .power_level = IWL_POWER_INDEX_1, | 1369 | .power_level = IWL_POWER_INDEX_1, |
1370 | .wd_disable = true, | ||
1371 | .d0i3_disable = true, | 1370 | .d0i3_disable = true, |
1372 | #ifndef CONFIG_IWLWIFI_UAPSD | 1371 | #ifndef CONFIG_IWLWIFI_UAPSD |
1373 | .uapsd_disable = true, | 1372 | .uapsd_disable = true, |
@@ -1478,10 +1477,6 @@ module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling, | |||
1478 | MODULE_PARM_DESC(antenna_coupling, | 1477 | MODULE_PARM_DESC(antenna_coupling, |
1479 | "specify antenna coupling in dB (default: 0 dB)"); | 1478 | "specify antenna coupling in dB (default: 0 dB)"); |
1480 | 1479 | ||
1481 | module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO); | ||
1482 | MODULE_PARM_DESC(wd_disable, | ||
1483 | "Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)"); | ||
1484 | |||
1485 | module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); | 1480 | module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); |
1486 | MODULE_PARM_DESC(nvm_file, "NVM file name"); | 1481 | MODULE_PARM_DESC(nvm_file, "NVM file name"); |
1487 | 1482 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index e4f589898eda..016d91384681 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h | |||
@@ -270,6 +270,7 @@ enum iwl_ucode_tlv_api { | |||
270 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 | 270 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 |
271 | * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory | 271 | * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory |
272 | * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. | 272 | * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. |
273 | * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer | ||
273 | * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality | 274 | * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality |
274 | * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current | 275 | * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current |
275 | * tx power value into TPC Report action frame and Link Measurement Report | 276 | * tx power value into TPC Report action frame and Link Measurement Report |
@@ -288,6 +289,7 @@ enum iwl_ucode_tlv_capa { | |||
288 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), | 289 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), |
289 | IWL_UCODE_TLV_CAPA_LAR_SUPPORT = BIT(1), | 290 | IWL_UCODE_TLV_CAPA_LAR_SUPPORT = BIT(1), |
290 | IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2), | 291 | IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2), |
292 | IWL_UCODE_TLV_CAPA_BEAMFORMER = BIT(3), | ||
291 | IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = BIT(6), | 293 | IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = BIT(6), |
292 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8), | 294 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8), |
293 | IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), | 295 | IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), |
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index 2a8cf4b2445c..e8eabd21ccfe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h | |||
@@ -96,7 +96,6 @@ enum iwl_disable_11n { | |||
96 | * use IWL_[DIS,EN]ABLE_HT_* constants | 96 | * use IWL_[DIS,EN]ABLE_HT_* constants |
97 | * @amsdu_size_8K: enable 8K amsdu size, default = 0 | 97 | * @amsdu_size_8K: enable 8K amsdu size, default = 0 |
98 | * @restart_fw: restart firmware, default = 1 | 98 | * @restart_fw: restart firmware, default = 1 |
99 | * @wd_disable: disable stuck queue check, default = 1 | ||
100 | * @bt_coex_active: enable bt coex, default = true | 99 | * @bt_coex_active: enable bt coex, default = true |
101 | * @led_mode: system default, default = 0 | 100 | * @led_mode: system default, default = 0 |
102 | * @power_save: enable power save, default = false | 101 | * @power_save: enable power save, default = false |
@@ -111,7 +110,6 @@ struct iwl_mod_params { | |||
111 | unsigned int disable_11n; | 110 | unsigned int disable_11n; |
112 | int amsdu_size_8K; | 111 | int amsdu_size_8K; |
113 | bool restart_fw; | 112 | bool restart_fw; |
114 | int wd_disable; | ||
115 | bool bt_coex_active; | 113 | bool bt_coex_active; |
116 | int led_mode; | 114 | int led_mode; |
117 | bool power_save; | 115 | bool power_save; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index b21fcf042b77..6221e4dfc64f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
@@ -252,6 +252,7 @@ | |||
252 | #define SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) | 252 | #define SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F) |
253 | #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) | 253 | #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) |
254 | #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) | 254 | #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) |
255 | #define SCD_GP_CTRL_ENABLE_31_QUEUES BIT(0) | ||
255 | 256 | ||
256 | /* Context Data */ | 257 | /* Context Data */ |
257 | #define SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600) | 258 | #define SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600) |
@@ -285,32 +286,9 @@ | |||
285 | #define SCD_CHAINEXT_EN (SCD_BASE + 0x244) | 286 | #define SCD_CHAINEXT_EN (SCD_BASE + 0x244) |
286 | #define SCD_AGGR_SEL (SCD_BASE + 0x248) | 287 | #define SCD_AGGR_SEL (SCD_BASE + 0x248) |
287 | #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) | 288 | #define SCD_INTERRUPT_MASK (SCD_BASE + 0x108) |
289 | #define SCD_GP_CTRL (SCD_BASE + 0x1a8) | ||
288 | #define SCD_EN_CTRL (SCD_BASE + 0x254) | 290 | #define SCD_EN_CTRL (SCD_BASE + 0x254) |
289 | 291 | ||
290 | static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl) | ||
291 | { | ||
292 | if (chnl < 20) | ||
293 | return SCD_BASE + 0x18 + chnl * 4; | ||
294 | WARN_ON_ONCE(chnl >= 32); | ||
295 | return SCD_BASE + 0x284 + (chnl - 20) * 4; | ||
296 | } | ||
297 | |||
298 | static inline unsigned int SCD_QUEUE_RDPTR(unsigned int chnl) | ||
299 | { | ||
300 | if (chnl < 20) | ||
301 | return SCD_BASE + 0x68 + chnl * 4; | ||
302 | WARN_ON_ONCE(chnl >= 32); | ||
303 | return SCD_BASE + 0x2B4 + (chnl - 20) * 4; | ||
304 | } | ||
305 | |||
306 | static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl) | ||
307 | { | ||
308 | if (chnl < 20) | ||
309 | return SCD_BASE + 0x10c + chnl * 4; | ||
310 | WARN_ON_ONCE(chnl >= 32); | ||
311 | return SCD_BASE + 0x384 + (chnl - 20) * 4; | ||
312 | } | ||
313 | |||
314 | /*********************** END TX SCHEDULER *************************************/ | 292 | /*********************** END TX SCHEDULER *************************************/ |
315 | 293 | ||
316 | /* Oscillator clock */ | 294 | /* Oscillator clock */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h index 6c622b21bba7..f2353ebf2666 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scd.h +++ b/drivers/net/wireless/iwlwifi/iwl-scd.h | |||
@@ -69,14 +69,6 @@ | |||
69 | #include "iwl-prph.h" | 69 | #include "iwl-prph.h" |
70 | 70 | ||
71 | 71 | ||
72 | static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans, | ||
73 | u16 txq_id) | ||
74 | { | ||
75 | iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), | ||
76 | (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| | ||
77 | (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); | ||
78 | } | ||
79 | |||
80 | static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans, | 72 | static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans, |
81 | u16 txq_id) | 73 | u16 txq_id) |
82 | { | 74 | { |
@@ -115,4 +107,37 @@ static inline void iwl_scd_enable_set_active(struct iwl_trans *trans, | |||
115 | { | 107 | { |
116 | iwl_write_prph(trans, SCD_EN_CTRL, value); | 108 | iwl_write_prph(trans, SCD_EN_CTRL, value); |
117 | } | 109 | } |
110 | |||
111 | static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl) | ||
112 | { | ||
113 | if (chnl < 20) | ||
114 | return SCD_BASE + 0x18 + chnl * 4; | ||
115 | WARN_ON_ONCE(chnl >= 32); | ||
116 | return SCD_BASE + 0x284 + (chnl - 20) * 4; | ||
117 | } | ||
118 | |||
119 | static inline unsigned int SCD_QUEUE_RDPTR(unsigned int chnl) | ||
120 | { | ||
121 | if (chnl < 20) | ||
122 | return SCD_BASE + 0x68 + chnl * 4; | ||
123 | WARN_ON_ONCE(chnl >= 32); | ||
124 | return SCD_BASE + 0x2B4 + chnl * 4; | ||
125 | } | ||
126 | |||
127 | static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl) | ||
128 | { | ||
129 | if (chnl < 20) | ||
130 | return SCD_BASE + 0x10c + chnl * 4; | ||
131 | WARN_ON_ONCE(chnl >= 32); | ||
132 | return SCD_BASE + 0x334 + chnl * 4; | ||
133 | } | ||
134 | |||
135 | static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans, | ||
136 | u16 txq_id) | ||
137 | { | ||
138 | iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), | ||
139 | (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| | ||
140 | (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); | ||
141 | } | ||
142 | |||
118 | #endif | 143 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 84d8477432a2..a96bd8db6ceb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -368,6 +368,7 @@ enum iwl_trans_status { | |||
368 | * @cmd_queue: the index of the command queue. | 368 | * @cmd_queue: the index of the command queue. |
369 | * Must be set before start_fw. | 369 | * Must be set before start_fw. |
370 | * @cmd_fifo: the fifo for host commands | 370 | * @cmd_fifo: the fifo for host commands |
371 | * @cmd_q_wdg_timeout: the timeout of the watchdog timer for the command queue. | ||
371 | * @no_reclaim_cmds: Some devices erroneously don't set the | 372 | * @no_reclaim_cmds: Some devices erroneously don't set the |
372 | * SEQ_RX_FRAME bit on some notifications, this is the | 373 | * SEQ_RX_FRAME bit on some notifications, this is the |
373 | * list of such notifications to filter. Max length is | 374 | * list of such notifications to filter. Max length is |
@@ -378,8 +379,6 @@ enum iwl_trans_status { | |||
378 | * @bc_table_dword: set to true if the BC table expects the byte count to be | 379 | * @bc_table_dword: set to true if the BC table expects the byte count to be |
379 | * in DWORD (as opposed to bytes) | 380 | * in DWORD (as opposed to bytes) |
380 | * @scd_set_active: should the transport configure the SCD for HCMD queue | 381 | * @scd_set_active: should the transport configure the SCD for HCMD queue |
381 | * @queue_watchdog_timeout: time (in ms) after which queues | ||
382 | * are considered stuck and will trigger device restart | ||
383 | * @command_names: array of command names, must be 256 entries | 382 | * @command_names: array of command names, must be 256 entries |
384 | * (one for each command); for debugging only | 383 | * (one for each command); for debugging only |
385 | * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until | 384 | * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until |
@@ -390,13 +389,13 @@ struct iwl_trans_config { | |||
390 | 389 | ||
391 | u8 cmd_queue; | 390 | u8 cmd_queue; |
392 | u8 cmd_fifo; | 391 | u8 cmd_fifo; |
392 | unsigned int cmd_q_wdg_timeout; | ||
393 | const u8 *no_reclaim_cmds; | 393 | const u8 *no_reclaim_cmds; |
394 | unsigned int n_no_reclaim_cmds; | 394 | unsigned int n_no_reclaim_cmds; |
395 | 395 | ||
396 | bool rx_buf_size_8k; | 396 | bool rx_buf_size_8k; |
397 | bool bc_table_dword; | 397 | bool bc_table_dword; |
398 | bool scd_set_active; | 398 | bool scd_set_active; |
399 | unsigned int queue_watchdog_timeout; | ||
400 | const char *const *command_names; | 399 | const char *const *command_names; |
401 | 400 | ||
402 | u32 sdio_adma_addr; | 401 | u32 sdio_adma_addr; |
@@ -511,7 +510,8 @@ struct iwl_trans_ops { | |||
511 | struct sk_buff_head *skbs); | 510 | struct sk_buff_head *skbs); |
512 | 511 | ||
513 | void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, | 512 | void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, |
514 | const struct iwl_trans_txq_scd_cfg *cfg); | 513 | const struct iwl_trans_txq_scd_cfg *cfg, |
514 | unsigned int queue_wdg_timeout); | ||
515 | void (*txq_disable)(struct iwl_trans *trans, int queue, | 515 | void (*txq_disable)(struct iwl_trans *trans, int queue, |
516 | bool configure_scd); | 516 | bool configure_scd); |
517 | 517 | ||
@@ -829,19 +829,21 @@ static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, | |||
829 | 829 | ||
830 | static inline void | 830 | static inline void |
831 | iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, | 831 | iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, |
832 | const struct iwl_trans_txq_scd_cfg *cfg) | 832 | const struct iwl_trans_txq_scd_cfg *cfg, |
833 | unsigned int queue_wdg_timeout) | ||
833 | { | 834 | { |
834 | might_sleep(); | 835 | might_sleep(); |
835 | 836 | ||
836 | if (unlikely((trans->state != IWL_TRANS_FW_ALIVE))) | 837 | if (unlikely((trans->state != IWL_TRANS_FW_ALIVE))) |
837 | IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); | 838 | IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); |
838 | 839 | ||
839 | trans->ops->txq_enable(trans, queue, ssn, cfg); | 840 | trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout); |
840 | } | 841 | } |
841 | 842 | ||
842 | static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, | 843 | static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, |
843 | int fifo, int sta_id, int tid, | 844 | int fifo, int sta_id, int tid, |
844 | int frame_limit, u16 ssn) | 845 | int frame_limit, u16 ssn, |
846 | unsigned int queue_wdg_timeout) | ||
845 | { | 847 | { |
846 | struct iwl_trans_txq_scd_cfg cfg = { | 848 | struct iwl_trans_txq_scd_cfg cfg = { |
847 | .fifo = fifo, | 849 | .fifo = fifo, |
@@ -851,11 +853,12 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, | |||
851 | .aggregate = sta_id >= 0, | 853 | .aggregate = sta_id >= 0, |
852 | }; | 854 | }; |
853 | 855 | ||
854 | iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg); | 856 | iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg, queue_wdg_timeout); |
855 | } | 857 | } |
856 | 858 | ||
857 | static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, | 859 | static inline |
858 | int fifo) | 860 | void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo, |
861 | unsigned int queue_wdg_timeout) | ||
859 | { | 862 | { |
860 | struct iwl_trans_txq_scd_cfg cfg = { | 863 | struct iwl_trans_txq_scd_cfg cfg = { |
861 | .fifo = fifo, | 864 | .fifo = fifo, |
@@ -865,16 +868,16 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, | |||
865 | .aggregate = false, | 868 | .aggregate = false, |
866 | }; | 869 | }; |
867 | 870 | ||
868 | iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg); | 871 | iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout); |
869 | } | 872 | } |
870 | 873 | ||
871 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, | 874 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, |
872 | u32 txq_bm) | 875 | u32 txqs) |
873 | { | 876 | { |
874 | if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) | 877 | if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) |
875 | IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); | 878 | IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); |
876 | 879 | ||
877 | return trans->ops->wait_tx_queue_empty(trans, txq_bm); | 880 | return trans->ops->wait_tx_queue_empty(trans, txqs); |
878 | } | 881 | } |
879 | 882 | ||
880 | static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, | 883 | static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index d91c46b0f888..beba375489f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h | |||
@@ -99,7 +99,7 @@ | |||
99 | #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 | 99 | #define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30 |
100 | #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 | 100 | #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0 |
101 | #define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 | 101 | #define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0 |
102 | #define IWL_MVM_QUOTA_THRESHOLD 8 | 102 | #define IWL_MVM_QUOTA_THRESHOLD 4 |
103 | #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 | 103 | #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 |
104 | #define IWL_MVM_RS_DISABLE_P2P_MIMO 0 | 104 | #define IWL_MVM_RS_DISABLE_P2P_MIMO 0 |
105 | #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 | 105 | #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 6a2a6b0ab91b..0f1ea80a55ef 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h | |||
@@ -308,16 +308,41 @@ enum { | |||
308 | #define LQ_FLAG_DYNAMIC_BW_POS 6 | 308 | #define LQ_FLAG_DYNAMIC_BW_POS 6 |
309 | #define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS) | 309 | #define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS) |
310 | 310 | ||
311 | /* Single Stream Parameters | 311 | /* Single Stream Tx Parameters (lq_cmd->ss_params) |
312 | * SS_STBC/BFER_ALLOWED - Controls whether STBC or Beamformer (BFER) is allowed | 312 | * Flags to control a smart FW decision about whether BFER/STBC/SISO will be |
313 | * ucode will make a smart decision between SISO/STBC/BFER | 313 | * used for single stream Tx. |
314 | * SS_PARAMS_VALID - if not set ignore the ss_params field. | ||
315 | */ | 314 | */ |
316 | enum { | 315 | |
317 | RS_SS_STBC_ALLOWED = BIT(0), | 316 | /* Bit 0-1: Max STBC streams allowed. Can be 0-3. |
318 | RS_SS_BFER_ALLOWED = BIT(1), | 317 | * (0) - No STBC allowed |
319 | RS_SS_PARAMS_VALID = BIT(31), | 318 | * (1) - 2x1 STBC allowed (HT/VHT) |
320 | }; | 319 | * (2) - 4x2 STBC allowed (HT/VHT) |
320 | * (3) - 3x2 STBC allowed (HT only) | ||
321 | * All our chips are at most 2 antennas so only (1) is valid for now. | ||
322 | */ | ||
323 | #define LQ_SS_STBC_ALLOWED_POS 0 | ||
324 | #define LQ_SS_STBC_ALLOWED_MSK (3 << LQ_SS_STBC_ALLOWED_MSK) | ||
325 | |||
326 | /* 2x1 STBC is allowed */ | ||
327 | #define LQ_SS_STBC_1SS_ALLOWED (1 << LQ_SS_STBC_ALLOWED_POS) | ||
328 | |||
329 | /* Bit 2: Beamformer (VHT only) is allowed */ | ||
330 | #define LQ_SS_BFER_ALLOWED_POS 2 | ||
331 | #define LQ_SS_BFER_ALLOWED (1 << LQ_SS_BFER_ALLOWED_POS) | ||
332 | |||
333 | /* Bit 3: Force BFER or STBC for testing | ||
334 | * If this is set: | ||
335 | * If BFER is allowed then force the ucode to choose BFER else | ||
336 | * If STBC is allowed then force the ucode to choose STBC over SISO | ||
337 | */ | ||
338 | #define LQ_SS_FORCE_POS 3 | ||
339 | #define LQ_SS_FORCE (1 << LQ_SS_FORCE_POS) | ||
340 | |||
341 | /* Bit 31: ss_params field is valid. Used for FW backward compatibility | ||
342 | * with other drivers which don't support the ss_params API yet | ||
343 | */ | ||
344 | #define LQ_SS_PARAMS_VALID_POS 31 | ||
345 | #define LQ_SS_PARAMS_VALID (1 << LQ_SS_PARAMS_VALID_POS) | ||
321 | 346 | ||
322 | /** | 347 | /** |
323 | * struct iwl_lq_cmd - link quality command | 348 | * struct iwl_lq_cmd - link quality command |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index a322a5e3d31b..ca38e9817374 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -575,7 +575,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
575 | goto error; | 575 | goto error; |
576 | } | 576 | } |
577 | 577 | ||
578 | iwl_mvm_get_shared_mem_conf(mvm); | 578 | if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) |
579 | iwl_mvm_get_shared_mem_conf(mvm); | ||
579 | 580 | ||
580 | ret = iwl_mvm_sf_update(mvm, NULL, false); | 581 | ret = iwl_mvm_sf_update(mvm, NULL, false); |
581 | if (ret) | 582 | if (ret) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 8bf78fa8ace0..7bdc6220743f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -462,6 +462,9 @@ exit_fail: | |||
462 | 462 | ||
463 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 463 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
464 | { | 464 | { |
465 | unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? | ||
466 | mvm->cfg->base_params->wd_timeout : | ||
467 | IWL_WATCHDOG_DISABLED; | ||
465 | u32 ac; | 468 | u32 ac; |
466 | int ret; | 469 | int ret; |
467 | 470 | ||
@@ -474,16 +477,17 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
474 | switch (vif->type) { | 477 | switch (vif->type) { |
475 | case NL80211_IFTYPE_P2P_DEVICE: | 478 | case NL80211_IFTYPE_P2P_DEVICE: |
476 | iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, | 479 | iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, |
477 | IWL_MVM_TX_FIFO_VO); | 480 | IWL_MVM_TX_FIFO_VO, wdg_timeout); |
478 | break; | 481 | break; |
479 | case NL80211_IFTYPE_AP: | 482 | case NL80211_IFTYPE_AP: |
480 | iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, | 483 | iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, |
481 | IWL_MVM_TX_FIFO_MCAST); | 484 | IWL_MVM_TX_FIFO_MCAST, wdg_timeout); |
482 | /* fall through */ | 485 | /* fall through */ |
483 | default: | 486 | default: |
484 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | 487 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
485 | iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac], | 488 | iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac], |
486 | iwl_mvm_ac_to_tx_fifo[ac]); | 489 | iwl_mvm_ac_to_tx_fifo[ac], |
490 | wdg_timeout); | ||
487 | break; | 491 | break; |
488 | } | 492 | } |
489 | 493 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index cef6f3373542..1ff7ec08532d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -401,10 +401,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
401 | if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) | 401 | if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels) |
402 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | 402 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = |
403 | &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; | 403 | &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; |
404 | if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) | 404 | if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) { |
405 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | 405 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = |
406 | &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | 406 | &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; |
407 | 407 | ||
408 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) | ||
409 | hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |= | ||
410 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; | ||
411 | } | ||
412 | |||
408 | hw->wiphy->hw_version = mvm->trans->hw_id; | 413 | hw->wiphy->hw_version = mvm->trans->hw_id; |
409 | 414 | ||
410 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) | 415 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) |
@@ -707,9 +712,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, | |||
707 | mvmvif->uploaded = false; | 712 | mvmvif->uploaded = false; |
708 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 713 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
709 | 714 | ||
710 | /* does this make sense at all? */ | ||
711 | mvmvif->color++; | ||
712 | |||
713 | spin_lock_bh(&mvm->time_event_lock); | 715 | spin_lock_bh(&mvm->time_event_lock); |
714 | iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); | 716 | iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); |
715 | spin_unlock_bh(&mvm->time_event_lock); | 717 | spin_unlock_bh(&mvm->time_event_lock); |
@@ -1353,7 +1355,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
1353 | 1355 | ||
1354 | ret = iwl_mvm_power_update_mac(mvm); | 1356 | ret = iwl_mvm_power_update_mac(mvm); |
1355 | if (ret) | 1357 | if (ret) |
1356 | goto out_release; | 1358 | goto out_remove_mac; |
1357 | 1359 | ||
1358 | /* beacon filtering */ | 1360 | /* beacon filtering */ |
1359 | ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); | 1361 | ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 979ac23522f2..6c69d0584f6c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -119,11 +119,13 @@ extern const struct ieee80211_ops iwl_mvm_hw_ops; | |||
119 | * We will register to mac80211 to have testmode working. The NIC must not | 119 | * We will register to mac80211 to have testmode working. The NIC must not |
120 | * be up'ed after the INIT fw asserted. This is useful to be able to use | 120 | * be up'ed after the INIT fw asserted. This is useful to be able to use |
121 | * proprietary tools over testmode to debug the INIT fw. | 121 | * proprietary tools over testmode to debug the INIT fw. |
122 | * @tfd_q_hang_detect: enabled the detection of hung transmit queues | ||
122 | * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power | 123 | * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power |
123 | * Save)-2(default), LP(Low Power)-3 | 124 | * Save)-2(default), LP(Low Power)-3 |
124 | */ | 125 | */ |
125 | struct iwl_mvm_mod_params { | 126 | struct iwl_mvm_mod_params { |
126 | bool init_dbg; | 127 | bool init_dbg; |
128 | bool tfd_q_hang_detect; | ||
127 | int power_scheme; | 129 | int power_scheme; |
128 | }; | 130 | }; |
129 | extern struct iwl_mvm_mod_params iwlmvm_mod_params; | 131 | extern struct iwl_mvm_mod_params iwlmvm_mod_params; |
@@ -532,6 +534,7 @@ enum { | |||
532 | enum iwl_mvm_tdls_cs_state { | 534 | enum iwl_mvm_tdls_cs_state { |
533 | IWL_MVM_TDLS_SW_IDLE = 0, | 535 | IWL_MVM_TDLS_SW_IDLE = 0, |
534 | IWL_MVM_TDLS_SW_REQ_SENT, | 536 | IWL_MVM_TDLS_SW_REQ_SENT, |
537 | IWL_MVM_TDLS_SW_RESP_RCVD, | ||
535 | IWL_MVM_TDLS_SW_REQ_RCVD, | 538 | IWL_MVM_TDLS_SW_REQ_RCVD, |
536 | IWL_MVM_TDLS_SW_ACTIVE, | 539 | IWL_MVM_TDLS_SW_ACTIVE, |
537 | }; | 540 | }; |
@@ -797,6 +800,9 @@ struct iwl_mvm { | |||
797 | struct cfg80211_chan_def chandef; | 800 | struct cfg80211_chan_def chandef; |
798 | struct sk_buff *skb; /* ch sw template */ | 801 | struct sk_buff *skb; /* ch sw template */ |
799 | u32 ch_sw_tm_ie; | 802 | u32 ch_sw_tm_ie; |
803 | |||
804 | /* timestamp of last ch-sw request sent (GP2 time) */ | ||
805 | u32 sent_timestamp; | ||
800 | } peer; | 806 | } peer; |
801 | } tdls_cs; | 807 | } tdls_cs; |
802 | 808 | ||
@@ -874,7 +880,7 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) | |||
874 | 880 | ||
875 | static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) | 881 | static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) |
876 | { | 882 | { |
877 | return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_API_SCD_CFG; | 883 | return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG; |
878 | } | 884 | } |
879 | 885 | ||
880 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; | 886 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; |
@@ -1312,11 +1318,13 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) | |||
1312 | 1318 | ||
1313 | /* hw scheduler queue config */ | 1319 | /* hw scheduler queue config */ |
1314 | void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, | 1320 | void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, |
1315 | const struct iwl_trans_txq_scd_cfg *cfg); | 1321 | const struct iwl_trans_txq_scd_cfg *cfg, |
1322 | unsigned int wdg_timeout); | ||
1316 | void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags); | 1323 | void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags); |
1317 | 1324 | ||
1318 | static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, | 1325 | static inline |
1319 | u8 fifo) | 1326 | void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, |
1327 | u8 fifo, unsigned int wdg_timeout) | ||
1320 | { | 1328 | { |
1321 | struct iwl_trans_txq_scd_cfg cfg = { | 1329 | struct iwl_trans_txq_scd_cfg cfg = { |
1322 | .fifo = fifo, | 1330 | .fifo = fifo, |
@@ -1325,12 +1333,13 @@ static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, | |||
1325 | .frame_limit = IWL_FRAME_LIMIT, | 1333 | .frame_limit = IWL_FRAME_LIMIT, |
1326 | }; | 1334 | }; |
1327 | 1335 | ||
1328 | iwl_mvm_enable_txq(mvm, queue, 0, &cfg); | 1336 | iwl_mvm_enable_txq(mvm, queue, 0, &cfg, wdg_timeout); |
1329 | } | 1337 | } |
1330 | 1338 | ||
1331 | static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, | 1339 | static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, |
1332 | int fifo, int sta_id, int tid, | 1340 | int fifo, int sta_id, int tid, |
1333 | int frame_limit, u16 ssn) | 1341 | int frame_limit, u16 ssn, |
1342 | unsigned int wdg_timeout) | ||
1334 | { | 1343 | { |
1335 | struct iwl_trans_txq_scd_cfg cfg = { | 1344 | struct iwl_trans_txq_scd_cfg cfg = { |
1336 | .fifo = fifo, | 1345 | .fifo = fifo, |
@@ -1340,7 +1349,7 @@ static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, | |||
1340 | .aggregate = true, | 1349 | .aggregate = true, |
1341 | }; | 1350 | }; |
1342 | 1351 | ||
1343 | iwl_mvm_enable_txq(mvm, queue, ssn, &cfg); | 1352 | iwl_mvm_enable_txq(mvm, queue, ssn, &cfg, wdg_timeout); |
1344 | } | 1353 | } |
1345 | 1354 | ||
1346 | /* Assoc status */ | 1355 | /* Assoc status */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 8bf8c2a29e5e..2dffc3600ed3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -93,6 +93,7 @@ static const struct iwl_op_mode_ops iwl_mvm_ops; | |||
93 | 93 | ||
94 | struct iwl_mvm_mod_params iwlmvm_mod_params = { | 94 | struct iwl_mvm_mod_params iwlmvm_mod_params = { |
95 | .power_scheme = IWL_POWER_SCHEME_BPS, | 95 | .power_scheme = IWL_POWER_SCHEME_BPS, |
96 | .tfd_q_hang_detect = true | ||
96 | /* rest of fields are 0 by default */ | 97 | /* rest of fields are 0 by default */ |
97 | }; | 98 | }; |
98 | 99 | ||
@@ -102,6 +103,10 @@ MODULE_PARM_DESC(init_dbg, | |||
102 | module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO); | 103 | module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO); |
103 | MODULE_PARM_DESC(power_scheme, | 104 | MODULE_PARM_DESC(power_scheme, |
104 | "power management scheme: 1-active, 2-balanced, 3-low power, default: 2"); | 105 | "power management scheme: 1-active, 2-balanced, 3-low power, default: 2"); |
106 | module_param_named(tfd_q_hang_detect, iwlmvm_mod_params.tfd_q_hang_detect, | ||
107 | bool, S_IRUGO); | ||
108 | MODULE_PARM_DESC(tfd_q_hang_detect, | ||
109 | "TFD queues hang detection (default: true"); | ||
105 | 110 | ||
106 | /* | 111 | /* |
107 | * module init and exit functions | 112 | * module init and exit functions |
@@ -473,11 +478,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
473 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) | 478 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) |
474 | trans_cfg.bc_table_dword = true; | 479 | trans_cfg.bc_table_dword = true; |
475 | 480 | ||
476 | if (!iwlwifi_mod_params.wd_disable) | ||
477 | trans_cfg.queue_watchdog_timeout = cfg->base_params->wd_timeout; | ||
478 | else | ||
479 | trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; | ||
480 | |||
481 | trans_cfg.command_names = iwl_mvm_cmd_strings; | 481 | trans_cfg.command_names = iwl_mvm_cmd_strings; |
482 | 482 | ||
483 | trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; | 483 | trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; |
@@ -486,6 +486,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
486 | 486 | ||
487 | trans_cfg.sdio_adma_addr = fw->sdio_adma_addr; | 487 | trans_cfg.sdio_adma_addr = fw->sdio_adma_addr; |
488 | 488 | ||
489 | /* Set a short watchdog for the command queue */ | ||
490 | trans_cfg.cmd_q_wdg_timeout = | ||
491 | iwlmvm_mod_params.tfd_q_hang_detect ? IWL_DEF_WD_TIMEOUT : | ||
492 | IWL_WATCHDOG_DISABLED; | ||
493 | |||
489 | snprintf(mvm->hw->wiphy->fw_version, | 494 | snprintf(mvm->hw->wiphy->fw_version, |
490 | sizeof(mvm->hw->wiphy->fw_version), | 495 | sizeof(mvm->hw->wiphy->fw_version), |
491 | "%s", fw->fw_version); | 496 | "%s", fw->fw_version); |
@@ -563,6 +568,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
563 | if (!mvm->scan_cmd) | 568 | if (!mvm->scan_cmd) |
564 | goto out_free; | 569 | goto out_free; |
565 | 570 | ||
571 | /* Set EBS as successful as long as not stated otherwise by the FW. */ | ||
572 | mvm->last_ebs_successful = true; | ||
573 | |||
566 | err = iwl_mvm_mac_setup_register(mvm); | 574 | err = iwl_mvm_mac_setup_register(mvm); |
567 | if (err) | 575 | if (err) |
568 | goto out_free; | 576 | goto out_free; |
@@ -870,7 +878,10 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) | |||
870 | * If WoWLAN fw asserted, don't restart either, mac80211 | 878 | * If WoWLAN fw asserted, don't restart either, mac80211 |
871 | * can't recover this since we're already half suspended. | 879 | * can't recover this since we're already half suspended. |
872 | */ | 880 | */ |
873 | if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | 881 | if (!mvm->restart_fw && fw_error) { |
882 | schedule_work(&mvm->fw_error_dump_wk); | ||
883 | } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, | ||
884 | &mvm->status)) { | ||
874 | struct iwl_mvm_reprobe *reprobe; | 885 | struct iwl_mvm_reprobe *reprobe; |
875 | 886 | ||
876 | IWL_ERR(mvm, | 887 | IWL_ERR(mvm, |
@@ -894,16 +905,13 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) | |||
894 | reprobe->dev = mvm->trans->dev; | 905 | reprobe->dev = mvm->trans->dev; |
895 | INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); | 906 | INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); |
896 | schedule_work(&reprobe->work); | 907 | schedule_work(&reprobe->work); |
897 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && | 908 | } else if (mvm->cur_ucode == IWL_UCODE_REGULAR) { |
898 | (!fw_error || mvm->restart_fw)) { | ||
899 | /* don't let the transport/FW power down */ | 909 | /* don't let the transport/FW power down */ |
900 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); | 910 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); |
901 | 911 | ||
902 | if (fw_error && mvm->restart_fw > 0) | 912 | if (fw_error && mvm->restart_fw > 0) |
903 | mvm->restart_fw--; | 913 | mvm->restart_fw--; |
904 | ieee80211_restart_hw(mvm->hw); | 914 | ieee80211_restart_hw(mvm->hw); |
905 | } else if (fw_error) { | ||
906 | schedule_work(&mvm->fw_error_dump_wk); | ||
907 | } | 915 | } |
908 | } | 916 | } |
909 | 917 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 9f32f2db95bd..194bd1f939ca 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "sta.h" | 39 | #include "sta.h" |
40 | #include "iwl-op-mode.h" | 40 | #include "iwl-op-mode.h" |
41 | #include "mvm.h" | 41 | #include "mvm.h" |
42 | #include "debugfs.h" | ||
42 | 43 | ||
43 | #define RS_NAME "iwl-mvm-rs" | 44 | #define RS_NAME "iwl-mvm-rs" |
44 | 45 | ||
@@ -1805,7 +1806,7 @@ static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
1805 | /* Our chip supports Tx STBC and the peer is an HT/VHT STA which | 1806 | /* Our chip supports Tx STBC and the peer is an HT/VHT STA which |
1806 | * supports STBC of at least 1*SS | 1807 | * supports STBC of at least 1*SS |
1807 | */ | 1808 | */ |
1808 | if (!lq_sta->stbc) | 1809 | if (!lq_sta->stbc_capable) |
1809 | return false; | 1810 | return false; |
1810 | 1811 | ||
1811 | if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) | 1812 | if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) |
@@ -2626,7 +2627,7 @@ static void rs_ht_init(struct iwl_mvm *mvm, | |||
2626 | if (mvm->cfg->ht_params->stbc && | 2627 | if (mvm->cfg->ht_params->stbc && |
2627 | (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && | 2628 | (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && |
2628 | (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) | 2629 | (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC)) |
2629 | lq_sta->stbc = true; | 2630 | lq_sta->stbc_capable = true; |
2630 | 2631 | ||
2631 | lq_sta->is_vht = false; | 2632 | lq_sta->is_vht = false; |
2632 | } | 2633 | } |
@@ -2645,7 +2646,12 @@ static void rs_vht_init(struct iwl_mvm *mvm, | |||
2645 | if (mvm->cfg->ht_params->stbc && | 2646 | if (mvm->cfg->ht_params->stbc && |
2646 | (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && | 2647 | (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && |
2647 | (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) | 2648 | (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK)) |
2648 | lq_sta->stbc = true; | 2649 | lq_sta->stbc_capable = true; |
2650 | |||
2651 | if ((mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) && | ||
2652 | (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) && | ||
2653 | (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) | ||
2654 | lq_sta->bfer_capable = true; | ||
2649 | 2655 | ||
2650 | lq_sta->is_vht = true; | 2656 | lq_sta->is_vht = true; |
2651 | } | 2657 | } |
@@ -2778,11 +2784,12 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
2778 | rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate); | 2784 | rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate); |
2779 | 2785 | ||
2780 | IWL_DEBUG_RATE(mvm, | 2786 | IWL_DEBUG_RATE(mvm, |
2781 | "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d\n", | 2787 | "LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d BFER=%d\n", |
2782 | lq_sta->active_legacy_rate, | 2788 | lq_sta->active_legacy_rate, |
2783 | lq_sta->active_siso_rate, | 2789 | lq_sta->active_siso_rate, |
2784 | lq_sta->active_mimo2_rate, | 2790 | lq_sta->active_mimo2_rate, |
2785 | lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc); | 2791 | lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc_capable, |
2792 | lq_sta->bfer_capable); | ||
2786 | IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", | 2793 | IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", |
2787 | lq_sta->max_legacy_rate_idx, | 2794 | lq_sta->max_legacy_rate_idx, |
2788 | lq_sta->max_siso_rate_idx, | 2795 | lq_sta->max_siso_rate_idx, |
@@ -2916,23 +2923,15 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, | |||
2916 | u8 valid_tx_ant = 0; | 2923 | u8 valid_tx_ant = 0; |
2917 | struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; | 2924 | struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; |
2918 | bool toggle_ant = false; | 2925 | bool toggle_ant = false; |
2919 | bool stbc_allowed = false; | ||
2920 | 2926 | ||
2921 | memcpy(&rate, initial_rate, sizeof(rate)); | 2927 | memcpy(&rate, initial_rate, sizeof(rate)); |
2922 | 2928 | ||
2923 | valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); | 2929 | valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm); |
2924 | 2930 | ||
2925 | stbc_allowed = rs_stbc_allow(mvm, sta, lq_sta); | 2931 | /* TODO: remove old API when min FW API hits 14 */ |
2926 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) { | 2932 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) && |
2927 | u32 ss_params = RS_SS_PARAMS_VALID; | 2933 | rs_stbc_allow(mvm, sta, lq_sta)) |
2928 | 2934 | rate.stbc = true; | |
2929 | if (stbc_allowed) | ||
2930 | ss_params |= RS_SS_STBC_ALLOWED; | ||
2931 | lq_cmd->ss_params = cpu_to_le32(ss_params); | ||
2932 | } else { | ||
2933 | /* TODO: remove old API when min FW API hits 14 */ | ||
2934 | rate.stbc = stbc_allowed; | ||
2935 | } | ||
2936 | 2935 | ||
2937 | if (is_siso(&rate)) { | 2936 | if (is_siso(&rate)) { |
2938 | num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES; | 2937 | num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES; |
@@ -2980,6 +2979,142 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, | |||
2980 | 2979 | ||
2981 | } | 2980 | } |
2982 | 2981 | ||
2982 | struct rs_bfer_active_iter_data { | ||
2983 | struct ieee80211_sta *exclude_sta; | ||
2984 | struct iwl_mvm_sta *bfer_mvmsta; | ||
2985 | }; | ||
2986 | |||
2987 | static void rs_bfer_active_iter(void *_data, | ||
2988 | struct ieee80211_sta *sta) | ||
2989 | { | ||
2990 | struct rs_bfer_active_iter_data *data = _data; | ||
2991 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
2992 | struct iwl_lq_cmd *lq_cmd = &mvmsta->lq_sta.lq; | ||
2993 | u32 ss_params = le32_to_cpu(lq_cmd->ss_params); | ||
2994 | |||
2995 | if (sta == data->exclude_sta) | ||
2996 | return; | ||
2997 | |||
2998 | /* The current sta has BFER allowed */ | ||
2999 | if (ss_params & LQ_SS_BFER_ALLOWED) { | ||
3000 | WARN_ON_ONCE(data->bfer_mvmsta != NULL); | ||
3001 | |||
3002 | data->bfer_mvmsta = mvmsta; | ||
3003 | } | ||
3004 | } | ||
3005 | |||
3006 | static int rs_bfer_priority(struct iwl_mvm_sta *sta) | ||
3007 | { | ||
3008 | int prio = -1; | ||
3009 | enum nl80211_iftype viftype = ieee80211_vif_type_p2p(sta->vif); | ||
3010 | |||
3011 | switch (viftype) { | ||
3012 | case NL80211_IFTYPE_AP: | ||
3013 | case NL80211_IFTYPE_P2P_GO: | ||
3014 | prio = 3; | ||
3015 | break; | ||
3016 | case NL80211_IFTYPE_P2P_CLIENT: | ||
3017 | prio = 2; | ||
3018 | break; | ||
3019 | case NL80211_IFTYPE_STATION: | ||
3020 | prio = 1; | ||
3021 | break; | ||
3022 | default: | ||
3023 | WARN_ONCE(true, "viftype %d sta_id %d", viftype, sta->sta_id); | ||
3024 | prio = -1; | ||
3025 | } | ||
3026 | |||
3027 | return prio; | ||
3028 | } | ||
3029 | |||
3030 | /* Returns >0 if sta1 has a higher BFER priority compared to sta2 */ | ||
3031 | static int rs_bfer_priority_cmp(struct iwl_mvm_sta *sta1, | ||
3032 | struct iwl_mvm_sta *sta2) | ||
3033 | { | ||
3034 | int prio1 = rs_bfer_priority(sta1); | ||
3035 | int prio2 = rs_bfer_priority(sta2); | ||
3036 | |||
3037 | if (prio1 > prio2) | ||
3038 | return 1; | ||
3039 | if (prio1 < prio2) | ||
3040 | return -1; | ||
3041 | return 0; | ||
3042 | } | ||
3043 | |||
3044 | static void rs_set_lq_ss_params(struct iwl_mvm *mvm, | ||
3045 | struct ieee80211_sta *sta, | ||
3046 | struct iwl_lq_sta *lq_sta, | ||
3047 | const struct rs_rate *initial_rate) | ||
3048 | { | ||
3049 | struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; | ||
3050 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | ||
3051 | struct rs_bfer_active_iter_data data = { | ||
3052 | .exclude_sta = sta, | ||
3053 | .bfer_mvmsta = NULL, | ||
3054 | }; | ||
3055 | struct iwl_mvm_sta *bfer_mvmsta = NULL; | ||
3056 | u32 ss_params = LQ_SS_PARAMS_VALID; | ||
3057 | |||
3058 | if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta)) | ||
3059 | goto out; | ||
3060 | |||
3061 | /* Check if forcing the decision is configured. | ||
3062 | * Note that SISO is forced by not allowing STBC or BFER | ||
3063 | */ | ||
3064 | if (lq_sta->ss_force == RS_SS_FORCE_STBC) | ||
3065 | ss_params |= (LQ_SS_STBC_1SS_ALLOWED | LQ_SS_FORCE); | ||
3066 | else if (lq_sta->ss_force == RS_SS_FORCE_BFER) | ||
3067 | ss_params |= (LQ_SS_BFER_ALLOWED | LQ_SS_FORCE); | ||
3068 | |||
3069 | if (lq_sta->ss_force != RS_SS_FORCE_NONE) { | ||
3070 | IWL_DEBUG_RATE(mvm, "Forcing single stream Tx decision %d\n", | ||
3071 | lq_sta->ss_force); | ||
3072 | goto out; | ||
3073 | } | ||
3074 | |||
3075 | if (lq_sta->stbc_capable) | ||
3076 | ss_params |= LQ_SS_STBC_1SS_ALLOWED; | ||
3077 | |||
3078 | if (!lq_sta->bfer_capable) | ||
3079 | goto out; | ||
3080 | |||
3081 | ieee80211_iterate_stations_atomic(mvm->hw, | ||
3082 | rs_bfer_active_iter, | ||
3083 | &data); | ||
3084 | bfer_mvmsta = data.bfer_mvmsta; | ||
3085 | |||
3086 | /* This code is safe as it doesn't run concurrently for different | ||
3087 | * stations. This is guaranteed by the fact that calls to | ||
3088 | * ieee80211_tx_status wouldn't run concurrently for a single HW. | ||
3089 | */ | ||
3090 | if (!bfer_mvmsta) { | ||
3091 | IWL_DEBUG_RATE(mvm, "No sta with BFER allowed found. Allow\n"); | ||
3092 | |||
3093 | ss_params |= LQ_SS_BFER_ALLOWED; | ||
3094 | goto out; | ||
3095 | } | ||
3096 | |||
3097 | IWL_DEBUG_RATE(mvm, "Found existing sta %d with BFER activated\n", | ||
3098 | bfer_mvmsta->sta_id); | ||
3099 | |||
3100 | /* Disallow BFER on another STA if active and we're a higher priority */ | ||
3101 | if (rs_bfer_priority_cmp(mvmsta, bfer_mvmsta) > 0) { | ||
3102 | struct iwl_lq_cmd *bfersta_lq_cmd = &bfer_mvmsta->lq_sta.lq; | ||
3103 | u32 bfersta_ss_params = le32_to_cpu(bfersta_lq_cmd->ss_params); | ||
3104 | |||
3105 | bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED; | ||
3106 | bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params); | ||
3107 | iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd, false); | ||
3108 | |||
3109 | ss_params |= LQ_SS_BFER_ALLOWED; | ||
3110 | IWL_DEBUG_RATE(mvm, | ||
3111 | "Lower priority BFER sta found (%d). Switch BFER\n", | ||
3112 | bfer_mvmsta->sta_id); | ||
3113 | } | ||
3114 | out: | ||
3115 | lq_cmd->ss_params = cpu_to_le32(ss_params); | ||
3116 | } | ||
3117 | |||
2983 | static void rs_fill_lq_cmd(struct iwl_mvm *mvm, | 3118 | static void rs_fill_lq_cmd(struct iwl_mvm *mvm, |
2984 | struct ieee80211_sta *sta, | 3119 | struct ieee80211_sta *sta, |
2985 | struct iwl_lq_sta *lq_sta, | 3120 | struct iwl_lq_sta *lq_sta, |
@@ -3006,6 +3141,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, | |||
3006 | 3141 | ||
3007 | rs_build_rates_table(mvm, sta, lq_sta, initial_rate); | 3142 | rs_build_rates_table(mvm, sta, lq_sta, initial_rate); |
3008 | 3143 | ||
3144 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) | ||
3145 | rs_set_lq_ss_params(mvm, sta, lq_sta, initial_rate); | ||
3146 | |||
3009 | if (num_of_ant(initial_rate->ant) == 1) | 3147 | if (num_of_ant(initial_rate->ant) == 1) |
3010 | lq_cmd->single_stream_ant_msk = initial_rate->ant; | 3148 | lq_cmd->single_stream_ant_msk = initial_rate->ant; |
3011 | 3149 | ||
@@ -3379,9 +3517,73 @@ static const struct file_operations rs_sta_dbgfs_drv_tx_stats_ops = { | |||
3379 | .llseek = default_llseek, | 3517 | .llseek = default_llseek, |
3380 | }; | 3518 | }; |
3381 | 3519 | ||
3520 | static ssize_t iwl_dbgfs_ss_force_read(struct file *file, | ||
3521 | char __user *user_buf, | ||
3522 | size_t count, loff_t *ppos) | ||
3523 | { | ||
3524 | struct iwl_lq_sta *lq_sta = file->private_data; | ||
3525 | char buf[12]; | ||
3526 | int bufsz = sizeof(buf); | ||
3527 | int pos = 0; | ||
3528 | static const char * const ss_force_name[] = { | ||
3529 | [RS_SS_FORCE_NONE] = "none", | ||
3530 | [RS_SS_FORCE_STBC] = "stbc", | ||
3531 | [RS_SS_FORCE_BFER] = "bfer", | ||
3532 | [RS_SS_FORCE_SISO] = "siso", | ||
3533 | }; | ||
3534 | |||
3535 | pos += scnprintf(buf+pos, bufsz-pos, "%s\n", | ||
3536 | ss_force_name[lq_sta->ss_force]); | ||
3537 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
3538 | } | ||
3539 | |||
3540 | static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf, | ||
3541 | size_t count, loff_t *ppos) | ||
3542 | { | ||
3543 | struct iwl_mvm *mvm = lq_sta->pers.drv; | ||
3544 | int ret = 0; | ||
3545 | |||
3546 | if (!strncmp("none", buf, 4)) { | ||
3547 | lq_sta->ss_force = RS_SS_FORCE_NONE; | ||
3548 | } else if (!strncmp("siso", buf, 4)) { | ||
3549 | lq_sta->ss_force = RS_SS_FORCE_SISO; | ||
3550 | } else if (!strncmp("stbc", buf, 4)) { | ||
3551 | if (lq_sta->stbc_capable) { | ||
3552 | lq_sta->ss_force = RS_SS_FORCE_STBC; | ||
3553 | } else { | ||
3554 | IWL_ERR(mvm, | ||
3555 | "can't force STBC. peer doesn't support\n"); | ||
3556 | ret = -EINVAL; | ||
3557 | } | ||
3558 | } else if (!strncmp("bfer", buf, 4)) { | ||
3559 | if (lq_sta->bfer_capable) { | ||
3560 | lq_sta->ss_force = RS_SS_FORCE_BFER; | ||
3561 | } else { | ||
3562 | IWL_ERR(mvm, | ||
3563 | "can't force BFER. peer doesn't support\n"); | ||
3564 | ret = -EINVAL; | ||
3565 | } | ||
3566 | } else { | ||
3567 | IWL_ERR(mvm, "valid values none|siso|stbc|bfer\n"); | ||
3568 | ret = -EINVAL; | ||
3569 | } | ||
3570 | return ret ?: count; | ||
3571 | } | ||
3572 | |||
3573 | #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ | ||
3574 | _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_lq_sta) | ||
3575 | #define MVM_DEBUGFS_ADD_FILE_RS(name, parent, mode) do { \ | ||
3576 | if (!debugfs_create_file(#name, mode, parent, lq_sta, \ | ||
3577 | &iwl_dbgfs_##name##_ops)) \ | ||
3578 | goto err; \ | ||
3579 | } while (0) | ||
3580 | |||
3581 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(ss_force, 32); | ||
3582 | |||
3382 | static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) | 3583 | static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) |
3383 | { | 3584 | { |
3384 | struct iwl_lq_sta *lq_sta = mvm_sta; | 3585 | struct iwl_lq_sta *lq_sta = mvm_sta; |
3586 | |||
3385 | debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, | 3587 | debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, |
3386 | lq_sta, &rs_sta_dbgfs_scale_table_ops); | 3588 | lq_sta, &rs_sta_dbgfs_scale_table_ops); |
3387 | debugfs_create_file("rate_stats_table", S_IRUSR, dir, | 3589 | debugfs_create_file("rate_stats_table", S_IRUSR, dir, |
@@ -3392,6 +3594,11 @@ static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) | |||
3392 | &lq_sta->tx_agg_tid_en); | 3594 | &lq_sta->tx_agg_tid_en); |
3393 | debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir, | 3595 | debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir, |
3394 | &lq_sta->pers.dbg_fixed_txp_reduction); | 3596 | &lq_sta->pers.dbg_fixed_txp_reduction); |
3597 | |||
3598 | MVM_DEBUGFS_ADD_FILE_RS(ss_force, dir, S_IRUSR | S_IWUSR); | ||
3599 | return; | ||
3600 | err: | ||
3601 | IWL_ERR((struct iwl_mvm *)mvm, "Can't create debugfs entity\n"); | ||
3395 | } | 3602 | } |
3396 | 3603 | ||
3397 | static void rs_remove_debugfs(void *mvm, void *mvm_sta) | 3604 | static void rs_remove_debugfs(void *mvm, void *mvm_sta) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index f8f5bf21cc38..dc4ef3dfafe1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h | |||
@@ -240,6 +240,13 @@ enum rs_column { | |||
240 | RS_COLUMN_INVALID, | 240 | RS_COLUMN_INVALID, |
241 | }; | 241 | }; |
242 | 242 | ||
243 | enum rs_ss_force_opt { | ||
244 | RS_SS_FORCE_NONE = 0, | ||
245 | RS_SS_FORCE_STBC, | ||
246 | RS_SS_FORCE_BFER, | ||
247 | RS_SS_FORCE_SISO, | ||
248 | }; | ||
249 | |||
243 | /* Packet stats per rate */ | 250 | /* Packet stats per rate */ |
244 | struct rs_rate_stats { | 251 | struct rs_rate_stats { |
245 | u64 success; | 252 | u64 success; |
@@ -293,7 +300,9 @@ struct iwl_lq_sta { | |||
293 | u64 last_tx; | 300 | u64 last_tx; |
294 | bool is_vht; | 301 | bool is_vht; |
295 | bool ldpc; /* LDPC Rx is supported by the STA */ | 302 | bool ldpc; /* LDPC Rx is supported by the STA */ |
296 | bool stbc; /* Tx STBC is supported by chip and Rx by STA */ | 303 | bool stbc_capable; /* Tx STBC is supported by chip and Rx by STA */ |
304 | bool bfer_capable; /* Remote supports beamformee and we BFer */ | ||
305 | |||
297 | enum ieee80211_band band; | 306 | enum ieee80211_band band; |
298 | 307 | ||
299 | /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ | 308 | /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ |
@@ -322,6 +331,9 @@ struct iwl_lq_sta { | |||
322 | /* tx power reduce for this sta */ | 331 | /* tx power reduce for this sta */ |
323 | int tpc_reduce; | 332 | int tpc_reduce; |
324 | 333 | ||
334 | /* force STBC/BFER/SISO for testing */ | ||
335 | enum rs_ss_force_opt ss_force; | ||
336 | |||
325 | /* persistent fields - initialized only once - keep last! */ | 337 | /* persistent fields - initialized only once - keep last! */ |
326 | struct lq_sta_pers { | 338 | struct lq_sta_pers { |
327 | #ifdef CONFIG_MAC80211_DEBUGFS | 339 | #ifdef CONFIG_MAC80211_DEBUGFS |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 3bd5f34d3285..7e9aa3cb3254 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -704,7 +704,8 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, | |||
704 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | 704 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); |
705 | } | 705 | } |
706 | 706 | ||
707 | mvm->last_ebs_successful = !ebs_status; | 707 | if (ebs_status) |
708 | mvm->last_ebs_successful = false; | ||
708 | 709 | ||
709 | return 0; | 710 | return 0; |
710 | } | 711 | } |
@@ -1682,10 +1683,10 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) | |||
1682 | 1683 | ||
1683 | band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; | 1684 | band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; |
1684 | for (i = 0; i < band->n_channels; i++, j++) | 1685 | for (i = 0; i < band->n_channels; i++, j++) |
1685 | scan_config->channel_array[j] = band->channels[i].center_freq; | 1686 | scan_config->channel_array[j] = band->channels[i].hw_value; |
1686 | band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | 1687 | band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; |
1687 | for (i = 0; i < band->n_channels; i++, j++) | 1688 | for (i = 0; i < band->n_channels; i++, j++) |
1688 | scan_config->channel_array[j] = band->channels[i].center_freq; | 1689 | scan_config->channel_array[j] = band->channels[i].hw_value; |
1689 | 1690 | ||
1690 | cmd.data[0] = scan_config; | 1691 | cmd.data[0] = scan_config; |
1691 | cmd.len[0] = cmd_size; | 1692 | cmd.len[0] = cmd_size; |
@@ -1862,6 +1863,13 @@ int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
1862 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; | 1863 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; |
1863 | 1864 | ||
1864 | cmd->general_flags = cpu_to_le32(flags); | 1865 | cmd->general_flags = cpu_to_le32(flags); |
1866 | |||
1867 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS && | ||
1868 | mvm->last_ebs_successful) | ||
1869 | cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS | | ||
1870 | IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | | ||
1871 | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; | ||
1872 | |||
1865 | cmd->n_channels = req->req.n_channels; | 1873 | cmd->n_channels = req->req.n_channels; |
1866 | 1874 | ||
1867 | for (i = 0; i < req->req.n_ssids; i++) | 1875 | for (i = 0; i < req->req.n_ssids; i++) |
@@ -2025,7 +2033,9 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, | |||
2025 | notif->ebs_status == IWL_SCAN_EBS_SUCCESS ? | 2033 | notif->ebs_status == IWL_SCAN_EBS_SUCCESS ? |
2026 | "success" : "failed"); | 2034 | "success" : "failed"); |
2027 | 2035 | ||
2028 | mvm->last_ebs_successful = !notif->ebs_status; | 2036 | if (notif->ebs_status) |
2037 | mvm->last_ebs_successful = false; | ||
2038 | |||
2029 | mvm->scan_uid[uid_idx] = 0; | 2039 | mvm->scan_uid[uid_idx] = 0; |
2030 | 2040 | ||
2031 | if (!sched) { | 2041 | if (!sched) { |
@@ -2058,10 +2068,14 @@ static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait, | |||
2058 | 2068 | ||
2059 | /* | 2069 | /* |
2060 | * Clear scan uid of scans that was aborted from above and completed | 2070 | * Clear scan uid of scans that was aborted from above and completed |
2061 | * in FW so the RX handler does nothing. | 2071 | * in FW so the RX handler does nothing. Set last_ebs_successful here if |
2072 | * needed. | ||
2062 | */ | 2073 | */ |
2063 | scan_done->mvm->scan_uid[uid_idx] = 0; | 2074 | scan_done->mvm->scan_uid[uid_idx] = 0; |
2064 | 2075 | ||
2076 | if (notif->ebs_status) | ||
2077 | scan_done->mvm->last_ebs_successful = false; | ||
2078 | |||
2065 | return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type); | 2079 | return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type); |
2066 | } | 2080 | } |
2067 | 2081 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 14a848480d04..5c23cddaaae3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -209,6 +209,9 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm, | |||
209 | { | 209 | { |
210 | unsigned long used_hw_queues; | 210 | unsigned long used_hw_queues; |
211 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 211 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
212 | unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? | ||
213 | mvm->cfg->base_params->wd_timeout : | ||
214 | IWL_WATCHDOG_DISABLED; | ||
212 | u32 ac; | 215 | u32 ac; |
213 | 216 | ||
214 | lockdep_assert_held(&mvm->mutex); | 217 | lockdep_assert_held(&mvm->mutex); |
@@ -232,7 +235,7 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm, | |||
232 | /* Found a place for all queues - enable them */ | 235 | /* Found a place for all queues - enable them */ |
233 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 236 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
234 | iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac], | 237 | iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac], |
235 | iwl_mvm_ac_to_tx_fifo[ac]); | 238 | iwl_mvm_ac_to_tx_fifo[ac], wdg_timeout); |
236 | mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]); | 239 | mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]); |
237 | } | 240 | } |
238 | 241 | ||
@@ -626,13 +629,16 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, | |||
626 | 629 | ||
627 | int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) | 630 | int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm) |
628 | { | 631 | { |
632 | unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? | ||
633 | mvm->cfg->base_params->wd_timeout : | ||
634 | IWL_WATCHDOG_DISABLED; | ||
629 | int ret; | 635 | int ret; |
630 | 636 | ||
631 | lockdep_assert_held(&mvm->mutex); | 637 | lockdep_assert_held(&mvm->mutex); |
632 | 638 | ||
633 | /* Map Aux queue to fifo - needs to happen before adding Aux station */ | 639 | /* Map Aux queue to fifo - needs to happen before adding Aux station */ |
634 | iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, | 640 | iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, |
635 | IWL_MVM_TX_FIFO_MCAST); | 641 | IWL_MVM_TX_FIFO_MCAST, wdg_timeout); |
636 | 642 | ||
637 | /* Allocate aux station and assign to it the aux queue */ | 643 | /* Allocate aux station and assign to it the aux queue */ |
638 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), | 644 | ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), |
@@ -965,6 +971,9 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
965 | { | 971 | { |
966 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 972 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
967 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | 973 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; |
974 | unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? | ||
975 | mvm->cfg->base_params->wd_timeout : | ||
976 | IWL_WATCHDOG_DISABLED; | ||
968 | int queue, fifo, ret; | 977 | int queue, fifo, ret; |
969 | u16 ssn; | 978 | u16 ssn; |
970 | 979 | ||
@@ -988,7 +997,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
988 | return -EIO; | 997 | return -EIO; |
989 | 998 | ||
990 | iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid, | 999 | iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid, |
991 | buf_size, ssn); | 1000 | buf_size, ssn, wdg_timeout); |
992 | 1001 | ||
993 | /* | 1002 | /* |
994 | * Even though in theory the peer could have different | 1003 | * Even though in theory the peer could have different |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index c0e00bae5bd0..a87b506c8c72 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c | |||
@@ -64,6 +64,8 @@ | |||
64 | #include <linux/etherdevice.h> | 64 | #include <linux/etherdevice.h> |
65 | #include "mvm.h" | 65 | #include "mvm.h" |
66 | #include "time-event.h" | 66 | #include "time-event.h" |
67 | #include "iwl-io.h" | ||
68 | #include "iwl-prph.h" | ||
67 | 69 | ||
68 | #define TU_TO_US(x) (x * 1024) | 70 | #define TU_TO_US(x) (x * 1024) |
69 | #define TU_TO_MS(x) (TU_TO_US(x) / 1000) | 71 | #define TU_TO_MS(x) (TU_TO_US(x) / 1000) |
@@ -228,6 +230,8 @@ iwl_mvm_tdls_cs_state_str(enum iwl_mvm_tdls_cs_state state) | |||
228 | return "IDLE"; | 230 | return "IDLE"; |
229 | case IWL_MVM_TDLS_SW_REQ_SENT: | 231 | case IWL_MVM_TDLS_SW_REQ_SENT: |
230 | return "REQ SENT"; | 232 | return "REQ SENT"; |
233 | case IWL_MVM_TDLS_SW_RESP_RCVD: | ||
234 | return "RESP RECEIVED"; | ||
231 | case IWL_MVM_TDLS_SW_REQ_RCVD: | 235 | case IWL_MVM_TDLS_SW_REQ_RCVD: |
232 | return "REQ RECEIVED"; | 236 | return "REQ RECEIVED"; |
233 | case IWL_MVM_TDLS_SW_ACTIVE: | 237 | case IWL_MVM_TDLS_SW_ACTIVE: |
@@ -248,6 +252,11 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, | |||
248 | iwl_mvm_tdls_cs_state_str(state)); | 252 | iwl_mvm_tdls_cs_state_str(state)); |
249 | mvm->tdls_cs.state = state; | 253 | mvm->tdls_cs.state = state; |
250 | 254 | ||
255 | /* we only send requests to our switching peer - update sent time */ | ||
256 | if (state == IWL_MVM_TDLS_SW_REQ_SENT) | ||
257 | mvm->tdls_cs.peer.sent_timestamp = | ||
258 | iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG); | ||
259 | |||
251 | if (state == IWL_MVM_TDLS_SW_IDLE) | 260 | if (state == IWL_MVM_TDLS_SW_IDLE) |
252 | mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT; | 261 | mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT; |
253 | } | 262 | } |
@@ -300,7 +309,7 @@ out: | |||
300 | static int | 309 | static int |
301 | iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, | 310 | iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, |
302 | enum iwl_tdls_channel_switch_type type, | 311 | enum iwl_tdls_channel_switch_type type, |
303 | const u8 *peer, bool peer_initiator) | 312 | const u8 *peer, bool peer_initiator, u32 timestamp) |
304 | { | 313 | { |
305 | bool same_peer = false; | 314 | bool same_peer = false; |
306 | int ret = 0; | 315 | int ret = 0; |
@@ -325,17 +334,30 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, | |||
325 | ret = -EINVAL; | 334 | ret = -EINVAL; |
326 | break; | 335 | break; |
327 | case IWL_MVM_TDLS_SW_REQ_SENT: | 336 | case IWL_MVM_TDLS_SW_REQ_SENT: |
337 | /* only allow requests from the same peer */ | ||
338 | if (!same_peer) | ||
339 | ret = -EBUSY; | ||
340 | else if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH && | ||
341 | !peer_initiator) | ||
342 | /* | ||
343 | * We received a ch-switch request while an outgoing | ||
344 | * one is pending. Allow it if the peer is the link | ||
345 | * initiator. | ||
346 | */ | ||
347 | ret = -EBUSY; | ||
348 | else if (type == TDLS_SEND_CHAN_SW_REQ) | ||
349 | /* wait for idle before sending another request */ | ||
350 | ret = -EBUSY; | ||
351 | else if (timestamp <= mvm->tdls_cs.peer.sent_timestamp) | ||
352 | /* we got a stale response - ignore it */ | ||
353 | ret = -EINVAL; | ||
354 | break; | ||
355 | case IWL_MVM_TDLS_SW_RESP_RCVD: | ||
328 | /* | 356 | /* |
329 | * We received a ch-switch request while an outgoing one is | 357 | * we are waiting for the FW to give an "active" notification, |
330 | * pending. Allow it to proceed if the other peer is the same | 358 | * so ignore requests in the meantime |
331 | * one we sent to, and we are not the link initiator. | ||
332 | */ | 359 | */ |
333 | if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH) { | 360 | ret = -EBUSY; |
334 | if (!same_peer) | ||
335 | ret = -EBUSY; | ||
336 | else if (!peer_initiator) /* we are the initiator */ | ||
337 | ret = -EBUSY; | ||
338 | } | ||
339 | break; | 361 | break; |
340 | case IWL_MVM_TDLS_SW_REQ_RCVD: | 362 | case IWL_MVM_TDLS_SW_REQ_RCVD: |
341 | /* as above, allow the link initiator to proceed */ | 363 | /* as above, allow the link initiator to proceed */ |
@@ -349,9 +371,12 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, | |||
349 | } | 371 | } |
350 | break; | 372 | break; |
351 | case IWL_MVM_TDLS_SW_ACTIVE: | 373 | case IWL_MVM_TDLS_SW_ACTIVE: |
352 | /* we don't allow initiations during active channel switch */ | 374 | /* |
353 | if (type == TDLS_SEND_CHAN_SW_REQ) | 375 | * the only valid request when active is a request to return |
354 | ret = -EINVAL; | 376 | * to the base channel by the current off-channel peer |
377 | */ | ||
378 | if (type != TDLS_MOVE_CH || !same_peer) | ||
379 | ret = -EBUSY; | ||
355 | break; | 380 | break; |
356 | } | 381 | } |
357 | 382 | ||
@@ -384,7 +409,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, | |||
384 | 409 | ||
385 | lockdep_assert_held(&mvm->mutex); | 410 | lockdep_assert_held(&mvm->mutex); |
386 | 411 | ||
387 | ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator); | 412 | ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator, |
413 | timestamp); | ||
388 | if (ret) | 414 | if (ret) |
389 | return ret; | 415 | return ret; |
390 | 416 | ||
@@ -473,6 +499,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, | |||
473 | type == TDLS_SEND_CHAN_SW_REQ ? | 499 | type == TDLS_SEND_CHAN_SW_REQ ? |
474 | IWL_MVM_TDLS_SW_REQ_SENT : | 500 | IWL_MVM_TDLS_SW_REQ_SENT : |
475 | IWL_MVM_TDLS_SW_REQ_RCVD); | 501 | IWL_MVM_TDLS_SW_REQ_RCVD); |
502 | } else { | ||
503 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_RESP_RCVD); | ||
476 | } | 504 | } |
477 | 505 | ||
478 | out: | 506 | out: |
@@ -657,12 +685,15 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, | |||
657 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 685 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
658 | enum iwl_tdls_channel_switch_type type; | 686 | enum iwl_tdls_channel_switch_type type; |
659 | unsigned int delay; | 687 | unsigned int delay; |
688 | const char *action_str = | ||
689 | params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ? | ||
690 | "REQ" : "RESP"; | ||
660 | 691 | ||
661 | mutex_lock(&mvm->mutex); | 692 | mutex_lock(&mvm->mutex); |
662 | 693 | ||
663 | IWL_DEBUG_TDLS(mvm, | 694 | IWL_DEBUG_TDLS(mvm, |
664 | "Received TDLS ch switch action %d from %pM status %d\n", | 695 | "Received TDLS ch switch action %s from %pM status %d\n", |
665 | params->action_code, params->sta->addr, params->status); | 696 | action_str, params->sta->addr, params->status); |
666 | 697 | ||
667 | /* | 698 | /* |
668 | * we got a non-zero status from a peer we were switching to - move to | 699 | * we got a non-zero status from a peer we were switching to - move to |
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 4eb3cad31aa9..8decf9953229 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
@@ -432,7 +432,7 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) | |||
432 | mvm->status, table.valid); | 432 | mvm->status, table.valid); |
433 | } | 433 | } |
434 | 434 | ||
435 | IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, | 435 | IWL_ERR(mvm, "0x%08X | %s\n", table.error_id, |
436 | desc_lookup(table.error_id)); | 436 | desc_lookup(table.error_id)); |
437 | IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); | 437 | IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); |
438 | IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); | 438 | IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); |
@@ -531,7 +531,8 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) | |||
531 | } | 531 | } |
532 | 532 | ||
533 | void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, | 533 | void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, |
534 | const struct iwl_trans_txq_scd_cfg *cfg) | 534 | const struct iwl_trans_txq_scd_cfg *cfg, |
535 | unsigned int wdg_timeout) | ||
535 | { | 536 | { |
536 | struct iwl_scd_txq_cfg_cmd cmd = { | 537 | struct iwl_scd_txq_cfg_cmd cmd = { |
537 | .scd_queue = queue, | 538 | .scd_queue = queue, |
@@ -545,11 +546,12 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, | |||
545 | }; | 546 | }; |
546 | 547 | ||
547 | if (!iwl_mvm_is_scd_cfg_supported(mvm)) { | 548 | if (!iwl_mvm_is_scd_cfg_supported(mvm)) { |
548 | iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, cfg); | 549 | iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, cfg, |
550 | wdg_timeout); | ||
549 | return; | 551 | return; |
550 | } | 552 | } |
551 | 553 | ||
552 | iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL); | 554 | iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout); |
553 | WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd), | 555 | WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd), |
554 | "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); | 556 | "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); |
555 | } | 557 | } |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index e5652d82d79e..cae0eb8835ce 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -216,6 +216,7 @@ struct iwl_pcie_txq_scratch_buf { | |||
216 | * @need_update: indicates need to update read/write index | 216 | * @need_update: indicates need to update read/write index |
217 | * @active: stores if queue is active | 217 | * @active: stores if queue is active |
218 | * @ampdu: true if this queue is an ampdu queue for an specific RA/TID | 218 | * @ampdu: true if this queue is an ampdu queue for an specific RA/TID |
219 | * @wd_timeout: queue watchdog timeout (jiffies) - per queue | ||
219 | * | 220 | * |
220 | * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame | 221 | * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame |
221 | * descriptors) and required locking structures. | 222 | * descriptors) and required locking structures. |
@@ -232,6 +233,7 @@ struct iwl_txq { | |||
232 | bool need_update; | 233 | bool need_update; |
233 | u8 active; | 234 | u8 active; |
234 | bool ampdu; | 235 | bool ampdu; |
236 | unsigned long wd_timeout; | ||
235 | }; | 237 | }; |
236 | 238 | ||
237 | static inline dma_addr_t | 239 | static inline dma_addr_t |
@@ -259,7 +261,6 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) | |||
259 | * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) | 261 | * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) |
260 | * @scd_set_active: should the transport configure the SCD for HCMD queue | 262 | * @scd_set_active: should the transport configure the SCD for HCMD queue |
261 | * @rx_page_order: page order for receive buffer size | 263 | * @rx_page_order: page order for receive buffer size |
262 | * @wd_timeout: queue watchdog timeout (jiffies) | ||
263 | * @reg_lock: protect hw register access | 264 | * @reg_lock: protect hw register access |
264 | * @cmd_in_flight: true when we have a host command in flight | 265 | * @cmd_in_flight: true when we have a host command in flight |
265 | * @fw_mon_phys: physical address of the buffer for the firmware monitor | 266 | * @fw_mon_phys: physical address of the buffer for the firmware monitor |
@@ -302,6 +303,7 @@ struct iwl_trans_pcie { | |||
302 | 303 | ||
303 | u8 cmd_queue; | 304 | u8 cmd_queue; |
304 | u8 cmd_fifo; | 305 | u8 cmd_fifo; |
306 | unsigned int cmd_q_wdg_timeout; | ||
305 | u8 n_no_reclaim_cmds; | 307 | u8 n_no_reclaim_cmds; |
306 | u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; | 308 | u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; |
307 | 309 | ||
@@ -312,9 +314,6 @@ struct iwl_trans_pcie { | |||
312 | 314 | ||
313 | const char *const *command_names; | 315 | const char *const *command_names; |
314 | 316 | ||
315 | /* queue watchdog */ | ||
316 | unsigned long wd_timeout; | ||
317 | |||
318 | /*protect hw register */ | 317 | /*protect hw register */ |
319 | spinlock_t reg_lock; | 318 | spinlock_t reg_lock; |
320 | bool cmd_in_flight; | 319 | bool cmd_in_flight; |
@@ -373,7 +372,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr); | |||
373 | int iwl_pcie_tx_stop(struct iwl_trans *trans); | 372 | int iwl_pcie_tx_stop(struct iwl_trans *trans); |
374 | void iwl_pcie_tx_free(struct iwl_trans *trans); | 373 | void iwl_pcie_tx_free(struct iwl_trans *trans); |
375 | void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, | 374 | void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn, |
376 | const struct iwl_trans_txq_scd_cfg *cfg); | 375 | const struct iwl_trans_txq_scd_cfg *cfg, |
376 | unsigned int wdg_timeout); | ||
377 | void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, | 377 | void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue, |
378 | bool configure_scd); | 378 | bool configure_scd); |
379 | int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | 379 | int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 1ff87677c3d3..69935aa5a1b3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -75,6 +75,7 @@ | |||
75 | #include "iwl-trans.h" | 75 | #include "iwl-trans.h" |
76 | #include "iwl-csr.h" | 76 | #include "iwl-csr.h" |
77 | #include "iwl-prph.h" | 77 | #include "iwl-prph.h" |
78 | #include "iwl-scd.h" | ||
78 | #include "iwl-agn-hw.h" | 79 | #include "iwl-agn-hw.h" |
79 | #include "iwl-fw-error-dump.h" | 80 | #include "iwl-fw-error-dump.h" |
80 | #include "internal.h" | 81 | #include "internal.h" |
@@ -1268,6 +1269,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, | |||
1268 | 1269 | ||
1269 | trans_pcie->cmd_queue = trans_cfg->cmd_queue; | 1270 | trans_pcie->cmd_queue = trans_cfg->cmd_queue; |
1270 | trans_pcie->cmd_fifo = trans_cfg->cmd_fifo; | 1271 | trans_pcie->cmd_fifo = trans_cfg->cmd_fifo; |
1272 | trans_pcie->cmd_q_wdg_timeout = trans_cfg->cmd_q_wdg_timeout; | ||
1271 | if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS)) | 1273 | if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS)) |
1272 | trans_pcie->n_no_reclaim_cmds = 0; | 1274 | trans_pcie->n_no_reclaim_cmds = 0; |
1273 | else | 1275 | else |
@@ -1282,9 +1284,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, | |||
1282 | else | 1284 | else |
1283 | trans_pcie->rx_page_order = get_order(4 * 1024); | 1285 | trans_pcie->rx_page_order = get_order(4 * 1024); |
1284 | 1286 | ||
1285 | trans_pcie->wd_timeout = | ||
1286 | msecs_to_jiffies(trans_cfg->queue_watchdog_timeout); | ||
1287 | |||
1288 | trans_pcie->command_names = trans_cfg->command_names; | 1287 | trans_pcie->command_names = trans_cfg->command_names; |
1289 | trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; | 1288 | trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; |
1290 | trans_pcie->scd_set_active = trans_cfg->scd_set_active; | 1289 | trans_pcie->scd_set_active = trans_cfg->scd_set_active; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index d40cd4a67d6e..af0bce736358 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -147,7 +147,6 @@ static void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, | |||
147 | static void iwl_pcie_txq_stuck_timer(unsigned long data) | 147 | static void iwl_pcie_txq_stuck_timer(unsigned long data) |
148 | { | 148 | { |
149 | struct iwl_txq *txq = (void *)data; | 149 | struct iwl_txq *txq = (void *)data; |
150 | struct iwl_queue *q = &txq->q; | ||
151 | struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; | 150 | struct iwl_trans_pcie *trans_pcie = txq->trans_pcie; |
152 | struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie); | 151 | struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie); |
153 | u32 scd_sram_addr = trans_pcie->scd_base_addr + | 152 | u32 scd_sram_addr = trans_pcie->scd_base_addr + |
@@ -164,7 +163,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) | |||
164 | spin_unlock(&txq->lock); | 163 | spin_unlock(&txq->lock); |
165 | 164 | ||
166 | IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id, | 165 | IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id, |
167 | jiffies_to_msecs(trans_pcie->wd_timeout)); | 166 | jiffies_to_msecs(txq->wd_timeout)); |
168 | IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", | 167 | IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n", |
169 | txq->q.read_ptr, txq->q.write_ptr); | 168 | txq->q.read_ptr, txq->q.write_ptr); |
170 | 169 | ||
@@ -198,11 +197,6 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data) | |||
198 | iwl_read_prph(trans, SCD_QUEUE_WRPTR(i))); | 197 | iwl_read_prph(trans, SCD_QUEUE_WRPTR(i))); |
199 | } | 198 | } |
200 | 199 | ||
201 | for (i = q->read_ptr; i != q->write_ptr; | ||
202 | i = iwl_queue_inc_wrap(i)) | ||
203 | IWL_ERR(trans, "scratch %d = 0x%08x\n", i, | ||
204 | le32_to_cpu(txq->scratchbufs[i].scratch)); | ||
205 | |||
206 | iwl_force_nmi(trans); | 200 | iwl_force_nmi(trans); |
207 | } | 201 | } |
208 | 202 | ||
@@ -680,7 +674,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr) | |||
680 | iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); | 674 | iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); |
681 | 675 | ||
682 | iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue, | 676 | iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue, |
683 | trans_pcie->cmd_fifo); | 677 | trans_pcie->cmd_fifo, |
678 | trans_pcie->cmd_q_wdg_timeout); | ||
684 | 679 | ||
685 | /* Activate all Tx DMA/FIFO channels */ | 680 | /* Activate all Tx DMA/FIFO channels */ |
686 | iwl_scd_activate_fifos(trans); | 681 | iwl_scd_activate_fifos(trans); |
@@ -722,7 +717,12 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) | |||
722 | iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, | 717 | iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, |
723 | trans_pcie->kw.dma >> 4); | 718 | trans_pcie->kw.dma >> 4); |
724 | 719 | ||
725 | iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr); | 720 | /* |
721 | * Send 0 as the scd_base_addr since the device may have be reset | ||
722 | * while we were in WoWLAN in which case SCD_SRAM_BASE_ADDR will | ||
723 | * contain garbage. | ||
724 | */ | ||
725 | iwl_pcie_tx_start(trans, 0); | ||
726 | } | 726 | } |
727 | 727 | ||
728 | /* | 728 | /* |
@@ -898,6 +898,10 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) | |||
898 | } | 898 | } |
899 | } | 899 | } |
900 | 900 | ||
901 | if (trans->cfg->base_params->num_of_queues > 20) | ||
902 | iwl_set_bits_prph(trans, SCD_GP_CTRL, | ||
903 | SCD_GP_CTRL_ENABLE_31_QUEUES); | ||
904 | |||
901 | return 0; | 905 | return 0; |
902 | error: | 906 | error: |
903 | /*Upon error, free only if we allocated something */ | 907 | /*Upon error, free only if we allocated something */ |
@@ -906,10 +910,9 @@ error: | |||
906 | return ret; | 910 | return ret; |
907 | } | 911 | } |
908 | 912 | ||
909 | static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie, | 913 | static inline void iwl_pcie_txq_progress(struct iwl_txq *txq) |
910 | struct iwl_txq *txq) | ||
911 | { | 914 | { |
912 | if (!trans_pcie->wd_timeout) | 915 | if (!txq->wd_timeout) |
913 | return; | 916 | return; |
914 | 917 | ||
915 | /* | 918 | /* |
@@ -919,7 +922,7 @@ static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie, | |||
919 | if (txq->q.read_ptr == txq->q.write_ptr) | 922 | if (txq->q.read_ptr == txq->q.write_ptr) |
920 | del_timer(&txq->stuck_timer); | 923 | del_timer(&txq->stuck_timer); |
921 | else | 924 | else |
922 | mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); | 925 | mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); |
923 | } | 926 | } |
924 | 927 | ||
925 | /* Frees buffers until index _not_ inclusive */ | 928 | /* Frees buffers until index _not_ inclusive */ |
@@ -981,7 +984,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | |||
981 | iwl_pcie_txq_free_tfd(trans, txq); | 984 | iwl_pcie_txq_free_tfd(trans, txq); |
982 | } | 985 | } |
983 | 986 | ||
984 | iwl_pcie_txq_progress(trans_pcie, txq); | 987 | iwl_pcie_txq_progress(txq); |
985 | 988 | ||
986 | if (iwl_queue_space(&txq->q) > txq->q.low_mark) | 989 | if (iwl_queue_space(&txq->q) > txq->q.low_mark) |
987 | iwl_wake_queue(trans, txq); | 990 | iwl_wake_queue(trans, txq); |
@@ -1109,7 +1112,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) | |||
1109 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); | 1112 | spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); |
1110 | } | 1113 | } |
1111 | 1114 | ||
1112 | iwl_pcie_txq_progress(trans_pcie, txq); | 1115 | iwl_pcie_txq_progress(txq); |
1113 | } | 1116 | } |
1114 | 1117 | ||
1115 | static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, | 1118 | static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, |
@@ -1142,14 +1145,18 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid, | |||
1142 | #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) | 1145 | #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) |
1143 | 1146 | ||
1144 | void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, | 1147 | void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, |
1145 | const struct iwl_trans_txq_scd_cfg *cfg) | 1148 | const struct iwl_trans_txq_scd_cfg *cfg, |
1149 | unsigned int wdg_timeout) | ||
1146 | { | 1150 | { |
1147 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 1151 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
1152 | struct iwl_txq *txq = &trans_pcie->txq[txq_id]; | ||
1148 | int fifo = -1; | 1153 | int fifo = -1; |
1149 | 1154 | ||
1150 | if (test_and_set_bit(txq_id, trans_pcie->queue_used)) | 1155 | if (test_and_set_bit(txq_id, trans_pcie->queue_used)) |
1151 | WARN_ONCE(1, "queue %d already used - expect issues", txq_id); | 1156 | WARN_ONCE(1, "queue %d already used - expect issues", txq_id); |
1152 | 1157 | ||
1158 | txq->wd_timeout = msecs_to_jiffies(wdg_timeout); | ||
1159 | |||
1153 | if (cfg) { | 1160 | if (cfg) { |
1154 | fifo = cfg->fifo; | 1161 | fifo = cfg->fifo; |
1155 | 1162 | ||
@@ -1173,7 +1180,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, | |||
1173 | 1180 | ||
1174 | /* enable aggregations for the queue */ | 1181 | /* enable aggregations for the queue */ |
1175 | iwl_scd_txq_enable_agg(trans, txq_id); | 1182 | iwl_scd_txq_enable_agg(trans, txq_id); |
1176 | trans_pcie->txq[txq_id].ampdu = true; | 1183 | txq->ampdu = true; |
1177 | } else { | 1184 | } else { |
1178 | /* | 1185 | /* |
1179 | * disable aggregations for the queue, this will also | 1186 | * disable aggregations for the queue, this will also |
@@ -1182,14 +1189,14 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, | |||
1182 | */ | 1189 | */ |
1183 | iwl_scd_txq_disable_agg(trans, txq_id); | 1190 | iwl_scd_txq_disable_agg(trans, txq_id); |
1184 | 1191 | ||
1185 | ssn = trans_pcie->txq[txq_id].q.read_ptr; | 1192 | ssn = txq->q.read_ptr; |
1186 | } | 1193 | } |
1187 | } | 1194 | } |
1188 | 1195 | ||
1189 | /* Place first TFD at index corresponding to start sequence number. | 1196 | /* Place first TFD at index corresponding to start sequence number. |
1190 | * Assumes that ssn_idx is valid (!= 0xFFF) */ | 1197 | * Assumes that ssn_idx is valid (!= 0xFFF) */ |
1191 | trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff); | 1198 | txq->q.read_ptr = (ssn & 0xff); |
1192 | trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff); | 1199 | txq->q.write_ptr = (ssn & 0xff); |
1193 | iwl_write_direct32(trans, HBUS_TARG_WRPTR, | 1200 | iwl_write_direct32(trans, HBUS_TARG_WRPTR, |
1194 | (ssn & 0xff) | (txq_id << 8)); | 1201 | (ssn & 0xff) | (txq_id << 8)); |
1195 | 1202 | ||
@@ -1230,7 +1237,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, | |||
1230 | txq_id, ssn & 0xff); | 1237 | txq_id, ssn & 0xff); |
1231 | } | 1238 | } |
1232 | 1239 | ||
1233 | trans_pcie->txq[txq_id].active = true; | 1240 | txq->active = true; |
1234 | } | 1241 | } |
1235 | 1242 | ||
1236 | void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, | 1243 | void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, |
@@ -1495,8 +1502,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, | |||
1495 | trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); | 1502 | trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); |
1496 | 1503 | ||
1497 | /* start timer if queue currently empty */ | 1504 | /* start timer if queue currently empty */ |
1498 | if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) | 1505 | if (q->read_ptr == q->write_ptr && txq->wd_timeout) |
1499 | mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); | 1506 | mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); |
1500 | 1507 | ||
1501 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); | 1508 | spin_lock_irqsave(&trans_pcie->reg_lock, flags); |
1502 | ret = iwl_pcie_set_cmd_in_flight(trans, cmd); | 1509 | ret = iwl_pcie_set_cmd_in_flight(trans, cmd); |
@@ -1846,9 +1853,8 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, | |||
1846 | 1853 | ||
1847 | /* start timer if queue currently empty */ | 1854 | /* start timer if queue currently empty */ |
1848 | if (q->read_ptr == q->write_ptr) { | 1855 | if (q->read_ptr == q->write_ptr) { |
1849 | if (txq->need_update && trans_pcie->wd_timeout) | 1856 | if (txq->wd_timeout) |
1850 | mod_timer(&txq->stuck_timer, | 1857 | mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); |
1851 | jiffies + trans_pcie->wd_timeout); | ||
1852 | IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id); | 1858 | IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id); |
1853 | iwl_trans_pcie_ref(trans); | 1859 | iwl_trans_pcie_ref(trans); |
1854 | } | 1860 | } |