rpcd: iwinfo plugin fixes
[openwrt.git] / package / kernel / mac80211 / patches / 333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch
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
4
5 This massively reduces data copying and thus improves rx performance
6
7 Signed-off-by: Felix Fietkau <nbd@nbd.name>
8 ---
9
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
13  }
14  EXPORT_SYMBOL(ieee80211_data_from_8023);
15  
16 +static void
17 +__frame_add_frag(struct sk_buff *skb, struct page *page,
18 +                void *ptr, int len, int size)
19 +{
20 +       struct skb_shared_info *sh = skb_shinfo(skb);
21 +       int page_offset;
22 +
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);
26 +}
27 +
28 +static void
29 +__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
30 +                           int offset, int len)
31 +{
32 +       struct skb_shared_info *sh = skb_shinfo(skb);
33 +       const skb_frag_t *frag = &sh->frags[-1];
34 +       struct page *frag_page;
35 +       void *frag_ptr;
36 +       int frag_len, frag_size;
37 +       int head_size = skb->len - skb->data_len;
38 +       int cur_len;
39 +
40 +       frag_page = virt_to_head_page(skb->head);
41 +       frag_ptr = skb->data;
42 +       frag_size = head_size;
43 +
44 +       while (offset >= frag_size) {
45 +               offset -= frag_size;
46 +               frag++;
47 +               frag_page = skb_frag_page(frag);
48 +               frag_ptr = skb_frag_address(frag);
49 +               frag_size = skb_frag_size(frag);
50 +       }
51 +
52 +       frag_ptr += offset;
53 +       frag_len = frag_size - offset;
54 +
55 +       cur_len = min(len, frag_len);
56 +
57 +       __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size);
58 +       len -= cur_len;
59 +
60 +       while (len > 0) {
61 +               frag++;
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);
66 +               len -= cur_len;
67 +       }
68 +}
69 +
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)
74  {
75         struct sk_buff *frame;
76 +       int cur_len = len;
77  
78         if (skb->len - offset < len)
79                 return NULL;
80  
81         /*
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.
85 +        */
86 +       if (reuse_frag)
87 +               cur_len = min_t(int, len, 32);
88 +
89 +       /*
90          * Allocate and reserve two bytes more for payload
91          * alignment since sizeof(struct ethhdr) is 14.
92          */
93 -       frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len);
94 +       frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len);
95  
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);
99 +
100 +       len -= cur_len;
101 +       if (!len)
102 +               return frame;
103 +
104 +       offset += cur_len;
105 +       __ieee80211_amsdu_copy_frag(skb, frame, offset, len);
106  
107         return frame;
108  }
109 @@ -676,6 +746,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
110         u8 *payload;
111         int offset = 0, remaining, err;
112         struct ethhdr eth;
113 +       bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
114         bool reuse_skb = false;
115         bool last = false;
116  
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);
124                         frame = skb;
125                         reuse_skb = true;
126                 } else {
127 -                       frame = __ieee80211_amsdu_copy(skb, hlen, offset, len);
128 +                       frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
129 +                                                      reuse_frag);
130                         if (!frame)
131                                 goto purge;
132