ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 701-net-0022-sdk_dpaa-ls1043a-errata-realign-and-linearize-egress.patch
1 From 9821d27a36704d19c57d4b6c52585b9868703633 Mon Sep 17 00:00:00 2001
2 From: Camelia Groza <camelia.groza@nxp.com>
3 Date: Mon, 4 Sep 2017 13:41:17 +0300
4 Subject: [PATCH] sdk_dpaa: ls1043a errata: realign and linearize egress skbs
5
6 Allocate a new page and copy the skb's contents to it in order to
7 guarantee that 4k boundary crossings do not occur.
8
9 Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
10 ---
11  .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c  | 159 +++++++++++----------
12  1 file changed, 84 insertions(+), 75 deletions(-)
13
14 --- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
15 +++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
16 @@ -742,86 +742,94 @@ int __hot skb_to_contig_fd(struct dpa_pr
17  EXPORT_SYMBOL(skb_to_contig_fd);
18  
19  #ifndef CONFIG_PPC
20 -struct sk_buff *split_skb_at_4k_boundaries(struct sk_buff *skb)
21 +/* Verify the conditions that trigger the A010022 errata: 4K memory address
22 + * crossings.
23 + */
24 +bool a010022_check_skb(struct sk_buff *skb)
25  {
26 -       unsigned int length, nr_frags, moved_len = 0;
27 -       u64 page_start;
28 -       struct page *page;
29 +       int nr_frags, i = 0;
30         skb_frag_t *frag;
31 -       int i = 0, j = 0;
32  
33 -       /* make sure skb is not shared */
34 -       skb = skb_share_check(skb, GFP_ATOMIC);
35 -       if (!skb)
36 -               return NULL;
37 +       /* Check if the headroom crosses a boundary */
38 +       if (HAS_DMA_ISSUE(skb->head, skb_headroom(skb)))
39 +               return true;
40 +
41 +       /* Check if the non-paged data crosses a boundary */
42 +       if (HAS_DMA_ISSUE(skb->data, skb_headlen(skb)))
43 +               return true;
44 +
45 +       /* Check if the entire linear skb crosses a boundary */
46 +       if (HAS_DMA_ISSUE(skb->head, skb_end_offset(skb)))
47 +               return true;
48  
49         nr_frags = skb_shinfo(skb)->nr_frags;
50 -       page_start = (u64)skb->data;
51  
52 -       /* split the linear part at the first 4k boundary and create one (big)
53 -        * fragment with the rest
54 -        */
55 -       if (HAS_DMA_ISSUE(skb->data, skb_headlen(skb))) {
56 -               /* we'll add one more frag, make sure there's room */
57 -               if (nr_frags + 1 > DPA_SGT_MAX_ENTRIES)
58 -                       return NULL;
59 -
60 -               /* next page boundary */
61 -               page_start = (page_start + 0x1000) & ~0xFFF;
62 -               page = virt_to_page(page_start);
63 -
64 -               /* move the rest of fragments to make room for a new one at j */
65 -               for (i = nr_frags - 1; i >= j;  i--)
66 -                       skb_shinfo(skb)->frags[i + 1] = skb_shinfo(skb)->frags[i];
67 -
68 -               /* move length bytes to a paged fragment at j */
69 -               length = min((u64)0x1000,
70 -                            (u64)skb->data + skb_headlen(skb) - page_start);
71 -               skb->data_len += length;
72 -               moved_len += length;
73 -               skb_fill_page_desc(skb, j++, page, 0, length);
74 -               get_page(page);
75 -               skb_shinfo(skb)->nr_frags = ++nr_frags;
76 +       while (i < nr_frags) {
77 +               frag = &skb_shinfo(skb)->frags[i];
78 +
79 +               /* Check if the paged fragment crosses a boundary from its
80 +                * offset to its end.
81 +                */
82 +               if (HAS_DMA_ISSUE(frag->page_offset, frag->size))
83 +                       return true;
84 +
85 +               i++;
86         }
87 -       /* adjust the tail pointer */
88 -       skb->tail -= moved_len;
89 -       j = 0;
90 -
91 -       /* split any paged fragment that crosses a 4K boundary */
92 -       while (j < nr_frags) {
93 -               frag = &skb_shinfo(skb)->frags[j];
94 -
95 -               /* if there is a 4K boundary between the fragment's offset and end */
96 -               if (HAS_DMA_ISSUE(frag->page_offset, frag->size)) {
97 -                       /* we'll add one more frag, make sure there's room */
98 -                       if (nr_frags + 1 > DPA_SGT_MAX_ENTRIES)
99 -                               return NULL;
100 -
101 -                       /* new page boundary */
102 -                       page_start = (u64)page_address(skb_frag_page(frag)) +
103 -                                                 frag->page_offset + 0x1000;
104 -                       page_start = (u64)page_start & ~0xFFF;
105 -                       page = virt_to_page(page_start);
106 -
107 -                       /* move the rest of fragments to make room for a new one at j+1 */
108 -                       for (i = nr_frags - 1; i > j;  i--)
109 -                               skb_shinfo(skb)->frags[i + 1] =
110 -                                               skb_shinfo(skb)->frags[i];
111 -
112 -                       /* move length bytes to a new paged fragment at j+1 */
113 -                       length = (u64)page_address(skb_frag_page(frag)) +
114 -                                frag->page_offset + frag->size - page_start;
115 -                       frag->size -= length;
116 -                       skb_fill_page_desc(skb, j + 1, page, 0, length);
117 -                       get_page(page);
118 -                       skb_shinfo(skb)->nr_frags = ++nr_frags;
119 -               }
120  
121 -               /* move to next frag */
122 -               j++;
123 +       return false;
124 +}
125 +
126 +/* Realign the skb by copying its contents at the start of a newly allocated
127 + * page. Build a new skb around the new buffer and release the old one.
128 + * A performance drop should be expected.
129 + */
130 +struct sk_buff *a010022_realign_skb(struct sk_buff *skb)
131 +{
132 +       int headroom = skb_headroom(skb);
133 +       struct sk_buff *nskb = NULL;
134 +       struct page *npage;
135 +       void *npage_addr;
136 +       int nsize;
137 +
138 +       npage = alloc_page(GFP_ATOMIC);
139 +       if (unlikely(!npage)) {
140 +               WARN_ONCE(1, "Memory allocation failure\n");
141 +               return NULL;
142 +       }
143 +       npage_addr = page_address(npage);
144 +
145 +       /* For the new skb we only need the old one's data (both non-paged and
146 +        * paged) and a headroom large enough to fit our private info. We can
147 +        * skip the old tailroom.
148 +        *
149 +        * Make sure the new linearized buffer will not exceed a page's size.
150 +        */
151 +       nsize = headroom + skb->len +
152 +               SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
153 +       if (unlikely(nsize > 4096))
154 +               goto err;
155 +
156 +       nskb = build_skb(npage_addr, nsize);
157 +       if (unlikely(!nskb))
158 +               goto err;
159 +
160 +       /* Code borrowed and adapted from skb_copy() */
161 +       skb_reserve(nskb, headroom);
162 +       skb_put(nskb, skb->len);
163 +       if (skb_copy_bits(skb, 0, nskb->data, skb->len)) {
164 +               WARN_ONCE(1, "skb parsing failure\n");
165 +               goto err;
166         }
167 +       copy_skb_header(nskb, skb);
168 +
169 +       dev_kfree_skb(skb);
170 +       return nskb;
171  
172 -       return skb;
173 +err:
174 +       if (nskb)
175 +               dev_kfree_skb(nskb);
176 +       put_page(npage);
177 +       return NULL;
178  }
179  #endif
180  
181 @@ -1016,9 +1024,9 @@ int __hot dpa_tx_extended(struct sk_buff
182  #endif /* CONFIG_FSL_DPAA_TS */
183  
184  #ifndef CONFIG_PPC
185 -resplit_4k:
186 -       if (unlikely(dpaa_errata_a010022)) {
187 -               skb = split_skb_at_4k_boundaries(skb);
188 +realign_4k:
189 +       if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb)) {
190 +               skb = a010022_realign_skb(skb);
191                 if (!skb)
192                         goto skb_to_fd_failed;
193         }
194 @@ -1064,8 +1072,9 @@ resplit_4k:
195                         kfree_skb(skb);
196                         skb = nskb;
197  #ifndef CONFIG_PPC
198 -                       if (unlikely(dpaa_errata_a010022))
199 -                               goto resplit_4k;
200 +                       if (unlikely(dpaa_errata_a010022) &&
201 +                           a010022_check_skb(skb))
202 +                               goto realign_4k;
203  #endif
204                         /* skb_copy() has now linearized the skbuff. */
205                 } else if (unlikely(nonlinear)) {