diff options
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 | } |
