Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 6/9] ARM64: dts: allwinner: sun50i: Add Crypto Engine node on A64
From: Corentin Labbe @ 2019-09-06 18:45 UTC (permalink / raw)
  To: davem, herbert, linux, mark.rutland, mripard, robh+dt, wens
  Cc: devicetree, linux-kernel, linux-sunxi, Corentin Labbe,
	linux-crypto, linux-arm-kernel
In-Reply-To: <20190906184551.17858-1-clabbe.montjoie@gmail.com>

The Crypto Engine is a hardware cryptographic accelerator that supports
many algorithms.
It could be found on most Allwinner SoCs.

This patch enables the Crypto Engine on the Allwinner A64 SoC Device-tree.

Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
---
 arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 69128a6dfc46..c9e30d462ab1 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -487,6 +487,17 @@
 			reg = <0x1c14000 0x400>;
 		};
 
+		crypto: crypto@1c15000 {
+			compatible = "allwinner,sun50i-a64-crypto";
+			reg = <0x01c15000 0x1000>;
+			interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ce_ns";
+			resets = <&ccu RST_BUS_CE>;
+			reset-names = "ahb";
+			clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>;
+			clock-names = "ahb", "mod";
+		};
+
 		usb_otg: usb@1c19000 {
 			compatible = "allwinner,sun8i-a33-musb";
 			reg = <0x01c19000 0x0400>;
-- 
2.21.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 7/9] ARM64: dts: allwinner: sun50i: Add crypto engine node on H5
From: Corentin Labbe @ 2019-09-06 18:45 UTC (permalink / raw)
  To: davem, herbert, linux, mark.rutland, mripard, robh+dt, wens
  Cc: devicetree, linux-kernel, linux-sunxi, Corentin Labbe,
	linux-crypto, linux-arm-kernel
In-Reply-To: <20190906184551.17858-1-clabbe.montjoie@gmail.com>

The Crypto Engine is a hardware cryptographic accelerator that supports
many algorithms.
It could be found on most Allwinner SoCs.

This patch enables the Crypto Engine on the Allwinner H5 SoC Device-tree.

Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
---
 arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
index f002a496d7cb..174fb3dcb3f7 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
@@ -127,6 +127,17 @@
 			allwinner,sram = <&ve_sram 1>;
 		};
 
+		crypto: crypto@1c15000 {
+			compatible = "allwinner,sun50i-h5-crypto";
+			reg = <0x01c15000 0x1000>;
+			interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "ce_ns";
+			resets = <&ccu RST_BUS_CE>;
+			reset-names = "ahb";
+			clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>;
+			clock-names = "ahb", "mod";
+		};
+
 		mali: gpu@1e80000 {
 			compatible = "allwinner,sun50i-h5-mali", "arm,mali-450";
 			reg = <0x01e80000 0x30000>;
-- 
2.21.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 8/9] ARM64: dts: allwinner: sun50i: Add Crypto Engine node on H6
From: Corentin Labbe @ 2019-09-06 18:45 UTC (permalink / raw)
  To: davem, herbert, linux, mark.rutland, mripard, robh+dt, wens
  Cc: devicetree, linux-kernel, linux-sunxi, Corentin Labbe,
	linux-crypto, linux-arm-kernel
In-Reply-To: <20190906184551.17858-1-clabbe.montjoie@gmail.com>

The Crypto Engine is a hardware cryptographic accelerator that supports
many algorithms.

This patch enables the Crypto Engine on the Allwinner H6 SoC Device-tree.

Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
---
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 0754f01fd731..51762499ed06 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -149,6 +149,16 @@
 			allwinner,sram = <&ve_sram 1>;
 		};
 
+		crypto: crypto@1904000 {
+			compatible = "allwinner,sun50i-h6-crypto";
+			reg = <0x01904000 0x1000>;
+			clocks = <&ccu CLK_BUS_CE>, <&ccu CLK_CE>, <&ccu CLK_MBUS_CE>;
+			clock-names = "ahb", "mod", "mbus";
+			resets = <&ccu RST_BUS_CE>;
+			reset-names = "ahb";
+			interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
 		syscon: syscon@3000000 {
 			compatible = "allwinner,sun50i-h6-system-control",
 				     "allwinner,sun50i-a64-system-control";
-- 
2.21.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 9/9] sunxi_defconfig: add new crypto options
From: Corentin Labbe @ 2019-09-06 18:45 UTC (permalink / raw)
  To: davem, herbert, linux, mark.rutland, mripard, robh+dt, wens
  Cc: devicetree, linux-kernel, linux-sunxi, Corentin Labbe,
	linux-crypto, linux-arm-kernel
In-Reply-To: <20190906184551.17858-1-clabbe.montjoie@gmail.com>

This patch adds the new allwinner crypto configs to sunxi_defconfig

Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
---
 arch/arm/configs/sunxi_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index df433abfcb02..d0ab8ba7710a 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -150,4 +150,6 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_FS=y
+CONFIG_CRYPTO_DEV_ALLWINNER=y
+CONFIG_CRYPTO_DEV_SUN8I_CE=y
 CONFIG_CRYPTO_DEV_SUN4I_SS=y
-- 
2.21.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH] PCI: dwc: Use PTR_ERR_OR_ZERO() in five functions
From: Markus Elfring @ 2019-09-06 18:50 UTC (permalink / raw)
  To: linux-pci, linux-arm-kernel, linux-samsung-soc, linux-amlogic,
	Binghui Wang, Bjorn Helgaas, Jingoo Han, Kevin Hilman,
	Krzysztof Kozlowski, Kukjin Kim, Lorenzo Pieralisi, Yue Wang,
	Xiaowei Song
  Cc: YueHaibing, zhong jiang, kernel-janitors, LKML

From: Markus Elfring <elfring@users.sourceforge.net>
Date: Fri, 6 Sep 2019 20:40:06 +0200

Simplify these function implementations by using a known function.

Generated by: scripts/coccinelle/api/ptr_ret.cocci

Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
---
 drivers/pci/controller/dwc/pci-exynos.c |  5 +----
 drivers/pci/controller/dwc/pci-meson.c  | 10 ++--------
 drivers/pci/controller/dwc/pcie-kirin.c | 10 ++--------
 3 files changed, 5 insertions(+), 20 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
index cee5f2f590e2..b6ab1cc5d895 100644
--- a/drivers/pci/controller/dwc/pci-exynos.c
+++ b/drivers/pci/controller/dwc/pci-exynos.c
@@ -92,10 +92,7 @@ static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,

 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	ep->mem_res->elbi_base = devm_ioremap_resource(dev, res);
-	if (IS_ERR(ep->mem_res->elbi_base))
-		return PTR_ERR(ep->mem_res->elbi_base);
-
-	return 0;
+	return PTR_ERR_OR_ZERO(ep->mem_res->elbi_base);
 }

 static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
index e35e9eaa50ee..713059918002 100644
--- a/drivers/pci/controller/dwc/pci-meson.c
+++ b/drivers/pci/controller/dwc/pci-meson.c
@@ -182,10 +182,7 @@ static int meson_pcie_get_mems(struct platform_device *pdev,

 	/* Meson SoC has two PCI controllers use same phy register*/
 	mp->mem_res.phy_base = meson_pcie_get_mem_shared(pdev, mp, "phy");
-	if (IS_ERR(mp->mem_res.phy_base))
-		return PTR_ERR(mp->mem_res.phy_base);
-
-	return 0;
+	return PTR_ERR_OR_ZERO(mp->mem_res.phy_base);
 }

 static void meson_pcie_power_on(struct meson_pcie *mp)
@@ -259,10 +256,7 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp)
 		return PTR_ERR(res->general_clk);

 	res->clk = meson_pcie_probe_clock(dev, "pcie", 0);
-	if (IS_ERR(res->clk))
-		return PTR_ERR(res->clk);
-
-	return 0;
+	return PTR_ERR_OR_ZERO(res->clk);
 }

 static inline void meson_elb_writel(struct meson_pcie *mp, u32 val, u32 reg)
diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
index c19617a912bd..75b1f1dde747 100644
--- a/drivers/pci/controller/dwc/pcie-kirin.c
+++ b/drivers/pci/controller/dwc/pcie-kirin.c
@@ -138,10 +138,7 @@ static long kirin_pcie_get_clk(struct kirin_pcie *kirin_pcie,
 		return PTR_ERR(kirin_pcie->apb_sys_clk);

 	kirin_pcie->pcie_aclk = devm_clk_get(dev, "pcie_aclk");
-	if (IS_ERR(kirin_pcie->pcie_aclk))
-		return PTR_ERR(kirin_pcie->pcie_aclk);
-
-	return 0;
+	return PTR_ERR_OR_ZERO(kirin_pcie->pcie_aclk);
 }

 static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
@@ -174,10 +171,7 @@ static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,

 	kirin_pcie->sysctrl =
 		syscon_regmap_lookup_by_compatible("hisilicon,hi3660-sctrl");
-	if (IS_ERR(kirin_pcie->sysctrl))
-		return PTR_ERR(kirin_pcie->sysctrl);
-
-	return 0;
+	return PTR_ERR_OR_ZERO(kirin_pcie->sysctrl);
 }

 static int kirin_pcie_phy_init(struct kirin_pcie *kirin_pcie)
--
2.23.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [PATCH v2] soc: fsl: dpio: Add support for QBMan ring bulk enqueue.
From: Roy Pledge @ 2019-09-06 18:55 UTC (permalink / raw)
  To: Youri Querry, Leo Li, linux-kernel@vger.kernel.org,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org, Ioana Ciocoi Radulescu,
	Ioana Ciornei
In-Reply-To: <1567710063-922-1-git-send-email-youri.querry_1@nxp.com>

