From f699254c7126d7df94491dfd4c3648f8ec0c0d51 Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Mon, 16 May 2011 19:17:49 -0700 Subject: mwifiex: reduce CPU usage by tracking tx_pkts_queued This patch adds tx_pkts_queued to track number of packets being enqueued & dequeued so that mwifiex_wmm_lists_empty() evaluation is lightweight. Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/11n_aggr.c | 4 ++++ drivers/net/wireless/mwifiex/main.h | 3 ++- drivers/net/wireless/mwifiex/wmm.c | 22 +++++++++++++--------- 3 files changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/mwifiex') diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index d3d5e0853c45..f807447e4d99 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -196,6 +196,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, if (skb_src) pra_list->total_pkts_size -= skb_src->len; + atomic_dec(&priv->wmm.tx_pkts_queued); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad); @@ -257,6 +259,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, pra_list->total_pkts_size += skb_aggr->len; + atomic_inc(&priv->wmm.tx_pkts_queued); + tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 672701dc2721..537b40dc016e 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -213,7 +213,8 @@ struct mwifiex_wmm_desc { u32 drv_pkt_delay_max; u8 queue_priority[IEEE80211_MAX_QUEUES]; u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */ - + /* Number of transmit packets queued */ + atomic_t tx_pkts_queued; }; struct mwifiex_802_11_security { diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index faa09e32902e..52d218512c1e 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -399,6 +399,8 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT; priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE; priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE; + + atomic_set(&priv->wmm.tx_pkts_queued, 0); } } @@ -408,17 +410,13 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) { - int i, j; + int i; struct mwifiex_private *priv; - for (j = 0; j < adapter->priv_num; ++j) { - priv = adapter->priv[j]; - if (priv) { - for (i = 0; i < MAX_NUM_TID; i++) - if (!mwifiex_wmm_is_ra_list_empty( - &priv->wmm.tid_tbl_ptr[i].ra_list)) - return false; - } + for (i = 0; i < adapter->priv_num; ++i) { + priv = adapter->priv[i]; + if (priv && atomic_read(&priv->wmm.tx_pkts_queued)) + return false; } return true; @@ -468,6 +466,8 @@ static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv) for (i = 0; i < MAX_NUM_TID; i++) mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i]. ra_list); + + atomic_set(&priv->wmm.tx_pkts_queued, 0); } /* @@ -638,6 +638,8 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, ra_list->total_pkts_size += skb->len; + atomic_inc(&priv->wmm.tx_pkts_queued); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } @@ -1028,6 +1030,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, .bss_prio_cur->list, struct mwifiex_bss_prio_node, list); + atomic_dec(&priv->wmm.tx_pkts_queued); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); } @@ -1134,6 +1137,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, .bss_prio_cur->list, struct mwifiex_bss_prio_node, list); + atomic_dec(&priv->wmm.tx_pkts_queued); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); } -- cgit v1.2.3 From 49729ff616547d7abcb96924d14aa860320e7352 Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Mon, 16 May 2011 19:17:50 -0700 Subject: mwifiex: reduce CPU usage by tracking highest_queued_prio This patch adds highest_queued_prio to track priority of packets as they are enqueued so that mwifiex_wmm_get_highest_priolist_ptr() starts checking at the first level where we have packets, instead of the highest. The function also lowers priority value to the level where first packet is found. Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/wmm.c | 29 ++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/mwifiex') diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 537b40dc016e..ea3184d15674 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -215,6 +215,8 @@ struct mwifiex_wmm_desc { u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */ /* Number of transmit packets queued */ atomic_t tx_pkts_queued; + /* Tracks highest priority with a packet queued */ + atomic_t highest_queued_prio; }; struct mwifiex_802_11_security { diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 52d218512c1e..f3d5f23c91d1 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -177,14 +177,20 @@ static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv) * This function map ACs to TIDs. */ static void -mwifiex_wmm_queue_priorities_tid(u8 queue_priority[]) +mwifiex_wmm_queue_priorities_tid(struct mwifiex_wmm_desc *wmm) { + u8 *queue_priority = wmm->queue_priority; int i; for (i = 0; i < 4; ++i) { tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1]; tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0]; } + + for (i = 0; i < MAX_NUM_TID; ++i) + tos_to_tid_inv[tos_to_tid[i]] = (u8)i; + + atomic_set(&wmm->highest_queued_prio, HIGH_PRIO_TID); } /* @@ -246,7 +252,7 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv, } } - mwifiex_wmm_queue_priorities_tid(priv->wmm.queue_priority); + mwifiex_wmm_queue_priorities_tid(&priv->wmm); } /* @@ -401,6 +407,7 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE; atomic_set(&priv->wmm.tx_pkts_queued, 0); + atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); } } @@ -468,6 +475,7 @@ static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv) ra_list); atomic_set(&priv->wmm.tx_pkts_queued, 0); + atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); } /* @@ -640,6 +648,11 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, atomic_inc(&priv->wmm.tx_pkts_queued); + if (atomic_read(&priv->wmm.highest_queued_prio) < + tos_to_tid_inv[tid_down]) + atomic_set(&priv->wmm.highest_queued_prio, + tos_to_tid_inv[tid_down]); + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } @@ -865,9 +878,14 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, } do { + atomic_t *hqp; + spinlock_t *lock; + priv_tmp = bssprio_node->priv; + hqp = &priv_tmp->wmm.highest_queued_prio; + lock = &priv_tmp->wmm.ra_list_spinlock; - for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) { + for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) { tid_ptr = &(priv_tmp)->wmm. tid_tbl_ptr[tos_to_tid[i]]; @@ -905,6 +923,11 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, is_list_empty = skb_queue_empty(&ptr->skb_head); if (!is_list_empty) { + spin_lock_irqsave(lock, flags); + if (atomic_read(hqp) > i) + atomic_set(hqp, i); + spin_unlock_irqrestore(lock, + flags); *priv = priv_tmp; *tid = tos_to_tid[i]; return ptr; -- cgit v1.2.3 From 93968147874508e6dd534af1e236a7353269da3f Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Mon, 16 May 2011 19:17:51 -0700 Subject: mwifiex: check mwifiex_wmm_lists_empty() before dequeue add checks to mwifiex_wmm_process_tx() loop so it doesn't re-enter mwifiex_dequeue_tx_packet() to find it can't send. Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/wmm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/mwifiex') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index f3d5f23c91d1..784ad4c00995 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1254,5 +1254,5 @@ mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter) if (mwifiex_dequeue_tx_packet(adapter)) break; - } while (true); + } while (!mwifiex_wmm_lists_empty(adapter)); } -- cgit v1.2.3 From 17e8cec87586c26b953c6541c8a045e906ea046c Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Mon, 16 May 2011 19:17:52 -0700 Subject: mwifiex: CPU mips optimization with NO_PKT_PRIO_TID If we go through the entire for loop in mwifiex_wmm_get_highest_priolist_ptr() and don't find any packets, set highest_queued_prio to NO_PKT_PRIO_TID (< LOW_PRIO_TID). Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/wmm.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'drivers/net/wireless/mwifiex') diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index ea3184d15674..3154b0a31ea6 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -202,6 +202,7 @@ 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 784ad4c00995..91634daec306 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -946,6 +946,12 @@ 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); + /* Get next bss priority node */ bssprio_node = list_first_entry(&bssprio_node->list, struct mwifiex_bss_prio_node, -- cgit v1.2.3 From 62a5b7dcee00c8e64e61ed98541c95fd38583116 Mon Sep 17 00:00:00 2001 From: Marc Yang Date: Mon, 16 May 2011 19:17:53 -0700 Subject: mwifiex: adjust high/low water marks for tx_pending queue This is to fix an issue that the throughput of the higher priority stream gets dropped when a lower priority stream is present. Signed-off-by: Marc Yang Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.h | 3 ++- drivers/net/wireless/mwifiex/txrx.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/mwifiex') diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 3154b0a31ea6..8316b3cd92cd 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -69,7 +69,8 @@ struct mwifiex_drv_mode { #define MWIFIEX_TIMER_10S 10000 #define MWIFIEX_TIMER_1S 1000 -#define MAX_TX_PENDING 60 +#define MAX_TX_PENDING 100 +#define LOW_TX_PENDING 80 #define MWIFIEX_UPLD_SIZE (2312) diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 210120889dfe..aaa50c074196 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -140,7 +140,9 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, } else { priv->stats.tx_errors++; } - atomic_dec(&adapter->tx_pending); + + if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING) + goto done; for (i = 0; i < adapter->priv_num; i++) { -- cgit v1.2.3