diff options
| author | David S. Miller <davem@davemloft.net> | 2011-05-05 17:09:28 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-05-05 17:09:28 -0400 |
| commit | 90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2 (patch) | |
| tree | 6951c8d0e529dbfc7c4cec75d4cec63350e39b7c /drivers/net/wireless/ath/carl9170 | |
| parent | 228e548e602061b08ee8e8966f567c12aa079682 (diff) | |
| parent | a70171dce9cd44cb06c7d299eba9fa87a8933045 (diff) | |
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net/wireless/ath/carl9170')
| -rw-r--r-- | drivers/net/wireless/ath/carl9170/carl9170.h | 2 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/carl9170/main.c | 92 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/carl9170/tx.c | 157 |
3 files changed, 112 insertions, 139 deletions
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 3d4ed5863732..bb578690935e 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h | |||
| @@ -448,6 +448,8 @@ struct carl9170_ba_stats { | |||
| 448 | 448 | ||
| 449 | struct carl9170_sta_info { | 449 | struct carl9170_sta_info { |
| 450 | bool ht_sta; | 450 | bool ht_sta; |
| 451 | bool sleeping; | ||
| 452 | atomic_t pending_frames; | ||
| 451 | unsigned int ampdu_max_len; | 453 | unsigned int ampdu_max_len; |
| 452 | struct carl9170_sta_tid *agg[CARL9170_NUM_TID]; | 454 | struct carl9170_sta_tid *agg[CARL9170_NUM_TID]; |
| 453 | struct carl9170_ba_stats stats[CARL9170_NUM_TID]; | 455 | struct carl9170_ba_stats stats[CARL9170_NUM_TID]; |
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 89fe60accf85..1638468be5a3 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c | |||
| @@ -1193,6 +1193,8 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw, | |||
| 1193 | struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; | 1193 | struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; |
| 1194 | unsigned int i; | 1194 | unsigned int i; |
| 1195 | 1195 | ||
| 1196 | atomic_set(&sta_info->pending_frames, 0); | ||
| 1197 | |||
| 1196 | if (sta->ht_cap.ht_supported) { | 1198 | if (sta->ht_cap.ht_supported) { |
| 1197 | if (sta->ht_cap.ampdu_density > 6) { | 1199 | if (sta->ht_cap.ampdu_density > 6) { |
| 1198 | /* | 1200 | /* |
| @@ -1467,99 +1469,17 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw, | |||
| 1467 | enum sta_notify_cmd cmd, | 1469 | enum sta_notify_cmd cmd, |
| 1468 | struct ieee80211_sta *sta) | 1470 | struct ieee80211_sta *sta) |
| 1469 | { | 1471 | { |
| 1470 | struct ar9170 *ar = hw->priv; | ||
| 1471 | struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; | 1472 | struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; |
| 1472 | struct sk_buff *skb, *tmp; | ||
| 1473 | struct sk_buff_head free; | ||
| 1474 | int i; | ||
| 1475 | 1473 | ||
| 1476 | switch (cmd) { | 1474 | switch (cmd) { |
| 1477 | case STA_NOTIFY_SLEEP: | 1475 | case STA_NOTIFY_SLEEP: |
| 1478 | /* | 1476 | sta_info->sleeping = true; |
| 1479 | * Since the peer is no longer listening, we have to return | 1477 | if (atomic_read(&sta_info->pending_frames)) |
| 1480 | * as many SKBs as possible back to the mac80211 stack. | 1478 | ieee80211_sta_block_awake(hw, sta, true); |
| 1481 | * It will deal with the retry procedure, once the peer | ||
| 1482 | * has become available again. | ||
| 1483 | * | ||
| 1484 | * NB: Ideally, the driver should return the all frames in | ||
| 1485 | * the correct, ascending order. However, I think that this | ||
| 1486 | * functionality should be implemented in the stack and not | ||
| 1487 | * here... | ||
| 1488 | */ | ||
| 1489 | |||
| 1490 | __skb_queue_head_init(&free); | ||
| 1491 | |||
| 1492 | if (sta->ht_cap.ht_supported) { | ||
| 1493 | rcu_read_lock(); | ||
| 1494 | for (i = 0; i < CARL9170_NUM_TID; i++) { | ||
| 1495 | struct carl9170_sta_tid *tid_info; | ||
| 1496 | |||
| 1497 | tid_info = rcu_dereference(sta_info->agg[i]); | ||
| 1498 | |||
| 1499 | if (!tid_info) | ||
| 1500 | continue; | ||
| 1501 | |||
| 1502 | spin_lock_bh(&ar->tx_ampdu_list_lock); | ||
| 1503 | if (tid_info->state > | ||
| 1504 | CARL9170_TID_STATE_SUSPEND) | ||
| 1505 | tid_info->state = | ||
| 1506 | CARL9170_TID_STATE_SUSPEND; | ||
| 1507 | spin_unlock_bh(&ar->tx_ampdu_list_lock); | ||
| 1508 | |||
| 1509 | spin_lock_bh(&tid_info->lock); | ||
| 1510 | while ((skb = __skb_dequeue(&tid_info->queue))) | ||
| 1511 | __skb_queue_tail(&free, skb); | ||
| 1512 | spin_unlock_bh(&tid_info->lock); | ||
| 1513 | } | ||
| 1514 | rcu_read_unlock(); | ||
| 1515 | } | ||
| 1516 | |||
| 1517 | for (i = 0; i < ar->hw->queues; i++) { | ||
| 1518 | spin_lock_bh(&ar->tx_pending[i].lock); | ||
| 1519 | skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) { | ||
| 1520 | struct _carl9170_tx_superframe *super; | ||
| 1521 | struct ieee80211_hdr *hdr; | ||
| 1522 | struct ieee80211_tx_info *info; | ||
| 1523 | |||
| 1524 | super = (void *) skb->data; | ||
| 1525 | hdr = (void *) super->frame_data; | ||
| 1526 | |||
| 1527 | if (compare_ether_addr(hdr->addr1, sta->addr)) | ||
| 1528 | continue; | ||
| 1529 | |||
| 1530 | __skb_unlink(skb, &ar->tx_pending[i]); | ||
| 1531 | |||
| 1532 | info = IEEE80211_SKB_CB(skb); | ||
| 1533 | if (info->flags & IEEE80211_TX_CTL_AMPDU) | ||
| 1534 | atomic_dec(&ar->tx_ampdu_upload); | ||
| 1535 | |||
| 1536 | carl9170_tx_status(ar, skb, false); | ||
| 1537 | } | ||
| 1538 | spin_unlock_bh(&ar->tx_pending[i].lock); | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | while ((skb = __skb_dequeue(&free))) | ||
| 1542 | carl9170_tx_status(ar, skb, false); | ||
| 1543 | |||
| 1544 | break; | 1479 | break; |
| 1545 | 1480 | ||
| 1546 | case STA_NOTIFY_AWAKE: | 1481 | case STA_NOTIFY_AWAKE: |
| 1547 | if (!sta->ht_cap.ht_supported) | 1482 | sta_info->sleeping = false; |
| 1548 | return; | ||
| 1549 | |||
| 1550 | rcu_read_lock(); | ||
| 1551 | for (i = 0; i < CARL9170_NUM_TID; i++) { | ||
| 1552 | struct carl9170_sta_tid *tid_info; | ||
| 1553 | |||
| 1554 | tid_info = rcu_dereference(sta_info->agg[i]); | ||
| 1555 | |||
| 1556 | if (!tid_info) | ||
| 1557 | continue; | ||
| 1558 | |||
| 1559 | if ((tid_info->state == CARL9170_TID_STATE_SUSPEND)) | ||
| 1560 | tid_info->state = CARL9170_TID_STATE_IDLE; | ||
| 1561 | } | ||
| 1562 | rcu_read_unlock(); | ||
| 1563 | break; | 1483 | break; |
| 1564 | } | 1484 | } |
| 1565 | } | 1485 | } |
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index cb70ed7ec5cc..bf2eff9dd582 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c | |||
| @@ -104,6 +104,56 @@ static void carl9170_tx_accounting(struct ar9170 *ar, struct sk_buff *skb) | |||
| 104 | spin_unlock_bh(&ar->tx_stats_lock); | 104 | spin_unlock_bh(&ar->tx_stats_lock); |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | /* needs rcu_read_lock */ | ||
| 108 | static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar, | ||
| 109 | struct sk_buff *skb) | ||
| 110 | { | ||
| 111 | struct _carl9170_tx_superframe *super = (void *) skb->data; | ||
| 112 | struct ieee80211_hdr *hdr = (void *) super->frame_data; | ||
| 113 | struct ieee80211_vif *vif; | ||
| 114 | unsigned int vif_id; | ||
| 115 | |||
| 116 | vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> | ||
| 117 | CARL9170_TX_SUPER_MISC_VIF_ID_S; | ||
| 118 | |||
| 119 | if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) | ||
| 120 | return NULL; | ||
| 121 | |||
| 122 | vif = rcu_dereference(ar->vif_priv[vif_id].vif); | ||
| 123 | if (unlikely(!vif)) | ||
| 124 | return NULL; | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Normally we should use wrappers like ieee80211_get_DA to get | ||
| 128 | * the correct peer ieee80211_sta. | ||
| 129 | * | ||
| 130 | * But there is a problem with indirect traffic (broadcasts, or | ||
| 131 | * data which is designated for other stations) in station mode. | ||
| 132 | * The frame will be directed to the AP for distribution and not | ||
| 133 | * to the actual destination. | ||
| 134 | */ | ||
| 135 | |||
| 136 | return ieee80211_find_sta(vif, hdr->addr1); | ||
| 137 | } | ||
| 138 | |||
| 139 | static void carl9170_tx_ps_unblock(struct ar9170 *ar, struct sk_buff *skb) | ||
| 140 | { | ||
| 141 | struct ieee80211_sta *sta; | ||
| 142 | struct carl9170_sta_info *sta_info; | ||
| 143 | |||
| 144 | rcu_read_lock(); | ||
| 145 | sta = __carl9170_get_tx_sta(ar, skb); | ||
| 146 | if (unlikely(!sta)) | ||
| 147 | goto out_rcu; | ||
| 148 | |||
| 149 | sta_info = (struct carl9170_sta_info *) sta->drv_priv; | ||
| 150 | if (atomic_dec_return(&sta_info->pending_frames) == 0) | ||
| 151 | ieee80211_sta_block_awake(ar->hw, sta, false); | ||
| 152 | |||
| 153 | out_rcu: | ||
| 154 | rcu_read_unlock(); | ||
| 155 | } | ||
| 156 | |||
| 107 | static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) | 157 | static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) |
| 108 | { | 158 | { |
| 109 | struct ieee80211_tx_info *txinfo; | 159 | struct ieee80211_tx_info *txinfo; |
| @@ -135,6 +185,7 @@ static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) | |||
| 135 | } | 185 | } |
| 136 | 186 | ||
| 137 | spin_unlock_bh(&ar->tx_stats_lock); | 187 | spin_unlock_bh(&ar->tx_stats_lock); |
| 188 | |||
| 138 | if (atomic_dec_and_test(&ar->tx_total_queued)) | 189 | if (atomic_dec_and_test(&ar->tx_total_queued)) |
| 139 | complete(&ar->tx_flush); | 190 | complete(&ar->tx_flush); |
| 140 | } | 191 | } |
| @@ -329,13 +380,10 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, | |||
| 329 | { | 380 | { |
| 330 | struct _carl9170_tx_superframe *super = (void *) skb->data; | 381 | struct _carl9170_tx_superframe *super = (void *) skb->data; |
| 331 | struct ieee80211_hdr *hdr = (void *) super->frame_data; | 382 | struct ieee80211_hdr *hdr = (void *) super->frame_data; |
| 332 | struct ieee80211_tx_info *tx_info; | ||
| 333 | struct carl9170_tx_info *ar_info; | 383 | struct carl9170_tx_info *ar_info; |
| 334 | struct carl9170_sta_info *sta_info; | ||
| 335 | struct ieee80211_sta *sta; | 384 | struct ieee80211_sta *sta; |
| 385 | struct carl9170_sta_info *sta_info; | ||
| 336 | struct carl9170_sta_tid *tid_info; | 386 | struct carl9170_sta_tid *tid_info; |
| 337 | struct ieee80211_vif *vif; | ||
| 338 | unsigned int vif_id; | ||
| 339 | u8 tid; | 387 | u8 tid; |
| 340 | 388 | ||
| 341 | if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) || | 389 | if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) || |
| @@ -343,30 +391,10 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, | |||
| 343 | (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR)))) | 391 | (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR)))) |
| 344 | return; | 392 | return; |
| 345 | 393 | ||
| 346 | tx_info = IEEE80211_SKB_CB(skb); | 394 | ar_info = (void *) txinfo->rate_driver_data; |
| 347 | ar_info = (void *) tx_info->rate_driver_data; | ||
| 348 | |||
| 349 | vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> | ||
| 350 | CARL9170_TX_SUPER_MISC_VIF_ID_S; | ||
| 351 | |||
| 352 | if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) | ||
| 353 | return; | ||
| 354 | 395 | ||
| 355 | rcu_read_lock(); | 396 | rcu_read_lock(); |
| 356 | vif = rcu_dereference(ar->vif_priv[vif_id].vif); | 397 | sta = __carl9170_get_tx_sta(ar, skb); |
| 357 | if (unlikely(!vif)) | ||
| 358 | goto out_rcu; | ||
| 359 | |||
| 360 | /* | ||
| 361 | * Normally we should use wrappers like ieee80211_get_DA to get | ||
| 362 | * the correct peer ieee80211_sta. | ||
| 363 | * | ||
| 364 | * But there is a problem with indirect traffic (broadcasts, or | ||
| 365 | * data which is designated for other stations) in station mode. | ||
| 366 | * The frame will be directed to the AP for distribution and not | ||
| 367 | * to the actual destination. | ||
| 368 | */ | ||
| 369 | sta = ieee80211_find_sta(vif, hdr->addr1); | ||
| 370 | if (unlikely(!sta)) | 398 | if (unlikely(!sta)) |
| 371 | goto out_rcu; | 399 | goto out_rcu; |
| 372 | 400 | ||
| @@ -427,6 +455,7 @@ void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, | |||
| 427 | if (txinfo->flags & IEEE80211_TX_CTL_AMPDU) | 455 | if (txinfo->flags & IEEE80211_TX_CTL_AMPDU) |
| 428 | carl9170_tx_status_process_ampdu(ar, skb, txinfo); | 456 | carl9170_tx_status_process_ampdu(ar, skb, txinfo); |
| 429 | 457 | ||
| 458 | carl9170_tx_ps_unblock(ar, skb); | ||
| 430 | carl9170_tx_put_skb(skb); | 459 | carl9170_tx_put_skb(skb); |
| 431 | } | 460 | } |
| 432 | 461 | ||
| @@ -540,11 +569,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar) | |||
| 540 | struct sk_buff *skb; | 569 | struct sk_buff *skb; |
| 541 | struct ieee80211_tx_info *txinfo; | 570 | struct ieee80211_tx_info *txinfo; |
| 542 | struct carl9170_tx_info *arinfo; | 571 | struct carl9170_tx_info *arinfo; |
| 543 | struct _carl9170_tx_superframe *super; | ||
| 544 | struct ieee80211_sta *sta; | 572 | struct ieee80211_sta *sta; |
| 545 | struct ieee80211_vif *vif; | ||
| 546 | struct ieee80211_hdr *hdr; | ||
| 547 | unsigned int vif_id; | ||
| 548 | 573 | ||
| 549 | rcu_read_lock(); | 574 | rcu_read_lock(); |
| 550 | list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) { | 575 | list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) { |
| @@ -562,20 +587,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar) | |||
| 562 | msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT))) | 587 | msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT))) |
| 563 | goto unlock; | 588 | goto unlock; |
| 564 | 589 | ||
| 565 | super = (void *) skb->data; | 590 | sta = __carl9170_get_tx_sta(ar, skb); |
| 566 | hdr = (void *) super->frame_data; | ||
| 567 | |||
| 568 | vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> | ||
| 569 | CARL9170_TX_SUPER_MISC_VIF_ID_S; | ||
| 570 | |||
| 571 | if (WARN_ON(vif_id >= AR9170_MAX_VIRTUAL_MAC)) | ||
| 572 | goto unlock; | ||
| 573 | |||
| 574 | vif = rcu_dereference(ar->vif_priv[vif_id].vif); | ||
| 575 | if (WARN_ON(!vif)) | ||
| 576 | goto unlock; | ||
| 577 | |||
| 578 | sta = ieee80211_find_sta(vif, hdr->addr1); | ||
| 579 | if (WARN_ON(!sta)) | 591 | if (WARN_ON(!sta)) |
| 580 | goto unlock; | 592 | goto unlock; |
| 581 | 593 | ||
| @@ -1199,15 +1211,6 @@ static struct sk_buff *carl9170_tx_pick_skb(struct ar9170 *ar, | |||
| 1199 | arinfo = (void *) info->rate_driver_data; | 1211 | arinfo = (void *) info->rate_driver_data; |
| 1200 | 1212 | ||
| 1201 | arinfo->timeout = jiffies; | 1213 | arinfo->timeout = jiffies; |
| 1202 | |||
| 1203 | /* | ||
| 1204 | * increase ref count to "2". | ||
| 1205 | * Ref counting is the easiest way to solve the race between | ||
| 1206 | * the the urb's completion routine: carl9170_tx_callback and | ||
| 1207 | * wlan tx status functions: carl9170_tx_status/janitor. | ||
| 1208 | */ | ||
| 1209 | carl9170_tx_get_skb(skb); | ||
| 1210 | |||
| 1211 | return skb; | 1214 | return skb; |
| 1212 | 1215 | ||
| 1213 | err_unlock: | 1216 | err_unlock: |
| @@ -1228,6 +1231,36 @@ void carl9170_tx_drop(struct ar9170 *ar, struct sk_buff *skb) | |||
| 1228 | __carl9170_tx_process_status(ar, super->s.cookie, q); | 1231 | __carl9170_tx_process_status(ar, super->s.cookie, q); |
| 1229 | } | 1232 | } |
| 1230 | 1233 | ||
| 1234 | static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb) | ||
| 1235 | { | ||
| 1236 | struct ieee80211_sta *sta; | ||
| 1237 | struct carl9170_sta_info *sta_info; | ||
| 1238 | |||
| 1239 | rcu_read_lock(); | ||
| 1240 | sta = __carl9170_get_tx_sta(ar, skb); | ||
| 1241 | if (!sta) | ||
| 1242 | goto out_rcu; | ||
| 1243 | |||
| 1244 | sta_info = (void *) sta->drv_priv; | ||
| 1245 | if (unlikely(sta_info->sleeping)) { | ||
| 1246 | struct ieee80211_tx_info *tx_info; | ||
| 1247 | |||
| 1248 | rcu_read_unlock(); | ||
| 1249 | |||
| 1250 | tx_info = IEEE80211_SKB_CB(skb); | ||
| 1251 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) | ||
| 1252 | atomic_dec(&ar->tx_ampdu_upload); | ||
| 1253 | |||
| 1254 | tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | ||
| 1255 | carl9170_tx_status(ar, skb, false); | ||
| 1256 | return true; | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | out_rcu: | ||
| 1260 | rcu_read_unlock(); | ||
| 1261 | return false; | ||
| 1262 | } | ||
| 1263 | |||
| 1231 | static void carl9170_tx(struct ar9170 *ar) | 1264 | static void carl9170_tx(struct ar9170 *ar) |
| 1232 | { | 1265 | { |
| 1233 | struct sk_buff *skb; | 1266 | struct sk_buff *skb; |
| @@ -1247,6 +1280,9 @@ static void carl9170_tx(struct ar9170 *ar) | |||
| 1247 | if (unlikely(!skb)) | 1280 | if (unlikely(!skb)) |
| 1248 | break; | 1281 | break; |
| 1249 | 1282 | ||
| 1283 | if (unlikely(carl9170_tx_ps_drop(ar, skb))) | ||
| 1284 | continue; | ||
| 1285 | |||
| 1250 | atomic_inc(&ar->tx_total_pending); | 1286 | atomic_inc(&ar->tx_total_pending); |
| 1251 | 1287 | ||
| 1252 | q = __carl9170_get_queue(ar, i); | 1288 | q = __carl9170_get_queue(ar, i); |
| @@ -1256,6 +1292,16 @@ static void carl9170_tx(struct ar9170 *ar) | |||
| 1256 | */ | 1292 | */ |
| 1257 | skb_queue_tail(&ar->tx_status[q], skb); | 1293 | skb_queue_tail(&ar->tx_status[q], skb); |
| 1258 | 1294 | ||
| 1295 | /* | ||
| 1296 | * increase ref count to "2". | ||
| 1297 | * Ref counting is the easiest way to solve the | ||
| 1298 | * race between the urb's completion routine: | ||
| 1299 | * carl9170_tx_callback | ||
| 1300 | * and wlan tx status functions: | ||
| 1301 | * carl9170_tx_status/janitor. | ||
| 1302 | */ | ||
| 1303 | carl9170_tx_get_skb(skb); | ||
| 1304 | |||
| 1259 | carl9170_usb_tx(ar, skb); | 1305 | carl9170_usb_tx(ar, skb); |
| 1260 | schedule_garbagecollector = true; | 1306 | schedule_garbagecollector = true; |
| 1261 | } | 1307 | } |
| @@ -1368,6 +1414,11 @@ void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 1368 | * all ressouces which are associated with the frame. | 1414 | * all ressouces which are associated with the frame. |
| 1369 | */ | 1415 | */ |
| 1370 | 1416 | ||
| 1417 | if (sta) { | ||
| 1418 | struct carl9170_sta_info *stai = (void *) sta->drv_priv; | ||
| 1419 | atomic_inc(&stai->pending_frames); | ||
| 1420 | } | ||
| 1421 | |||
| 1371 | if (info->flags & IEEE80211_TX_CTL_AMPDU) { | 1422 | if (info->flags & IEEE80211_TX_CTL_AMPDU) { |
| 1372 | run = carl9170_tx_ampdu_queue(ar, sta, skb); | 1423 | run = carl9170_tx_ampdu_queue(ar, sta, skb); |
| 1373 | if (run) | 1424 | if (run) |