On 9/5/2019 3:01 PM, Youri Querry wrote:
> The QBMan frame descriptor enqueuing is changed from array
>  mode (a single frame enqueue at a time) to bulk ring mode.
>
> This new mode allows the enqueuing of multiple frames in one operation.
> The original interface is kept but use the bulk enqueue of one frame
>
> Signed-off-by: Youri Querry <youri.querry_1@nxp.com>
Acked-by: Roy Pledge <roy.pledge@nxp.com>
> ---
>  drivers/soc/fsl/dpio/dpio-service.c |  69 +++-
>  drivers/soc/fsl/dpio/qbman-portal.c | 772 ++++++++++++++++++++++++++++++++----
>  drivers/soc/fsl/dpio/qbman-portal.h | 175 +++++++-
>  3 files changed, 935 insertions(+), 81 deletions(-)
>
> diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c
> index b9539ef..4eb53ee 100644
> --- a/drivers/soc/fsl/dpio/dpio-service.c
> +++ b/drivers/soc/fsl/dpio/dpio-service.c
> @@ -1,7 +1,7 @@
>  // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
>  /*
>   * Copyright 2014-2016 Freescale Semiconductor Inc.
> - * Copyright 2016 NXP
> + * Copyright 2016-2019 NXP
>   *
>   */
>  #include <linux/types.h>
> @@ -435,6 +435,69 @@ int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d,
>  EXPORT_SYMBOL(dpaa2_io_service_enqueue_fq);
>  
>  /**
> + * dpaa2_io_service_enqueue_multiple_fq() - Enqueue multiple frames
> + * to a frame queue using one fqid.
> + * @d: the given DPIO service.
> + * @fqid: the given frame queue id.
> + * @fd: the list of frame descriptors enqueued.
> + * @nb: number of frames to be enqueued
> + *
> + * Return the number of enqueued frames (0 if EQCR is busy)
> + * or -ENODEV if there is no dpio service.
> + */
> +int dpaa2_io_service_enqueue_multiple_fq(struct dpaa2_io *d,
> +				u32 fqid,
> +				const struct dpaa2_fd *fd,
> +				int nb)
> +{
> +	struct qbman_eq_desc ed;
> +
> +	d = service_select(d);
> +	if (!d)
> +		return -ENODEV;
> +
> +	qbman_eq_desc_clear(&ed);
> +	qbman_eq_desc_set_no_orp(&ed, 0);
> +	qbman_eq_desc_set_fq(&ed, fqid);
> +
> +	return qbman_swp_enqueue_multiple(d->swp, &ed, fd, 0, nb);
> +}
> +EXPORT_SYMBOL(dpaa2_io_service_enqueue_multiple_fq);
> +
> +/**
> + * dpaa2_io_service_enqueue_multiple_desc_fq() - Enqueue multiple frames
> + * to different frame queue using a list of fqids.
> + * @d: the given DPIO service.
> + * @fqid: the given list of frame queue ids.
> + * @fd: the list of frame descriptors enqueued.
> + * @nb: number of frames to be enqueued
> + *
> + * Return the number of enqueued frames (0 if EQCR is busy)
> + * or -ENODEV if there is no dpio service.
> + */
> +int dpaa2_io_service_enqueue_multiple_desc_fq(struct dpaa2_io *d,
> +				u32 *fqid,
> +				const struct dpaa2_fd *fd,
> +				int nb)
> +{
> +	int i;
> +	struct qbman_eq_desc_min ed[32];
> +
> +	d = service_select(d);
> +	if (!d)
> +		return -ENODEV;
> +
> +	for (i = 0; i < nb; i++) {
> +		qbman_eq_desc_min_clear(&ed[i]);
> +		qbman_eq_desc_set_no_orp_min(&ed[i], 0);
> +		qbman_eq_desc_set_min_fq(&ed[i], fqid[i]);
> +	}
> +
> +	return qbman_swp_enqueue_multiple_desc(d->swp, &ed[0], fd, nb);
> +}
> +EXPORT_SYMBOL(dpaa2_io_service_enqueue_multiple_desc_fq);
> +
> +/**
>   * dpaa2_io_service_enqueue_qd() - Enqueue a frame to a QD.
>   * @d: the given DPIO service.
>   * @qdid: the given queuing destination id.
> @@ -528,7 +591,7 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_acquire);
>  
>  /**
>   * dpaa2_io_store_create() - Create the dma memory storage for dequeue result.
> - * @max_frames: the maximum number of dequeued result for frames, must be <= 16.
> + * @max_frames: the maximum number of dequeued result for frames, must be <= 32.
>   * @dev:        the device to allow mapping/unmapping the DMAable region.
>   *
>   * The size of the storage is "max_frames*sizeof(struct dpaa2_dq)".
> @@ -543,7 +606,7 @@ struct dpaa2_io_store *dpaa2_io_store_create(unsigned int max_frames,
>  	struct dpaa2_io_store *ret;
>  	size_t size;
>  
> -	if (!max_frames || (max_frames > 16))
> +	if (!max_frames || (max_frames > 32))
>  		return NULL;
>  
>  	ret = kmalloc(sizeof(*ret), GFP_KERNEL);
> diff --git a/drivers/soc/fsl/dpio/qbman-portal.c b/drivers/soc/fsl/dpio/qbman-portal.c
> index c66f5b7..0ed2c8f 100644
> --- a/drivers/soc/fsl/dpio/qbman-portal.c
> +++ b/drivers/soc/fsl/dpio/qbman-portal.c
> @@ -1,13 +1,14 @@
>  // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
>  /*
>   * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
> - * Copyright 2016 NXP
> + * Copyright 2016-2019 NXP
>   *
>   */
>  
>  #include <asm/cacheflush.h>
>  #include <linux/io.h>
>  #include <linux/slab.h>
> +#include <linux/spinlock.h>
>  #include <soc/fsl/dpaa2-global.h>
>  
>  #include "qbman-portal.h"
> @@ -28,6 +29,7 @@
>  
>  /* CINH register offsets */
>  #define QBMAN_CINH_SWP_EQCR_PI      0x800
> +#define QBMAN_CINH_SWP_EQCR_CI	    0x840
>  #define QBMAN_CINH_SWP_EQAR    0x8c0
>  #define QBMAN_CINH_SWP_CR_RT        0x900
>  #define QBMAN_CINH_SWP_VDQCR_RT     0x940
> @@ -51,6 +53,8 @@
>  #define QBMAN_CENA_SWP_CR      0x600
>  #define QBMAN_CENA_SWP_RR(vb)  (0x700 + ((u32)(vb) >> 1))
>  #define QBMAN_CENA_SWP_VDQCR   0x780
> +#define QBMAN_CENA_SWP_EQCR_CI 0x840
> +#define QBMAN_CENA_SWP_EQCR_CI_MEMBACK 0x1840
>  
>  /* CENA register offsets in memory-backed mode */
>  #define QBMAN_CENA_SWP_DQRR_MEM(n)  (0x800 + ((u32)(n) << 6))
> @@ -78,6 +82,12 @@
>  /* opaque token for static dequeues */
>  #define QMAN_SDQCR_TOKEN    0xbb
>  
> +#define QBMAN_EQCR_DCA_IDXMASK          0x0f
> +#define QBMAN_ENQUEUE_FLAG_DCA          (1ULL << 31)
> +
> +#define EQ_DESC_SIZE_WITHOUT_FD 29
> +#define EQ_DESC_SIZE_FD_START 32
> +
>  enum qbman_sdqcr_dct {
>  	qbman_sdqcr_dct_null = 0,
>  	qbman_sdqcr_dct_prio_ics,
> @@ -90,6 +100,82 @@ enum qbman_sdqcr_fc {
>  	qbman_sdqcr_fc_up_to_3 = 1
>  };
>  
> +/* Internal Function declaration */
> +static int qbman_swp_enqueue_ring_mode_direct(struct qbman_swp *s,
> +					      const struct qbman_eq_desc *d,
> +					      const struct dpaa2_fd *fd);
> +static int qbman_swp_enqueue_ring_mode_mem_back(struct qbman_swp *s,
> +						const struct qbman_eq_desc *d,
> +						const struct dpaa2_fd *fd);
> +static int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
> +					     const struct qbman_eq_desc *d,
> +					     const struct dpaa2_fd *fd,
> +					     uint32_t *flags,
> +					     int num_frames);
> +static int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s,
> +					       const struct qbman_eq_desc *d,
> +					       const struct dpaa2_fd *fd,
> +					       uint32_t *flags,
> +					       int num_frames);
> +static int
> +qbman_swp_enqueue_multiple_desc_direct(struct qbman_swp *s,
> +				       const struct qbman_eq_desc_min *d,
> +				       const struct dpaa2_fd *fd,
> +				       int num_frames);
> +static
> +int qbman_swp_enqueue_multiple_desc_mem_back(struct qbman_swp *s,
> +					     const struct qbman_eq_desc_min *d,
> +					     const struct dpaa2_fd *fd,
> +					     int num_frames);
> +static int qbman_swp_pull_direct(struct qbman_swp *s,
> +				 struct qbman_pull_desc *d);
> +static int qbman_swp_pull_mem_back(struct qbman_swp *s,
> +				   struct qbman_pull_desc *d);
> +
> +const struct dpaa2_dq *qbman_swp_dqrr_next_direct(struct qbman_swp *s);
> +const struct dpaa2_dq *qbman_swp_dqrr_next_mem_back(struct qbman_swp *s);
> +
> +static int qbman_swp_release_direct(struct qbman_swp *s,
> +				    const struct qbman_release_desc *d,
> +				    const u64 *buffers,
> +				    unsigned int num_buffers);
> +static int qbman_swp_release_mem_back(struct qbman_swp *s,
> +				      const struct qbman_release_desc *d,
> +				      const u64 *buffers,
> +				      unsigned int num_buffers);
> +
> +/* Function pointers */
> +int (*qbman_swp_enqueue_ring_mode_ptr)(struct qbman_swp *s,
> +				       const struct qbman_eq_desc *d,
> +				       const struct dpaa2_fd *fd)
> +	= qbman_swp_enqueue_ring_mode_direct;
> +
> +int (*qbman_swp_enqueue_multiple_ptr)(struct qbman_swp *s,
> +				      const struct qbman_eq_desc *d,
> +				      const struct dpaa2_fd *fd,
> +				      uint32_t *flags,
> +					     int num_frames)
> +	= qbman_swp_enqueue_multiple_direct;
> +
> +int
> +(*qbman_swp_enqueue_multiple_desc_ptr)(struct qbman_swp *s,
> +				       const struct qbman_eq_desc_min *d,
> +				       const struct dpaa2_fd *fd,
> +				       int num_frames)
> +	= qbman_swp_enqueue_multiple_desc_direct;
> +
> +int (*qbman_swp_pull_ptr)(struct qbman_swp *s, struct qbman_pull_desc *d)
> +			= qbman_swp_pull_direct;
> +
> +const struct dpaa2_dq *(*qbman_swp_dqrr_next_ptr)(struct qbman_swp *s)
> +			= qbman_swp_dqrr_next_direct;
> +
> +int (*qbman_swp_release_ptr)(struct qbman_swp *s,
> +			     const struct qbman_release_desc *d,
> +			     const u64 *buffers,
> +			     unsigned int num_buffers)
> +			= qbman_swp_release_direct;
> +
>  /* Portal Access */
>  
>  static inline u32 qbman_read_register(struct qbman_swp *p, u32 offset)
> @@ -146,6 +232,15 @@ static inline u32 qbman_set_swp_cfg(u8 max_fill, u8 wn,	u8 est, u8 rpm, u8 dcm,
>  
>  #define QMAN_RT_MODE	   0x00000100
>  
> +static inline u8 qm_cyc_diff(u8 ringsize, u8 first, u8 last)
> +{
> +	/* 'first' is included, 'last' is excluded */
> +	if (first <= last)
> +		return last - first;
> +	else
> +		return (2 * ringsize) - (first - last);
> +}
> +
>  /**
>   * qbman_swp_init() - Create a functional object representing the given
>   *                    QBMan portal descriptor.
> @@ -156,8 +251,12 @@ static inline u32 qbman_set_swp_cfg(u8 max_fill, u8 wn,	u8 est, u8 rpm, u8 dcm,
>   */
>  struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
>  {
> -	struct qbman_swp *p = kmalloc(sizeof(*p), GFP_KERNEL);
> +	struct qbman_swp *p = kzalloc(sizeof(*p), GFP_KERNEL);
>  	u32 reg;
> +	u32 mask_size;
> +	u32 eqcr_pi;
> +
> +	spin_lock_init(&p->access_spinlock);
>  
>  	if (!p)
>  		return NULL;
> @@ -189,22 +288,39 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
>  	if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000)
>  		memset(p->addr_cena, 0, 64 * 1024);
>  
> -	reg = qbman_set_swp_cfg(p->dqrr.dqrr_size,
> -				1, /* Writes Non-cacheable */
> -				0, /* EQCR_CI stashing threshold */
> -				3, /* RPM: Valid bit mode, RCR in array mode */
> -				2, /* DCM: Discrete consumption ack mode */
> -				3, /* EPM: Valid bit mode, EQCR in array mode */
> -				1, /* mem stashing drop enable == TRUE */
> -				1, /* mem stashing priority == TRUE */
> -				1, /* mem stashing enable == TRUE */
> -				1, /* dequeue stashing priority == TRUE */
> -				0, /* dequeue stashing enable == FALSE */
> -				0); /* EQCR_CI stashing priority == FALSE */
> -	if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000)
> +	if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) {
> +
> +		reg = qbman_set_swp_cfg(p->dqrr.dqrr_size,
> +			0, /* Writes Non-cacheable */
> +			1, /* EQCR_CI stashing threshold */
> +			3, /* RPM: RCR in array mode */
> +			2, /* DCM: Discrete consumption ack */
> +			0, /* EPM: EQCR in ring mode */
> +			1, /* mem stashing drop enable */
> +			1, /* mem stashing priority enable */
> +			1, /* mem stashing enable */
> +			1, /* dequeue stashing priority enable */
> +			0, /* dequeue stashing enable */
> +			0); /* EQCR_CI stashing priority enable */
> +	} else {
> +		reg = qbman_set_swp_cfg(p->dqrr.dqrr_size,
> +			1, /* Writes Non-cacheable */
> +			0, /* EQCR_CI stashing threshold */
> +			3, /* RPM: RCR in array mode */
> +			2, /* DCM: Discrete consumption ack */
> +			2, /* EPM: EQCR in ring mode */
> +			1, /* mem stashing drop enable enable */
> +			1, /* mem stashing priority enable */
> +			1, /* mem stashing enable */
> +			1, /* dequeue stashing priority enable */
> +			0, /* dequeue stashing enable enable */
> +			0); /* EQCR_CI stashing priority enable */
> +	}
> +	if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) {
>  		reg |= 1 << SWP_CFG_CPBS_SHIFT | /* memory-backed mode */
>  		       1 << SWP_CFG_VPM_SHIFT |  /* VDQCR read triggered mode */
>  		       1 << SWP_CFG_CPM_SHIFT;   /* CR read triggered mode */
> +	}
>  
>  	qbman_write_register(p, QBMAN_CINH_SWP_CFG, reg);
>  	reg = qbman_read_register(p, QBMAN_CINH_SWP_CFG);
> @@ -225,6 +341,30 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
>  	 * applied when dequeues from a specific channel are enabled.
>  	 */
>  	qbman_write_register(p, QBMAN_CINH_SWP_SDQCR, 0);
> +
> +	p->eqcr.pi_ring_size = 8;
> +	if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) {
> +		p->eqcr.pi_ring_size = 32;
> +		qbman_swp_enqueue_ring_mode_ptr =
> +			qbman_swp_enqueue_ring_mode_mem_back;
> +		qbman_swp_enqueue_multiple_ptr =
> +			qbman_swp_enqueue_multiple_mem_back;
> +		qbman_swp_enqueue_multiple_desc_ptr =
> +			qbman_swp_enqueue_multiple_desc_mem_back;
> +		qbman_swp_pull_ptr = qbman_swp_pull_mem_back;
> +		qbman_swp_dqrr_next_ptr = qbman_swp_dqrr_next_mem_back;
> +		qbman_swp_release_ptr = qbman_swp_release_mem_back;
> +	}
> +
> +	for (mask_size = p->eqcr.pi_ring_size; mask_size > 0; mask_size >>= 1)
> +		p->eqcr.pi_ci_mask = (p->eqcr.pi_ci_mask << 1) + 1;
> +	eqcr_pi = qbman_read_register(p, QBMAN_CINH_SWP_EQCR_PI);
> +	p->eqcr.pi = eqcr_pi & p->eqcr.pi_ci_mask;
> +	p->eqcr.pi_vb = eqcr_pi & QB_VALID_BIT;
> +	p->eqcr.ci = qbman_read_register(p, QBMAN_CINH_SWP_EQCR_CI)
> +			& p->eqcr.pi_ci_mask;
> +	p->eqcr.available = p->eqcr.pi_ring_size;
> +
>  	return p;
>  }
>  
> @@ -378,6 +518,7 @@ enum qb_enqueue_commands {
>  #define QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT      2
>  #define QB_ENQUEUE_CMD_IRQ_ON_DISPATCH_SHIFT 3
>  #define QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT     4
> +#define QB_ENQUEUE_CMD_DCA_EN_SHIFT          7
>  
>  /**
>   * qbman_eq_desc_clear() - Clear the contents of a descriptor to
> @@ -389,6 +530,16 @@ void qbman_eq_desc_clear(struct qbman_eq_desc *d)
>  }
>  
>  /**
> + * qbman_eq_desc_min_clear() - Clear the contents of a minimal
> + *			   enqueue descriptor to
> + *                         default/starting state.
> + */
> +void qbman_eq_desc_min_clear(struct qbman_eq_desc_min *d)
> +{
> +	memset(d, 0, sizeof(*d));
> +}
> +
> +/**
>   * qbman_eq_desc_set_no_orp() - Set enqueue descriptor without orp
>   * @d:                the enqueue descriptor.
>   * @response_success: 1 = enqueue with response always; 0 = enqueue with
> @@ -403,6 +554,22 @@ void qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success)
>  		d->verb |= enqueue_rejects_to_fq;
>  }
>  
> +/**
> + * qbman_eq_desc_set_no_orp_min() - Set minimal enqueue descriptor without orp
> + * @d:                the enqueue descriptor.
> + * @response_success: 1 = enqueue with response always; 0 = enqueue with
> + *                    rejections returned on a FQ.
> + */
> +void qbman_eq_desc_set_no_orp_min(struct qbman_eq_desc_min *d,
> +				  int respond_success)
> +{
> +	d->verb &= ~(1 << QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT);
> +	if (respond_success)
> +		d->verb |= enqueue_response_always;
> +	else
> +		d->verb |= enqueue_rejects_to_fq;
> +}
> +
>  /*
>   * Exactly one of the following descriptor "targets" should be set. (Calling any
>   * one of these will replace the effect of any prior call to one of these.)
> @@ -422,6 +589,17 @@ void qbman_eq_desc_set_fq(struct qbman_eq_desc *d, u32 fqid)
>  }
>  
>  /**
> + * qbman_eq_desc_set_min_fq() - set the FQ for the minimal enqueue command
> + * @d:    the enqueue descriptor
> + * @fqid: the id of the frame queue to be enqueued
> + */
> +void qbman_eq_desc_set_min_fq(struct qbman_eq_desc_min *d, u32 fqid)
> +{
> +	d->verb &= ~(1 << QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT);
> +	d->tgtid = cpu_to_le32(fqid);
> +}
> +
> +/**
>   * qbman_eq_desc_set_qd() - Set Queuing Destination for the enqueue command
>   * @d:       the enqueue descriptor
>   * @qdid:    the id of the queuing destination to be enqueued
> @@ -453,41 +631,340 @@ static inline void qbman_write_eqcr_am_rt_register(struct qbman_swp *p,
>  				     QMAN_RT_MODE);
>  }
>  
> +#define QB_RT_BIT ((u32)0x100)
>  /**
> - * qbman_swp_enqueue() - Issue an enqueue command
> + * qbman_swp_enqueue_ring_mode_direct() - Issue an enqueue command
>   * @s:  the software portal used for enqueue
>   * @d:  the enqueue descriptor
>   * @fd: the frame descriptor to be enqueued
>   *
> - * Please note that 'fd' should only be NULL if the "action" of the
> - * descriptor is "orp_hole" or "orp_nesn".
> + * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready.
> + */
> +static
> +int qbman_swp_enqueue_ring_mode_direct(struct qbman_swp *s,
> +				       const struct qbman_eq_desc *d,
> +				       const struct dpaa2_fd *fd)
> +{
> +	int flags = 0;
> +	int ret = qbman_swp_enqueue_multiple_direct(s, d, fd, &flags, 1);
> +
> +	if (ret >= 0)
> +		ret = 0;
> +	else
> +		ret = -EBUSY;
> +	return  ret;
> +}
> +
> +/**
> + * qbman_swp_enqueue_ring_mode_mem_back() - Issue an enqueue command
> + * @s:  the software portal used for enqueue
> + * @d:  the enqueue descriptor
> + * @fd: the frame descriptor to be enqueued
>   *
>   * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready.
>   */
> -int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d,
> -		      const struct dpaa2_fd *fd)
> +static
> +int qbman_swp_enqueue_ring_mode_mem_back(struct qbman_swp *s,
> +					 const struct qbman_eq_desc *d,
> +					 const struct dpaa2_fd *fd)
>  {
> -	struct qbman_eq_desc *p;
> -	u32 eqar = qbman_read_register(s, QBMAN_CINH_SWP_EQAR);
> +	int flags = 0;
> +	int ret = qbman_swp_enqueue_multiple_mem_back(s, d, fd, &flags, 1);
>  
> -	if (!EQAR_SUCCESS(eqar))
> -		return -EBUSY;
> +	if (ret >= 0)
> +		ret = 0;
> +	else
> +		ret = -EBUSY;
> +	return  ret;
> +}
>  
> -	p = qbman_get_cmd(s, QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar)));
> -	memcpy(&p->dca, &d->dca, 31);
> -	memcpy(&p->fd, fd, sizeof(*fd));
> +/**
> + * qbman_swp_enqueue_multiple_direct() - Issue a multi enqueue command
> + * using one enqueue descriptor
> + * @s:  the software portal used for enqueue
> + * @d:  the enqueue descriptor
> + * @fd: table pointer of frame descriptor table to be enqueued
> + * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL
> + * @num_frames: number of fd to be enqueued
> + *
> + * Return the number of fd enqueued, or a negative error number.
> + */
> +static
> +int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s,
> +				      const struct qbman_eq_desc *d,
> +				      const struct dpaa2_fd *fd,
> +				      uint32_t *flags,
> +				      int num_frames)
> +{
> +	uint32_t *p = NULL;
> +	const uint32_t *cl = (uint32_t *)d;
> +	uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
> +	int i, num_enqueued = 0;
> +
> +	half_mask = (s->eqcr.pi_ci_mask>>1);
> +	full_mask = s->eqcr.pi_ci_mask;
> +
> +	if (!s->eqcr.available) {
> +		eqcr_ci = s->eqcr.ci;
> +		p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI;
> +		s->eqcr.ci = __raw_readl(p) & full_mask;
> +
> +		s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size,
> +					eqcr_ci, s->eqcr.ci);
> +		if (!s->eqcr.available)
> +			return 0;
> +	}
>  
> -	if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
> -		/* Set the verb byte, have to substitute in the valid-bit */
> -		dma_wmb();
> -		p->verb = d->verb | EQAR_VB(eqar);
> -	} else {
> -		p->verb = d->verb | EQAR_VB(eqar);
> -		dma_wmb();
> -		qbman_write_eqcr_am_rt_register(s, EQAR_IDX(eqar));
> +	eqcr_pi = s->eqcr.pi;
> +	num_enqueued = (s->eqcr.available < num_frames) ?
> +			s->eqcr.available : num_frames;
> +	s->eqcr.available -= num_enqueued;
> +	/* Fill in the EQCR ring */
> +	for (i = 0; i < num_enqueued; i++) {
> +		p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
> +		/* Skip copying the verb */
> +		memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1);
> +		memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)],
> +		       &fd[i], sizeof(*fd));
> +		eqcr_pi++;
>  	}
>  
> -	return 0;
> +	dma_wmb();
> +
> +	/* Set the verb byte, have to substitute in the valid-bit */
> +	eqcr_pi = s->eqcr.pi;
> +	for (i = 0; i < num_enqueued; i++) {
> +		p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
> +		p[0] = cl[0] | s->eqcr.pi_vb;
> +		if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) {
> +			struct qbman_eq_desc *d = (struct qbman_eq_desc *)p;
> +
> +			d->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) |
> +				((flags[i]) & QBMAN_EQCR_DCA_IDXMASK);
> +		}
> +		eqcr_pi++;
> +		if (!(eqcr_pi & half_mask))
> +			s->eqcr.pi_vb ^= QB_VALID_BIT;
> +	}
> +
> +	s->eqcr.pi = (s->eqcr.pi + num_enqueued) & full_mask;
> +
> +	return num_enqueued;
> +}
> +
> +/**
> + * qbman_swp_enqueue_multiple_mem_back() - Issue a multi enqueue command
> + * using one enqueue descriptor
> + * @s:  the software portal used for enqueue
> + * @d:  the enqueue descriptor
> + * @fd: table pointer of frame descriptor table to be enqueued
> + * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL
> + * @num_frames: number of fd to be enqueued
> + *
> + * Return the number of fd enqueued, or a negative error number.
> + */
> +static
> +int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s,
> +					const struct qbman_eq_desc *d,
> +					const struct dpaa2_fd *fd,
> +					uint32_t *flags,
> +					int num_frames)
> +{
> +	uint32_t *p = NULL;
> +	const uint32_t *cl = (uint32_t *)(d);
> +	uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
> +	int i, num_enqueued = 0;
> +	unsigned long irq_flags;
> +
> +	spin_lock(&s->access_spinlock);
> +	local_irq_save(irq_flags);
> +
> +	half_mask = (s->eqcr.pi_ci_mask>>1);
> +	full_mask = s->eqcr.pi_ci_mask;
> +	if (!s->eqcr.available) {
> +		eqcr_ci = s->eqcr.ci;
> +		p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI_MEMBACK;
> +		s->eqcr.ci = __raw_readl(p) & full_mask;
> +		s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size,
> +					eqcr_ci, s->eqcr.ci);
> +		if (!s->eqcr.available) {
> +			local_irq_restore(irq_flags);
> +			spin_unlock(&s->access_spinlock);
> +			return 0;
> +		}
> +	}
> +
> +	eqcr_pi = s->eqcr.pi;
> +	num_enqueued = (s->eqcr.available < num_frames) ?
> +			s->eqcr.available : num_frames;
> +	s->eqcr.available -= num_enqueued;
> +	/* Fill in the EQCR ring */
> +	for (i = 0; i < num_enqueued; i++) {
> +		p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
> +		/* Skip copying the verb */
> +		memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1);
> +		memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)],
> +		       &fd[i], sizeof(*fd));
> +		eqcr_pi++;
> +	}
> +
> +	/* Set the verb byte, have to substitute in the valid-bit */
> +	eqcr_pi = s->eqcr.pi;
> +	for (i = 0; i < num_enqueued; i++) {
> +		p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
> +		p[0] = cl[0] | s->eqcr.pi_vb;
> +		if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) {
> +			struct qbman_eq_desc *d = (struct qbman_eq_desc *)p;
> +
> +			d->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) |
> +				((flags[i]) & QBMAN_EQCR_DCA_IDXMASK);
> +		}
> +		eqcr_pi++;
> +		if (!(eqcr_pi & half_mask))
> +			s->eqcr.pi_vb ^= QB_VALID_BIT;
> +	}
> +	s->eqcr.pi = eqcr_pi & full_mask;
> +
> +	dma_wmb();
> +	qbman_write_register(s, QBMAN_CINH_SWP_EQCR_PI,
> +				(QB_RT_BIT)|(s->eqcr.pi)|s->eqcr.pi_vb);
> +	local_irq_restore(irq_flags);
> +	spin_unlock(&s->access_spinlock);
> +
> +	return num_enqueued;
> +}
> +
> +/**
> + * qbman_swp_enqueue_multiple_desc_direct() - Issue a multi enqueue command
> + * using multiple enqueue descriptor
> + * @s:  the software portal used for enqueue
> + * @d:  table of minimal enqueue descriptor
> + * @fd: table pointer of frame descriptor table to be enqueued
> + * @num_frames: number of fd to be enqueued
> + *
> + * Return the number of fd enqueued, or a negative error number.
> + */
> +static
> +int qbman_swp_enqueue_multiple_desc_direct(struct qbman_swp *s,
> +					   const struct qbman_eq_desc_min *d,
> +					   const struct dpaa2_fd *fd,
> +					   int num_frames)
> +{
> +	uint32_t *p;
> +	const uint32_t *cl;
> +	uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
> +	int i, num_enqueued = 0;
> +
> +	half_mask = (s->eqcr.pi_ci_mask>>1);
> +	full_mask = s->eqcr.pi_ci_mask;
> +	if (!s->eqcr.available) {
> +		eqcr_ci = s->eqcr.ci;
> +		p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI;
> +		s->eqcr.ci = __raw_readl(p) & full_mask;
> +		s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size,
> +					eqcr_ci, s->eqcr.ci);
> +		if (!s->eqcr.available)
> +			return 0;
> +	}
> +
> +	eqcr_pi = s->eqcr.pi;
> +	num_enqueued = (s->eqcr.available < num_frames) ?
> +			s->eqcr.available : num_frames;
> +	s->eqcr.available -= num_enqueued;
> +	/* Fill in the EQCR ring */
> +	for (i = 0; i < num_enqueued; i++) {
> +		p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
> +		cl = (uint32_t *)(&d[i]);
> +		/* Skip copying the verb */
> +		memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1);
> +		memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)],
> +		       &fd[i], sizeof(*fd));
> +		eqcr_pi++;
> +	}
> +
> +	dma_wmb();
> +
> +	/* Set the verb byte, have to substitute in the valid-bit */
> +	eqcr_pi = s->eqcr.pi;
> +	for (i = 0; i < num_enqueued; i++) {
> +		p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
> +		cl = (uint32_t *)(&d[i]);
> +		p[0] = cl[0] | s->eqcr.pi_vb;
> +		eqcr_pi++;
> +		if (!(eqcr_pi & half_mask))
> +			s->eqcr.pi_vb ^= QB_VALID_BIT;
> +	}
> +	s->eqcr.pi = (s->eqcr.pi + num_enqueued) & full_mask;
> +
> +	return num_enqueued;
> +}
> +
> +/**
> + * qbman_swp_enqueue_multiple_desc_mem_back() - Issue a multi enqueue command
> + * using multiple enqueue descriptor
> + * @s:  the software portal used for enqueue
> + * @d:  table of minimal enqueue descriptor
> + * @fd: table pointer of frame descriptor table to be enqueued
> + * @num_frames: number of fd to be enqueued
> + *
> + * Return the number of fd enqueued, or a negative error number.
> + */
> +static
> +int qbman_swp_enqueue_multiple_desc_mem_back(struct qbman_swp *s,
> +					     const struct qbman_eq_desc_min *d,
> +					     const struct dpaa2_fd *fd,
> +					     int num_frames)
> +{
> +	uint32_t *p;
> +	const uint32_t *cl;
> +	uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask;
> +	int i, num_enqueued = 0;
> +
> +	half_mask = (s->eqcr.pi_ci_mask>>1);
> +	full_mask = s->eqcr.pi_ci_mask;
> +	if (!s->eqcr.available) {
> +		eqcr_ci = s->eqcr.ci;
> +		p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI_MEMBACK;
> +		s->eqcr.ci = __raw_readl(p) & full_mask;
> +		s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size,
> +					eqcr_ci, s->eqcr.ci);
> +		if (!s->eqcr.available)
> +			return 0;
> +	}
> +
> +	eqcr_pi = s->eqcr.pi;
> +	num_enqueued = (s->eqcr.available < num_frames) ?
> +			s->eqcr.available : num_frames;
> +	s->eqcr.available -= num_enqueued;
> +	/* Fill in the EQCR ring */
> +	for (i = 0; i < num_enqueued; i++) {
> +		p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
> +		cl = (uint32_t *)(&d[i]);
> +		/* Skip copying the verb */
> +		memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1);
> +		memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)],
> +		       &fd[i], sizeof(*fd));
> +		eqcr_pi++;
> +	}
> +
> +	/* Set the verb byte, have to substitute in the valid-bit */
> +	eqcr_pi = s->eqcr.pi;
> +	for (i = 0; i < num_enqueued; i++) {
> +		p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask));
> +		cl = (uint32_t *)(&d[i]);
> +		p[0] = cl[0] | s->eqcr.pi_vb;
> +		eqcr_pi++;
> +		if (!(eqcr_pi & half_mask))
> +			s->eqcr.pi_vb ^= QB_VALID_BIT;
> +	}
> +
> +	s->eqcr.pi = eqcr_pi & full_mask;
> +
> +	dma_wmb();
> +	qbman_write_register(s, QBMAN_CINH_SWP_EQCR_PI,
> +				(QB_RT_BIT)|(s->eqcr.pi)|s->eqcr.pi_vb);
> +
> +	return num_enqueued;
>  }
>  
>  /* Static (push) dequeue */
> @@ -645,7 +1122,7 @@ void qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid,
>  }
>  
>  /**
> - * qbman_swp_pull() - Issue the pull dequeue command
> + * qbman_swp_pull_direct() - Issue the pull dequeue command
>   * @s: the software portal object
>   * @d: the software portal descriptor which has been configured with
>   *     the set of qbman_pull_desc_set_*() calls
> @@ -653,7 +1130,7 @@ void qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid,
>   * Return 0 for success, and -EBUSY if the software portal is not ready
>   * to do pull dequeue.
>   */
> -int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d)
> +static int qbman_swp_pull_direct(struct qbman_swp *s, struct qbman_pull_desc *d)
>  {
>  	struct qbman_pull_desc *p;
>  
> @@ -671,18 +1148,48 @@ int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d)
>  	p->dq_src = d->dq_src;
>  	p->rsp_addr = d->rsp_addr;
>  	p->rsp_addr_virt = d->rsp_addr_virt;
> +	dma_wmb();
> +	/* Set the verb byte, have to substitute in the valid-bit */
> +	p->verb = d->verb | s->vdq.valid_bit;
> +	s->vdq.valid_bit ^= QB_VALID_BIT;
>  
> -	if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
> -		dma_wmb();
> -		/* Set the verb byte, have to substitute in the valid-bit */
> -		p->verb = d->verb | s->vdq.valid_bit;
> -		s->vdq.valid_bit ^= QB_VALID_BIT;
> -	} else {
> -		p->verb = d->verb | s->vdq.valid_bit;
> -		s->vdq.valid_bit ^= QB_VALID_BIT;
> -		dma_wmb();
> -		qbman_write_register(s, QBMAN_CINH_SWP_VDQCR_RT, QMAN_RT_MODE);
> +	return 0;
> +}
> +
> +/**
> + * qbman_swp_pull_mem_back() - Issue the pull dequeue command
> + * @s: the software portal object
> + * @d: the software portal descriptor which has been configured with
> + *     the set of qbman_pull_desc_set_*() calls
> + *
> + * Return 0 for success, and -EBUSY if the software portal is not ready
> + * to do pull dequeue.
> + */
> +static int qbman_swp_pull_mem_back(struct qbman_swp *s,
> +				   struct qbman_pull_desc *d)
> +{
> +	struct qbman_pull_desc *p;
> +
> +	if (!atomic_dec_and_test(&s->vdq.available)) {
> +		atomic_inc(&s->vdq.available);
> +		return -EBUSY;
>  	}
> +	s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt;
> +	if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
> +		p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR);
> +	else
> +		p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR_MEM);
> +	p->numf = d->numf;
> +	p->tok = QMAN_DQ_TOKEN_VALID;
> +	p->dq_src = d->dq_src;
> +	p->rsp_addr = d->rsp_addr;
> +	p->rsp_addr_virt = d->rsp_addr_virt;
> +
> +	/* Set the verb byte, have to substitute in the valid-bit */
> +	p->verb = d->verb | s->vdq.valid_bit;
> +	s->vdq.valid_bit ^= QB_VALID_BIT;
> +	dma_wmb();
> +	qbman_write_register(s, QBMAN_CINH_SWP_VDQCR_RT, QMAN_RT_MODE);
>  
>  	return 0;
>  }
> @@ -690,14 +1197,14 @@ int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d)
>  #define QMAN_DQRR_PI_MASK   0xf
>  
>  /**
> - * qbman_swp_dqrr_next() - Get an valid DQRR entry
> + * qbman_swp_dqrr_next_direct() - Get an valid DQRR entry
>   * @s: the software portal object
>   *
>   * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry
>   * only once, so repeated calls can return a sequence of DQRR entries, without
>   * requiring they be consumed immediately or in any particular order.
>   */
> -const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
> +const struct dpaa2_dq *qbman_swp_dqrr_next_direct(struct qbman_swp *s)
>  {
>  	u32 verb;
>  	u32 response_verb;
> @@ -740,10 +1247,7 @@ const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
>  				       QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)));
>  	}
>  
> -	if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
> -		p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
> -	else
> -		p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR_MEM(s->dqrr.next_idx));
> +	p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
>  	verb = p->dq.verb;
>  
>  	/*
> @@ -785,6 +1289,98 @@ const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
>  }
>  
>  /**
> + * qbman_swp_dqrr_next_mem_back() - Get an valid DQRR entry
> + * @s: the software portal object
> + *
> + * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry
> + * only once, so repeated calls can return a sequence of DQRR entries, without
> + * requiring they be consumed immediately or in any particular order.
> + */
> +const struct dpaa2_dq *qbman_swp_dqrr_next_mem_back(struct qbman_swp *s)
> +{
> +	u32 verb;
> +	u32 response_verb;
> +	u32 flags;
> +	struct dpaa2_dq *p;
> +
> +	/* Before using valid-bit to detect if something is there, we have to
> +	 * handle the case of the DQRR reset bug...
> +	 */
> +	if (unlikely(s->dqrr.reset_bug)) {
> +		/*
> +		 * We pick up new entries by cache-inhibited producer index,
> +		 * which means that a non-coherent mapping would require us to
> +		 * invalidate and read *only* once that PI has indicated that
> +		 * there's an entry here. The first trip around the DQRR ring
> +		 * will be much less efficient than all subsequent trips around
> +		 * it...
> +		 */
> +		u8 pi = qbman_read_register(s, QBMAN_CINH_SWP_DQPI) &
> +			QMAN_DQRR_PI_MASK;
> +
> +		/* there are new entries if pi != next_idx */
> +		if (pi == s->dqrr.next_idx)
> +			return NULL;
> +
> +		/*
> +		 * if next_idx is/was the last ring index, and 'pi' is
> +		 * different, we can disable the workaround as all the ring
> +		 * entries have now been DMA'd to so valid-bit checking is
> +		 * repaired. Note: this logic needs to be based on next_idx
> +		 * (which increments one at a time), rather than on pi (which
> +		 * can burst and wrap-around between our snapshots of it).
> +		 */
> +		if (s->dqrr.next_idx == (s->dqrr.dqrr_size - 1)) {
> +			pr_debug("next_idx=%d, pi=%d, clear reset bug\n",
> +				 s->dqrr.next_idx, pi);
> +			s->dqrr.reset_bug = 0;
> +		}
> +		prefetch(qbman_get_cmd(s,
> +				       QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)));
> +	}
> +
> +	p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR_MEM(s->dqrr.next_idx));
> +	verb = p->dq.verb;
> +
> +	/*
> +	 * If the valid-bit isn't of the expected polarity, nothing there. Note,
> +	 * in the DQRR reset bug workaround, we shouldn't need to skip these
> +	 * check, because we've already determined that a new entry is available
> +	 * and we've invalidated the cacheline before reading it, so the
> +	 * valid-bit behaviour is repaired and should tell us what we already
> +	 * knew from reading PI.
> +	 */
> +	if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) {
> +		prefetch(qbman_get_cmd(s,
> +			 QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)));
> +		return NULL;
> +	}
> +	/*
> +	 * There's something there. Move "next_idx" attention to the next ring
> +	 * entry (and prefetch it) before returning what we found.
> +	 */
> +	s->dqrr.next_idx++;
> +	s->dqrr.next_idx &= s->dqrr.dqrr_size - 1; /* Wrap around */
> +	if (!s->dqrr.next_idx)
> +		s->dqrr.valid_bit ^= QB_VALID_BIT;
> +
> +	/*
> +	 * If this is the final response to a volatile dequeue command
> +	 * indicate that the vdq is available
> +	 */
> +	flags = p->dq.stat;
> +	response_verb = verb & QBMAN_RESULT_MASK;
> +	if (response_verb == QBMAN_RESULT_DQ &&
> +	    (flags & DPAA2_DQ_STAT_VOLATILE) &&
> +	    (flags & DPAA2_DQ_STAT_EXPIRED))
> +		atomic_inc(&s->vdq.available);
> +
> +	prefetch(qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)));
> +
> +	return p;
> +}
> +
> +/**
>   * qbman_swp_dqrr_consume() -  Consume DQRR entries previously returned from
>   *                             qbman_swp_dqrr_next().
>   * @s: the software portal object
> @@ -872,7 +1468,7 @@ void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable)
>  #define RAR_SUCCESS(rar) ((rar) & 0x100)
>  
>  /**
> - * qbman_swp_release() - Issue a buffer release command
> + * qbman_swp_release_direct() - Issue a buffer release command
>   * @s:           the software portal object
>   * @d:           the release descriptor
>   * @buffers:     a pointer pointing to the buffer address to be released
> @@ -880,8 +1476,53 @@ void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable)
>   *
>   * Return 0 for success, -EBUSY if the release command ring is not ready.
>   */
> -int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d,
> -		      const u64 *buffers, unsigned int num_buffers)
> +int qbman_swp_release_direct(struct qbman_swp *s,
> +			     const struct qbman_release_desc *d,
> +			     const u64 *buffers, unsigned int num_buffers)
> +{
> +	int i;
> +	struct qbman_release_desc *p;
> +	u32 rar;
> +
> +	if (!num_buffers || num_buffers > 7)
> +		return -EINVAL;
> +
> +	rar = qbman_read_register(s, QBMAN_CINH_SWP_RAR);
> +	if (!RAR_SUCCESS(rar))
> +		return -EBUSY;
> +
> +	/* Start the release command */
> +	if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000)
> +		p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar)));
> +	else
> +		p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR_MEM(RAR_IDX(rar)));
> +	/* Copy the caller's buffer pointers to the command */
> +	for (i = 0; i < num_buffers; i++)
> +		p->buf[i] = cpu_to_le64(buffers[i]);
> +	p->bpid = d->bpid;
> +
> +	/*
> +	 * Set the verb byte, have to substitute in the valid-bit
> +	 * and the number of buffers.
> +	 */
> +	dma_wmb();
> +	p->verb = d->verb | RAR_VB(rar) | num_buffers;
> +
> +	return 0;
> +}
> +
> +/**
> + * qbman_swp_release_mem_back() - Issue a buffer release command
> + * @s:           the software portal object
> + * @d:           the release descriptor
> + * @buffers:     a pointer pointing to the buffer address to be released
> + * @num_buffers: number of buffers to be released,  must be less than 8
> + *
> + * Return 0 for success, -EBUSY if the release command ring is not ready.
> + */
> +int qbman_swp_release_mem_back(struct qbman_swp *s,
> +			       const struct qbman_release_desc *d,
> +			       const u64 *buffers, unsigned int num_buffers)
>  {
>  	int i;
>  	struct qbman_release_desc *p;
> @@ -904,19 +1545,10 @@ int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d,
>  		p->buf[i] = cpu_to_le64(buffers[i]);
>  	p->bpid = d->bpid;
>  
> -	if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) {
> -		/*
> -		 * Set the verb byte, have to substitute in the valid-bit
> -		 * and the number of buffers.
> -		 */
> -		dma_wmb();
> -		p->verb = d->verb | RAR_VB(rar) | num_buffers;
> -	} else {
> -		p->verb = d->verb | RAR_VB(rar) | num_buffers;
> -		dma_wmb();
> -		qbman_write_register(s, QBMAN_CINH_SWP_RCR_AM_RT +
> -				     RAR_IDX(rar)  * 4, QMAN_RT_MODE);
> -	}
> +	p->verb = d->verb | RAR_VB(rar) | num_buffers;
> +	dma_wmb();
> +	qbman_write_register(s, QBMAN_CINH_SWP_RCR_AM_RT +
> +			     RAR_IDX(rar)  * 4, QMAN_RT_MODE);
>  
>  	return 0;
>  }
> diff --git a/drivers/soc/fsl/dpio/qbman-portal.h b/drivers/soc/fsl/dpio/qbman-portal.h
> index f3ec5d2..f4b6e47 100644
> --- a/drivers/soc/fsl/dpio/qbman-portal.h
> +++ b/drivers/soc/fsl/dpio/qbman-portal.h
> @@ -9,6 +9,13 @@
>  
>  #include <soc/fsl/dpaa2-fd.h>
>  
> +#define QMAN_REV_4000   0x04000000
> +#define QMAN_REV_4100   0x04010000
> +#define QMAN_REV_4101   0x04010001
> +#define QMAN_REV_5000   0x05000000
> +
> +#define QMAN_REV_MASK   0xffff0000
> +
>  struct dpaa2_dq;
>  struct qbman_swp;
>  
> @@ -67,6 +74,22 @@ enum qbman_pull_type_e {
>  #define QBMAN_FQ_XOFF		0x4e
>  
>  /* structure of enqueue descriptor */
> +struct qbman_eq_desc_min {
> +	u8 verb;
> +	u8 dca;
> +	__le16 seqnum;
> +	__le16 orpid;
> +	__le16 reserved1;
> +	__le32 tgtid;
> +	__le32 tag;
> +	__le16 qdbin;
> +	u8 qpri;
> +	u8 reserved[3];
> +	u8 wae;
> +	u8 rspid;
> +	__le64 rsp_addr;
> +};
> +
>  struct qbman_eq_desc {
>  	u8 verb;
>  	u8 dca;
> @@ -132,8 +155,48 @@ struct qbman_swp {
>  		u8 dqrr_size;
>  		int reset_bug; /* indicates dqrr reset workaround is needed */
>  	} dqrr;
> +
> +	struct {
> +		u32 pi;
> +		u32 pi_vb;
> +		u32 pi_ring_size;
> +		u32 pi_ci_mask;
> +		u32 ci;
> +		int available;
> +		u32 pend;
> +		u32 no_pfdr;
> +	} eqcr;
> +
> +	spinlock_t access_spinlock;
>  };
>  
> +/* Function pointers */
> +extern
> +int (*qbman_swp_enqueue_ring_mode_ptr)(struct qbman_swp *s,
> +				       const struct qbman_eq_desc *d,
> +				       const struct dpaa2_fd *fd);
> +extern
> +int (*qbman_swp_enqueue_multiple_ptr)(struct qbman_swp *s,
> +				      const struct qbman_eq_desc *d,
> +				      const struct dpaa2_fd *fd,
> +				      uint32_t *flags,
> +				      int num_frames);
> +extern
> +int (*qbman_swp_enqueue_multiple_desc_ptr)(struct qbman_swp *s,
> +					   const struct qbman_eq_desc_min *d,
> +					   const struct dpaa2_fd *fd,
> +					   int num_frames);
> +extern
> +int (*qbman_swp_pull_ptr)(struct qbman_swp *s, struct qbman_pull_desc *d);
> +extern
> +const struct dpaa2_dq *(*qbman_swp_dqrr_next_ptr)(struct qbman_swp *s);
> +extern
> +int (*qbman_swp_release_ptr)(struct qbman_swp *s,
> +			     const struct qbman_release_desc *d,
> +			     const u64 *buffers,
> +			     unsigned int num_buffers);
> +
> +/* Functions */
>  struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d);
>  void qbman_swp_finish(struct qbman_swp *p);
>  u32 qbman_swp_interrupt_read_status(struct qbman_swp *p);
> @@ -158,29 +221,25 @@ void qbman_pull_desc_set_wq(struct qbman_pull_desc *d, u32 wqid,
>  void qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid,
>  				 enum qbman_pull_type_e dct);
>  
> -int qbman_swp_pull(struct qbman_swp *p, struct qbman_pull_desc *d);
> -
> -const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s);
>  void qbman_swp_dqrr_consume(struct qbman_swp *s, const struct dpaa2_dq *dq);
>  
>  int qbman_result_has_new_result(struct qbman_swp *p, const struct dpaa2_dq *dq);
>  
>  void qbman_eq_desc_clear(struct qbman_eq_desc *d);
> +void qbman_eq_desc_min_clear(struct qbman_eq_desc_min *d);
>  void qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success);
> +void qbman_eq_desc_set_no_orp_min(struct qbman_eq_desc_min *d,
> +				  int respond_success);
>  void qbman_eq_desc_set_token(struct qbman_eq_desc *d, u8 token);
>  void qbman_eq_desc_set_fq(struct qbman_eq_desc *d, u32 fqid);
> +void qbman_eq_desc_set_min_fq(struct qbman_eq_desc_min *d, u32 fqid);
>  void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid,
>  			  u32 qd_bin, u32 qd_prio);
>  
> -int qbman_swp_enqueue(struct qbman_swp *p, const struct qbman_eq_desc *d,
> -		      const struct dpaa2_fd *fd);
> -
>  void qbman_release_desc_clear(struct qbman_release_desc *d);
>  void qbman_release_desc_set_bpid(struct qbman_release_desc *d, u16 bpid);
>  void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable);
>  
> -int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d,
> -		      const u64 *buffers, unsigned int num_buffers);
>  int qbman_swp_acquire(struct qbman_swp *s, u16 bpid, u64 *buffers,
>  		      unsigned int num_buffers);
>  int qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid,
> @@ -194,6 +253,61 @@ void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb);
>  void *qbman_swp_mc_result(struct qbman_swp *p);
>  
>  /**
> + * qbman_swp_enqueue() - Issue an enqueue command
> + * @s:  the software portal used for enqueue
> + * @d:  the enqueue descriptor
> + * @fd: the frame descriptor to be enqueued
> + *
> + * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready.
> + */
> +static inline int
> +qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d,
> +		  const struct dpaa2_fd *fd)
> +{
> +	return qbman_swp_enqueue_ring_mode_ptr(s, d, fd);
> +}
> +
> +/**
> + * qbman_swp_enqueue_multiple() - Issue a multi enqueue command
> + * using one enqueue descriptor
> + * @s:  the software portal used for enqueue
> + * @d:  the enqueue descriptor
> + * @fd: table pointer of frame descriptor table to be enqueued
> + * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL
> + * @num_frames: number of fd to be enqueued
> + *
> + * Return the number of fd enqueued, or a negative error number.
> + */
> +static inline int
> +qbman_swp_enqueue_multiple(struct qbman_swp *s,
> +			   const struct qbman_eq_desc *d,
> +			   const struct dpaa2_fd *fd,
> +			   uint32_t *flags,
> +			   int num_frames)
> +{
> +	return qbman_swp_enqueue_multiple_ptr(s, d, fd, flags, num_frames);
> +}
> +
> +/**
> + * qbman_swp_enqueue_multiple_desc() - Issue a multi enqueue command
> + * using multiple enqueue descriptor
> + * @s:  the software portal used for enqueue
> + * @d:  table of minimal enqueue descriptor
> + * @fd: table pointer of frame descriptor table to be enqueued
> + * @num_frames: number of fd to be enqueued
> + *
> + * Return the number of fd enqueued, or a negative error number.
> + */
> +static inline int
> +qbman_swp_enqueue_multiple_desc(struct qbman_swp *s,
> +				const struct qbman_eq_desc_min *d,
> +				const struct dpaa2_fd *fd,
> +				int num_frames)
> +{
> +	return qbman_swp_enqueue_multiple_desc_ptr(s, d, fd, num_frames);
> +}
> +
> +/**
>   * qbman_result_is_DQ() - check if the dequeue result is a dequeue response
>   * @dq: the dequeue result to be checked
>   *
> @@ -504,4 +618,49 @@ int qbman_bp_query(struct qbman_swp *s, u16 bpid,
>  
>  u32 qbman_bp_info_num_free_bufs(struct qbman_bp_query_rslt *a);
>  
> +/**
> + * qbman_swp_release() - Issue a buffer release command
> + * @s:           the software portal object
> + * @d:           the release descriptor
> + * @buffers:     a pointer pointing to the buffer address to be released
> + * @num_buffers: number of buffers to be released,  must be less than 8
> + *
> + * Return 0 for success, -EBUSY if the release command ring is not ready.
> + */
> +static inline int qbman_swp_release(struct qbman_swp *s,
> +				    const struct qbman_release_desc *d,
> +				    const u64 *buffers,
> +				    unsigned int num_buffers)
> +{
> +	return qbman_swp_release_ptr(s, d, buffers, num_buffers);
> +}
> +
> +/**
> + * qbman_swp_pull() - Issue the pull dequeue command
> + * @s: the software portal object
> + * @d: the software portal descriptor which has been configured with
> + *     the set of qbman_pull_desc_set_*() calls
> + *
> + * Return 0 for success, and -EBUSY if the software portal is not ready
> + * to do pull dequeue.
> + */
> +static inline int qbman_swp_pull(struct qbman_swp *s,
> +				 struct qbman_pull_desc *d)
> +{
> +	return qbman_swp_pull_ptr(s, d);
> +}
> +
> +/**
> + * qbman_swp_dqrr_next() - Get an valid DQRR entry
> + * @s: the software portal object
> + *
> + * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry
> + * only once, so repeated calls can return a sequence of DQRR entries, without
> + * requiring they be consumed immediately or in any particular order.
> + */
> +static inline const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
> +{
> +	return qbman_swp_dqrr_next_ptr(s);
> +}
> +
>  #endif /* __FSL_QBMAN_PORTAL_H */



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v3 08/17] arm64, trans_pgd: make trans_pgd_map_page generic
From: Pavel Tatashin @ 2019-09-06 18:58 UTC (permalink / raw)
  To: James Morse
  Cc: Sasha Levin, Mark Rutland, Vladimir Murzin, Jonathan Corbet,
	Marc Zyngier, Catalin Marinas, Bhupesh Sharma, kexec mailing list,
	LKML, James Morris, linux-mm, Eric W. Biederman, Matthias Brugger,
	will, Linux ARM
