diff options
author | Sujith <Sujith.Manoharan@atheros.com> | 2010-06-01 05:44:11 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-06-03 14:10:47 -0400 |
commit | 881ac6a53587acb12b009a3053830295688f2c70 (patch) | |
tree | e676fee215db1f8f33bd79d9daa24b9733de1afd | |
parent | e9141f71f4734584bc9704e1266090abe98e1859 (diff) |
ath9k_htc: Revamp CONF_IDLE handling
This patch revamps IDLE power save handling in the driver.
Two separate functions (radio enable/disable) are introduced,
because the semantics of radio handling is just not the same
as the start()/stop() callbacks. For example, the HW must not
be disabled, instead, the PHY has to be disabled in radio_disable().
Also, the HW has to be reset properly in radio enable/disable and
certain registers have to be programmed only once, in the
start() callback.
The radio_enable() routine doesn't need the PS wrappers since
we set the HW power mode to AWAKE anyway before calling it.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 129 |
1 files changed, 93 insertions, 36 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 6d464237d13a..ae84c7bf355a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -1052,6 +1052,89 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv) | |||
1052 | wiphy_rfkill_start_polling(priv->hw->wiphy); | 1052 | wiphy_rfkill_start_polling(priv->hw->wiphy); |
1053 | } | 1053 | } |
1054 | 1054 | ||
1055 | static void ath9k_htc_radio_enable(struct ieee80211_hw *hw) | ||
1056 | { | ||
1057 | struct ath9k_htc_priv *priv = hw->priv; | ||
1058 | struct ath_hw *ah = priv->ah; | ||
1059 | struct ath_common *common = ath9k_hw_common(ah); | ||
1060 | int ret; | ||
1061 | u8 cmd_rsp; | ||
1062 | |||
1063 | if (!ah->curchan) | ||
1064 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | ||
1065 | |||
1066 | /* Reset the HW */ | ||
1067 | ret = ath9k_hw_reset(ah, ah->curchan, false); | ||
1068 | if (ret) { | ||
1069 | ath_print(common, ATH_DBG_FATAL, | ||
1070 | "Unable to reset hardware; reset status %d " | ||
1071 | "(freq %u MHz)\n", ret, ah->curchan->channel); | ||
1072 | } | ||
1073 | |||
1074 | ath_update_txpow(priv); | ||
1075 | |||
1076 | /* Start RX */ | ||
1077 | WMI_CMD(WMI_START_RECV_CMDID); | ||
1078 | ath9k_host_rx_init(priv); | ||
1079 | |||
1080 | /* Start TX */ | ||
1081 | htc_start(priv->htc); | ||
1082 | spin_lock_bh(&priv->tx_lock); | ||
1083 | priv->tx_queues_stop = false; | ||
1084 | spin_unlock_bh(&priv->tx_lock); | ||
1085 | ieee80211_wake_queues(hw); | ||
1086 | |||
1087 | WMI_CMD(WMI_ENABLE_INTR_CMDID); | ||
1088 | |||
1089 | /* Enable LED */ | ||
1090 | ath9k_hw_cfg_output(ah, ah->led_pin, | ||
1091 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1092 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); | ||
1093 | } | ||
1094 | |||
1095 | static void ath9k_htc_radio_disable(struct ieee80211_hw *hw) | ||
1096 | { | ||
1097 | struct ath9k_htc_priv *priv = hw->priv; | ||
1098 | struct ath_hw *ah = priv->ah; | ||
1099 | struct ath_common *common = ath9k_hw_common(ah); | ||
1100 | int ret; | ||
1101 | u8 cmd_rsp; | ||
1102 | |||
1103 | ath9k_htc_ps_wakeup(priv); | ||
1104 | |||
1105 | /* Disable LED */ | ||
1106 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | ||
1107 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | ||
1108 | |||
1109 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
1110 | |||
1111 | /* Stop TX */ | ||
1112 | ieee80211_stop_queues(hw); | ||
1113 | htc_stop(priv->htc); | ||
1114 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | ||
1115 | skb_queue_purge(&priv->tx_queue); | ||
1116 | |||
1117 | /* Stop RX */ | ||
1118 | WMI_CMD(WMI_STOP_RECV_CMDID); | ||
1119 | |||
1120 | if (!ah->curchan) | ||
1121 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | ||
1122 | |||
1123 | /* Reset the HW */ | ||
1124 | ret = ath9k_hw_reset(ah, ah->curchan, false); | ||
1125 | if (ret) { | ||
1126 | ath_print(common, ATH_DBG_FATAL, | ||
1127 | "Unable to reset hardware; reset status %d " | ||
1128 | "(freq %u MHz)\n", ret, ah->curchan->channel); | ||
1129 | } | ||
1130 | |||
1131 | /* Disable the PHY */ | ||
1132 | ath9k_hw_phy_disable(ah); | ||
1133 | |||
1134 | ath9k_htc_ps_restore(priv); | ||
1135 | ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); | ||
1136 | } | ||
1137 | |||
1055 | /**********************/ | 1138 | /**********************/ |
1056 | /* mac80211 Callbacks */ | 1139 | /* mac80211 Callbacks */ |
1057 | /**********************/ | 1140 | /**********************/ |
@@ -1097,7 +1180,7 @@ fail_tx: | |||
1097 | return 0; | 1180 | return 0; |
1098 | } | 1181 | } |
1099 | 1182 | ||
1100 | static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) | 1183 | static int ath9k_htc_start(struct ieee80211_hw *hw) |
1101 | { | 1184 | { |
1102 | struct ath9k_htc_priv *priv = hw->priv; | 1185 | struct ath9k_htc_priv *priv = hw->priv; |
1103 | struct ath_hw *ah = priv->ah; | 1186 | struct ath_hw *ah = priv->ah; |
@@ -1109,6 +1192,8 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) | |||
1109 | __be16 htc_mode; | 1192 | __be16 htc_mode; |
1110 | u8 cmd_rsp; | 1193 | u8 cmd_rsp; |
1111 | 1194 | ||
1195 | mutex_lock(&priv->mutex); | ||
1196 | |||
1112 | ath_print(common, ATH_DBG_CONFIG, | 1197 | ath_print(common, ATH_DBG_CONFIG, |
1113 | "Starting driver with initial channel: %d MHz\n", | 1198 | "Starting driver with initial channel: %d MHz\n", |
1114 | curchan->center_freq); | 1199 | curchan->center_freq); |
@@ -1125,6 +1210,7 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) | |||
1125 | ath_print(common, ATH_DBG_FATAL, | 1210 | ath_print(common, ATH_DBG_FATAL, |
1126 | "Unable to reset hardware; reset status %d " | 1211 | "Unable to reset hardware; reset status %d " |
1127 | "(freq %u MHz)\n", ret, curchan->center_freq); | 1212 | "(freq %u MHz)\n", ret, curchan->center_freq); |
1213 | mutex_unlock(&priv->mutex); | ||
1128 | return ret; | 1214 | return ret; |
1129 | } | 1215 | } |
1130 | 1216 | ||
@@ -1145,31 +1231,14 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) | |||
1145 | priv->tx_queues_stop = false; | 1231 | priv->tx_queues_stop = false; |
1146 | spin_unlock_bh(&priv->tx_lock); | 1232 | spin_unlock_bh(&priv->tx_lock); |
1147 | 1233 | ||
1148 | if (led) { | ||
1149 | /* Enable LED */ | ||
1150 | ath9k_hw_cfg_output(ah, ah->led_pin, | ||
1151 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1152 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); | ||
1153 | } | ||
1154 | |||
1155 | ieee80211_wake_queues(hw); | 1234 | ieee80211_wake_queues(hw); |
1156 | 1235 | ||
1157 | return ret; | ||
1158 | } | ||
1159 | |||
1160 | static int ath9k_htc_start(struct ieee80211_hw *hw) | ||
1161 | { | ||
1162 | struct ath9k_htc_priv *priv = hw->priv; | ||
1163 | int ret = 0; | ||
1164 | |||
1165 | mutex_lock(&priv->mutex); | ||
1166 | ret = ath9k_htc_radio_enable(hw, false); | ||
1167 | mutex_unlock(&priv->mutex); | 1236 | mutex_unlock(&priv->mutex); |
1168 | 1237 | ||
1169 | return ret; | 1238 | return ret; |
1170 | } | 1239 | } |
1171 | 1240 | ||
1172 | static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led) | 1241 | static void ath9k_htc_stop(struct ieee80211_hw *hw) |
1173 | { | 1242 | { |
1174 | struct ath9k_htc_priv *priv = hw->priv; | 1243 | struct ath9k_htc_priv *priv = hw->priv; |
1175 | struct ath_hw *ah = priv->ah; | 1244 | struct ath_hw *ah = priv->ah; |
@@ -1177,17 +1246,14 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led) | |||
1177 | int ret = 0; | 1246 | int ret = 0; |
1178 | u8 cmd_rsp; | 1247 | u8 cmd_rsp; |
1179 | 1248 | ||
1249 | mutex_lock(&priv->mutex); | ||
1250 | |||
1180 | if (priv->op_flags & OP_INVALID) { | 1251 | if (priv->op_flags & OP_INVALID) { |
1181 | ath_print(common, ATH_DBG_ANY, "Device not present\n"); | 1252 | ath_print(common, ATH_DBG_ANY, "Device not present\n"); |
1253 | mutex_unlock(&priv->mutex); | ||
1182 | return; | 1254 | return; |
1183 | } | 1255 | } |
1184 | 1256 | ||
1185 | if (led) { | ||
1186 | /* Disable LED */ | ||
1187 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | ||
1188 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | ||
1189 | } | ||
1190 | |||
1191 | /* Cancel all the running timers/work .. */ | 1257 | /* Cancel all the running timers/work .. */ |
1192 | cancel_work_sync(&priv->ps_work); | 1258 | cancel_work_sync(&priv->ps_work); |
1193 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | 1259 | cancel_delayed_work_sync(&priv->ath9k_ani_work); |
@@ -1221,18 +1287,9 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led) | |||
1221 | priv->op_flags |= OP_INVALID; | 1287 | priv->op_flags |= OP_INVALID; |
1222 | 1288 | ||
1223 | ath_print(common, ATH_DBG_CONFIG, "Driver halt\n"); | 1289 | ath_print(common, ATH_DBG_CONFIG, "Driver halt\n"); |
1224 | } | ||
1225 | |||
1226 | static void ath9k_htc_stop(struct ieee80211_hw *hw) | ||
1227 | { | ||
1228 | struct ath9k_htc_priv *priv = hw->priv; | ||
1229 | |||
1230 | mutex_lock(&priv->mutex); | ||
1231 | ath9k_htc_radio_disable(hw, false); | ||
1232 | mutex_unlock(&priv->mutex); | 1290 | mutex_unlock(&priv->mutex); |
1233 | } | 1291 | } |
1234 | 1292 | ||
1235 | |||
1236 | static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | 1293 | static int ath9k_htc_add_interface(struct ieee80211_hw *hw, |
1237 | struct ieee80211_vif *vif) | 1294 | struct ieee80211_vif *vif) |
1238 | { | 1295 | { |
@@ -1348,7 +1405,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) | |||
1348 | 1405 | ||
1349 | if (enable_radio) { | 1406 | if (enable_radio) { |
1350 | ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); | 1407 | ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); |
1351 | ath9k_htc_radio_enable(hw, true); | 1408 | ath9k_htc_radio_enable(hw); |
1352 | ath_print(common, ATH_DBG_CONFIG, | 1409 | ath_print(common, ATH_DBG_CONFIG, |
1353 | "not-idle: enabling radio\n"); | 1410 | "not-idle: enabling radio\n"); |
1354 | } | 1411 | } |
@@ -1396,7 +1453,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) | |||
1396 | if (priv->ps_idle) { | 1453 | if (priv->ps_idle) { |
1397 | ath_print(common, ATH_DBG_CONFIG, | 1454 | ath_print(common, ATH_DBG_CONFIG, |
1398 | "idle: disabling radio\n"); | 1455 | "idle: disabling radio\n"); |
1399 | ath9k_htc_radio_disable(hw, true); | 1456 | ath9k_htc_radio_disable(hw); |
1400 | } | 1457 | } |
1401 | 1458 | ||
1402 | mutex_unlock(&priv->mutex); | 1459 | mutex_unlock(&priv->mutex); |