aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/power.c
diff options
context:
space:
mode:
authorAvri Altman <avri.altman@intel.com>2014-03-19 01:25:06 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-04-06 03:18:46 -0400
commit198890258fc0f9e3270ed1c1794b7610dad92ada (patch)
tree1d889017a3eb4acac995c6536128a33da7eca4d1 /drivers/net/wireless/iwlwifi/mvm/power.c
parenta31267c30880ebdc73e6815f58c69a665052fab8 (diff)
iwlwifi: mvm: Handle power management constraints for additional use-cases
Today, the driver logic looks for the conditions to disable power management albeit power management should be enabled in a very few distinct cases. This patch changes the driver logic to enable power management once the required conditions met. While at it, make some housekeeping and support a few additional use cases: a) Add support for a standalone p2p client: Power management should be enabled for a P2P client MAC only if the firmware supports it (TLV flag is set). Instead we used the DCM flag, therefore we didn't cover use cases that did not include the DCM flag. b) Add support to Same-Channel-Mode (SCM): If both clients share the same channel (SCM), and there are no other active vifs in the system, power management should be enabled only if the firmware supports this (TLV flag is set). c) Fix power management logic for GO/AP: Today, when we detect an active GO / AP MAC - we disable power management for all the vifs altogether. Actually, the correct behavior is to enable power management on a client if on a different channel (based on the firmware capabilities). d) Housekeeping - Along with that, this patch includes some code-reorganizing: Today the logic of disabling power is scattered across several functions, specifically in the iterator. For the sake of both readability and scalability, we moved this logic to its applicable function, leaving the iterator gather information only. Furthermore, as power management is a MAC-related attribute, we moved the power management member to the iwl_mvm_vif structure. Signed-off-by: Avri Altman <avri.altman@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/power.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/power.c193
1 files changed, 110 insertions, 83 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index 6b636eab3339..a1ce8d26f999 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -309,7 +309,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
309 cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); 309 cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
310#endif 310#endif
311 if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || 311 if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) ||
312 mvm->pm_disabled) 312 !mvmvif->pm_enabled)
313 return; 313 return;
314 314
315 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); 315 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -421,13 +421,6 @@ static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,
421{ 421{
422 struct iwl_mac_power_cmd cmd = {}; 422 struct iwl_mac_power_cmd cmd = {};
423 423
424 if (vif->type != NL80211_IFTYPE_STATION)
425 return 0;
426
427 if (vif->p2p &&
428 !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM))
429 return 0;
430
431 iwl_mvm_power_build_cmd(mvm, vif, &cmd); 424 iwl_mvm_power_build_cmd(mvm, vif, &cmd);
432 iwl_mvm_power_log(mvm, &cmd); 425 iwl_mvm_power_log(mvm, &cmd);
433#ifdef CONFIG_IWLWIFI_DEBUGFS 426#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -508,86 +501,69 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
508 return 0; 501 return 0;
509} 502}
510 503
511struct iwl_power_constraint { 504struct iwl_power_vifs {
512 struct ieee80211_vif *bf_vif; 505 struct ieee80211_vif *bf_vif;
513 struct ieee80211_vif *bss_vif; 506 struct ieee80211_vif *bss_vif;
514 struct ieee80211_vif *p2p_vif; 507 struct ieee80211_vif *p2p_vif;
515 u16 bss_phyctx_id; 508 struct ieee80211_vif *ap_vif;
516 u16 p2p_phyctx_id; 509 struct ieee80211_vif *monitor_vif;
517 bool pm_disabled; 510 bool p2p_active;
518 bool ps_disabled; 511 bool bss_active;
519 struct iwl_mvm *mvm; 512 bool ap_active;
513 bool monitor_active;
520}; 514};
521 515
522static void iwl_mvm_power_iterator(void *_data, u8 *mac, 516static void iwl_mvm_power_iterator(void *_data, u8 *mac,
523 struct ieee80211_vif *vif) 517 struct ieee80211_vif *vif)
524{ 518{
525 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 519 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
526 struct iwl_power_constraint *power_iterator = _data; 520 struct iwl_power_vifs *power_iterator = _data;
527 struct iwl_mvm *mvm = power_iterator->mvm;
528 521
522 mvmvif->pm_enabled = false;
529 switch (ieee80211_vif_type_p2p(vif)) { 523 switch (ieee80211_vif_type_p2p(vif)) {
530 case NL80211_IFTYPE_P2P_DEVICE: 524 case NL80211_IFTYPE_P2P_DEVICE:
531 break; 525 break;
532 526
533 case NL80211_IFTYPE_P2P_GO: 527 case NL80211_IFTYPE_P2P_GO:
534 case NL80211_IFTYPE_AP: 528 case NL80211_IFTYPE_AP:
535 /* no BSS power mgmt if we have an active AP */ 529 /* only a single MAC of the same type */
536 if (mvmvif->ap_ibss_active) 530 WARN_ON(power_iterator->ap_vif);
537 power_iterator->pm_disabled = true; 531 power_iterator->ap_vif = vif;
532 if (mvmvif->phy_ctxt)
533 if (mvmvif->phy_ctxt->id < MAX_PHYS)
534 power_iterator->ap_active = true;
538 break; 535 break;
539 536
540 case NL80211_IFTYPE_MONITOR: 537 case NL80211_IFTYPE_MONITOR:
541 /* no BSS power mgmt and no device power save */ 538 /* only a single MAC of the same type */
542 power_iterator->pm_disabled = true; 539 WARN_ON(power_iterator->monitor_vif);
543 power_iterator->ps_disabled = true; 540 power_iterator->monitor_vif = vif;
541 if (mvmvif->phy_ctxt)
542 if (mvmvif->phy_ctxt->id < MAX_PHYS)
543 power_iterator->monitor_active = true;
544 break; 544 break;
545 545
546 case NL80211_IFTYPE_P2P_CLIENT: 546 case NL80211_IFTYPE_P2P_CLIENT:
547 if (mvmvif->phy_ctxt) 547 /* only a single MAC of the same type */
548 power_iterator->p2p_phyctx_id = mvmvif->phy_ctxt->id;
549
550 /* we should have only one P2P vif */
551 WARN_ON(power_iterator->p2p_vif); 548 WARN_ON(power_iterator->p2p_vif);
552 power_iterator->p2p_vif = vif; 549 power_iterator->p2p_vif = vif;
553 550 if (mvmvif->phy_ctxt)
554 IWL_DEBUG_POWER(mvm, "p2p: p2p_id=%d, bss_id=%d\n", 551 if (mvmvif->phy_ctxt->id < MAX_PHYS)
555 power_iterator->p2p_phyctx_id, 552 power_iterator->p2p_active = true;
556 power_iterator->bss_phyctx_id);
557 if (!(mvm->fw->ucode_capa.flags &
558 IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) {
559 /* no BSS power mgmt if we have a P2P client*/
560 power_iterator->pm_disabled = true;
561 } else if (power_iterator->p2p_phyctx_id < MAX_PHYS &&
562 power_iterator->bss_phyctx_id < MAX_PHYS &&
563 power_iterator->p2p_phyctx_id ==
564 power_iterator->bss_phyctx_id) {
565 power_iterator->pm_disabled = true;
566 }
567 break; 553 break;
568 554
569 case NL80211_IFTYPE_STATION: 555 case NL80211_IFTYPE_STATION:
570 if (mvmvif->phy_ctxt) 556 /* only a single MAC of the same type */
571 power_iterator->bss_phyctx_id = mvmvif->phy_ctxt->id;
572
573 /* we should have only one BSS vif */
574 WARN_ON(power_iterator->bss_vif); 557 WARN_ON(power_iterator->bss_vif);
575 power_iterator->bss_vif = vif; 558 power_iterator->bss_vif = vif;
559 if (mvmvif->phy_ctxt)
560 if (mvmvif->phy_ctxt->id < MAX_PHYS)
561 power_iterator->bss_active = true;
576 562
577 if (mvmvif->bf_data.bf_enabled && 563 if (mvmvif->bf_data.bf_enabled &&
578 !WARN_ON(power_iterator->bf_vif)) 564 !WARN_ON(power_iterator->bf_vif))
579 power_iterator->bf_vif = vif; 565 power_iterator->bf_vif = vif;
580 566
581 IWL_DEBUG_POWER(mvm, "bss: p2p_id=%d, bss_id=%d\n",
582 power_iterator->p2p_phyctx_id,
583 power_iterator->bss_phyctx_id);
584 if (mvm->fw->ucode_capa.flags &
585 IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM &&
586 (power_iterator->p2p_phyctx_id < MAX_PHYS &&
587 power_iterator->bss_phyctx_id < MAX_PHYS &&
588 power_iterator->p2p_phyctx_id ==
589 power_iterator->bss_phyctx_id))
590 power_iterator->pm_disabled = true;
591 break; 567 break;
592 568
593 default: 569 default:
@@ -596,29 +572,75 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac,
596} 572}
597 573
598static void 574static void
599iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm, 575iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
600 struct iwl_power_constraint *constraint) 576 struct iwl_power_vifs *vifs)
601{ 577{
602 lockdep_assert_held(&mvm->mutex); 578 struct iwl_mvm_vif *bss_mvmvif = NULL;
579 struct iwl_mvm_vif *p2p_mvmvif = NULL;
580 struct iwl_mvm_vif *ap_mvmvif = NULL;
581 bool client_same_channel = false;
582 bool ap_same_channel = false;
603 583
604 if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) { 584 lockdep_assert_held(&mvm->mutex);
605 constraint->pm_disabled = true;
606 constraint->ps_disabled = true;
607 }
608 585
586 /* get vifs info + set pm_enable to false */
609 ieee80211_iterate_active_interfaces_atomic(mvm->hw, 587 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
610 IEEE80211_IFACE_ITER_NORMAL, 588 IEEE80211_IFACE_ITER_NORMAL,
611 iwl_mvm_power_iterator, constraint); 589 iwl_mvm_power_iterator, vifs);
590
591 if (vifs->bss_vif)
592 bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif);
593
594 if (vifs->p2p_vif)
595 p2p_mvmvif = iwl_mvm_vif_from_mac80211(vifs->p2p_vif);
596
597 if (vifs->ap_vif)
598 ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif);
599
600 /* enable PM on bss if bss stand alone */
601 if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) {
602 bss_mvmvif->pm_enabled = true;
603 return;
604 }
605
606 /* enable PM on p2p if p2p stand alone */
607 if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) {
608 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM)
609 p2p_mvmvif->pm_enabled = true;
610 return;
611 }
612
613 if (vifs->bss_active && vifs->p2p_active)
614 client_same_channel = (bss_mvmvif->phy_ctxt->id ==
615 p2p_mvmvif->phy_ctxt->id);
616 if (vifs->bss_active && vifs->ap_active)
617 ap_same_channel = (bss_mvmvif->phy_ctxt->id ==
618 ap_mvmvif->phy_ctxt->id);
619
620 /* bss is not stand alone: enable PM if alone on its channel */
621 if (vifs->bss_active && !(client_same_channel || ap_same_channel) &&
622 (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM)) {
623 bss_mvmvif->pm_enabled = true;
624 return;
625 }
626
627 /*
628 * There is only one channel in the system and there are only
629 * bss and p2p clients that share it
630 */
631 if (client_same_channel && !vifs->ap_active &&
632 (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_SCM)) {
633 /* share same channel*/
634 bss_mvmvif->pm_enabled = true;
635 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PM)
636 p2p_mvmvif->pm_enabled = true;
637 }
612} 638}
613 639
614int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 640int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
615{ 641{
616 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 642 struct iwl_mvm_vif *mvmvif;
617 struct iwl_power_constraint constraint = { 643 struct iwl_power_vifs vifs = {};
618 .p2p_phyctx_id = MAX_PHYS,
619 .bss_phyctx_id = MAX_PHYS,
620 .mvm = mvm,
621 };
622 bool ba_enable; 644 bool ba_enable;
623 int ret; 645 int ret;
624 646
@@ -627,39 +649,44 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
627 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) 649 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
628 return 0; 650 return 0;
629 651
630 iwl_mvm_power_get_global_constraint(mvm, &constraint); 652 iwl_mvm_power_set_pm(mvm, &vifs);
631 mvm->ps_disabled = constraint.ps_disabled;
632 mvm->pm_disabled = constraint.pm_disabled;
633 653
654 /* disable PS if CAM */
655 if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) {
656 mvm->ps_disabled = true;
657 } else {
634 /* don't update device power state unless we add / remove monitor */ 658 /* don't update device power state unless we add / remove monitor */
635 if (vif->type == NL80211_IFTYPE_MONITOR) { 659 if (vifs.monitor_vif) {
636 ret = iwl_mvm_power_update_device(mvm); 660 if (vifs.monitor_active)
637 if (ret) 661 mvm->ps_disabled = true;
638 return ret; 662 ret = iwl_mvm_power_update_device(mvm);
663 if (ret)
664 return ret;
665 }
639 } 666 }
640 667
641 if (constraint.bss_vif) { 668 if (vifs.bss_vif) {
642 ret = iwl_mvm_power_send_cmd(mvm, constraint.bss_vif); 669 ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif);
643 if (ret) 670 if (ret)
644 return ret; 671 return ret;
645 } 672 }
646 673
647 if (constraint.p2p_vif) { 674 if (vifs.p2p_vif) {
648 ret = iwl_mvm_power_send_cmd(mvm, constraint.p2p_vif); 675 ret = iwl_mvm_power_send_cmd(mvm, vifs.p2p_vif);
649 if (ret) 676 if (ret)
650 return ret; 677 return ret;
651 } 678 }
652 679
653 if (!constraint.bf_vif) 680 if (!vifs.bf_vif)
654 return 0; 681 return 0;
655 682
656 vif = constraint.bf_vif; 683 vif = vifs.bf_vif;
657 mvmvif = iwl_mvm_vif_from_mac80211(vif); 684 mvmvif = iwl_mvm_vif_from_mac80211(vif);
658 685
659 ba_enable = !(constraint.pm_disabled || constraint.ps_disabled || 686 ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled ||
660 !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif)); 687 !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif));
661 688
662 return iwl_mvm_update_beacon_abort(mvm, constraint.bf_vif, ba_enable); 689 return iwl_mvm_update_beacon_abort(mvm, vifs.bf_vif, ba_enable);
663} 690}
664 691
665#ifdef CONFIG_IWLWIFI_DEBUGFS 692#ifdef CONFIG_IWLWIFI_DEBUGFS