diff options
author | Yangbo Lu <yangbo.lu@nxp.com> | 2020-04-10 10:47:05 +0800 |
---|---|---|
committer | Petr Štetiar <ynezz@true.cz> | 2020-05-07 12:53:06 +0200 |
commit | cddd4591404fb4c53dc0b3c0b15b942cdbed4356 (patch) | |
tree | 392c1179de46b0f804e3789edca19069b64e6b44 /target/linux/layerscape/patches-5.4/701-net-0054-dpaa_eth-workaround-for-ERR010022.patch | |
parent | d1d2c0b5579ea4f69a42246c9318539d61ba1999 (diff) | |
download | upstream-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.patch | 299 |
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(); |