aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSujith <Sujith.Manoharan@atheros.com>2010-06-01 05:44:11 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-03 14:10:47 -0400
commit881ac6a53587acb12b009a3053830295688f2c70 (patch)
treee676fee215db1f8f33bd79d9daa24b9733de1afd
parente9141f71f4734584bc9704e1266090abe98e1859 (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.c129
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
1055static 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
1095static 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
1100static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) 1183static 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
1160static 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
1172static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led) 1241static 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
1226static 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
1236static int ath9k_htc_add_interface(struct ieee80211_hw *hw, 1293static 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);