In-Reply-To: <62fc9ed9-1740-d40b-bc72-6d1911ef1f24@arm.com>

On Fri, Sep 6, 2019 at 11:20 AM James Morse <james.morse@arm.com> wrote:
>
> Hi Pavel,
>
> On 21/08/2019 19:31, Pavel Tatashin wrote:
> > Currently, trans_pgd_map_page has assumptions that are relevant to
> > hibernate. But, to make it generic we must allow it to use any allocator
>
> Sounds familiar: you removed this in patch 2.

Yes, will fix it. Thank  you.

>
>
> > and also, can't assume that entries do not exist in the page table
> > already.
>
> This thing creates a set of page tables to map one page: the relocation code.
> This is mapped in TTBR0_EL1.
> It can assume existing entries do not exist, because it creates the single-entry levels as
> it goes. Kexec also needs to map precisely one page for relocation. You don't need to
> generalise this.
>
> 'trans_pgd_create_copy()' is what creates a copy the linear map. This is mapped in TTBR1_EL1.
>
> There is no reason for kexec to behave differently here.

This is again left over from earlier version where I had a flag for
this assumption. But later redesigned kexec to never have conflicting
mapptings.
I will fix this commit log.

>
>
> > Also, we can't use init_mm here.
>
> Why not? arm64's pgd_populate() doesn't use the mm. It's only there to make it obvious
> this is an EL1 mapping we are creating. We use the kernel-asid with the new mapping.

