aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>2013-07-21 10:23:59 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-08-16 06:12:24 -0400
commita20fd398666dbf5cdee3fe97722350cc10619c84 (patch)
treea70433b643ebb44a00a611b1c297e901144435a4 /drivers/net/wireless
parenteafe25e0afaf45a4e38f9b3560ac774a2395c695 (diff)
iwlwifi: mvm: Implement CQM offloading
Use beacon statistics notification to track RSSI. Notify mac80211 when the tresholds are crossed. The roaming treshold is configured to be equal to cqm_thold. If the beacon filtering command is not supported by fw fall back and use mac80211 mechanism. Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c22
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h20
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/power.c37
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c61
6 files changed, 133 insertions, 11 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 14811a583d2b..c67b17aa7dfb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -920,7 +920,7 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file,
920 }; 920 };
921 921
922 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); 922 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
923 if (mvmvif->bf_enabled) 923 if (mvmvif->bf_data.bf_enabled)
924 cmd.bf_enable_beacon_filter = cpu_to_le32(1); 924 cmd.bf_enable_beacon_filter = cpu_to_le32(1);
925 else 925 else
926 cmd.bf_enable_beacon_filter = 0; 926 cmd.bf_enable_beacon_filter = 0;
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index b1047102ea47..66264cc5a016 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -1321,7 +1321,7 @@ struct mvm_statistics_general {
1321 struct mvm_statistics_general_common common; 1321 struct mvm_statistics_general_common common;
1322 __le32 beacon_filtered; 1322 __le32 beacon_filtered;
1323 __le32 missed_beacons; 1323 __le32 missed_beacons;
1324 __s8 beacon_filter_everage_energy; 1324 __s8 beacon_filter_average_energy;
1325 __s8 beacon_filter_reason; 1325 __s8 beacon_filter_reason;
1326 __s8 beacon_filter_current_energy; 1326 __s8 beacon_filter_current_energy;
1327 __s8 beacon_filter_reserved; 1327 __s8 beacon_filter_reserved;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 66803b99cca8..692d2ea211e8 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -575,7 +575,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
575 vif->type == NL80211_IFTYPE_STATION && !vif->p2p && 575 vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
576 mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED){ 576 mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BF_UPDATED){
577 mvm->bf_allowed_vif = mvmvif; 577 mvm->bf_allowed_vif = mvmvif;
578 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; 578 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
579 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
579 } 580 }
580 581
581 /* 582 /*
@@ -615,7 +616,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
615 out_free_bf: 616 out_free_bf:
616 if (mvm->bf_allowed_vif == mvmvif) { 617 if (mvm->bf_allowed_vif == mvmvif) {
617 mvm->bf_allowed_vif = NULL; 618 mvm->bf_allowed_vif = NULL;
618 vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; 619 vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
620 IEEE80211_VIF_SUPPORTS_CQM_RSSI);
619 } 621 }
620 out_remove_mac: 622 out_remove_mac:
621 mvmvif->phy_ctxt = NULL; 623 mvmvif->phy_ctxt = NULL;
@@ -681,7 +683,8 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
681 683
682 if (mvm->bf_allowed_vif == mvmvif) { 684 if (mvm->bf_allowed_vif == mvmvif) {
683 mvm->bf_allowed_vif = NULL; 685 mvm->bf_allowed_vif = NULL;
684 vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; 686 vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
687 IEEE80211_VIF_SUPPORTS_CQM_RSSI);
685 } 688 }
686 689
687 iwl_mvm_vif_dbgfs_clean(mvm, vif); 690 iwl_mvm_vif_dbgfs_clean(mvm, vif);
@@ -799,6 +802,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
799 if (ret) 802 if (ret)
800 IWL_ERR(mvm, "failed to update quotas\n"); 803 IWL_ERR(mvm, "failed to update quotas\n");
801 } 804 }
805
806 /* reset rssi values */
807 mvmvif->bf_data.ave_beacon_signal = 0;
808
802 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD)) { 809 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD)) {
803 /* Workaround for FW bug, otherwise FW disables device 810 /* Workaround for FW bug, otherwise FW disables device
804 * power save upon disassociation 811 * power save upon disassociation
@@ -825,6 +832,15 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
825 bss_conf->txpower); 832 bss_conf->txpower);
826 iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); 833 iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
827 } 834 }
835
836 if (changes & BSS_CHANGED_CQM) {
837 IWL_DEBUG_MAC80211(mvm, "cqm info_changed");
838 /* reset cqm events tracking */
839 mvmvif->bf_data.last_cqm_event = 0;
840 ret = iwl_mvm_update_beacon_filter(mvm, vif);
841 if (ret)
842 IWL_ERR(mvm, "failed to update CQM thresholds\n");
843 }
828} 844}
829 845
830static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 846static int iwl_mvm_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 014d77931c56..ee46dea69509 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -233,6 +233,21 @@ enum iwl_mvm_smps_type_request {
233}; 233};
234 234
235/** 235/**
236* struct iwl_mvm_vif_bf_data - beacon filtering related data
237* @bf_enabled: indicates if beacon filtering is enabled
238* @ba_enabled: indicated if beacon abort is enabled
239* @last_beacon_signal: last beacon rssi signal in dbm
240* @ave_beacon_signal: average beacon signal
241* @last_cqm_event: rssi of the last cqm event
242*/
243struct iwl_mvm_vif_bf_data {
244 bool bf_enabled;
245 bool ba_enabled;
246 s8 ave_beacon_signal;
247 s8 last_cqm_event;
248};
249
250/**
236 * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context 251 * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context
237 * @id: between 0 and 3 252 * @id: between 0 and 3
238 * @color: to solve races upon MAC addition and removal 253 * @color: to solve races upon MAC addition and removal
@@ -257,8 +272,7 @@ struct iwl_mvm_vif {
257 bool uploaded; 272 bool uploaded;
258 bool ap_active; 273 bool ap_active;
259 bool monitor_active; 274 bool monitor_active;
260 /* indicate whether beacon filtering is enabled */ 275 struct iwl_mvm_vif_bf_data bf_data;
261 bool bf_enabled;
262 276
263 u32 ap_beacon_time; 277 u32 ap_beacon_time;
264 278
@@ -758,6 +772,8 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
758 struct iwl_beacon_filter_cmd *cmd); 772 struct iwl_beacon_filter_cmd *cmd);
759int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, 773int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
760 struct ieee80211_vif *vif, bool enable); 774 struct ieee80211_vif *vif, bool enable);
775int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
776 struct ieee80211_vif *vif);
761 777
762/* SMPS */ 778/* SMPS */
763void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 779void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index 9c9b5bafb577..a5529b85de8b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -110,6 +110,23 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
110 return ret; 110 return ret;
111} 111}
112 112
113static
114void iwl_mvm_beacon_filter_set_cqm_params(struct iwl_mvm *mvm,
115 struct ieee80211_vif *vif,
116 struct iwl_beacon_filter_cmd *cmd)
117{
118 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
119
120 if (vif->bss_conf.cqm_rssi_thold) {
121 cmd->bf_energy_delta =
122 cpu_to_le32(vif->bss_conf.cqm_rssi_hyst);
123 /* fw uses an absolute value for this */
124 cmd->bf_roaming_state =
125 cpu_to_le32(-vif->bss_conf.cqm_rssi_thold);
126 }
127 cmd->ba_enable_beacon_abort = cpu_to_le32(mvmvif->bf_data.ba_enabled);
128}
129
113int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, 130int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
114 struct ieee80211_vif *vif, bool enable) 131 struct ieee80211_vif *vif, bool enable)
115{ 132{
@@ -120,12 +137,14 @@ int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
120 .ba_enable_beacon_abort = cpu_to_le32(enable), 137 .ba_enable_beacon_abort = cpu_to_le32(enable),
121 }; 138 };
122 139
123 if (!mvmvif->bf_enabled) 140 if (!mvmvif->bf_data.bf_enabled)
124 return 0; 141 return 0;
125 142
126 if (mvm->cur_ucode == IWL_UCODE_WOWLAN) 143 if (mvm->cur_ucode == IWL_UCODE_WOWLAN)
127 cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3); 144 cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3);
128 145
146 mvmvif->bf_data.ba_enabled = enable;
147 iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd);
129 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); 148 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
130 return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); 149 return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
131} 150}
@@ -510,11 +529,12 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
510 vif->type != NL80211_IFTYPE_STATION || vif->p2p) 529 vif->type != NL80211_IFTYPE_STATION || vif->p2p)
511 return 0; 530 return 0;
512 531
532 iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd);
513 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); 533 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
514 ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); 534 ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
515 535
516 if (!ret) 536 if (!ret)
517 mvmvif->bf_enabled = true; 537 mvmvif->bf_data.bf_enabled = true;
518 538
519 return ret; 539 return ret;
520} 540}
@@ -533,11 +553,22 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
533 ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); 553 ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd);
534 554
535 if (!ret) 555 if (!ret)
536 mvmvif->bf_enabled = false; 556 mvmvif->bf_data.bf_enabled = false;
537 557
538 return ret; 558 return ret;
539} 559}
540 560
561int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
562 struct ieee80211_vif *vif)
563{
564 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
565
566 if (!mvmvif->bf_data.bf_enabled)
567 return 0;
568
569 return iwl_mvm_enable_beacon_filter(mvm, vif);
570}
571
541const struct iwl_mvm_power_ops pm_mac_ops = { 572const struct iwl_mvm_power_ops pm_mac_ops = {
542 .power_update_mode = iwl_mvm_power_mac_update_mode, 573 .power_update_mode = iwl_mvm_power_mac_update_mode,
543 .power_disable = iwl_mvm_power_mac_disable, 574 .power_disable = iwl_mvm_power_mac_disable,
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index ee6547d22287..2a8cb5a60535 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -396,11 +396,62 @@ static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm,
396 memcpy(&mvm->rx_stats, &stats->rx, sizeof(struct mvm_statistics_rx)); 396 memcpy(&mvm->rx_stats, &stats->rx, sizeof(struct mvm_statistics_rx));
397} 397}
398 398
399struct iwl_mvm_stat_data {
400 struct iwl_notif_statistics *stats;
401 struct iwl_mvm *mvm;
402};
403
404static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
405 struct ieee80211_vif *vif)
406{
407 struct iwl_mvm_stat_data *data = _data;
408 struct iwl_notif_statistics *stats = data->stats;
409 struct iwl_mvm *mvm = data->mvm;
410 int sig = -stats->general.beacon_filter_average_energy;
411 int last_event;
412 int thold = vif->bss_conf.cqm_rssi_thold;
413 int hyst = vif->bss_conf.cqm_rssi_hyst;
414 u16 id = le32_to_cpu(stats->rx.general.mac_id);
415 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
416
417 if (mvmvif->id != id)
418 return;
419
420 if (vif->type != NL80211_IFTYPE_STATION)
421 return;
422
423 mvmvif->bf_data.ave_beacon_signal = sig;
424
425 if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI))
426 return;
427
428 /* CQM Notification */
429 last_event = mvmvif->bf_data.last_cqm_event;
430 if (thold && sig < thold && (last_event == 0 ||
431 sig < last_event - hyst)) {
432 mvmvif->bf_data.last_cqm_event = sig;
433 IWL_DEBUG_RX(mvm, "cqm_iterator cqm low %d\n",
434 sig);
435 ieee80211_cqm_rssi_notify(
436 vif,
437 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
438 GFP_KERNEL);
439 } else if (sig > thold &&
440 (last_event == 0 || sig > last_event + hyst)) {
441 mvmvif->bf_data.last_cqm_event = sig;
442 IWL_DEBUG_RX(mvm, "cqm_iterator cqm high %d\n",
443 sig);
444 ieee80211_cqm_rssi_notify(
445 vif,
446 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
447 GFP_KERNEL);
448 }
449}
450
399/* 451/*
400 * iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler 452 * iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler
401 * 453 *
402 * TODO: This handler is implemented partially. 454 * TODO: This handler is implemented partially.
403 * It only gets the NIC's temperature.
404 */ 455 */
405int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, 456int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
406 struct iwl_rx_cmd_buffer *rxb, 457 struct iwl_rx_cmd_buffer *rxb,
@@ -409,6 +460,10 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
409 struct iwl_rx_packet *pkt = rxb_addr(rxb); 460 struct iwl_rx_packet *pkt = rxb_addr(rxb);
410 struct iwl_notif_statistics *stats = (void *)&pkt->data; 461 struct iwl_notif_statistics *stats = (void *)&pkt->data;
411 struct mvm_statistics_general_common *common = &stats->general.common; 462 struct mvm_statistics_general_common *common = &stats->general.common;
463 struct iwl_mvm_stat_data data = {
464 .stats = stats,
465 .mvm = mvm,
466 };
412 467
413 if (mvm->temperature != le32_to_cpu(common->temperature)) { 468 if (mvm->temperature != le32_to_cpu(common->temperature)) {
414 mvm->temperature = le32_to_cpu(common->temperature); 469 mvm->temperature = le32_to_cpu(common->temperature);
@@ -416,5 +471,9 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
416 } 471 }
417 iwl_mvm_update_rx_statistics(mvm, stats); 472 iwl_mvm_update_rx_statistics(mvm, stats);
418 473
474 ieee80211_iterate_active_interfaces(mvm->hw,
475 IEEE80211_IFACE_ITER_NORMAL,
476 iwl_mvm_stat_iterator,
477 &data);
419 return 0; 478 return 0;
420} 479}