aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/power.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/power.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/power.c426
1 files changed, 301 insertions, 125 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index d9eab3b7bb9f..6b636eab3339 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -74,39 +74,36 @@
74 74
75#define POWER_KEEP_ALIVE_PERIOD_SEC 25 75#define POWER_KEEP_ALIVE_PERIOD_SEC 25
76 76
77static
77int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, 78int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
78 struct iwl_beacon_filter_cmd *cmd) 79 struct iwl_beacon_filter_cmd *cmd,
80 u32 flags)
79{ 81{
80 int ret; 82 IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n",
81 83 le32_to_cpu(cmd->ba_enable_beacon_abort));
82 ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, CMD_SYNC, 84 IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n",
83 sizeof(struct iwl_beacon_filter_cmd), cmd); 85 le32_to_cpu(cmd->ba_escape_timer));
84 86 IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n",
85 if (!ret) { 87 le32_to_cpu(cmd->bf_debug_flag));
86 IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", 88 IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n",
87 le32_to_cpu(cmd->ba_enable_beacon_abort)); 89 le32_to_cpu(cmd->bf_enable_beacon_filter));
88 IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", 90 IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n",
89 le32_to_cpu(cmd->ba_escape_timer)); 91 le32_to_cpu(cmd->bf_energy_delta));
90 IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", 92 IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n",
91 le32_to_cpu(cmd->bf_debug_flag)); 93 le32_to_cpu(cmd->bf_escape_timer));
92 IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", 94 IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n",
93 le32_to_cpu(cmd->bf_enable_beacon_filter)); 95 le32_to_cpu(cmd->bf_roaming_energy_delta));
94 IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", 96 IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n",
95 le32_to_cpu(cmd->bf_energy_delta)); 97 le32_to_cpu(cmd->bf_roaming_state));
96 IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", 98 IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n",
97 le32_to_cpu(cmd->bf_escape_timer)); 99 le32_to_cpu(cmd->bf_temp_threshold));
98 IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", 100 IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n",
99 le32_to_cpu(cmd->bf_roaming_energy_delta)); 101 le32_to_cpu(cmd->bf_temp_fast_filter));
100 IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", 102 IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n",
101 le32_to_cpu(cmd->bf_roaming_state)); 103 le32_to_cpu(cmd->bf_temp_slow_filter));
102 IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n", 104
103 le32_to_cpu(cmd->bf_temp_threshold)); 105 return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags,
104 IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n", 106 sizeof(struct iwl_beacon_filter_cmd), cmd);
105 le32_to_cpu(cmd->bf_temp_fast_filter));
106 IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n",
107 le32_to_cpu(cmd->bf_temp_slow_filter));
108 }
109 return ret;
110} 107}
111 108
112static 109static
@@ -145,7 +142,7 @@ int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
145 mvmvif->bf_data.ba_enabled = enable; 142 mvmvif->bf_data.ba_enabled = enable;
146 iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); 143 iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd);
147 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); 144 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd);
148 return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); 145 return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, CMD_SYNC);
149} 146}
150 147
151static void iwl_mvm_power_log(struct iwl_mvm *mvm, 148static void iwl_mvm_power_log(struct iwl_mvm *mvm,
@@ -301,8 +298,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
301 keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); 298 keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
302 cmd->keep_alive_seconds = cpu_to_le16(keep_alive); 299 cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
303 300
304 if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || 301 if (mvm->ps_disabled)
305 mvm->ps_prevented)
306 return; 302 return;
307 303
308 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); 304 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
@@ -312,7 +308,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
312 mvmvif->dbgfs_pm.disable_power_off) 308 mvmvif->dbgfs_pm.disable_power_off)
313 cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); 309 cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
314#endif 310#endif
315 if (!vif->bss_conf.ps || mvmvif->pm_prevented) 311 if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) ||
312 mvm->pm_disabled)
316 return; 313 return;
317 314
318 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); 315 cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -419,72 +416,44 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
419#endif /* CONFIG_IWLWIFI_DEBUGFS */ 416#endif /* CONFIG_IWLWIFI_DEBUGFS */
420} 417}
421 418
422static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, 419static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,
423 struct ieee80211_vif *vif) 420 struct ieee80211_vif *vif)
424{ 421{
425 int ret;
426 bool ba_enable;
427 struct iwl_mac_power_cmd cmd = {}; 422 struct iwl_mac_power_cmd cmd = {};
428 423
429 if (vif->type != NL80211_IFTYPE_STATION) 424 if (vif->type != NL80211_IFTYPE_STATION)
430 return 0; 425 return 0;
431 426
432 if (vif->p2p && 427 if (vif->p2p &&
433 !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)) 428 !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BSS_P2P_PS_DCM))
434 return 0; 429 return 0;
435 430
436 iwl_mvm_power_build_cmd(mvm, vif, &cmd); 431 iwl_mvm_power_build_cmd(mvm, vif, &cmd);
437 iwl_mvm_power_log(mvm, &cmd); 432 iwl_mvm_power_log(mvm, &cmd);
438
439 ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC,
440 sizeof(cmd), &cmd);
441 if (ret)
442 return ret;
443
444 ba_enable = !!(cmd.flags &
445 cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK));
446
447 return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable);
448}
449
450static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm,
451 struct ieee80211_vif *vif)
452{
453 struct iwl_mac_power_cmd cmd = {};
454 struct iwl_mvm_vif *mvmvif __maybe_unused =
455 iwl_mvm_vif_from_mac80211(vif);
456
457 if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
458 return 0;
459
460 cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
461 mvmvif->color));
462
463 if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
464 cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
465
466#ifdef CONFIG_IWLWIFI_DEBUGFS 433#ifdef CONFIG_IWLWIFI_DEBUGFS
467 if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && 434 memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd));
468 mvmvif->dbgfs_pm.disable_power_off)
469 cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK);
470#endif 435#endif
471 iwl_mvm_power_log(mvm, &cmd);
472 436
473 return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_ASYNC, 437 return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC,
474 sizeof(cmd), &cmd); 438 sizeof(cmd), &cmd);
475} 439}
476 440
477static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) 441int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
478{ 442{
479 struct iwl_device_power_cmd cmd = { 443 struct iwl_device_power_cmd cmd = {
480 .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), 444 .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
481 }; 445 };
482 446
447 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
448 return 0;
449
483 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) 450 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
484 return 0; 451 return 0;
485 452
486 if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || 453 if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
487 force_disable) 454 mvm->ps_disabled = true;
455
456 if (mvm->ps_disabled)
488 cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); 457 cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK);
489 458
490#ifdef CONFIG_IWLWIFI_DEBUGFS 459#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -501,11 +470,6 @@ static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable)
501 &cmd); 470 &cmd);
502} 471}
503 472
504static int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
505{
506 return _iwl_mvm_power_update_device(mvm, false);
507}
508
509void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 473void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
510{ 474{
511 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 475 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -544,44 +508,176 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
544 return 0; 508 return 0;
545} 509}
546 510
547static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac, 511struct iwl_power_constraint {
548 struct ieee80211_vif *vif) 512 struct ieee80211_vif *bf_vif;
513 struct ieee80211_vif *bss_vif;
514 struct ieee80211_vif *p2p_vif;
515 u16 bss_phyctx_id;
516 u16 p2p_phyctx_id;
517 bool pm_disabled;
518 bool ps_disabled;
519 struct iwl_mvm *mvm;
520};
521
522static void iwl_mvm_power_iterator(void *_data, u8 *mac,
523 struct ieee80211_vif *vif)
549{ 524{
550 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 525 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
551 struct iwl_mvm *mvm = _data; 526 struct iwl_power_constraint *power_iterator = _data;
552 int ret; 527 struct iwl_mvm *mvm = power_iterator->mvm;
528
529 switch (ieee80211_vif_type_p2p(vif)) {
530 case NL80211_IFTYPE_P2P_DEVICE:
531 break;
532
533 case NL80211_IFTYPE_P2P_GO:
534 case NL80211_IFTYPE_AP:
535 /* no BSS power mgmt if we have an active AP */
536 if (mvmvif->ap_ibss_active)
537 power_iterator->pm_disabled = true;
538 break;
539
540 case NL80211_IFTYPE_MONITOR:
541 /* no BSS power mgmt and no device power save */
542 power_iterator->pm_disabled = true;
543 power_iterator->ps_disabled = true;
544 break;
545
546 case NL80211_IFTYPE_P2P_CLIENT:
547 if (mvmvif->phy_ctxt)
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);
552 power_iterator->p2p_vif = vif;
553
554 IWL_DEBUG_POWER(mvm, "p2p: p2p_id=%d, bss_id=%d\n",
555 power_iterator->p2p_phyctx_id,
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;
568
569 case NL80211_IFTYPE_STATION:
570 if (mvmvif->phy_ctxt)
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);
575 power_iterator->bss_vif = vif;
576
577 if (mvmvif->bf_data.bf_enabled &&
578 !WARN_ON(power_iterator->bf_vif))
579 power_iterator->bf_vif = vif;
580
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;
592
593 default:
594 break;
595 }
596}
553 597
554 mvmvif->pm_prevented = (mvm->bound_vif_cnt <= 1) ? false : true; 598static void
599iwl_mvm_power_get_global_constraint(struct iwl_mvm *mvm,
600 struct iwl_power_constraint *constraint)
601{
602 lockdep_assert_held(&mvm->mutex);
603
604 if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) {
605 constraint->pm_disabled = true;
606 constraint->ps_disabled = true;
607 }
555 608
556 ret = iwl_mvm_power_mac_update_mode(mvm, vif); 609 ieee80211_iterate_active_interfaces_atomic(mvm->hw,
557 WARN_ONCE(ret, "Failed to update power parameters on a specific vif\n"); 610 IEEE80211_IFACE_ITER_NORMAL,
611 iwl_mvm_power_iterator, constraint);
558} 612}
559 613
560static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm, 614int iwl_mvm_power_update_mac(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
561 struct ieee80211_vif *vif,
562 bool assign)
563{ 615{
616 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
617 struct iwl_power_constraint constraint = {
618 .p2p_phyctx_id = MAX_PHYS,
619 .bss_phyctx_id = MAX_PHYS,
620 .mvm = mvm,
621 };
622 bool ba_enable;
623 int ret;
624
625 lockdep_assert_held(&mvm->mutex);
626
627 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT))
628 return 0;
629
630 iwl_mvm_power_get_global_constraint(mvm, &constraint);
631 mvm->ps_disabled = constraint.ps_disabled;
632 mvm->pm_disabled = constraint.pm_disabled;
633
634 /* don't update device power state unless we add / remove monitor */
564 if (vif->type == NL80211_IFTYPE_MONITOR) { 635 if (vif->type == NL80211_IFTYPE_MONITOR) {
565 int ret = _iwl_mvm_power_update_device(mvm, assign); 636 ret = iwl_mvm_power_update_device(mvm);
566 mvm->ps_prevented = assign; 637 if (ret)
567 WARN_ONCE(ret, "Failed to update power device state\n"); 638 return ret;
568 } 639 }
569 640
570 ieee80211_iterate_active_interfaces(mvm->hw, 641 if (constraint.bss_vif) {
571 IEEE80211_IFACE_ITER_NORMAL, 642 ret = iwl_mvm_power_send_cmd(mvm, constraint.bss_vif);
572 iwl_mvm_power_binding_iterator, 643 if (ret)
573 mvm); 644 return ret;
645 }
646
647 if (constraint.p2p_vif) {
648 ret = iwl_mvm_power_send_cmd(mvm, constraint.p2p_vif);
649 if (ret)
650 return ret;
651 }
652
653 if (!constraint.bf_vif)
654 return 0;
655
656 vif = constraint.bf_vif;
657 mvmvif = iwl_mvm_vif_from_mac80211(vif);
658
659 ba_enable = !(constraint.pm_disabled || constraint.ps_disabled ||
660 !vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif));
661
662 return iwl_mvm_update_beacon_abort(mvm, constraint.bf_vif, ba_enable);
574} 663}
575 664
576#ifdef CONFIG_IWLWIFI_DEBUGFS 665#ifdef CONFIG_IWLWIFI_DEBUGFS
577static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, 666int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm,
578 struct ieee80211_vif *vif, char *buf, 667 struct ieee80211_vif *vif, char *buf,
579 int bufsz) 668 int bufsz)
580{ 669{
670 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
581 struct iwl_mac_power_cmd cmd = {}; 671 struct iwl_mac_power_cmd cmd = {};
582 int pos = 0; 672 int pos = 0;
583 673
584 iwl_mvm_power_build_cmd(mvm, vif, &cmd); 674 if (WARN_ON(!(mvm->fw->ucode_capa.flags &
675 IWL_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)))
676 return 0;
677
678 mutex_lock(&mvm->mutex);
679 memcpy(&cmd, &mvmvif->mac_pwr_cmd, sizeof(cmd));
680 mutex_unlock(&mvm->mutex);
585 681
586 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) 682 if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
587 pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", 683 pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n",
@@ -685,32 +781,46 @@ iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
685} 781}
686#endif 782#endif
687 783
688int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, 784static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
689 struct ieee80211_vif *vif) 785 struct ieee80211_vif *vif,
786 struct iwl_beacon_filter_cmd *cmd,
787 u32 cmd_flags,
788 bool d0i3)
690{ 789{
691 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 790 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
692 struct iwl_beacon_filter_cmd cmd = {
693 IWL_BF_CMD_CONFIG_DEFAULTS,
694 .bf_enable_beacon_filter = cpu_to_le32(1),
695 };
696 int ret; 791 int ret;
697 792
698 if (mvmvif != mvm->bf_allowed_vif || 793 if (mvmvif != mvm->bf_allowed_vif ||
699 vif->type != NL80211_IFTYPE_STATION || vif->p2p) 794 vif->type != NL80211_IFTYPE_STATION || vif->p2p)
700 return 0; 795 return 0;
701 796
702 iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, &cmd); 797 iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd);
703 iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); 798 if (!d0i3)
704 ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); 799 iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd);
800 ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags);
705 801
706 if (!ret) 802 /* don't change bf_enabled in case of temporary d0i3 configuration */
803 if (!ret && !d0i3)
707 mvmvif->bf_data.bf_enabled = true; 804 mvmvif->bf_data.bf_enabled = true;
708 805
709 return ret; 806 return ret;
710} 807}
711 808
809int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
810 struct ieee80211_vif *vif,
811 u32 flags)
812{
813 struct iwl_beacon_filter_cmd cmd = {
814 IWL_BF_CMD_CONFIG_DEFAULTS,
815 .bf_enable_beacon_filter = cpu_to_le32(1),
816 };
817
818 return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags, false);
819}
820
712int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, 821int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
713 struct ieee80211_vif *vif) 822 struct ieee80211_vif *vif,
823 u32 flags)
714{ 824{
715 struct iwl_beacon_filter_cmd cmd = {}; 825 struct iwl_beacon_filter_cmd cmd = {};
716 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 826 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -720,7 +830,7 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
720 vif->type != NL80211_IFTYPE_STATION || vif->p2p) 830 vif->type != NL80211_IFTYPE_STATION || vif->p2p)
721 return 0; 831 return 0;
722 832
723 ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); 833 ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags);
724 834
725 if (!ret) 835 if (!ret)
726 mvmvif->bf_data.bf_enabled = false; 836 mvmvif->bf_data.bf_enabled = false;
@@ -728,23 +838,89 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
728 return ret; 838 return ret;
729} 839}
730 840
731int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, 841int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
732 struct ieee80211_vif *vif) 842 struct ieee80211_vif *vif,
843 bool enable, u32 flags)
733{ 844{
845 int ret;
734 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 846 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
847 struct iwl_mac_power_cmd cmd = {};
735 848
736 if (!mvmvif->bf_data.bf_enabled) 849 if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
737 return 0; 850 return 0;
738 851
739 return iwl_mvm_enable_beacon_filter(mvm, vif); 852 if (!vif->bss_conf.assoc)
740} 853 return 0;
741 854
742const struct iwl_mvm_power_ops pm_mac_ops = { 855 iwl_mvm_power_build_cmd(mvm, vif, &cmd);
743 .power_update_mode = iwl_mvm_power_mac_update_mode, 856 if (enable) {
744 .power_update_device_mode = iwl_mvm_power_update_device, 857 /* configure skip over dtim up to 300 msec */
745 .power_disable = iwl_mvm_power_mac_disable, 858 int dtimper = mvm->hw->conf.ps_dtim_period ?: 1;
746 .power_update_binding = _iwl_mvm_power_update_binding, 859 int dtimper_msec = dtimper * vif->bss_conf.beacon_int;
860
861 if (WARN_ON(!dtimper_msec))
862 return 0;
863
864 cmd.flags |=
865 cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
866 cmd.skip_dtim_periods = 300 / dtimper_msec;
867 }
868 iwl_mvm_power_log(mvm, &cmd);
747#ifdef CONFIG_IWLWIFI_DEBUGFS 869#ifdef CONFIG_IWLWIFI_DEBUGFS
748 .power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read, 870 memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd));
749#endif 871#endif
750}; 872 ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags,
873 sizeof(cmd), &cmd);
874 if (ret)
875 return ret;
876
877 /* configure beacon filtering */
878 if (mvmvif != mvm->bf_allowed_vif)
879 return 0;
880
881 if (enable) {
882 struct iwl_beacon_filter_cmd cmd_bf = {
883 IWL_BF_CMD_CONFIG_D0I3,
884 .bf_enable_beacon_filter = cpu_to_le32(1),
885 };
886 ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf,
887 flags, true);
888 } else {
889 if (mvmvif->bf_data.bf_enabled)
890 ret = iwl_mvm_enable_beacon_filter(mvm, vif, flags);
891 else
892 ret = iwl_mvm_disable_beacon_filter(mvm, vif, flags);
893 }
894
895 return ret;
896}
897
898int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm,
899 struct ieee80211_vif *vif,
900 bool force,
901 u32 flags)
902{
903 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
904
905 if (mvmvif != mvm->bf_allowed_vif)
906 return 0;
907
908 if (!mvmvif->bf_data.bf_enabled) {
909 /* disable beacon filtering explicitly if force is true */
910 if (force)
911 return iwl_mvm_disable_beacon_filter(mvm, vif, flags);
912 return 0;
913 }
914
915 return iwl_mvm_enable_beacon_filter(mvm, vif, flags);
916}
917
918int iwl_power_legacy_set_cam_mode(struct iwl_mvm *mvm)
919{
920 struct iwl_powertable_cmd cmd = {
921 .keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC,
922 };
923
924 return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
925 sizeof(cmd), &cmd);
926}