diff options
author | Andreas Fenkart <andreas.fenkart@streamunlimited.com> | 2013-04-04 23:03:52 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-04-08 15:28:39 -0400 |
commit | 333f6b22c5b88a9d856703b440257f46efa714c8 (patch) | |
tree | 4cc881717c225356f42d0870997332b424e0a2ae /drivers/net/wireless | |
parent | 6d2344ec6043a2de8cfa9d8f27909a99ca967a08 (diff) |
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.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/wmm.c | 13 |
2 files changed, 6 insertions, 8 deletions
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 622b17f884f0..b7484efc9443 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -219,7 +219,6 @@ struct mwifiex_tid_tbl { | |||
219 | #define WMM_HIGHEST_PRIORITY 7 | 219 | #define WMM_HIGHEST_PRIORITY 7 |
220 | #define HIGH_PRIO_TID 7 | 220 | #define HIGH_PRIO_TID 7 |
221 | #define LOW_PRIO_TID 0 | 221 | #define LOW_PRIO_TID 0 |
222 | #define NO_PKT_PRIO_TID (-1) | ||
223 | 222 | ||
224 | struct mwifiex_wmm_desc { | 223 | struct mwifiex_wmm_desc { |
225 | struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; | 224 | 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 c1d848882fe2..75c8e80bb62f 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, | |||
916 | 916 | ||
917 | do { | 917 | do { |
918 | priv_tmp = bssprio_node->priv; | 918 | priv_tmp = bssprio_node->priv; |
919 | hqp = &priv_tmp->wmm.highest_queued_prio; | ||
920 | 919 | ||
920 | if (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0) | ||
921 | goto skip_bss; | ||
922 | |||
923 | /* iterate over the WMM queues of the BSS */ | ||
924 | hqp = &priv_tmp->wmm.highest_queued_prio; | ||
921 | for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) { | 925 | for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) { |
922 | 926 | ||
923 | tid_ptr = &(priv_tmp)->wmm. | 927 | tid_ptr = &(priv_tmp)->wmm. |
@@ -976,12 +980,7 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, | |||
976 | } while (ptr != head); | 980 | } while (ptr != head); |
977 | } | 981 | } |
978 | 982 | ||
979 | /* No packet at any TID for this priv. Mark as such | 983 | skip_bss: |
980 | * to skip checking TIDs for this priv (until pkt is | ||
981 | * added). | ||
982 | */ | ||
983 | atomic_set(hqp, NO_PKT_PRIO_TID); | ||
984 | |||
985 | /* Get next bss priority node */ | 984 | /* Get next bss priority node */ |
986 | bssprio_node = list_first_entry(&bssprio_node->list, | 985 | bssprio_node = list_first_entry(&bssprio_node->list, |
987 | struct mwifiex_bss_prio_node, | 986 | struct mwifiex_bss_prio_node, |