diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2008-07-24 11:46:44 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-08-01 15:31:33 -0400 |
commit | f8e79ddd31c3615ddca26b9a469c44a7adbd4e13 (patch) | |
tree | befabd77386f496a3a5049bace1d335fcd8f8148 | |
parent | dc1968e7b7862bcd2d358c1be6119c011992bdd2 (diff) |
mac80211: fix fragmentation kludge
This patch make mac80211 transmit correctly fragmented packet after
queue was stopped
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/tx.c | 17 | ||||
-rw-r--r-- | net/mac80211/util.c | 1 |
3 files changed, 14 insertions, 5 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a4f9a832722a..a2e200f9811e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -586,6 +586,7 @@ struct ieee80211_local { | |||
586 | struct timer_list sta_cleanup; | 586 | struct timer_list sta_cleanup; |
587 | 587 | ||
588 | unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; | 588 | unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; |
589 | unsigned long queues_pending_run[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; | ||
589 | struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; | 590 | struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; |
590 | struct tasklet_struct tx_pending_tasklet; | 591 | struct tasklet_struct tx_pending_tasklet; |
591 | 592 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 69019e943873..771ec68b848d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1060,13 +1060,14 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, | |||
1060 | static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | 1060 | static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, |
1061 | struct ieee80211_tx_data *tx) | 1061 | struct ieee80211_tx_data *tx) |
1062 | { | 1062 | { |
1063 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1063 | struct ieee80211_tx_info *info; |
1064 | int ret, i; | 1064 | int ret, i; |
1065 | 1065 | ||
1066 | if (netif_subqueue_stopped(local->mdev, skb)) | ||
1067 | return IEEE80211_TX_AGAIN; | ||
1068 | |||
1069 | if (skb) { | 1066 | if (skb) { |
1067 | if (netif_subqueue_stopped(local->mdev, skb)) | ||
1068 | return IEEE80211_TX_AGAIN; | ||
1069 | info = IEEE80211_SKB_CB(skb); | ||
1070 | |||
1070 | ieee80211_dump_frame(wiphy_name(local->hw.wiphy), | 1071 | ieee80211_dump_frame(wiphy_name(local->hw.wiphy), |
1071 | "TX to low-level driver", skb); | 1072 | "TX to low-level driver", skb); |
1072 | ret = local->ops->tx(local_to_hw(local), skb); | 1073 | ret = local->ops->tx(local_to_hw(local), skb); |
@@ -1215,6 +1216,7 @@ retry: | |||
1215 | 1216 | ||
1216 | if (ret == IEEE80211_TX_FRAG_AGAIN) | 1217 | if (ret == IEEE80211_TX_FRAG_AGAIN) |
1217 | skb = NULL; | 1218 | skb = NULL; |
1219 | |||
1218 | set_bit(queue, local->queues_pending); | 1220 | set_bit(queue, local->queues_pending); |
1219 | smp_mb(); | 1221 | smp_mb(); |
1220 | /* | 1222 | /* |
@@ -1708,14 +1710,19 @@ void ieee80211_tx_pending(unsigned long data) | |||
1708 | netif_tx_lock_bh(dev); | 1710 | netif_tx_lock_bh(dev); |
1709 | for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { | 1711 | for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { |
1710 | /* Check that this queue is ok */ | 1712 | /* Check that this queue is ok */ |
1711 | if (__netif_subqueue_stopped(local->mdev, i)) | 1713 | if (__netif_subqueue_stopped(local->mdev, i) && |
1714 | !test_bit(i, local->queues_pending_run)) | ||
1712 | continue; | 1715 | continue; |
1713 | 1716 | ||
1714 | if (!test_bit(i, local->queues_pending)) { | 1717 | if (!test_bit(i, local->queues_pending)) { |
1718 | clear_bit(i, local->queues_pending_run); | ||
1715 | ieee80211_wake_queue(&local->hw, i); | 1719 | ieee80211_wake_queue(&local->hw, i); |
1716 | continue; | 1720 | continue; |
1717 | } | 1721 | } |
1718 | 1722 | ||
1723 | clear_bit(i, local->queues_pending_run); | ||
1724 | netif_start_subqueue(local->mdev, i); | ||
1725 | |||
1719 | store = &local->pending_packet[i]; | 1726 | store = &local->pending_packet[i]; |
1720 | tx.extra_frag = store->extra_frag; | 1727 | tx.extra_frag = store->extra_frag; |
1721 | tx.num_extra_frag = store->num_extra_frag; | 1728 | tx.num_extra_frag = store->num_extra_frag; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 19f85e1b3695..0d463c80c404 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -361,6 +361,7 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) | |||
361 | struct ieee80211_local *local = hw_to_local(hw); | 361 | struct ieee80211_local *local = hw_to_local(hw); |
362 | 362 | ||
363 | if (test_bit(queue, local->queues_pending)) { | 363 | if (test_bit(queue, local->queues_pending)) { |
364 | set_bit(queue, local->queues_pending_run); | ||
364 | tasklet_schedule(&local->tx_pending_tasklet); | 365 | tasklet_schedule(&local->tx_pending_tasklet); |
365 | } else { | 366 | } else { |
366 | netif_wake_subqueue(local->mdev, queue); | 367 | netif_wake_subqueue(local->mdev, queue); |