333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. From: Felix Fietkau <nbd@openwrt.org>
  2. Date: Mon, 8 Feb 2016 14:33:19 +0100
  3. Subject: [PATCH] cfg80211: reuse existing page fragments in A-MSDU rx
  4. This massively reduces data copying and thus improves rx performance
  5. Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  6. ---
  7. --- a/net/wireless/util.c
  8. +++ b/net/wireless/util.c
  9. @@ -644,23 +644,93 @@ int ieee80211_data_from_8023(struct sk_b
  10. }
  11. EXPORT_SYMBOL(ieee80211_data_from_8023);
  12. +static void
  13. +__frame_add_frag(struct sk_buff *skb, struct page *page,
  14. + void *ptr, int len, int size)
  15. +{
  16. + struct skb_shared_info *sh = skb_shinfo(skb);
  17. + int page_offset;
  18. +
  19. + atomic_inc(&page->_count);
  20. + page_offset = ptr - page_address(page);
  21. + skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size);
  22. +}
  23. +
  24. +static void
  25. +__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
  26. + int offset, int len)
  27. +{
  28. + struct skb_shared_info *sh = skb_shinfo(skb);
  29. + const skb_frag_t *frag = &sh->frags[-1];
  30. + struct page *frag_page;
  31. + void *frag_ptr;
  32. + int frag_len, frag_size;
  33. + int head_size = skb->len - skb->data_len;
  34. + int cur_len;
  35. +
  36. + frag_page = virt_to_head_page(skb->head);
  37. + frag_ptr = skb->data;
  38. + frag_size = head_size;
  39. +
  40. + while (offset >= frag_size) {
  41. + offset -= frag_size;
  42. + frag++;
  43. + frag_page = skb_frag_page(frag);
  44. + frag_ptr = skb_frag_address(frag);
  45. + frag_size = skb_frag_size(frag);
  46. + }
  47. +
  48. + frag_ptr += offset;
  49. + frag_len = frag_size - offset;
  50. +
  51. + cur_len = min(len, frag_len);
  52. +
  53. + __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size);
  54. + len -= cur_len;
  55. +
  56. + while (len > 0) {
  57. + frag++;
  58. + frag_len = skb_frag_size(frag);
  59. + cur_len = min(len, frag_len);
  60. + __frame_add_frag(frame, skb_frag_page(frag),
  61. + skb_frag_address(frag), cur_len, frag_len);
  62. + len -= cur_len;
  63. + }
  64. +}
  65. +
  66. static struct sk_buff *
  67. __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
  68. - int offset, int len)
  69. + int offset, int len, bool reuse_frag)
  70. {
  71. struct sk_buff *frame;
  72. + int cur_len = len;
  73. if (skb->len - offset < len)
  74. return NULL;
  75. /*
  76. + * When reusing framents, copy some data to the head to simplify
  77. + * ethernet header handling and speed up protocol header processing
  78. + * in the stack later.
  79. + */
  80. + if (reuse_frag)
  81. + cur_len = min_t(int, len, 32);
  82. +
  83. + /*
  84. * Allocate and reserve two bytes more for payload
  85. * alignment since sizeof(struct ethhdr) is 14.
  86. */
  87. - frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len);
  88. + frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len);
  89. skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
  90. - skb_copy_bits(skb, offset, skb_put(frame, len), len);
  91. + skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
  92. +
  93. + len -= cur_len;
  94. + if (!len)
  95. + return frame;
  96. +
  97. + offset += cur_len;
  98. + __ieee80211_amsdu_copy_frag(skb, frame, offset, len);
  99. return frame;
  100. }
  101. @@ -676,6 +746,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
  102. u8 *payload;
  103. int offset = 0, remaining, err;
  104. struct ethhdr eth;
  105. + bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
  106. bool reuse_skb = false;
  107. bool last = false;
  108. @@ -703,12 +774,13 @@ void ieee80211_amsdu_to_8023s(struct sk_
  109. offset += sizeof(struct ethhdr);
  110. /* reuse skb for the last subframe */
  111. last = remaining <= subframe_len + padding;
  112. - if (!skb_is_nonlinear(skb) && last) {
  113. + if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
  114. skb_pull(skb, offset);
  115. frame = skb;
  116. reuse_skb = true;
  117. } else {
  118. - frame = __ieee80211_amsdu_copy(skb, hlen, offset, len);
  119. + frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
  120. + reuse_frag);
  121. if (!frame)
  122. goto purge;