diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-08-02 15:37:34 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-08-02 15:37:34 -0400 |
commit | 204162296edf0d0ac3e4dfd5bd0cac4af731b583 (patch) | |
tree | fdf941fd23fae6097500db4998d4ca96467fc352 /drivers/net/wireless/iwlwifi/mvm/bt-coex.c | |
parent | e3d5291436ff9efeeb968459724af5332305dded (diff) | |
parent | 147fc9be81d10e6e863323c0b54e140b42fd1ed6 (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/bt-coex.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/bt-coex.c | 162 |
1 files changed, 98 insertions, 64 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index dbd622a3929c..0fad98b85f60 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c | |||
@@ -220,66 +220,87 @@ static const __le32 iwl_single_shared_ant_lookup[BT_COEX_LUT_SIZE] = { | |||
220 | 220 | ||
221 | int iwl_send_bt_init_conf(struct iwl_mvm *mvm) | 221 | int iwl_send_bt_init_conf(struct iwl_mvm *mvm) |
222 | { | 222 | { |
223 | struct iwl_bt_coex_cmd cmd = { | 223 | struct iwl_bt_coex_cmd *bt_cmd; |
224 | .max_kill = 5, | 224 | struct iwl_host_cmd cmd = { |
225 | .bt3_time_t7_value = 1, | 225 | .id = BT_CONFIG, |
226 | .bt3_prio_sample_time = 2, | 226 | .len = { sizeof(*bt_cmd), }, |
227 | .bt3_timer_t2_value = 0xc, | 227 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
228 | .flags = CMD_SYNC, | ||
228 | }; | 229 | }; |
229 | int ret; | 230 | int ret; |
230 | 231 | ||
231 | cmd.flags = iwlwifi_mod_params.bt_coex_active ? | 232 | /* go to CALIB state in internal BT-Coex state machine */ |
233 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN, | ||
234 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
235 | if (ret) | ||
236 | return ret; | ||
237 | |||
238 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE, | ||
239 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
240 | if (ret) | ||
241 | return ret; | ||
242 | |||
243 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); | ||
244 | if (!bt_cmd) | ||
245 | return -ENOMEM; | ||
246 | cmd.data[0] = bt_cmd; | ||
247 | |||
248 | bt_cmd->max_kill = 5; | ||
249 | bt_cmd->bt3_time_t7_value = 1; | ||
250 | bt_cmd->bt3_prio_sample_time = 2; | ||
251 | bt_cmd->bt3_timer_t2_value = 0xc; | ||
252 | |||
253 | bt_cmd->flags = iwlwifi_mod_params.bt_coex_active ? | ||
232 | BT_COEX_NW : BT_COEX_DISABLE; | 254 | BT_COEX_NW : BT_COEX_DISABLE; |
233 | cmd.flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE; | 255 | bt_cmd->flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE; |
234 | 256 | ||
235 | cmd.valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE | | 257 | bt_cmd->valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE | |
236 | BT_VALID_BT_PRIO_BOOST | | 258 | BT_VALID_BT_PRIO_BOOST | |
237 | BT_VALID_MAX_KILL | | 259 | BT_VALID_MAX_KILL | |
238 | BT_VALID_3W_TMRS | | 260 | BT_VALID_3W_TMRS | |
239 | BT_VALID_KILL_ACK | | 261 | BT_VALID_KILL_ACK | |
240 | BT_VALID_KILL_CTS | | 262 | BT_VALID_KILL_CTS | |
241 | BT_VALID_REDUCED_TX_POWER | | 263 | BT_VALID_REDUCED_TX_POWER | |
242 | BT_VALID_LUT); | 264 | BT_VALID_LUT); |
243 | 265 | ||
244 | if (mvm->cfg->bt_shared_single_ant) | 266 | if (mvm->cfg->bt_shared_single_ant) |
245 | memcpy(&cmd.decision_lut, iwl_single_shared_ant_lookup, | 267 | memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant_lookup, |
246 | sizeof(iwl_single_shared_ant_lookup)); | 268 | sizeof(iwl_single_shared_ant_lookup)); |
247 | else if (is_loose_coex()) | 269 | else if (is_loose_coex()) |
248 | memcpy(&cmd.decision_lut, iwl_loose_lookup, | 270 | memcpy(&bt_cmd->decision_lut, iwl_loose_lookup, |
249 | sizeof(iwl_tight_lookup)); | 271 | sizeof(iwl_tight_lookup)); |
250 | else | 272 | else |
251 | memcpy(&cmd.decision_lut, iwl_tight_lookup, | 273 | memcpy(&bt_cmd->decision_lut, iwl_tight_lookup, |
252 | sizeof(iwl_tight_lookup)); | 274 | sizeof(iwl_tight_lookup)); |
253 | 275 | ||
254 | cmd.bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST); | 276 | bt_cmd->bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST); |
255 | cmd.kill_ack_msk = | 277 | bt_cmd->kill_ack_msk = |
256 | cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); | 278 | cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]); |
257 | cmd.kill_cts_msk = | 279 | bt_cmd->kill_cts_msk = |
258 | cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); | 280 | cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); |
259 | 281 | ||
260 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | 282 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); |
261 | 283 | ||
262 | /* go to CALIB state in internal BT-Coex state machine */ | 284 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
263 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN, | ||
264 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
265 | if (ret) | ||
266 | return ret; | ||
267 | |||
268 | ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE, | ||
269 | BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); | ||
270 | if (ret) | ||
271 | return ret; | ||
272 | 285 | ||
273 | return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, | 286 | kfree(bt_cmd); |
274 | sizeof(cmd), &cmd); | 287 | return ret; |
275 | } | 288 | } |
276 | 289 | ||
277 | static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | 290 | static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, |
278 | bool reduced_tx_power) | 291 | bool reduced_tx_power) |
279 | { | 292 | { |
280 | enum iwl_bt_kill_msk bt_kill_msk; | 293 | enum iwl_bt_kill_msk bt_kill_msk; |
281 | struct iwl_bt_coex_cmd cmd = {}; | 294 | struct iwl_bt_coex_cmd *bt_cmd; |
282 | struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; | 295 | struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; |
296 | struct iwl_host_cmd cmd = { | ||
297 | .id = BT_CONFIG, | ||
298 | .data[0] = &bt_cmd, | ||
299 | .len = { sizeof(*bt_cmd), }, | ||
300 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
301 | .flags = CMD_SYNC, | ||
302 | }; | ||
303 | int ret = 0; | ||
283 | 304 | ||
284 | lockdep_assert_held(&mvm->mutex); | 305 | lockdep_assert_held(&mvm->mutex); |
285 | 306 | ||
@@ -308,24 +329,40 @@ static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm, | |||
308 | return 0; | 329 | return 0; |
309 | 330 | ||
310 | mvm->bt_kill_msk = bt_kill_msk; | 331 | mvm->bt_kill_msk = bt_kill_msk; |
311 | cmd.kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); | 332 | |
312 | cmd.kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); | 333 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); |
313 | cmd.valid_bit_msk = cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS); | 334 | if (!bt_cmd) |
335 | return -ENOMEM; | ||
336 | cmd.data[0] = bt_cmd; | ||
337 | |||
338 | bt_cmd->kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); | ||
339 | bt_cmd->kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); | ||
340 | bt_cmd->valid_bit_msk = | ||
341 | cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS); | ||
314 | 342 | ||
315 | IWL_DEBUG_COEX(mvm, "bt_kill_msk = %d\n", bt_kill_msk); | 343 | IWL_DEBUG_COEX(mvm, "bt_kill_msk = %d\n", bt_kill_msk); |
316 | return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, | 344 | |
317 | sizeof(cmd), &cmd); | 345 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
346 | |||
347 | kfree(bt_cmd); | ||
348 | return ret; | ||
318 | } | 349 | } |
319 | 350 | ||
320 | static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | 351 | static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, |
321 | bool enable) | 352 | bool enable) |
322 | { | 353 | { |
323 | struct iwl_bt_coex_cmd cmd = { | 354 | struct iwl_bt_coex_cmd *bt_cmd; |
324 | .valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER), | 355 | /* Send ASYNC since this can be sent from an atomic context */ |
325 | .bt_reduced_tx_power = sta_id, | 356 | struct iwl_host_cmd cmd = { |
357 | .id = BT_CONFIG, | ||
358 | .len = { sizeof(*bt_cmd), }, | ||
359 | .dataflags = { IWL_HCMD_DFL_DUP, }, | ||
360 | .flags = CMD_ASYNC, | ||
326 | }; | 361 | }; |
362 | |||
327 | struct ieee80211_sta *sta; | 363 | struct ieee80211_sta *sta; |
328 | struct iwl_mvm_sta *mvmsta; | 364 | struct iwl_mvm_sta *mvmsta; |
365 | int ret; | ||
329 | 366 | ||
330 | /* This can happen if the station has been removed right now */ | 367 | /* This can happen if the station has been removed right now */ |
331 | if (sta_id == IWL_MVM_STATION_COUNT) | 368 | if (sta_id == IWL_MVM_STATION_COUNT) |
@@ -339,17 +376,26 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, | |||
339 | if (mvmsta->bt_reduced_txpower == enable) | 376 | if (mvmsta->bt_reduced_txpower == enable) |
340 | return 0; | 377 | return 0; |
341 | 378 | ||
379 | bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_ATOMIC); | ||
380 | if (!bt_cmd) | ||
381 | return -ENOMEM; | ||
382 | cmd.data[0] = bt_cmd; | ||
383 | |||
384 | bt_cmd->valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER), | ||
385 | bt_cmd->bt_reduced_tx_power = sta_id; | ||
386 | |||
342 | if (enable) | 387 | if (enable) |
343 | cmd.bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; | 388 | bt_cmd->bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT; |
344 | 389 | ||
345 | IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", | 390 | IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", |
346 | enable ? "en" : "dis", sta_id); | 391 | enable ? "en" : "dis", sta_id); |
347 | 392 | ||
348 | mvmsta->bt_reduced_txpower = enable; | 393 | mvmsta->bt_reduced_txpower = enable; |
349 | 394 | ||
350 | /* Send ASYNC since this can be sent from an atomic context */ | 395 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
351 | return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_ASYNC, | 396 | |
352 | sizeof(cmd), &cmd); | 397 | kfree(bt_cmd); |
398 | return ret; | ||
353 | } | 399 | } |
354 | 400 | ||
355 | struct iwl_bt_iterator_data { | 401 | struct iwl_bt_iterator_data { |
@@ -384,6 +430,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
384 | 430 | ||
385 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 431 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
386 | 432 | ||
433 | /* non associated BSSes aren't to be considered */ | ||
434 | if (!vif->bss_conf.assoc) | ||
435 | return; | ||
436 | |||
387 | if (band != IEEE80211_BAND_2GHZ) { | 437 | if (band != IEEE80211_BAND_2GHZ) { |
388 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, | 438 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, |
389 | smps_mode); | 439 | smps_mode); |
@@ -523,6 +573,8 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, | |||
523 | lockdep_is_held(&mvm->mutex)); | 573 | lockdep_is_held(&mvm->mutex)); |
524 | mvmsta = (void *)sta->drv_priv; | 574 | mvmsta = (void *)sta->drv_priv; |
525 | 575 | ||
576 | data->num_bss_ifaces++; | ||
577 | |||
526 | /* | 578 | /* |
527 | * This interface doesn't support reduced Tx power (because of low | 579 | * This interface doesn't support reduced Tx power (because of low |
528 | * RSSI probably), then set bt_kill_msk to default values. | 580 | * RSSI probably), then set bt_kill_msk to default values. |
@@ -588,23 +640,5 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
588 | 640 | ||
589 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 641 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
590 | { | 642 | { |
591 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
592 | enum ieee80211_band band; | ||
593 | |||
594 | rcu_read_lock(); | ||
595 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
596 | if (chanctx_conf && chanctx_conf->def.chan) | ||
597 | band = chanctx_conf->def.chan->band; | ||
598 | else | ||
599 | band = -1; | ||
600 | rcu_read_unlock(); | ||
601 | |||
602 | /* if we are in 2GHz we will get a notification from the fw */ | ||
603 | if (band == IEEE80211_BAND_2GHZ) | ||
604 | return; | ||
605 | |||
606 | /* else, we can remove all the constraints */ | ||
607 | memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); | ||
608 | |||
609 | iwl_mvm_bt_coex_notif_handle(mvm); | 643 | iwl_mvm_bt_coex_notif_handle(mvm); |
610 | } | 644 | } |