aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-02-27 11:50:04 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2014-02-28 04:59:25 -0500
commit6c5151a9ffa9f796f2d707617cecb6b6b241dff8 (patch)
tree7d26b8eb0e0c575698a83080e10a183f23e2b197
parenta16942e63008875a6a057ea2973becd261ed0c4e (diff)
ath10k: batch htt tx/rx completions
HTT Rx endpoint processes both frame rx indications and frame tx completion indications. Those completions typically come in batches and may be mixed so it makes sense to defer processing hoping to get a bunch of them and take advantage of hot caches. 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.h7
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c118
2 files changed, 85 insertions, 40 deletions
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 2b76cb5d77a4..654867fc1ae7 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1283,6 +1283,12 @@ struct ath10k_htt {
1283 * used to avoid further failures */ 1283 * used to avoid further failures */
1284 bool rx_confused; 1284 bool rx_confused;
1285 struct tasklet_struct rx_replenish_task; 1285 struct tasklet_struct rx_replenish_task;
1286
1287 /* This is used to group tx/rx completions separately and process them
1288 * in batches to reduce cache stalls */
1289 struct tasklet_struct txrx_compl_task;
1290 struct sk_buff_head tx_compl_q;
1291 struct sk_buff_head rx_compl_q;
1286}; 1292};
1287 1293
1288#define RX_HTT_HDR_STATUS_LEN 64 1294#define RX_HTT_HDR_STATUS_LEN 64
@@ -1354,4 +1360,5 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt);
1354void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id); 1360void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
1355int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *); 1361int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *);
1356int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *); 1362int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *);
1363
1357#endif 1364#endif
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 23d909555e58..b7150de984e7 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -43,7 +43,7 @@
43 43
44 44
45static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb); 45static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
46 46static void ath10k_htt_txrx_compl_task(unsigned long ptr);
47 47
48static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt) 48static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt)
49{ 49{
@@ -237,6 +237,10 @@ void ath10k_htt_rx_detach(struct ath10k_htt *htt)
237 237
238 del_timer_sync(&htt->rx_ring.refill_retry_timer); 238 del_timer_sync(&htt->rx_ring.refill_retry_timer);
239 tasklet_kill(&htt->rx_replenish_task); 239 tasklet_kill(&htt->rx_replenish_task);
240 tasklet_kill(&htt->txrx_compl_task);
241
242 skb_queue_purge(&htt->tx_compl_q);
243 skb_queue_purge(&htt->rx_compl_q);
240 244
241 while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) { 245 while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) {
242 struct sk_buff *skb = 246 struct sk_buff *skb =
@@ -529,6 +533,12 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt)
529 tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task, 533 tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task,
530 (unsigned long)htt); 534 (unsigned long)htt);
531 535
536 skb_queue_head_init(&htt->tx_compl_q);
537 skb_queue_head_init(&htt->rx_compl_q);
538
539 tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
540 (unsigned long)htt);
541
532 ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n", 542 ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
533 htt->rx_ring.size, htt->rx_ring.fill_level); 543 htt->rx_ring.size, htt->rx_ring.fill_level);
534 return 0; 544 return 0;
@@ -1138,6 +1148,43 @@ end:
1138 } 1148 }
1139} 1149}
1140 1150
1151static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
1152 struct sk_buff *skb)
1153{
1154 struct ath10k_htt *htt = &ar->htt;
1155 struct htt_resp *resp = (struct htt_resp *)skb->data;
1156 struct htt_tx_done tx_done = {};
1157 int status = MS(resp->data_tx_completion.flags, HTT_DATA_TX_STATUS);
1158 __le16 msdu_id;
1159 int i;
1160
1161 switch (status) {
1162 case HTT_DATA_TX_STATUS_NO_ACK:
1163 tx_done.no_ack = true;
1164 break;
1165 case HTT_DATA_TX_STATUS_OK:
1166 break;
1167 case HTT_DATA_TX_STATUS_DISCARD:
1168 case HTT_DATA_TX_STATUS_POSTPONE:
1169 case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL:
1170 tx_done.discard = true;
1171 break;
1172 default:
1173 ath10k_warn("unhandled tx completion status %d\n", status);
1174 tx_done.discard = true;
1175 break;
1176 }
1177
1178 ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
1179 resp->data_tx_completion.num_msdus);
1180
1181 for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
1182 msdu_id = resp->data_tx_completion.msdus[i];
1183 tx_done.msdu_id = __le16_to_cpu(msdu_id);
1184 ath10k_txrx_tx_unref(htt, &tx_done);
1185 }
1186}
1187
1141void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) 1188void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
1142{ 1189{
1143 struct ath10k_htt *htt = &ar->htt; 1190 struct ath10k_htt *htt = &ar->htt;
@@ -1156,10 +1203,10 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
1156 complete(&htt->target_version_received); 1203 complete(&htt->target_version_received);
1157 break; 1204 break;
1158 } 1205 }
1159 case HTT_T2H_MSG_TYPE_RX_IND: { 1206 case HTT_T2H_MSG_TYPE_RX_IND:
1160 ath10k_htt_rx_handler(htt, &resp->rx_ind); 1207 skb_queue_tail(&htt->rx_compl_q, skb);
1161 break; 1208 tasklet_schedule(&htt->txrx_compl_task);
1162 } 1209 return;
1163 case HTT_T2H_MSG_TYPE_PEER_MAP: { 1210 case HTT_T2H_MSG_TYPE_PEER_MAP: {
1164 struct htt_peer_map_event ev = { 1211 struct htt_peer_map_event ev = {
1165 .vdev_id = resp->peer_map.vdev_id, 1212 .vdev_id = resp->peer_map.vdev_id,
@@ -1194,44 +1241,17 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
1194 break; 1241 break;
1195 } 1242 }
1196 1243
1244 spin_lock_bh(&htt->tx_lock);
1197 ath10k_txrx_tx_unref(htt, &tx_done); 1245 ath10k_txrx_tx_unref(htt, &tx_done);
1246 spin_unlock_bh(&htt->tx_lock);
1198 break; 1247 break;
1199 } 1248 }
1200 case HTT_T2H_MSG_TYPE_TX_COMPL_IND: { 1249 case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
1201 struct htt_tx_done tx_done = {}; 1250 spin_lock_bh(&htt->tx_lock);
1202 int status = MS(resp->data_tx_completion.flags, 1251 __skb_queue_tail(&htt->tx_compl_q, skb);
1203 HTT_DATA_TX_STATUS); 1252 spin_unlock_bh(&htt->tx_lock);
1204 __le16 msdu_id; 1253 tasklet_schedule(&htt->txrx_compl_task);
1205 int i; 1254 return;
1206
1207 switch (status) {
1208 case HTT_DATA_TX_STATUS_NO_ACK:
1209 tx_done.no_ack = true;
1210 break;
1211 case HTT_DATA_TX_STATUS_OK:
1212 break;
1213 case HTT_DATA_TX_STATUS_DISCARD:
1214 case HTT_DATA_TX_STATUS_POSTPONE:
1215 case HTT_DATA_TX_STATUS_DOWNLOAD_FAIL:
1216 tx_done.discard = true;
1217 break;
1218 default:
1219 ath10k_warn("unhandled tx completion status %d\n",
1220 status);
1221 tx_done.discard = true;
1222 break;
1223 }
1224
1225 ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
1226 resp->data_tx_completion.num_msdus);
1227
1228 for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
1229 msdu_id = resp->data_tx_completion.msdus[i];
1230 tx_done.msdu_id = __le16_to_cpu(msdu_id);
1231 ath10k_txrx_tx_unref(htt, &tx_done);
1232 }
1233 break;
1234 }
1235 case HTT_T2H_MSG_TYPE_SEC_IND: { 1255 case HTT_T2H_MSG_TYPE_SEC_IND: {
1236 struct ath10k *ar = htt->ar; 1256 struct ath10k *ar = htt->ar;
1237 struct htt_security_indication *ev = &resp->security_indication; 1257 struct htt_security_indication *ev = &resp->security_indication;
@@ -1271,3 +1291,21 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
1271 /* Free the indication buffer */ 1291 /* Free the indication buffer */
1272 dev_kfree_skb_any(skb); 1292 dev_kfree_skb_any(skb);
1273} 1293}
1294
1295static void ath10k_htt_txrx_compl_task(unsigned long ptr)
1296{
1297 struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
1298 struct htt_resp *resp;
1299 struct sk_buff *skb;
1300
1301 while ((skb = skb_dequeue(&htt->tx_compl_q))) {
1302 ath10k_htt_rx_frm_tx_compl(htt->ar, skb);
1303 dev_kfree_skb_any(skb);
1304 }
1305
1306 while ((skb = skb_dequeue(&htt->rx_compl_q))) {
1307 resp = (struct htt_resp *)skb->data;
1308 ath10k_htt_rx_handler(htt, &resp->rx_ind);
1309 dev_kfree_skb_any(skb);
1310 }
1311}