I understand, and we can use "mm" pointer here, but the problem of
doing so in trans_pdg_* is that it makes the design look ugly. We are
creating page tables for context that runs "mm" because it is between
kernels when everything is overwritten. Yet, relying on "mm" to create
these page tables is odd.

>
> The __ version is a lot less readable.

The only __version of macros I am using is for "populate" calls: for
example, __pmd_populate  instead of pmd_populate etc. I will use non
'__' variants with NULL argument instead of mm.

> Please don't use the page tables as an array: this is what the offset helpers are for.

Sure, I can use:

pte_offset_kernel()
pmd_offset()
pud_offset()
pgd_offset_raw()

The code becomes a little less efficient, because offsets return
pointer to the entry after READ_ONCE, and we need to use another
READ_ONCE() to read its content to parse its value in for example
pud_table(), pud_none() etc . In my case we use READ_ONCE() only one
time  per entry and operate on the content multiple times. Also,
because of unfortunate differences in macro names, the code become a
little less symmetric. Still, I can change the code to use _offsets
here. Please let me know if you still think it is better to use them
here.

>
>
> > Also, add "flags" for trans_pgd_info, they are going to be used
> > in copy functions once they are generalized.
>
> You don't need to 'generalize' this to support hypothetical users.
> There are only two: hibernate and kexec, both of which are very specialised. Making these
> things top-level marionette strings will tangle the logic.

