Commit 333f6b22 authored by Andreas Fenkart's avatar Andreas Fenkart Committed by John W. Linville

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: default avatarAndreas Fenkart <andreas.fenkart@streamunlimited.com>
Signed-off-by: default avatarAvinash Patil <patila@marvell.com>
Signed-off-by: default avatarBing Zhao <bzhao@marvell.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 6d2344ec
...@@ -219,7 +219,6 @@ struct mwifiex_tid_tbl { ...@@ -219,7 +219,6 @@ struct mwifiex_tid_tbl {
#define WMM_HIGHEST_PRIORITY 7 #define WMM_HIGHEST_PRIORITY 7
#define HIGH_PRIO_TID 7 #define HIGH_PRIO_TID 7
#define LOW_PRIO_TID 0 #define LOW_PRIO_TID 0
#define NO_PKT_PRIO_TID (-1)
struct mwifiex_wmm_desc { struct mwifiex_wmm_desc {
struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
......
...@@ -916,8 +916,12 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, ...@@ -916,8 +916,12 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
do { do {
priv_tmp = bssprio_node->priv; 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) { for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
tid_ptr = &(priv_tmp)->wmm. tid_ptr = &(priv_tmp)->wmm.
...@@ -976,12 +980,7 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, ...@@ -976,12 +980,7 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
} while (ptr != head); } while (ptr != head);
} }
/* No packet at any TID for this priv. Mark as such skip_bss:
* to skip checking TIDs for this priv (until pkt is
* added).
*/
atomic_set(hqp, NO_PKT_PRIO_TID);
/* Get next bss priority node */ /* Get next bss priority node */
bssprio_node = list_first_entry(&bssprio_node->list, bssprio_node = list_first_entry(&bssprio_node->list,
struct mwifiex_bss_prio_node, struct mwifiex_bss_prio_node,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment