aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlegacy/common.c
diff options
context:
space:
mode:
authorStanislaw Gruszka <sgruszka@redhat.com>2014-02-19 03:15:11 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-02-24 15:21:55 -0500
commitdbdac2b581811e1f2a573454451136c2497de4fc (patch)
treefe9d80baf342f26d5db00729ed0c98eb57c06312 /drivers/net/wireless/iwlegacy/common.c
parent8e67427aca2f0dda148181af930732734f6e2e42 (diff)
iwlegacy: properly enable power saving
Even if we mark PS on, device still worked in normal mode. Patch corrects that and now we send proper powertable command to device, which put it in sleep mode when PS is on. Reported-and-tested-by: Tino Keitel <tino.keitel@tikei.de> Tested-by: Pedro Francisco <pedrogfrancisco@gmail.com> Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlegacy/common.c')
-rw-r--r--drivers/net/wireless/iwlegacy/common.c83
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), \
1090struct 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
1095static void 1092static void
1096il_power_sleep_cam_cmd(struct il_priv *il, struct il_powertable_cmd *cmd) 1093il_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
1106static int 1159static 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}
1179EXPORT_SYMBOL(il_power_update_mode); 1233EXPORT_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");