Will do that (see reply below)

>
> The copy_p?d() functions should decide if they should manipulate _this_ entry based on
> _this_ entry and the kernel configuration. This is only really done in _copy_pte(), which
> is where it should stay.

I am sorry, I do not understand this comment. Could you please
elaborate what would you like me to change.

>
>
> > diff --git a/arch/arm64/include/asm/trans_pgd.h b/arch/arm64/include/asm/trans_pgd.h
> > index c7b5402b7d87..e3d022b1b526 100644
> > --- a/arch/arm64/include/asm/trans_pgd.h
> > +++ b/arch/arm64/include/asm/trans_pgd.h
> > @@ -11,10 +11,45 @@
> >  #include <linux/bits.h>
> >  #include <asm/pgtable-types.h>
> >
> > +/*
> > + * trans_alloc_page
> > + *   - Allocator that should return exactly one uninitilaized page, if this
> > + *    allocator fails, trans_pgd returns -ENOMEM error.
> > + *
> > + * trans_alloc_arg
> > + *   - Passed to trans_alloc_page as an argument
>
> This is very familiar.

Sorry, What do you mean?

>
>
> > + * trans_flags
> > + *   - bitmap with flags that control how page table is filled.
> > + *     TRANS_MKWRITE: during page table copy make PTE, PME, and PUD page
> > + *                    writeable by removing RDONLY flag from PTE.
>
> Why would you ever keep the read-only flags in a set of page tables that exist to let you
> overwrite memory?

It meant to take care of this comment, and keep it in hibernate specific code:
329                 /*
330                  * Resume will overwrite areas that may be marked read only
331                  * (code, rodata). Clear the RDONLY bit from the temporary
332                  * mappings we use during restore.
333                  */
334                 .trans_flags            = TRANS_MKWRITE,
335         };

But, sure, this makes sense I will remove this flag, and will do
RDONLY unconditionally.

I re-evaluated "flags", and figured that they are indeed not needed.
So, I will embed them into the code directly.

>
>
> > + *     TRANS_MKVALID: during page table copy, if PTE present, but not valid,
> > + *                    make it valid.
>
> Please keep this logic together with the !pte_none(pte) and debug_pagealloc_enabled()
> check, where it is today.
>
> Making an entry valid without those checks should never be necessary.

Yes, will do that.

>
>
> > + *     TRANS_CHECKPFN: During page table copy, for every PTE entry check that
> > + *                     PFN that this PTE points to is valid. Otherwise return
> > + *                     -ENXIO
>
> Hibernate does this when inventing a new mapping. This is how we check the kernel
> should be able to read/write this page. If !pfn_valid(), the page should not be mapped.
>
> Why do you need to turn this off?
>
> It us only necessary at the leaf level, and only if debug-pagealloc is in use. Please keep
> all these bits together, as its much harder to understand why this entry needs inventing
> when its split up like this.
>
>
>

