diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2013-09-18 08:43:22 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2013-09-20 01:18:10 -0400 |
commit | 1f8bb1518eee321d94477ca7bcbb153c47d43ba4 (patch) | |
tree | 1d2242d63ab28b1de5c4a67b5b749ba8fd1a9437 /drivers/net | |
parent | 2f3773bcaf9fbf3ddb9d4315e3a3ca5e4b376cef (diff) |
ath10k: use msdu headroom to store txfrag
Instead of allocating sk_buff for a mere 16-byte
tx fragment list buffer use headroom of the
original msdu sk_buff.
This decreases CPU cache pressure and improves
performance.
Measured improvement on AP135 is 560mbps ->
590mbps of UDP TX briding traffic.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/htt_tx.c | 82 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/txrx.c | 16 |
4 files changed, 53 insertions, 53 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 4563f800a291..292ad4577c98 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
@@ -54,7 +54,9 @@ struct ath10k_skb_cb { | |||
54 | u8 vdev_id; | 54 | u8 vdev_id; |
55 | u8 tid; | 55 | u8 tid; |
56 | bool is_offchan; | 56 | bool is_offchan; |
57 | struct sk_buff *txfrag; | 57 | |
58 | u8 frag_len; | ||
59 | u8 pad_len; | ||
58 | } __packed htt; | 60 | } __packed htt; |
59 | } __packed; | 61 | } __packed; |
60 | 62 | ||
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 5e738d80138f..3b93c6a01c6c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c | |||
@@ -307,7 +307,8 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
307 | struct device *dev = htt->ar->dev; | 307 | struct device *dev = htt->ar->dev; |
308 | struct sk_buff *txdesc = NULL; | 308 | struct sk_buff *txdesc = NULL; |
309 | struct htt_cmd *cmd; | 309 | struct htt_cmd *cmd; |
310 | u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id; | 310 | struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); |
311 | u8 vdev_id = skb_cb->htt.vdev_id; | ||
311 | int len = 0; | 312 | int len = 0; |
312 | int msdu_id = -1; | 313 | int msdu_id = -1; |
313 | int res; | 314 | int res; |
@@ -350,6 +351,9 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
350 | memcpy(cmd->mgmt_tx.hdr, msdu->data, | 351 | memcpy(cmd->mgmt_tx.hdr, msdu->data, |
351 | min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN)); | 352 | min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN)); |
352 | 353 | ||
354 | skb_cb->htt.frag_len = 0; | ||
355 | skb_cb->htt.pad_len = 0; | ||
356 | |||
353 | res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); | 357 | res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); |
354 | if (res) | 358 | if (res) |
355 | goto err_unmap_msdu; | 359 | goto err_unmap_msdu; |
@@ -377,13 +381,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
377 | struct htt_cmd *cmd; | 381 | struct htt_cmd *cmd; |
378 | struct htt_data_tx_desc_frag *tx_frags; | 382 | struct htt_data_tx_desc_frag *tx_frags; |
379 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; | 383 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; |
384 | struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); | ||
380 | struct sk_buff *txdesc = NULL; | 385 | struct sk_buff *txdesc = NULL; |
381 | struct sk_buff *txfrag = NULL; | ||
382 | bool use_frags; | 386 | bool use_frags; |
383 | u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id; | 387 | u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id; |
384 | u8 tid; | 388 | u8 tid; |
385 | int prefetch_len, desc_len, frag_len; | 389 | int prefetch_len, desc_len; |
386 | dma_addr_t frags_paddr; | ||
387 | int msdu_id = -1; | 390 | int msdu_id = -1; |
388 | int res; | 391 | int res; |
389 | u8 flags0; | 392 | u8 flags0; |
@@ -407,7 +410,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
407 | prefetch_len = roundup(prefetch_len, 4); | 410 | prefetch_len = roundup(prefetch_len, 4); |
408 | 411 | ||
409 | desc_len = sizeof(cmd->hdr) + sizeof(cmd->data_tx) + prefetch_len; | 412 | desc_len = sizeof(cmd->hdr) + sizeof(cmd->data_tx) + prefetch_len; |
410 | frag_len = sizeof(*tx_frags) * 2; | ||
411 | 413 | ||
412 | txdesc = ath10k_htc_alloc_skb(desc_len); | 414 | txdesc = ath10k_htc_alloc_skb(desc_len); |
413 | if (!txdesc) { | 415 | if (!txdesc) { |
@@ -421,41 +423,44 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
421 | use_frags = htt->target_version_major < 3 || | 423 | use_frags = htt->target_version_major < 3 || |
422 | !ieee80211_is_mgmt(hdr->frame_control); | 424 | !ieee80211_is_mgmt(hdr->frame_control); |
423 | 425 | ||
424 | if (use_frags) { | ||
425 | txfrag = dev_alloc_skb(frag_len); | ||
426 | if (!txfrag) { | ||
427 | res = -ENOMEM; | ||
428 | goto err_free_txdesc; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) { | 426 | if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) { |
433 | ath10k_warn("htt alignment check failed. dropping packet.\n"); | 427 | ath10k_warn("htt alignment check failed. dropping packet.\n"); |
434 | res = -EIO; | 428 | res = -EIO; |
435 | goto err_free_txfrag; | 429 | goto err_free_txdesc; |
430 | } | ||
431 | |||
432 | if (use_frags) { | ||
433 | skb_cb->htt.frag_len = sizeof(*tx_frags) * 2; | ||
434 | skb_cb->htt.pad_len = (unsigned long)msdu->data - | ||
435 | round_down((unsigned long)msdu->data, 4); | ||
436 | |||
437 | skb_push(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); | ||
438 | } else { | ||
439 | skb_cb->htt.frag_len = 0; | ||
440 | skb_cb->htt.pad_len = 0; | ||
436 | } | 441 | } |
437 | 442 | ||
438 | res = ath10k_skb_map(dev, msdu); | 443 | res = ath10k_skb_map(dev, msdu); |
439 | if (res) | 444 | if (res) |
440 | goto err_free_txfrag; | 445 | goto err_pull_txfrag; |
441 | 446 | ||
442 | if (use_frags) { | 447 | if (use_frags) { |
448 | dma_sync_single_for_cpu(dev, skb_cb->paddr, msdu->len, | ||
449 | DMA_TO_DEVICE); | ||
450 | |||
443 | /* tx fragment list must be terminated with zero-entry */ | 451 | /* tx fragment list must be terminated with zero-entry */ |
444 | skb_put(txfrag, frag_len); | 452 | tx_frags = (struct htt_data_tx_desc_frag *)msdu->data; |
445 | tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data; | 453 | tx_frags[0].paddr = __cpu_to_le32(skb_cb->paddr + |
446 | tx_frags[0].paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr); | 454 | skb_cb->htt.frag_len + |
447 | tx_frags[0].len = __cpu_to_le32(msdu->len); | 455 | skb_cb->htt.pad_len); |
456 | tx_frags[0].len = __cpu_to_le32(msdu->len - | ||
457 | skb_cb->htt.frag_len - | ||
458 | skb_cb->htt.pad_len); | ||
448 | tx_frags[1].paddr = __cpu_to_le32(0); | 459 | tx_frags[1].paddr = __cpu_to_le32(0); |
449 | tx_frags[1].len = __cpu_to_le32(0); | 460 | tx_frags[1].len = __cpu_to_le32(0); |
450 | 461 | ||
451 | res = ath10k_skb_map(dev, txfrag); | 462 | dma_sync_single_for_device(dev, skb_cb->paddr, msdu->len, |
452 | if (res) | 463 | DMA_TO_DEVICE); |
453 | goto err_unmap_msdu; | ||
454 | |||
455 | ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx\n", | ||
456 | (unsigned long long) ATH10K_SKB_CB(txfrag)->paddr); | ||
457 | ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "txfrag: ", | ||
458 | txfrag->data, frag_len); | ||
459 | } | 464 | } |
460 | 465 | ||
461 | ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n", | 466 | ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n", |
@@ -488,35 +493,28 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) | |||
488 | flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; | 493 | flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; |
489 | flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; | 494 | flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; |
490 | 495 | ||
491 | if (use_frags) | ||
492 | frags_paddr = ATH10K_SKB_CB(txfrag)->paddr; | ||
493 | else | ||
494 | frags_paddr = ATH10K_SKB_CB(msdu)->paddr; | ||
495 | |||
496 | cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; | 496 | cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; |
497 | cmd->data_tx.flags0 = flags0; | 497 | cmd->data_tx.flags0 = flags0; |
498 | cmd->data_tx.flags1 = __cpu_to_le16(flags1); | 498 | cmd->data_tx.flags1 = __cpu_to_le16(flags1); |
499 | cmd->data_tx.len = __cpu_to_le16(msdu->len); | 499 | cmd->data_tx.len = __cpu_to_le16(msdu->len - |
500 | skb_cb->htt.frag_len - | ||
501 | skb_cb->htt.pad_len); | ||
500 | cmd->data_tx.id = __cpu_to_le16(msdu_id); | 502 | cmd->data_tx.id = __cpu_to_le16(msdu_id); |
501 | cmd->data_tx.frags_paddr = __cpu_to_le32(frags_paddr); | 503 | cmd->data_tx.frags_paddr = __cpu_to_le32(skb_cb->paddr); |
502 | cmd->data_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); | 504 | cmd->data_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); |
503 | 505 | ||
504 | memcpy(cmd->data_tx.prefetch, msdu->data, prefetch_len); | 506 | memcpy(cmd->data_tx.prefetch, hdr, prefetch_len); |
505 | 507 | ||
506 | res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); | 508 | res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); |
507 | if (res) | 509 | if (res) |
508 | goto err_restore; | 510 | goto err_unmap_msdu; |
509 | 511 | ||
510 | return 0; | 512 | return 0; |
511 | 513 | ||
512 | err_restore: | ||
513 | if (use_frags) | ||
514 | ath10k_skb_unmap(dev, txfrag); | ||
515 | err_unmap_msdu: | 514 | err_unmap_msdu: |
516 | ath10k_skb_unmap(dev, msdu); | 515 | ath10k_skb_unmap(dev, msdu); |
517 | err_free_txfrag: | 516 | err_pull_txfrag: |
518 | if (use_frags) | 517 | skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); |
519 | dev_kfree_skb_any(txfrag); | ||
520 | err_free_txdesc: | 518 | err_free_txdesc: |
521 | dev_kfree_skb_any(txdesc); | 519 | dev_kfree_skb_any(txdesc); |
522 | err_free_msdu_id: | 520 | err_free_msdu_id: |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 9112e6d6f75c..99a9bad3f398 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -3342,6 +3342,10 @@ int ath10k_mac_register(struct ath10k *ar) | |||
3342 | IEEE80211_HW_WANT_MONITOR_VIF | | 3342 | IEEE80211_HW_WANT_MONITOR_VIF | |
3343 | IEEE80211_HW_AP_LINK_PS; | 3343 | IEEE80211_HW_AP_LINK_PS; |
3344 | 3344 | ||
3345 | /* MSDU can have HTT TX fragment pushed in front. The additional 4 | ||
3346 | * bytes is used for padding/alignment if necessary. */ | ||
3347 | ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4; | ||
3348 | |||
3345 | if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) | 3349 | if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) |
3346 | ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS; | 3350 | ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS; |
3347 | 3351 | ||
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 15395afae957..57931d0fae4b 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c | |||
@@ -49,7 +49,8 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, | |||
49 | { | 49 | { |
50 | struct device *dev = htt->ar->dev; | 50 | struct device *dev = htt->ar->dev; |
51 | struct ieee80211_tx_info *info; | 51 | struct ieee80211_tx_info *info; |
52 | struct sk_buff *msdu, *txfrag; | 52 | struct ath10k_skb_cb *skb_cb; |
53 | struct sk_buff *msdu; | ||
53 | int ret; | 54 | int ret; |
54 | 55 | ||
55 | ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", | 56 | ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n", |
@@ -62,20 +63,15 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, | |||
62 | } | 63 | } |
63 | 64 | ||
64 | msdu = htt->pending_tx[tx_done->msdu_id]; | 65 | msdu = htt->pending_tx[tx_done->msdu_id]; |
65 | txfrag = ATH10K_SKB_CB(msdu)->htt.txfrag; | 66 | skb_cb = ATH10K_SKB_CB(msdu); |
66 | |||
67 | if (txfrag) { | ||
68 | ret = ath10k_skb_unmap(dev, txfrag); | ||
69 | if (ret) | ||
70 | ath10k_warn("txfrag unmap failed (%d)\n", ret); | ||
71 | |||
72 | dev_kfree_skb_any(txfrag); | ||
73 | } | ||
74 | 67 | ||
75 | ret = ath10k_skb_unmap(dev, msdu); | 68 | ret = ath10k_skb_unmap(dev, msdu); |
76 | if (ret) | 69 | if (ret) |
77 | ath10k_warn("data skb unmap failed (%d)\n", ret); | 70 | ath10k_warn("data skb unmap failed (%d)\n", ret); |
78 | 71 | ||
72 | if (skb_cb->htt.frag_len) | ||
73 | skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len); | ||
74 | |||
79 | ath10k_report_offchan_tx(htt->ar, msdu); | 75 | ath10k_report_offchan_tx(htt->ar, msdu); |
80 | 76 | ||
81 | info = IEEE80211_SKB_CB(msdu); | 77 | info = IEEE80211_SKB_CB(msdu); |