aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch
diff options
context:
space:
mode:
authorYangbo Lu <yangbo.lu@nxp.com>2020-04-10 10:47:05 +0800
committerPetr Štetiar <ynezz@true.cz>2020-05-07 12:53:06 +0200
commitcddd4591404fb4c53dc0b3c0b15b942cdbed4356 (patch)
tree392c1179de46b0f804e3789edca19069b64e6b44 /target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch
parentd1d2c0b5579ea4f69a42246c9318539d61ba1999 (diff)
downloadupstream-cddd4591404fb4c53dc0b3c0b15b942cdbed4356.tar.gz
upstream-cddd4591404fb4c53dc0b3c0b15b942cdbed4356.tar.bz2
upstream-cddd4591404fb4c53dc0b3c0b15b942cdbed4356.zip
layerscape: add patches-5.4
Add patches for linux-5.4. The patches are from NXP LSDK-20.04 release which was tagged LSDK-20.04-V5.4. https://source.codeaurora.org/external/qoriq/qoriq-components/linux/ For boards LS1021A-IOT, and Traverse-LS1043 which are not involved in LSDK, port the dts patches from 4.14. The patches are sorted into the following categories: 301-arch-xxxx 302-dts-xxxx 303-core-xxxx 701-net-xxxx 801-audio-xxxx 802-can-xxxx 803-clock-xxxx 804-crypto-xxxx 805-display-xxxx 806-dma-xxxx 807-gpio-xxxx 808-i2c-xxxx 809-jailhouse-xxxx 810-keys-xxxx 811-kvm-xxxx 812-pcie-xxxx 813-pm-xxxx 814-qe-xxxx 815-sata-xxxx 816-sdhc-xxxx 817-spi-xxxx 818-thermal-xxxx 819-uart-xxxx 820-usb-xxxx 821-vfio-xxxx Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Diffstat (limited to 'target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch299
1 files changed, 299 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch b/target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch
new file mode 100644
index 0000000000..3c66e5a5f5
--- /dev/null
+++ b/target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch
@@ -0,0 +1,299 @@
+From fced03d891377fa04153fb0538bc8ca95ba05020 Mon Sep 17 00:00:00 2001
+From: Madalin Bucur <madalin.bucur@nxp.com>
+Date: Tue, 14 Nov 2017 08:12:12 +0200
+Subject: [PATCH] dpaa_eth: workaround for ERR010022
+
+On LS1043A SoC there is a known erratum ERR010022 that results in split DMA
+transfers in the FMan under certain conditions. This, combined with a fixed
+size FIFO of ongoing DMA transfers that may overflow when a split occurs,
+results in the FMan stalling DMA transfers under high traffic. To avoid the
+problem, one needs to prevent the DMA transfer splits to occur by preparing
+the buffers as follows.
+
+In order to prevent split transactions, all frames need to be aligned to 16
+bytes and not cross 4K address boundaries. To allow Jumbo frames (up to
+9.6K), all data must be aligned to 256 byes. This way, 4K boundary crossings
+will not trigger any transaction splits.
+
+The errata is prevented from manifesting by realigning all outgoing frames to
+256 byte boundaries. In the process, all S/G frames are linearized.
+
+Signed-off-by: Madalin Bucur <madalin.bucur@nxp.com>
+Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
+[rebase]
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 204 +++++++++++++++++++++++--
+ 1 file changed, 194 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
++++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+@@ -54,6 +54,10 @@
+ #include <linux/phy_fixed.h>
+ #include <soc/fsl/bman.h>
+ #include <soc/fsl/qman.h>
++#if !defined(CONFIG_PPC) && defined(CONFIG_SOC_BUS)
++#include <linux/sys_soc.h> /* soc_device_match */
++#endif
++
+ #include "fman.h"
+ #include "fman_port.h"
+ #include "mac.h"
+@@ -73,6 +77,10 @@ static u16 tx_timeout = 1000;
+ module_param(tx_timeout, ushort, 0444);
+ MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms");
+
++#ifndef CONFIG_PPC
++bool dpaa_errata_a010022;
++#endif
++
+ #define FM_FD_STAT_RX_ERRORS \
+ (FM_FD_ERR_DMA | FM_FD_ERR_PHYSICAL | \
+ FM_FD_ERR_SIZE | FM_FD_ERR_CLS_DISCARD | \
+@@ -1495,7 +1503,19 @@ static int dpaa_bp_add_8_bufs(const stru
+ u8 i;
+
+ for (i = 0; i < 8; i++) {
++#ifndef CONFIG_PPC
++ if (dpaa_errata_a010022) {
++ struct page *page = alloc_page(GFP_KERNEL);
++
++ if (unlikely(!page))
++ goto release_previous_buffs;
++ new_buf = page_address(page);
++ } else {
++ new_buf = netdev_alloc_frag(dpaa_bp->raw_size);
++ }
++#else
+ new_buf = netdev_alloc_frag(dpaa_bp->raw_size);
++#endif
+ if (unlikely(!new_buf)) {
+ dev_err(dev, "netdev_alloc_frag() failed, size %zu\n",
+ dpaa_bp->raw_size);
+@@ -1663,9 +1683,15 @@ static struct sk_buff *dpaa_cleanup_tx_f
+ }
+ }
+
+- if (qm_fd_get_format(fd) == qm_fd_sg)
+- /* Free the page frag that we allocated on Tx */
+- skb_free_frag(phys_to_virt(addr));
++ if (qm_fd_get_format(fd) == qm_fd_sg) {
++#ifndef CONFIG_PPC
++ if (dpaa_errata_a010022)
++ put_page(virt_to_page(sgt));
++ else
++#endif
++ /* Free the page frag that we allocated on Tx */
++ skb_free_frag(phys_to_virt(addr));
++ }
+
+ return skb;
+ }
+@@ -1922,14 +1948,26 @@ static int skb_to_sg_fd(struct dpaa_priv
+ size_t frag_len;
+ void *sgt_buf;
+
+- /* get a page frag to store the SGTable */
+- sz = SKB_DATA_ALIGN(priv->tx_headroom + DPAA_SGT_SIZE);
+- sgt_buf = netdev_alloc_frag(sz);
+- if (unlikely(!sgt_buf)) {
+- netdev_err(net_dev, "netdev_alloc_frag() failed for size %d\n",
+- sz);
+- return -ENOMEM;
++#ifndef CONFIG_PPC
++ if (unlikely(dpaa_errata_a010022)) {
++ struct page *page = alloc_page(GFP_ATOMIC);
++ if (unlikely(!page))
++ return -ENOMEM;
++ sgt_buf = page_address(page);
++ } else {
++#endif
++ /* get a page frag to store the SGTable */
++ sz = SKB_DATA_ALIGN(priv->tx_headroom + DPAA_SGT_SIZE);
++ sgt_buf = netdev_alloc_frag(sz);
++ if (unlikely(!sgt_buf)) {
++ netdev_err(net_dev,
++ "netdev_alloc_frag() failed for size %d\n",
++ sz);
++ return -ENOMEM;
++ }
++#ifndef CONFIG_PPC
+ }
++#endif
+
+ /* Enable L3/L4 hardware checksum computation.
+ *
+@@ -2049,6 +2087,122 @@ static inline int dpaa_xmit(struct dpaa_
+ return 0;
+ }
+
++#ifndef CONFIG_PPC
++/* On LS1043A SoC there is a known erratum ERR010022 that results in split DMA
++ * transfers in the FMan under certain conditions. This, combined with a fixed
++ * size FIFO of ongoing DMA transfers that may overflow when a split occurs,
++ * results in the FMan stalling DMA transfers under high traffic. To avoid the
++ * problem, one needs to prevent the DMA transfer splits to occur by preparing
++ * the buffers
++ */
++
++#define DPAA_A010022_HEADROOM 256
++#define CROSS_4K_BOUND(start, size) \
++ (((start) + (size)) > (((start) + 0x1000) & ~0xFFF))
++
++static bool dpaa_errata_a010022_has_dma_issue(struct sk_buff *skb,
++ struct dpaa_priv *priv)
++{
++ int nr_frags, i = 0;
++ skb_frag_t *frag;
++
++ /* Transfers that do not start at 16B aligned addresses will be split;
++ * Transfers that cross a 4K page boundary will also be split
++ */
++
++ /* Check if the frame data is aligned to 16 bytes */
++ if ((uintptr_t)skb->data % DPAA_FD_DATA_ALIGNMENT)
++ return true;
++
++ /* Check if the headroom crosses a boundary */
++ if (CROSS_4K_BOUND((uintptr_t)skb->head, skb_headroom(skb)))
++ return true;
++
++ /* Check if the non-paged data crosses a boundary */
++ if (CROSS_4K_BOUND((uintptr_t)skb->data, skb_headlen(skb)))
++ return true;
++
++ nr_frags = skb_shinfo(skb)->nr_frags;
++
++ while (i < nr_frags) {
++ frag = &skb_shinfo(skb)->frags[i];
++
++ /* Check if a paged fragment crosses a boundary from its
++ * offset to its end.
++ */
++ if (CROSS_4K_BOUND((uintptr_t)frag->page_offset, frag->size))
++ return true;
++
++ i++;
++ }
++
++ return false;
++}
++
++static struct sk_buff *dpaa_errata_a010022_prevent(struct sk_buff *skb,
++ struct dpaa_priv *priv)
++{
++ int trans_offset = skb_transport_offset(skb);
++ int net_offset = skb_network_offset(skb);
++ int nsize, npage_order, headroom;
++ struct sk_buff *nskb = NULL;
++ struct page *npage;
++ void *npage_addr;
++
++ if (!dpaa_errata_a010022_has_dma_issue(skb, priv))
++ return skb;
++
++ /* For the new skb we only need the old one's data (both non-paged and
++ * paged). We can skip the old tailroom.
++ *
++ * The headroom also needs to fit our private info (64 bytes) but we
++ * reserve 256 bytes instead in order to guarantee that the data is
++ * aligned to 256.
++ */
++ headroom = DPAA_A010022_HEADROOM;
++ nsize = headroom + skb->len +
++ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
++
++ /* Reserve enough memory to accommodate Jumbo frames */
++ npage_order = (nsize - 1) / PAGE_SIZE;
++ npage = alloc_pages(GFP_ATOMIC | __GFP_COMP, npage_order);
++ if (unlikely(!npage)) {
++ WARN_ONCE(1, "Memory allocation failure\n");
++ return NULL;
++ }
++ npage_addr = page_address(npage);
++
++ nskb = build_skb(npage_addr, nsize);
++ if (unlikely(!nskb))
++ goto err;
++
++ /* Code borrowed and adapted from skb_copy() */
++ skb_reserve(nskb, headroom);
++ skb_put(nskb, skb->len);
++ if (skb_copy_bits(skb, 0, nskb->data, skb->len)) {
++ WARN_ONCE(1, "skb parsing failure\n");
++ goto err;
++ }
++ copy_skb_header(nskb, skb);
++
++ /* We move the headroom when we align it so we have to reset the
++ * network and transport header offsets relative to the new data
++ * pointer. The checksum offload relies on these offsets.
++ */
++ skb_set_network_header(nskb, net_offset);
++ skb_set_transport_header(nskb, trans_offset);
++
++ dev_kfree_skb(skb);
++ return nskb;
++
++err:
++ if (nskb)
++ dev_kfree_skb(nskb);
++ put_page(npage);
++ return NULL;
++}
++#endif
++
+ static netdev_tx_t
+ dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
+ {
+@@ -2095,6 +2249,15 @@ dpaa_start_xmit(struct sk_buff *skb, str
+ nonlinear = skb_is_nonlinear(skb);
+ }
+
++#ifndef CONFIG_PPC
++ if (unlikely(dpaa_errata_a010022)) {
++ skb = dpaa_errata_a010022_prevent(skb, priv);
++ if (!skb)
++ goto enomem;
++ nonlinear = skb_is_nonlinear(skb);
++ }
++#endif
++
+ if (nonlinear) {
+ /* Just create a S/G fd based on the skb */
+ err = skb_to_sg_fd(priv, skb, &fd);
+@@ -2992,6 +3155,23 @@ static int dpaa_remove(struct platform_d
+ return err;
+ }
+
++#ifndef CONFIG_PPC
++static bool __init soc_has_errata_a010022(void)
++{
++#ifdef CONFIG_SOC_BUS
++ const struct soc_device_attribute soc_msi_matches[] = {
++ { .family = "QorIQ LS1043A",
++ .data = NULL },
++ { },
++ };
++
++ if (!soc_device_match(soc_msi_matches))
++ return false;
++#endif
++ return true; /* cannot identify SoC or errata applies */
++}
++#endif
++
+ static const struct platform_device_id dpaa_devtype[] = {
+ {
+ .name = "dpaa-ethernet",
+@@ -3016,6 +3196,10 @@ static int __init dpaa_load(void)
+
+ pr_debug("FSL DPAA Ethernet driver\n");
+
++#ifndef CONFIG_PPC
++ /* Detect if the current SoC requires the DMA transfer alignment workaround */
++ dpaa_errata_a010022 = soc_has_errata_a010022();
++#endif
+ /* initialize dpaa_eth mirror values */
+ dpaa_rx_extra_headroom = fman_get_rx_extra_headroom();
+ dpaa_max_frm = fman_get_max_frm();