diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/debugfs.c | 33 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 75 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api.h | 5 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 46 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/ops.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/power.c | 128 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/power_legacy.c | 319 |
9 files changed, 544 insertions, 81 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index ff856e543ae8..6d73817850ce 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile | |||
@@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o | |||
2 | iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o | 2 | iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o |
3 | iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o | 3 | iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o |
4 | iwlmvm-y += scan.o time-event.o rs.o | 4 | iwlmvm-y += scan.o time-event.o rs.o |
5 | iwlmvm-y += power.o bt-coex.o | 5 | iwlmvm-y += power.o power_legacy.o bt-coex.o |
6 | iwlmvm-y += led.o tt.o | 6 | iwlmvm-y += led.o tt.o |
7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o | 7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o |
8 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o | 8 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index e56ed2a84888..5d669da09afe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -424,40 +424,11 @@ static ssize_t iwl_dbgfs_pm_params_read(struct file *file, | |||
424 | struct ieee80211_vif *vif = file->private_data; | 424 | struct ieee80211_vif *vif = file->private_data; |
425 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 425 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
426 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; | 426 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; |
427 | struct iwl_powertable_cmd cmd = {}; | ||
428 | char buf[256]; | 427 | char buf[256]; |
429 | int bufsz = sizeof(buf); | 428 | int bufsz = sizeof(buf); |
430 | int pos = 0; | 429 | int pos; |
431 | 430 | ||
432 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | 431 | pos = iwl_mvm_power_dbgfs_read(mvm, vif, buf, bufsz); |
433 | |||
434 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", | ||
435 | (cmd.flags & | ||
436 | cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? | ||
437 | 0 : 1); | ||
438 | pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", | ||
439 | le32_to_cpu(cmd.skip_dtim_periods)); | ||
440 | pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", | ||
441 | iwlmvm_mod_params.power_scheme); | ||
442 | pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", | ||
443 | le16_to_cpu(cmd.flags)); | ||
444 | pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", | ||
445 | cmd.keep_alive_seconds); | ||
446 | |||
447 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
448 | pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", | ||
449 | (cmd.flags & | ||
450 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? | ||
451 | 1 : 0); | ||
452 | pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", | ||
453 | le32_to_cpu(cmd.rx_data_timeout)); | ||
454 | pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", | ||
455 | le32_to_cpu(cmd.tx_data_timeout)); | ||
456 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | ||
457 | pos += scnprintf(buf+pos, bufsz-pos, | ||
458 | "lprx_rssi_threshold = %d\n", | ||
459 | le32_to_cpu(cmd.lprx_rssi_threshold)); | ||
460 | } | ||
461 | 432 | ||
462 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 433 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
463 | } | 434 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index a6da359a80c3..300211d79f2a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | |||
@@ -79,6 +79,10 @@ | |||
79 | * '1' Driver enables PM (use rest of parameters) | 79 | * '1' Driver enables PM (use rest of parameters) |
80 | * @POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, | 80 | * @POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, |
81 | * '1' PM could sleep over DTIM till listen Interval. | 81 | * '1' PM could sleep over DTIM till listen Interval. |
82 | * @POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all | ||
83 | * access categories are both delivery and trigger enabled. | ||
84 | * @POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and | ||
85 | * PBW Snoozing enabled | ||
82 | * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask | 86 | * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask |
83 | * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. | 87 | * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable. |
84 | */ | 88 | */ |
@@ -86,6 +90,8 @@ enum iwl_power_flags { | |||
86 | POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), | 90 | POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), |
87 | POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(1), | 91 | POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(1), |
88 | POWER_FLAGS_SKIP_OVER_DTIM_MSK = BIT(2), | 92 | POWER_FLAGS_SKIP_OVER_DTIM_MSK = BIT(2), |
93 | POWER_FLAGS_SNOOZE_ENA_MSK = BIT(5), | ||
94 | POWER_FLAGS_BT_SCO_ENA = BIT(8), | ||
89 | POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9), | 95 | POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9), |
90 | POWER_FLAGS_LPRX_ENA_MSK = BIT(11), | 96 | POWER_FLAGS_LPRX_ENA_MSK = BIT(11), |
91 | }; | 97 | }; |
@@ -93,7 +99,8 @@ enum iwl_power_flags { | |||
93 | #define IWL_POWER_VEC_SIZE 5 | 99 | #define IWL_POWER_VEC_SIZE 5 |
94 | 100 | ||
95 | /** | 101 | /** |
96 | * struct iwl_powertable_cmd - Power Table Command | 102 | * struct iwl_powertable_cmd - legacy power command. Beside old API support this |
103 | * is used also with a new power API for device wide power settings. | ||
97 | * POWER_TABLE_CMD = 0x77 (command, has simple generic response) | 104 | * POWER_TABLE_CMD = 0x77 (command, has simple generic response) |
98 | * | 105 | * |
99 | * @flags: Power table command flags from POWER_FLAGS_* | 106 | * @flags: Power table command flags from POWER_FLAGS_* |
@@ -125,6 +132,72 @@ struct iwl_powertable_cmd { | |||
125 | } __packed; | 132 | } __packed; |
126 | 133 | ||
127 | /** | 134 | /** |
135 | * struct iwl_mac_power_cmd - New power command containing uAPSD support | ||
136 | * MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) | ||
137 | * @id_and_color: MAC contex identifier | ||
138 | * @flags: Power table command flags from POWER_FLAGS_* | ||
139 | * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. | ||
140 | * Minimum allowed:- 3 * DTIM. Keep alive period must be | ||
141 | * set regardless of power scheme or current power state. | ||
142 | * FW use this value also when PM is disabled. | ||
143 | * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to | ||
144 | * PSM transition - legacy PM | ||
145 | * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to | ||
146 | * PSM transition - legacy PM | ||
147 | * @sleep_interval: not in use | ||
148 | * @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag | ||
149 | * is set. For example, if it is required to skip over | ||
150 | * one DTIM, this value need to be set to 2 (DTIM periods). | ||
151 | * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to | ||
152 | * PSM transition - uAPSD | ||
153 | * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to | ||
154 | * PSM transition - uAPSD | ||
155 | * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. | ||
156 | * Default: 80dbm | ||
157 | * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set | ||
158 | * @snooze_interval: TBD | ||
159 | * @snooze_window: TBD | ||
160 | * @snooze_step: TBD | ||
161 | * @qndp_tid: TID client shall use for uAPSD QNDP triggers | ||
162 | * @uapsd_ac_flags: Set trigger-enabled and delivery-enabled indication for | ||
163 | * each corresponding AC. | ||
164 | * Use IEEE80211_WMM_IE_STA_QOSINFO_AC* for correct values. | ||
165 | * @uapsd_max_sp: Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct | ||
166 | * values. | ||
167 | * @heavy_traffic_thr_tx_pkts: TX threshold measured in number of packets | ||
168 | * @heavy_traffic_thr_rx_pkts: RX threshold measured in number of packets | ||
169 | * @heavy_traffic_thr_tx_load: TX threshold measured in load's percentage | ||
170 | * @heavy_traffic_thr_rx_load: RX threshold measured in load's percentage | ||
171 | * @limited_ps_threshold: | ||
172 | */ | ||
173 | struct iwl_mac_power_cmd { | ||
174 | /* CONTEXT_DESC_API_T_VER_1 */ | ||
175 | __le32 id_and_color; | ||
176 | |||
177 | /* CLIENT_PM_POWER_TABLE_S_VER_1 */ | ||
178 | __le16 flags; | ||
179 | __le16 keep_alive_seconds; | ||
180 | __le32 rx_data_timeout; | ||
181 | __le32 tx_data_timeout; | ||
182 | __le32 rx_data_timeout_uapsd; | ||
183 | __le32 tx_data_timeout_uapsd; | ||
184 | u8 lprx_rssi_threshold; | ||
185 | u8 skip_dtim_periods; | ||
186 | __le16 snooze_interval; | ||
187 | __le16 snooze_window; | ||
188 | u8 snooze_step; | ||
189 | u8 qndp_tid; | ||
190 | u8 uapsd_ac_flags; | ||
191 | u8 uapsd_max_sp; | ||
192 | u8 heavy_traffic_threshold_tx_packets; | ||
193 | u8 heavy_traffic_threshold_rx_packets; | ||
194 | u8 heavy_traffic_threshold_tx_percentage; | ||
195 | u8 heavy_traffic_threshold_rx_percentage; | ||
196 | u8 limited_ps_threshold; | ||
197 | u8 reserved; | ||
198 | } __packed; | ||
199 | |||
200 | /** | ||
128 | * struct iwl_beacon_filter_cmd | 201 | * struct iwl_beacon_filter_cmd |
129 | * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) | 202 | * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) |
130 | * @id_and_color: MAC contex identifier | 203 | * @id_and_color: MAC contex identifier |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index cbfb3beae783..44614f5e4485 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -136,7 +136,7 @@ enum { | |||
136 | CALIB_RES_NOTIF_PHY_DB = 0x6b, | 136 | CALIB_RES_NOTIF_PHY_DB = 0x6b, |
137 | /* PHY_DB_CMD = 0x6c, */ | 137 | /* PHY_DB_CMD = 0x6c, */ |
138 | 138 | ||
139 | /* Power */ | 139 | /* Power - legacy power table command */ |
140 | POWER_TABLE_CMD = 0x77, | 140 | POWER_TABLE_CMD = 0x77, |
141 | 141 | ||
142 | /* Thermal Throttling*/ | 142 | /* Thermal Throttling*/ |
@@ -166,6 +166,9 @@ enum { | |||
166 | 166 | ||
167 | MISSED_BEACONS_NOTIFICATION = 0xa2, | 167 | MISSED_BEACONS_NOTIFICATION = 0xa2, |
168 | 168 | ||
169 | /* Power - new power table command */ | ||
170 | MAC_PM_POWER_TABLE = 0xa9, | ||
171 | |||
169 | REPLY_RX_PHY_CMD = 0xc0, | 172 | REPLY_RX_PHY_CMD = 0xc0, |
170 | REPLY_RX_MPDU_CMD = 0xc1, | 173 | REPLY_RX_MPDU_CMD = 0xc1, |
171 | BA_NOTIF = 0xc5, | 174 | BA_NOTIF = 0xc5, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e08683b20531..2d07605eaabf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -774,9 +774,14 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
774 | if (ret) | 774 | if (ret) |
775 | IWL_ERR(mvm, "failed to update quotas\n"); | 775 | IWL_ERR(mvm, "failed to update quotas\n"); |
776 | } | 776 | } |
777 | ret = iwl_mvm_power_update_mode(mvm, vif); | 777 | if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD)) { |
778 | if (ret) | 778 | /* Workaround for FW bug, otherwise FW disables device |
779 | IWL_ERR(mvm, "failed to update power mode\n"); | 779 | * power save upon disassociation |
780 | */ | ||
781 | ret = iwl_mvm_power_update_mode(mvm, vif); | ||
782 | if (ret) | ||
783 | IWL_ERR(mvm, "failed to update power mode\n"); | ||
784 | } | ||
780 | } else if (changes & BSS_CHANGED_BEACON_INFO) { | 785 | } else if (changes & BSS_CHANGED_BEACON_INFO) { |
781 | /* | 786 | /* |
782 | * We received a beacon _after_ association so | 787 | * We received a beacon _after_ association so |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 3aaecbcdc551..caa6a1758172 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -91,6 +91,9 @@ enum iwl_mvm_tx_fifo { | |||
91 | }; | 91 | }; |
92 | 92 | ||
93 | extern struct ieee80211_ops iwl_mvm_hw_ops; | 93 | extern struct ieee80211_ops iwl_mvm_hw_ops; |
94 | extern const struct iwl_mvm_power_ops pm_legacy_ops; | ||
95 | extern const struct iwl_mvm_power_ops pm_mac_ops; | ||
96 | |||
94 | /** | 97 | /** |
95 | * struct iwl_mvm_mod_params - module parameters for iwlmvm | 98 | * struct iwl_mvm_mod_params - module parameters for iwlmvm |
96 | * @init_dbg: if true, then the NIC won't be stopped if the INIT fw asserted. | 99 | * @init_dbg: if true, then the NIC won't be stopped if the INIT fw asserted. |
@@ -150,6 +153,17 @@ enum iwl_power_scheme { | |||
150 | 153 | ||
151 | #define IWL_CONN_MAX_LISTEN_INTERVAL 70 | 154 | #define IWL_CONN_MAX_LISTEN_INTERVAL 70 |
152 | 155 | ||
156 | struct iwl_mvm_power_ops { | ||
157 | int (*power_update_mode)(struct iwl_mvm *mvm, | ||
158 | struct ieee80211_vif *vif); | ||
159 | int (*power_disable)(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
160 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
161 | int (*power_dbgfs_read)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
162 | char *buf, int bufsz); | ||
163 | #endif | ||
164 | }; | ||
165 | |||
166 | |||
153 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 167 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
154 | enum iwl_dbgfs_pm_mask { | 168 | enum iwl_dbgfs_pm_mask { |
155 | MVM_DEBUGFS_PM_KEEP_ALIVE = BIT(0), | 169 | MVM_DEBUGFS_PM_KEEP_ALIVE = BIT(0), |
@@ -163,7 +177,7 @@ enum iwl_dbgfs_pm_mask { | |||
163 | }; | 177 | }; |
164 | 178 | ||
165 | struct iwl_dbgfs_pm { | 179 | struct iwl_dbgfs_pm { |
166 | u8 keep_alive_seconds; | 180 | u16 keep_alive_seconds; |
167 | u32 rx_data_timeout; | 181 | u32 rx_data_timeout; |
168 | u32 tx_data_timeout; | 182 | u32 tx_data_timeout; |
169 | bool skip_over_dtim; | 183 | bool skip_over_dtim; |
@@ -481,6 +495,8 @@ struct iwl_mvm { | |||
481 | /* Thermal Throttling and CTkill */ | 495 | /* Thermal Throttling and CTkill */ |
482 | struct iwl_mvm_tt_mgmt thermal_throttle; | 496 | struct iwl_mvm_tt_mgmt thermal_throttle; |
483 | s32 temperature; /* Celsius */ | 497 | s32 temperature; /* Celsius */ |
498 | |||
499 | const struct iwl_mvm_power_ops *pm_ops; | ||
484 | }; | 500 | }; |
485 | 501 | ||
486 | /* Extract MVM priv from op_mode and _hw */ | 502 | /* Extract MVM priv from op_mode and _hw */ |
@@ -660,10 +676,26 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | |||
660 | u8 flags, bool init); | 676 | u8 flags, bool init); |
661 | 677 | ||
662 | /* power managment */ | 678 | /* power managment */ |
663 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 679 | static inline int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, |
664 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 680 | struct ieee80211_vif *vif) |
665 | void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 681 | { |
666 | struct iwl_powertable_cmd *cmd); | 682 | return mvm->pm_ops->power_update_mode(mvm, vif); |
683 | } | ||
684 | |||
685 | static inline int iwl_mvm_power_disable(struct iwl_mvm *mvm, | ||
686 | struct ieee80211_vif *vif) | ||
687 | { | ||
688 | return mvm->pm_ops->power_disable(mvm, vif); | ||
689 | } | ||
690 | |||
691 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
692 | static inline int iwl_mvm_power_dbgfs_read(struct iwl_mvm *mvm, | ||
693 | struct ieee80211_vif *vif, | ||
694 | char *buf, int bufsz) | ||
695 | { | ||
696 | return mvm->pm_ops->power_dbgfs_read(mvm, vif, buf, bufsz); | ||
697 | } | ||
698 | #endif | ||
667 | 699 | ||
668 | int iwl_mvm_leds_init(struct iwl_mvm *mvm); | 700 | int iwl_mvm_leds_init(struct iwl_mvm *mvm); |
669 | void iwl_mvm_leds_exit(struct iwl_mvm *mvm); | 701 | void iwl_mvm_leds_exit(struct iwl_mvm *mvm); |
@@ -707,6 +739,10 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | |||
707 | struct ieee80211_vif *vif); | 739 | struct ieee80211_vif *vif); |
708 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | 740 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, |
709 | struct ieee80211_vif *vif); | 741 | struct ieee80211_vif *vif); |
742 | int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, | ||
743 | struct iwl_beacon_filter_cmd *cmd); | ||
744 | int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, | ||
745 | struct ieee80211_vif *vif, bool enable); | ||
710 | 746 | ||
711 | /* SMPS */ | 747 | /* SMPS */ |
712 | void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 748 | void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 0a4eb278f789..fa1e1ce9f2be 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -301,6 +301,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
301 | CMD(MCAST_FILTER_CMD), | 301 | CMD(MCAST_FILTER_CMD), |
302 | CMD(REPLY_BEACON_FILTERING_CMD), | 302 | CMD(REPLY_BEACON_FILTERING_CMD), |
303 | CMD(REPLY_THERMAL_MNG_BACKOFF), | 303 | CMD(REPLY_THERMAL_MNG_BACKOFF), |
304 | CMD(MAC_PM_POWER_TABLE), | ||
304 | }; | 305 | }; |
305 | #undef CMD | 306 | #undef CMD |
306 | 307 | ||
@@ -431,6 +432,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
431 | if (err) | 432 | if (err) |
432 | goto out_unregister; | 433 | goto out_unregister; |
433 | 434 | ||
435 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD) | ||
436 | mvm->pm_ops = &pm_mac_ops; | ||
437 | else | ||
438 | mvm->pm_ops = &pm_legacy_ops; | ||
439 | |||
434 | return op_mode; | 440 | return op_mode; |
435 | 441 | ||
436 | out_unregister: | 442 | out_unregister: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index e7ca965a89b8..644bf476921a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -75,8 +75,8 @@ | |||
75 | 75 | ||
76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 | 76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 |
77 | 77 | ||
78 | static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, | 78 | int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, |
79 | struct iwl_beacon_filter_cmd *cmd) | 79 | struct iwl_beacon_filter_cmd *cmd) |
80 | { | 80 | { |
81 | int ret; | 81 | int ret; |
82 | 82 | ||
@@ -106,8 +106,8 @@ static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, | |||
106 | return ret; | 106 | return ret; |
107 | } | 107 | } |
108 | 108 | ||
109 | static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, | 109 | int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, |
110 | struct ieee80211_vif *vif, bool enable) | 110 | struct ieee80211_vif *vif, bool enable) |
111 | { | 111 | { |
112 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 112 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
113 | struct iwl_beacon_filter_cmd cmd = { | 113 | struct iwl_beacon_filter_cmd cmd = { |
@@ -124,13 +124,14 @@ static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, | |||
124 | } | 124 | } |
125 | 125 | ||
126 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, | 126 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, |
127 | struct iwl_powertable_cmd *cmd) | 127 | struct iwl_mac_power_cmd *cmd) |
128 | { | 128 | { |
129 | IWL_DEBUG_POWER(mvm, | 129 | IWL_DEBUG_POWER(mvm, |
130 | "Sending power table command for power level %d, flags = 0x%X\n", | 130 | "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", |
131 | iwlmvm_mod_params.power_scheme, | 131 | cmd->id_and_color, iwlmvm_mod_params.power_scheme, |
132 | le16_to_cpu(cmd->flags)); | 132 | le16_to_cpu(cmd->flags)); |
133 | IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", cmd->keep_alive_seconds); | 133 | IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", |
134 | le16_to_cpu(cmd->keep_alive_seconds)); | ||
134 | 135 | ||
135 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | 136 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { |
136 | IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", | 137 | IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", |
@@ -139,15 +140,16 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm, | |||
139 | le32_to_cpu(cmd->tx_data_timeout)); | 140 | le32_to_cpu(cmd->tx_data_timeout)); |
140 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) | 141 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) |
141 | IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", | 142 | IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", |
142 | le32_to_cpu(cmd->skip_dtim_periods)); | 143 | cmd->skip_dtim_periods); |
143 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | 144 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) |
144 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", | 145 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", |
145 | le32_to_cpu(cmd->lprx_rssi_threshold)); | 146 | cmd->lprx_rssi_threshold); |
146 | } | 147 | } |
147 | } | 148 | } |
148 | 149 | ||
149 | void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 150 | static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, |
150 | struct iwl_powertable_cmd *cmd) | 151 | struct ieee80211_vif *vif, |
152 | struct iwl_mac_power_cmd *cmd) | ||
151 | { | 153 | { |
152 | struct ieee80211_hw *hw = mvm->hw; | 154 | struct ieee80211_hw *hw = mvm->hw; |
153 | struct ieee80211_chanctx_conf *chanctx_conf; | 155 | struct ieee80211_chanctx_conf *chanctx_conf; |
@@ -158,19 +160,26 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
158 | struct iwl_mvm_vif *mvmvif __maybe_unused = | 160 | struct iwl_mvm_vif *mvmvif __maybe_unused = |
159 | iwl_mvm_vif_from_mac80211(vif); | 161 | iwl_mvm_vif_from_mac80211(vif); |
160 | 162 | ||
163 | cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
164 | mvmvif->color)); | ||
165 | dtimper = hw->conf.ps_dtim_period ?: 1; | ||
166 | |||
161 | /* | 167 | /* |
162 | * Regardless of power management state the driver must set | 168 | * Regardless of power management state the driver must set |
163 | * keep alive period. FW will use it for sending keep alive NDPs | 169 | * keep alive period. FW will use it for sending keep alive NDPs |
164 | * immediately after association. | 170 | * immediately after association. Check that keep alive period |
171 | * is at least 3 * DTIM | ||
165 | */ | 172 | */ |
166 | cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC; | 173 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; |
174 | keep_alive = max_t(int, 3 * dtimper_msec, | ||
175 | MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); | ||
176 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | ||
177 | cmd->keep_alive_seconds = cpu_to_le16(keep_alive); | ||
167 | 178 | ||
168 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) | 179 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) |
169 | return; | 180 | return; |
170 | 181 | ||
171 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | 182 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
172 | if (!vif->bss_conf.assoc) | ||
173 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | ||
174 | 183 | ||
175 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 184 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
176 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | 185 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && |
@@ -186,12 +195,9 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
186 | (vif->bss_conf.beacon_rate->bitrate == 10 || | 195 | (vif->bss_conf.beacon_rate->bitrate == 10 || |
187 | vif->bss_conf.beacon_rate->bitrate == 60)) { | 196 | vif->bss_conf.beacon_rate->bitrate == 60)) { |
188 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); | 197 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); |
189 | cmd->lprx_rssi_threshold = | 198 | cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD; |
190 | cpu_to_le32(POWER_LPRX_RSSI_THRESHOLD); | ||
191 | } | 199 | } |
192 | 200 | ||
193 | dtimper = hw->conf.ps_dtim_period ?: 1; | ||
194 | |||
195 | /* Check if radar detection is required on current channel */ | 201 | /* Check if radar detection is required on current channel */ |
196 | rcu_read_lock(); | 202 | rcu_read_lock(); |
197 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | 203 | chanctx_conf = rcu_dereference(vif->chanctx_conf); |
@@ -207,16 +213,9 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
207 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || | 213 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || |
208 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { | 214 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { |
209 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | 215 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); |
210 | cmd->skip_dtim_periods = cpu_to_le32(3); | 216 | cmd->skip_dtim_periods = 3; |
211 | } | 217 | } |
212 | 218 | ||
213 | /* Check that keep alive period is at least 3 * DTIM */ | ||
214 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | ||
215 | keep_alive = max_t(int, 3 * dtimper_msec, | ||
216 | MSEC_PER_SEC * cmd->keep_alive_seconds); | ||
217 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | ||
218 | cmd->keep_alive_seconds = keep_alive; | ||
219 | |||
220 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { | 219 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { |
221 | cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | 220 | cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); |
222 | cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | 221 | cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); |
@@ -227,7 +226,8 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
227 | 226 | ||
228 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 227 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
229 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) | 228 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) |
230 | cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds; | 229 | cmd->keep_alive_seconds = |
230 | cpu_to_le16(mvmvif->dbgfs_pm.keep_alive_seconds); | ||
231 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { | 231 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { |
232 | if (mvmvif->dbgfs_pm.skip_over_dtim) | 232 | if (mvmvif->dbgfs_pm.skip_over_dtim) |
233 | cmd->flags |= | 233 | cmd->flags |= |
@@ -243,8 +243,7 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
243 | cmd->tx_data_timeout = | 243 | cmd->tx_data_timeout = |
244 | cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); | 244 | cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); |
245 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) | 245 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) |
246 | cmd->skip_dtim_periods = | 246 | cmd->skip_dtim_periods = mvmvif->dbgfs_pm.skip_dtim_periods; |
247 | cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods); | ||
248 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { | 247 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { |
249 | if (mvmvif->dbgfs_pm.lprx_ena) | 248 | if (mvmvif->dbgfs_pm.lprx_ena) |
250 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); | 249 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); |
@@ -252,16 +251,16 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
252 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); | 251 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); |
253 | } | 252 | } |
254 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) | 253 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) |
255 | cmd->lprx_rssi_threshold = | 254 | cmd->lprx_rssi_threshold = mvmvif->dbgfs_pm.lprx_rssi_threshold; |
256 | cpu_to_le32(mvmvif->dbgfs_pm.lprx_rssi_threshold); | ||
257 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | 255 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ |
258 | } | 256 | } |
259 | 257 | ||
260 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 258 | static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, |
259 | struct ieee80211_vif *vif) | ||
261 | { | 260 | { |
262 | int ret; | 261 | int ret; |
263 | bool ba_enable; | 262 | bool ba_enable; |
264 | struct iwl_powertable_cmd cmd = {}; | 263 | struct iwl_mac_power_cmd cmd = {}; |
265 | 264 | ||
266 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 265 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
267 | return 0; | 266 | return 0; |
@@ -280,7 +279,7 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
280 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | 279 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); |
281 | iwl_mvm_power_log(mvm, &cmd); | 280 | iwl_mvm_power_log(mvm, &cmd); |
282 | 281 | ||
283 | ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | 282 | ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, |
284 | sizeof(cmd), &cmd); | 283 | sizeof(cmd), &cmd); |
285 | if (ret) | 284 | if (ret) |
286 | return ret; | 285 | return ret; |
@@ -291,15 +290,19 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
291 | return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); | 290 | return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); |
292 | } | 291 | } |
293 | 292 | ||
294 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 293 | static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, |
294 | struct ieee80211_vif *vif) | ||
295 | { | 295 | { |
296 | struct iwl_powertable_cmd cmd = {}; | 296 | struct iwl_mac_power_cmd cmd = {}; |
297 | struct iwl_mvm_vif *mvmvif __maybe_unused = | 297 | struct iwl_mvm_vif *mvmvif __maybe_unused = |
298 | iwl_mvm_vif_from_mac80211(vif); | 298 | iwl_mvm_vif_from_mac80211(vif); |
299 | 299 | ||
300 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 300 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
301 | return 0; | 301 | return 0; |
302 | 302 | ||
303 | cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, | ||
304 | mvmvif->color)); | ||
305 | |||
303 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) | 306 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) |
304 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | 307 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
305 | 308 | ||
@@ -310,11 +313,50 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
310 | #endif | 313 | #endif |
311 | iwl_mvm_power_log(mvm, &cmd); | 314 | iwl_mvm_power_log(mvm, &cmd); |
312 | 315 | ||
313 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, | 316 | return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_ASYNC, |
314 | sizeof(cmd), &cmd); | 317 | sizeof(cmd), &cmd); |
315 | } | 318 | } |
316 | 319 | ||
317 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 320 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
321 | static int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, | ||
322 | struct ieee80211_vif *vif, char *buf, | ||
323 | int bufsz) | ||
324 | { | ||
325 | struct iwl_mac_power_cmd cmd = {}; | ||
326 | int pos = 0; | ||
327 | |||
328 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | ||
329 | |||
330 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", | ||
331 | (cmd.flags & | ||
332 | cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? | ||
333 | 0 : 1); | ||
334 | pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", | ||
335 | cmd.skip_dtim_periods); | ||
336 | pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", | ||
337 | iwlmvm_mod_params.power_scheme); | ||
338 | pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", | ||
339 | le16_to_cpu(cmd.flags)); | ||
340 | pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", | ||
341 | le16_to_cpu(cmd.keep_alive_seconds)); | ||
342 | |||
343 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
344 | pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", | ||
345 | (cmd.flags & | ||
346 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? | ||
347 | 1 : 0); | ||
348 | pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", | ||
349 | le32_to_cpu(cmd.rx_data_timeout)); | ||
350 | pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", | ||
351 | le32_to_cpu(cmd.tx_data_timeout)); | ||
352 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | ||
353 | pos += scnprintf(buf+pos, bufsz-pos, | ||
354 | "lprx_rssi_threshold = %d\n", | ||
355 | cmd.lprx_rssi_threshold); | ||
356 | } | ||
357 | return pos; | ||
358 | } | ||
359 | |||
318 | void | 360 | void |
319 | iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | 361 | iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, |
320 | struct iwl_beacon_filter_cmd *cmd) | 362 | struct iwl_beacon_filter_cmd *cmd) |
@@ -382,3 +424,11 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | |||
382 | 424 | ||
383 | return ret; | 425 | return ret; |
384 | } | 426 | } |
427 | |||
428 | const struct iwl_mvm_power_ops pm_mac_ops = { | ||
429 | .power_update_mode = iwl_mvm_power_mac_update_mode, | ||
430 | .power_disable = iwl_mvm_power_mac_disable, | ||
431 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
432 | .power_dbgfs_read = iwl_mvm_power_mac_dbgfs_read, | ||
433 | #endif | ||
434 | }; | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c new file mode 100644 index 000000000000..2ce79bad5845 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called COPYING. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include <linux/kernel.h> | ||
65 | #include <linux/module.h> | ||
66 | #include <linux/slab.h> | ||
67 | #include <linux/init.h> | ||
68 | |||
69 | #include <net/mac80211.h> | ||
70 | |||
71 | #include "iwl-debug.h" | ||
72 | #include "mvm.h" | ||
73 | #include "iwl-modparams.h" | ||
74 | #include "fw-api-power.h" | ||
75 | |||
76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 | ||
77 | |||
78 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, | ||
79 | struct iwl_powertable_cmd *cmd) | ||
80 | { | ||
81 | IWL_DEBUG_POWER(mvm, | ||
82 | "Sending power table command for power level %d, flags = 0x%X\n", | ||
83 | iwlmvm_mod_params.power_scheme, | ||
84 | le16_to_cpu(cmd->flags)); | ||
85 | IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", cmd->keep_alive_seconds); | ||
86 | |||
87 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
88 | IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n", | ||
89 | le32_to_cpu(cmd->rx_data_timeout)); | ||
90 | IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n", | ||
91 | le32_to_cpu(cmd->tx_data_timeout)); | ||
92 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) | ||
93 | IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", | ||
94 | le32_to_cpu(cmd->skip_dtim_periods)); | ||
95 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | ||
96 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", | ||
97 | le32_to_cpu(cmd->lprx_rssi_threshold)); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, | ||
102 | struct ieee80211_vif *vif, | ||
103 | struct iwl_powertable_cmd *cmd) | ||
104 | { | ||
105 | struct ieee80211_hw *hw = mvm->hw; | ||
106 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
107 | struct ieee80211_channel *chan; | ||
108 | int dtimper, dtimper_msec; | ||
109 | int keep_alive; | ||
110 | bool radar_detect = false; | ||
111 | struct iwl_mvm_vif *mvmvif __maybe_unused = | ||
112 | iwl_mvm_vif_from_mac80211(vif); | ||
113 | |||
114 | /* | ||
115 | * Regardless of power management state the driver must set | ||
116 | * keep alive period. FW will use it for sending keep alive NDPs | ||
117 | * immediately after association. | ||
118 | */ | ||
119 | cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC; | ||
120 | |||
121 | if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) | ||
122 | return; | ||
123 | |||
124 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
125 | if (!vif->bss_conf.assoc) | ||
126 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | ||
127 | |||
128 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
129 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | ||
130 | mvmvif->dbgfs_pm.disable_power_off) | ||
131 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
132 | #endif | ||
133 | if (!vif->bss_conf.ps) | ||
134 | return; | ||
135 | |||
136 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | ||
137 | |||
138 | if (vif->bss_conf.beacon_rate && | ||
139 | (vif->bss_conf.beacon_rate->bitrate == 10 || | ||
140 | vif->bss_conf.beacon_rate->bitrate == 60)) { | ||
141 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); | ||
142 | cmd->lprx_rssi_threshold = | ||
143 | cpu_to_le32(POWER_LPRX_RSSI_THRESHOLD); | ||
144 | } | ||
145 | |||
146 | dtimper = hw->conf.ps_dtim_period ?: 1; | ||
147 | |||
148 | /* Check if radar detection is required on current channel */ | ||
149 | rcu_read_lock(); | ||
150 | chanctx_conf = rcu_dereference(vif->chanctx_conf); | ||
151 | WARN_ON(!chanctx_conf); | ||
152 | if (chanctx_conf) { | ||
153 | chan = chanctx_conf->def.chan; | ||
154 | radar_detect = chan->flags & IEEE80211_CHAN_RADAR; | ||
155 | } | ||
156 | rcu_read_unlock(); | ||
157 | |||
158 | /* Check skip over DTIM conditions */ | ||
159 | if (!radar_detect && (dtimper <= 10) && | ||
160 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || | ||
161 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { | ||
162 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
163 | cmd->skip_dtim_periods = cpu_to_le32(3); | ||
164 | } | ||
165 | |||
166 | /* Check that keep alive period is at least 3 * DTIM */ | ||
167 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | ||
168 | keep_alive = max_t(int, 3 * dtimper_msec, | ||
169 | MSEC_PER_SEC * cmd->keep_alive_seconds); | ||
170 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | ||
171 | cmd->keep_alive_seconds = keep_alive; | ||
172 | |||
173 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { | ||
174 | cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | ||
175 | cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | ||
176 | } else { | ||
177 | cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); | ||
178 | cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); | ||
179 | } | ||
180 | |||
181 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
182 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) | ||
183 | cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds; | ||
184 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { | ||
185 | if (mvmvif->dbgfs_pm.skip_over_dtim) | ||
186 | cmd->flags |= | ||
187 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
188 | else | ||
189 | cmd->flags &= | ||
190 | cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
191 | } | ||
192 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT) | ||
193 | cmd->rx_data_timeout = | ||
194 | cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout); | ||
195 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT) | ||
196 | cmd->tx_data_timeout = | ||
197 | cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); | ||
198 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) | ||
199 | cmd->skip_dtim_periods = | ||
200 | cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods); | ||
201 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_ENA) { | ||
202 | if (mvmvif->dbgfs_pm.lprx_ena) | ||
203 | cmd->flags |= cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK); | ||
204 | else | ||
205 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_LPRX_ENA_MSK); | ||
206 | } | ||
207 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD) | ||
208 | cmd->lprx_rssi_threshold = | ||
209 | cpu_to_le32(mvmvif->dbgfs_pm.lprx_rssi_threshold); | ||
210 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | ||
211 | } | ||
212 | |||
213 | static int iwl_mvm_power_legacy_update_mode(struct iwl_mvm *mvm, | ||
214 | struct ieee80211_vif *vif) | ||
215 | { | ||
216 | int ret; | ||
217 | bool ba_enable; | ||
218 | struct iwl_powertable_cmd cmd = {}; | ||
219 | |||
220 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
221 | return 0; | ||
222 | |||
223 | /* | ||
224 | * TODO: The following vif_count verification is temporary condition. | ||
225 | * Avoid power mode update if more than one interface is currently | ||
226 | * active. Remove this condition when FW will support power management | ||
227 | * on multiple MACs. | ||
228 | */ | ||
229 | IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n", | ||
230 | mvm->vif_count); | ||
231 | if (mvm->vif_count > 1) | ||
232 | return 0; | ||
233 | |||
234 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | ||
235 | iwl_mvm_power_log(mvm, &cmd); | ||
236 | |||
237 | ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | ||
238 | sizeof(cmd), &cmd); | ||
239 | if (ret) | ||
240 | return ret; | ||
241 | |||
242 | ba_enable = !!(cmd.flags & | ||
243 | cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); | ||
244 | |||
245 | return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); | ||
246 | } | ||
247 | |||
248 | static int iwl_mvm_power_legacy_disable(struct iwl_mvm *mvm, | ||
249 | struct ieee80211_vif *vif) | ||
250 | { | ||
251 | struct iwl_powertable_cmd cmd = {}; | ||
252 | struct iwl_mvm_vif *mvmvif __maybe_unused = | ||
253 | iwl_mvm_vif_from_mac80211(vif); | ||
254 | |||
255 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
256 | return 0; | ||
257 | |||
258 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) | ||
259 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
260 | |||
261 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
262 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | ||
263 | mvmvif->dbgfs_pm.disable_power_off) | ||
264 | cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
265 | #endif | ||
266 | iwl_mvm_power_log(mvm, &cmd); | ||
267 | |||
268 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, | ||
269 | sizeof(cmd), &cmd); | ||
270 | } | ||
271 | |||
272 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
273 | static int iwl_mvm_power_legacy_dbgfs_read(struct iwl_mvm *mvm, | ||
274 | struct ieee80211_vif *vif, char *buf, | ||
275 | int bufsz) | ||
276 | { | ||
277 | struct iwl_powertable_cmd cmd = {}; | ||
278 | int pos = 0; | ||
279 | |||
280 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | ||
281 | |||
282 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", | ||
283 | (cmd.flags & | ||
284 | cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? | ||
285 | 0 : 1); | ||
286 | pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", | ||
287 | le32_to_cpu(cmd.skip_dtim_periods)); | ||
288 | pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", | ||
289 | iwlmvm_mod_params.power_scheme); | ||
290 | pos += scnprintf(buf+pos, bufsz-pos, "flags = 0x%x\n", | ||
291 | le16_to_cpu(cmd.flags)); | ||
292 | pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", | ||
293 | cmd.keep_alive_seconds); | ||
294 | |||
295 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
296 | pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", | ||
297 | (cmd.flags & | ||
298 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? | ||
299 | 1 : 0); | ||
300 | pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", | ||
301 | le32_to_cpu(cmd.rx_data_timeout)); | ||
302 | pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", | ||
303 | le32_to_cpu(cmd.tx_data_timeout)); | ||
304 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_LPRX_ENA_MSK)) | ||
305 | pos += scnprintf(buf+pos, bufsz-pos, | ||
306 | "lprx_rssi_threshold = %d\n", | ||
307 | le32_to_cpu(cmd.lprx_rssi_threshold)); | ||
308 | } | ||
309 | return pos; | ||
310 | } | ||
311 | #endif | ||
312 | |||
313 | const struct iwl_mvm_power_ops pm_legacy_ops = { | ||
314 | .power_update_mode = iwl_mvm_power_legacy_update_mode, | ||
315 | .power_disable = iwl_mvm_power_legacy_disable, | ||
316 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
317 | .power_dbgfs_read = iwl_mvm_power_legacy_dbgfs_read, | ||
318 | #endif | ||
319 | }; | ||