summaryrefslogtreecommitdiff
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorAndreas Fenkart <andreas.fenkart@streamunlimited.com>2013-04-05 03:03:52 (GMT)
committerJohn W. Linville <linville@tuxdriver.com>2013-04-08 19:28:39 (GMT)
commit333f6b22c5b88a9d856703b440257f46efa714c8 (patch)
tree4cc881717c225356f42d0870997332b424e0a2ae /drivers/net/wireless
parent6d2344ec6043a2de8cfa9d8f27909a99ca967a08 (diff)
downloadlinux-333f6b22c5b88a9d856703b440257f46efa714c8.tar.xz
mwifiex: fix infinite loop by removing NO_PKT_PRIO_TID
Using NO_PKT_PRIO_TID and tx_pkts_queued to check for an empty state, can lead to a contradictory state, resulting in an infinite loop. Currently queueing and dequeuing of packets is not synchronized, and can happen concurrently. While tx_pkts_queued is incremented when adding a packet, max prio is set to NO_PKT when the WMM list is empty. If a packet is added right after the check for empty, but before setting max prio to NO_PKT, that packet is trapped and creates an infinite loop. Because of the new packet, tx_pkts_queued is at least 1, indicating wmm lists are not empty. Opposing that max prio is NO_PKT, which means "skip this wmm queue, it has no packets". The infinite loop results, because the main loop checks the wmm lists for not empty via tx_pkts_queued, but for dequeing it uses max_prio to see if it can skip current list. This will never end, unless a new packet is added which will restore max prio to the level of the trapped packet. The solution here is to rely on tx_pkts_queued solely for checking wmm queue to be empty, and drop the NO_PKT define. It does not address the locking issue. Signed-off-by: Andreas Fenkart <andreas.fenkart@streamunlimited.com> Signed-off-by: Avinash Patil <patila@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/mwifiex/main.h1
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c13
2 files changed, 6 insertions, 8 deletions
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 622b17f..b7484ef 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -219,7 +219,6 @@ struct mwifiex_tid_tbl {
#define WMM_HIGHEST_PRIORITY 7
#define HIGH_PRIO_TID 7
#define LOW_PRIO_TID 0
-#define NO_PKT_PRIO_TID (-1)
struct mwifiex_wmm_desc {
struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index c1d8488..75c8e80 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -916,8 +916,12 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
do {
priv_tmp = bssprio_node->priv;
- hqp = &priv_tmp->wmm.highest_queued_prio;
+ if (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0)
+ goto skip_bss;
+
+ /* iterate over the WMM queues of the BSS */
+ hqp = &priv_tmp->wmm.highest_queued_prio;
for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
tid_ptr = &(priv_tmp)->wmm.
@@ -976,12 +980,7 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
} while (ptr != head);
}
- /* No packet at any TID for this priv. Mark as such
- * to skip checking TIDs for this priv (until pkt is
- * added).
- */
- atomic_set(hqp, NO_PKT_PRIO_TID);
-
+skip_bss:
/* Get next bss priority node */
bssprio_node = list_first_entry(&bssprio_node->list,
struct mwifiex_bss_prio_node,