diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/htc_drv_main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 397 |
1 files changed, 249 insertions, 148 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 9d371c18eb4..7aefbc63877 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -325,133 +325,122 @@ static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) | |||
325 | tcap.flags_ext = 0x80601000; | 325 | tcap.flags_ext = 0x80601000; |
326 | tcap.ampdu_limit = 0xffff0000; | 326 | tcap.ampdu_limit = 0xffff0000; |
327 | tcap.ampdu_subframes = 20; | 327 | tcap.ampdu_subframes = 20; |
328 | tcap.tx_chainmask_legacy = 1; | 328 | tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask; |
329 | tcap.protmode = 1; | 329 | tcap.protmode = 1; |
330 | tcap.tx_chainmask = 1; | 330 | tcap.tx_chainmask = priv->ah->caps.tx_chainmask; |
331 | 331 | ||
332 | WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap); | 332 | WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap); |
333 | 333 | ||
334 | return ret; | 334 | return ret; |
335 | } | 335 | } |
336 | 336 | ||
337 | static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv, | 337 | static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv, |
338 | struct ieee80211_vif *vif, | 338 | struct ieee80211_sta *sta, |
339 | struct ieee80211_sta *sta) | 339 | struct ath9k_htc_target_rate *trate) |
340 | { | 340 | { |
341 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
342 | struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; | 341 | struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; |
343 | struct ieee80211_supported_band *sband; | 342 | struct ieee80211_supported_band *sband; |
344 | struct ath9k_htc_target_rate trate; | ||
345 | u32 caps = 0; | 343 | u32 caps = 0; |
346 | u8 cmd_rsp; | 344 | int i, j; |
347 | int i, j, ret; | ||
348 | |||
349 | memset(&trate, 0, sizeof(trate)); | ||
350 | 345 | ||
351 | /* Only 2GHz is supported */ | 346 | sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band]; |
352 | sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
353 | 347 | ||
354 | for (i = 0, j = 0; i < sband->n_bitrates; i++) { | 348 | for (i = 0, j = 0; i < sband->n_bitrates; i++) { |
355 | if (sta->supp_rates[sband->band] & BIT(i)) { | 349 | if (sta->supp_rates[sband->band] & BIT(i)) { |
356 | priv->tgt_rate.rates.legacy_rates.rs_rates[j] | 350 | trate->rates.legacy_rates.rs_rates[j] |
357 | = (sband->bitrates[i].bitrate * 2) / 10; | 351 | = (sband->bitrates[i].bitrate * 2) / 10; |
358 | j++; | 352 | j++; |
359 | } | 353 | } |
360 | } | 354 | } |
361 | priv->tgt_rate.rates.legacy_rates.rs_nrates = j; | 355 | trate->rates.legacy_rates.rs_nrates = j; |
362 | 356 | ||
363 | if (sta->ht_cap.ht_supported) { | 357 | if (sta->ht_cap.ht_supported) { |
364 | for (i = 0, j = 0; i < 77; i++) { | 358 | for (i = 0, j = 0; i < 77; i++) { |
365 | if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) | 359 | if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) |
366 | priv->tgt_rate.rates.ht_rates.rs_rates[j++] = i; | 360 | trate->rates.ht_rates.rs_rates[j++] = i; |
367 | if (j == ATH_HTC_RATE_MAX) | 361 | if (j == ATH_HTC_RATE_MAX) |
368 | break; | 362 | break; |
369 | } | 363 | } |
370 | priv->tgt_rate.rates.ht_rates.rs_nrates = j; | 364 | trate->rates.ht_rates.rs_nrates = j; |
371 | 365 | ||
372 | caps = WLAN_RC_HT_FLAG; | 366 | caps = WLAN_RC_HT_FLAG; |
367 | if (priv->ah->caps.tx_chainmask != 1 && | ||
368 | ath9k_hw_getcapability(priv->ah, ATH9K_CAP_DS, 0, NULL)) { | ||
369 | if (sta->ht_cap.mcs.rx_mask[1]) | ||
370 | caps |= WLAN_RC_DS_FLAG; | ||
371 | } | ||
373 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 372 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) |
374 | caps |= WLAN_RC_40_FLAG; | 373 | caps |= WLAN_RC_40_FLAG; |
375 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) | 374 | if (conf_is_ht40(&priv->hw->conf) && |
375 | (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) | ||
376 | caps |= WLAN_RC_SGI_FLAG; | ||
377 | else if (conf_is_ht20(&priv->hw->conf) && | ||
378 | (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)) | ||
376 | caps |= WLAN_RC_SGI_FLAG; | 379 | caps |= WLAN_RC_SGI_FLAG; |
377 | |||
378 | } | 380 | } |
379 | 381 | ||
380 | priv->tgt_rate.sta_index = ista->index; | 382 | trate->sta_index = ista->index; |
381 | priv->tgt_rate.isnew = 1; | 383 | trate->isnew = 1; |
382 | trate = priv->tgt_rate; | 384 | trate->capflags = cpu_to_be32(caps); |
383 | priv->tgt_rate.capflags = cpu_to_be32(caps); | 385 | } |
384 | trate.capflags = cpu_to_be32(caps); | ||
385 | 386 | ||
386 | WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate); | 387 | static int ath9k_htc_send_rate_cmd(struct ath9k_htc_priv *priv, |
388 | struct ath9k_htc_target_rate *trate) | ||
389 | { | ||
390 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
391 | int ret; | ||
392 | u8 cmd_rsp; | ||
393 | |||
394 | WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate); | ||
387 | if (ret) { | 395 | if (ret) { |
388 | ath_print(common, ATH_DBG_FATAL, | 396 | ath_print(common, ATH_DBG_FATAL, |
389 | "Unable to initialize Rate information on target\n"); | 397 | "Unable to initialize Rate information on target\n"); |
390 | return ret; | ||
391 | } | 398 | } |
392 | 399 | ||
393 | ath_print(common, ATH_DBG_CONFIG, | 400 | return ret; |
394 | "Updated target STA: %pM (caps: 0x%x)\n", sta->addr, caps); | ||
395 | return 0; | ||
396 | } | 401 | } |
397 | 402 | ||
398 | static bool check_rc_update(struct ieee80211_hw *hw, bool *cw40) | 403 | static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv, |
404 | struct ieee80211_sta *sta) | ||
399 | { | 405 | { |
400 | struct ath9k_htc_priv *priv = hw->priv; | 406 | struct ath_common *common = ath9k_hw_common(priv->ah); |
401 | struct ieee80211_conf *conf = &hw->conf; | 407 | struct ath9k_htc_target_rate trate; |
402 | 408 | int ret; | |
403 | if (!conf_is_ht(conf)) | ||
404 | return false; | ||
405 | |||
406 | if (!(priv->op_flags & OP_ASSOCIATED) || | ||
407 | (priv->op_flags & OP_SCANNING)) | ||
408 | return false; | ||
409 | 409 | ||
410 | if (conf_is_ht40(conf)) { | 410 | memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); |
411 | if (priv->ah->curchan->chanmode & | 411 | ath9k_htc_setup_rate(priv, sta, &trate); |
412 | (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)) { | 412 | ret = ath9k_htc_send_rate_cmd(priv, &trate); |
413 | return false; | 413 | if (!ret) |
414 | } else { | 414 | ath_print(common, ATH_DBG_CONFIG, |
415 | *cw40 = true; | 415 | "Updated target sta: %pM, rate caps: 0x%X\n", |
416 | return true; | 416 | sta->addr, be32_to_cpu(trate.capflags)); |
417 | } | ||
418 | } else { /* ht20 */ | ||
419 | if (priv->ah->curchan->chanmode & CHANNEL_HT20) | ||
420 | return false; | ||
421 | else | ||
422 | return true; | ||
423 | } | ||
424 | } | 417 | } |
425 | 418 | ||
426 | static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40) | 419 | static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv, |
420 | struct ieee80211_vif *vif, | ||
421 | struct ieee80211_bss_conf *bss_conf) | ||
427 | { | 422 | { |
428 | struct ath9k_htc_target_rate trate; | ||
429 | struct ath_common *common = ath9k_hw_common(priv->ah); | 423 | struct ath_common *common = ath9k_hw_common(priv->ah); |
424 | struct ath9k_htc_target_rate trate; | ||
425 | struct ieee80211_sta *sta; | ||
430 | int ret; | 426 | int ret; |
431 | u32 caps = be32_to_cpu(priv->tgt_rate.capflags); | ||
432 | u8 cmd_rsp; | ||
433 | |||
434 | memset(&trate, 0, sizeof(trate)); | ||
435 | 427 | ||
436 | trate = priv->tgt_rate; | 428 | memset(&trate, 0, sizeof(struct ath9k_htc_target_rate)); |
437 | |||
438 | if (is_cw40) | ||
439 | caps |= WLAN_RC_40_FLAG; | ||
440 | else | ||
441 | caps &= ~WLAN_RC_40_FLAG; | ||
442 | 429 | ||
443 | priv->tgt_rate.capflags = cpu_to_be32(caps); | 430 | rcu_read_lock(); |
444 | trate.capflags = cpu_to_be32(caps); | 431 | sta = ieee80211_find_sta(vif, bss_conf->bssid); |
445 | 432 | if (!sta) { | |
446 | WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate); | 433 | rcu_read_unlock(); |
447 | if (ret) { | ||
448 | ath_print(common, ATH_DBG_FATAL, | ||
449 | "Unable to update Rate information on target\n"); | ||
450 | return; | 434 | return; |
451 | } | 435 | } |
436 | ath9k_htc_setup_rate(priv, sta, &trate); | ||
437 | rcu_read_unlock(); | ||
452 | 438 | ||
453 | ath_print(common, ATH_DBG_CONFIG, "Rate control updated with " | 439 | ret = ath9k_htc_send_rate_cmd(priv, &trate); |
454 | "caps:0x%x on target\n", priv->tgt_rate.capflags); | 440 | if (!ret) |
441 | ath_print(common, ATH_DBG_CONFIG, | ||
442 | "Updated target sta: %pM, rate caps: 0x%X\n", | ||
443 | bss_conf->bssid, be32_to_cpu(trate.capflags)); | ||
455 | } | 444 | } |
456 | 445 | ||
457 | static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv, | 446 | static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv, |
@@ -617,6 +606,19 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, | |||
617 | "%20s : %10u\n", "SKBs dropped", | 606 | "%20s : %10u\n", "SKBs dropped", |
618 | priv->debug.tx_stats.skb_dropped); | 607 | priv->debug.tx_stats.skb_dropped); |
619 | 608 | ||
609 | len += snprintf(buf + len, sizeof(buf) - len, | ||
610 | "%20s : %10u\n", "BE queued", | ||
611 | priv->debug.tx_stats.queue_stats[WME_AC_BE]); | ||
612 | len += snprintf(buf + len, sizeof(buf) - len, | ||
613 | "%20s : %10u\n", "BK queued", | ||
614 | priv->debug.tx_stats.queue_stats[WME_AC_BK]); | ||
615 | len += snprintf(buf + len, sizeof(buf) - len, | ||
616 | "%20s : %10u\n", "VI queued", | ||
617 | priv->debug.tx_stats.queue_stats[WME_AC_VI]); | ||
618 | len += snprintf(buf + len, sizeof(buf) - len, | ||
619 | "%20s : %10u\n", "VO queued", | ||
620 | priv->debug.tx_stats.queue_stats[WME_AC_VO]); | ||
621 | |||
620 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 622 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); |
621 | } | 623 | } |
622 | 624 | ||
@@ -1054,6 +1056,95 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv) | |||
1054 | wiphy_rfkill_start_polling(priv->hw->wiphy); | 1056 | wiphy_rfkill_start_polling(priv->hw->wiphy); |
1055 | } | 1057 | } |
1056 | 1058 | ||
1059 | static void ath9k_htc_radio_enable(struct ieee80211_hw *hw) | ||
1060 | { | ||
1061 | struct ath9k_htc_priv *priv = hw->priv; | ||
1062 | struct ath_hw *ah = priv->ah; | ||
1063 | struct ath_common *common = ath9k_hw_common(ah); | ||
1064 | int ret; | ||
1065 | u8 cmd_rsp; | ||
1066 | |||
1067 | if (!ah->curchan) | ||
1068 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | ||
1069 | |||
1070 | /* Reset the HW */ | ||
1071 | ret = ath9k_hw_reset(ah, ah->curchan, false); | ||
1072 | if (ret) { | ||
1073 | ath_print(common, ATH_DBG_FATAL, | ||
1074 | "Unable to reset hardware; reset status %d " | ||
1075 | "(freq %u MHz)\n", ret, ah->curchan->channel); | ||
1076 | } | ||
1077 | |||
1078 | ath_update_txpow(priv); | ||
1079 | |||
1080 | /* Start RX */ | ||
1081 | WMI_CMD(WMI_START_RECV_CMDID); | ||
1082 | ath9k_host_rx_init(priv); | ||
1083 | |||
1084 | /* Start TX */ | ||
1085 | htc_start(priv->htc); | ||
1086 | spin_lock_bh(&priv->tx_lock); | ||
1087 | priv->tx_queues_stop = false; | ||
1088 | spin_unlock_bh(&priv->tx_lock); | ||
1089 | ieee80211_wake_queues(hw); | ||
1090 | |||
1091 | WMI_CMD(WMI_ENABLE_INTR_CMDID); | ||
1092 | |||
1093 | /* Enable LED */ | ||
1094 | ath9k_hw_cfg_output(ah, ah->led_pin, | ||
1095 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1096 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); | ||
1097 | } | ||
1098 | |||
1099 | static void ath9k_htc_radio_disable(struct ieee80211_hw *hw) | ||
1100 | { | ||
1101 | struct ath9k_htc_priv *priv = hw->priv; | ||
1102 | struct ath_hw *ah = priv->ah; | ||
1103 | struct ath_common *common = ath9k_hw_common(ah); | ||
1104 | int ret; | ||
1105 | u8 cmd_rsp; | ||
1106 | |||
1107 | ath9k_htc_ps_wakeup(priv); | ||
1108 | |||
1109 | /* Disable LED */ | ||
1110 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | ||
1111 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | ||
1112 | |||
1113 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
1114 | |||
1115 | /* Stop TX */ | ||
1116 | ieee80211_stop_queues(hw); | ||
1117 | htc_stop(priv->htc); | ||
1118 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | ||
1119 | skb_queue_purge(&priv->tx_queue); | ||
1120 | |||
1121 | /* Stop RX */ | ||
1122 | WMI_CMD(WMI_STOP_RECV_CMDID); | ||
1123 | |||
1124 | /* | ||
1125 | * The MIB counters have to be disabled here, | ||
1126 | * since the target doesn't do it. | ||
1127 | */ | ||
1128 | ath9k_hw_disable_mib_counters(ah); | ||
1129 | |||
1130 | if (!ah->curchan) | ||
1131 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | ||
1132 | |||
1133 | /* Reset the HW */ | ||
1134 | ret = ath9k_hw_reset(ah, ah->curchan, false); | ||
1135 | if (ret) { | ||
1136 | ath_print(common, ATH_DBG_FATAL, | ||
1137 | "Unable to reset hardware; reset status %d " | ||
1138 | "(freq %u MHz)\n", ret, ah->curchan->channel); | ||
1139 | } | ||
1140 | |||
1141 | /* Disable the PHY */ | ||
1142 | ath9k_hw_phy_disable(ah); | ||
1143 | |||
1144 | ath9k_htc_ps_restore(priv); | ||
1145 | ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); | ||
1146 | } | ||
1147 | |||
1057 | /**********************/ | 1148 | /**********************/ |
1058 | /* mac80211 Callbacks */ | 1149 | /* mac80211 Callbacks */ |
1059 | /**********************/ | 1150 | /**********************/ |
@@ -1099,7 +1190,7 @@ fail_tx: | |||
1099 | return 0; | 1190 | return 0; |
1100 | } | 1191 | } |
1101 | 1192 | ||
1102 | static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) | 1193 | static int ath9k_htc_start(struct ieee80211_hw *hw) |
1103 | { | 1194 | { |
1104 | struct ath9k_htc_priv *priv = hw->priv; | 1195 | struct ath9k_htc_priv *priv = hw->priv; |
1105 | struct ath_hw *ah = priv->ah; | 1196 | struct ath_hw *ah = priv->ah; |
@@ -1111,10 +1202,16 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) | |||
1111 | __be16 htc_mode; | 1202 | __be16 htc_mode; |
1112 | u8 cmd_rsp; | 1203 | u8 cmd_rsp; |
1113 | 1204 | ||
1205 | mutex_lock(&priv->mutex); | ||
1206 | |||
1114 | ath_print(common, ATH_DBG_CONFIG, | 1207 | ath_print(common, ATH_DBG_CONFIG, |
1115 | "Starting driver with initial channel: %d MHz\n", | 1208 | "Starting driver with initial channel: %d MHz\n", |
1116 | curchan->center_freq); | 1209 | curchan->center_freq); |
1117 | 1210 | ||
1211 | /* Ensure that HW is awake before flushing RX */ | ||
1212 | ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); | ||
1213 | WMI_CMD(WMI_FLUSH_RECV_CMDID); | ||
1214 | |||
1118 | /* setup initial channel */ | 1215 | /* setup initial channel */ |
1119 | init_channel = ath9k_cmn_get_curchannel(hw, ah); | 1216 | init_channel = ath9k_cmn_get_curchannel(hw, ah); |
1120 | 1217 | ||
@@ -1127,6 +1224,7 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) | |||
1127 | ath_print(common, ATH_DBG_FATAL, | 1224 | ath_print(common, ATH_DBG_FATAL, |
1128 | "Unable to reset hardware; reset status %d " | 1225 | "Unable to reset hardware; reset status %d " |
1129 | "(freq %u MHz)\n", ret, curchan->center_freq); | 1226 | "(freq %u MHz)\n", ret, curchan->center_freq); |
1227 | mutex_unlock(&priv->mutex); | ||
1130 | return ret; | 1228 | return ret; |
1131 | } | 1229 | } |
1132 | 1230 | ||
@@ -1147,31 +1245,14 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led) | |||
1147 | priv->tx_queues_stop = false; | 1245 | priv->tx_queues_stop = false; |
1148 | spin_unlock_bh(&priv->tx_lock); | 1246 | spin_unlock_bh(&priv->tx_lock); |
1149 | 1247 | ||
1150 | if (led) { | ||
1151 | /* Enable LED */ | ||
1152 | ath9k_hw_cfg_output(ah, ah->led_pin, | ||
1153 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1154 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); | ||
1155 | } | ||
1156 | |||
1157 | ieee80211_wake_queues(hw); | 1248 | ieee80211_wake_queues(hw); |
1158 | 1249 | ||
1159 | return ret; | ||
1160 | } | ||
1161 | |||
1162 | static int ath9k_htc_start(struct ieee80211_hw *hw) | ||
1163 | { | ||
1164 | struct ath9k_htc_priv *priv = hw->priv; | ||
1165 | int ret = 0; | ||
1166 | |||
1167 | mutex_lock(&priv->mutex); | ||
1168 | ret = ath9k_htc_radio_enable(hw, false); | ||
1169 | mutex_unlock(&priv->mutex); | 1250 | mutex_unlock(&priv->mutex); |
1170 | 1251 | ||
1171 | return ret; | 1252 | return ret; |
1172 | } | 1253 | } |
1173 | 1254 | ||
1174 | static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led) | 1255 | static void ath9k_htc_stop(struct ieee80211_hw *hw) |
1175 | { | 1256 | { |
1176 | struct ath9k_htc_priv *priv = hw->priv; | 1257 | struct ath9k_htc_priv *priv = hw->priv; |
1177 | struct ath_hw *ah = priv->ah; | 1258 | struct ath_hw *ah = priv->ah; |
@@ -1179,17 +1260,14 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led) | |||
1179 | int ret = 0; | 1260 | int ret = 0; |
1180 | u8 cmd_rsp; | 1261 | u8 cmd_rsp; |
1181 | 1262 | ||
1263 | mutex_lock(&priv->mutex); | ||
1264 | |||
1182 | if (priv->op_flags & OP_INVALID) { | 1265 | if (priv->op_flags & OP_INVALID) { |
1183 | ath_print(common, ATH_DBG_ANY, "Device not present\n"); | 1266 | ath_print(common, ATH_DBG_ANY, "Device not present\n"); |
1267 | mutex_unlock(&priv->mutex); | ||
1184 | return; | 1268 | return; |
1185 | } | 1269 | } |
1186 | 1270 | ||
1187 | if (led) { | ||
1188 | /* Disable LED */ | ||
1189 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | ||
1190 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | ||
1191 | } | ||
1192 | |||
1193 | /* Cancel all the running timers/work .. */ | 1271 | /* Cancel all the running timers/work .. */ |
1194 | cancel_work_sync(&priv->ps_work); | 1272 | cancel_work_sync(&priv->ps_work); |
1195 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | 1273 | cancel_delayed_work_sync(&priv->ath9k_ani_work); |
@@ -1202,12 +1280,6 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led) | |||
1202 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 1280 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
1203 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | 1281 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); |
1204 | WMI_CMD(WMI_STOP_RECV_CMDID); | 1282 | WMI_CMD(WMI_STOP_RECV_CMDID); |
1205 | ath9k_hw_phy_disable(ah); | ||
1206 | ath9k_hw_disable(ah); | ||
1207 | ath9k_hw_configpcipowersave(ah, 1, 1); | ||
1208 | ath9k_htc_ps_restore(priv); | ||
1209 | ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); | ||
1210 | |||
1211 | skb_queue_purge(&priv->tx_queue); | 1283 | skb_queue_purge(&priv->tx_queue); |
1212 | 1284 | ||
1213 | /* Remove monitor interface here */ | 1285 | /* Remove monitor interface here */ |
@@ -1220,21 +1292,18 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led) | |||
1220 | "Monitor interface removed\n"); | 1292 | "Monitor interface removed\n"); |
1221 | } | 1293 | } |
1222 | 1294 | ||
1295 | ath9k_hw_phy_disable(ah); | ||
1296 | ath9k_hw_disable(ah); | ||
1297 | ath9k_hw_configpcipowersave(ah, 1, 1); | ||
1298 | ath9k_htc_ps_restore(priv); | ||
1299 | ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); | ||
1300 | |||
1223 | priv->op_flags |= OP_INVALID; | 1301 | priv->op_flags |= OP_INVALID; |
1224 | 1302 | ||
1225 | ath_print(common, ATH_DBG_CONFIG, "Driver halt\n"); | 1303 | ath_print(common, ATH_DBG_CONFIG, "Driver halt\n"); |
1226 | } | ||
1227 | |||
1228 | static void ath9k_htc_stop(struct ieee80211_hw *hw) | ||
1229 | { | ||
1230 | struct ath9k_htc_priv *priv = hw->priv; | ||
1231 | |||
1232 | mutex_lock(&priv->mutex); | ||
1233 | ath9k_htc_radio_disable(hw, false); | ||
1234 | mutex_unlock(&priv->mutex); | 1304 | mutex_unlock(&priv->mutex); |
1235 | } | 1305 | } |
1236 | 1306 | ||
1237 | |||
1238 | static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | 1307 | static int ath9k_htc_add_interface(struct ieee80211_hw *hw, |
1239 | struct ieee80211_vif *vif) | 1308 | struct ieee80211_vif *vif) |
1240 | { | 1309 | { |
@@ -1302,6 +1371,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | |||
1302 | out: | 1371 | out: |
1303 | ath9k_htc_ps_restore(priv); | 1372 | ath9k_htc_ps_restore(priv); |
1304 | mutex_unlock(&priv->mutex); | 1373 | mutex_unlock(&priv->mutex); |
1374 | |||
1305 | return ret; | 1375 | return ret; |
1306 | } | 1376 | } |
1307 | 1377 | ||
@@ -1318,6 +1388,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, | |||
1318 | ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); | 1388 | ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); |
1319 | 1389 | ||
1320 | mutex_lock(&priv->mutex); | 1390 | mutex_lock(&priv->mutex); |
1391 | ath9k_htc_ps_wakeup(priv); | ||
1321 | 1392 | ||
1322 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 1393 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); |
1323 | memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); | 1394 | memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); |
@@ -1328,6 +1399,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, | |||
1328 | ath9k_htc_remove_station(priv, vif, NULL); | 1399 | ath9k_htc_remove_station(priv, vif, NULL); |
1329 | priv->vif = NULL; | 1400 | priv->vif = NULL; |
1330 | 1401 | ||
1402 | ath9k_htc_ps_restore(priv); | ||
1331 | mutex_unlock(&priv->mutex); | 1403 | mutex_unlock(&priv->mutex); |
1332 | } | 1404 | } |
1333 | 1405 | ||
@@ -1343,30 +1415,27 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) | |||
1343 | bool enable_radio = false; | 1415 | bool enable_radio = false; |
1344 | bool idle = !!(conf->flags & IEEE80211_CONF_IDLE); | 1416 | bool idle = !!(conf->flags & IEEE80211_CONF_IDLE); |
1345 | 1417 | ||
1418 | mutex_lock(&priv->htc_pm_lock); | ||
1346 | if (!idle && priv->ps_idle) | 1419 | if (!idle && priv->ps_idle) |
1347 | enable_radio = true; | 1420 | enable_radio = true; |
1348 | |||
1349 | priv->ps_idle = idle; | 1421 | priv->ps_idle = idle; |
1422 | mutex_unlock(&priv->htc_pm_lock); | ||
1350 | 1423 | ||
1351 | if (enable_radio) { | 1424 | if (enable_radio) { |
1352 | ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); | ||
1353 | ath9k_htc_radio_enable(hw, true); | ||
1354 | ath_print(common, ATH_DBG_CONFIG, | 1425 | ath_print(common, ATH_DBG_CONFIG, |
1355 | "not-idle: enabling radio\n"); | 1426 | "not-idle: enabling radio\n"); |
1427 | ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); | ||
1428 | ath9k_htc_radio_enable(hw); | ||
1356 | } | 1429 | } |
1357 | } | 1430 | } |
1358 | 1431 | ||
1359 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | 1432 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
1360 | struct ieee80211_channel *curchan = hw->conf.channel; | 1433 | struct ieee80211_channel *curchan = hw->conf.channel; |
1361 | int pos = curchan->hw_value; | 1434 | int pos = curchan->hw_value; |
1362 | bool is_cw40 = false; | ||
1363 | 1435 | ||
1364 | ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", | 1436 | ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", |
1365 | curchan->center_freq); | 1437 | curchan->center_freq); |
1366 | 1438 | ||
1367 | if (check_rc_update(hw, &is_cw40)) | ||
1368 | ath9k_htc_rc_update(priv, is_cw40); | ||
1369 | |||
1370 | ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]); | 1439 | ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]); |
1371 | 1440 | ||
1372 | if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { | 1441 | if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { |
@@ -1399,14 +1468,21 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) | |||
1399 | } | 1468 | } |
1400 | } | 1469 | } |
1401 | 1470 | ||
1402 | if (priv->ps_idle) { | 1471 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { |
1472 | mutex_lock(&priv->htc_pm_lock); | ||
1473 | if (!priv->ps_idle) { | ||
1474 | mutex_unlock(&priv->htc_pm_lock); | ||
1475 | goto out; | ||
1476 | } | ||
1477 | mutex_unlock(&priv->htc_pm_lock); | ||
1478 | |||
1403 | ath_print(common, ATH_DBG_CONFIG, | 1479 | ath_print(common, ATH_DBG_CONFIG, |
1404 | "idle: disabling radio\n"); | 1480 | "idle: disabling radio\n"); |
1405 | ath9k_htc_radio_disable(hw, true); | 1481 | ath9k_htc_radio_disable(hw); |
1406 | } | 1482 | } |
1407 | 1483 | ||
1484 | out: | ||
1408 | mutex_unlock(&priv->mutex); | 1485 | mutex_unlock(&priv->mutex); |
1409 | |||
1410 | return 0; | 1486 | return 0; |
1411 | } | 1487 | } |
1412 | 1488 | ||
@@ -1428,8 +1504,8 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, | |||
1428 | u32 rfilt; | 1504 | u32 rfilt; |
1429 | 1505 | ||
1430 | mutex_lock(&priv->mutex); | 1506 | mutex_lock(&priv->mutex); |
1431 | |||
1432 | ath9k_htc_ps_wakeup(priv); | 1507 | ath9k_htc_ps_wakeup(priv); |
1508 | |||
1433 | changed_flags &= SUPPORTED_FILTERS; | 1509 | changed_flags &= SUPPORTED_FILTERS; |
1434 | *total_flags &= SUPPORTED_FILTERS; | 1510 | *total_flags &= SUPPORTED_FILTERS; |
1435 | 1511 | ||
@@ -1444,30 +1520,38 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, | |||
1444 | mutex_unlock(&priv->mutex); | 1520 | mutex_unlock(&priv->mutex); |
1445 | } | 1521 | } |
1446 | 1522 | ||
1447 | static void ath9k_htc_sta_notify(struct ieee80211_hw *hw, | 1523 | static int ath9k_htc_sta_add(struct ieee80211_hw *hw, |
1448 | struct ieee80211_vif *vif, | 1524 | struct ieee80211_vif *vif, |
1449 | enum sta_notify_cmd cmd, | 1525 | struct ieee80211_sta *sta) |
1450 | struct ieee80211_sta *sta) | ||
1451 | { | 1526 | { |
1452 | struct ath9k_htc_priv *priv = hw->priv; | 1527 | struct ath9k_htc_priv *priv = hw->priv; |
1453 | int ret; | 1528 | int ret; |
1454 | 1529 | ||
1455 | mutex_lock(&priv->mutex); | 1530 | mutex_lock(&priv->mutex); |
1531 | ath9k_htc_ps_wakeup(priv); | ||
1532 | ret = ath9k_htc_add_station(priv, vif, sta); | ||
1533 | if (!ret) | ||
1534 | ath9k_htc_init_rate(priv, sta); | ||
1535 | ath9k_htc_ps_restore(priv); | ||
1536 | mutex_unlock(&priv->mutex); | ||
1456 | 1537 | ||
1457 | switch (cmd) { | 1538 | return ret; |
1458 | case STA_NOTIFY_ADD: | 1539 | } |
1459 | ret = ath9k_htc_add_station(priv, vif, sta); | ||
1460 | if (!ret) | ||
1461 | ath9k_htc_init_rate(priv, vif, sta); | ||
1462 | break; | ||
1463 | case STA_NOTIFY_REMOVE: | ||
1464 | ath9k_htc_remove_station(priv, vif, sta); | ||
1465 | break; | ||
1466 | default: | ||
1467 | break; | ||
1468 | } | ||
1469 | 1540 | ||
1541 | static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, | ||
1542 | struct ieee80211_vif *vif, | ||
1543 | struct ieee80211_sta *sta) | ||
1544 | { | ||
1545 | struct ath9k_htc_priv *priv = hw->priv; | ||
1546 | int ret; | ||
1547 | |||
1548 | mutex_lock(&priv->mutex); | ||
1549 | ath9k_htc_ps_wakeup(priv); | ||
1550 | ret = ath9k_htc_remove_station(priv, vif, sta); | ||
1551 | ath9k_htc_ps_restore(priv); | ||
1470 | mutex_unlock(&priv->mutex); | 1552 | mutex_unlock(&priv->mutex); |
1553 | |||
1554 | return ret; | ||
1471 | } | 1555 | } |
1472 | 1556 | ||
1473 | static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1557 | static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, |
@@ -1482,6 +1566,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1482 | return 0; | 1566 | return 0; |
1483 | 1567 | ||
1484 | mutex_lock(&priv->mutex); | 1568 | mutex_lock(&priv->mutex); |
1569 | ath9k_htc_ps_wakeup(priv); | ||
1485 | 1570 | ||
1486 | memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); | 1571 | memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); |
1487 | 1572 | ||
@@ -1499,9 +1584,16 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1499 | params->cw_max, params->txop); | 1584 | params->cw_max, params->txop); |
1500 | 1585 | ||
1501 | ret = ath_htc_txq_update(priv, qnum, &qi); | 1586 | ret = ath_htc_txq_update(priv, qnum, &qi); |
1502 | if (ret) | 1587 | if (ret) { |
1503 | ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n"); | 1588 | ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n"); |
1589 | goto out; | ||
1590 | } | ||
1504 | 1591 | ||
1592 | if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) && | ||
1593 | (qnum == priv->hwq_map[ATH9K_WME_AC_BE])) | ||
1594 | ath9k_htc_beaconq_config(priv); | ||
1595 | out: | ||
1596 | ath9k_htc_ps_restore(priv); | ||
1505 | mutex_unlock(&priv->mutex); | 1597 | mutex_unlock(&priv->mutex); |
1506 | 1598 | ||
1507 | return ret; | 1599 | return ret; |
@@ -1574,7 +1666,6 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, | |||
1574 | ath_start_ani(priv); | 1666 | ath_start_ani(priv); |
1575 | } else { | 1667 | } else { |
1576 | priv->op_flags &= ~OP_ASSOCIATED; | 1668 | priv->op_flags &= ~OP_ASSOCIATED; |
1577 | cancel_work_sync(&priv->ps_work); | ||
1578 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | 1669 | cancel_delayed_work_sync(&priv->ath9k_ani_work); |
1579 | } | 1670 | } |
1580 | } | 1671 | } |
@@ -1631,6 +1722,9 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, | |||
1631 | ath9k_hw_init_global_settings(ah); | 1722 | ath9k_hw_init_global_settings(ah); |
1632 | } | 1723 | } |
1633 | 1724 | ||
1725 | if (changed & BSS_CHANGED_HT) | ||
1726 | ath9k_htc_update_rate(priv, vif, bss_conf); | ||
1727 | |||
1634 | ath9k_htc_ps_restore(priv); | 1728 | ath9k_htc_ps_restore(priv); |
1635 | mutex_unlock(&priv->mutex); | 1729 | mutex_unlock(&priv->mutex); |
1636 | } | 1730 | } |
@@ -1641,7 +1735,9 @@ static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw) | |||
1641 | u64 tsf; | 1735 | u64 tsf; |
1642 | 1736 | ||
1643 | mutex_lock(&priv->mutex); | 1737 | mutex_lock(&priv->mutex); |
1738 | ath9k_htc_ps_wakeup(priv); | ||
1644 | tsf = ath9k_hw_gettsf64(priv->ah); | 1739 | tsf = ath9k_hw_gettsf64(priv->ah); |
1740 | ath9k_htc_ps_restore(priv); | ||
1645 | mutex_unlock(&priv->mutex); | 1741 | mutex_unlock(&priv->mutex); |
1646 | 1742 | ||
1647 | return tsf; | 1743 | return tsf; |
@@ -1652,7 +1748,9 @@ static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf) | |||
1652 | struct ath9k_htc_priv *priv = hw->priv; | 1748 | struct ath9k_htc_priv *priv = hw->priv; |
1653 | 1749 | ||
1654 | mutex_lock(&priv->mutex); | 1750 | mutex_lock(&priv->mutex); |
1751 | ath9k_htc_ps_wakeup(priv); | ||
1655 | ath9k_hw_settsf64(priv->ah, tsf); | 1752 | ath9k_hw_settsf64(priv->ah, tsf); |
1753 | ath9k_htc_ps_restore(priv); | ||
1656 | mutex_unlock(&priv->mutex); | 1754 | mutex_unlock(&priv->mutex); |
1657 | } | 1755 | } |
1658 | 1756 | ||
@@ -1660,11 +1758,11 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw) | |||
1660 | { | 1758 | { |
1661 | struct ath9k_htc_priv *priv = hw->priv; | 1759 | struct ath9k_htc_priv *priv = hw->priv; |
1662 | 1760 | ||
1663 | ath9k_htc_ps_wakeup(priv); | ||
1664 | mutex_lock(&priv->mutex); | 1761 | mutex_lock(&priv->mutex); |
1762 | ath9k_htc_ps_wakeup(priv); | ||
1665 | ath9k_hw_reset_tsf(priv->ah); | 1763 | ath9k_hw_reset_tsf(priv->ah); |
1666 | mutex_unlock(&priv->mutex); | ||
1667 | ath9k_htc_ps_restore(priv); | 1764 | ath9k_htc_ps_restore(priv); |
1765 | mutex_unlock(&priv->mutex); | ||
1668 | } | 1766 | } |
1669 | 1767 | ||
1670 | static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, | 1768 | static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, |
@@ -1722,8 +1820,8 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) | |||
1722 | { | 1820 | { |
1723 | struct ath9k_htc_priv *priv = hw->priv; | 1821 | struct ath9k_htc_priv *priv = hw->priv; |
1724 | 1822 | ||
1725 | ath9k_htc_ps_wakeup(priv); | ||
1726 | mutex_lock(&priv->mutex); | 1823 | mutex_lock(&priv->mutex); |
1824 | ath9k_htc_ps_wakeup(priv); | ||
1727 | spin_lock_bh(&priv->beacon_lock); | 1825 | spin_lock_bh(&priv->beacon_lock); |
1728 | priv->op_flags &= ~OP_SCANNING; | 1826 | priv->op_flags &= ~OP_SCANNING; |
1729 | spin_unlock_bh(&priv->beacon_lock); | 1827 | spin_unlock_bh(&priv->beacon_lock); |
@@ -1731,8 +1829,8 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) | |||
1731 | if (priv->op_flags & OP_ASSOCIATED) | 1829 | if (priv->op_flags & OP_ASSOCIATED) |
1732 | ath9k_htc_beacon_config(priv, priv->vif); | 1830 | ath9k_htc_beacon_config(priv, priv->vif); |
1733 | ath_start_ani(priv); | 1831 | ath_start_ani(priv); |
1734 | mutex_unlock(&priv->mutex); | ||
1735 | ath9k_htc_ps_restore(priv); | 1832 | ath9k_htc_ps_restore(priv); |
1833 | mutex_unlock(&priv->mutex); | ||
1736 | } | 1834 | } |
1737 | 1835 | ||
1738 | static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | 1836 | static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) |
@@ -1746,8 +1844,10 @@ static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, | |||
1746 | struct ath9k_htc_priv *priv = hw->priv; | 1844 | struct ath9k_htc_priv *priv = hw->priv; |
1747 | 1845 | ||
1748 | mutex_lock(&priv->mutex); | 1846 | mutex_lock(&priv->mutex); |
1847 | ath9k_htc_ps_wakeup(priv); | ||
1749 | priv->ah->coverage_class = coverage_class; | 1848 | priv->ah->coverage_class = coverage_class; |
1750 | ath9k_hw_init_global_settings(priv->ah); | 1849 | ath9k_hw_init_global_settings(priv->ah); |
1850 | ath9k_htc_ps_restore(priv); | ||
1751 | mutex_unlock(&priv->mutex); | 1851 | mutex_unlock(&priv->mutex); |
1752 | } | 1852 | } |
1753 | 1853 | ||
@@ -1759,7 +1859,8 @@ struct ieee80211_ops ath9k_htc_ops = { | |||
1759 | .remove_interface = ath9k_htc_remove_interface, | 1859 | .remove_interface = ath9k_htc_remove_interface, |
1760 | .config = ath9k_htc_config, | 1860 | .config = ath9k_htc_config, |
1761 | .configure_filter = ath9k_htc_configure_filter, | 1861 | .configure_filter = ath9k_htc_configure_filter, |
1762 | .sta_notify = ath9k_htc_sta_notify, | 1862 | .sta_add = ath9k_htc_sta_add, |
1863 | .sta_remove = ath9k_htc_sta_remove, | ||
1763 | .conf_tx = ath9k_htc_conf_tx, | 1864 | .conf_tx = ath9k_htc_conf_tx, |
1764 | .bss_info_changed = ath9k_htc_bss_info_changed, | 1865 | .bss_info_changed = ath9k_htc_bss_info_changed, |
1765 | .set_key = ath9k_htc_set_key, | 1866 | .set_key = ath9k_htc_set_key, |