> > diff --git a/arch/arm64/mm/trans_pgd.c b/arch/arm64/mm/trans_pgd.c
> > index 00b62d8640c2..dbabccd78cc4 100644
> > --- a/arch/arm64/mm/trans_pgd.c
> > +++ b/arch/arm64/mm/trans_pgd.c
> > @@ -17,6 +17,16 @@
> >  #include <asm/pgtable.h>
> >  #include <linux/suspend.h>
> >
> > +static void *trans_alloc(struct trans_pgd_info *info)
> > +{
> > +     void *page = info->trans_alloc_page(info->trans_alloc_arg);
> > +
> > +     if (page)
> > +             clear_page(page);
>
> The hibernate allocator already does this. As your reason for doing this is to make this
> faster, it seems odd we do this twice.
>
> If zeroed pages are necessary, the allocator should do it. (It already needs to be a
> use-case specific allocator)

Makes sense, I will change the requirement for allocator to return
zeroed memory.

>
>
> > +
> > +     return page;
> > +}
> > +
> >  static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
> >  {
> >       pte_t pte = READ_ONCE(*src_ptep);
> > @@ -172,40 +182,64 @@ int trans_pgd_create_copy(pgd_t **dst_pgdp, unsigned long start,
> >       return rc;
> >  }
> >
> > -int trans_pgd_map_page(pgd_t *trans_pgd, void *page, unsigned long dst_addr,
> > -                    pgprot_t pgprot)
> > +int trans_pgd_map_page(struct trans_pgd_info *info, pgd_t *trans_pgd,
> > +                    void *page, unsigned long dst_addr, pgprot_t pgprot)
> >  {
> > -     pgd_t *pgdp;
> > -     pud_t *pudp;
> > -     pmd_t *pmdp;
> > -     pte_t *ptep;
> > -
> > -     pgdp = pgd_offset_raw(trans_pgd, dst_addr);
> > -     if (pgd_none(READ_ONCE(*pgdp))) {
> > -             pudp = (void *)get_safe_page(GFP_ATOMIC);
> > -             if (!pudp)
> > +     int pgd_idx = pgd_index(dst_addr);
> > +     int pud_idx = pud_index(dst_addr);
> > +     int pmd_idx = pmd_index(dst_addr);
> > +     int pte_idx = pte_index(dst_addr);
>
> Yuck.
>

What's wrong with pre-calculating indices? :)

>
>
> > +     pgd_t *pgdp = trans_pgd;
> > +     pgd_t pgd = READ_ONCE(pgdp[pgd_idx]);
> > +     pud_t *pudp, pud;
> > +     pmd_t *pmdp, pmd;
> > +     pte_t *ptep, pte;
> > +
> > +     if (pgd_none(pgd)) {
> > +             pud_t *t = trans_alloc(info);
> > +
> > +             if (!t)
> >                       return -ENOMEM;
>
> > -             pgd_populate(&init_mm, pgdp, pudp);
> > +
> > +             __pgd_populate(&pgdp[pgd_idx], __pa(t), PUD_TYPE_TABLE);
> > +             pgd = READ_ONCE(pgdp[pgd_idx]);
>
>
> Please keep the pgd_populate() call. If there is some reason we can't pass init_mm, we can
> pass NULL, or a fake mm pointer instead.\\

Hm, we could use NULL instead of "mm", I will do that, thanks.

>
> Going behind the page table helpers back to play with the table directly is a maintenance
> headache.
>
>
> >       }
> >
>
>
> > -     pudp = pud_offset(pgdp, dst_addr);
> > -     if (pud_none(READ_ONCE(*pudp))) {
> > -             pmdp = (void *)get_safe_page(GFP_ATOMIC);
> > -             if (!pmdp)
> > +     pudp = __va(pgd_page_paddr(pgd));
> > +     pud = READ_ONCE(pudp[pud_idx]);
> > +     if (pud_sect(pud)) {
> > +             return -ENXIO;
> > +     } else if (pud_none(pud) || pud_sect(pud)) {
> > +             pmd_t *t = trans_alloc(info);
> > +
> > +             if (!t)
> >                       return -ENOMEM;
>
> Choke on block mappings? This should never happen because this function should only create
> the tables necessary to map one page. Not a block mapping in sight.
>
> (see my comments on patch 6)

I can remove this, but what should I replace it with BUG() or silently
ignore, and assume no huge page hre? I thought the idea is not to use
BUG() calls in kernel code, and return errors instead. If, in the
future PUD size mappings are added, how is that going to be detected?

Thank you,
Pasha

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v3 09/17] arm64, trans_pgd: add trans_pgd_create_empty
From: Pavel Tatashin @ 2019-09-06 19:00 UTC (permalink / raw)
  To: James Morse
  Cc: Sasha Levin, Mark Rutland, Vladimir Murzin, Jonathan Corbet,
	Marc Zyngier, Catalin Marinas, Bhupesh Sharma, kexec mailing list,
	LKML, James Morris, linux-mm, Eric W. Biederman, Matthias Brugger,
	will, Linux ARM
In-Reply-To: <2d9f7511-ce65-d5ca-653e-f4d43994a32d@arm.com>

On Fri, Sep 6, 2019 at 11:20 AM James Morse <james.morse@arm.com> wrote:
>
> Hi Pavel,
>
> On 21/08/2019 19:31, Pavel Tatashin wrote:
> > This functions returns a zeroed trans_pgd using the allocator that is
> > specified in the info argument.
> >
> > trans_pgds should be created by using this function.
>
> This function takes the allocator you give it, and calls it once.
>
> Given both users need one pgd, and have to provide the allocator, it seems strange that
> they aren't trusted to call it.
>
> I don't think this patch is necessary.
>
> Let the caller pass in the pgd_t to the helpers.

Ok.

Thank you,
Pasha

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v3 10/17] arm64, trans_pgd: adjust trans_pgd_create_copy interface
From: Pavel Tatashin @ 2019-09-06 19:03 UTC (permalink / raw)
  To: James Morse
  Cc: Sasha Levin, Mark Rutland, Vladimir Murzin, Jonathan Corbet,
	Marc Zyngier, Catalin Marinas, Bhupesh Sharma, kexec mailing list,
	LKML, James Morris, linux-mm, Eric W. Biederman, Matthias Brugger,
	will, Linux ARM
In-Reply-To: <21f6eb6f-be3a-a715-a37c-2f59183ed183@arm.com>

> > -int trans_pgd_create_copy(pgd_t **dst_pgdp, unsigned long start,
> > +/*
> > + * Create trans_pgd and copy entries from from_table to trans_pgd in range
> > + * [start, end)
> > + */
> > +int trans_pgd_create_copy(struct trans_pgd_info *info, pgd_t **trans_pgd,
> > +                       pgd_t *from_table, unsigned long start,
> >                         unsigned long end);
>
> This creates a copy of the linear-map. Why does it need to be told from_table?

This what done as a generic page table entries copy, but I agree, will
remove the from_table.

>
>
> > diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
> > index 8c2641a9bb09..8bb602e91065 100644
> > --- a/arch/arm64/kernel/hibernate.c
> > +++ b/arch/arm64/kernel/hibernate.c
> > @@ -323,15 +323,42 @@ int swsusp_arch_resume(void)
> >       phys_addr_t phys_hibernate_exit;
> >       void __noreturn (*hibernate_exit)(phys_addr_t, phys_addr_t, void *,
> >                                         void *, phys_addr_t, phys_addr_t);
> > +     struct trans_pgd_info trans_info = {
> > +             .trans_alloc_page       = hibernate_page_alloc,
> > +             .trans_alloc_arg        = (void *)GFP_ATOMIC,
> > +             /*
> > +              * Resume will overwrite areas that may be marked read only
> > +              * (code, rodata). Clear the RDONLY bit from the temporary
> > +              * mappings we use during restore.
> > +              */
> > +             .trans_flags            = TRANS_MKWRITE,
> > +     };
>
>
> > +     /*
> > +      * debug_pagealloc will removed the PTE_VALID bit if the page isn't in
> > +      * use by the resume kernel. It may have been in use by the original
> > +      * kernel, in which case we need to put it back in our copy to do the
> > +      * restore.
> > +      *
> > +      * Before marking this entry valid, check the pfn should be mapped.
> > +      */
> > +     if (debug_pagealloc_enabled())
> > +             trans_info.trans_flags |= (TRANS_MKVALID | TRANS_CHECKPFN);
>
> The debug_pagealloc_enabled() check should be with the code that generates a different
> entry. Whether the different entry is correct needs to be considered with
> debug_pagealloc_enabled() in mind. You are making this tricky logic less clear.
>
> There is no way the existing code invents an entry for a !pfn_valid() page. With your
> 'checkpfn' flag, this thing can. You don't need to generalise this for hypothetical users.

Ok

>
>
> If kexec needs to create mappings for bogus pages, I'd like to know why.
>

It does not.

>
> >       /*
> >        * Restoring the memory image will overwrite the ttbr1 page tables.
> >        * Create a second copy of just the linear map, and use this when
> >        * restoring.
> >        */
> > -     rc = trans_pgd_create_copy(&tmp_pg_dir, PAGE_OFFSET, 0);
> > -     if (rc)
> > +     rc = trans_pgd_create_copy(&trans_info, &tmp_pg_dir, init_mm.pgd,
> > +                                PAGE_OFFSET, 0);
>
> > +     if (rc) {
> > +             if (rc == -ENOMEM)
> > +                     pr_err("Failed to allocate memory for temporary page tables.\n");
> > +             else if (rc == -ENXIO)
> > +                     pr_err("Tried to set PTE for PFN that does not exist\n");
> >               goto out;
> > +     }
>
> If you think the distinction for this error message is useful, it would be clearer to
> change it in the current hibernate code before you move it. (_copy_pte() to return an
> error, instead of silently failing). Done here, this is unrelated noise.
>

Ok, will do that.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 1/1] mm/pgtable/debug: Add test validating architecture page table helpers
From: Gerald Schaefer @ 2019-09-06 19:03 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: Mark Rutland, linux-ia64, linux-sh, Peter Zijlstra, James Hogan,
	Tetsuo Handa, Heiko Carstens, Michal Hocko, linux-mm, Dave Hansen,
	Paul Mackerras, sparclinux, Thomas Gleixner, linux-s390,
	Michael Ellerman, x86, Russell King - ARM Linux, Matthew Wilcox,
	Steven Price, Jason Gunthorpe, linux-arm-kernel, linux-snps-arc,
	Kees Cook, Masahiro Yamada, Mark Brown, Dan Williams,
	Vlastimil Babka, Sri Krishna chowdary, Ard Biesheuvel,
	Greg Kroah-Hartman, linux-mips, Ralf Baechle, linux-kernel,
	Paul Burton, Mike Rapoport, Vineet Gupta, Martin Schwidefsky,
	Andrew Morton, linuxppc-dev, David S. Miller
In-Reply-To: <3c609e33-afbb-ffaf-481a-6d225a06d1d0@arm.com>

On Fri, 6 Sep 2019 11:58:59 +0530
Anshuman Khandual <anshuman.khandual@arm.com> wrote:

> On 09/05/2019 10:36 PM, Gerald Schaefer wrote:
> > On Thu, 5 Sep 2019 14:48:14 +0530
> > Anshuman Khandual <anshuman.khandual@arm.com> wrote:
> >   
> >>> [...]    
> >>>> +
> >>>> +#if !defined(__PAGETABLE_PMD_FOLDED) && !defined(__ARCH_HAS_4LEVEL_HACK)
> >>>> +static void pud_clear_tests(pud_t *pudp)
> >>>> +{
> >>>> +	memset(pudp, RANDOM_NZVALUE, sizeof(pud_t));
> >>>> +	pud_clear(pudp);
> >>>> +	WARN_ON(!pud_none(READ_ONCE(*pudp)));
> >>>> +}    
> >>>
> >>> For pgd/p4d/pud_clear(), we only clear if the page table level is present
> >>> and not folded. The memset() here overwrites the table type bits, so
> >>> pud_clear() will not clear anything on s390 and the pud_none() check will
> >>> fail.
> >>> Would it be possible to OR a (larger) random value into the table, so that
> >>> the lower 12 bits would be preserved?    
> >>
> >> So the suggestion is instead of doing memset() on entry with RANDOM_NZVALUE,
> >> it should OR a large random value preserving lower 12 bits. Hmm, this should
> >> still do the trick for other platforms, they just need non zero value. So on
> >> s390, the lower 12 bits on the page table entry already has valid value while
> >> entering this function which would make sure that pud_clear() really does
> >> clear the entry ?  
> > 
> > Yes, in theory the table entry on s390 would have the type set in the last
> > 4 bits, so preserving those would be enough. If it does not conflict with
> > others, I would still suggest preserving all 12 bits since those would contain
> > arch-specific flags in general, just to be sure. For s390, the pte/pmd tests
> > would also work with the memset, but for consistency I think the same logic
> > should be used in all pxd_clear_tests.  
> 
> Makes sense but..
> 
> There is a small challenge with this. Modifying individual bits on a given
> page table entry from generic code like this test case is bit tricky. That
> is because there are not enough helpers to create entries with an absolute
> value. This would have been easier if all the platforms provided functions
> like __pxx() which is not the case now. Otherwise something like this should
> have worked.
> 
> 
> pud_t pud = READ_ONCE(*pudp);
> pud = __pud(pud_val(pud) | RANDOM_VALUE (keeping lower 12 bits 0))
> WRITE_ONCE(*pudp, pud);
> 
> But __pud() will fail to build in many platforms.

Hmm, I simply used this on my system to make pud_clear_tests() work, not
sure if it works on all archs:

pud_val(*pudp) |= RANDOM_NZVALUE;

> 
> The other alternative will be to make sure memset() happens on all other
> bits except the lower 12 bits which will depend on endianness. If s390
> has a fixed endianness, we can still use either of them which will hold
> good for others as well.
> 
> memset(pudp, RANDOM_NZVALUE, sizeof(pud_t) - 3);
> 
> OR
> 
> memset(pudp + 3, RANDOM_NZVALUE, sizeof(pud_t) - 3);
> 
> > 
> > However, there is another issue on s390 which will make this only work
> > for pud_clear_tests(), and not for the p4d/pgd_tests. The problem is that
> > mm_alloc() will only give you a 3-level page table initially on s390.
> > This means that pudp == p4dp == pgdp, and so the p4d/pgd_tests will
> > both see the pud level (of course this also affects other tests).  
> 
> Got it.
> 
> > 
> > Not sure yet how to fix this, i.e. how to initialize/update the page table
> > to 5 levels. We can handle 5 level page tables, and it would be good if
> > all levels could be tested, but using mm_alloc() to establish the page
> > tables might not work on s390. One option could be to provide an arch-hook
> > or weak function to allocate/initialize the mm.  
> 
> Sure, got it. Though I plan to do add some arch specific tests or init sequence
> like the above later on but for now the idea is to get the smallest possible set
> of test cases which builds and runs on all platforms without requiring any arch
> specific hooks or special casing (#ifdef) to be agreed upon broadly and accepted.
> 
> Do you think this is absolutely necessary on s390 for the very first set of test
> cases or we can add this later on as an improvement ?

It can be added later, no problem. I did not expect this to work flawlessly
on s390 right from the start anyway, with all our peculiarities, so don't
let this hinder you. I might come up with an add-on patch later.

Actually, using get_unmapped_area() as suggested by Kirill could also
solve this issue. We do create a new mm with 3-level page tables on s390,
and the dynamic upgrade to 4 or 5 levels is then triggered exactly by
arch_get_unmapped_area(), depending on the addr. But I currently don't
see how / where arch_get_unmapped_area() is set up for such a dummy mm
created by mm_alloc().

Regards,
Gerald


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v3 11/17] arm64, trans_pgd: add PUD_SECT_RDONLY
From: Pavel Tatashin @ 2019-09-06 19:04 UTC (permalink / raw)
  To: James Morse
  Cc: Sasha Levin, Mark Rutland, Vladimir Murzin, Jonathan Corbet,
	Marc Zyngier, Catalin Marinas, Bhupesh Sharma, kexec mailing list,
	LKML, James Morris, linux-mm, Eric W. Biederman, Matthias Brugger,
	will, Linux ARM
In-Reply-To: <d53d973c-17dc-2f4f-c052-83d6df15b002@arm.com>

On Fri, Sep 6, 2019 at 11:21 AM James Morse <james.morse@arm.com> wrote:
>
> Hi Pavel,
>
> On 21/08/2019 19:31, Pavel Tatashin wrote:
> > Thre is PMD_SECT_RDONLY that is used in pud_* function which is confusing.
>
> Nit: There
>
> I bet it was equally confusing before before you moved it! Could you do this earlier in
> the series with the rest of the cleanup?
>
> With that,
> Acked-by: James Morse <james.morse@arm.com>

Will move it earlier.

Thank you,
Pasha

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v3 12/17] arm64, trans_pgd: complete generalization of trans_pgds
From: Pavel Tatashin @ 2019-09-06 19:06 UTC (permalink / raw)
  To: James Morse
  Cc: Sasha Levin, Mark Rutland, Vladimir Murzin, Jonathan Corbet,
	Marc Zyngier, Catalin Marinas, Bhupesh Sharma, kexec mailing list,
	LKML, James Morris, linux-mm, Eric W. Biederman, Matthias Brugger,
	will, Linux ARM
In-Reply-To: <d4a5bb7b-21c0-9f39-ad96-3fa43684c6c6@arm.com>

On Fri, Sep 6, 2019 at 11:23 AM James Morse <james.morse@arm.com> wrote:
>
> Hi Pavel,
>
> On 21/08/2019 19:31, Pavel Tatashin wrote:
> > Make the last private functions in page table copy path generlized for use
> > outside of hibernate.
> >
> > Switch to use the provided allocator, flags, and source page table. Also,
> > unify all copy function implementations to reduce the possibility of bugs.
>
> By changing it? No one has reported any problems. We're more likely to break it making
> unnecessary changes.
>
> Why is this necessary?

I tried to make it cleaner, but if you think the final version does
not make it better, I will keep the current versions.

Thank you,
Pasha

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] PCI: dwc: Use PTR_ERR_OR_ZERO() in five functions
From: Andrew Murray @ 2019-09-06 19:30 UTC (permalink / raw)
  To: Markus Elfring
  Cc: kernel-janitors, linux-samsung-soc, Xiaowei Song, linux-pci,
	Binghui Wang, YueHaibing, LKML, Krzysztof Kozlowski, Yue Wang,
	Kukjin Kim, Kevin Hilman, Jingoo Han, Bjorn Helgaas,
	linux-amlogic, zhong jiang, Lorenzo Pieralisi, linux-arm-kernel
In-Reply-To: <95c9dfae-af81-82ad-e989-1fdf5f29808e@web.de>

On Fri, Sep 06, 2019 at 08:50:07PM +0200, Markus Elfring wrote:
> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Fri, 6 Sep 2019 20:40:06 +0200
> 
> Simplify these function implementations by using a known function.
> 
> Generated by: scripts/coccinelle/api/ptr_ret.cocci
> 
> Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>

Thanks for this, looks good to me:

Reviewed-by: Andrew Murray <andrew.murray@arm.com>

> ---
>  drivers/pci/controller/dwc/pci-exynos.c |  5 +----
>  drivers/pci/controller/dwc/pci-meson.c  | 10 ++--------
>  drivers/pci/controller/dwc/pcie-kirin.c | 10 ++--------
>  3 files changed, 5 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
> index cee5f2f590e2..b6ab1cc5d895 100644
> --- a/drivers/pci/controller/dwc/pci-exynos.c
> +++ b/drivers/pci/controller/dwc/pci-exynos.c
> @@ -92,10 +92,7 @@ static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
> 
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	ep->mem_res->elbi_base = devm_ioremap_resource(dev, res);
> -	if (IS_ERR(ep->mem_res->elbi_base))
> -		return PTR_ERR(ep->mem_res->elbi_base);
> -
> -	return 0;
> +	return PTR_ERR_OR_ZERO(ep->mem_res->elbi_base);
>  }
> 
>  static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
> diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
> index e35e9eaa50ee..713059918002 100644
> --- a/drivers/pci/controller/dwc/pci-meson.c
> +++ b/drivers/pci/controller/dwc/pci-meson.c
> @@ -182,10 +182,7 @@ static int meson_pcie_get_mems(struct platform_device *pdev,
> 
>  	/* Meson SoC has two PCI controllers use same phy register*/
>  	mp->mem_res.phy_base = meson_pcie_get_mem_shared(pdev, mp, "phy");
> -	if (IS_ERR(mp->mem_res.phy_base))
> -		return PTR_ERR(mp->mem_res.phy_base);
> -
> -	return 0;
> +	return PTR_ERR_OR_ZERO(mp->mem_res.phy_base);
>  }
> 
>  static void meson_pcie_power_on(struct meson_pcie *mp)
> @@ -259,10 +256,7 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp)
>  		return PTR_ERR(res->general_clk);
> 
>  	res->clk = meson_pcie_probe_clock(dev, "pcie", 0);
> -	if (IS_ERR(res->clk))
> -		return PTR_ERR(res->clk);
> -
> -	return 0;
> +	return PTR_ERR_OR_ZERO(res->clk);
>  }
> 
>  static inline void meson_elb_writel(struct meson_pcie *mp, u32 val, u32 reg)
> diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
> index c19617a912bd..75b1f1dde747 100644
> --- a/drivers/pci/controller/dwc/pcie-kirin.c
> +++ b/drivers/pci/controller/dwc/pcie-kirin.c
> @@ -138,10 +138,7 @@ static long kirin_pcie_get_clk(struct kirin_pcie *kirin_pcie,
>  		return PTR_ERR(kirin_pcie->apb_sys_clk);
> 
>  	kirin_pcie->pcie_aclk = devm_clk_get(dev, "pcie_aclk");
> -	if (IS_ERR(kirin_pcie->pcie_aclk))
> -		return PTR_ERR(kirin_pcie->pcie_aclk);
> -
> -	return 0;
> +	return PTR_ERR_OR_ZERO(kirin_pcie->pcie_aclk);
>  }
> 
>  static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
> @@ -174,10 +171,7 @@ static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
> 
>  	kirin_pcie->sysctrl =
>  		syscon_regmap_lookup_by_compatible("hisilicon,hi3660-sctrl");
> -	if (IS_ERR(kirin_pcie->sysctrl))
> -		return PTR_ERR(kirin_pcie->sysctrl);
> -
> -	return 0;
> +	return PTR_ERR_OR_ZERO(kirin_pcie->sysctrl);
>  }
> 
>  static int kirin_pcie_phy_init(struct kirin_pcie *kirin_pcie)
> --
> 2.23.0
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] clk: imx: pll14xx: Fix quick switch of S/K parameter
From: Leonard Crestez @ 2019-09-06 19:36 UTC (permalink / raw)
  To: Stephen Boyd, Peng Fan, Shawn Guo, Daniel Baluta
  Cc: Aisheng Dong, Jacky Bai, Michael Turquette,
	linux-clk@vger.kernel.org, dl-linux-imx, Viorel Suman,
	Fabio Estevam, kernel@pengutronix.de,
	linux-arm-kernel@lists.infradead.org, Abel Vesa
In-Reply-To: <20190906172452.D1ED620838@mail.kernel.org>

On 06.09.2019 20:24, Stephen Boyd wrote:
> Quoting Leonard Crestez (2019-09-04 02:49:18)
>> The PLL14xx on imx8m can change the S and K parameter without requiring
>> a reset and relock of the whole PLL.
>>
>> Fix clk_pll144xx_mp_change register reading and use it for pll1443 as
>> well since no reset+relock is required on K changes either.
>>
>> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
>> ---
>>   drivers/clk/imx/clk-pll14xx.c | 40 +++++++----------------------------
>>   1 file changed, 8 insertions(+), 32 deletions(-)
>>
>> The PLLs are currently table-based and none of the entries differ only
>> in S/K so further work would be required to make use of this. The
>> prospective user is audio doing tiny freq adjustments and there is no
>> standard API for that.
> 
> sub-Hz adjustments?

Maybe at the audio level? The PLL itself runs at ~400Mhz so wouldn't 
need sub-hz adjustment.

My understanding is that adjustments would be made based on an external 
clock so if CLK framework rounds to 1hz then it would just take longer 
for adjustment to kick in.

>> Lacking users is not a good reason to carry broken code around.
> 
> Maybe add a Fixes tag so if anyone wants to use it in LTS kernels there
> might be a chance that they'll find this patch mention code they're
> using.

It doesn't meet stable kernel rules because it doesn't "fix a real bug 
that bothers people" but it's still technically a fix:

Fixes: 8646d4dcc7fb ("clk: imx: Add PLLs driver for imx8mm soc")

