diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-02-27 11:50:05 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2014-02-28 04:59:55 -0500 |
commit | 45967089d2685d2327c9710fe796d499d90ae844 (patch) | |
tree | 7600c8c437adc82454701f7a0991f4cfefbdea79 | |
parent | 6c5151a9ffa9f796f2d707617cecb6b6b241dff8 (diff) |
ath10k: reduce htt tx/rx spinlock overhead
It is inefficient to grab irqsave spinlocks for
skb lists for each queue/dequeue action.
Using rx_ring.lock and tx_lock allows to use less
heavy bh spinlock functions and moving locking
upwards allows to toggle spinlocks less often.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt_rx.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt_tx.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/txrx.c | 4 |
3 files changed, 23 insertions, 10 deletions
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index b7150de984e7..8e708dfb63e3 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c | |||
@@ -274,7 +274,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) | |||
274 | int idx; | 274 | int idx; |
275 | struct sk_buff *msdu; | 275 | struct sk_buff *msdu; |
276 | 276 | ||
277 | spin_lock_bh(&htt->rx_ring.lock); | 277 | lockdep_assert_held(&htt->rx_ring.lock); |
278 | 278 | ||
279 | if (ath10k_htt_rx_ring_elems(htt) == 0) | 279 | if (ath10k_htt_rx_ring_elems(htt) == 0) |
280 | ath10k_warn("htt rx ring is empty!\n"); | 280 | ath10k_warn("htt rx ring is empty!\n"); |
@@ -287,7 +287,6 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) | |||
287 | htt->rx_ring.sw_rd_idx.msdu_payld = idx; | 287 | htt->rx_ring.sw_rd_idx.msdu_payld = idx; |
288 | htt->rx_ring.fill_cnt--; | 288 | htt->rx_ring.fill_cnt--; |
289 | 289 | ||
290 | spin_unlock_bh(&htt->rx_ring.lock); | ||
291 | return msdu; | 290 | return msdu; |
292 | } | 291 | } |
293 | 292 | ||
@@ -311,6 +310,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, | |||
311 | struct sk_buff *msdu; | 310 | struct sk_buff *msdu; |
312 | struct htt_rx_desc *rx_desc; | 311 | struct htt_rx_desc *rx_desc; |
313 | 312 | ||
313 | lockdep_assert_held(&htt->rx_ring.lock); | ||
314 | |||
314 | if (ath10k_htt_rx_ring_elems(htt) == 0) | 315 | if (ath10k_htt_rx_ring_elems(htt) == 0) |
315 | ath10k_warn("htt rx ring is empty!\n"); | 316 | ath10k_warn("htt rx ring is empty!\n"); |
316 | 317 | ||
@@ -918,6 +919,8 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, | |||
918 | u8 *fw_desc; | 919 | u8 *fw_desc; |
919 | int i, j; | 920 | int i, j; |
920 | 921 | ||
922 | lockdep_assert_held(&htt->rx_ring.lock); | ||
923 | |||
921 | memset(&info, 0, sizeof(info)); | 924 | memset(&info, 0, sizeof(info)); |
922 | 925 | ||
923 | fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes); | 926 | fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes); |
@@ -1055,8 +1058,11 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, | |||
1055 | 1058 | ||
1056 | msdu_head = NULL; | 1059 | msdu_head = NULL; |
1057 | msdu_tail = NULL; | 1060 | msdu_tail = NULL; |
1061 | |||
1062 | spin_lock_bh(&htt->rx_ring.lock); | ||
1058 | msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, | 1063 | msdu_chaining = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len, |
1059 | &msdu_head, &msdu_tail); | 1064 | &msdu_head, &msdu_tail); |
1065 | spin_unlock_bh(&htt->rx_ring.lock); | ||
1060 | 1066 | ||
1061 | ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); | 1067 | ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); |
1062 | 1068 | ||
@@ -1158,6 +1164,8 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, | |||
1158 | __le16 msdu_id; | 1164 | __le16 msdu_id; |
1159 | int i; | 1165 | int i; |
1160 | 1166 | ||
1167 | lockdep_assert_held(&htt->tx_lock); | ||
1168 | |||
1161 | switch (status) { | 1169 | switch (status) { |
1162 | case HTT_DATA_TX_STATUS_NO_ACK: | 1170 | case HTT_DATA_TX_STATUS_NO_ACK: |
1163 | tx_done.no_ack = true; | 1171 | tx_done.no_ack = true; |
@@ -1204,7 +1212,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) | |||
1204 | break; | 1212 | break; |
1205 | } | 1213 | } |
1206 | case HTT_T2H_MSG_TYPE_RX_IND: | 1214 | case HTT_T2H_MSG_TYPE_RX_IND: |
1207 | skb_queue_tail(&htt->rx_compl_q, skb); | 1215 | spin_lock_bh(&htt->rx_ring.lock); |
1216 | __skb_queue_tail(&htt->rx_compl_q, skb); | ||
1217 | spin_unlock_bh(&htt->rx_ring.lock); | ||
1208 | tasklet_schedule(&htt->txrx_compl_task); | 1218 | tasklet_schedule(&htt->txrx_compl_task); |
1209 | return; | 1219 | return; |
1210 | case HTT_T2H_MSG_TYPE_PEER_MAP: { | 1220 | case HTT_T2H_MSG_TYPE_PEER_MAP: { |
@@ -1298,14 +1308,18 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) | |||
1298 | struct htt_resp *resp; | 1308 | struct htt_resp *resp; |
1299 | struct sk_buff *skb; | 1309 | struct sk_buff *skb; |
1300 | 1310 | ||
1301 | while ((skb = skb_dequeue(&htt->tx_compl_q))) { | 1311 | spin_lock_bh(&htt->tx_lock); |
1312 | while ((skb = __skb_dequeue(&htt->tx_compl_q))) { | ||
1302 | ath10k_htt_rx_frm_tx_compl(htt->ar, skb); | 1313 | ath10k_htt_rx_frm_tx_compl(htt->ar, skb); |
1303 | dev_kfree_skb_any(skb); | 1314 | dev_kfree_skb_any(skb); |
1304 | } | 1315 | } |
1316 | spin_unlock_bh(&htt->tx_lock); | ||
1305 | 1317 | ||
1306 | while ((skb = skb_dequeue(&htt->rx_compl_q))) { | 1318 | spin_lock_bh(&htt->rx_ring.lock); |
1319 | while ((skb = __skb_dequeue(&htt->rx_compl_q))) { | ||
1307 | resp = (struct htt_resp *)skb->data; | 1320 | resp = (struct htt_resp *)skb->data; |
1308 | ath10k_htt_rx_handler(htt, &resp->rx_ind); | 1321 | ath10k_htt_rx_handler(htt, &resp->rx_ind); |
1309 | dev_kfree_skb_any(skb); | 1322 | dev_kfree_skb_any(skb); |
1310 | } | 1323 | } |
1324 | spin_unlock_bh(&htt->rx_ring.lock); | ||
1311 | } | 1325 | } |
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 20b7a446a9f8..7a3e2e40dd5c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c | |||
@@ -125,9 +125,7 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt) | |||
125 | struct htt_tx_done tx_done = {0}; | 125 | struct htt_tx_done tx_done = {0}; |
126 | int msdu_id; | 126 | int msdu_id; |
127 | 127 | ||
128 | /* No locks needed. Called after communication with the device has | 128 | spin_lock_bh(&htt->tx_lock); |
129 | * been stopped. */ | ||
130 | |||
131 | for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) { | 129 | for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) { |
132 | if (!test_bit(msdu_id, htt->used_msdu_ids)) | 130 | if (!test_bit(msdu_id, htt->used_msdu_ids)) |
133 | continue; | 131 | continue; |
@@ -140,6 +138,7 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt) | |||
140 | 138 | ||
141 | ath10k_txrx_tx_unref(htt, &tx_done); | 139 | ath10k_txrx_tx_unref(htt, &tx_done); |
142 | } | 140 | } |
141 | spin_unlock_bh(&htt->tx_lock); | ||
143 | } | 142 | } |
144 | 143 | ||
145 | void ath10k_htt_tx_detach(struct ath10k_htt *htt) | 144 | void ath10k_htt_tx_detach(struct ath10k_htt *htt) |
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 2993ca772c56..0541dd939ce9 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c | |||
@@ -52,6 +52,8 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, | |||
52 | struct ath10k_skb_cb *skb_cb; | 52 | struct ath10k_skb_cb *skb_cb; |
53 | struct sk_buff *msdu; | 53 | struct sk_buff *msdu; |
54 | 54 | ||
55 | lockdep_assert_held(&htt->tx_lock); | ||
56 | |||
55 | ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", | 57 | ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", |
56 | tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack); | 58 | tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack); |
57 | 59 | ||
@@ -91,13 +93,11 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, | |||
91 | /* we do not own the msdu anymore */ | 93 | /* we do not own the msdu anymore */ |
92 | 94 | ||
93 | exit: | 95 | exit: |
94 | spin_lock_bh(&htt->tx_lock); | ||
95 | htt->pending_tx[tx_done->msdu_id] = NULL; | 96 | htt->pending_tx[tx_done->msdu_id] = NULL; |
96 | ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); | 97 | ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); |
97 | __ath10k_htt_tx_dec_pending(htt); | 98 | __ath10k_htt_tx_dec_pending(htt); |
98 | if (htt->num_pending_tx == 0) | 99 | if (htt->num_pending_tx == 0) |
99 | wake_up(&htt->empty_tx_wq); | 100 | wake_up(&htt->empty_tx_wq); |
100 | spin_unlock_bh(&htt->tx_lock); | ||
101 | } | 101 | } |
102 | 102 | ||
103 | static const u8 rx_legacy_rate_idx[] = { | 103 | static const u8 rx_legacy_rate_idx[] = { |