mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 14:04:26 -04:00 
			
		
		
		
	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>
		
			
				
	
	
		
			300 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| 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();
 |