--
Regards,
Leonard

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v5 03/10] arm64: atomics: avoid out-of-line ll/sc atomics
From: Nick Desaulniers @ 2019-09-06 19:44 UTC (permalink / raw)
  To: Andrew Murray
  Cc: Mark Rutland, Peter Zijlstra, Catalin Marinas, Robin Murphy,
	clang-built-linux, Ard.Biesheuvel, Kristof Beyls,
	Nathan Chancellor, Will Deacon, Linux ARM
In-Reply-To: <20190905112519.GY9720@e119886-lin.cambridge.arm.com>

On Thu, Sep 5, 2019 at 4:25 AM Andrew Murray <andrew.murray@arm.com> wrote:
>
> On Wed, Sep 04, 2019 at 10:28:14AM -0700, Nick Desaulniers wrote:
> > On Tue, Sep 3, 2019 at 3:04 PM Andrew Murray <andrew.murray@arm.com> wrote:
> > >
> > > On Tue, Sep 03, 2019 at 05:37:55PM +0100, Will Deacon wrote:
> > > > On Tue, Sep 03, 2019 at 04:31:20PM +0100, Andrew Murray wrote:
> > > > > On Tue, Sep 03, 2019 at 04:15:44PM +0100, Andrew Murray wrote:
> > > > > > On Tue, Sep 03, 2019 at 03:45:34PM +0100, Will Deacon wrote:
> > > > > > > Does it work if the only thing you change is the toolchain, and use GCC
> > > > > > > instead?
> > > > > >
> > > > > > Yup.
> > > > >
> > > > > Also this is Clang generation:
> > > > >
> > > > > ffff8000100f2700 <__ptrace_link>:
> > > > > ffff8000100f2700:       f9426009        ldr     x9, [x0, #1216]
> > > > > ffff8000100f2704:       91130008        add     x8, x0, #0x4c0
> > > > > ffff8000100f2708:       eb09011f        cmp     x8, x9
> > > > > ffff8000100f270c:       540002a1        b.ne    ffff8000100f2760 <__ptrace_link+0x60>  // b.any
> > > > > ffff8000100f2710:       f9425829        ldr     x9, [x1, #1200]
> > > > > ffff8000100f2714:       9112c02a        add     x10, x1, #0x4b0
> > > > > ffff8000100f2718:       f9000528        str     x8, [x9, #8]
> > > > > ffff8000100f271c:       f9026009        str     x9, [x0, #1216]
> > > > > ffff8000100f2720:       f902640a        str     x10, [x0, #1224]
> > > > > ffff8000100f2724:       f9025828        str     x8, [x1, #1200]
> > > > > ffff8000100f2728:       f9024001        str     x1, [x0, #1152]
> > > > > ffff8000100f272c:       b4000162        cbz     x2, ffff8000100f2758 <__ptrace_link+0x58>
> > > > > ffff8000100f2730:       b900985f        str     wzr, [x2, #152]
> > > > > ffff8000100f2734:       14000004        b       ffff8000100f2744 <__ptrace_link+0x44>
> > > > > ffff8000100f2738:       14000001        b       ffff8000100f273c <__ptrace_link+0x3c>
> > > > > ffff8000100f273c:       14000006        b       ffff8000100f2754 <__ptrace_link+0x54>
> > > > > ffff8000100f2740:       14000001        b       ffff8000100f2744 <__ptrace_link+0x44>
> > > > > ffff8000100f2744:       52800028        mov     w8, #0x1                        // #1
> > > > > ffff8000100f2748:       b828005f        stadd   w8, [x2]
> > > > > ffff8000100f274c:       f9030002        str     x2, [x0, #1536]
> > > > > ffff8000100f2750:       d65f03c0        ret
> > > > > ffff8000100f2754:       140007fd        b       ffff8000100f4748 <ptrace_check_attach+0xf8>
> > > > > ...
> > > > >
> > > > > This looks like the default path (before we write over it) will take you to
> > > > > the LSE code (e.g. ffff8000100f2734). I'm pretty sure this is wrong, or at
> > > > > least not what we expected to see. Also why 4 branches?
> > > >
> > > > So I reproduced this with a silly atomic_inc wrapper:
> > > >
> > > > void will_atomic_inc(atomic_t *v)
> > > > {
> > > >         atomic_inc(v);
> > > > }
> > > >
> > > > Compiles to:
> > > >
> > > > 0000000000000018 <will_atomic_inc>:
> > > >   18: 14000004        b       28 <will_atomic_inc+0x10>
> > > >   1c: 14000001        b       20 <will_atomic_inc+0x8>
> > > >   20: 14000005        b       34 <will_atomic_inc+0x1c>
> > > >   24: 14000001        b       28 <will_atomic_inc+0x10>
> > > >   28: 52800028        mov     w8, #0x1                        // #1
> > > >   2c: b828001f        stadd   w8, [x0]
> > > >   30: d65f03c0        ret
> > > >   34: 14000027        b       d0 <dump_kernel_offset+0x60>
> > > >   38: d65f03c0        ret
> > > >
> > > > which is going to explode.
> > >
> > > I've come up with a simple reproducer for this issue:
> > >
> > > static bool branch_jump()
> > > {
> > >         asm_volatile_goto(
> > >                 "1: b %l[l_yes2]"
> > >                  : : : : l_yes2);
> > >
> > >         return false;
> > > l_yes2:
> > >         return true;
> > > }
> > >
> > > static bool branch_test()
> > > {
> > >         return (!branch_jump() && !branch_jump());
> > > }
> > >
> > > void andy_test(int *v)
> > > {
> > >         if (branch_test())
> > >                 *v = 0xff;
> > > }
> > >
> > > This leads to the following (it shouldn't do anything):
> > >
> > > 0000000000000000 <andy_test>:
> > >    0:   14000004        b       10 <andy_test+0x10>
> > >    4:   14000001        b       8 <andy_test+0x8>
> > >    8:   14000004        b       18 <andy_test+0x18>
> > >    c:   14000001        b       10 <andy_test+0x10>
> > >   10:   52801fe8        mov     w8, #0xff                       // #255
> > >   14:   b9000008        str     w8, [x0]
> > >   18:   d65f03c0        ret
> > >
> > > The issue goes away with any of the following hunks:
> > >
> > >
> > > @@ -55,7 +55,7 @@ static bool branch_jump()
> > >
> > >  static bool branch_test()
> > >  {
> > > -       return (!branch_jump() && !branch_jump());
> > > +       return (!branch_jump());
> > >  }
> > >
> > >  void andy_test(int *v)
> > >
> > >
> > > or:
> > >
> > >
> > > @@ -53,14 +53,10 @@ static bool branch_jump()
> > >          return true;
> > >  }
> > >
> > > -static bool branch_test()
> > > -{
> > > -       return (!branch_jump() && !branch_jump());
> > > -}
> > >
> > >  void andy_test(int *v)
> > >  {
> > > -       if (branch_test())
> > > +       if (!branch_jump() && !branch_jump())
> > >                 *v = 0xff;
> > >  }
> >
> > Indeed, playing with the definition of `__lse_ll_sc_body`, I can get
> > the kernel to boot again.
>
> Thanks for investigating this.
>
> Did it boot to a prompt? I played with the structure of the code and
> too was able to get it to boot, but I found that it hung later-on during
> boot. Thus I lost a bit of confidence in it.
>
> >
> > So I think your very helpful test cases are illustrating two different problems:
> > https://godbolt.org/z/dMf7x-
> > See the disassembly of `andy_test2`.  Reference to the correct label
> > is emitted in the inline asm, but there's some silly unconditional
> > branches to the next instruction.  That's issue #1 and part of the
> > reason you see superfluous branches.  With that fixed, `andy_test2`
> > would match between GCC and Clang.  I think that can be a very late
> > peephole optimization (and further, we could probably combine labels
> > that refer to the same location, oh and .Lfunc_endX could just use
> > `.`, too!). LLVM devs noted that the x86 backend doesn't have this
> > issue, but this is a curiously recurring pattern I'm noticing in LLVM
> > where some arch agnostic optimization is only implemented for x86...
> > I'm reading through our Branch Folding pass which I think should
> > handle this, but I'll need to fire up a debugger.
> >
> > Issue #2 is the more critical issue, but may be conflated with issue
> > #1.  Issue #2 is the nonsensical control flow with one level of
> > inlining.  See how in the disassembly of `andy_test`, the first label
> > referenced from inline assembly is *before* the mov/str when it should
> > have been *after*.  Not sure where we could be going wrong, but it's
> > straightforward for me to observe the code change as its transformed
> > through LLVM, and I've debugged and fixed issues related to inlining
> > asm goto before.
>
> You may also be interested in this:
>
> https://godbolt.org/z/8OthP2
>
> void andy_test3(int *v)
> {
>     if (!branch_jump())
>         return;
>
>     if (!branch_jump())
>         return;
>
>     *v = 0xff;
> }
>
> (I used a similar approach with system_uses_lse_atomics to get the
> kernel to boot a bit more).
>
> This generated code does the right thing here (in comparison to andy_test2).
> I felt like this gave an insight as to what is going on, but I don't
> have the knowledge to know what. It's as if the early return prevents the
> compiler from getting confused when it should otherwise jump to the second
> goto.

Thanks for all of these test cases.  It highlighted a bug in our
implementation that I have a fix in hand for (currently awaiting code
review):
https://reviews.llvm.org/D67252

Further, I wrote a check for this kind of bug in our verification
pass, so that this kind of bug doesn't creep back in:
https://reviews.llvm.org/D67196

I cleared https://reviews.llvm.org/D67252 w/ the clang-9 release
manager; assuming I land it today or early next week we'll likely be
able to pick it up for the clang-9 release.

I very much appreciate the help debugging and the reduced test cases.
It's been a pleasure!
-- 
Thanks,
~Nick Desaulniers

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v3 2/5] gpio/aspeed: Fix incorrect number of banks
From: Joel Stanley @ 2019-09-06 19:46 UTC (permalink / raw)
  To: Rashmica Gupta
  Cc: moderated list:ARM/ASPEED MACHINE SUPPORT,
	open list:GPIO SUBSYSTEM, Andrew Jeffery, Linus Walleij,
	open list, Bartosz Golaszewski,
	moderated list:ARM/ASPEED MACHINE SUPPORT
In-Reply-To: <20190906062623.13354-1-rashmica.g@gmail.com>

On Fri, 6 Sep 2019 at 06:26, Rashmica Gupta <rashmica.g@gmail.com> wrote:
>
> The current calculation for the number of GPIO banks is only correct if
> the number of GPIOs is a multiple of 32 (if there were 31 GPIOs we would
> currently say there are 0 banks, which is incorrect).
>
> Fixes: 361b79119a4b7 ('gpio: Add Aspeed driver')
>
> Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
> Reviewed-by: Andrew Jeffery <andrew@aj.id.au>

Reviewed-by: Joel Stanley <joel@jms.d.au>

> ---
>  drivers/gpio/gpio-aspeed.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
> index 9defe25d4721..b83e23aecd18 100644
> --- a/drivers/gpio/gpio-aspeed.c
> +++ b/drivers/gpio/gpio-aspeed.c
> @@ -1165,7 +1165,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
>         gpio->chip.base = -1;
>
>         /* Allocate a cache of the output registers */
> -       banks = gpio->config->nr_gpios >> 5;
> +       banks = DIV_ROUND_UP(gpio->config->nr_gpios, 32);
>         gpio->dcache = devm_kcalloc(&pdev->dev,
>                                     banks, sizeof(u32), GFP_KERNEL);
>         if (!gpio->dcache)
> --
> 2.20.1
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v3 3/5] gpio/aspeed: Setup irqchip dynamically
From: Joel Stanley @ 2019-09-06 19:46 UTC (permalink / raw)
  To: Rashmica Gupta
  Cc: moderated list:ARM/ASPEED MACHINE SUPPORT,
	open list:GPIO SUBSYSTEM, Andrew Jeffery, Linus Walleij,
	open list, Bartosz Golaszewski,
	moderated list:ARM/ASPEED MACHINE SUPPORT
In-Reply-To: <20190906062644.13445-1-rashmica.g@gmail.com>

On Fri, 6 Sep 2019 at 06:26, Rashmica Gupta <rashmica.g@gmail.com> wrote:
>
> This is in preparation for adding ast2600 support. The ast2600 SoC
> requires two instances of the GPIO driver as it has two GPIO
> controllers. Each instance needs it's own irqchip.
>
> Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>

Reviewed-by: Joel Stanley <joel@jms.id.au>

> ---
>  drivers/gpio/gpio-aspeed.c | 16 +++++++---------
>  1 file changed, 7 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
> index b83e23aecd18..16c6eaf70857 100644
> --- a/drivers/gpio/gpio-aspeed.c
> +++ b/drivers/gpio/gpio-aspeed.c
> @@ -52,6 +52,7 @@ struct aspeed_gpio_config {
>   */
>  struct aspeed_gpio {
>         struct gpio_chip chip;
> +       struct irq_chip irqc;
>         spinlock_t lock;
>         void __iomem *base;
>         int irq;
> @@ -681,14 +682,6 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)
>         chained_irq_exit(ic, desc);
>  }
>
> -static struct irq_chip aspeed_gpio_irqchip = {
> -       .name           = "aspeed-gpio",
> -       .irq_ack        = aspeed_gpio_irq_ack,
> -       .irq_mask       = aspeed_gpio_irq_mask,
> -       .irq_unmask     = aspeed_gpio_irq_unmask,
> -       .irq_set_type   = aspeed_gpio_set_type,
> -};
> -
>  static void set_irq_valid_mask(struct aspeed_gpio *gpio)
>  {
>         const struct aspeed_bank_props *props = gpio->config->props;
> @@ -1192,7 +1185,12 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
>
>                 gpio->irq = rc;
>                 girq = &gpio->chip.irq;
> -               girq->chip = &aspeed_gpio_irqchip;
> +               girq->chip = &gpio->irqc;
> +               girq->chip->name = dev_name(&pdev->dev);
> +               girq->chip->irq_ack = aspeed_gpio_irq_ack;
> +               girq->chip->irq_mask = aspeed_gpio_irq_mask;
> +               girq->chip->irq_unmask = aspeed_gpio_irq_unmask;
> +               girq->chip->irq_set_type = aspeed_gpio_set_type;
>                 girq->parent_handler = aspeed_gpio_irq_handler;
>                 girq->num_parents = 1;
>                 girq->parents = devm_kcalloc(&pdev->dev, 1,
> --
> 2.20.1
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v3 4/5] gpios: Use ngpio property from device tree if available
From: Joel Stanley @ 2019-09-06 19:47 UTC (permalink / raw)
  To: Rashmica Gupta
  Cc: moderated list:ARM/ASPEED MACHINE SUPPORT,
	open list:GPIO SUBSYSTEM, Andrew Jeffery, Linus Walleij,
	open list, Bartosz Golaszewski,
	moderated list:ARM/ASPEED MACHINE SUPPORT
In-Reply-To: <20190906062727.13521-1-rashmica.g@gmail.com>

On Fri, 6 Sep 2019 at 06:27, Rashmica Gupta <rashmica.g@gmail.com> wrote:
>
> Use the ngpio property from the device tree if it exists. If it doesn't
> then fallback to the hardcoded value in the config.
>
> This is in preparation for adding ast2600 support. The ast2600 SoC has
> two GPIO controllers and so requires two instances of the GPIO driver.
> We use the ngpio property to different between them as they have
> different numbers of GPIOs.
>
> Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>

Reviewed-by: Joel Stanley <joel@jms.id.au>

> ---
>  drivers/gpio/gpio-aspeed.c | 18 +++++++++++-------
>  1 file changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
> index 16c6eaf70857..c3d5ecba343b 100644
> --- a/drivers/gpio/gpio-aspeed.c
> +++ b/drivers/gpio/gpio-aspeed.c
> @@ -694,7 +694,7 @@ static void set_irq_valid_mask(struct aspeed_gpio *gpio)
>                 for_each_clear_bit(offset, &input, 32) {
>                         unsigned int i = props->bank * 32 + offset;
>
> -                       if (i >= gpio->config->nr_gpios)
> +                       if (i >= gpio->chip.ngpio)
>                                 break;
>
>                         clear_bit(i, gpio->chip.irq.valid_mask);
> @@ -1007,10 +1007,10 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc,
>         unsigned long flags;
>
>         if (!gpio->cf_copro_bankmap)
> -               gpio->cf_copro_bankmap = kzalloc(gpio->config->nr_gpios >> 3, GFP_KERNEL);
> +               gpio->cf_copro_bankmap = kzalloc(gpio->chip.ngpio >> 3, GFP_KERNEL);
>         if (!gpio->cf_copro_bankmap)
>                 return -ENOMEM;
> -       if (offset < 0 || offset > gpio->config->nr_gpios)
> +       if (offset < 0 || offset > gpio->chip.ngpio)
>                 return -EINVAL;
>         bindex = offset >> 3;
>
> @@ -1055,7 +1055,7 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc)
>         if (!gpio->cf_copro_bankmap)
>                 return -ENXIO;
>
> -       if (offset < 0 || offset > gpio->config->nr_gpios)
> +       if (offset < 0 || offset > gpio->chip.ngpio)
>                 return -EINVAL;
>         bindex = offset >> 3;
>
> @@ -1119,7 +1119,8 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
>  {
>         const struct of_device_id *gpio_id;
>         struct aspeed_gpio *gpio;
> -       int rc, i, banks;
> +       int rc, i, banks, err;
> +       u32 ngpio;
>
>         gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
>         if (!gpio)
> @@ -1145,7 +1146,10 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
>         gpio->config = gpio_id->data;
>
>         gpio->chip.parent = &pdev->dev;
> -       gpio->chip.ngpio = gpio->config->nr_gpios;
> +       err = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpio);
> +       gpio->chip.ngpio = (u16) ngpio;
> +       if (err)
> +               gpio->chip.ngpio = gpio->config->nr_gpios;
>         gpio->chip.direction_input = aspeed_gpio_dir_in;
>         gpio->chip.direction_output = aspeed_gpio_dir_out;
>         gpio->chip.get_direction = aspeed_gpio_get_direction;
> @@ -1158,7 +1162,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
>         gpio->chip.base = -1;
>
>         /* Allocate a cache of the output registers */
> -       banks = DIV_ROUND_UP(gpio->config->nr_gpios, 32);
> +       banks = DIV_ROUND_UP(gpio->chip.ngpio, 32);
>         gpio->dcache = devm_kcalloc(&pdev->dev,
>                                     banks, sizeof(u32), GFP_KERNEL);
>         if (!gpio->dcache)
> --
> 2.20.1
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [GIT PULL] ARM: SoC fixes for -rc8
From: Arnd Bergmann @ 2019-09-06 19:48 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Geert Uytterhoeven, Linux Kernel Mailing List, SoC Team,
	Simon Horman, Andy Gross, Lee Jones, Linux ARM

The following changes since commit 089cf7f6ecb266b6a4164919a2e69bd2f938374a:

  Linux 5.3-rc7 (2019-09-02 09:57:40 -0700)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/armsoc-fixes

for you to fetch changes up to 8928e917aeafaf38d65cc5cbc1f11e952dbed062:

  soc: qcom: geni: Provide parameter error checking (2019-09-06 11:08:08 +0200)

----------------------------------------------------------------
ARM: SoC fixes

There are three more fixes for this week:

- The Windows-on-ARM laptops require a workaround to
  prevent crashing at boot from ACPI
- The Renesas "draak" board needs one bugfix for
  the backlight regulator
- Also for Renesas, the "hihope" board accidentally
  had its eMMC turned off in the 5.3 merge window.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

----------------------------------------------------------------
Arnd Bergmann (2):
      Merge tag 'renesas-fixes-for-v5.3' of
git://git.kernel.org/.../horms/renesas into arm/fixes
      Merge tag 'renesas-fixes2-for-v5.3' of
git://git.kernel.org/.../horms/renesas into arm/fixes

Fabrizio Castro (1):
      arm64: dts: renesas: hihope-common: Fix eMMC status

Geert Uytterhoeven (1):
      arm64: dts: renesas: r8a77995: draak: Fix backlight regulator name

Lee Jones (1):
      soc: qcom: geni: Provide parameter error checking

 arch/arm64/boot/dts/renesas/hihope-common.dtsi | 1 +
 arch/arm64/boot/dts/renesas/r8a77995-draak.dts | 6 +++---
 drivers/soc/qcom/qcom-geni-se.c                | 6 ++++++
 3 files changed, 10 insertions(+), 3 deletions(-)

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [GIT PULL] ARM: SoC fixes for -rc8
From: pr-tracker-bot @ 2019-09-06 20:00 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Geert Uytterhoeven, Lee Jones, Linux Kernel Mailing List,
	SoC Team, Simon Horman, Andy Gross, Linus Torvalds, Linux ARM
In-Reply-To: <CAK8P3a0MsTFjqChoz+DLSC8nVnBuvqQdYx6V0SuCybg7MZ79mQ@mail.gmail.com>

The pull request you sent on Fri, 6 Sep 2019 21:48:09 +0200:

> git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git tags/armsoc-fixes

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/36daa831b55538dc2e4a906de20c5d91033ebb21

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.wiki.kernel.org/userdoc/prtracker

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH] bus: ti-sysc: Remove unpaired sysc_clkdm_deny_idle()
From: Tony Lindgren @ 2019-09-06 20:01 UTC (permalink / raw)
  To: linux-omap
  Cc: Nishanth Menon, Tero Kristo, Vignesh Raghavendra, Dave Gerlach,
	Keerthy, linux-kernel, Andrew F . Davis, Peter Ujfalusi,
	Faiz Abbas, Greg Kroah-Hartman, linux-arm-kernel, Roger Quadros

Commit d098913a10f8 ("bus: ti-sysc: Fix clock handling for no-idle
quirks") fixed handling for no-idle quirk modules that are not enabled
by the bootloader.

But it also caused unpaired clockdomain calls that won't allow idling
the system. That's because clkdm_allow_idle_nolock() and
clkdm_deny_idle_nolock() have usage count with clkdm->forcewake_count.

Let's drop the unpaired sysc_clkdm_deny_idle() to fix idling of devices.

Fixes: d098913a10f8 ("bus: ti-sysc: Fix clock handling for no-idle quirks")
Cc: Keerthy <j-keerthy@ti.com>
Cc: Vignesh Raghavendra <vigneshr@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
 drivers/bus/ti-sysc.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -2363,7 +2363,6 @@ static void ti_sysc_idle(struct work_struct *work)
 	 */
 	if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE |
 				 SYSC_QUIRK_NO_IDLE_ON_INIT)) {
-		sysc_clkdm_deny_idle(ddata);
 		sysc_disable_main_clocks(ddata);
 		sysc_disable_opt_clocks(ddata);
 		sysc_clkdm_allow_idle(ddata);
-- 
2.23.0

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCHv4 01/10] dt-bindings: omap: add new binding for PRM instances
From: Tero Kristo @ 2019-09-06 20:02 UTC (permalink / raw)
  To: Tony Lindgren, Rob Herring
  Cc: devicetree, linux-omap, Philipp Zabel, Santosh Shilimkar,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20190906153658.GB52127@atomide.com>

On 06/09/2019 18:36, Tony Lindgren wrote:
> * Rob Herring <robh+dt@kernel.org> [190906 12:57]:
>> On Fri, Sep 6, 2019 at 11:36 AM Tero Kristo <t-kristo@ti.com> wrote:
>>>
>>> Add new binding for OMAP PRM (Power and Reset Manager) instances. Each
>>> of these will act as a power domain controller and potentially as a reset
>>> provider.
>>>
>>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>>> ---
>>> v4:
>>> - renamed nodes as power-controller
>>> - added documentation about hierarchy
>>>
>>>   .../devicetree/bindings/arm/omap/prm-inst.txt | 31 +++++++++++++++++++
>>>   1 file changed, 31 insertions(+)
>>>   create mode 100644 Documentation/devicetree/bindings/arm/omap/prm-inst.txt
>>
>> Reviewed-by: Rob Herring <robh@kernel.org>
> 
> Looks good to me too:
> 
> Reviewed-by: Tony Lindgren <tony@atomide.com>
> 

I may need to re-spin slightly new version of this. Stephen has some 
comments on the clock driver side I am depending on, he does not like 
the hard link between reset + clocks, so I may need to ditch the 
"clocks" property from this one also.

I'll see next week which direction I need to go.

-Tero
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v4 3/4] dt-bindings: Add Qualcomm USB SuperSpeed PHY bindings
From: Stephen Boyd @ 2019-09-06 20:40 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: mark.rutland, robh, Jack Pham, devicetree, gregkh, linux-usb,
	khasim.mohammed, linux-kernel, kishon, linux-arm-msm, andy.gross,
	Jorge Ramirez, shawn.guo, linux-arm-kernel
In-Reply-To: <20190906182530.GD11938@tuxbook-pro>

Quoting Bjorn Andersson (2019-09-06 11:25:30)
> On Thu 05 Sep 22:26 PDT 2019, Stephen Boyd wrote:
> 
> > 
> > Yes this looks like the approach that should be taken. One question
> > though, is this a micro-b connector or a type-c connector on the board?
> > I thought it was a type-c, so then this USB gpio based connection driver
> > isn't an exact fit?
> > 
> 
> For this particular case it's a type c connector, but the port
> controller is operated completely passively (and there's no PD or DP
> involved), so the GPIO based approach seems like a good fit.
> 

OK. Perhaps the binding needs an update then to have another compatible
string indicating type-c connector that's not able to support PD or DP?


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] gpio/mpc8xxx: change irq handler from chained to normal
From: Li Yang @ 2019-09-06 21:46 UTC (permalink / raw)
  To: Hui Song
  Cc: Mark Rutland,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	linux-gpio, Linus Walleij, lkml, Bartosz Golaszewski, Rob Herring,
	Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20190906115614.5645-1-hui.song_1@nxp.com>

On Fri, Sep 6, 2019 at 10:20 AM Hui Song <hui.song_1@nxp.com> wrote:
>
> From: Song Hui <hui.song_1@nxp.com>
>

The English below need to be fixed.

> more one gpio controller use share one interrupt,
> make request interrupt to be shared.

More than one gpio controllers can share one interrupt, change the
driver to request shared irq.

>
> Signed-off-by: Laurentiu Tudor <Laurentiu.Tudor@nxp.com>
> Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
> Signed-off-by: Song Hui <hui.song_1@nxp.com>
> ---
>  drivers/gpio/gpio-mpc8xxx.c | 20 +++++++++++++-------
>  1 file changed, 13 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
> index 16a47de..4006250 100644
> --- a/drivers/gpio/gpio-mpc8xxx.c
> +++ b/drivers/gpio/gpio-mpc8xxx.c
> @@ -22,6 +22,7 @@
>  #include <linux/irq.h>
>  #include <linux/gpio/driver.h>
>  #include <linux/bitops.h>
> +#include <linux/interrupt.h>
>
>  #define MPC8XXX_GPIO_PINS      32
>
> @@ -127,10 +128,9 @@ static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
>                 return -ENXIO;
>  }
>
> -static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc)
> +static irqreturn_t mpc8xxx_gpio_irq_cascade(int irq, void *data)
>  {
> -       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc);
> -       struct irq_chip *chip = irq_desc_get_chip(desc);
> +       struct mpc8xxx_gpio_chip *mpc8xxx_gc = (struct mpc8xxx_gpio_chip *)data;
>         struct gpio_chip *gc = &mpc8xxx_gc->gc;
>         unsigned int mask;
>
> @@ -139,8 +139,8 @@ static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc)
>         if (mask)
>                 generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
>                                                      32 - ffs(mask)));
> -       if (chip->irq_eoi)
> -               chip->irq_eoi(&desc->irq_data);
> +
> +       return IRQ_HANDLED;
>  }
>
>  static void mpc8xxx_irq_unmask(struct irq_data *d)
> @@ -409,8 +409,14 @@ static int mpc8xxx_probe(struct platform_device *pdev)
>         if (devtype->gpio_dir_in_init)
>                 devtype->gpio_dir_in_init(gc);
>
> -       irq_set_chained_handler_and_data(mpc8xxx_gc->irqn,
> -                                        mpc8xxx_gpio_irq_cascade, mpc8xxx_gc);
> +       ret = request_irq(mpc8xxx_gc->irqn, mpc8xxx_gpio_irq_cascade,
> +               IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade", mpc8xxx_gc);
> +       if (ret) {
> +               pr_err("%s: failed to request_irq(%d), ret = %d\n",
> +                               np->full_name, mpc8xxx_gc->irqn, ret);
> +               goto err;
> +       }
> +
>         return 0;
>  err:
>         iounmap(mpc8xxx_gc->regs);
> --
> 2.9.5
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 2/2] clk: Add support for AST2600 SoC
From: Stephen Boyd @ 2019-09-06 22:03 UTC (permalink / raw)
  To: Joel Stanley
  Cc: Ryan Chen, linux-aspeed, Andrew Jeffery, Michael Turquette,
	Linux Kernel Mailing List, Rob Herring, linux-clk, Linux ARM
