1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Mon, 8 Feb 2016 14:33:19 +0100
3 Subject: [PATCH] cfg80211: reuse existing page fragments in A-MSDU rx
5 This massively reduces data copying and thus improves rx performance
7 Signed-off-by: Felix Fietkau <nbd@nbd.name>
10 --- a/net/wireless/util.c
11 +++ b/net/wireless/util.c
12 @@ -644,23 +644,93 @@ int ieee80211_data_from_8023(struct sk_b
14 EXPORT_SYMBOL(ieee80211_data_from_8023);
17 +__frame_add_frag(struct sk_buff *skb, struct page *page,
18 + void *ptr, int len, int size)
20 + struct skb_shared_info *sh = skb_shinfo(skb);
23 + atomic_inc(&page->_count);
24 + page_offset = ptr - page_address(page);
25 + skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size);
29 +__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
30 + int offset, int len)
32 + struct skb_shared_info *sh = skb_shinfo(skb);
33 + const skb_frag_t *frag = &sh->frags[-1];
34 + struct page *frag_page;
36 + int frag_len, frag_size;
37 + int head_size = skb->len - skb->data_len;
40 + frag_page = virt_to_head_page(skb->head);
41 + frag_ptr = skb->data;
42 + frag_size = head_size;
44 + while (offset >= frag_size) {
45 + offset -= frag_size;
47 + frag_page = skb_frag_page(frag);
48 + frag_ptr = skb_frag_address(frag);
49 + frag_size = skb_frag_size(frag);
53 + frag_len = frag_size - offset;
55 + cur_len = min(len, frag_len);
57 + __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size);
62 + frag_len = skb_frag_size(frag);
63 + cur_len = min(len, frag_len);
64 + __frame_add_frag(frame, skb_frag_page(frag),
65 + skb_frag_address(frag), cur_len, frag_len);
70 static struct sk_buff *
71 __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
72 - int offset, int len)
73 + int offset, int len, bool reuse_frag)
75 struct sk_buff *frame;
78 if (skb->len - offset < len)
82 + * When reusing framents, copy some data to the head to simplify
83 + * ethernet header handling and speed up protocol header processing
84 + * in the stack later.
87 + cur_len = min_t(int, len, 32);
90 * Allocate and reserve two bytes more for payload
91 * alignment since sizeof(struct ethhdr) is 14.
93 - frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len);
94 + frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len);
96 skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
97 - skb_copy_bits(skb, offset, skb_put(frame, len), len);
98 + skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
105 + __ieee80211_amsdu_copy_frag(skb, frame, offset, len);
109 @@ -676,6 +746,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
111 int offset = 0, remaining, err;
113 + bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
114 bool reuse_skb = false;
117 @@ -703,12 +774,13 @@ void ieee80211_amsdu_to_8023s(struct sk_
118 offset += sizeof(struct ethhdr);
119 /* reuse skb for the last subframe */
120 last = remaining <= subframe_len + padding;
121 - if (!skb_is_nonlinear(skb) && last) {
122 + if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
123 skb_pull(skb, offset);
127 - frame = __ieee80211_amsdu_copy(skb, hlen, offset, len);
128 + frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,