aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-06-10 23:41:43 -0700
committerDavid S. Miller <davem@davemloft.net>2009-06-10 23:41:43 -0700
commit84503ddd65e804ccdeedee3f307b40d80ff793e6 (patch)
treec7b805f441b1d8cb2e86b8411cf2302ff46186b4
parent51611a120e8120290152edd7d0020d22a7f4b4a3 (diff)
parent2f0accc13520b2644b85f80aedce10d10d88b0ca (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
-rw-r--r--drivers/net/wireless/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h34
-rw-r--r--drivers/net/wireless/ath/ar9170/hw.h3
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c676
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c122
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.h7
-rw-r--r--drivers/net/wireless/ath/ath5k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h12
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c17
-rw-r--r--drivers/net/wireless/ath/ath5k/rfkill.c121
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c1
-rw-r--r--drivers/net/wireless/b43/Kconfig7
-rw-r--r--drivers/net/wireless/b43/Makefile2
-rw-r--r--drivers/net/wireless/b43/b43.h17
-rw-r--r--drivers/net/wireless/b43/dma.c2
-rw-r--r--drivers/net/wireless/b43/leds.c7
-rw-r--r--drivers/net/wireless/b43/main.c83
-rw-r--r--drivers/net/wireless/b43/main.h1
-rw-r--r--drivers/net/wireless/b43/phy_common.h2
-rw-r--r--drivers/net/wireless/b43/pio.c2
-rw-r--r--drivers/net/wireless/b43/rfkill.c113
-rw-r--r--drivers/net/wireless/b43/rfkill.h44
-rw-r--r--drivers/net/wireless/b43/xmit.c5
-rw-r--r--drivers/net/wireless/b43legacy/Kconfig8
-rw-r--r--drivers/net/wireless/b43legacy/Makefile2
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h3
-rw-r--r--drivers/net/wireless/b43legacy/leds.c7
-rw-r--r--drivers/net/wireless/b43legacy/main.c17
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.c115
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.h50
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig4
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c42
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c138
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rfkill.c131
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rfkill.h48
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c41
-rw-r--r--drivers/net/wireless/libertas/if_spi.c92
-rw-r--r--drivers/net/wireless/rndis_wlan.c292
-rw-r--r--drivers/platform/x86/acer-wmi.c3
-rw-r--r--drivers/platform/x86/eeepc-laptop.c8
-rw-r--r--drivers/platform/x86/hp-wmi.c4
-rw-r--r--drivers/platform/x86/sony-laptop.c4
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c31
-rw-r--r--include/linux/rfkill.h35
-rw-r--r--include/linux/skbuff.h4
-rw-r--r--include/linux/spi/libertas_spi.h3
-rw-r--r--include/net/mac80211.h3
-rw-r--r--net/core/skbuff.c1
-rw-r--r--net/mac80211/agg-tx.c6
-rw-r--r--net/mac80211/cfg.c4
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/main.c61
-rw-r--r--net/mac80211/mlme.c57
-rw-r--r--net/mac80211/rc80211_minstrel.c2
-rw-r--r--net/mac80211/rx.c27
-rw-r--r--net/mac80211/tx.c19
-rw-r--r--net/mac80211/util.c46
-rw-r--r--net/mac80211/wme.c2
-rw-r--r--net/rfkill/Kconfig2
-rw-r--r--net/rfkill/core.c93
-rw-r--r--net/wireless/core.c19
-rw-r--r--net/wireless/reg.c7
69 files changed, 1275 insertions, 1482 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index daf4c805be5..fb7541c28e5 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -153,7 +153,7 @@ config LIBERTAS_SDIO
config LIBERTAS_SPI
tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
- depends on LIBERTAS && SPI && GENERIC_GPIO
+ depends on LIBERTAS && SPI
---help---
A driver for Marvell Libertas 8686 SPI devices.
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index c7cba66b63c..bb97981fb24 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -109,6 +109,11 @@ struct ar9170_rxstream_mpdu_merge {
bool has_plcp;
};
+#define AR9170_QUEUE_TIMEOUT 64
+#define AR9170_TX_TIMEOUT 8
+#define AR9170_JANITOR_DELAY 128
+#define AR9170_TX_INVALID_RATE 0xffffffff
+
struct ar9170 {
struct ieee80211_hw *hw;
struct mutex mutex;
@@ -117,10 +122,11 @@ struct ar9170 {
int (*open)(struct ar9170 *);
void (*stop)(struct ar9170 *);
- int (*tx)(struct ar9170 *, struct sk_buff *, bool, unsigned int);
+ int (*tx)(struct ar9170 *, struct sk_buff *);
int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 ,
void *, u32 , void *);
void (*callback_cmd)(struct ar9170 *, u32 , void *);
+ int (*flush)(struct ar9170 *);
/* interface mode settings */
struct ieee80211_vif *vif;
@@ -177,10 +183,10 @@ struct ar9170 {
struct ar9170_eeprom eeprom;
struct ath_regulatory regulatory;
- /* global tx status for unregistered Stations. */
- struct sk_buff_head global_tx_status;
- struct sk_buff_head global_tx_status_waste;
- struct delayed_work tx_status_janitor;
+ /* tx queues - as seen by hw - */
+ struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
+ struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
+ struct delayed_work tx_janitor;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
@@ -189,11 +195,19 @@ struct ar9170 {
};
struct ar9170_sta_info {
- struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
};
-#define IS_STARTED(a) (a->state >= AR9170_STARTED)
-#define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE)
+#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0)
+#define AR9170_TX_FLAG_NO_ACK BIT(1)
+#define AR9170_TX_FLAG_BLOCK_ACK BIT(2)
+
+struct ar9170_tx_info {
+ unsigned long timeout;
+ unsigned int flags;
+};
+
+#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED)
+#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE)
#define AR9170_FILTER_CHANGED_MODE BIT(0)
#define AR9170_FILTER_CHANGED_MULTICAST BIT(1)
@@ -204,9 +218,9 @@ void *ar9170_alloc(size_t priv_size);
int ar9170_register(struct ar9170 *ar, struct device *pdev);
void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb);
void ar9170_unregister(struct ar9170 *ar);
-void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
- bool update_statistics, u16 tx_status);
+void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb);
void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
+int ar9170_nag_limiter(struct ar9170 *ar);
/* MAC */
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h
index 3c8004fb730..6cbfb2f8339 100644
--- a/drivers/net/wireless/ath/ar9170/hw.h
+++ b/drivers/net/wireless/ath/ar9170/hw.h
@@ -420,4 +420,7 @@ enum ar9170_txq {
__AR9170_NUM_TXQ,
};
+#define AR9170_TXQ_DEPTH 32
+#define AR9170_TX_MAX_PENDING 128
+
#endif /* __AR9170_HW_H */
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index b104d7efd67..9d38cf60a0d 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -173,59 +173,122 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
.ht_cap = AR9170_HT_CAP,
};
-#ifdef AR9170_QUEUE_DEBUG
-/*
- * In case some wants works with AR9170's crazy tx_status queueing techniques.
- * He might need this rather useful probing function.
- *
- * NOTE: caller must hold the queue's spinlock!
- */
+static void ar9170_tx(struct ar9170 *ar);
+#ifdef AR9170_QUEUE_DEBUG
static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
{
struct ar9170_tx_control *txc = (void *) skb->data;
- struct ieee80211_hdr *hdr = (void *)txc->frame_data;
+ struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+ struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
+ struct ieee80211_hdr *hdr = (void *) txc->frame_data;
- printk(KERN_DEBUG "%s: => FRAME [skb:%p, queue:%d, DA:[%pM] "
- "mac_control:%04x, phy_control:%08x]\n",
+ printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x "
+ "mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
- ieee80211_get_DA(hdr), le16_to_cpu(txc->mac_control),
- le32_to_cpu(txc->phy_control));
+ ieee80211_get_DA(hdr), arinfo->flags,
+ le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
+ jiffies_to_msecs(arinfo->timeout - jiffies));
}
-static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar,
- struct sk_buff_head *queue)
+static void __ar9170_dump_txqueue(struct ar9170 *ar,
+ struct sk_buff_head *queue)
{
struct sk_buff *skb;
int i = 0;
printk(KERN_DEBUG "---[ cut here ]---\n");
- printk(KERN_DEBUG "%s: %d entries in tx_status queue.\n",
+ printk(KERN_DEBUG "%s: %d entries in queue.\n",
wiphy_name(ar->hw->wiphy), skb_queue_len(queue));
skb_queue_walk(queue, skb) {
- struct ar9170_tx_control *txc = (void *) skb->data;
- struct ieee80211_hdr *hdr = (void *)txc->frame_data;
-
- printk(KERN_DEBUG "index:%d => \n", i);
+ printk(KERN_DEBUG "index:%d => \n", i++);
ar9170_print_txheader(ar, skb);
}
+ if (i != skb_queue_len(queue))
+ printk(KERN_DEBUG "WARNING: queue frame counter "
+ "mismatch %d != %d\n", skb_queue_len(queue), i);
printk(KERN_DEBUG "---[ end ]---\n");
}
-#endif /* AR9170_QUEUE_DEBUG */
-void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
- bool valid_status, u16 tx_status)
+static void ar9170_dump_txqueue(struct ar9170 *ar,
+ struct sk_buff_head *queue)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->lock, flags);
+ __ar9170_dump_txqueue(ar, queue);
+ spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static void __ar9170_dump_txstats(struct ar9170 *ar)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: QoS queue stats\n",
+ wiphy_name(ar->hw->wiphy));
+
+ for (i = 0; i < __AR9170_NUM_TXQ; i++)
+ printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n",
+ wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit,
+ ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i]));
+}
+
+static void ar9170_dump_txstats(struct ar9170 *ar)
{
- struct ieee80211_tx_info *txinfo;
- unsigned int retries = 0, queue = skb_get_queue_mapping(skb);
unsigned long flags;
spin_lock_irqsave(&ar->tx_stats_lock, flags);
- ar->tx_stats[queue].len--;
- if (ieee80211_queue_stopped(ar->hw, queue))
- ieee80211_wake_queue(ar->hw, queue);
+ __ar9170_dump_txstats(ar);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
+}
+#endif /* AR9170_QUEUE_DEBUG */
+
+/* caller must guarantee exclusive access for _bin_ queue. */
+static void ar9170_recycle_expired(struct ar9170 *ar,
+ struct sk_buff_head *queue,
+ struct sk_buff_head *bin)
+{
+ struct sk_buff *skb, *old = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->lock, flags);
+ while ((skb = skb_peek(queue))) {
+ struct ieee80211_tx_info *txinfo;
+ struct ar9170_tx_info *arinfo;
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ arinfo = (void *) txinfo->rate_driver_data;
+
+ if (time_is_before_jiffies(arinfo->timeout)) {
+#ifdef AR9170_QUEUE_DEBUG
+ printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => "
+ "recycle \n", wiphy_name(ar->hw->wiphy),
+ jiffies, arinfo->timeout);
+ ar9170_print_txheader(ar, skb);
+#endif /* AR9170_QUEUE_DEBUG */
+ __skb_unlink(skb, queue);
+ __skb_queue_tail(bin, skb);
+ } else {
+ break;
+ }
+
+ if (unlikely(old == skb)) {
+ /* bail out - queue is shot. */
+
+ WARN_ON(1);
+ break;
+ }
+ old = skb;
+ }
+ spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
+ u16 tx_status)
+{
+ struct ieee80211_tx_info *txinfo;
+ unsigned int retries = 0;
txinfo = IEEE80211_SKB_CB(skb);
ieee80211_tx_info_clear_status(txinfo);
@@ -247,45 +310,61 @@ void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
break;
}
- if (valid_status)
- txinfo->status.rates[0].count = retries + 1;
-
+ txinfo->status.rates[0].count = retries + 1;
skb_pull(skb, sizeof(struct ar9170_tx_control));
ieee80211_tx_status_irqsafe(ar->hw, skb);
}
-static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar,
- const u8 *mac,
- const u32 queue,
- struct sk_buff_head *q)
+void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data;
+ unsigned int queue = skb_get_queue_mapping(skb);
unsigned long flags;
- struct sk_buff *skb;
- spin_lock_irqsave(&q->lock, flags);
- skb_queue_walk(q, skb) {
- struct ar9170_tx_control *txc = (void *) skb->data;
- struct ieee80211_hdr *hdr = (void *) txc->frame_data;
- u32 txc_queue = (le32_to_cpu(txc->phy_control) &
- AR9170_TX_PHY_QOS_MASK) >>
- AR9170_TX_PHY_QOS_SHIFT;
+ spin_lock_irqsave(&ar->tx_stats_lock, flags);
+ ar->tx_stats[queue].len--;
- if ((queue != txc_queue) ||
- (compare_ether_addr(ieee80211_get_DA(hdr), mac)))
- continue;
+ if (skb_queue_empty(&ar->tx_pending[queue])) {
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: wake queue %d\n",
+ wiphy_name(ar->hw->wiphy), queue);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
+ ieee80211_wake_queue(ar->hw, queue);
+ }
+ spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
- __skb_unlink(skb, q);
- spin_unlock_irqrestore(&q->lock, flags);
- return skb;
+ if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
+ dev_kfree_skb_any(skb);
+ } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
+ arinfo->timeout = jiffies +
+ msecs_to_jiffies(AR9170_TX_TIMEOUT);
+
+ skb_queue_tail(&ar->tx_status[queue], skb);
+ } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) {
+ ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
+ } else {
+#ifdef AR9170_QUEUE_DEBUG
+ printk(KERN_DEBUG "%s: unsupported frame flags!\n",
+ wiphy_name(ar->hw->wiphy));
+ ar9170_print_txheader(ar, skb);
+#endif /* AR9170_QUEUE_DEBUG */
+ dev_kfree_skb_any(skb);
+ }
+
+ if (!ar->tx_stats[queue].len &&
+ !skb_queue_empty(&ar->tx_pending[queue])) {
+ ar9170_tx(ar);
}
- spin_unlock_irqrestore(&q->lock, flags);
- return NULL;
}
-static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
- const u32 queue)
+static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
+ const u8 *mac,
+ struct sk_buff_head *queue,
+ const u32 rate)
{
- struct ieee80211_sta *sta;
+ unsigned long flags;
struct sk_buff *skb;
/*
@@ -296,78 +375,91 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
* the firmware provided (-> destination MAC, and phy_control) -
* and hope that we picked the right one...
*/
- rcu_read_lock();
- sta = ieee80211_find_sta(ar->hw, mac);
-
- if (likely(sta)) {
- struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv;
- skb = skb_dequeue(&sta_priv->tx_status[queue]);
- rcu_read_unlock();
- if (likely(skb))
- return skb;
- } else
- rcu_read_unlock();
-
- /* scan the waste queue for candidates */
- skb = ar9170_find_skb_in_queue(ar, mac, queue,
- &ar->global_tx_status_waste);
- if (!skb) {
- /* so it still _must_ be in the global list. */
- skb = ar9170_find_skb_in_queue(ar, mac, queue,
- &ar->global_tx_status);
- }
+ spin_lock_irqsave(&queue->lock, flags);
+ skb_queue_walk(queue, skb) {
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ struct ieee80211_hdr *hdr = (void *) txc->frame_data;
+ u32 r;
+
+ if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) {
#ifdef AR9170_QUEUE_DEBUG
- if (unlikely((!skb) && net_ratelimit())) {
- printk(KERN_ERR "%s: ESS:[%pM] does not have any "
- "outstanding frames in this queue (%d).\n",
- wiphy_name(ar->hw->wiphy), mac, queue);
+ printk(KERN_DEBUG "%s: skip frame => DA %pM != %pM\n",
+ wiphy_name(ar->hw->wiphy), mac,
+ ieee80211_get_DA(hdr));
+ ar9170_print_txheader(ar, skb);
+#endif /* AR9170_QUEUE_DEBUG */
+ continue;
+ }
+
+ r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >>
+ AR9170_TX_PHY_MCS_SHIFT;
+
+ if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) {
+#ifdef AR9170_QUEUE_DEBUG
+ printk(KERN_DEBUG "%s: skip frame => rate %d != %d\n",
+ wiphy_name(ar->hw->wiphy), rate, r);
+ ar9170_print_txheader(ar, skb);
+#endif /* AR9170_QUEUE_DEBUG */
+ continue;
+ }
+
+ __skb_unlink(skb, queue);
+ spin_unlock_irqrestore(&queue->lock, flags);
+ return skb;
}
+
+#ifdef AR9170_QUEUE_DEBUG
+ printk(KERN_ERR "%s: ESS:[%pM] does not have any "
+ "outstanding frames in queue.\n",
+ wiphy_name(ar->hw->wiphy), mac);
+ __ar9170_dump_txqueue(ar, queue);
#endif /* AR9170_QUEUE_DEBUG */
- return skb;
+ spin_unlock_irqrestore(&queue->lock, flags);
+
+ return NULL;
}
/*
- * This worker tries to keep the global tx_status queue empty.
- * So we can guarantee that incoming tx_status reports for
- * unregistered stations are always synced with the actual
- * frame - which we think - belongs to.
+ * This worker tries to keeps an maintain tx_status queues.
+ * So we can guarantee that incoming tx_status reports are
+ * actually for a pending frame.
*/
-static void ar9170_tx_status_janitor(struct work_struct *work)
+static void ar9170_tx_janitor(struct work_struct *work)
{
struct ar9170 *ar = container_of(work, struct ar9170,
- tx_status_janitor.work);
- struct sk_buff *skb;
+ tx_janitor.work);
+ struct sk_buff_head waste;
+ unsigned int i;
+ bool resched = false;
if (unlikely(!IS_STARTED(ar)))
return ;
- /* recycle the garbage back to mac80211... one by one. */
- while ((skb = skb_dequeue(&ar->global_tx_status_waste))) {
+ skb_queue_head_init(&waste);
+
+ for (i = 0; i < __AR9170_NUM_TXQ; i++) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: dispose queued frame =>\n",
- wiphy_name(ar->hw->wiphy));
- ar9170_print_txheader(ar, skb);
+ printk(KERN_DEBUG "%s: garbage collector scans queue:%d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
+ ar9170_dump_txqueue(ar, &ar->tx_status[i]);
#endif /* AR9170_QUEUE_DEBUG */
- ar9170_handle_tx_status(ar, skb, false,
- AR9170_TX_STATUS_FAILED);
- }
- while ((skb = skb_dequeue(&ar->global_tx_status))) {
-#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: moving frame into waste queue =>\n",
- wiphy_name(ar->hw->wiphy));
+ ar9170_recycle_expired(ar, &ar->tx_status[i], &waste);
+ ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste);
+ skb_queue_purge(&waste);
- ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
- skb_queue_tail(&ar->global_tx_status_waste, skb);
+ if (!skb_queue_empty(&ar->tx_status[i]) ||
+ !skb_queue_empty(&ar->tx_pending[i]))
+ resched = true;
}
- /* recall the janitor in 100ms - if there's garbage in the can. */
- if (skb_queue_len(&ar->global_tx_status_waste) > 0)
- queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
- msecs_to_jiffies(100));
+ if (resched)
+ queue_delayed_work(ar->hw->workqueue,
+ &ar->tx_janitor,
+ msecs_to_jiffies(AR9170_JANITOR_DELAY));
}
void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
@@ -394,15 +486,21 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
*/
struct sk_buff *skb;
- u32 queue = (le32_to_cpu(cmd->tx_status.rate) &
- AR9170_TX_PHY_QOS_MASK) >> AR9170_TX_PHY_QOS_SHIFT;
+ u32 phy = le32_to_cpu(cmd->tx_status.rate);
+ u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >>
+ AR9170_TX_PHY_QOS_SHIFT;
+#ifdef AR9170_QUEUE_DEBUG
+ printk(KERN_DEBUG "%s: recv tx_status for %pM, p:%08x, q:%d\n",
+ wiphy_name(ar->hw->wiphy), cmd->tx_status.dst, phy, q);
+#endif /* AR9170_QUEUE_DEBUG */
- skb = ar9170_find_queued_skb(ar, cmd->tx_status.dst, queue);
+ skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst,
+ &ar->tx_status[q],
+ AR9170_TX_INVALID_RATE);
if (unlikely(!skb))
return ;
- ar9170_handle_tx_status(ar, skb, true,
- le16_to_cpu(cmd->tx_status.status));
+ ar9170_tx