diff options
author | Avri Altman <avri.altman@intel.com> | 2014-03-19 01:25:06 -0400 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-04-06 03:18:46 -0400 |
commit | 198890258fc0f9e3270ed1c1794b7610dad92ada (patch) | |
tree | 1d889017a3eb4acac995c6536128a33da7eca4d1 /drivers/net/wireless/iwlwifi/mvm/power.c | |
parent | a31267c30880ebdc73e6815f58c69a665052fab8 (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.c | 193 |
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 | ||
511 | struct iwl_power_constraint { | 504 | struct 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 | ||
522 | static void iwl_mvm_power_iterator(void *_data, u8 *mac, | 516 | static 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 | ||
598 | static void | 574 | static void |
599 | iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm, | 575 | iwl_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 | ||
614 | int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 640 | int 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 |