In-Reply-To: <CACPK8Xf3C36KMgDmmRtNFqVFHzZx81ko+=54PA4+d5xPitum3g@mail.gmail.com>

Quoting Joel Stanley (2019-08-18 19:03:54)
> On Fri, 16 Aug 2019 at 17:14, Stephen Boyd <sboyd@kernel.org> wrote:
> >
> > Quoting Joel Stanley (2019-08-16 08:58:06)
> > > +static const char * const vclk_parent_names[] = {
> >
> > Can you use the new way of specifying clk parents instead of just using
> > strings?
> 
> How does this work? I had a browse of the APIs in clk-provider.h and
> it appeared the functions all take char *s still.

Sorry I didn't reply earlier. I'm going to write a kernel-doc to
describe how to write a "modern" clk driver which should hopefully help
here.

The gist is that you can fill out a clk_parent_data array or a clk_hw
array and set the .name and .fw_name and .index in the clk_parent_data
array to indicate which clks to get from the DT node's "clocks" and
"clock-names" properties.

> 
> > > +       hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, axi_div * ahb_div);

Take this one for example. If 'hpll' is actually a clk_hw pointer in
hand, then you could do something like:

	clk_hw_register_fixed_factor_parent_hw(NULL, "ahb", &hpll, 0, 1, axi_div * ahb_div);

And if it's something like a clock from DT you could do

	struct clk_parent_data pdata = {
		.name = "hpll",
		.fw_name = <clock-names string>,
		.index = <whatever clock index it is>
	};

	clk_hw_register_fixed_factor_parent_data(NULL, "ahb", &pdata, 0, 1, axi_div * ahb_div);

I haven't actually written the clk_hw_register_fixed_factor_*() APIs,
because I'm thinking that it would be better to register the pdata with
some more parameters so that the
clk_hw_register_fixed_factor_parent_data() API becomes more like:

	clk_hw_register_fixed_factor_parent_data(NULL, "ahb", "hpll",
		<clock-names string>, <whatever clock index it is>, 0, 1,
		axi_div * ahb_div);

Because there's only one parent. For the mux clk it will be a pointer to
parent_data because I don't see a way around it.

> >
> > There aren't checks for if these things fail. I guess it doesn't matter
> > and just let it fail hard?
> 
> I think that's sensible here. If the system has run out of memory this
> early on then there's not going to be much that works.
> 
> Thanks for the review. I've fixed all of the style issues you
> mentioned, but would appreciate some guidance on the parent API.
> 

Cool! Thanks.


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox