diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2015-03-13 09:09:18 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-03-13 09:09:18 -0400 |
commit | 0cf151bdf99b9f425f12efaff779a09e4120a08f (patch) | |
tree | 06391817ad73ffdfd15e26cbfedacf611ec1cce2 | |
parent | 719a11cdbf57b7bdd6c87ded00fd7cb36a76a6a3 (diff) | |
parent | 208d271a3f5388672b3d7ec141e975abd84ab3da (diff) |
Merge tag 'iwlwifi-next-for-kalle-2015-03-12' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
* Location Aware Regulatory was added by Arik
* 8000 device family work
* Update to the BT Coex firmware API
43 files changed, 1562 insertions, 586 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 47e64e8b9517..cceb026e0793 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -1114,16 +1114,17 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |||
1114 | scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) | | 1114 | scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) | |
1115 | BIT(IWL_DEFAULT_CMD_QUEUE_NUM)); | 1115 | BIT(IWL_DEFAULT_CMD_QUEUE_NUM)); |
1116 | 1116 | ||
1117 | if (vif) | 1117 | if (drop) { |
1118 | scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]); | 1118 | IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", |
1119 | 1119 | scd_queues); | |
1120 | IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues); | 1120 | if (iwlagn_txfifo_flush(priv, scd_queues)) { |
1121 | if (iwlagn_txfifo_flush(priv, scd_queues)) { | 1121 | IWL_ERR(priv, "flush request fail\n"); |
1122 | IWL_ERR(priv, "flush request fail\n"); | 1122 | goto done; |
1123 | goto done; | 1123 | } |
1124 | } | 1124 | } |
1125 | |||
1125 | IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n"); | 1126 | IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n"); |
1126 | iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff); | 1127 | iwl_trans_wait_tx_queue_empty(priv->trans, scd_queues); |
1127 | done: | 1128 | done: |
1128 | mutex_unlock(&priv->mutex); | 1129 | mutex_unlock(&priv->mutex); |
1129 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 1130 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 32b78a66536d..3bd7c86e90d9 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c | |||
@@ -3153,12 +3153,13 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
3153 | desc += sprintf(buff+desc, "lq type %s\n", | 3153 | desc += sprintf(buff+desc, "lq type %s\n", |
3154 | (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); | 3154 | (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); |
3155 | if (is_Ht(tbl->lq_type)) { | 3155 | if (is_Ht(tbl->lq_type)) { |
3156 | desc += sprintf(buff+desc, " %s", | 3156 | desc += sprintf(buff + desc, " %s", |
3157 | (is_siso(tbl->lq_type)) ? "SISO" : | 3157 | (is_siso(tbl->lq_type)) ? "SISO" : |
3158 | ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); | 3158 | ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); |
3159 | desc += sprintf(buff+desc, " %s", | 3159 | desc += sprintf(buff + desc, " %s", |
3160 | (tbl->is_ht40) ? "40MHz" : "20MHz"); | 3160 | (tbl->is_ht40) ? "40MHz" : "20MHz"); |
3161 | desc += sprintf(buff+desc, " %s %s %s\n", (tbl->is_SGI) ? "SGI" : "", | 3161 | desc += sprintf(buff + desc, " %s %s %s\n", |
3162 | (tbl->is_SGI) ? "SGI" : "", | ||
3162 | (lq_sta->is_green) ? "GF enabled" : "", | 3163 | (lq_sta->is_green) ? "GF enabled" : "", |
3163 | (lq_sta->is_agg) ? "AGG on" : ""); | 3164 | (lq_sta->is_agg) ? "AGG on" : ""); |
3164 | } | 3165 | } |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 1e40a12de077..275df12a6045 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -189,9 +189,9 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, | |||
189 | rate_flags |= RATE_MCS_CCK_MSK; | 189 | rate_flags |= RATE_MCS_CCK_MSK; |
190 | 190 | ||
191 | /* Set up antennas */ | 191 | /* Set up antennas */ |
192 | if (priv->lib->bt_params && | 192 | if (priv->lib->bt_params && |
193 | priv->lib->bt_params->advanced_bt_coexist && | 193 | priv->lib->bt_params->advanced_bt_coexist && |
194 | priv->bt_full_concurrent) { | 194 | priv->bt_full_concurrent) { |
195 | /* operated as 1x1 in full concurrency mode */ | 195 | /* operated as 1x1 in full concurrency mode */ |
196 | priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, | 196 | priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, |
197 | first_antenna(priv->nvm_data->valid_tx_ant)); | 197 | first_antenna(priv->nvm_data->valid_tx_ant)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index c3817fae16c0..06f6cc08f451 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c | |||
@@ -95,7 +95,8 @@ static const struct iwl_eeprom_params iwl1000_eeprom_params = { | |||
95 | .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ | 95 | .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ |
96 | .base_params = &iwl1000_base_params, \ | 96 | .base_params = &iwl1000_base_params, \ |
97 | .eeprom_params = &iwl1000_eeprom_params, \ | 97 | .eeprom_params = &iwl1000_eeprom_params, \ |
98 | .led_mode = IWL_LED_BLINK | 98 | .led_mode = IWL_LED_BLINK, \ |
99 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
99 | 100 | ||
100 | const struct iwl_cfg iwl1000_bgn_cfg = { | 101 | const struct iwl_cfg iwl1000_bgn_cfg = { |
101 | .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN", | 102 | .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN", |
@@ -121,7 +122,8 @@ const struct iwl_cfg iwl1000_bg_cfg = { | |||
121 | .base_params = &iwl1000_base_params, \ | 122 | .base_params = &iwl1000_base_params, \ |
122 | .eeprom_params = &iwl1000_eeprom_params, \ | 123 | .eeprom_params = &iwl1000_eeprom_params, \ |
123 | .led_mode = IWL_LED_RF_STATE, \ | 124 | .led_mode = IWL_LED_RF_STATE, \ |
124 | .rx_with_siso_diversity = true | 125 | .rx_with_siso_diversity = true, \ |
126 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
125 | 127 | ||
126 | const struct iwl_cfg iwl100_bgn_cfg = { | 128 | const struct iwl_cfg iwl100_bgn_cfg = { |
127 | .name = "Intel(R) Centrino(R) Wireless-N 100 BGN", | 129 | .name = "Intel(R) Centrino(R) Wireless-N 100 BGN", |
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 21e5d0843a62..890b95f497d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c | |||
@@ -123,7 +123,9 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = { | |||
123 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ | 123 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ |
124 | .base_params = &iwl2000_base_params, \ | 124 | .base_params = &iwl2000_base_params, \ |
125 | .eeprom_params = &iwl20x0_eeprom_params, \ | 125 | .eeprom_params = &iwl20x0_eeprom_params, \ |
126 | .led_mode = IWL_LED_RF_STATE | 126 | .led_mode = IWL_LED_RF_STATE, \ |
127 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
128 | |||
127 | 129 | ||
128 | const struct iwl_cfg iwl2000_2bgn_cfg = { | 130 | const struct iwl_cfg iwl2000_2bgn_cfg = { |
129 | .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN", | 131 | .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN", |
@@ -149,7 +151,8 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = { | |||
149 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ | 151 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ |
150 | .base_params = &iwl2030_base_params, \ | 152 | .base_params = &iwl2030_base_params, \ |
151 | .eeprom_params = &iwl20x0_eeprom_params, \ | 153 | .eeprom_params = &iwl20x0_eeprom_params, \ |
152 | .led_mode = IWL_LED_RF_STATE | 154 | .led_mode = IWL_LED_RF_STATE, \ |
155 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
153 | 156 | ||
154 | const struct iwl_cfg iwl2030_2bgn_cfg = { | 157 | const struct iwl_cfg iwl2030_2bgn_cfg = { |
155 | .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN", | 158 | .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN", |
@@ -170,7 +173,8 @@ const struct iwl_cfg iwl2030_2bgn_cfg = { | |||
170 | .base_params = &iwl2000_base_params, \ | 173 | .base_params = &iwl2000_base_params, \ |
171 | .eeprom_params = &iwl20x0_eeprom_params, \ | 174 | .eeprom_params = &iwl20x0_eeprom_params, \ |
172 | .led_mode = IWL_LED_RF_STATE, \ | 175 | .led_mode = IWL_LED_RF_STATE, \ |
173 | .rx_with_siso_diversity = true | 176 | .rx_with_siso_diversity = true, \ |
177 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
174 | 178 | ||
175 | const struct iwl_cfg iwl105_bgn_cfg = { | 179 | const struct iwl_cfg iwl105_bgn_cfg = { |
176 | .name = "Intel(R) Centrino(R) Wireless-N 105 BGN", | 180 | .name = "Intel(R) Centrino(R) Wireless-N 105 BGN", |
@@ -197,7 +201,8 @@ const struct iwl_cfg iwl105_bgn_d_cfg = { | |||
197 | .base_params = &iwl2030_base_params, \ | 201 | .base_params = &iwl2030_base_params, \ |
198 | .eeprom_params = &iwl20x0_eeprom_params, \ | 202 | .eeprom_params = &iwl20x0_eeprom_params, \ |
199 | .led_mode = IWL_LED_RF_STATE, \ | 203 | .led_mode = IWL_LED_RF_STATE, \ |
200 | .rx_with_siso_diversity = true | 204 | .rx_with_siso_diversity = true, \ |
205 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
201 | 206 | ||
202 | const struct iwl_cfg iwl135_bgn_cfg = { | 207 | const struct iwl_cfg iwl135_bgn_cfg = { |
203 | .name = "Intel(R) Centrino(R) Wireless-N 135 BGN", | 208 | .name = "Intel(R) Centrino(R) Wireless-N 135 BGN", |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 332bbede39e5..724194e23414 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -93,7 +93,8 @@ static const struct iwl_eeprom_params iwl5000_eeprom_params = { | |||
93 | .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ | 93 | .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ |
94 | .base_params = &iwl5000_base_params, \ | 94 | .base_params = &iwl5000_base_params, \ |
95 | .eeprom_params = &iwl5000_eeprom_params, \ | 95 | .eeprom_params = &iwl5000_eeprom_params, \ |
96 | .led_mode = IWL_LED_BLINK | 96 | .led_mode = IWL_LED_BLINK, \ |
97 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
97 | 98 | ||
98 | const struct iwl_cfg iwl5300_agn_cfg = { | 99 | const struct iwl_cfg iwl5300_agn_cfg = { |
99 | .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", | 100 | .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", |
@@ -158,7 +159,8 @@ const struct iwl_cfg iwl5350_agn_cfg = { | |||
158 | .base_params = &iwl5000_base_params, \ | 159 | .base_params = &iwl5000_base_params, \ |
159 | .eeprom_params = &iwl5000_eeprom_params, \ | 160 | .eeprom_params = &iwl5000_eeprom_params, \ |
160 | .led_mode = IWL_LED_BLINK, \ | 161 | .led_mode = IWL_LED_BLINK, \ |
161 | .internal_wimax_coex = true | 162 | .internal_wimax_coex = true, \ |
163 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
162 | 164 | ||
163 | const struct iwl_cfg iwl5150_agn_cfg = { | 165 | const struct iwl_cfg iwl5150_agn_cfg = { |
164 | .name = "Intel(R) WiMAX/WiFi Link 5150 AGN", | 166 | .name = "Intel(R) WiMAX/WiFi Link 5150 AGN", |
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 8f2c3c8c6b84..21b2630763dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -145,7 +145,8 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = { | |||
145 | .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ | 145 | .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ |
146 | .base_params = &iwl6000_g2_base_params, \ | 146 | .base_params = &iwl6000_g2_base_params, \ |
147 | .eeprom_params = &iwl6000_eeprom_params, \ | 147 | .eeprom_params = &iwl6000_eeprom_params, \ |
148 | .led_mode = IWL_LED_RF_STATE | 148 | .led_mode = IWL_LED_RF_STATE, \ |
149 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
149 | 150 | ||
150 | const struct iwl_cfg iwl6005_2agn_cfg = { | 151 | const struct iwl_cfg iwl6005_2agn_cfg = { |
151 | .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN", | 152 | .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN", |
@@ -199,7 +200,8 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = { | |||
199 | .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ | 200 | .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ |
200 | .base_params = &iwl6000_g2_base_params, \ | 201 | .base_params = &iwl6000_g2_base_params, \ |
201 | .eeprom_params = &iwl6000_eeprom_params, \ | 202 | .eeprom_params = &iwl6000_eeprom_params, \ |
202 | .led_mode = IWL_LED_RF_STATE | 203 | .led_mode = IWL_LED_RF_STATE, \ |
204 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
203 | 205 | ||
204 | const struct iwl_cfg iwl6030_2agn_cfg = { | 206 | const struct iwl_cfg iwl6030_2agn_cfg = { |
205 | .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN", | 207 | .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN", |
@@ -235,7 +237,8 @@ const struct iwl_cfg iwl6030_2bg_cfg = { | |||
235 | .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ | 237 | .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ |
236 | .base_params = &iwl6000_g2_base_params, \ | 238 | .base_params = &iwl6000_g2_base_params, \ |
237 | .eeprom_params = &iwl6000_eeprom_params, \ | 239 | .eeprom_params = &iwl6000_eeprom_params, \ |
238 | .led_mode = IWL_LED_RF_STATE | 240 | .led_mode = IWL_LED_RF_STATE, \ |
241 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
239 | 242 | ||
240 | const struct iwl_cfg iwl6035_2agn_cfg = { | 243 | const struct iwl_cfg iwl6035_2agn_cfg = { |
241 | .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", | 244 | .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", |
@@ -290,7 +293,8 @@ const struct iwl_cfg iwl130_bg_cfg = { | |||
290 | .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ | 293 | .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ |
291 | .base_params = &iwl6000_base_params, \ | 294 | .base_params = &iwl6000_base_params, \ |
292 | .eeprom_params = &iwl6000_eeprom_params, \ | 295 | .eeprom_params = &iwl6000_eeprom_params, \ |
293 | .led_mode = IWL_LED_BLINK | 296 | .led_mode = IWL_LED_BLINK, \ |
297 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
294 | 298 | ||
295 | const struct iwl_cfg iwl6000i_2agn_cfg = { | 299 | const struct iwl_cfg iwl6000i_2agn_cfg = { |
296 | .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN", | 300 | .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN", |
@@ -322,7 +326,8 @@ const struct iwl_cfg iwl6000i_2bg_cfg = { | |||
322 | .base_params = &iwl6050_base_params, \ | 326 | .base_params = &iwl6050_base_params, \ |
323 | .eeprom_params = &iwl6000_eeprom_params, \ | 327 | .eeprom_params = &iwl6000_eeprom_params, \ |
324 | .led_mode = IWL_LED_BLINK, \ | 328 | .led_mode = IWL_LED_BLINK, \ |
325 | .internal_wimax_coex = true | 329 | .internal_wimax_coex = true, \ |
330 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
326 | 331 | ||
327 | const struct iwl_cfg iwl6050_2agn_cfg = { | 332 | const struct iwl_cfg iwl6050_2agn_cfg = { |
328 | .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN", | 333 | .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN", |
@@ -347,7 +352,8 @@ const struct iwl_cfg iwl6050_2abg_cfg = { | |||
347 | .base_params = &iwl6050_base_params, \ | 352 | .base_params = &iwl6050_base_params, \ |
348 | .eeprom_params = &iwl6000_eeprom_params, \ | 353 | .eeprom_params = &iwl6000_eeprom_params, \ |
349 | .led_mode = IWL_LED_BLINK, \ | 354 | .led_mode = IWL_LED_BLINK, \ |
350 | .internal_wimax_coex = true | 355 | .internal_wimax_coex = true, \ |
356 | .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K | ||
351 | 357 | ||
352 | const struct iwl_cfg iwl6150_bgn_cfg = { | 358 | const struct iwl_cfg iwl6150_bgn_cfg = { |
353 | .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN", | 359 | .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN", |
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 0597a9cfd2f6..36e786f0387b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c | |||
@@ -69,12 +69,12 @@ | |||
69 | #include "iwl-agn-hw.h" | 69 | #include "iwl-agn-hw.h" |
70 | 70 | ||
71 | /* Highest firmware API version supported */ | 71 | /* Highest firmware API version supported */ |
72 | #define IWL7260_UCODE_API_MAX 12 | 72 | #define IWL7260_UCODE_API_MAX 13 |
73 | #define IWL3160_UCODE_API_MAX 12 | 73 | #define IWL3160_UCODE_API_MAX 13 |
74 | 74 | ||
75 | /* Oldest version we won't warn about */ | 75 | /* Oldest version we won't warn about */ |
76 | #define IWL7260_UCODE_API_OK 10 | 76 | #define IWL7260_UCODE_API_OK 12 |
77 | #define IWL3160_UCODE_API_OK 10 | 77 | #define IWL3160_UCODE_API_OK 12 |
78 | 78 | ||
79 | /* Lowest firmware API version supported */ | 79 | /* Lowest firmware API version supported */ |
80 | #define IWL7260_UCODE_API_MIN 10 | 80 | #define IWL7260_UCODE_API_MIN 10 |
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index d8dfa6da6307..9c396a42aec8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c | |||
@@ -69,10 +69,10 @@ | |||
69 | #include "iwl-agn-hw.h" | 69 | #include "iwl-agn-hw.h" |
70 | 70 | ||
71 | /* Highest firmware API version supported */ | 71 | /* Highest firmware API version supported */ |
72 | #define IWL8000_UCODE_API_MAX 12 | 72 | #define IWL8000_UCODE_API_MAX 13 |
73 | 73 | ||
74 | /* Oldest version we won't warn about */ | 74 | /* Oldest version we won't warn about */ |
75 | #define IWL8000_UCODE_API_OK 10 | 75 | #define IWL8000_UCODE_API_OK 12 |
76 | 76 | ||
77 | /* Lowest firmware API version supported */ | 77 | /* Lowest firmware API version supported */ |
78 | #define IWL8000_UCODE_API_MIN 10 | 78 | #define IWL8000_UCODE_API_MIN 10 |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 684254553558..9bb36d79c2bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h | |||
@@ -157,6 +157,7 @@ do { \ | |||
157 | /* 0x0000F000 - 0x00001000 */ | 157 | /* 0x0000F000 - 0x00001000 */ |
158 | #define IWL_DL_ASSOC 0x00001000 | 158 | #define IWL_DL_ASSOC 0x00001000 |
159 | #define IWL_DL_DROP 0x00002000 | 159 | #define IWL_DL_DROP 0x00002000 |
160 | #define IWL_DL_LAR 0x00004000 | ||
160 | #define IWL_DL_COEX 0x00008000 | 161 | #define IWL_DL_COEX 0x00008000 |
161 | /* 0x000F0000 - 0x00010000 */ | 162 | /* 0x000F0000 - 0x00010000 */ |
162 | #define IWL_DL_FW 0x00010000 | 163 | #define IWL_DL_FW 0x00010000 |
@@ -219,5 +220,6 @@ do { \ | |||
219 | #define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a) | 220 | #define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a) |
220 | #define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a) | 221 | #define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a) |
221 | #define IWL_DEBUG_RPM(p, f, a...) IWL_DEBUG(p, IWL_DL_RPM, f, ## a) | 222 | #define IWL_DEBUG_RPM(p, f, a...) IWL_DEBUG(p, IWL_DL_RPM, f, ## a) |
223 | #define IWL_DEBUG_LAR(p, f, a...) IWL_DEBUG(p, IWL_DL_LAR, f, ## a) | ||
222 | 224 | ||
223 | #endif | 225 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 141331d41abf..66ca000f0da1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -1014,34 +1014,34 @@ static int validate_sec_sizes(struct iwl_drv *drv, | |||
1014 | 1014 | ||
1015 | /* Verify that uCode images will fit in card's SRAM. */ | 1015 | /* Verify that uCode images will fit in card's SRAM. */ |
1016 | if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) > | 1016 | if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) > |
1017 | cfg->max_inst_size) { | 1017 | cfg->max_inst_size) { |
1018 | IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n", | 1018 | IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n", |
1019 | get_sec_size(pieces, IWL_UCODE_REGULAR, | 1019 | get_sec_size(pieces, IWL_UCODE_REGULAR, |
1020 | IWL_UCODE_SECTION_INST)); | 1020 | IWL_UCODE_SECTION_INST)); |
1021 | return -1; | 1021 | return -1; |
1022 | } | 1022 | } |
1023 | 1023 | ||
1024 | if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) > | 1024 | if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) > |
1025 | cfg->max_data_size) { | 1025 | cfg->max_data_size) { |
1026 | IWL_ERR(drv, "uCode data len %Zd too large to fit in\n", | 1026 | IWL_ERR(drv, "uCode data len %Zd too large to fit in\n", |
1027 | get_sec_size(pieces, IWL_UCODE_REGULAR, | 1027 | get_sec_size(pieces, IWL_UCODE_REGULAR, |
1028 | IWL_UCODE_SECTION_DATA)); | 1028 | IWL_UCODE_SECTION_DATA)); |
1029 | return -1; | 1029 | return -1; |
1030 | } | 1030 | } |
1031 | 1031 | ||
1032 | if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) > | 1032 | if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) > |
1033 | cfg->max_inst_size) { | 1033 | cfg->max_inst_size) { |
1034 | IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n", | 1034 | IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n", |
1035 | get_sec_size(pieces, IWL_UCODE_INIT, | 1035 | get_sec_size(pieces, IWL_UCODE_INIT, |
1036 | IWL_UCODE_SECTION_INST)); | 1036 | IWL_UCODE_SECTION_INST)); |
1037 | return -1; | 1037 | return -1; |
1038 | } | 1038 | } |
1039 | 1039 | ||
1040 | if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) > | 1040 | if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) > |
1041 | cfg->max_data_size) { | 1041 | cfg->max_data_size) { |
1042 | IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n", | 1042 | IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n", |
1043 | get_sec_size(pieces, IWL_UCODE_REGULAR, | 1043 | get_sec_size(pieces, IWL_UCODE_REGULAR, |
1044 | IWL_UCODE_SECTION_DATA)); | 1044 | IWL_UCODE_SECTION_DATA)); |
1045 | return -1; | 1045 | return -1; |
1046 | } | 1046 | } |
1047 | return 0; | 1047 | return 0; |
@@ -1546,6 +1546,10 @@ module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable, | |||
1546 | bool, S_IRUGO); | 1546 | bool, S_IRUGO); |
1547 | MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)"); | 1547 | MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)"); |
1548 | 1548 | ||
1549 | module_param_named(lar_disable, iwlwifi_mod_params.lar_disable, | ||
1550 | bool, S_IRUGO); | ||
1551 | MODULE_PARM_DESC(lar_disable, "disable LAR functionality (default: N)"); | ||
1552 | |||
1549 | module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, | 1553 | module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, |
1550 | bool, S_IRUGO | S_IWUSR); | 1554 | bool, S_IRUGO | S_IWUSR); |
1551 | #ifdef CONFIG_IWLWIFI_UAPSD | 1555 | #ifdef CONFIG_IWLWIFI_UAPSD |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index adf522c756e6..67a3a241b331 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h | |||
@@ -68,7 +68,7 @@ | |||
68 | 68 | ||
69 | /* for all modules */ | 69 | /* for all modules */ |
70 | #define DRV_NAME "iwlwifi" | 70 | #define DRV_NAME "iwlwifi" |
71 | #define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation" | 71 | #define DRV_COPYRIGHT "Copyright(c) 2003- 2015 Intel Corporation" |
72 | #define DRV_AUTHOR "<ilw@linux.intel.com>" | 72 | #define DRV_AUTHOR "<ilw@linux.intel.com>" |
73 | 73 | ||
74 | /* radio config bits (actual values from NVM definition) */ | 74 | /* radio config bits (actual values from NVM definition) */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h index f0548b8a64b0..5234a0bf11e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h | |||
@@ -94,6 +94,7 @@ struct iwl_nvm_data { | |||
94 | u32 nvm_version; | 94 | u32 nvm_version; |
95 | s8 max_tx_pwr_half_dbm; | 95 | s8 max_tx_pwr_half_dbm; |
96 | 96 | ||
97 | bool lar_enabled; | ||
97 | struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; | 98 | struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; |
98 | struct ieee80211_channel channels[]; | 99 | struct ieee80211_channel channels[]; |
99 | }; | 100 | }; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 5ea381861d5d..291a3382aa3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h | |||
@@ -240,10 +240,9 @@ enum iwl_ucode_tlv_flag { | |||
240 | /** | 240 | /** |
241 | * enum iwl_ucode_tlv_api - ucode api | 241 | * enum iwl_ucode_tlv_api - ucode api |
242 | * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex | 242 | * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex |
243 | * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. | ||
244 | * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. | ||
245 | * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time | 243 | * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time |
246 | * longer than the passive one, which is essential for fragmented scan. | 244 | * longer than the passive one, which is essential for fragmented scan. |
245 | * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. | ||
247 | * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR | 246 | * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR |
248 | * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, | 247 | * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, |
249 | * regardless of the band or the number of the probes. FW will calculate | 248 | * regardless of the band or the number of the probes. FW will calculate |
@@ -258,9 +257,8 @@ enum iwl_ucode_tlv_flag { | |||
258 | */ | 257 | */ |
259 | enum iwl_ucode_tlv_api { | 258 | enum iwl_ucode_tlv_api { |
260 | IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), | 259 | IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), |
261 | IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), | ||
262 | IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), | ||
263 | IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), | 260 | IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), |
261 | IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = BIT(9), | ||
264 | IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10), | 262 | IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10), |
265 | IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), | 263 | IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), |
266 | IWL_UCODE_TLV_API_SCD_CFG = BIT(15), | 264 | IWL_UCODE_TLV_API_SCD_CFG = BIT(15), |
@@ -292,6 +290,7 @@ enum iwl_ucode_tlv_api { | |||
292 | * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command | 290 | * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command |
293 | * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics | 291 | * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics |
294 | * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running | 292 | * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running |
293 | * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC | ||
295 | */ | 294 | */ |
296 | enum iwl_ucode_tlv_capa { | 295 | enum iwl_ucode_tlv_capa { |
297 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), | 296 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), |
@@ -308,6 +307,7 @@ enum iwl_ucode_tlv_capa { | |||
308 | IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18), | 307 | IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18), |
309 | IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = BIT(22), | 308 | IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = BIT(22), |
310 | IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = BIT(28), | 309 | IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = BIT(28), |
310 | IWL_UCODE_TLV_CAPA_BT_COEX_RRC = BIT(30), | ||
311 | }; | 311 | }; |
312 | 312 | ||
313 | /* The default calibrate table size if not specified by firmware file */ | 313 | /* The default calibrate table size if not specified by firmware file */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 03250a45272e..78cac43e2bcd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c | |||
@@ -201,6 +201,8 @@ void iwl_force_nmi(struct iwl_trans *trans) | |||
201 | } else { | 201 | } else { |
202 | iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, | 202 | iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, |
203 | DEVICE_SET_NMI_8000B_VAL); | 203 | DEVICE_SET_NMI_8000B_VAL); |
204 | iwl_write_prph(trans, DEVICE_SET_NMI_REG, | ||
205 | DEVICE_SET_NMI_VAL_DRV); | ||
204 | } | 206 | } |
205 | } | 207 | } |
206 | IWL_EXPORT_SYMBOL(iwl_force_nmi); | 208 | IWL_EXPORT_SYMBOL(iwl_force_nmi); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index e8eabd21ccfe..ac2b90df8413 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h | |||
@@ -103,6 +103,7 @@ enum iwl_disable_11n { | |||
103 | * @debug_level: levels are IWL_DL_* | 103 | * @debug_level: levels are IWL_DL_* |
104 | * @ant_coupling: antenna coupling in dB, default = 0 | 104 | * @ant_coupling: antenna coupling in dB, default = 0 |
105 | * @d0i3_disable: disable d0i3, default = 1, | 105 | * @d0i3_disable: disable d0i3, default = 1, |
106 | * @lar_disable: disable LAR (regulatory), default = 0 | ||
106 | * @fw_monitor: allow to use firmware monitor | 107 | * @fw_monitor: allow to use firmware monitor |
107 | */ | 108 | */ |
108 | struct iwl_mod_params { | 109 | struct iwl_mod_params { |
@@ -121,6 +122,7 @@ struct iwl_mod_params { | |||
121 | char *nvm_file; | 122 | char *nvm_file; |
122 | bool uapsd_disable; | 123 | bool uapsd_disable; |
123 | bool d0i3_disable; | 124 | bool d0i3_disable; |
125 | bool lar_disable; | ||
124 | bool fw_monitor; | 126 | bool fw_monitor; |
125 | }; | 127 | }; |
126 | 128 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index c74f1a4edf23..774637746427 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | |||
@@ -103,8 +103,16 @@ enum family_8000_nvm_offsets { | |||
103 | SKU_FAMILY_8000 = 4, | 103 | SKU_FAMILY_8000 = 4, |
104 | N_HW_ADDRS_FAMILY_8000 = 5, | 104 | N_HW_ADDRS_FAMILY_8000 = 5, |
105 | 105 | ||
106 | /* NVM PHY-SKU-Section offset (in words) for B0 */ | ||
107 | RADIO_CFG_FAMILY_8000_B0 = 0, | ||
108 | SKU_FAMILY_8000_B0 = 2, | ||
109 | N_HW_ADDRS_FAMILY_8000_B0 = 3, | ||
110 | |||
106 | /* NVM REGULATORY -Section offset (in words) definitions */ | 111 | /* NVM REGULATORY -Section offset (in words) definitions */ |
107 | NVM_CHANNELS_FAMILY_8000 = 0, | 112 | NVM_CHANNELS_FAMILY_8000 = 0, |
113 | NVM_LAR_OFFSET_FAMILY_8000_OLD = 0x4C7, | ||
114 | NVM_LAR_OFFSET_FAMILY_8000 = 0x507, | ||
115 | NVM_LAR_ENABLED_FAMILY_8000 = 0x7, | ||
108 | 116 | ||
109 | /* NVM calibration section offset (in words) definitions */ | 117 | /* NVM calibration section offset (in words) definitions */ |
110 | NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8, | 118 | NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8, |
@@ -146,7 +154,9 @@ static const u8 iwl_nvm_channels_family_8000[] = { | |||
146 | #define NUM_2GHZ_CHANNELS_FAMILY_8000 14 | 154 | #define NUM_2GHZ_CHANNELS_FAMILY_8000 14 |
147 | #define FIRST_2GHZ_HT_MINUS 5 | 155 | #define FIRST_2GHZ_HT_MINUS 5 |
148 | #define LAST_2GHZ_HT_PLUS 9 | 156 | #define LAST_2GHZ_HT_PLUS 9 |
149 | #define LAST_5GHZ_HT 161 | 157 | #define LAST_5GHZ_HT 165 |
158 | #define LAST_5GHZ_HT_FAMILY_8000 181 | ||
159 | #define N_HW_ADDR_MASK 0xF | ||
150 | 160 | ||
151 | /* rate data (static) */ | 161 | /* rate data (static) */ |
152 | static struct ieee80211_rate iwl_cfg80211_rates[] = { | 162 | static struct ieee80211_rate iwl_cfg80211_rates[] = { |
@@ -201,9 +211,57 @@ enum iwl_nvm_channel_flags { | |||
201 | #define CHECK_AND_PRINT_I(x) \ | 211 | #define CHECK_AND_PRINT_I(x) \ |
202 | ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "") | 212 | ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "") |
203 | 213 | ||
214 | static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, | ||
215 | u16 nvm_flags, const struct iwl_cfg *cfg) | ||
216 | { | ||
217 | u32 flags = IEEE80211_CHAN_NO_HT40; | ||
218 | u32 last_5ghz_ht = LAST_5GHZ_HT; | ||
219 | |||
220 | if (cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
221 | last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000; | ||
222 | |||
223 | if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) { | ||
224 | if (ch_num <= LAST_2GHZ_HT_PLUS) | ||
225 | flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | ||
226 | if (ch_num >= FIRST_2GHZ_HT_MINUS) | ||
227 | flags &= ~IEEE80211_CHAN_NO_HT40MINUS; | ||
228 | } else if (ch_num <= last_5ghz_ht && (nvm_flags & NVM_CHANNEL_40MHZ)) { | ||
229 | if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) | ||
230 | flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | ||
231 | else | ||
232 | flags &= ~IEEE80211_CHAN_NO_HT40MINUS; | ||
233 | } | ||
234 | if (!(nvm_flags & NVM_CHANNEL_80MHZ)) | ||
235 | flags |= IEEE80211_CHAN_NO_80MHZ; | ||
236 | if (!(nvm_flags & NVM_CHANNEL_160MHZ)) | ||
237 | flags |= IEEE80211_CHAN_NO_160MHZ; | ||
238 | |||
239 | if (!(nvm_flags & NVM_CHANNEL_IBSS)) | ||
240 | flags |= IEEE80211_CHAN_NO_IR; | ||
241 | |||
242 | if (!(nvm_flags & NVM_CHANNEL_ACTIVE)) | ||
243 | flags |= IEEE80211_CHAN_NO_IR; | ||
244 | |||
245 | if (nvm_flags & NVM_CHANNEL_RADAR) | ||
246 | flags |= IEEE80211_CHAN_RADAR; | ||
247 | |||
248 | if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY) | ||
249 | flags |= IEEE80211_CHAN_INDOOR_ONLY; | ||
250 | |||
251 | /* Set the GO concurrent flag only in case that NO_IR is set. | ||
252 | * Otherwise it is meaningless | ||
253 | */ | ||
254 | if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) && | ||
255 | (flags & IEEE80211_CHAN_NO_IR)) | ||
256 | flags |= IEEE80211_CHAN_GO_CONCURRENT; | ||
257 | |||
258 | return flags; | ||
259 | } | ||
260 | |||
204 | static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | 261 | static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, |
205 | struct iwl_nvm_data *data, | 262 | struct iwl_nvm_data *data, |
206 | const __le16 * const nvm_ch_flags) | 263 | const __le16 * const nvm_ch_flags, |
264 | bool lar_supported) | ||
207 | { | 265 | { |
208 | int ch_idx; | 266 | int ch_idx; |
209 | int n_channels = 0; | 267 | int n_channels = 0; |
@@ -228,9 +286,14 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | |||
228 | 286 | ||
229 | if (ch_idx >= num_2ghz_channels && | 287 | if (ch_idx >= num_2ghz_channels && |
230 | !data->sku_cap_band_52GHz_enable) | 288 | !data->sku_cap_band_52GHz_enable) |
231 | ch_flags &= ~NVM_CHANNEL_VALID; | 289 | continue; |
232 | 290 | ||
233 | if (!(ch_flags & NVM_CHANNEL_VALID)) { | 291 | if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) { |
292 | /* | ||
293 | * Channels might become valid later if lar is | ||
294 | * supported, hence we still want to add them to | ||
295 | * the list of supported channels to cfg80211. | ||
296 | */ | ||
234 | IWL_DEBUG_EEPROM(dev, | 297 | IWL_DEBUG_EEPROM(dev, |
235 | "Ch. %d Flags %x [%sGHz] - No traffic\n", | 298 | "Ch. %d Flags %x [%sGHz] - No traffic\n", |
236 | nvm_chan[ch_idx], | 299 | nvm_chan[ch_idx], |
@@ -250,45 +313,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | |||
250 | ieee80211_channel_to_frequency( | 313 | ieee80211_channel_to_frequency( |
251 | channel->hw_value, channel->band); | 314 | channel->hw_value, channel->band); |
252 | 315 | ||
253 | /* TODO: Need to be dependent to the NVM */ | ||
254 | channel->flags = IEEE80211_CHAN_NO_HT40; | ||
255 | if (ch_idx < num_2ghz_channels && | ||
256 | (ch_flags & NVM_CHANNEL_40MHZ)) { | ||
257 | if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS) | ||
258 | channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | ||
259 | if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) | ||
260 | channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; | ||
261 | } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT && | ||
262 | (ch_flags & NVM_CHANNEL_40MHZ)) { | ||
263 | if ((ch_idx - num_2ghz_channels) % 2 == 0) | ||
264 | channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | ||
265 | else | ||
266 | channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; | ||
267 | } | ||
268 | if (!(ch_flags & NVM_CHANNEL_80MHZ)) | ||
269 | channel->flags |= IEEE80211_CHAN_NO_80MHZ; | ||
270 | if (!(ch_flags & NVM_CHANNEL_160MHZ)) | ||
271 | channel->flags |= IEEE80211_CHAN_NO_160MHZ; | ||
272 | |||
273 | if (!(ch_flags & NVM_CHANNEL_IBSS)) | ||
274 | channel->flags |= IEEE80211_CHAN_NO_IR; | ||
275 | |||
276 | if (!(ch_flags & NVM_CHANNEL_ACTIVE)) | ||
277 | channel->flags |= IEEE80211_CHAN_NO_IR; | ||
278 | |||
279 | if (ch_flags & NVM_CHANNEL_RADAR) | ||
280 | channel->flags |= IEEE80211_CHAN_RADAR; | ||
281 | |||
282 | if (ch_flags & NVM_CHANNEL_INDOOR_ONLY) | ||
283 | channel->flags |= IEEE80211_CHAN_INDOOR_ONLY; | ||
284 | |||
285 | /* Set the GO concurrent flag only in case that NO_IR is set. | ||
286 | * Otherwise it is meaningless | ||
287 | */ | ||
288 | if ((ch_flags & NVM_CHANNEL_GO_CONCURRENT) && | ||
289 | (channel->flags & IEEE80211_CHAN_NO_IR)) | ||
290 | channel->flags |= IEEE80211_CHAN_GO_CONCURRENT; | ||
291 | |||
292 | /* Initialize regulatory-based run-time data */ | 316 | /* Initialize regulatory-based run-time data */ |
293 | 317 | ||
294 | /* | 318 | /* |
@@ -297,6 +321,15 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, | |||
297 | */ | 321 | */ |
298 | channel->max_power = IWL_DEFAULT_MAX_TX_POWER; | 322 | channel->max_power = IWL_DEFAULT_MAX_TX_POWER; |
299 | is_5ghz = channel->band == IEEE80211_BAND_5GHZ; | 323 | is_5ghz = channel->band == IEEE80211_BAND_5GHZ; |
324 | |||
325 | /* don't put limitations in case we're using LAR */ | ||
326 | if (!lar_supported) | ||
327 | channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx], | ||
328 | ch_idx, is_5ghz, | ||
329 | ch_flags, cfg); | ||
330 | else | ||
331 | channel->flags = 0; | ||
332 | |||
300 | IWL_DEBUG_EEPROM(dev, | 333 | IWL_DEBUG_EEPROM(dev, |
301 | "Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", | 334 | "Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", |
302 | channel->hw_value, | 335 | channel->hw_value, |
@@ -370,8 +403,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
370 | 403 | ||
371 | static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | 404 | static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, |
372 | struct iwl_nvm_data *data, | 405 | struct iwl_nvm_data *data, |
373 | const __le16 *ch_section, bool enable_vht, | 406 | const __le16 *ch_section, |
374 | u8 tx_chains, u8 rx_chains) | 407 | u8 tx_chains, u8 rx_chains, bool lar_supported) |
375 | { | 408 | { |
376 | int n_channels; | 409 | int n_channels; |
377 | int n_used = 0; | 410 | int n_used = 0; |
@@ -380,11 +413,12 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
380 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | 413 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) |
381 | n_channels = iwl_init_channel_map( | 414 | n_channels = iwl_init_channel_map( |
382 | dev, cfg, data, | 415 | dev, cfg, data, |
383 | &ch_section[NVM_CHANNELS]); | 416 | &ch_section[NVM_CHANNELS], lar_supported); |
384 | else | 417 | else |
385 | n_channels = iwl_init_channel_map( | 418 | n_channels = iwl_init_channel_map( |
386 | dev, cfg, data, | 419 | dev, cfg, data, |
387 | &ch_section[NVM_CHANNELS_FAMILY_8000]); | 420 | &ch_section[NVM_CHANNELS_FAMILY_8000], |
421 | lar_supported); | ||
388 | 422 | ||
389 | sband = &data->bands[IEEE80211_BAND_2GHZ]; | 423 | sband = &data->bands[IEEE80211_BAND_2GHZ]; |
390 | sband->band = IEEE80211_BAND_2GHZ; | 424 | sband->band = IEEE80211_BAND_2GHZ; |
@@ -403,7 +437,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
403 | IEEE80211_BAND_5GHZ); | 437 | IEEE80211_BAND_5GHZ); |
404 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ, | 438 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ, |
405 | tx_chains, rx_chains); | 439 | tx_chains, rx_chains); |
406 | if (enable_vht) | 440 | if (data->sku_cap_11ac_enable) |
407 | iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap, | 441 | iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap, |
408 | tx_chains, rx_chains); | 442 | tx_chains, rx_chains); |
409 | 443 | ||
@@ -413,10 +447,15 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
413 | } | 447 | } |
414 | 448 | ||
415 | static int iwl_get_sku(const struct iwl_cfg *cfg, | 449 | static int iwl_get_sku(const struct iwl_cfg *cfg, |
416 | const __le16 *nvm_sw) | 450 | const __le16 *nvm_sw, const __le16 *phy_sku, |
451 | bool is_family_8000_a_step) | ||
417 | { | 452 | { |
418 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | 453 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) |
419 | return le16_to_cpup(nvm_sw + SKU); | 454 | return le16_to_cpup(nvm_sw + SKU); |
455 | |||
456 | if (!is_family_8000_a_step) | ||
457 | return le32_to_cpup((__le32 *)(phy_sku + | ||
458 | SKU_FAMILY_8000_B0)); | ||
420 | else | 459 | else |
421 | return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000)); | 460 | return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000)); |
422 | } | 461 | } |
@@ -432,23 +471,36 @@ static int iwl_get_nvm_version(const struct iwl_cfg *cfg, | |||
432 | } | 471 | } |
433 | 472 | ||
434 | static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, | 473 | static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, |
435 | const __le16 *nvm_sw) | 474 | const __le16 *nvm_sw, const __le16 *phy_sku, |
475 | bool is_family_8000_a_step) | ||
436 | { | 476 | { |
437 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | 477 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) |
438 | return le16_to_cpup(nvm_sw + RADIO_CFG); | 478 | return le16_to_cpup(nvm_sw + RADIO_CFG); |
479 | |||
480 | if (!is_family_8000_a_step) | ||
481 | return le32_to_cpup((__le32 *)(phy_sku + | ||
482 | RADIO_CFG_FAMILY_8000_B0)); | ||
439 | else | 483 | else |
440 | return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000)); | 484 | return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000)); |
485 | |||
441 | } | 486 | } |
442 | 487 | ||
443 | #define N_HW_ADDRS_MASK_FAMILY_8000 0xF | ||
444 | static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, | 488 | static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, |
445 | const __le16 *nvm_sw) | 489 | const __le16 *nvm_sw, bool is_family_8000_a_step) |
446 | { | 490 | { |
491 | int n_hw_addr; | ||
492 | |||
447 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | 493 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) |
448 | return le16_to_cpup(nvm_sw + N_HW_ADDRS); | 494 | return le16_to_cpup(nvm_sw + N_HW_ADDRS); |
495 | |||
496 | if (!is_family_8000_a_step) | ||
497 | n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + | ||
498 | N_HW_ADDRS_FAMILY_8000_B0)); | ||
449 | else | 499 | else |
450 | return le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000)) | 500 | n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + |
451 | & N_HW_ADDRS_MASK_FAMILY_8000; | 501 | N_HW_ADDRS_FAMILY_8000)); |
502 | |||
503 | return n_hw_addr & N_HW_ADDR_MASK; | ||
452 | } | 504 | } |
453 | 505 | ||
454 | static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, | 506 | static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, |
@@ -491,7 +543,8 @@ static void iwl_set_hw_address_family_8000(struct device *dev, | |||
491 | const struct iwl_cfg *cfg, | 543 | const struct iwl_cfg *cfg, |
492 | struct iwl_nvm_data *data, | 544 | struct iwl_nvm_data *data, |
493 | const __le16 *mac_override, | 545 | const __le16 *mac_override, |
494 | const __le16 *nvm_hw) | 546 | const __le16 *nvm_hw, |
547 | u32 mac_addr0, u32 mac_addr1) | ||
495 | { | 548 | { |
496 | const u8 *hw_addr; | 549 | const u8 *hw_addr; |
497 | 550 | ||
@@ -515,48 +568,17 @@ static void iwl_set_hw_address_family_8000(struct device *dev, | |||
515 | } | 568 | } |
516 | 569 | ||
517 | if (nvm_hw) { | 570 | if (nvm_hw) { |
518 | /* read the MAC address from OTP */ | 571 | /* read the MAC address from HW resisters */ |
519 | if (!dev_is_pci(dev) || (data->nvm_version < 0xE08)) { | 572 | hw_addr = (const u8 *)&mac_addr0; |
520 | /* read the mac address from the WFPM location */ | 573 | data->hw_addr[0] = hw_addr[3]; |
521 | hw_addr = (const u8 *)(nvm_hw + | 574 | data->hw_addr[1] = hw_addr[2]; |
522 | HW_ADDR0_WFPM_FAMILY_8000); | 575 | data->hw_addr[2] = hw_addr[1]; |
523 | data->hw_addr[0] = hw_addr[3]; | 576 | data->hw_addr[3] = hw_addr[0]; |
524 | data->hw_addr[1] = hw_addr[2]; | 577 | |
525 | data->hw_addr[2] = hw_addr[1]; | 578 | hw_addr = (const u8 *)&mac_addr1; |
526 | data->hw_addr[3] = hw_addr[0]; | 579 | data->hw_addr[4] = hw_addr[1]; |
527 | 580 | data->hw_addr[5] = hw_addr[0]; | |
528 | hw_addr = (const u8 *)(nvm_hw + | 581 | |
529 | HW_ADDR1_WFPM_FAMILY_8000); | ||
530 | data->hw_addr[4] = hw_addr[1]; | ||
531 | data->hw_addr[5] = hw_addr[0]; | ||
532 | } else if ((data->nvm_version >= 0xE08) && | ||
533 | (data->nvm_version < 0xE0B)) { | ||
534 | /* read "reverse order" from the PCIe location */ | ||
535 | hw_addr = (const u8 *)(nvm_hw + | ||
536 | HW_ADDR0_PCIE_FAMILY_8000); | ||
537 | data->hw_addr[5] = hw_addr[2]; | ||
538 | data->hw_addr[4] = hw_addr[1]; | ||
539 | data->hw_addr[3] = hw_addr[0]; | ||
540 | |||
541 | hw_addr = (const u8 *)(nvm_hw + | ||
542 | HW_ADDR1_PCIE_FAMILY_8000); | ||
543 | data->hw_addr[2] = hw_addr[3]; | ||
544 | data->hw_addr[1] = hw_addr[2]; | ||
545 | data->hw_addr[0] = hw_addr[1]; | ||
546 | } else { | ||
547 | /* read from the PCIe location */ | ||
548 | hw_addr = (const u8 *)(nvm_hw + | ||
549 | HW_ADDR0_PCIE_FAMILY_8000); | ||
550 | data->hw_addr[5] = hw_addr[0]; | ||
551 | data->hw_addr[4] = hw_addr[1]; | ||
552 | data->hw_addr[3] = hw_addr[2]; | ||
553 | |||
554 | hw_addr = (const u8 *)(nvm_hw + | ||
555 | HW_ADDR1_PCIE_FAMILY_8000); | ||
556 | data->hw_addr[2] = hw_addr[1]; | ||
557 | data->hw_addr[1] = hw_addr[2]; | ||
558 | data->hw_addr[0] = hw_addr[3]; | ||
559 | } | ||
560 | if (!is_valid_ether_addr(data->hw_addr)) | 582 | if (!is_valid_ether_addr(data->hw_addr)) |
561 | IWL_ERR_DEV(dev, | 583 | IWL_ERR_DEV(dev, |
562 | "mac address from hw section is not valid\n"); | 584 | "mac address from hw section is not valid\n"); |
@@ -571,11 +593,15 @@ struct iwl_nvm_data * | |||
571 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | 593 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, |
572 | const __le16 *nvm_hw, const __le16 *nvm_sw, | 594 | const __le16 *nvm_hw, const __le16 *nvm_sw, |
573 | const __le16 *nvm_calib, const __le16 *regulatory, | 595 | const __le16 *nvm_calib, const __le16 *regulatory, |
574 | const __le16 *mac_override, u8 tx_chains, u8 rx_chains) | 596 | const __le16 *mac_override, const __le16 *phy_sku, |
597 | u8 tx_chains, u8 rx_chains, | ||
598 | bool lar_fw_supported, bool is_family_8000_a_step, | ||
599 | u32 mac_addr0, u32 mac_addr1) | ||
575 | { | 600 | { |
576 | struct iwl_nvm_data *data; | 601 | struct iwl_nvm_data *data; |
577 | u32 sku; | 602 | u32 sku; |
578 | u32 radio_cfg; | 603 | u32 radio_cfg; |
604 | u16 lar_config; | ||
579 | 605 | ||
580 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) | 606 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) |
581 | data = kzalloc(sizeof(*data) + | 607 | data = kzalloc(sizeof(*data) + |
@@ -592,22 +618,25 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | |||
592 | 618 | ||
593 | data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw); | 619 | data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw); |
594 | 620 | ||
595 | radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw); | 621 | radio_cfg = |
622 | iwl_get_radio_cfg(cfg, nvm_sw, phy_sku, is_family_8000_a_step); | ||
596 | iwl_set_radio_cfg(cfg, data, radio_cfg); | 623 | iwl_set_radio_cfg(cfg, data, radio_cfg); |
597 | if (data->valid_tx_ant) | 624 | if (data->valid_tx_ant) |
598 | tx_chains &= data->valid_tx_ant; | 625 | tx_chains &= data->valid_tx_ant; |
599 | if (data->valid_rx_ant) | 626 | if (data->valid_rx_ant) |
600 | rx_chains &= data->valid_rx_ant; | 627 | rx_chains &= data->valid_rx_ant; |
601 | 628 | ||
602 | sku = iwl_get_sku(cfg, nvm_sw); | 629 | sku = iwl_get_sku(cfg, nvm_sw, phy_sku, is_family_8000_a_step); |
603 | data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; | 630 | data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; |
604 | data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; | 631 | data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; |
605 | data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; | 632 | data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; |
606 | data->sku_cap_11ac_enable = sku & NVM_SKU_CAP_11AC_ENABLE; | ||
607 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) | 633 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) |
608 | data->sku_cap_11n_enable = false; | 634 | data->sku_cap_11n_enable = false; |
635 | data->sku_cap_11ac_enable = data->sku_cap_11n_enable && | ||
636 | (sku & NVM_SKU_CAP_11AC_ENABLE); | ||
609 | 637 | ||
610 | data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); | 638 | data->n_hw_addrs = |
639 | iwl_get_n_hw_addrs(cfg, nvm_sw, is_family_8000_a_step); | ||
611 | 640 | ||
612 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { | 641 | if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { |
613 | /* Checking for required sections */ | 642 | /* Checking for required sections */ |
@@ -626,16 +655,23 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | |||
626 | iwl_set_hw_address(cfg, data, nvm_hw); | 655 | iwl_set_hw_address(cfg, data, nvm_hw); |
627 | 656 | ||
628 | iwl_init_sbands(dev, cfg, data, nvm_sw, | 657 | iwl_init_sbands(dev, cfg, data, nvm_sw, |
629 | sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, | 658 | tx_chains, rx_chains, lar_fw_supported); |
630 | rx_chains); | ||
631 | } else { | 659 | } else { |
660 | u16 lar_offset = data->nvm_version < 0xE39 ? | ||
661 | NVM_LAR_OFFSET_FAMILY_8000_OLD : | ||
662 | NVM_LAR_OFFSET_FAMILY_8000; | ||
663 | |||
664 | lar_config = le16_to_cpup(regulatory + lar_offset); | ||
665 | data->lar_enabled = !!(lar_config & | ||
666 | NVM_LAR_ENABLED_FAMILY_8000); | ||
667 | |||
632 | /* MAC address in family 8000 */ | 668 | /* MAC address in family 8000 */ |
633 | iwl_set_hw_address_family_8000(dev, cfg, data, mac_override, | 669 | iwl_set_hw_address_family_8000(dev, cfg, data, mac_override, |
634 | nvm_hw); | 670 | nvm_hw, mac_addr0, mac_addr1); |
635 | 671 | ||
636 | iwl_init_sbands(dev, cfg, data, regulatory, | 672 | iwl_init_sbands(dev, cfg, data, regulatory, |
637 | sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, | 673 | tx_chains, rx_chains, |
638 | rx_chains); | 674 | lar_fw_supported && data->lar_enabled); |
639 | } | 675 | } |
640 | 676 | ||
641 | data->calib_version = 255; | 677 | data->calib_version = 255; |
@@ -643,3 +679,164 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | |||
643 | return data; | 679 | return data; |
644 | } | 680 | } |
645 | IWL_EXPORT_SYMBOL(iwl_parse_nvm_data); | 681 | IWL_EXPORT_SYMBOL(iwl_parse_nvm_data); |
682 | |||
683 | static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan, | ||
684 | int ch_idx, u16 nvm_flags, | ||
685 | const struct iwl_cfg *cfg) | ||
686 | { | ||
687 | u32 flags = NL80211_RRF_NO_HT40; | ||
688 | u32 last_5ghz_ht = LAST_5GHZ_HT; | ||
689 | |||
690 | if (cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
691 | last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000; | ||
692 | |||
693 | if (ch_idx < NUM_2GHZ_CHANNELS && | ||
694 | (nvm_flags & NVM_CHANNEL_40MHZ)) { | ||
695 | if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS) | ||
696 | flags &= ~NL80211_RRF_NO_HT40PLUS; | ||
697 | if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) | ||
698 | flags &= ~NL80211_RRF_NO_HT40MINUS; | ||
699 | } else if (nvm_chan[ch_idx] <= last_5ghz_ht && | ||
700 | (nvm_flags & NVM_CHANNEL_40MHZ)) { | ||
701 | if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) | ||
702 | flags &= ~NL80211_RRF_NO_HT40PLUS; | ||
703 | else | ||
704 | flags &= ~NL80211_RRF_NO_HT40MINUS; | ||
705 | } | ||
706 | |||
707 | if (!(nvm_flags & NVM_CHANNEL_80MHZ)) | ||
708 | flags |= NL80211_RRF_NO_80MHZ; | ||
709 | if (!(nvm_flags & NVM_CHANNEL_160MHZ)) | ||
710 | flags |= NL80211_RRF_NO_160MHZ; | ||
711 | |||
712 | if (!(nvm_flags & NVM_CHANNEL_ACTIVE)) | ||
713 | flags |= NL80211_RRF_NO_IR; | ||
714 | |||
715 | if (nvm_flags & NVM_CHANNEL_RADAR) | ||
716 | flags |= NL80211_RRF_DFS; | ||
717 | |||
718 | if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY) | ||
719 | flags |= NL80211_RRF_NO_OUTDOOR; | ||
720 | |||
721 | /* Set the GO concurrent flag only in case that NO_IR is set. | ||
722 | * Otherwise it is meaningless | ||
723 | */ | ||
724 | if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) && | ||
725 | (flags & NL80211_RRF_NO_IR)) | ||
726 | flags |= NL80211_RRF_GO_CONCURRENT; | ||
727 | |||
728 | return flags; | ||
729 | } | ||
730 | |||
731 | struct ieee80211_regdomain * | ||
732 | iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, | ||
733 | int num_of_ch, __le32 *channels, u16 fw_mcc) | ||
734 | { | ||
735 | int ch_idx; | ||
736 | u16 ch_flags, prev_ch_flags = 0; | ||
737 | const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? | ||
738 | iwl_nvm_channels_family_8000 : iwl_nvm_channels; | ||
739 | struct ieee80211_regdomain *regd; | ||
740 | int size_of_regd; | ||
741 | struct ieee80211_reg_rule *rule; | ||
742 | enum ieee80211_band band; | ||
743 | int center_freq, prev_center_freq = 0; | ||
744 | int valid_rules = 0; | ||
745 | bool new_rule; | ||
746 | int max_num_ch = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? | ||
747 | IWL_NUM_CHANNELS_FAMILY_8000 : IWL_NUM_CHANNELS; | ||
748 | |||
749 | if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) | ||
750 | return ERR_PTR(-EINVAL); | ||
751 | |||
752 | if (WARN_ON(num_of_ch > max_num_ch)) | ||
753 | num_of_ch = max_num_ch; | ||
754 | |||
755 | IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n", | ||
756 | num_of_ch); | ||
757 | |||
758 | /* build a regdomain rule for every valid channel */ | ||
759 | size_of_regd = | ||
760 | sizeof(struct ieee80211_regdomain) + | ||
761 | num_of_ch * sizeof(struct ieee80211_reg_rule); | ||
762 | |||
763 | regd = kzalloc(size_of_regd, GFP_KERNEL); | ||
764 | if (!regd) | ||
765 | return ERR_PTR(-ENOMEM); | ||
766 | |||
767 | for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { | ||
768 | ch_flags = (u16)__le32_to_cpup(channels + ch_idx); | ||
769 | band = (ch_idx < NUM_2GHZ_CHANNELS) ? | ||
770 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
771 | center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx], | ||
772 | band); | ||
773 | new_rule = false; | ||
774 | |||
775 | if (!(ch_flags & NVM_CHANNEL_VALID)) { | ||
776 | IWL_DEBUG_DEV(dev, IWL_DL_LAR, | ||
777 | "Ch. %d Flags %x [%sGHz] - No traffic\n", | ||
778 | nvm_chan[ch_idx], | ||
779 | ch_flags, | ||
780 | (ch_idx >= NUM_2GHZ_CHANNELS) ? | ||
781 | "5.2" : "2.4"); | ||
782 | continue; | ||
783 | } | ||
784 | |||
785 | /* we can't continue the same rule */ | ||
786 | if (ch_idx == 0 || prev_ch_flags != ch_flags || | ||
787 | center_freq - prev_center_freq > 20) { | ||
788 | valid_rules++; | ||
789 | new_rule = true; | ||
790 | } | ||
791 | |||
792 | rule = ®d->reg_rules[valid_rules - 1]; | ||
793 | |||
794 | if (new_rule) | ||
795 | rule->freq_range.start_freq_khz = | ||
796 | MHZ_TO_KHZ(center_freq - 10); | ||
797 | |||
798 | rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10); | ||
799 | |||
800 | /* this doesn't matter - not used by FW */ | ||
801 | rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); | ||
802 | rule->power_rule.max_eirp = | ||
803 | DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER); | ||
804 | |||
805 | rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx, | ||
806 | ch_flags, cfg); | ||
807 | |||
808 | /* rely on auto-calculation to merge BW of contiguous chans */ | ||
809 | rule->flags |= NL80211_RRF_AUTO_BW; | ||
810 | rule->freq_range.max_bandwidth_khz = 0; | ||
811 | |||
812 | prev_ch_flags = ch_flags; | ||
813 | prev_center_freq = center_freq; | ||
814 | |||
815 | IWL_DEBUG_DEV(dev, IWL_DL_LAR, | ||
816 | "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s(0x%02x): Ad-Hoc %ssupported\n", | ||
817 | center_freq, | ||
818 | band == IEEE80211_BAND_5GHZ ? "5.2" : "2.4", | ||
819 | CHECK_AND_PRINT_I(VALID), | ||
820 | CHECK_AND_PRINT_I(ACTIVE), | ||
821 | CHECK_AND_PRINT_I(RADAR), | ||
822 | CHECK_AND_PRINT_I(WIDE), | ||
823 | CHECK_AND_PRINT_I(40MHZ), | ||
824 | CHECK_AND_PRINT_I(80MHZ), | ||
825 | CHECK_AND_PRINT_I(160MHZ), | ||
826 | CHECK_AND_PRINT_I(INDOOR_ONLY), | ||
827 | CHECK_AND_PRINT_I(GO_CONCURRENT), | ||
828 | ch_flags, | ||
829 | ((ch_flags & NVM_CHANNEL_ACTIVE) && | ||
830 | !(ch_flags & NVM_CHANNEL_RADAR)) | ||
831 | ? "" : "not "); | ||
832 | } | ||
833 | |||
834 | regd->n_reg_rules = valid_rules; | ||
835 | |||
836 | /* set alpha2 from FW. */ | ||
837 | regd->alpha2[0] = fw_mcc >> 8; | ||
838 | regd->alpha2[1] = fw_mcc & 0xff; | ||
839 | |||
840 | return regd; | ||
841 | } | ||
842 | IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info); | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index c9c45a39d212..c995d2cee3f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | |||
@@ -62,6 +62,7 @@ | |||
62 | #ifndef __iwl_nvm_parse_h__ | 62 | #ifndef __iwl_nvm_parse_h__ |
63 | #define __iwl_nvm_parse_h__ | 63 | #define __iwl_nvm_parse_h__ |
64 | 64 | ||
65 | #include <net/cfg80211.h> | ||
65 | #include "iwl-eeprom-parse.h" | 66 | #include "iwl-eeprom-parse.h" |
66 | 67 | ||
67 | /** | 68 | /** |
@@ -76,6 +77,22 @@ struct iwl_nvm_data * | |||
76 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | 77 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, |
77 | const __le16 *nvm_hw, const __le16 *nvm_sw, | 78 | const __le16 *nvm_hw, const __le16 *nvm_sw, |
78 | const __le16 *nvm_calib, const __le16 *regulatory, | 79 | const __le16 *nvm_calib, const __le16 *regulatory, |
79 | const __le16 *mac_override, u8 tx_chains, u8 rx_chains); | 80 | const __le16 *mac_override, const __le16 *phy_sku, |
81 | u8 tx_chains, u8 rx_chains, | ||
82 | bool lar_fw_supported, bool is_family_8000_a_step, | ||
83 | u32 mac_addr0, u32 mac_addr1); | ||
84 | |||
85 | /** | ||
86 | * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW | ||
87 | * | ||
88 | * This function parses the regulatory channel data received as a | ||
89 | * MCC_UPDATE_CMD command. It returns a newly allocation regulatory domain, | ||
90 | * to be fed into the regulatory core. An ERR_PTR is returned on error. | ||
91 | * If not given to the regulatory core, the user is responsible for freeing | ||
92 | * the regdomain returned here with kfree. | ||
93 | */ | ||
94 | struct ieee80211_regdomain * | ||
95 | iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, | ||
96 | int num_of_ch, __le32 *channels, u16 fw_mcc); | ||
80 | 97 | ||
81 | #endif /* __iwl_nvm_parse_h__ */ | 98 | #endif /* __iwl_nvm_parse_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 6095088b88d9..bc962888c583 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
@@ -371,6 +371,33 @@ enum secure_load_status_reg { | |||
371 | 371 | ||
372 | #define DBGC_IN_SAMPLE (0xa03c00) | 372 | #define DBGC_IN_SAMPLE (0xa03c00) |
373 | 373 | ||
374 | /* enable the ID buf for read */ | ||
375 | #define WFPM_PS_CTL_CLR 0xA0300C | ||
376 | #define WFMP_MAC_ADDR_0 0xA03080 | ||
377 | #define WFMP_MAC_ADDR_1 0xA03084 | ||
378 | #define LMPM_PMG_EN 0xA01CEC | ||
379 | #define RADIO_REG_SYS_MANUAL_DFT_0 0xAD4078 | ||
380 | #define RFIC_REG_RD 0xAD0470 | ||
381 | #define WFPM_CTRL_REG 0xA03030 | ||
382 | enum { | ||
383 | ENABLE_WFPM = BIT(31), | ||
384 | WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000, | ||
385 | }; | ||
386 | |||
387 | #define AUX_MISC_REG 0xA200B0 | ||
388 | enum { | ||
389 | HW_STEP_LOCATION_BITS = 24, | ||
390 | }; | ||
391 | |||
392 | #define AUX_MISC_MASTER1_EN 0xA20818 | ||
393 | enum aux_misc_master1_en { | ||
394 | AUX_MISC_MASTER1_EN_SBE_MSK = 0x1, | ||
395 | }; | ||
396 | |||
397 | #define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800 | ||
398 | #define RSA_ENABLE 0xA24B08 | ||
399 | #define PREG_AUX_BUS_WPROT_0 0xA04CC0 | ||
400 | |||
374 | /* FW chicken bits */ | 401 | /* FW chicken bits */ |
375 | #define LMPM_CHICK 0xA01FF8 | 402 | #define LMPM_CHICK 0xA01FF8 |
376 | enum { | 403 | enum { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 542a6810c81c..11ac5c58527f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -458,6 +458,8 @@ struct iwl_trans_txq_scd_cfg { | |||
458 | * @txq_disable: de-configure a Tx queue to send AMPDUs | 458 | * @txq_disable: de-configure a Tx queue to send AMPDUs |
459 | * Must be atomic | 459 | * Must be atomic |
460 | * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. | 460 | * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. |
461 | * @freeze_txq_timer: prevents the timer of the queue from firing until the | ||
462 | * queue is set to awake. Must be atomic. | ||
461 | * @dbgfs_register: add the dbgfs files under this directory. Files will be | 463 | * @dbgfs_register: add the dbgfs files under this directory. Files will be |
462 | * automatically deleted. | 464 | * automatically deleted. |
463 | * @write8: write a u8 to a register at offset ofs from the BAR | 465 | * @write8: write a u8 to a register at offset ofs from the BAR |
@@ -517,6 +519,8 @@ struct iwl_trans_ops { | |||
517 | 519 | ||
518 | int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); | 520 | int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); |
519 | int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm); | 521 | int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm); |
522 | void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs, | ||
523 | bool freeze); | ||
520 | 524 | ||
521 | void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val); | 525 | void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val); |
522 | void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val); | 526 | void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val); |
@@ -873,6 +877,17 @@ void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo, | |||
873 | iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout); | 877 | iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout); |
874 | } | 878 | } |
875 | 879 | ||
880 | static inline void iwl_trans_freeze_txq_timer(struct iwl_trans *trans, | ||
881 | unsigned long txqs, | ||
882 | bool freeze) | ||
883 | { | ||
884 | if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) | ||
885 | IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); | ||
886 | |||
887 | if (trans->ops->freeze_txq_timer) | ||
888 | trans->ops->freeze_txq_timer(trans, txqs, freeze); | ||
889 | } | ||
890 | |||
876 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, | 891 | static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, |
877 | u32 txqs) | 892 | u32 txqs) |
878 | { | 893 | { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index ce99572a982d..770b0e2a9b46 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c | |||
@@ -72,158 +72,6 @@ | |||
72 | #include "mvm.h" | 72 | #include "mvm.h" |
73 | #include "iwl-debug.h" | 73 | #include "iwl-debug.h" |
74 | 74 | ||
75 | const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { | ||
76 | [BT_KILL_MSK_DEFAULT] = 0xfffffc00, | ||
77 | [BT_KILL_MSK_NEVER] = 0xffffffff, | ||
78 | [BT_KILL_MSK_ALWAYS] = 0, | ||
79 | }; | ||
80 | |||
81 | const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { | ||
82 | { | ||
83 | BT_KILL_MSK_ALWAYS, | ||
84 | BT_KILL_MSK_ALWAYS, | ||
85 | BT_KILL_MSK_ALWAYS, | ||
86 | }, | ||
87 | { | ||
88 | BT_KILL_MSK_NEVER, | ||
89 | BT_KILL_MSK_NEVER, | ||
90 | BT_KILL_MSK_NEVER, | ||
91 | }, | ||
92 | { | ||
93 | BT_KILL_MSK_NEVER, | ||
94 | BT_KILL_MSK_NEVER, | ||
95 | BT_KILL_MSK_NEVER, | ||
96 | }, | ||
97 | { | ||
98 | BT_KILL_MSK_DEFAULT, | ||
99 | BT_KILL_MSK_NEVER, | ||
100 | BT_KILL_MSK_DEFAULT, | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { | ||
105 | { | ||
106 | BT_KILL_MSK_ALWAYS, | ||
107 | BT_KILL_MSK_ALWAYS, | ||
108 | BT_KILL_MSK_ALWAYS, | ||
109 | }, | ||
110 | { | ||
111 | BT_KILL_MSK_ALWAYS, | ||
112 | BT_KILL_MSK_ALWAYS, | ||
113 | BT_KILL_MSK_ALWAYS, | ||
114 | }, | ||
115 | { | ||
116 | BT_KILL_MSK_ALWAYS, | ||
117 | BT_KILL_MSK_ALWAYS, | ||
118 | BT_KILL_MSK_ALWAYS, | ||
119 | }, | ||
120 | { | ||
121 | BT_KILL_MSK_DEFAULT, | ||
122 | BT_KILL_MSK_ALWAYS, | ||
123 | BT_KILL_MSK_DEFAULT, | ||
124 | }, | ||
125 | }; | ||
126 | |||
127 | static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = { | ||
128 | cpu_to_le32(0xf0f0f0f0), /* 50% */ | ||
129 | cpu_to_le32(0xc0c0c0c0), /* 25% */ | ||
130 | cpu_to_le32(0xfcfcfcfc), /* 75% */ | ||
131 | cpu_to_le32(0xfefefefe), /* 87.5% */ | ||
132 | }; | ||
133 | |||
134 | static const __le32 iwl_single_shared_ant[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = { | ||
135 | { | ||
136 | cpu_to_le32(0x40000000), | ||
137 | cpu_to_le32(0x00000000), | ||
138 | cpu_to_le32(0x44000000), | ||
139 | cpu_to_le32(0x00000000), | ||
140 | cpu_to_le32(0x40000000), | ||
141 | cpu_to_le32(0x00000000), | ||
142 | cpu_to_le32(0x44000000), | ||
143 | cpu_to_le32(0x00000000), | ||
144 | cpu_to_le32(0xc0004000), | ||
145 | cpu_to_le32(0xf0005000), | ||
146 | cpu_to_le32(0xc0004000), | ||
147 | cpu_to_le32(0xf0005000), | ||
148 | }, | ||
149 | { | ||
150 | cpu_to_le32(0x40000000), | ||
151 | cpu_to_le32(0x00000000), | ||
152 | cpu_to_le32(0x44000000), | ||
153 | cpu_to_le32(0x00000000), | ||
154 | cpu_to_le32(0x40000000), | ||
155 | cpu_to_le32(0x00000000), | ||
156 | cpu_to_le32(0x44000000), | ||
157 | cpu_to_le32(0x00000000), | ||
158 | cpu_to_le32(0xc0004000), | ||
159 | cpu_to_le32(0xf0005000), | ||
160 | cpu_to_le32(0xc0004000), | ||
161 | cpu_to_le32(0xf0005000), | ||
162 | }, | ||
163 | { | ||
164 | cpu_to_le32(0x40000000), | ||
165 | cpu_to_le32(0x00000000), | ||
166 | cpu_to_le32(0x44000000), | ||
167 | cpu_to_le32(0x00000000), | ||
168 | cpu_to_le32(0x40000000), | ||
169 | cpu_to_le32(0x00000000), | ||
170 | cpu_to_le32(0x44000000), | ||
171 | cpu_to_le32(0x00000000), | ||
172 | cpu_to_le32(0xc0004000), | ||
173 | cpu_to_le32(0xf0005000), | ||
174 | cpu_to_le32(0xc0004000), | ||
175 | cpu_to_le32(0xf0005000), | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = { | ||
180 | { | ||
181 | /* Tight */ | ||
182 | cpu_to_le32(0xaaaaaaaa), | ||
183 | cpu_to_le32(0xaaaaaaaa), | ||
184 | cpu_to_le32(0xaeaaaaaa), | ||
185 | cpu_to_le32(0xaaaaaaaa), | ||
186 | cpu_to_le32(0xcc00ff28), | ||
187 | cpu_to_le32(0x0000aaaa), | ||
188 | cpu_to_le32(0xcc00aaaa), | ||
189 | cpu_to_le32(0x0000aaaa), | ||
190 | cpu_to_le32(0xc0004000), | ||
191 | cpu_to_le32(0x00004000), | ||
192 | cpu_to_le32(0xf0005000), | ||
193 | cpu_to_le32(0xf0005000), | ||
194 | }, | ||
195 | { | ||
196 | /* Loose */ | ||
197 | cpu_to_le32(0xaaaaaaaa), | ||
198 | cpu_to_le32(0xaaaaaaaa), | ||
199 | cpu_to_le32(0xaaaaaaaa), | ||
200 | cpu_to_le32(0xaaaaaaaa), | ||
201 | cpu_to_le32(0xcc00ff28), | ||
202 | cpu_to_le32(0x0000aaaa), | ||
203 | cpu_to_le32(0xcc00aaaa), | ||
204 | cpu_to_le32(0x0000aaaa), | ||
205 | cpu_to_le32(0x00000000), | ||
206 | cpu_to_le32(0x00000000), | ||
207 | cpu_to_le32(0xf0005000), | ||
208 | cpu_to_le32(0xf0005000), | ||
209 | }, | ||
210 | { | ||
211 | /* Tx Tx disabled */ | ||
212 | cpu_to_le32(0xaaaaaaaa), | ||
213 | cpu_to_le32(0xaaaaaaaa), | ||
214 | cpu_to_le32(0xeeaaaaaa), | ||
215 | cpu_to_le32(0xaaaaaaaa), | ||
216 | cpu_to_le32(0xcc00ff28), | ||
217 | cpu_to_le32(0x0000aaaa), | ||
218 | cpu_to_le32(0xcc00aaaa), | ||
219 | cpu_to_le32(0x0000aaaa), | ||
220 | cpu_to_le32(0xc0004000), | ||
221 | cpu_to_le32(0xc0004000), | ||
222 | cpu_to_le32(0xf0005000), | ||
223 | cpu_to_le32(0xf0005000), | ||
224 | }, | ||
225 | }; | ||
226 | |||
227 | /* 20MHz / 40MHz below / 40Mhz above*/ | 75 | /* 20MHz / 40MHz below / 40Mhz above*/ |
228 | static const __le64 iwl_ci_mask[][3] = { | 76 | static const __le64 iwl_ci_mask[][3] = { |
229 | /* dummy entry for channel 0 */ | 77 | /* dummy entry for channel 0 */ |
@@ -596,14 +444,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | |||
596 | goto send_cmd; | 444 | goto send_cmd; |
597 | } | 445 | } |
598 | 446 | ||
599 | bt_cmd->max_kill = cpu_to_le32(5); | ||
600 | bt_cmd->bt4_antenna_isolation_thr = | ||
601 | cpu_to_le32(IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS); | ||
602 | bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15); | ||
603 | bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15); | ||
604 | bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); | ||
605 | bt_cmd->override_secondary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); | ||
606 | |||
607 | mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE; | 447 | mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE; |
608 | bt_cmd->mode = cpu_to_le32(mode); | 448 | bt_cmd->mode = cpu_to_le32(mode); |
609 | 449 | ||
@@ -622,18 +462,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | |||
622 | 462 | ||
623 | bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET); | 463 | bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET); |
624 | 464 | ||
625 | if (mvm->cfg->bt_shared_single_ant) | ||
626 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, | ||
627 | sizeof(iwl_single_shared_ant)); | ||
628 | else | ||
629 | memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, | ||
630 | sizeof(iwl_combined_lookup)); | ||
631 | |||
632 | memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost, | ||
633 | sizeof(iwl_bt_prio_boost)); | ||
634 | bt_cmd->multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0); | ||
635 | bt_cmd->multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1); | ||
636 | |||
637 | send_cmd: | 465 | send_cmd: |
638 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | 466 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); |
639 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); | 467 | memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); |
@@ -644,48 +472,6 @@ send_cmd: | |||
644 | return ret; | 472 | return ret; |
645 | } | 473 | } |
646 | 474 | ||
647 | static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm) | ||
648 | { | ||
649 | struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; | ||
650 | u32 primary_lut = le32_to_cpu(notif->primary_ch_lut); | ||
651 | u32 secondary_lut = le32_to_cpu(notif->secondary_ch_lut); | ||
652 | u32 ag = le32_to_cpu(notif->bt_activity_grading); | ||
653 | struct iwl_bt_coex_sw_boost_update_cmd cmd = {}; | ||
654 | u8 ack_kill_msk[NUM_PHY_CTX] = {}; | ||
655 | u8 cts_kill_msk[NUM_PHY_CTX] = {}; | ||
656 | int i; | ||
657 | |||
658 | lockdep_assert_held(&mvm->mutex); | ||
659 | |||
660 | ack_kill_msk[0] = iwl_bt_ack_kill_msk[ag][primary_lut]; | ||
661 | cts_kill_msk[0] = iwl_bt_cts_kill_msk[ag][primary_lut]; | ||
662 | |||
663 | ack_kill_msk[1] = iwl_bt_ack_kill_msk[ag][secondary_lut]; | ||
664 | cts_kill_msk[1] = iwl_bt_cts_kill_msk[ag][secondary_lut]; | ||
665 | |||
666 | /* Don't send HCMD if there is no update */ | ||
667 | if (!memcmp(ack_kill_msk, mvm->bt_ack_kill_msk, sizeof(ack_kill_msk)) || | ||
668 | !memcmp(cts_kill_msk, mvm->bt_cts_kill_msk, sizeof(cts_kill_msk))) | ||
669 | return 0; | ||
670 | |||
671 | memcpy(mvm->bt_ack_kill_msk, ack_kill_msk, | ||
672 | sizeof(mvm->bt_ack_kill_msk)); | ||
673 | memcpy(mvm->bt_cts_kill_msk, cts_kill_msk, | ||
674 | sizeof(mvm->bt_cts_kill_msk)); | ||
675 | |||
676 | BUILD_BUG_ON(ARRAY_SIZE(ack_kill_msk) < ARRAY_SIZE(cmd.boost_values)); | ||
677 | |||
678 | for (i = 0; i < ARRAY_SIZE(cmd.boost_values); i++) { | ||
679 | cmd.boost_values[i].kill_ack_msk = | ||
680 | cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk[i]]); | ||
681 | cmd.boost_values[i].kill_cts_msk = | ||
682 | cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk[i]]); | ||
683 | } | ||
684 | |||
685 | return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0, | ||
686 | sizeof(cmd), &cmd); | ||
687 | } | ||
688 | |||
689 | static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | 475 | static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, |
690 | bool enable) | 476 | bool enable) |
691 | { | 477 | { |
@@ -793,7 +579,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
793 | if (!vif->bss_conf.assoc) | 579 | if (!vif->bss_conf.assoc) |
794 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 580 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
795 | 581 | ||
796 | if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status, | 582 | if (mvmvif->phy_ctxt && |
583 | IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status, | ||
797 | mvmvif->phy_ctxt->id)) | 584 | mvmvif->phy_ctxt->id)) |
798 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 585 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
799 | 586 | ||
@@ -950,9 +737,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) | |||
950 | IWL_ERR(mvm, "Failed to send BT_CI cmd\n"); | 737 | IWL_ERR(mvm, "Failed to send BT_CI cmd\n"); |
951 | memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd)); | 738 | memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd)); |
952 | } | 739 | } |
953 | |||
954 | if (iwl_mvm_bt_udpate_sw_boost(mvm)) | ||
955 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | ||
956 | } | 740 | } |
957 | 741 | ||
958 | int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, | 742 | int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, |
@@ -1073,9 +857,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
1073 | ieee80211_iterate_active_interfaces_atomic( | 857 | ieee80211_iterate_active_interfaces_atomic( |
1074 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | 858 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, |
1075 | iwl_mvm_bt_rssi_iterator, &data); | 859 | iwl_mvm_bt_rssi_iterator, &data); |
1076 | |||
1077 | if (iwl_mvm_bt_udpate_sw_boost(mvm)) | ||
1078 | IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); | ||
1079 | } | 860 | } |
1080 | 861 | ||
1081 | #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) | 862 | #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 9717ee61928c..4f303639147b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | |||
@@ -288,6 +288,65 @@ static const __le64 iwl_ci_mask[][3] = { | |||
288 | }, | 288 | }, |
289 | }; | 289 | }; |
290 | 290 | ||
291 | enum iwl_bt_kill_msk { | ||
292 | BT_KILL_MSK_DEFAULT, | ||
293 | BT_KILL_MSK_NEVER, | ||
294 | BT_KILL_MSK_ALWAYS, | ||
295 | BT_KILL_MSK_MAX, | ||
296 | }; | ||
297 | |||
298 | static const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { | ||
299 | [BT_KILL_MSK_DEFAULT] = 0xfffffc00, | ||
300 | [BT_KILL_MSK_NEVER] = 0xffffffff, | ||
301 | [BT_KILL_MSK_ALWAYS] = 0, | ||
302 | }; | ||
303 | |||
304 | static const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { | ||
305 | { | ||
306 | BT_KILL_MSK_ALWAYS, | ||
307 | BT_KILL_MSK_ALWAYS, | ||
308 | BT_KILL_MSK_ALWAYS, | ||
309 | }, | ||
310 | { | ||
311 | BT_KILL_MSK_NEVER, | ||
312 | BT_KILL_MSK_NEVER, | ||
313 | BT_KILL_MSK_NEVER, | ||
314 | }, | ||
315 | { | ||
316 | BT_KILL_MSK_NEVER, | ||
317 | BT_KILL_MSK_NEVER, | ||
318 | BT_KILL_MSK_NEVER, | ||
319 | }, | ||
320 | { | ||
321 | BT_KILL_MSK_DEFAULT, | ||
322 | BT_KILL_MSK_NEVER, | ||
323 | BT_KILL_MSK_DEFAULT, | ||
324 | }, | ||
325 | }; | ||
326 | |||
327 | static const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { | ||
328 | { | ||
329 | BT_KILL_MSK_ALWAYS, | ||
330 | BT_KILL_MSK_ALWAYS, | ||
331 | BT_KILL_MSK_ALWAYS, | ||
332 | }, | ||
333 | { | ||
334 | BT_KILL_MSK_ALWAYS, | ||
335 | BT_KILL_MSK_ALWAYS, | ||
336 | BT_KILL_MSK_ALWAYS, | ||
337 | }, | ||
338 | { | ||
339 | BT_KILL_MSK_ALWAYS, | ||
340 | BT_KILL_MSK_ALWAYS, | ||
341 | BT_KILL_MSK_ALWAYS, | ||
342 | }, | ||
343 | { | ||
344 | BT_KILL_MSK_DEFAULT, | ||
345 | BT_KILL_MSK_ALWAYS, | ||
346 | BT_KILL_MSK_DEFAULT, | ||
347 | }, | ||
348 | }; | ||
349 | |||
291 | struct corunning_block_luts { | 350 | struct corunning_block_luts { |
292 | u8 range; | 351 | u8 range; |
293 | __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; | 352 | __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; |
@@ -633,7 +692,7 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) | |||
633 | if (IWL_MVM_BT_COEX_TTC) | 692 | if (IWL_MVM_BT_COEX_TTC) |
634 | bt_cmd->flags |= cpu_to_le32(BT_COEX_TTC); | 693 | bt_cmd->flags |= cpu_to_le32(BT_COEX_TTC); |
635 | 694 | ||
636 | if (IWL_MVM_BT_COEX_RRC) | 695 | if (iwl_mvm_bt_is_rrc_supported(mvm)) |
637 | bt_cmd->flags |= cpu_to_le32(BT_COEX_RRC); | 696 | bt_cmd->flags |= cpu_to_le32(BT_COEX_RRC); |
638 | 697 | ||
639 | if (mvm->cfg->bt_shared_single_ant) | 698 | if (mvm->cfg->bt_shared_single_ant) |
@@ -832,7 +891,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
832 | if (!vif->bss_conf.assoc) | 891 | if (!vif->bss_conf.assoc) |
833 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 892 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
834 | 893 | ||
835 | if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id)) | 894 | if (mvmvif->phy_ctxt && |
895 | data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id)) | ||
836 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 896 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
837 | 897 | ||
838 | IWL_DEBUG_COEX(data->mvm, | 898 | IWL_DEBUG_COEX(data->mvm, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 9bdfa95d6ce7..5f8afa5f11a3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -694,6 +694,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
694 | if (ret) | 694 | if (ret) |
695 | IWL_ERR(mvm, "Failed to send quota: %d\n", ret); | 695 | IWL_ERR(mvm, "Failed to send quota: %d\n", ret); |
696 | 696 | ||
697 | if (iwl_mvm_is_lar_supported(mvm) && iwl_mvm_init_fw_regd(mvm)) | ||
698 | IWL_ERR(mvm, "Failed to initialize D3 LAR information\n"); | ||
699 | |||
697 | return 0; | 700 | return 0; |
698 | } | 701 | } |
699 | 702 | ||
@@ -1596,7 +1599,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
1596 | 1599 | ||
1597 | /* RF-kill already asserted again... */ | 1600 | /* RF-kill already asserted again... */ |
1598 | if (!cmd.resp_pkt) { | 1601 | if (!cmd.resp_pkt) { |
1599 | ret = -ERFKILL; | 1602 | fw_status = ERR_PTR(-ERFKILL); |
1600 | goto out_free_resp; | 1603 | goto out_free_resp; |
1601 | } | 1604 | } |
1602 | 1605 | ||
@@ -1605,7 +1608,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
1605 | len = iwl_rx_packet_payload_len(cmd.resp_pkt); | 1608 | len = iwl_rx_packet_payload_len(cmd.resp_pkt); |
1606 | if (len < status_size) { | 1609 | if (len < status_size) { |
1607 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | 1610 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); |
1608 | ret = -EIO; | 1611 | fw_status = ERR_PTR(-EIO); |
1609 | goto out_free_resp; | 1612 | goto out_free_resp; |
1610 | } | 1613 | } |
1611 | 1614 | ||
@@ -1613,7 +1616,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
1613 | if (len != (status_size + | 1616 | if (len != (status_size + |
1614 | ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4))) { | 1617 | ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4))) { |
1615 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | 1618 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); |
1616 | ret = -EIO; | 1619 | fw_status = ERR_PTR(-EIO); |
1617 | goto out_free_resp; | 1620 | goto out_free_resp; |
1618 | } | 1621 | } |
1619 | 1622 | ||
@@ -1621,7 +1624,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
1621 | 1624 | ||
1622 | out_free_resp: | 1625 | out_free_resp: |
1623 | iwl_free_resp(&cmd); | 1626 | iwl_free_resp(&cmd); |
1624 | return ret ? ERR_PTR(ret) : fw_status; | 1627 | return fw_status; |
1625 | } | 1628 | } |
1626 | 1629 | ||
1627 | /* releases the MVM mutex */ | 1630 | /* releases the MVM mutex */ |
@@ -1874,6 +1877,12 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
1874 | /* query SRAM first in case we want event logging */ | 1877 | /* query SRAM first in case we want event logging */ |
1875 | iwl_mvm_read_d3_sram(mvm); | 1878 | iwl_mvm_read_d3_sram(mvm); |
1876 | 1879 | ||
1880 | /* | ||
1881 | * Query the current location and source from the D3 firmware so we | ||
1882 | * can play it back when we re-intiailize the D0 firmware | ||
1883 | */ | ||
1884 | iwl_mvm_update_changed_regdom(mvm); | ||
1885 | |||
1877 | if (mvm->net_detect) { | 1886 | if (mvm->net_detect) { |
1878 | iwl_mvm_query_netdetect_reasons(mvm, vif); | 1887 | iwl_mvm_query_netdetect_reasons(mvm, vif); |
1879 | /* has unlocked the mutex, so skip that */ | 1888 | /* has unlocked the mutex, so skip that */ |
@@ -1883,9 +1892,9 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
1883 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1892 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
1884 | if (keep) | 1893 | if (keep) |
1885 | mvm->keep_vif = vif; | 1894 | mvm->keep_vif = vif; |
1895 | #endif | ||
1886 | /* has unlocked the mutex, so skip that */ | 1896 | /* has unlocked the mutex, so skip that */ |
1887 | goto out_iterate; | 1897 | goto out_iterate; |
1888 | #endif | ||
1889 | } | 1898 | } |
1890 | 1899 | ||
1891 | out_unlock: | 1900 | out_unlock: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 8cbe77dc1dbb..8c5229892e57 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -562,11 +562,12 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, | |||
562 | "\tSecondary Channel Bitmap 0x%016llx\n", | 562 | "\tSecondary Channel Bitmap 0x%016llx\n", |
563 | le64_to_cpu(cmd->bt_secondary_ci)); | 563 | le64_to_cpu(cmd->bt_secondary_ci)); |
564 | 564 | ||
565 | pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); | 565 | pos += scnprintf(buf+pos, bufsz-pos, |
566 | pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", | 566 | "BT Configuration CMD - 0=default, 1=never, 2=always\n"); |
567 | iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]); | 567 | pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill msk idx %d\n", |
568 | pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", | 568 | mvm->bt_ack_kill_msk[0]); |
569 | iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]); | 569 | pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill msk idx %d\n", |
570 | mvm->bt_cts_kill_msk[0]); | ||
570 | 571 | ||
571 | } else { | 572 | } else { |
572 | struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; | 573 | struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; |
@@ -579,21 +580,6 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, | |||
579 | pos += scnprintf(buf+pos, bufsz-pos, | 580 | pos += scnprintf(buf+pos, bufsz-pos, |
580 | "\tSecondary Channel Bitmap 0x%016llx\n", | 581 | "\tSecondary Channel Bitmap 0x%016llx\n", |
581 | le64_to_cpu(cmd->bt_secondary_ci)); | 582 | le64_to_cpu(cmd->bt_secondary_ci)); |
582 | |||
583 | pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); | ||
584 | pos += scnprintf(buf+pos, bufsz-pos, | ||
585 | "\tPrimary: ACK Kill Mask 0x%08x\n", | ||
586 | iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]); | ||
587 | pos += scnprintf(buf+pos, bufsz-pos, | ||
588 | "\tPrimary: CTS Kill Mask 0x%08x\n", | ||
589 | iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]); | ||
590 | pos += scnprintf(buf+pos, bufsz-pos, | ||
591 | "\tSecondary: ACK Kill Mask 0x%08x\n", | ||
592 | iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[1]]); | ||
593 | pos += scnprintf(buf+pos, bufsz-pos, | ||
594 | "\tSecondary: CTS Kill Mask 0x%08x\n", | ||
595 | iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[1]]); | ||
596 | |||
597 | } | 583 | } |
598 | 584 | ||
599 | mutex_unlock(&mvm->mutex); | 585 | mutex_unlock(&mvm->mutex); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index f3b11897991e..d398a6102805 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h | |||
@@ -235,36 +235,12 @@ enum iwl_bt_coex_enabled_modules { | |||
235 | * struct iwl_bt_coex_cmd - bt coex configuration command | 235 | * struct iwl_bt_coex_cmd - bt coex configuration command |
236 | * @mode: enum %iwl_bt_coex_mode | 236 | * @mode: enum %iwl_bt_coex_mode |
237 | * @enabled_modules: enum %iwl_bt_coex_enabled_modules | 237 | * @enabled_modules: enum %iwl_bt_coex_enabled_modules |
238 | * @max_kill: max count of Tx retries due to kill from PTA | ||
239 | * @override_primary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT | ||
240 | * should be set by default | ||
241 | * @override_secondary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT | ||
242 | * should be set by default | ||
243 | * @bt4_antenna_isolation_thr: antenna threshold value | ||
244 | * @bt4_tx_tx_delta_freq_thr: TxTx delta frequency | ||
245 | * @bt4_tx_rx_max_freq0: TxRx max frequency | ||
246 | * @multiprio_lut: multi priority LUT configuration | ||
247 | * @mplut_prio_boost: BT priority boost registers | ||
248 | * @decision_lut: PTA decision LUT, per Prio-Ch | ||
249 | * | 238 | * |
250 | * The structure is used for the BT_COEX command. | 239 | * The structure is used for the BT_COEX command. |
251 | */ | 240 | */ |
252 | struct iwl_bt_coex_cmd { | 241 | struct iwl_bt_coex_cmd { |
253 | __le32 mode; | 242 | __le32 mode; |
254 | __le32 enabled_modules; | 243 | __le32 enabled_modules; |
255 | |||
256 | __le32 max_kill; | ||
257 | __le32 override_primary_lut; | ||
258 | __le32 override_secondary_lut; | ||
259 | __le32 bt4_antenna_isolation_thr; | ||
260 | |||
261 | __le32 bt4_tx_tx_delta_freq_thr; | ||
262 | __le32 bt4_tx_rx_max_freq0; | ||
263 | |||
264 | __le32 multiprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE]; | ||
265 | __le32 mplut_prio_boost[BT_COEX_BOOST_SIZE]; | ||
266 | |||
267 | __le32 decision_lut[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE]; | ||
268 | } __packed; /* BT_COEX_CMD_API_S_VER_6 */ | 244 | } __packed; /* BT_COEX_CMD_API_S_VER_6 */ |
269 | 245 | ||
270 | /** | 246 | /** |
@@ -280,29 +256,6 @@ struct iwl_bt_coex_corun_lut_update_cmd { | |||
280 | } __packed; /* BT_COEX_UPDATE_CORUN_LUT_API_S_VER_1 */ | 256 | } __packed; /* BT_COEX_UPDATE_CORUN_LUT_API_S_VER_1 */ |
281 | 257 | ||
282 | /** | 258 | /** |
283 | * struct iwl_bt_coex_sw_boost - SW boost values | ||
284 | * @wifi_tx_prio_boost: SW boost of wifi tx priority | ||
285 | * @wifi_rx_prio_boost: SW boost of wifi rx priority | ||
286 | * @kill_ack_msk: kill ACK mask. 1 - Tx ACK, 0 - kill Tx of ACK. | ||
287 | * @kill_cts_msk: kill CTS mask. 1 - Tx CTS, 0 - kill Tx of CTS. | ||
288 | */ | ||
289 | struct iwl_bt_coex_sw_boost { | ||
290 | __le32 wifi_tx_prio_boost; | ||
291 | __le32 wifi_rx_prio_boost; | ||
292 | __le32 kill_ack_msk; | ||
293 | __le32 kill_cts_msk; | ||
294 | }; | ||
295 | |||
296 | /** | ||
297 | * struct iwl_bt_coex_sw_boost_update_cmd - command to update the SW boost | ||
298 | * @boost_values: check struct %iwl_bt_coex_sw_boost - one for each channel | ||
299 | * primary / secondary / low priority | ||
300 | */ | ||
301 | struct iwl_bt_coex_sw_boost_update_cmd { | ||
302 | struct iwl_bt_coex_sw_boost boost_values[3]; | ||
303 | } __packed; /* BT_COEX_UPDATE_SW_BOOST_S_VER_1 */ | ||
304 | |||
305 | /** | ||
306 | * struct iwl_bt_coex_reduced_txp_update_cmd | 259 | * struct iwl_bt_coex_reduced_txp_update_cmd |
307 | * @reduced_txp: bit BT_REDUCED_TX_POWER_BIT to enable / disable, rest of the | 260 | * @reduced_txp: bit BT_REDUCED_TX_POWER_BIT to enable / disable, rest of the |
308 | * bits are the sta_id (value) | 261 | * bits are the sta_id (value) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index d95b47213731..aab68cbae754 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -212,6 +212,10 @@ enum { | |||
212 | REPLY_RX_MPDU_CMD = 0xc1, | 212 | REPLY_RX_MPDU_CMD = 0xc1, |
213 | BA_NOTIF = 0xc5, | 213 | BA_NOTIF = 0xc5, |
214 | 214 | ||
215 | /* Location Aware Regulatory */ | ||
216 | MCC_UPDATE_CMD = 0xc8, | ||
217 | MCC_CHUB_UPDATE_CMD = 0xc9, | ||
218 | |||
215 | MARKER_CMD = 0xcb, | 219 | MARKER_CMD = 0xcb, |
216 | 220 | ||
217 | /* BT Coex */ | 221 | /* BT Coex */ |
@@ -362,7 +366,8 @@ enum { | |||
362 | NVM_SECTION_TYPE_CALIBRATION = 4, | 366 | NVM_SECTION_TYPE_CALIBRATION = 4, |
363 | NVM_SECTION_TYPE_PRODUCTION = 5, | 367 | NVM_SECTION_TYPE_PRODUCTION = 5, |
364 | NVM_SECTION_TYPE_MAC_OVERRIDE = 11, | 368 | NVM_SECTION_TYPE_MAC_OVERRIDE = 11, |
365 | NVM_MAX_NUM_SECTIONS = 12, | 369 | NVM_SECTION_TYPE_PHY_SKU = 12, |
370 | NVM_MAX_NUM_SECTIONS = 13, | ||
366 | }; | 371 | }; |
367 | 372 | ||
368 | /** | 373 | /** |
@@ -1442,7 +1447,19 @@ enum iwl_sf_scenario { | |||
1442 | #define SF_W_MARK_LEGACY 4096 | 1447 | #define SF_W_MARK_LEGACY 4096 |
1443 | #define SF_W_MARK_SCAN 4096 | 1448 | #define SF_W_MARK_SCAN 4096 |
1444 | 1449 | ||
1445 | /* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */ | 1450 | /* SF Scenarios timers for default configuration (aligned to 32 uSec) */ |
1451 | #define SF_SINGLE_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ | ||
1452 | #define SF_SINGLE_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ | ||
1453 | #define SF_AGG_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ | ||
1454 | #define SF_AGG_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ | ||
1455 | #define SF_MCAST_IDLE_TIMER_DEF 160 /* 150 mSec */ | ||
1456 | #define SF_MCAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ | ||
1457 | #define SF_BA_IDLE_TIMER_DEF 160 /* 150 uSec */ | ||
1458 | #define SF_BA_AGING_TIMER_DEF 400 /* 0.4 mSec */ | ||
1459 | #define SF_TX_RE_IDLE_TIMER_DEF 160 /* 150 uSec */ | ||
1460 | #define SF_TX_RE_AGING_TIMER_DEF 400 /* 0.4 mSec */ | ||
1461 | |||
1462 | /* SF Scenarios timers for BSS MAC configuration (aligned to 32 uSec) */ | ||
1446 | #define SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */ | 1463 | #define SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */ |
1447 | #define SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */ | 1464 | #define SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */ |
1448 | #define SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */ | 1465 | #define SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */ |
@@ -1473,6 +1490,92 @@ struct iwl_sf_cfg_cmd { | |||
1473 | __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; | 1490 | __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; |
1474 | } __packed; /* SF_CFG_API_S_VER_2 */ | 1491 | } __packed; /* SF_CFG_API_S_VER_2 */ |
1475 | 1492 | ||
1493 | /*********************************** | ||
1494 | * Location Aware Regulatory (LAR) API - MCC updates | ||
1495 | ***********************************/ | ||
1496 | |||
1497 | /** | ||
1498 | * struct iwl_mcc_update_cmd - Request the device to update geographic | ||
1499 | * regulatory profile according to the given MCC (Mobile Country Code). | ||
1500 | * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. | ||
1501 | * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the | ||
1502 | * MCC in the cmd response will be the relevant MCC in the NVM. | ||
1503 | * @mcc: given mobile country code | ||
1504 | * @source_id: the source from where we got the MCC, see iwl_mcc_source | ||
1505 | * @reserved: reserved for alignment | ||
1506 | */ | ||
1507 | struct iwl_mcc_update_cmd { | ||
1508 | __le16 mcc; | ||
1509 | u8 source_id; | ||
1510 | u8 reserved; | ||
1511 | } __packed; /* LAR_UPDATE_MCC_CMD_API_S */ | ||
1512 | |||
1513 | /** | ||
1514 | * iwl_mcc_update_resp - response to MCC_UPDATE_CMD. | ||
1515 | * Contains the new channel control profile map, if changed, and the new MCC | ||
1516 | * (mobile country code). | ||
1517 | * The new MCC may be different than what was requested in MCC_UPDATE_CMD. | ||
1518 | * @status: see &enum iwl_mcc_update_status | ||
1519 | * @mcc: the new applied MCC | ||
1520 | * @cap: capabilities for all channels which matches the MCC | ||
1521 | * @source_id: the MCC source, see iwl_mcc_source | ||
1522 | * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 | ||
1523 | * channels, depending on platform) | ||
1524 | * @channels: channel control data map, DWORD for each channel. Only the first | ||
1525 | * 16bits are used. | ||
1526 | */ | ||
1527 | struct iwl_mcc_update_resp { | ||
1528 | __le32 status; | ||
1529 | __le16 mcc; | ||
1530 | u8 cap; | ||
1531 | u8 source_id; | ||
1532 | __le32 n_channels; | ||
1533 | __le32 channels[0]; | ||
1534 | } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S */ | ||
1535 | |||
1536 | /** | ||
1537 | * struct iwl_mcc_chub_notif - chub notifies of mcc change | ||
1538 | * (MCC_CHUB_UPDATE_CMD = 0xc9) | ||
1539 | * The Chub (Communication Hub, CommsHUB) is a HW component that connects to | ||
1540 | * the cellular and connectivity cores that gets updates of the mcc, and | ||
1541 | * notifies the ucode directly of any mcc change. | ||
1542 | * The ucode requests the driver to request the device to update geographic | ||
1543 | * regulatory profile according to the given MCC (Mobile Country Code). | ||
1544 | * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. | ||
1545 | * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the | ||
1546 | * MCC in the cmd response will be the relevant MCC in the NVM. | ||
1547 | * @mcc: given mobile country code | ||
1548 | * @source_id: identity of the change originator, see iwl_mcc_source | ||
1549 | * @reserved1: reserved for alignment | ||
1550 | */ | ||
1551 | struct iwl_mcc_chub_notif { | ||
1552 | u16 mcc; | ||
1553 | u8 source_id; | ||
1554 | u8 reserved1; | ||
1555 | } __packed; /* LAR_MCC_NOTIFY_S */ | ||
1556 | |||
1557 | enum iwl_mcc_update_status { | ||
1558 | MCC_RESP_NEW_CHAN_PROFILE, | ||
1559 | MCC_RESP_SAME_CHAN_PROFILE, | ||
1560 | MCC_RESP_INVALID, | ||
1561 | MCC_RESP_NVM_DISABLED, | ||
1562 | MCC_RESP_ILLEGAL, | ||
1563 | MCC_RESP_LOW_PRIORITY, | ||
1564 | }; | ||
1565 | |||
1566 | enum iwl_mcc_source { | ||
1567 | MCC_SOURCE_OLD_FW = 0, | ||
1568 | MCC_SOURCE_ME = 1, | ||
1569 | MCC_SOURCE_BIOS = 2, | ||
1570 | MCC_SOURCE_3G_LTE_HOST = 3, | ||
1571 | MCC_SOURCE_3G_LTE_DEVICE = 4, | ||
1572 | MCC_SOURCE_WIFI = 5, | ||
1573 | MCC_SOURCE_RESERVED = 6, | ||
1574 | MCC_SOURCE_DEFAULT = 7, | ||
1575 | MCC_SOURCE_UNINITIALIZED = 8, | ||
1576 | MCC_SOURCE_GET_CURRENT = 0x10 | ||
1577 | }; | ||
1578 | |||
1476 | /* DTS measurements */ | 1579 | /* DTS measurements */ |
1477 | 1580 | ||
1478 | enum iwl_dts_measurement_flags { | 1581 | enum iwl_dts_measurement_flags { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index a81da4cde643..6cf7d9837ca5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -739,6 +739,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
739 | if (ret) | 739 | if (ret) |
740 | goto error; | 740 | goto error; |
741 | 741 | ||
742 | /* | ||
743 | * RTNL is not taken during Ct-kill, but we don't need to scan/Tx | ||
744 | * anyway, so don't init MCC. | ||
745 | */ | ||
746 | if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) { | ||
747 | ret = iwl_mvm_init_mcc(mvm); | ||
748 | if (ret) | ||
749 | goto error; | ||
750 | } | ||
751 | |||
742 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { | 752 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { |
743 | ret = iwl_mvm_config_scan(mvm); | 753 | ret = iwl_mvm_config_scan(mvm); |
744 | if (ret) | 754 | if (ret) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 204255423d99..302c8cc50f25 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -86,6 +86,7 @@ | |||
86 | #include "iwl-fw-error-dump.h" | 86 | #include "iwl-fw-error-dump.h" |
87 | #include "iwl-prph.h" | 87 | #include "iwl-prph.h" |
88 | #include "iwl-csr.h" | 88 | #include "iwl-csr.h" |
89 | #include "iwl-nvm-parse.h" | ||
89 | 90 | ||
90 | static const struct ieee80211_iface_limit iwl_mvm_limits[] = { | 91 | static const struct ieee80211_iface_limit iwl_mvm_limits[] = { |
91 | { | 92 | { |
@@ -301,6 +302,109 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) | |||
301 | } | 302 | } |
302 | } | 303 | } |
303 | 304 | ||
305 | struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, | ||
306 | const char *alpha2, | ||
307 | enum iwl_mcc_source src_id, | ||
308 | bool *changed) | ||
309 | { | ||
310 | struct ieee80211_regdomain *regd = NULL; | ||
311 | struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); | ||
312 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
313 | struct iwl_mcc_update_resp *resp; | ||
314 | |||
315 | IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2); | ||
316 | |||
317 | lockdep_assert_held(&mvm->mutex); | ||
318 | |||
319 | resp = iwl_mvm_update_mcc(mvm, alpha2, src_id); | ||
320 | if (IS_ERR_OR_NULL(resp)) { | ||
321 | IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n", | ||
322 | PTR_RET(resp)); | ||
323 | goto out; | ||
324 | } | ||
325 | |||
326 | if (changed) | ||
327 | *changed = (resp->status == MCC_RESP_NEW_CHAN_PROFILE); | ||
328 | |||
329 | regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg, | ||
330 | __le32_to_cpu(resp->n_channels), | ||
331 | resp->channels, | ||
332 | __le16_to_cpu(resp->mcc)); | ||
333 | /* Store the return source id */ | ||
334 | src_id = resp->source_id; | ||
335 | kfree(resp); | ||
336 | if (IS_ERR_OR_NULL(regd)) { | ||
337 | IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n", | ||
338 | PTR_RET(regd)); | ||
339 | goto out; | ||
340 | } | ||
341 | |||
342 | IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x) src=%d\n", | ||
343 | regd->alpha2, regd->alpha2[0], regd->alpha2[1], src_id); | ||
344 | mvm->lar_regdom_set = true; | ||
345 | mvm->mcc_src = src_id; | ||
346 | |||
347 | out: | ||
348 | return regd; | ||
349 | } | ||
350 | |||
351 | void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm) | ||
352 | { | ||
353 | bool changed; | ||
354 | struct ieee80211_regdomain *regd; | ||
355 | |||
356 | if (!iwl_mvm_is_lar_supported(mvm)) | ||
357 | return; | ||
358 | |||
359 | regd = iwl_mvm_get_current_regdomain(mvm, &changed); | ||
360 | if (!IS_ERR_OR_NULL(regd)) { | ||
361 | /* only update the regulatory core if changed */ | ||
362 | if (changed) | ||
363 | regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); | ||
364 | |||
365 | kfree(regd); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm, | ||
370 | bool *changed) | ||
371 | { | ||
372 | return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ", | ||
373 | iwl_mvm_is_wifi_mcc_supported(mvm) ? | ||
374 | MCC_SOURCE_GET_CURRENT : | ||
375 | MCC_SOURCE_OLD_FW, changed); | ||
376 | } | ||
377 | |||
378 | int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) | ||
379 | { | ||
380 | enum iwl_mcc_source used_src; | ||
381 | struct ieee80211_regdomain *regd; | ||
382 | const struct ieee80211_regdomain *r = | ||
383 | rtnl_dereference(mvm->hw->wiphy->regd); | ||
384 | |||
385 | if (!r) | ||
386 | return 0; | ||
387 | |||
388 | /* save the last source in case we overwrite it below */ | ||
389 | used_src = mvm->mcc_src; | ||
390 | if (iwl_mvm_is_wifi_mcc_supported(mvm)) { | ||
391 | /* Notify the firmware we support wifi location updates */ | ||
392 | regd = iwl_mvm_get_current_regdomain(mvm, NULL); | ||
393 | if (!IS_ERR_OR_NULL(regd)) | ||
394 | kfree(regd); | ||
395 | } | ||
396 | |||
397 | /* Now set our last stored MCC and source */ | ||
398 | regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src, NULL); | ||
399 | if (IS_ERR_OR_NULL(regd)) | ||
400 | return -EIO; | ||
401 | |||
402 | regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); | ||
403 | kfree(regd); | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
304 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | 408 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) |
305 | { | 409 | { |
306 | struct ieee80211_hw *hw = mvm->hw; | 410 | struct ieee80211_hw *hw = mvm->hw; |
@@ -356,8 +460,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
356 | BIT(NL80211_IFTYPE_ADHOC); | 460 | BIT(NL80211_IFTYPE_ADHOC); |
357 | 461 | ||
358 | hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | 462 | hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; |
359 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | | 463 | hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR; |
360 | REGULATORY_DISABLE_BEACON_HINTS; | 464 | if (iwl_mvm_is_lar_supported(mvm)) |
465 | hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; | ||
466 | else | ||
467 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | | ||
468 | REGULATORY_DISABLE_BEACON_HINTS; | ||
361 | 469 | ||
362 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) | 470 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) |
363 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | 471 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; |
@@ -402,7 +510,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
402 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | 510 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = |
403 | &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | 511 | &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; |
404 | 512 | ||
405 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) | 513 | if ((mvm->fw->ucode_capa.capa[0] & |
514 | IWL_UCODE_TLV_CAPA_BEAMFORMER) && | ||
515 | (mvm->fw->ucode_capa.api[0] & | ||
516 | IWL_UCODE_TLV_API_LQ_SS_PARAMS)) | ||
406 | hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |= | 517 | hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |= |
407 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; | 518 | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; |
408 | } | 519 | } |
@@ -1190,7 +1301,7 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) | |||
1190 | 1301 | ||
1191 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 1302 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
1192 | iwl_mvm_d0i3_enable_tx(mvm, NULL); | 1303 | iwl_mvm_d0i3_enable_tx(mvm, NULL); |
1193 | ret = iwl_mvm_update_quotas(mvm, NULL); | 1304 | ret = iwl_mvm_update_quotas(mvm, false, NULL); |
1194 | if (ret) | 1305 | if (ret) |
1195 | IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", | 1306 | IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", |
1196 | ret); | 1307 | ret); |
@@ -1869,7 +1980,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
1869 | sizeof(mvmvif->beacon_stats)); | 1980 | sizeof(mvmvif->beacon_stats)); |
1870 | 1981 | ||
1871 | /* add quota for this interface */ | 1982 | /* add quota for this interface */ |
1872 | ret = iwl_mvm_update_quotas(mvm, NULL); | 1983 | ret = iwl_mvm_update_quotas(mvm, true, NULL); |
1873 | if (ret) { | 1984 | if (ret) { |
1874 | IWL_ERR(mvm, "failed to update quotas\n"); | 1985 | IWL_ERR(mvm, "failed to update quotas\n"); |
1875 | return; | 1986 | return; |
@@ -1921,7 +2032,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
1921 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | 2032 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; |
1922 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 2033 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
1923 | /* remove quota for this interface */ | 2034 | /* remove quota for this interface */ |
1924 | ret = iwl_mvm_update_quotas(mvm, NULL); | 2035 | ret = iwl_mvm_update_quotas(mvm, false, NULL); |
1925 | if (ret) | 2036 | if (ret) |
1926 | IWL_ERR(mvm, "failed to update quotas\n"); | 2037 | IWL_ERR(mvm, "failed to update quotas\n"); |
1927 | 2038 | ||
@@ -2040,7 +2151,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
2040 | /* power updated needs to be done before quotas */ | 2151 | /* power updated needs to be done before quotas */ |
2041 | iwl_mvm_power_update_mac(mvm); | 2152 | iwl_mvm_power_update_mac(mvm); |
2042 | 2153 | ||
2043 | ret = iwl_mvm_update_quotas(mvm, NULL); | 2154 | ret = iwl_mvm_update_quotas(mvm, false, NULL); |
2044 | if (ret) | 2155 | if (ret) |
2045 | goto out_quota_failed; | 2156 | goto out_quota_failed; |
2046 | 2157 | ||
@@ -2106,7 +2217,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, | |||
2106 | if (vif->p2p && mvm->p2p_device_vif) | 2217 | if (vif->p2p && mvm->p2p_device_vif) |
2107 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); | 2218 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); |
2108 | 2219 | ||
2109 | iwl_mvm_update_quotas(mvm, NULL); | 2220 | iwl_mvm_update_quotas(mvm, false, NULL); |
2110 | iwl_mvm_send_rm_bcast_sta(mvm, vif); | 2221 | iwl_mvm_send_rm_bcast_sta(mvm, vif); |
2111 | iwl_mvm_binding_remove_vif(mvm, vif); | 2222 | iwl_mvm_binding_remove_vif(mvm, vif); |
2112 | 2223 | ||
@@ -2245,6 +2356,12 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
2245 | 2356 | ||
2246 | mutex_lock(&mvm->mutex); | 2357 | mutex_lock(&mvm->mutex); |
2247 | 2358 | ||
2359 | if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) { | ||
2360 | IWL_ERR(mvm, "scan while LAR regdomain is not set\n"); | ||
2361 | ret = -EBUSY; | ||
2362 | goto out; | ||
2363 | } | ||
2364 | |||
2248 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { | 2365 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { |
2249 | ret = -EBUSY; | 2366 | ret = -EBUSY; |
2250 | goto out; | 2367 | goto out; |
@@ -2271,7 +2388,19 @@ static void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, | |||
2271 | 2388 | ||
2272 | mutex_lock(&mvm->mutex); | 2389 | mutex_lock(&mvm->mutex); |
2273 | 2390 | ||
2274 | iwl_mvm_cancel_scan(mvm); | 2391 | /* Due to a race condition, it's possible that mac80211 asks |
2392 | * us to stop a hw_scan when it's already stopped. This can | ||
2393 | * happen, for instance, if we stopped the scan ourselves, | ||
2394 | * called ieee80211_scan_completed() and the userspace called | ||
2395 | * cancel scan scan before ieee80211_scan_work() could run. | ||
2396 | * To handle that, simply return if the scan is not running. | ||
2397 | */ | ||
2398 | /* FIXME: for now, we ignore this race for UMAC scans, since | ||
2399 | * they don't set the scan_status. | ||
2400 | */ | ||
2401 | if ((mvm->scan_status == IWL_MVM_SCAN_OS) || | ||
2402 | (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) | ||
2403 | iwl_mvm_cancel_scan(mvm); | ||
2275 | 2404 | ||
2276 | mutex_unlock(&mvm->mutex); | 2405 | mutex_unlock(&mvm->mutex); |
2277 | } | 2406 | } |
@@ -2313,25 +2442,35 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | |||
2313 | { | 2442 | { |
2314 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2443 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2315 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 2444 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
2445 | unsigned long txqs = 0, tids = 0; | ||
2316 | int tid; | 2446 | int tid; |
2317 | 2447 | ||
2448 | spin_lock_bh(&mvmsta->lock); | ||
2449 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { | ||
2450 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | ||
2451 | |||
2452 | if (tid_data->state != IWL_AGG_ON && | ||
2453 | tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) | ||
2454 | continue; | ||
2455 | |||
2456 | __set_bit(tid_data->txq_id, &txqs); | ||
2457 | |||
2458 | if (iwl_mvm_tid_queued(tid_data) == 0) | ||
2459 | continue; | ||
2460 | |||
2461 | __set_bit(tid, &tids); | ||
2462 | } | ||
2463 | |||
2318 | switch (cmd) { | 2464 | switch (cmd) { |
2319 | case STA_NOTIFY_SLEEP: | 2465 | case STA_NOTIFY_SLEEP: |
2320 | if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) | 2466 | if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) |
2321 | ieee80211_sta_block_awake(hw, sta, true); | 2467 | ieee80211_sta_block_awake(hw, sta, true); |
2322 | spin_lock_bh(&mvmsta->lock); | ||
2323 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { | ||
2324 | struct iwl_mvm_tid_data *tid_data; | ||
2325 | 2468 | ||
2326 | tid_data = &mvmsta->tid_data[tid]; | 2469 | for_each_set_bit(tid, &tids, IWL_MAX_TID_COUNT) |
2327 | if (tid_data->state != IWL_AGG_ON && | ||
2328 | tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) | ||
2329 | continue; | ||
2330 | if (iwl_mvm_tid_queued(tid_data) == 0) | ||
2331 | continue; | ||
2332 | ieee80211_sta_set_buffered(sta, tid, true); | 2470 | ieee80211_sta_set_buffered(sta, tid, true); |
2333 | } | 2471 | |
2334 | spin_unlock_bh(&mvmsta->lock); | 2472 | if (txqs) |
2473 | iwl_trans_freeze_txq_timer(mvm->trans, txqs, true); | ||
2335 | /* | 2474 | /* |
2336 | * The fw updates the STA to be asleep. Tx packets on the Tx | 2475 | * The fw updates the STA to be asleep. Tx packets on the Tx |
2337 | * queues to this station will not be transmitted. The fw will | 2476 | * queues to this station will not be transmitted. The fw will |
@@ -2341,11 +2480,15 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | |||
2341 | case STA_NOTIFY_AWAKE: | 2480 | case STA_NOTIFY_AWAKE: |
2342 | if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) | 2481 | if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) |
2343 | break; | 2482 | break; |
2483 | |||
2484 | if (txqs) | ||
2485 | iwl_trans_freeze_txq_timer(mvm->trans, txqs, false); | ||
2344 | iwl_mvm_sta_modify_ps_wake(mvm, sta); | 2486 | iwl_mvm_sta_modify_ps_wake(mvm, sta); |
2345 | break; | 2487 | break; |
2346 | default: | 2488 | default: |
2347 | break; | 2489 | break; |
2348 | } | 2490 | } |
2491 | spin_unlock_bh(&mvmsta->lock); | ||
2349 | } | 2492 | } |
2350 | 2493 | ||
2351 | static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, | 2494 | static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, |
@@ -2583,6 +2726,12 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
2583 | 2726 | ||
2584 | mutex_lock(&mvm->mutex); | 2727 | mutex_lock(&mvm->mutex); |
2585 | 2728 | ||
2729 | if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) { | ||
2730 | IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n"); | ||
2731 | ret = -EBUSY; | ||
2732 | goto out; | ||
2733 | } | ||
2734 | |||
2586 | if (!vif->bss_conf.idle) { | 2735 | if (!vif->bss_conf.idle) { |
2587 | ret = -EBUSY; | 2736 | ret = -EBUSY; |
2588 | goto out; | 2737 | goto out; |
@@ -2609,12 +2758,29 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, | |||
2609 | int ret; | 2758 | int ret; |
2610 | 2759 | ||
2611 | mutex_lock(&mvm->mutex); | 2760 | mutex_lock(&mvm->mutex); |
2761 | |||
2762 | /* Due to a race condition, it's possible that mac80211 asks | ||
2763 | * us to stop a sched_scan when it's already stopped. This | ||
2764 | * can happen, for instance, if we stopped the scan ourselves, | ||
2765 | * called ieee80211_sched_scan_stopped() and the userspace called | ||
2766 | * stop sched scan scan before ieee80211_sched_scan_stopped_work() | ||
2767 | * could run. To handle this, simply return if the scan is | ||
2768 | * not running. | ||
2769 | */ | ||
2770 | /* FIXME: for now, we ignore this race for UMAC scans, since | ||
2771 | * they don't set the scan_status. | ||
2772 | */ | ||
2773 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED && | ||
2774 | !(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { | ||
2775 | mutex_unlock(&mvm->mutex); | ||
2776 | return 0; | ||
2777 | } | ||
2778 | |||
2612 | ret = iwl_mvm_scan_offload_stop(mvm, false); | 2779 | ret = iwl_mvm_scan_offload_stop(mvm, false); |
2613 | mutex_unlock(&mvm->mutex); | 2780 | mutex_unlock(&mvm->mutex); |
2614 | iwl_mvm_wait_for_async_handlers(mvm); | 2781 | iwl_mvm_wait_for_async_handlers(mvm); |
2615 | 2782 | ||
2616 | return ret; | 2783 | return ret; |
2617 | |||
2618 | } | 2784 | } |
2619 | 2785 | ||
2620 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | 2786 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, |
@@ -3127,14 +3293,14 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, | |||
3127 | */ | 3293 | */ |
3128 | if (vif->type == NL80211_IFTYPE_MONITOR) { | 3294 | if (vif->type == NL80211_IFTYPE_MONITOR) { |
3129 | mvmvif->monitor_active = true; | 3295 | mvmvif->monitor_active = true; |
3130 | ret = iwl_mvm_update_quotas(mvm, NULL); | 3296 | ret = iwl_mvm_update_quotas(mvm, false, NULL); |
3131 | if (ret) | 3297 | if (ret) |
3132 | goto out_remove_binding; | 3298 | goto out_remove_binding; |
3133 | } | 3299 | } |
3134 | 3300 | ||
3135 | /* Handle binding during CSA */ | 3301 | /* Handle binding during CSA */ |
3136 | if (vif->type == NL80211_IFTYPE_AP) { | 3302 | if (vif->type == NL80211_IFTYPE_AP) { |
3137 | iwl_mvm_update_quotas(mvm, NULL); | 3303 | iwl_mvm_update_quotas(mvm, false, NULL); |
3138 | iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); | 3304 | iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); |
3139 | } | 3305 | } |
3140 | 3306 | ||
@@ -3158,7 +3324,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, | |||
3158 | 3324 | ||
3159 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA); | 3325 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA); |
3160 | 3326 | ||
3161 | iwl_mvm_update_quotas(mvm, NULL); | 3327 | iwl_mvm_update_quotas(mvm, false, NULL); |
3162 | } | 3328 | } |
3163 | 3329 | ||
3164 | goto out; | 3330 | goto out; |
@@ -3231,7 +3397,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | |||
3231 | break; | 3397 | break; |
3232 | } | 3398 | } |
3233 | 3399 | ||
3234 | iwl_mvm_update_quotas(mvm, disabled_vif); | 3400 | iwl_mvm_update_quotas(mvm, false, disabled_vif); |
3235 | iwl_mvm_binding_remove_vif(mvm, vif); | 3401 | iwl_mvm_binding_remove_vif(mvm, vif); |
3236 | 3402 | ||
3237 | out: | 3403 | out: |
@@ -3423,7 +3589,7 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, | |||
3423 | mvm->noa_duration = noa_duration; | 3589 | mvm->noa_duration = noa_duration; |
3424 | mvm->noa_vif = vif; | 3590 | mvm->noa_vif = vif; |
3425 | 3591 | ||
3426 | return iwl_mvm_update_quotas(mvm, NULL); | 3592 | return iwl_mvm_update_quotas(mvm, false, NULL); |
3427 | case IWL_MVM_TM_CMD_SET_BEACON_FILTER: | 3593 | case IWL_MVM_TM_CMD_SET_BEACON_FILTER: |
3428 | /* must be associated client vif - ignore authorized */ | 3594 | /* must be associated client vif - ignore authorized */ |
3429 | if (!vif || vif->type != NL80211_IFTYPE_STATION || | 3595 | if (!vif || vif->type != NL80211_IFTYPE_STATION || |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e10172d69eaa..432265eb0dd7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -810,6 +810,9 @@ struct iwl_mvm { | |||
810 | /* system time of last beacon (for AP/GO interface) */ | 810 | /* system time of last beacon (for AP/GO interface) */ |
811 | u32 ap_last_beacon_gp2; | 811 | u32 ap_last_beacon_gp2; |
812 | 812 | ||
813 | bool lar_regdom_set; | ||
814 | enum iwl_mcc_source mcc_src; | ||
815 | |||
813 | u8 low_latency_agg_frame_limit; | 816 | u8 low_latency_agg_frame_limit; |
814 | 817 | ||
815 | /* TDLS channel switch data */ | 818 | /* TDLS channel switch data */ |
@@ -910,6 +913,30 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) | |||
910 | (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); | 913 | (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); |
911 | } | 914 | } |
912 | 915 | ||
916 | static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm) | ||
917 | { | ||
918 | bool nvm_lar = mvm->nvm_data->lar_enabled; | ||
919 | bool tlv_lar = mvm->fw->ucode_capa.capa[0] & | ||
920 | IWL_UCODE_TLV_CAPA_LAR_SUPPORT; | ||
921 | |||
922 | if (iwlwifi_mod_params.lar_disable) | ||
923 | return false; | ||
924 | |||
925 | /* | ||
926 | * Enable LAR only if it is supported by the FW (TLV) && | ||
927 | * enabled in the NVM | ||
928 | */ | ||
929 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
930 | return nvm_lar && tlv_lar; | ||
931 | else | ||
932 | return tlv_lar; | ||
933 | } | ||
934 | |||
935 | static inline bool iwl_mvm_is_wifi_mcc_supported(struct iwl_mvm *mvm) | ||
936 | { | ||
937 | return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WIFI_MCC_UPDATE; | ||
938 | } | ||
939 | |||
913 | static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) | 940 | static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) |
914 | { | 941 | { |
915 | return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG; | 942 | return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG; |
@@ -921,6 +948,12 @@ static inline bool iwl_mvm_bt_is_plcr_supported(struct iwl_mvm *mvm) | |||
921 | IWL_MVM_BT_COEX_CORUNNING; | 948 | IWL_MVM_BT_COEX_CORUNNING; |
922 | } | 949 | } |
923 | 950 | ||
951 | static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm) | ||
952 | { | ||
953 | return (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BT_COEX_RRC) && | ||
954 | IWL_MVM_BT_COEX_RRC; | ||
955 | } | ||
956 | |||
924 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; | 957 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; |
925 | 958 | ||
926 | struct iwl_rate_info { | 959 | struct iwl_rate_info { |
@@ -1106,7 +1139,7 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | |||
1106 | int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 1139 | int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
1107 | 1140 | ||
1108 | /* Quota management */ | 1141 | /* Quota management */ |
1109 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | 1142 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, bool force_upload, |
1110 | struct ieee80211_vif *disabled_vif); | 1143 | struct ieee80211_vif *disabled_vif); |
1111 | 1144 | ||
1112 | /* Scanning */ | 1145 | /* Scanning */ |
@@ -1282,17 +1315,6 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, | |||
1282 | struct iwl_rx_cmd_buffer *rxb, | 1315 | struct iwl_rx_cmd_buffer *rxb, |
1283 | struct iwl_device_cmd *cmd); | 1316 | struct iwl_device_cmd *cmd); |
1284 | 1317 | ||
1285 | enum iwl_bt_kill_msk { | ||
1286 | BT_KILL_MSK_DEFAULT, | ||
1287 | BT_KILL_MSK_NEVER, | ||
1288 | BT_KILL_MSK_ALWAYS, | ||
1289 | BT_KILL_MSK_MAX, | ||
1290 | }; | ||
1291 | |||
1292 | extern const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT]; | ||
1293 | extern const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT]; | ||
1294 | extern const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX]; | ||
1295 | |||
1296 | /* beacon filtering */ | 1318 | /* beacon filtering */ |
1297 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1319 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
1298 | void | 1320 | void |
@@ -1389,6 +1411,23 @@ void iwl_mvm_tt_exit(struct iwl_mvm *mvm); | |||
1389 | void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); | 1411 | void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); |
1390 | int iwl_mvm_get_temp(struct iwl_mvm *mvm); | 1412 | int iwl_mvm_get_temp(struct iwl_mvm *mvm); |
1391 | 1413 | ||
1414 | /* Location Aware Regulatory */ | ||
1415 | struct iwl_mcc_update_resp * | ||
1416 | iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, | ||
1417 | enum iwl_mcc_source src_id); | ||
1418 | int iwl_mvm_init_mcc(struct iwl_mvm *mvm); | ||
1419 | int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, | ||
1420 | struct iwl_rx_cmd_buffer *rxb, | ||
1421 | struct iwl_device_cmd *cmd); | ||
1422 | struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, | ||
1423 | const char *alpha2, | ||
1424 | enum iwl_mcc_source src_id, | ||
1425 | bool *changed); | ||
1426 | struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm, | ||
1427 | bool *changed); | ||
1428 | int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm); | ||
1429 | void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm); | ||
1430 | |||
1392 | /* smart fifo */ | 1431 | /* smart fifo */ |
1393 | int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1432 | int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
1394 | bool added_vif); | 1433 | bool added_vif); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 5383429d96c1..123e0a16aea8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
@@ -63,12 +63,16 @@ | |||
63 | * | 63 | * |
64 | *****************************************************************************/ | 64 | *****************************************************************************/ |
65 | #include <linux/firmware.h> | 65 | #include <linux/firmware.h> |
66 | #include <linux/rtnetlink.h> | ||
67 | #include <linux/pci.h> | ||
68 | #include <linux/acpi.h> | ||
66 | #include "iwl-trans.h" | 69 | #include "iwl-trans.h" |
67 | #include "iwl-csr.h" | 70 | #include "iwl-csr.h" |
68 | #include "mvm.h" | 71 | #include "mvm.h" |
69 | #include "iwl-eeprom-parse.h" | 72 | #include "iwl-eeprom-parse.h" |
70 | #include "iwl-eeprom-read.h" | 73 | #include "iwl-eeprom-read.h" |
71 | #include "iwl-nvm-parse.h" | 74 | #include "iwl-nvm-parse.h" |
75 | #include "iwl-prph.h" | ||
72 | 76 | ||
73 | /* Default NVM size to read */ | 77 | /* Default NVM size to read */ |
74 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) | 78 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) |
@@ -262,7 +266,9 @@ static struct iwl_nvm_data * | |||
262 | iwl_parse_nvm_sections(struct iwl_mvm *mvm) | 266 | iwl_parse_nvm_sections(struct iwl_mvm *mvm) |
263 | { | 267 | { |
264 | struct iwl_nvm_section *sections = mvm->nvm_sections; | 268 | struct iwl_nvm_section *sections = mvm->nvm_sections; |
265 | const __le16 *hw, *sw, *calib, *regulatory, *mac_override; | 269 | const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku; |
270 | bool is_family_8000_a_step = false, lar_enabled; | ||
271 | u32 mac_addr0, mac_addr1; | ||
266 | 272 | ||
267 | /* Checking for required sections */ | 273 | /* Checking for required sections */ |
268 | if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { | 274 | if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { |
@@ -286,22 +292,43 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) | |||
286 | "Can't parse mac_address, empty sections\n"); | 292 | "Can't parse mac_address, empty sections\n"); |
287 | return NULL; | 293 | return NULL; |
288 | } | 294 | } |
295 | |||
296 | if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) | ||
297 | is_family_8000_a_step = true; | ||
298 | |||
299 | /* PHY_SKU section is mandatory in B0 */ | ||
300 | if (!is_family_8000_a_step && | ||
301 | !mvm->nvm_sections[NVM_SECTION_TYPE_PHY_SKU].data) { | ||
302 | IWL_ERR(mvm, | ||
303 | "Can't parse phy_sku in B0, empty sections\n"); | ||
304 | return NULL; | ||
305 | } | ||
289 | } | 306 | } |
290 | 307 | ||
291 | if (WARN_ON(!mvm->cfg)) | 308 | if (WARN_ON(!mvm->cfg)) |
292 | return NULL; | 309 | return NULL; |
293 | 310 | ||
311 | /* read the mac address from WFMP registers */ | ||
312 | mac_addr0 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_0); | ||
313 | mac_addr1 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_1); | ||
314 | |||
294 | hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; | 315 | hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; |
295 | sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; | 316 | sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; |
296 | calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; | 317 | calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; |
297 | regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data; | 318 | regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data; |
298 | mac_override = | 319 | mac_override = |
299 | (const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data; | 320 | (const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data; |
321 | phy_sku = (const __le16 *)sections[NVM_SECTION_TYPE_PHY_SKU].data; | ||
322 | |||
323 | lar_enabled = !iwlwifi_mod_params.lar_disable && | ||
324 | (mvm->fw->ucode_capa.capa[0] & | ||
325 | IWL_UCODE_TLV_CAPA_LAR_SUPPORT); | ||
300 | 326 | ||
301 | return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, | 327 | return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, |
302 | regulatory, mac_override, | 328 | regulatory, mac_override, phy_sku, |
303 | mvm->fw->valid_tx_ant, | 329 | mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant, |
304 | mvm->fw->valid_rx_ant); | 330 | lar_enabled, is_family_8000_a_step, |
331 | mac_addr0, mac_addr1); | ||
305 | } | 332 | } |
306 | 333 | ||
307 | #define MAX_NVM_FILE_LEN 16384 | 334 | #define MAX_NVM_FILE_LEN 16384 |
@@ -570,3 +597,258 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) | |||
570 | 597 | ||
571 | return 0; | 598 | return 0; |
572 | } | 599 | } |
600 | |||
601 | struct iwl_mcc_update_resp * | ||
602 | iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, | ||
603 | enum iwl_mcc_source src_id) | ||
604 | { | ||
605 | struct iwl_mcc_update_cmd mcc_update_cmd = { | ||
606 | .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]), | ||
607 | .source_id = (u8)src_id, | ||
608 | }; | ||
609 | struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL; | ||
610 | struct iwl_rx_packet *pkt; | ||
611 | struct iwl_host_cmd cmd = { | ||
612 | .id = MCC_UPDATE_CMD, | ||
613 | .flags = CMD_WANT_SKB, | ||
614 | .data = { &mcc_update_cmd }, | ||
615 | }; | ||
616 | |||
617 | int ret; | ||
618 | u32 status; | ||
619 | int resp_len, n_channels; | ||
620 | u16 mcc; | ||
621 | |||
622 | if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) | ||
623 | return ERR_PTR(-EOPNOTSUPP); | ||
624 | |||
625 | cmd.len[0] = sizeof(struct iwl_mcc_update_cmd); | ||
626 | |||
627 | IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n", | ||
628 | alpha2[0], alpha2[1], src_id); | ||
629 | |||
630 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
631 | if (ret) | ||
632 | return ERR_PTR(ret); | ||
633 | |||
634 | pkt = cmd.resp_pkt; | ||
635 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
636 | IWL_ERR(mvm, "Bad return from MCC_UPDATE_COMMAND (0x%08X)\n", | ||
637 | pkt->hdr.flags); | ||
638 | ret = -EIO; | ||
639 | goto exit; | ||
640 | } | ||
641 | |||
642 | /* Extract MCC response */ | ||
643 | mcc_resp = (void *)pkt->data; | ||
644 | status = le32_to_cpu(mcc_resp->status); | ||
645 | |||
646 | mcc = le16_to_cpu(mcc_resp->mcc); | ||
647 | |||
648 | /* W/A for a FW/NVM issue - returns 0x00 for the world domain */ | ||
649 | if (mcc == 0) { | ||
650 | mcc = 0x3030; /* "00" - world */ | ||
651 | mcc_resp->mcc = cpu_to_le16(mcc); | ||
652 | } | ||
653 | |||
654 | n_channels = __le32_to_cpu(mcc_resp->n_channels); | ||
655 | IWL_DEBUG_LAR(mvm, | ||
656 | "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n", | ||
657 | status, mcc, mcc >> 8, mcc & 0xff, | ||
658 | !!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels); | ||
659 | |||
660 | resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32); | ||
661 | resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); | ||
662 | if (!resp_cp) { | ||
663 | ret = -ENOMEM; | ||
664 | goto exit; | ||
665 | } | ||
666 | |||
667 | ret = 0; | ||
668 | exit: | ||
669 | iwl_free_resp(&cmd); | ||
670 | if (ret) | ||
671 | return ERR_PTR(ret); | ||
672 | return resp_cp; | ||
673 | } | ||
674 | |||
675 | #ifdef CONFIG_ACPI | ||
676 | #define WRD_METHOD "WRDD" | ||
677 | #define WRDD_WIFI (0x07) | ||
678 | #define WRDD_WIGIG (0x10) | ||
679 | |||
680 | static u32 iwl_mvm_wrdd_get_mcc(struct iwl_mvm *mvm, union acpi_object *wrdd) | ||
681 | { | ||
682 | union acpi_object *mcc_pkg, *domain_type, *mcc_value; | ||
683 | u32 i; | ||
684 | |||
685 | if (wrdd->type != ACPI_TYPE_PACKAGE || | ||
686 | wrdd->package.count < 2 || | ||
687 | wrdd->package.elements[0].type != ACPI_TYPE_INTEGER || | ||
688 | wrdd->package.elements[0].integer.value != 0) { | ||
689 | IWL_DEBUG_LAR(mvm, "Unsupported wrdd structure\n"); | ||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | for (i = 1 ; i < wrdd->package.count ; ++i) { | ||
694 | mcc_pkg = &wrdd->package.elements[i]; | ||
695 | |||
696 | if (mcc_pkg->type != ACPI_TYPE_PACKAGE || | ||
697 | mcc_pkg->package.count < 2 || | ||
698 | mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER || | ||
699 | mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { | ||
700 | mcc_pkg = NULL; | ||
701 | continue; | ||
702 | } | ||
703 | |||
704 | domain_type = &mcc_pkg->package.elements[0]; | ||
705 | if (domain_type->integer.value == WRDD_WIFI) | ||
706 | break; | ||
707 | |||
708 | mcc_pkg = NULL; | ||
709 | } | ||
710 | |||
711 | if (mcc_pkg) { | ||
712 | mcc_value = &mcc_pkg->package.elements[1]; | ||
713 | return mcc_value->integer.value; | ||
714 | } | ||
715 | |||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc) | ||
720 | { | ||
721 | acpi_handle root_handle; | ||
722 | acpi_handle handle; | ||
723 | struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
724 | acpi_status status; | ||
725 | u32 mcc_val; | ||
726 | struct pci_dev *pdev = to_pci_dev(mvm->dev); | ||
727 | |||
728 | root_handle = ACPI_HANDLE(&pdev->dev); | ||
729 | if (!root_handle) { | ||
730 | IWL_DEBUG_LAR(mvm, | ||
731 | "Could not retrieve root port ACPI handle\n"); | ||
732 | return -ENOENT; | ||
733 | } | ||
734 | |||
735 | /* Get the method's handle */ | ||
736 | status = acpi_get_handle(root_handle, (acpi_string)WRD_METHOD, &handle); | ||
737 | if (ACPI_FAILURE(status)) { | ||
738 | IWL_DEBUG_LAR(mvm, "WRD method not found\n"); | ||
739 | return -ENOENT; | ||
740 | } | ||
741 | |||
742 | /* Call WRDD with no arguments */ | ||
743 | status = acpi_evaluate_object(handle, NULL, NULL, &wrdd); | ||
744 | if (ACPI_FAILURE(status)) { | ||
745 | IWL_DEBUG_LAR(mvm, "WRDC invocation failed (0x%x)\n", status); | ||
746 | return -ENOENT; | ||
747 | } | ||
748 | |||
749 | mcc_val = iwl_mvm_wrdd_get_mcc(mvm, wrdd.pointer); | ||
750 | kfree(wrdd.pointer); | ||
751 | if (!mcc_val) | ||
752 | return -ENOENT; | ||
753 | |||
754 | mcc[0] = (mcc_val >> 8) & 0xff; | ||
755 | mcc[1] = mcc_val & 0xff; | ||
756 | mcc[2] = '\0'; | ||
757 | return 0; | ||
758 | } | ||
759 | #else /* CONFIG_ACPI */ | ||
760 | static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc) | ||
761 | { | ||
762 | return -ENOENT; | ||
763 | } | ||
764 | #endif | ||
765 | |||
766 | int iwl_mvm_init_mcc(struct iwl_mvm *mvm) | ||
767 | { | ||
768 | bool tlv_lar; | ||
769 | bool nvm_lar; | ||
770 | int retval; | ||
771 | struct ieee80211_regdomain *regd; | ||
772 | char mcc[3]; | ||
773 | |||
774 | if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) { | ||
775 | tlv_lar = mvm->fw->ucode_capa.capa[0] & | ||
776 | IWL_UCODE_TLV_CAPA_LAR_SUPPORT; | ||
777 | nvm_lar = mvm->nvm_data->lar_enabled; | ||
778 | if (tlv_lar != nvm_lar) | ||
779 | IWL_INFO(mvm, | ||
780 | "Conflict between TLV & NVM regarding enabling LAR (TLV = %s NVM =%s)\n", | ||
781 | tlv_lar ? "enabled" : "disabled", | ||
782 | nvm_lar ? "enabled" : "disabled"); | ||
783 | } | ||
784 | |||
785 | if (!iwl_mvm_is_lar_supported(mvm)) | ||
786 | return 0; | ||
787 | |||
788 | /* | ||
789 | * During HW restart, only replay the last set MCC to FW. Otherwise, | ||
790 | * queue an update to cfg80211 to retrieve the default alpha2 from FW. | ||
791 | */ | ||
792 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | ||
793 | /* This should only be called during vif up and hold RTNL */ | ||
794 | return iwl_mvm_init_fw_regd(mvm); | ||
795 | } | ||
796 | |||
797 | /* | ||
798 | * Driver regulatory hint for initial update, this also informs the | ||
799 | * firmware we support wifi location updates. | ||
800 | * Disallow scans that might crash the FW while the LAR regdomain | ||
801 | * is not set. | ||
802 | */ | ||
803 | mvm->lar_regdom_set = false; | ||
804 | |||
805 | regd = iwl_mvm_get_current_regdomain(mvm, NULL); | ||
806 | if (IS_ERR_OR_NULL(regd)) | ||
807 | return -EIO; | ||
808 | |||
809 | if (iwl_mvm_is_wifi_mcc_supported(mvm) && | ||
810 | !iwl_mvm_get_bios_mcc(mvm, mcc)) { | ||
811 | kfree(regd); | ||
812 | regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, | ||
813 | MCC_SOURCE_BIOS, NULL); | ||
814 | if (IS_ERR_OR_NULL(regd)) | ||
815 | return -EIO; | ||
816 | } | ||
817 | |||
818 | retval = regulatory_set_wiphy_regd_sync_rtnl(mvm->hw->wiphy, regd); | ||
819 | kfree(regd); | ||
820 | return retval; | ||
821 | } | ||
822 | |||
823 | int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, | ||
824 | struct iwl_rx_cmd_buffer *rxb, | ||
825 | struct iwl_device_cmd *cmd) | ||
826 | { | ||
827 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
828 | struct iwl_mcc_chub_notif *notif = (void *)pkt->data; | ||
829 | enum iwl_mcc_source src; | ||
830 | char mcc[3]; | ||
831 | struct ieee80211_regdomain *regd; | ||
832 | |||
833 | lockdep_assert_held(&mvm->mutex); | ||
834 | |||
835 | if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) | ||
836 | return 0; | ||
837 | |||
838 | mcc[0] = notif->mcc >> 8; | ||
839 | mcc[1] = notif->mcc & 0xff; | ||
840 | mcc[2] = '\0'; | ||
841 | src = notif->source_id; | ||
842 | |||
843 | IWL_DEBUG_LAR(mvm, | ||
844 | "RX: received chub update mcc cmd (mcc '%s' src %d)\n", | ||
845 | mcc, src); | ||
846 | regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src, NULL); | ||
847 | if (IS_ERR_OR_NULL(regd)) | ||
848 | return 0; | ||
849 | |||
850 | regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); | ||
851 | kfree(regd); | ||
852 | |||
853 | return 0; | ||
854 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index fe40922a6b0d..80121e41ca22 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -82,7 +82,6 @@ | |||
82 | #include "rs.h" | 82 | #include "rs.h" |
83 | #include "fw-api-scan.h" | 83 | #include "fw-api-scan.h" |
84 | #include "time-event.h" | 84 | #include "time-event.h" |
85 | #include "iwl-fw-error-dump.h" | ||
86 | 85 | ||
87 | #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" | 86 | #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" |
88 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | 87 | MODULE_DESCRIPTION(DRV_DESCRIPTION); |
@@ -234,6 +233,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
234 | iwl_mvm_rx_ant_coupling_notif, true), | 233 | iwl_mvm_rx_ant_coupling_notif, true), |
235 | 234 | ||
236 | RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), | 235 | RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), |
236 | RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, true), | ||
237 | 237 | ||
238 | RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false), | 238 | RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false), |
239 | 239 | ||
@@ -358,6 +358,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
358 | CMD(TDLS_CHANNEL_SWITCH_CMD), | 358 | CMD(TDLS_CHANNEL_SWITCH_CMD), |
359 | CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION), | 359 | CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION), |
360 | CMD(TDLS_CONFIG_CMD), | 360 | CMD(TDLS_CONFIG_CMD), |
361 | CMD(MCC_UPDATE_CMD), | ||
361 | }; | 362 | }; |
362 | #undef CMD | 363 | #undef CMD |
363 | 364 | ||
@@ -871,8 +872,8 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) | |||
871 | 872 | ||
872 | /* start recording again if the firmware is not crashed */ | 873 | /* start recording again if the firmware is not crashed */ |
873 | WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) && | 874 | WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) && |
874 | mvm->fw->dbg_dest_tlv && | 875 | mvm->fw->dbg_dest_tlv && |
875 | iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf)); | 876 | iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf)); |
876 | 877 | ||
877 | mutex_unlock(&mvm->mutex); | 878 | mutex_unlock(&mvm->mutex); |
878 | 879 | ||
@@ -1270,6 +1271,10 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) | |||
1270 | iwl_free_resp(&get_status_cmd); | 1271 | iwl_free_resp(&get_status_cmd); |
1271 | out: | 1272 | out: |
1272 | iwl_mvm_d0i3_enable_tx(mvm, qos_seq); | 1273 | iwl_mvm_d0i3_enable_tx(mvm, qos_seq); |
1274 | |||
1275 | /* the FW might have updated the regdomain */ | ||
1276 | iwl_mvm_update_changed_regdom(mvm); | ||
1277 | |||
1273 | iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK); | 1278 | iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK); |
1274 | mutex_unlock(&mvm->mutex); | 1279 | mutex_unlock(&mvm->mutex); |
1275 | } | 1280 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 33bbdde0046f..d2c6ba9d326b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -358,7 +358,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | |||
358 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | 358 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
359 | 359 | ||
360 | if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || | 360 | if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || |
361 | !mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif)) | 361 | !mvmvif->pm_enabled) |
362 | return; | 362 | return; |
363 | 363 | ||
364 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | 364 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); |
@@ -639,6 +639,10 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, | |||
639 | if (vifs->ap_vif) | 639 | if (vifs->ap_vif) |
640 | ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); | 640 | ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); |
641 | 641 | ||
642 | /* don't allow PM if any TDLS stations exist */ | ||
643 | if (iwl_mvm_tdls_sta_count(mvm, NULL)) | ||
644 | return; | ||
645 | |||
642 | /* enable PM on bss if bss stand alone */ | 646 | /* enable PM on bss if bss stand alone */ |
643 | if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { | 647 | if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { |
644 | bss_mvmvif->pm_enabled = true; | 648 | bss_mvmvif->pm_enabled = true; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index dbb2594390e9..509a66d05245 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -172,6 +172,7 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, | |||
172 | } | 172 | } |
173 | 173 | ||
174 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | 174 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, |
175 | bool force_update, | ||
175 | struct ieee80211_vif *disabled_vif) | 176 | struct ieee80211_vif *disabled_vif) |
176 | { | 177 | { |
177 | struct iwl_time_quota_cmd cmd = {}; | 178 | struct iwl_time_quota_cmd cmd = {}; |
@@ -309,7 +310,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | |||
309 | "zero quota on binding %d\n", i); | 310 | "zero quota on binding %d\n", i); |
310 | } | 311 | } |
311 | 312 | ||
312 | if (!send) { | 313 | if (!send && !force_update) { |
313 | /* don't send a practically unchanged command, the firmware has | 314 | /* don't send a practically unchanged command, the firmware has |
314 | * to re-initialize a lot of state and that can have an adverse | 315 | * to re-initialize a lot of state and that can have an adverse |
315 | * impact on it | 316 | * impact on it |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 6578498dd5af..dd457df9601e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -1065,6 +1065,37 @@ static inline bool rs_rate_column_match(struct rs_rate *a, | |||
1065 | && ant_match; | 1065 | && ant_match; |
1066 | } | 1066 | } |
1067 | 1067 | ||
1068 | static inline enum rs_column rs_get_column_from_rate(struct rs_rate *rate) | ||
1069 | { | ||
1070 | if (is_legacy(rate)) { | ||
1071 | if (rate->ant == ANT_A) | ||
1072 | return RS_COLUMN_LEGACY_ANT_A; | ||
1073 | |||
1074 | if (rate->ant == ANT_B) | ||
1075 | return RS_COLUMN_LEGACY_ANT_B; | ||
1076 | |||
1077 | goto err; | ||
1078 | } | ||
1079 | |||
1080 | if (is_siso(rate)) { | ||
1081 | if (rate->ant == ANT_A || rate->stbc || rate->bfer) | ||
1082 | return rate->sgi ? RS_COLUMN_SISO_ANT_A_SGI : | ||
1083 | RS_COLUMN_SISO_ANT_A; | ||
1084 | |||
1085 | if (rate->ant == ANT_B) | ||
1086 | return rate->sgi ? RS_COLUMN_SISO_ANT_B_SGI : | ||
1087 | RS_COLUMN_SISO_ANT_B; | ||
1088 | |||
1089 | goto err; | ||
1090 | } | ||
1091 | |||
1092 | if (is_mimo(rate)) | ||
1093 | return rate->sgi ? RS_COLUMN_MIMO2_SGI : RS_COLUMN_MIMO2; | ||
1094 | |||
1095 | err: | ||
1096 | return RS_COLUMN_INVALID; | ||
1097 | } | ||
1098 | |||
1068 | static u8 rs_get_tid(struct ieee80211_hdr *hdr) | 1099 | static u8 rs_get_tid(struct ieee80211_hdr *hdr) |
1069 | { | 1100 | { |
1070 | u8 tid = IWL_MAX_TID_COUNT; | 1101 | u8 tid = IWL_MAX_TID_COUNT; |
@@ -1106,17 +1137,43 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
1106 | return; | 1137 | return; |
1107 | } | 1138 | } |
1108 | 1139 | ||
1140 | /* This packet was aggregated but doesn't carry status info */ | ||
1141 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | ||
1142 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) | ||
1143 | return; | ||
1144 | |||
1145 | rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, &tx_resp_rate); | ||
1146 | |||
1109 | #ifdef CONFIG_MAC80211_DEBUGFS | 1147 | #ifdef CONFIG_MAC80211_DEBUGFS |
1110 | /* Disable last tx check if we are debugging with fixed rate */ | 1148 | /* Disable last tx check if we are debugging with fixed rate but |
1149 | * update tx stats */ | ||
1111 | if (lq_sta->pers.dbg_fixed_rate) { | 1150 | if (lq_sta->pers.dbg_fixed_rate) { |
1112 | IWL_DEBUG_RATE(mvm, "Fixed rate. avoid rate scaling\n"); | 1151 | int index = tx_resp_rate.index; |
1152 | enum rs_column column; | ||
1153 | int attempts, success; | ||
1154 | |||
1155 | column = rs_get_column_from_rate(&tx_resp_rate); | ||
1156 | if (WARN_ONCE(column == RS_COLUMN_INVALID, | ||
1157 | "Can't map rate 0x%x to column", | ||
1158 | tx_resp_hwrate)) | ||
1159 | return; | ||
1160 | |||
1161 | if (info->flags & IEEE80211_TX_STAT_AMPDU) { | ||
1162 | attempts = info->status.ampdu_len; | ||
1163 | success = info->status.ampdu_ack_len; | ||
1164 | } else { | ||
1165 | attempts = info->status.rates[0].count; | ||
1166 | success = !!(info->flags & IEEE80211_TX_STAT_ACK); | ||
1167 | } | ||
1168 | |||
1169 | lq_sta->pers.tx_stats[column][index].total += attempts; | ||
1170 | lq_sta->pers.tx_stats[column][index].success += success; | ||
1171 | |||
1172 | IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n", | ||
1173 | tx_resp_hwrate, success, attempts); | ||
1113 | return; | 1174 | return; |
1114 | } | 1175 | } |
1115 | #endif | 1176 | #endif |
1116 | /* This packet was aggregated but doesn't carry status info */ | ||
1117 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && | ||
1118 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) | ||
1119 | return; | ||
1120 | 1177 | ||
1121 | if (time_after(jiffies, | 1178 | if (time_after(jiffies, |
1122 | (unsigned long)(lq_sta->last_tx + | 1179 | (unsigned long)(lq_sta->last_tx + |
@@ -1142,7 +1199,6 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | |||
1142 | table = &lq_sta->lq; | 1199 | table = &lq_sta->lq; |
1143 | lq_hwrate = le32_to_cpu(table->rs_table[0]); | 1200 | lq_hwrate = le32_to_cpu(table->rs_table[0]); |
1144 | rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate); | 1201 | rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate); |
1145 | rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, &tx_resp_rate); | ||
1146 | 1202 | ||
1147 | /* Here we actually compare this rate to the latest LQ command */ | 1203 | /* Here we actually compare this rate to the latest LQ command */ |
1148 | if (!rs_rate_equal(&tx_resp_rate, &lq_rate, allow_ant_mismatch)) { | 1204 | if (!rs_rate_equal(&tx_resp_rate, &lq_rate, allow_ant_mismatch)) { |
@@ -3343,16 +3399,16 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
3343 | (is_legacy(rate)) ? "legacy" : | 3399 | (is_legacy(rate)) ? "legacy" : |
3344 | is_vht(rate) ? "VHT" : "HT"); | 3400 | is_vht(rate) ? "VHT" : "HT"); |
3345 | if (!is_legacy(rate)) { | 3401 | if (!is_legacy(rate)) { |
3346 | desc += sprintf(buff+desc, " %s", | 3402 | desc += sprintf(buff + desc, " %s", |
3347 | (is_siso(rate)) ? "SISO" : "MIMO2"); | 3403 | (is_siso(rate)) ? "SISO" : "MIMO2"); |
3348 | desc += sprintf(buff+desc, " %s", | 3404 | desc += sprintf(buff + desc, " %s", |
3349 | (is_ht20(rate)) ? "20MHz" : | 3405 | (is_ht20(rate)) ? "20MHz" : |
3350 | (is_ht40(rate)) ? "40MHz" : | 3406 | (is_ht40(rate)) ? "40MHz" : |
3351 | (is_ht80(rate)) ? "80Mhz" : "BAD BW"); | 3407 | (is_ht80(rate)) ? "80Mhz" : "BAD BW"); |
3352 | desc += sprintf(buff+desc, " %s %s %s\n", | 3408 | desc += sprintf(buff + desc, " %s %s %s\n", |
3353 | (rate->sgi) ? "SGI" : "NGI", | 3409 | (rate->sgi) ? "SGI" : "NGI", |
3354 | (rate->ldpc) ? "LDPC" : "BCC", | 3410 | (rate->ldpc) ? "LDPC" : "BCC", |
3355 | (lq_sta->is_agg) ? "AGG on" : ""); | 3411 | (lq_sta->is_agg) ? "AGG on" : ""); |
3356 | } | 3412 | } |
3357 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", | 3413 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", |
3358 | lq_sta->last_rate_n_flags); | 3414 | lq_sta->last_rate_n_flags); |
@@ -3373,13 +3429,13 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
3373 | ss_params = le32_to_cpu(lq_sta->lq.ss_params); | 3429 | ss_params = le32_to_cpu(lq_sta->lq.ss_params); |
3374 | desc += sprintf(buff+desc, "single stream params: %s%s%s%s\n", | 3430 | desc += sprintf(buff+desc, "single stream params: %s%s%s%s\n", |
3375 | (ss_params & LQ_SS_PARAMS_VALID) ? | 3431 | (ss_params & LQ_SS_PARAMS_VALID) ? |
3376 | "VALID," : "INVALID", | 3432 | "VALID" : "INVALID", |
3377 | (ss_params & LQ_SS_BFER_ALLOWED) ? | 3433 | (ss_params & LQ_SS_BFER_ALLOWED) ? |
3378 | "BFER," : "", | 3434 | ", BFER" : "", |
3379 | (ss_params & LQ_SS_STBC_1SS_ALLOWED) ? | 3435 | (ss_params & LQ_SS_STBC_1SS_ALLOWED) ? |
3380 | "STBC," : "", | 3436 | ", STBC" : "", |
3381 | (ss_params & LQ_SS_FORCE) ? | 3437 | (ss_params & LQ_SS_FORCE) ? |
3382 | "FORCE" : ""); | 3438 | ", FORCE" : ""); |
3383 | desc += sprintf(buff+desc, | 3439 | desc += sprintf(buff+desc, |
3384 | "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n", | 3440 | "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n", |
3385 | lq_sta->lq.initial_rate_index[0], | 3441 | lq_sta->lq.initial_rate_index[0], |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index f0946b5dd7c8..a75bb150ea27 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -587,8 +587,10 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) | |||
587 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) | 587 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) |
588 | return 0; | 588 | return 0; |
589 | 589 | ||
590 | if (iwl_mvm_is_radio_killed(mvm)) | 590 | if (iwl_mvm_is_radio_killed(mvm)) { |
591 | ret = 0; | ||
591 | goto out; | 592 | goto out; |
593 | } | ||
592 | 594 | ||
593 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, | 595 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, |
594 | scan_done_notif, | 596 | scan_done_notif, |
@@ -600,16 +602,14 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) | |||
600 | IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n", | 602 | IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n", |
601 | sched ? "offloaded " : "", ret); | 603 | sched ? "offloaded " : "", ret); |
602 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); | 604 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); |
603 | return ret; | 605 | goto out; |
604 | } | 606 | } |
605 | 607 | ||
606 | IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n", | 608 | IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n", |
607 | sched ? "offloaded " : ""); | 609 | sched ? "offloaded " : ""); |
608 | 610 | ||
609 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); | 611 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); |
610 | if (ret) | 612 | out: |
611 | return ret; | ||
612 | |||
613 | /* | 613 | /* |
614 | * Clear the scan status so the next scan requests will succeed. This | 614 | * Clear the scan status so the next scan requests will succeed. This |
615 | * also ensures the Rx handler doesn't do anything, as the scan was | 615 | * also ensures the Rx handler doesn't do anything, as the scan was |
@@ -619,7 +619,6 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) | |||
619 | if (mvm->scan_status == IWL_MVM_SCAN_OS) | 619 | if (mvm->scan_status == IWL_MVM_SCAN_OS) |
620 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | 620 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); |
621 | 621 | ||
622 | out: | ||
623 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 622 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
624 | 623 | ||
625 | if (notify) { | 624 | if (notify) { |
@@ -629,7 +628,7 @@ out: | |||
629 | ieee80211_scan_completed(mvm->hw, true); | 628 | ieee80211_scan_completed(mvm->hw, true); |
630 | } | 629 | } |
631 | 630 | ||
632 | return 0; | 631 | return ret; |
633 | } | 632 | } |
634 | 633 | ||
635 | static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm, | 634 | static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index 7eb78e2c240a..b0f59fdd287c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c | |||
@@ -99,7 +99,35 @@ static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac, | |||
99 | 99 | ||
100 | /* | 100 | /* |
101 | * Aging and idle timeouts for the different possible scenarios | 101 | * Aging and idle timeouts for the different possible scenarios |
102 | * in SF_FULL_ON state. | 102 | * in default configuration |
103 | */ | ||
104 | static const | ||
105 | __le32 sf_full_timeout_def[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = { | ||
106 | { | ||
107 | cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER_DEF), | ||
108 | cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER_DEF) | ||
109 | }, | ||
110 | { | ||
111 | cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER_DEF), | ||
112 | cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER_DEF) | ||
113 | }, | ||
114 | { | ||
115 | cpu_to_le32(SF_MCAST_AGING_TIMER_DEF), | ||
116 | cpu_to_le32(SF_MCAST_IDLE_TIMER_DEF) | ||
117 | }, | ||
118 | { | ||
119 | cpu_to_le32(SF_BA_AGING_TIMER_DEF), | ||
120 | cpu_to_le32(SF_BA_IDLE_TIMER_DEF) | ||
121 | }, | ||
122 | { | ||
123 | cpu_to_le32(SF_TX_RE_AGING_TIMER_DEF), | ||
124 | cpu_to_le32(SF_TX_RE_IDLE_TIMER_DEF) | ||
125 | }, | ||
126 | }; | ||
127 | |||
128 | /* | ||
129 | * Aging and idle timeouts for the different possible scenarios | ||
130 | * in single BSS MAC configuration. | ||
103 | */ | 131 | */ |
104 | static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = { | 132 | static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = { |
105 | { | 133 | { |
@@ -124,7 +152,8 @@ static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = { | |||
124 | }, | 152 | }, |
125 | }; | 153 | }; |
126 | 154 | ||
127 | static void iwl_mvm_fill_sf_command(struct iwl_sf_cfg_cmd *sf_cmd, | 155 | static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm, |
156 | struct iwl_sf_cfg_cmd *sf_cmd, | ||
128 | struct ieee80211_sta *sta) | 157 | struct ieee80211_sta *sta) |
129 | { | 158 | { |
130 | int i, j, watermark; | 159 | int i, j, watermark; |
@@ -163,24 +192,38 @@ static void iwl_mvm_fill_sf_command(struct iwl_sf_cfg_cmd *sf_cmd, | |||
163 | cpu_to_le32(SF_LONG_DELAY_AGING_TIMER); | 192 | cpu_to_le32(SF_LONG_DELAY_AGING_TIMER); |
164 | } | 193 | } |
165 | } | 194 | } |
166 | BUILD_BUG_ON(sizeof(sf_full_timeout) != | ||
167 | sizeof(__le32) * SF_NUM_SCENARIO * SF_NUM_TIMEOUT_TYPES); | ||
168 | 195 | ||
169 | memcpy(sf_cmd->full_on_timeouts, sf_full_timeout, | 196 | if (sta || IWL_UCODE_API(mvm->fw->ucode_ver) < 13) { |
170 | sizeof(sf_full_timeout)); | 197 | BUILD_BUG_ON(sizeof(sf_full_timeout) != |
198 | sizeof(__le32) * SF_NUM_SCENARIO * | ||
199 | SF_NUM_TIMEOUT_TYPES); | ||
200 | |||
201 | memcpy(sf_cmd->full_on_timeouts, sf_full_timeout, | ||
202 | sizeof(sf_full_timeout)); | ||
203 | } else { | ||
204 | BUILD_BUG_ON(sizeof(sf_full_timeout_def) != | ||
205 | sizeof(__le32) * SF_NUM_SCENARIO * | ||
206 | SF_NUM_TIMEOUT_TYPES); | ||
207 | |||
208 | memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def, | ||
209 | sizeof(sf_full_timeout_def)); | ||
210 | } | ||
211 | |||
171 | } | 212 | } |
172 | 213 | ||
173 | static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, | 214 | static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, |
174 | enum iwl_sf_state new_state) | 215 | enum iwl_sf_state new_state) |
175 | { | 216 | { |
176 | struct iwl_sf_cfg_cmd sf_cmd = { | 217 | struct iwl_sf_cfg_cmd sf_cmd = { |
177 | .state = cpu_to_le32(new_state), | 218 | .state = cpu_to_le32(SF_FULL_ON), |
178 | }; | 219 | }; |
179 | struct ieee80211_sta *sta; | 220 | struct ieee80211_sta *sta; |
180 | int ret = 0; | 221 | int ret = 0; |
181 | 222 | ||
182 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF && | 223 | if (IWL_UCODE_API(mvm->fw->ucode_ver) < 13) |
183 | mvm->cfg->disable_dummy_notification) | 224 | sf_cmd.state = cpu_to_le32(new_state); |
225 | |||
226 | if (mvm->cfg->disable_dummy_notification) | ||
184 | sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); | 227 | sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); |
185 | 228 | ||
186 | /* | 229 | /* |
@@ -192,6 +235,8 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, | |||
192 | 235 | ||
193 | switch (new_state) { | 236 | switch (new_state) { |
194 | case SF_UNINIT: | 237 | case SF_UNINIT: |
238 | if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 13) | ||
239 | iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL); | ||
195 | break; | 240 | break; |
196 | case SF_FULL_ON: | 241 | case SF_FULL_ON: |
197 | if (sta_id == IWL_MVM_STATION_COUNT) { | 242 | if (sta_id == IWL_MVM_STATION_COUNT) { |
@@ -206,11 +251,11 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, | |||
206 | rcu_read_unlock(); | 251 | rcu_read_unlock(); |
207 | return -EINVAL; | 252 | return -EINVAL; |
208 | } | 253 | } |
209 | iwl_mvm_fill_sf_command(&sf_cmd, sta); | 254 | iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta); |
210 | rcu_read_unlock(); | 255 | rcu_read_unlock(); |
211 | break; | 256 | break; |
212 | case SF_INIT_OFF: | 257 | case SF_INIT_OFF: |
213 | iwl_mvm_fill_sf_command(&sf_cmd, NULL); | 258 | iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL); |
214 | break; | 259 | break; |
215 | default: | 260 | default: |
216 | WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n", | 261 | WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n", |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 5c23cddaaae3..50f9288368af 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -273,7 +273,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
273 | else | 273 | else |
274 | sta_id = mvm_sta->sta_id; | 274 | sta_id = mvm_sta->sta_id; |
275 | 275 | ||
276 | if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) | 276 | if (sta_id == IWL_MVM_STATION_COUNT) |
277 | return -ENOSPC; | 277 | return -ENOSPC; |
278 | 278 | ||
279 | spin_lock_init(&mvm_sta->lock); | 279 | spin_lock_init(&mvm_sta->lock); |
@@ -1681,9 +1681,6 @@ void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, | |||
1681 | }; | 1681 | }; |
1682 | int ret; | 1682 | int ret; |
1683 | 1683 | ||
1684 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_DISABLE_STA_TX)) | ||
1685 | return; | ||
1686 | |||
1687 | ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); | 1684 | ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); |
1688 | if (ret) | 1685 | if (ret) |
1689 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); | 1686 | IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 54fafbf9a711..8d179ab67cc2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -197,6 +197,8 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm, | |||
197 | struct iwl_time_event_notif *notif) | 197 | struct iwl_time_event_notif *notif) |
198 | { | 198 | { |
199 | if (!le32_to_cpu(notif->status)) { | 199 | if (!le32_to_cpu(notif->status)) { |
200 | if (te_data->vif->type == NL80211_IFTYPE_STATION) | ||
201 | ieee80211_connection_loss(te_data->vif); | ||
200 | IWL_DEBUG_TE(mvm, "CSA time event failed to start\n"); | 202 | IWL_DEBUG_TE(mvm, "CSA time event failed to start\n"); |
201 | iwl_mvm_te_clear_data(mvm, te_data); | 203 | iwl_mvm_te_clear_data(mvm, te_data); |
202 | return; | 204 | return; |
@@ -261,17 +263,23 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
261 | "TE ended - current time %lu, estimated end %lu\n", | 263 | "TE ended - current time %lu, estimated end %lu\n", |
262 | jiffies, te_data->end_jiffies); | 264 | jiffies, te_data->end_jiffies); |
263 | 265 | ||
264 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 266 | switch (te_data->vif->type) { |
267 | case NL80211_IFTYPE_P2P_DEVICE: | ||
265 | ieee80211_remain_on_channel_expired(mvm->hw); | 268 | ieee80211_remain_on_channel_expired(mvm->hw); |
266 | iwl_mvm_roc_finished(mvm); | 269 | iwl_mvm_roc_finished(mvm); |
270 | break; | ||
271 | case NL80211_IFTYPE_STATION: | ||
272 | /* | ||
273 | * By now, we should have finished association | ||
274 | * and know the dtim period. | ||
275 | */ | ||
276 | iwl_mvm_te_check_disconnect(mvm, te_data->vif, | ||
277 | "No association and the time event is over already..."); | ||
278 | break; | ||
279 | default: | ||
280 | break; | ||
267 | } | 281 | } |
268 | 282 | ||
269 | /* | ||
270 | * By now, we should have finished association | ||
271 | * and know the dtim period. | ||
272 | */ | ||
273 | iwl_mvm_te_check_disconnect(mvm, te_data->vif, | ||
274 | "No association and the time event is over already..."); | ||
275 | iwl_mvm_te_clear_data(mvm, te_data); | 283 | iwl_mvm_te_clear_data(mvm, te_data); |
276 | } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) { | 284 | } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) { |
277 | te_data->running = true; | 285 | te_data->running = true; |
@@ -750,8 +758,7 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm) | |||
750 | * request | 758 | * request |
751 | */ | 759 | */ |
752 | list_for_each_entry(te_data, &mvm->time_event_list, list) { | 760 | list_for_each_entry(te_data, &mvm->time_event_list, list) { |
753 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE && | 761 | if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { |
754 | te_data->running) { | ||
755 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); | 762 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); |
756 | is_p2p = true; | 763 | is_p2p = true; |
757 | goto remove_te; | 764 | goto remove_te; |
@@ -766,10 +773,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm) | |||
766 | * request | 773 | * request |
767 | */ | 774 | */ |
768 | list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) { | 775 | list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) { |
769 | if (te_data->running) { | 776 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); |
770 | mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); | 777 | goto remove_te; |
771 | goto remove_te; | ||
772 | } | ||
773 | } | 778 | } |
774 | 779 | ||
775 | remove_te: | 780 | remove_te: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 2b9de63951e6..435faee0a28e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
@@ -857,7 +857,7 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
857 | 857 | ||
858 | mvmvif->low_latency = value; | 858 | mvmvif->low_latency = value; |
859 | 859 | ||
860 | res = iwl_mvm_update_quotas(mvm, NULL); | 860 | res = iwl_mvm_update_quotas(mvm, false, NULL); |
861 | if (res) | 861 | if (res) |
862 | return res; | 862 | return res; |
863 | 863 | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index dbd6bcf52205..2794cd2d3a64 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c | |||
@@ -413,10 +413,35 @@ static const struct pci_device_id iwl_hw_card_ids[] = { | |||
413 | 413 | ||
414 | /* 8000 Series */ | 414 | /* 8000 Series */ |
415 | {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, | 415 | {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, |
416 | {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, | 416 | {IWL_PCI_DEVICE(0x24F3, 0x1010, iwl8260_2ac_cfg)}, |
417 | {IWL_PCI_DEVICE(0x24F3, 0x0110, iwl8260_2ac_cfg)}, | ||
418 | {IWL_PCI_DEVICE(0x24F3, 0x1110, iwl8260_2ac_cfg)}, | ||
419 | {IWL_PCI_DEVICE(0x24F3, 0x0050, iwl8260_2ac_cfg)}, | ||
420 | {IWL_PCI_DEVICE(0x24F3, 0x0250, iwl8260_2ac_cfg)}, | ||
421 | {IWL_PCI_DEVICE(0x24F3, 0x1050, iwl8260_2ac_cfg)}, | ||
422 | {IWL_PCI_DEVICE(0x24F3, 0x0150, iwl8260_2ac_cfg)}, | ||
417 | {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, | 423 | {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, |
424 | {IWL_PCI_DEVICE(0x24F4, 0x1130, iwl8260_2ac_cfg)}, | ||
425 | {IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)}, | ||
426 | {IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)}, | ||
427 | {IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)}, | ||
428 | {IWL_PCI_DEVICE(0x24F4, 0xC030, iwl8260_2ac_cfg)}, | ||
429 | {IWL_PCI_DEVICE(0x24F4, 0xD030, iwl8260_2ac_cfg)}, | ||
430 | {IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)}, | ||
431 | {IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)}, | ||
432 | {IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)}, | ||
433 | {IWL_PCI_DEVICE(0x24F3, 0x9010, iwl8260_2ac_cfg)}, | ||
434 | {IWL_PCI_DEVICE(0x24F4, 0x8030, iwl8260_2ac_cfg)}, | ||
435 | {IWL_PCI_DEVICE(0x24F4, 0x9030, iwl8260_2ac_cfg)}, | ||
436 | {IWL_PCI_DEVICE(0x24F3, 0x8050, iwl8260_2ac_cfg)}, | ||
437 | {IWL_PCI_DEVICE(0x24F3, 0x9050, iwl8260_2ac_cfg)}, | ||
438 | {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, | ||
418 | {IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)}, | 439 | {IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)}, |
419 | {IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)}, | 440 | {IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)}, |
441 | {IWL_PCI_DEVICE(0x24F3, 0x0810, iwl8260_2ac_cfg)}, | ||
442 | {IWL_PCI_DEVICE(0x24F3, 0x0910, iwl8260_2ac_cfg)}, | ||
443 | {IWL_PCI_DEVICE(0x24F3, 0x0850, iwl8260_2ac_cfg)}, | ||
444 | {IWL_PCI_DEVICE(0x24F3, 0x0950, iwl8260_2ac_cfg)}, | ||
420 | #endif /* CONFIG_IWLMVM */ | 445 | #endif /* CONFIG_IWLMVM */ |
421 | 446 | ||
422 | {0} | 447 | {0} |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index cae0eb8835ce..01996c9d98a7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -217,6 +217,8 @@ struct iwl_pcie_txq_scratch_buf { | |||
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 | * @wd_timeout: queue watchdog timeout (jiffies) - per queue |
220 | * @frozen: tx stuck queue timer is frozen | ||
221 | * @frozen_expiry_remainder: remember how long until the timer fires | ||
220 | * | 222 | * |
221 | * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame | 223 | * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame |
222 | * descriptors) and required locking structures. | 224 | * descriptors) and required locking structures. |
@@ -228,9 +230,11 @@ struct iwl_txq { | |||
228 | dma_addr_t scratchbufs_dma; | 230 | dma_addr_t scratchbufs_dma; |
229 | struct iwl_pcie_txq_entry *entries; | 231 | struct iwl_pcie_txq_entry *entries; |
230 | spinlock_t lock; | 232 | spinlock_t lock; |
233 | unsigned long frozen_expiry_remainder; | ||
231 | struct timer_list stuck_timer; | 234 | struct timer_list stuck_timer; |
232 | struct iwl_trans_pcie *trans_pcie; | 235 | struct iwl_trans_pcie *trans_pcie; |
233 | bool need_update; | 236 | bool need_update; |
237 | bool frozen; | ||
234 | u8 active; | 238 | u8 active; |
235 | bool ampdu; | 239 | bool ampdu; |
236 | unsigned long wd_timeout; | 240 | unsigned long wd_timeout; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index f31a94160771..dc247325d8d7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -682,6 +682,43 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, | |||
682 | return ret; | 682 | return ret; |
683 | } | 683 | } |
684 | 684 | ||
685 | /* | ||
686 | * Driver Takes the ownership on secure machine before FW load | ||
687 | * and prevent race with the BT load. | ||
688 | * W/A for ROM bug. (should be remove in the next Si step) | ||
689 | */ | ||
690 | static int iwl_pcie_rsa_race_bug_wa(struct iwl_trans *trans) | ||
691 | { | ||
692 | u32 val, loop = 1000; | ||
693 | |||
694 | /* Check the RSA semaphore is accessible - if not, we are in trouble */ | ||
695 | val = iwl_read_prph(trans, PREG_AUX_BUS_WPROT_0); | ||
696 | if (val & (BIT(1) | BIT(17))) { | ||
697 | IWL_ERR(trans, | ||
698 | "can't access the RSA semaphore it is write protected\n"); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | /* take ownership on the AUX IF */ | ||
703 | iwl_write_prph(trans, WFPM_CTRL_REG, WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK); | ||
704 | iwl_write_prph(trans, AUX_MISC_MASTER1_EN, AUX_MISC_MASTER1_EN_SBE_MSK); | ||
705 | |||
706 | do { | ||
707 | iwl_write_prph(trans, AUX_MISC_MASTER1_SMPHR_STATUS, 0x1); | ||
708 | val = iwl_read_prph(trans, AUX_MISC_MASTER1_SMPHR_STATUS); | ||
709 | if (val == 0x1) { | ||
710 | iwl_write_prph(trans, RSA_ENABLE, 0); | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | udelay(10); | ||
715 | loop--; | ||
716 | } while (loop > 0); | ||
717 | |||
718 | IWL_ERR(trans, "Failed to take ownership on secure machine\n"); | ||
719 | return -EIO; | ||
720 | } | ||
721 | |||
685 | static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans, | 722 | static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans, |
686 | const struct fw_img *image, | 723 | const struct fw_img *image, |
687 | int cpu, | 724 | int cpu, |
@@ -901,6 +938,11 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, | |||
901 | if (trans->dbg_dest_tlv) | 938 | if (trans->dbg_dest_tlv) |
902 | iwl_pcie_apply_destination(trans); | 939 | iwl_pcie_apply_destination(trans); |
903 | 940 | ||
941 | /* TODO: remove in the next Si step */ | ||
942 | ret = iwl_pcie_rsa_race_bug_wa(trans); | ||
943 | if (ret) | ||
944 | return ret; | ||
945 | |||
904 | /* configure the ucode to be ready to get the secured image */ | 946 | /* configure the ucode to be ready to get the secured image */ |
905 | /* release CPU reset */ | 947 | /* release CPU reset */ |
906 | iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); | 948 | iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); |
@@ -1462,6 +1504,60 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, | |||
1462 | return ret; | 1504 | return ret; |
1463 | } | 1505 | } |
1464 | 1506 | ||
1507 | static void iwl_trans_pcie_freeze_txq_timer(struct iwl_trans *trans, | ||
1508 | unsigned long txqs, | ||
1509 | bool freeze) | ||
1510 | { | ||
1511 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
1512 | int queue; | ||
1513 | |||
1514 | for_each_set_bit(queue, &txqs, BITS_PER_LONG) { | ||
1515 | struct iwl_txq *txq = &trans_pcie->txq[queue]; | ||
1516 | unsigned long now; | ||
1517 | |||
1518 | spin_lock_bh(&txq->lock); | ||
1519 | |||
1520 | now = jiffies; | ||
1521 | |||
1522 | if (txq->frozen == freeze) | ||
1523 | goto next_queue; | ||
1524 | |||
1525 | IWL_DEBUG_TX_QUEUES(trans, "%s TXQ %d\n", | ||
1526 | freeze ? "Freezing" : "Waking", queue); | ||
1527 | |||
1528 | txq->frozen = freeze; | ||
1529 | |||
1530 | if (txq->q.read_ptr == txq->q.write_ptr) | ||
1531 | goto next_queue; | ||
1532 | |||
1533 | if (freeze) { | ||
1534 | if (unlikely(time_after(now, | ||
1535 | txq->stuck_timer.expires))) { | ||
1536 | /* | ||
1537 | * The timer should have fired, maybe it is | ||
1538 | * spinning right now on the lock. | ||
1539 | */ | ||
1540 | goto next_queue; | ||
1541 | } | ||
1542 | /* remember how long until the timer fires */ | ||
1543 | txq->frozen_expiry_remainder = | ||
1544 | txq->stuck_timer.expires - now; | ||
1545 | del_timer(&txq->stuck_timer); | ||
1546 | goto next_queue; | ||
1547 | } | ||
1548 | |||
1549 | /* | ||
1550 | * Wake a non-empty queue -> arm timer with the | ||
1551 | * remainder before it froze | ||
1552 | */ | ||
1553 | mod_timer(&txq->stuck_timer, | ||
1554 | now + txq->frozen_expiry_remainder); | ||
1555 | |||
1556 | next_queue: | ||
1557 | spin_unlock_bh(&txq->lock); | ||
1558 | } | ||
1559 | } | ||
1560 | |||
1465 | #define IWL_FLUSH_WAIT_MS 2000 | 1561 | #define IWL_FLUSH_WAIT_MS 2000 |
1466 | 1562 | ||
1467 | static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) | 1563 | static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) |
@@ -1713,7 +1809,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, | |||
1713 | int ret; | 1809 | int ret; |
1714 | size_t bufsz; | 1810 | size_t bufsz; |
1715 | 1811 | ||
1716 | bufsz = sizeof(char) * 64 * trans->cfg->base_params->num_of_queues; | 1812 | bufsz = sizeof(char) * 75 * trans->cfg->base_params->num_of_queues; |
1717 | 1813 | ||
1718 | if (!trans_pcie->txq) | 1814 | if (!trans_pcie->txq) |
1719 | return -EAGAIN; | 1815 | return -EAGAIN; |
@@ -1726,11 +1822,11 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, | |||
1726 | txq = &trans_pcie->txq[cnt]; | 1822 | txq = &trans_pcie->txq[cnt]; |
1727 | q = &txq->q; | 1823 | q = &txq->q; |
1728 | pos += scnprintf(buf + pos, bufsz - pos, | 1824 | pos += scnprintf(buf + pos, bufsz - pos, |
1729 | "hwq %.2d: read=%u write=%u use=%d stop=%d need_update=%d%s\n", | 1825 | "hwq %.2d: read=%u write=%u use=%d stop=%d need_update=%d frozen=%d%s\n", |
1730 | cnt, q->read_ptr, q->write_ptr, | 1826 | cnt, q->read_ptr, q->write_ptr, |
1731 | !!test_bit(cnt, trans_pcie->queue_used), | 1827 | !!test_bit(cnt, trans_pcie->queue_used), |
1732 | !!test_bit(cnt, trans_pcie->queue_stopped), | 1828 | !!test_bit(cnt, trans_pcie->queue_stopped), |
1733 | txq->need_update, | 1829 | txq->need_update, txq->frozen, |
1734 | (cnt == trans_pcie->cmd_queue ? " HCMD" : "")); | 1830 | (cnt == trans_pcie->cmd_queue ? " HCMD" : "")); |
1735 | } | 1831 | } |
1736 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 1832 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
@@ -1961,24 +2057,25 @@ static const struct { | |||
1961 | { .start = 0x00a01c7c, .end = 0x00a01c7c }, | 2057 | { .start = 0x00a01c7c, .end = 0x00a01c7c }, |
1962 | { .start = 0x00a01c28, .end = 0x00a01c54 }, | 2058 | { .start = 0x00a01c28, .end = 0x00a01c54 }, |
1963 | { .start = 0x00a01c5c, .end = 0x00a01c5c }, | 2059 | { .start = 0x00a01c5c, .end = 0x00a01c5c }, |
1964 | { .start = 0x00a01c84, .end = 0x00a01c84 }, | 2060 | { .start = 0x00a01c60, .end = 0x00a01cdc }, |
1965 | { .start = 0x00a01ce0, .end = 0x00a01d0c }, | 2061 | { .start = 0x00a01ce0, .end = 0x00a01d0c }, |
1966 | { .start = 0x00a01d18, .end = 0x00a01d20 }, | 2062 | { .start = 0x00a01d18, .end = 0x00a01d20 }, |
1967 | { .start = 0x00a01d2c, .end = 0x00a01d30 }, | 2063 | { .start = 0x00a01d2c, .end = 0x00a01d30 }, |
1968 | { .start = 0x00a01d40, .end = 0x00a01d5c }, | 2064 | { .start = 0x00a01d40, .end = 0x00a01d5c }, |
1969 | { .start = 0x00a01d80, .end = 0x00a01d80 }, | 2065 | { .start = 0x00a01d80, .end = 0x00a01d80 }, |
1970 | { .start = 0x00a01d98, .end = 0x00a01d98 }, | 2066 | { .start = 0x00a01d98, .end = 0x00a01d9c }, |
2067 | { .start = 0x00a01da8, .end = 0x00a01da8 }, | ||
2068 | { .start = 0x00a01db8, .end = 0x00a01df4 }, | ||
1971 | { .start = 0x00a01dc0, .end = 0x00a01dfc }, | 2069 | { .start = 0x00a01dc0, .end = 0x00a01dfc }, |
1972 | { .start = 0x00a01e00, .end = 0x00a01e2c }, | 2070 | { .start = 0x00a01e00, .end = 0x00a01e2c }, |
1973 | { .start = 0x00a01e40, .end = 0x00a01e60 }, | 2071 | { .start = 0x00a01e40, .end = 0x00a01e60 }, |
2072 | { .start = 0x00a01e68, .end = 0x00a01e6c }, | ||
2073 | { .start = 0x00a01e74, .end = 0x00a01e74 }, | ||
1974 | { .start = 0x00a01e84, .end = 0x00a01e90 }, | 2074 | { .start = 0x00a01e84, .end = 0x00a01e90 }, |
1975 | { .start = 0x00a01e9c, .end = 0x00a01ec4 }, | 2075 | { .start = 0x00a01e9c, .end = 0x00a01ec4 }, |
1976 | { .start = 0x00a01ed0, .end = 0x00a01ed0 }, | 2076 | { .start = 0x00a01ed0, .end = 0x00a01ee0 }, |
1977 | { .start = 0x00a01f00, .end = 0x00a01f14 }, | 2077 | { .start = 0x00a01f00, .end = 0x00a01f1c }, |
1978 | { .start = 0x00a01f44, .end = 0x00a01f58 }, | 2078 | { .start = 0x00a01f44, .end = 0x00a01ffc }, |
1979 | { .start = 0x00a01f80, .end = 0x00a01fa8 }, | ||
1980 | { .start = 0x00a01fb0, .end = 0x00a01fbc }, | ||
1981 | { .start = 0x00a01ff8, .end = 0x00a01ffc }, | ||
1982 | { .start = 0x00a02000, .end = 0x00a02048 }, | 2079 | { .start = 0x00a02000, .end = 0x00a02048 }, |
1983 | { .start = 0x00a02068, .end = 0x00a020f0 }, | 2080 | { .start = 0x00a02068, .end = 0x00a020f0 }, |
1984 | { .start = 0x00a02100, .end = 0x00a02118 }, | 2081 | { .start = 0x00a02100, .end = 0x00a02118 }, |
@@ -2305,6 +2402,7 @@ static const struct iwl_trans_ops trans_ops_pcie = { | |||
2305 | .dbgfs_register = iwl_trans_pcie_dbgfs_register, | 2402 | .dbgfs_register = iwl_trans_pcie_dbgfs_register, |
2306 | 2403 | ||
2307 | .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty, | 2404 | .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty, |
2405 | .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, | ||
2308 | 2406 | ||
2309 | .write8 = iwl_trans_pcie_write8, | 2407 | .write8 = iwl_trans_pcie_write8, |
2310 | .write32 = iwl_trans_pcie_write32, | 2408 | .write32 = iwl_trans_pcie_write32, |
@@ -2423,10 +2521,45 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
2423 | * "dash" value). To keep hw_rev backwards compatible - we'll store it | 2521 | * "dash" value). To keep hw_rev backwards compatible - we'll store it |
2424 | * in the old format. | 2522 | * in the old format. |
2425 | */ | 2523 | */ |
2426 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | 2524 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { |
2525 | unsigned long flags; | ||
2526 | int ret; | ||
2527 | |||
2427 | trans->hw_rev = (trans->hw_rev & 0xfff0) | | 2528 | trans->hw_rev = (trans->hw_rev & 0xfff0) | |
2428 | (CSR_HW_REV_STEP(trans->hw_rev << 2) << 2); | 2529 | (CSR_HW_REV_STEP(trans->hw_rev << 2) << 2); |
2429 | 2530 | ||
2531 | /* | ||
2532 | * in-order to recognize C step driver should read chip version | ||
2533 | * id located at the AUX bus MISC address space. | ||
2534 | */ | ||
2535 | iwl_set_bit(trans, CSR_GP_CNTRL, | ||
2536 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | ||
2537 | udelay(2); | ||
2538 | |||
2539 | ret = iwl_poll_bit(trans, CSR_GP_CNTRL, | ||
2540 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | ||
2541 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | ||
2542 | 25000); | ||
2543 | if (ret < 0) { | ||
2544 | IWL_DEBUG_INFO(trans, "Failed to wake up the nic\n"); | ||
2545 | goto out_pci_disable_msi; | ||
2546 | } | ||
2547 | |||
2548 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { | ||
2549 | u32 hw_step; | ||
2550 | |||
2551 | hw_step = __iwl_read_prph(trans, WFPM_CTRL_REG); | ||
2552 | hw_step |= ENABLE_WFPM; | ||
2553 | __iwl_write_prph(trans, WFPM_CTRL_REG, hw_step); | ||
2554 | hw_step = __iwl_read_prph(trans, AUX_MISC_REG); | ||
2555 | hw_step = (hw_step >> HW_STEP_LOCATION_BITS) & 0xF; | ||
2556 | if (hw_step == 0x3) | ||
2557 | trans->hw_rev = (trans->hw_rev & 0xFFFFFFF3) | | ||
2558 | (SILICON_C_STEP << 2); | ||
2559 | iwl_trans_release_nic_access(trans, &flags); | ||
2560 | } | ||
2561 | } | ||
2562 | |||
2430 | trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; | 2563 | trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; |
2431 | snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), | 2564 | snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), |
2432 | "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device); | 2565 | "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device); |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index af0bce736358..06952aadfd7b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -725,33 +725,50 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) | |||
725 | iwl_pcie_tx_start(trans, 0); | 725 | iwl_pcie_tx_start(trans, 0); |
726 | } | 726 | } |
727 | 727 | ||
728 | static void iwl_pcie_tx_stop_fh(struct iwl_trans *trans) | ||
729 | { | ||
730 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | ||
731 | unsigned long flags; | ||
732 | int ch, ret; | ||
733 | u32 mask = 0; | ||
734 | |||
735 | spin_lock(&trans_pcie->irq_lock); | ||
736 | |||
737 | if (!iwl_trans_grab_nic_access(trans, false, &flags)) | ||
738 | goto out; | ||
739 | |||
740 | /* Stop each Tx DMA channel */ | ||
741 | for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { | ||
742 | iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); | ||
743 | mask |= FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch); | ||
744 | } | ||
745 | |||
746 | /* Wait for DMA channels to be idle */ | ||
747 | ret = iwl_poll_bit(trans, FH_TSSR_TX_STATUS_REG, mask, mask, 5000); | ||
748 | if (ret < 0) | ||
749 | IWL_ERR(trans, | ||
750 | "Failing on timeout while stopping DMA channel %d [0x%08x]\n", | ||
751 | ch, iwl_read32(trans, FH_TSSR_TX_STATUS_REG)); | ||
752 | |||
753 | iwl_trans_release_nic_access(trans, &flags); | ||
754 | |||
755 | out: | ||
756 | spin_unlock(&trans_pcie->irq_lock); | ||
757 | } | ||
758 | |||
728 | /* | 759 | /* |
729 | * iwl_pcie_tx_stop - Stop all Tx DMA channels | 760 | * iwl_pcie_tx_stop - Stop all Tx DMA channels |
730 | */ | 761 | */ |
731 | int iwl_pcie_tx_stop(struct iwl_trans *trans) | 762 | int iwl_pcie_tx_stop(struct iwl_trans *trans) |
732 | { | 763 | { |
733 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 764 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
734 | int ch, txq_id, ret; | 765 | int txq_id; |
735 | 766 | ||
736 | /* Turn off all Tx DMA fifos */ | 767 | /* Turn off all Tx DMA fifos */ |
737 | spin_lock(&trans_pcie->irq_lock); | ||
738 | |||
739 | iwl_scd_deactivate_fifos(trans); | 768 | iwl_scd_deactivate_fifos(trans); |
740 | 769 | ||
741 | /* Stop each Tx DMA channel, and wait for it to be idle */ | 770 | /* Turn off all Tx DMA channels */ |
742 | for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { | 771 | iwl_pcie_tx_stop_fh(trans); |
743 | iwl_write_direct32(trans, | ||
744 | FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); | ||
745 | ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG, | ||
746 | FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000); | ||
747 | if (ret < 0) | ||
748 | IWL_ERR(trans, | ||
749 | "Failing on timeout while stopping DMA channel %d [0x%08x]\n", | ||
750 | ch, | ||
751 | iwl_read_direct32(trans, | ||
752 | FH_TSSR_TX_STATUS_REG)); | ||
753 | } | ||
754 | spin_unlock(&trans_pcie->irq_lock); | ||
755 | 772 | ||
756 | /* | 773 | /* |
757 | * This function can be called before the op_mode disabled the | 774 | * This function can be called before the op_mode disabled the |
@@ -912,10 +929,19 @@ error: | |||
912 | 929 | ||
913 | static inline void iwl_pcie_txq_progress(struct iwl_txq *txq) | 930 | static inline void iwl_pcie_txq_progress(struct iwl_txq *txq) |
914 | { | 931 | { |
932 | lockdep_assert_held(&txq->lock); | ||
933 | |||
915 | if (!txq->wd_timeout) | 934 | if (!txq->wd_timeout) |
916 | return; | 935 | return; |
917 | 936 | ||
918 | /* | 937 | /* |
938 | * station is asleep and we send data - that must | ||
939 | * be uAPSD or PS-Poll. Don't rearm the timer. | ||
940 | */ | ||
941 | if (txq->frozen) | ||
942 | return; | ||
943 | |||
944 | /* | ||
919 | * if empty delete timer, otherwise move timer forward | 945 | * if empty delete timer, otherwise move timer forward |
920 | * since we're making progress on this queue | 946 | * since we're making progress on this queue |
921 | */ | 947 | */ |
@@ -1248,6 +1274,9 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, | |||
1248 | SCD_TX_STTS_QUEUE_OFFSET(txq_id); | 1274 | SCD_TX_STTS_QUEUE_OFFSET(txq_id); |
1249 | static const u32 zero_val[4] = {}; | 1275 | static const u32 zero_val[4] = {}; |
1250 | 1276 | ||
1277 | trans_pcie->txq[txq_id].frozen_expiry_remainder = 0; | ||
1278 | trans_pcie->txq[txq_id].frozen = false; | ||
1279 | |||
1251 | /* | 1280 | /* |
1252 | * Upon HW Rfkill - we stop the device, and then stop the queues | 1281 | * Upon HW Rfkill - we stop the device, and then stop the queues |
1253 | * in the op_mode. Just for the sake of the simplicity of the op_mode, | 1282 | * in the op_mode. Just for the sake of the simplicity of the op_mode, |