diff options
Diffstat (limited to 'drivers/net/wireless/iwlegacy/common.c')
-rw-r--r-- | drivers/net/wireless/iwlegacy/common.c | 83 |
1 files changed, 69 insertions, 14 deletions
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 02e8233ccf29..4f42174d9994 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c | |||
@@ -1078,29 +1078,82 @@ EXPORT_SYMBOL(il_get_channel_info); | |||
1078 | * Setting power level allows the card to go to sleep when not busy. | 1078 | * Setting power level allows the card to go to sleep when not busy. |
1079 | * | 1079 | * |
1080 | * We calculate a sleep command based on the required latency, which | 1080 | * We calculate a sleep command based on the required latency, which |
1081 | * we get from mac80211. In order to handle thermal throttling, we can | 1081 | * we get from mac80211. |
1082 | * also use pre-defined power levels. | ||
1083 | */ | 1082 | */ |
1084 | 1083 | ||
1085 | /* | 1084 | #define SLP_VEC(X0, X1, X2, X3, X4) { \ |
1086 | * This defines the old power levels. They are still used by default | 1085 | cpu_to_le32(X0), \ |
1087 | * (level 1) and for thermal throttle (levels 3 through 5) | 1086 | cpu_to_le32(X1), \ |
1088 | */ | 1087 | cpu_to_le32(X2), \ |
1089 | 1088 | cpu_to_le32(X3), \ | |
1090 | struct il_power_vec_entry { | 1089 | cpu_to_le32(X4) \ |
1091 | struct il_powertable_cmd cmd; | 1090 | } |
1092 | u8 no_dtim; /* number of skip dtim */ | ||
1093 | }; | ||
1094 | 1091 | ||
1095 | static void | 1092 | static void |
1096 | il_power_sleep_cam_cmd(struct il_priv *il, struct il_powertable_cmd *cmd) | 1093 | il_build_powertable_cmd(struct il_priv *il, struct il_powertable_cmd *cmd) |
1097 | { | 1094 | { |
1095 | const __le32 interval[3][IL_POWER_VEC_SIZE] = { | ||
1096 | SLP_VEC(2, 2, 4, 6, 0xFF), | ||
1097 | SLP_VEC(2, 4, 7, 10, 10), | ||
1098 | SLP_VEC(4, 7, 10, 10, 0xFF) | ||
1099 | }; | ||
1100 | int i, dtim_period, no_dtim; | ||
1101 | u32 max_sleep; | ||
1102 | bool skip; | ||
1103 | |||
1098 | memset(cmd, 0, sizeof(*cmd)); | 1104 | memset(cmd, 0, sizeof(*cmd)); |
1099 | 1105 | ||
1100 | if (il->power_data.pci_pm) | 1106 | if (il->power_data.pci_pm) |
1101 | cmd->flags |= IL_POWER_PCI_PM_MSK; | 1107 | cmd->flags |= IL_POWER_PCI_PM_MSK; |
1102 | 1108 | ||
1103 | D_POWER("Sleep command for CAM\n"); | 1109 | /* if no Power Save, we are done */ |
1110 | if (il->power_data.ps_disabled) | ||
1111 | return; | ||
1112 | |||
1113 | cmd->flags = IL_POWER_DRIVER_ALLOW_SLEEP_MSK; | ||
1114 | cmd->keep_alive_seconds = 0; | ||
1115 | cmd->debug_flags = 0; | ||
1116 | cmd->rx_data_timeout = cpu_to_le32(25 * 1024); | ||
1117 | cmd->tx_data_timeout = cpu_to_le32(25 * 1024); | ||
1118 | cmd->keep_alive_beacons = 0; | ||
1119 | |||
1120 | dtim_period = il->vif ? il->vif->bss_conf.dtim_period : 0; | ||
1121 | |||
1122 | if (dtim_period <= 2) { | ||
1123 | memcpy(cmd->sleep_interval, interval[0], sizeof(interval[0])); | ||
1124 | no_dtim = 2; | ||
1125 | } else if (dtim_period <= 10) { | ||
1126 | memcpy(cmd->sleep_interval, interval[1], sizeof(interval[1])); | ||
1127 | no_dtim = 2; | ||
1128 | } else { | ||
1129 | memcpy(cmd->sleep_interval, interval[2], sizeof(interval[2])); | ||
1130 | no_dtim = 0; | ||
1131 | } | ||
1132 | |||
1133 | if (dtim_period == 0) { | ||
1134 | dtim_period = 1; | ||
1135 | skip = false; | ||
1136 | } else { | ||
1137 | skip = !!no_dtim; | ||
1138 | } | ||
1139 | |||
1140 | if (skip) { | ||
1141 | __le32 tmp = cmd->sleep_interval[IL_POWER_VEC_SIZE - 1]; | ||
1142 | |||
1143 | max_sleep = le32_to_cpu(tmp); | ||
1144 | if (max_sleep == 0xFF) | ||
1145 | max_sleep = dtim_period * (skip + 1); | ||
1146 | else if (max_sleep > dtim_period) | ||
1147 | max_sleep = (max_sleep / dtim_period) * dtim_period; | ||
1148 | cmd->flags |= IL_POWER_SLEEP_OVER_DTIM_MSK; | ||
1149 | } else { | ||
1150 | max_sleep = dtim_period; | ||
1151 | cmd->flags &= ~IL_POWER_SLEEP_OVER_DTIM_MSK; | ||
1152 | } | ||
1153 | |||
1154 | for (i = 0; i < IL_POWER_VEC_SIZE; i++) | ||
1155 | if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep) | ||
1156 | cmd->sleep_interval[i] = cpu_to_le32(max_sleep); | ||
1104 | } | 1157 | } |
1105 | 1158 | ||
1106 | static int | 1159 | static int |
@@ -1173,7 +1226,8 @@ il_power_update_mode(struct il_priv *il, bool force) | |||
1173 | { | 1226 | { |
1174 | struct il_powertable_cmd cmd; | 1227 | struct il_powertable_cmd cmd; |
1175 | 1228 | ||
1176 | il_power_sleep_cam_cmd(il, &cmd); | 1229 | il_build_powertable_cmd(il, &cmd); |
1230 | |||
1177 | return il_power_set_mode(il, &cmd, force); | 1231 | return il_power_set_mode(il, &cmd, force); |
1178 | } | 1232 | } |
1179 | EXPORT_SYMBOL(il_power_update_mode); | 1233 | EXPORT_SYMBOL(il_power_update_mode); |
@@ -5081,6 +5135,7 @@ set_ch_out: | |||
5081 | } | 5135 | } |
5082 | 5136 | ||
5083 | if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) { | 5137 | if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) { |
5138 | il->power_data.ps_disabled = !(conf->flags & IEEE80211_CONF_PS); | ||
5084 | ret = il_power_update_mode(il, false); | 5139 | ret = il_power_update_mode(il, false); |
5085 | if (ret) | 5140 | if (ret) |
5086 | D_MAC80211("Error setting sleep level\n"); | 5141 | D_MAC80211("Error setting sleep level\n"); |