diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/power.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/power.c | 426 |
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 | ||
77 | static | ||
77 | int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, | 78 | int 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 | ||
112 | static | 109 | static |
@@ -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 | ||
151 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, | 148 | static 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 | ||
422 | static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, | 419 | static 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 | |||
450 | static 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 | ||
477 | static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) | 441 | int 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 | ||
504 | static int iwl_mvm_power_update_device(struct iwl_mvm *mvm) | ||
505 | { | ||
506 | return _iwl_mvm_power_update_device(mvm, false); | ||
507 | } | ||
508 | |||
509 | void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 473 | void 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 | ||
547 | static void iwl_mvm_power_binding_iterator(void *_data, u8 *mac, | 511 | struct 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 | |||
522 | static 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; | 598 | static void |
599 | iwl_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 | ||
560 | static void _iwl_mvm_power_update_binding(struct iwl_mvm *mvm, | 614 | int 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 |
577 | static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, | 666 | int 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 | ||
688 | int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | 784 | static 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 | ||
809 | int 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 | |||
712 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | 821 | int 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 | ||
731 | int iwl_mvm_update_beacon_filter(struct iwl_mvm *mvm, | 841 | int 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 | ||
742 | const 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 | |||
898 | int 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 | |||
918 | int 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 | } | ||