1 From fced03d891377fa04153fb0538bc8ca95ba05020 Mon Sep 17 00:00:00 2001
2 From: Madalin Bucur <madalin.bucur@nxp.com>
3 Date: Tue, 14 Nov 2017 08:12:12 +0200
4 Subject: [PATCH] dpaa_eth: workaround for ERR010022
6 On LS1043A SoC there is a known erratum ERR010022 that results in split DMA
7 transfers in the FMan under certain conditions. This, combined with a fixed
8 size FIFO of ongoing DMA transfers that may overflow when a split occurs,
9 results in the FMan stalling DMA transfers under high traffic. To avoid the
10 problem, one needs to prevent the DMA transfer splits to occur by preparing
11 the buffers as follows.
13 In order to prevent split transactions, all frames need to be aligned to 16
14 bytes and not cross 4K address boundaries. To allow Jumbo frames (up to
15 9.6K), all data must be aligned to 256 byes. This way, 4K boundary crossings
16 will not trigger any transaction splits.
18 The errata is prevented from manifesting by realigning all outgoing frames to
19 256 byte boundaries. In the process, all S/G frames are linearized.
21 Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
22 Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
24 Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
26 drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 204 +++++++++++++++++++++++--
27 1 file changed, 194 insertions(+), 10 deletions(-)
29 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
30 +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
32 #include <linux/phy_fixed.h>
33 #include <soc/fsl/bman.h>
34 #include <soc/fsl/qman.h>
35 +#if !defined(CONFIG_PPC) && defined(CONFIG_SOC_BUS)
36 +#include <linux/sys_soc.h> /* soc_device_match */
40 #include "fman_port.h"
42 @@ -73,6 +77,10 @@ static u16 tx_timeout = 1000;
43 module_param(tx_timeout, ushort, 0444);
44 MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms");
47 +bool dpaa_errata_a010022;
50 #define FM_FD_STAT_RX_ERRORS \
51 (FM_FD_ERR_DMA | FM_FD_ERR_PHYSICAL | \
52 FM_FD_ERR_SIZE | FM_FD_ERR_CLS_DISCARD | \
53 @@ -1495,7 +1503,19 @@ static int dpaa_bp_add_8_bufs(const stru
56 for (i = 0; i < 8; i++) {
58 + if (dpaa_errata_a010022) {
59 + struct page *page = alloc_page(GFP_KERNEL);
61 + if (unlikely(!page))
62 + goto release_previous_buffs;
63 + new_buf = page_address(page);
65 + new_buf = netdev_alloc_frag(dpaa_bp->raw_size);
68 new_buf = netdev_alloc_frag(dpaa_bp->raw_size);
70 if (unlikely(!new_buf)) {
71 dev_err(dev, "netdev_alloc_frag() failed, size %zu\n",
73 @@ -1663,9 +1683,15 @@ static struct sk_buff *dpaa_cleanup_tx_f
77 - if (qm_fd_get_format(fd) == qm_fd_sg)
78 - /* Free the page frag that we allocated on Tx */
79 - skb_free_frag(phys_to_virt(addr));
80 + if (qm_fd_get_format(fd) == qm_fd_sg) {
82 + if (dpaa_errata_a010022)
83 + put_page(virt_to_page(sgt));
86 + /* Free the page frag that we allocated on Tx */
87 + skb_free_frag(phys_to_virt(addr));
92 @@ -1922,14 +1948,26 @@ static int skb_to_sg_fd(struct dpaa_priv
96 - /* get a page frag to store the SGTable */
97 - sz = SKB_DATA_ALIGN(priv->tx_headroom + DPAA_SGT_SIZE);
98 - sgt_buf = netdev_alloc_frag(sz);
99 - if (unlikely(!sgt_buf)) {
100 - netdev_err(net_dev, "netdev_alloc_frag() failed for size %d\n",
104 + if (unlikely(dpaa_errata_a010022)) {
105 + struct page *page = alloc_page(GFP_ATOMIC);
106 + if (unlikely(!page))
108 + sgt_buf = page_address(page);
111 + /* get a page frag to store the SGTable */
112 + sz = SKB_DATA_ALIGN(priv->tx_headroom + DPAA_SGT_SIZE);
113 + sgt_buf = netdev_alloc_frag(sz);
114 + if (unlikely(!sgt_buf)) {
115 + netdev_err(net_dev,
116 + "netdev_alloc_frag() failed for size %d\n",
124 /* Enable L3/L4 hardware checksum computation.
126 @@ -2049,6 +2087,122 @@ static inline int dpaa_xmit(struct dpaa_
131 +/* On LS1043A SoC there is a known erratum ERR010022 that results in split DMA
132 + * transfers in the FMan under certain conditions. This, combined with a fixed
133 + * size FIFO of ongoing DMA transfers that may overflow when a split occurs,
134 + * results in the FMan stalling DMA transfers under high traffic. To avoid the
135 + * problem, one needs to prevent the DMA transfer splits to occur by preparing
139 +#define DPAA_A010022_HEADROOM 256
140 +#define CROSS_4K_BOUND(start, size) \
141 + (((start) + (size)) > (((start) + 0x1000) & ~0xFFF))
143 +static bool dpaa_errata_a010022_has_dma_issue(struct sk_buff *skb,
144 + struct dpaa_priv *priv)
146 + int nr_frags, i = 0;
149 + /* Transfers that do not start at 16B aligned addresses will be split;
150 + * Transfers that cross a 4K page boundary will also be split
153 + /* Check if the frame data is aligned to 16 bytes */
154 + if ((uintptr_t)skb->data % DPAA_FD_DATA_ALIGNMENT)
157 + /* Check if the headroom crosses a boundary */
158 + if (CROSS_4K_BOUND((uintptr_t)skb->head, skb_headroom(skb)))
161 + /* Check if the non-paged data crosses a boundary */
162 + if (CROSS_4K_BOUND((uintptr_t)skb->data, skb_headlen(skb)))
165 + nr_frags = skb_shinfo(skb)->nr_frags;
167 + while (i < nr_frags) {
168 + frag = &skb_shinfo(skb)->frags[i];
170 + /* Check if a paged fragment crosses a boundary from its
171 + * offset to its end.
173 + if (CROSS_4K_BOUND((uintptr_t)frag->page_offset, frag->size))
182 +static struct sk_buff *dpaa_errata_a010022_prevent(struct sk_buff *skb,
183 + struct dpaa_priv *priv)
185 + int trans_offset = skb_transport_offset(skb);
186 + int net_offset = skb_network_offset(skb);
187 + int nsize, npage_order, headroom;
188 + struct sk_buff *nskb = NULL;
189 + struct page *npage;
192 + if (!dpaa_errata_a010022_has_dma_issue(skb, priv))
195 + /* For the new skb we only need the old one's data (both non-paged and
196 + * paged). We can skip the old tailroom.
198 + * The headroom also needs to fit our private info (64 bytes) but we
199 + * reserve 256 bytes instead in order to guarantee that the data is
202 + headroom = DPAA_A010022_HEADROOM;
203 + nsize = headroom + skb->len +
204 + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
206 + /* Reserve enough memory to accommodate Jumbo frames */
207 + npage_order = (nsize - 1) / PAGE_SIZE;
208 + npage = alloc_pages(GFP_ATOMIC | __GFP_COMP, npage_order);
209 + if (unlikely(!npage)) {
210 + WARN_ONCE(1, "Memory allocation failure\n");
213 + npage_addr = page_address(npage);
215 + nskb = build_skb(npage_addr, nsize);
216 + if (unlikely(!nskb))
219 + /* Code borrowed and adapted from skb_copy() */
220 + skb_reserve(nskb, headroom);
221 + skb_put(nskb, skb->len);
222 + if (skb_copy_bits(skb, 0, nskb->data, skb->len)) {
223 + WARN_ONCE(1, "skb parsing failure\n");
226 + copy_skb_header(nskb, skb);
228 + /* We move the headroom when we align it so we have to reset the
229 + * network and transport header offsets relative to the new data
230 + * pointer. The checksum offload relies on these offsets.
232 + skb_set_network_header(nskb, net_offset);
233 + skb_set_transport_header(nskb, trans_offset);
235 + dev_kfree_skb(skb);
240 + dev_kfree_skb(nskb);
247 dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
249 @@ -2095,6 +2249,15 @@ dpaa_start_xmit(struct sk_buff *skb, str
250 nonlinear = skb_is_nonlinear(skb);
254 + if (unlikely(dpaa_errata_a010022)) {
255 + skb = dpaa_errata_a010022_prevent(skb, priv);
258 + nonlinear = skb_is_nonlinear(skb);
263 /* Just create a S/G fd based on the skb */
264 err = skb_to_sg_fd(priv, skb, &fd);
265 @@ -2992,6 +3155,23 @@ static int dpaa_remove(struct platform_d
270 +static bool __init soc_has_errata_a010022(void)
272 +#ifdef CONFIG_SOC_BUS
273 + const struct soc_device_attribute soc_msi_matches[] = {
274 + { .family = "QorIQ LS1043A",
279 + if (!soc_device_match(soc_msi_matches))
282 + return true; /* cannot identify SoC or errata applies */
286 static const struct platform_device_id dpaa_devtype[] = {
288 .name = "dpaa-ethernet",
289 @@ -3016,6 +3196,10 @@ static int __init dpaa_load(void)
291 pr_debug("FSL DPAA Ethernet driver\n");
294 + /* Detect if the current SoC requires the DMA transfer alignment workaround */
295 + dpaa_errata_a010022 = soc_has_errata_a010022();
297 /* initialize dpaa_eth mirror values */
298 dpaa_rx_extra_headroom = fman_get_rx_extra_headroom();
299 dpaa_max_frm = fman_get_max_frm();